1 page.title=Security with HTTPS and SSL 2 page.tags="network","certificates" 3 4 page.article=true 5 @jd:body 6 7 <div id="tb-wrapper"> 8 <div id="tb"> 9 <h2>In this document</h2> 10 <ol class="nolist"> 11 <li><a href="#Concepts">Concepts</a></li> 12 <li><a href="#HttpsExample">An HTTP Example</a></li> 13 <li><a href="#CommonProblems">Common Problems Verifying Server Certificates</a> 14 <ol class="nolist"> 15 <li><a href="#UnknownCa">Unknown certificate authority</a></li> 16 <li><a href="#SelfSigned">Self-signed server certificate</a></li> 17 <li><a href="#MissingCa">Missing intermediate certificate authority</a></li> 18 </ol> 19 </li> 20 <li><a href="#CommonHostnameProbs">Common Problems with Hostname Verification</a></li> 21 <li><a href="#WarningsSslSocket">Warnings About Using SSLSocket Directly</a></li> 22 <li><a href="#Blacklisting">Blacklisting</a></li> 23 <li><a href="#Pinning">Pinning</a></li> 24 <li><a href="#ClientCert">Client Certificates</a></li> 25 </ol> 26 27 28 <h2>See also</h2> 29 <ul> 30 <li><a href="http://source.android.com/tech/security/index.html">Android 31 Security Overview</a></li> 32 <li><a href="{@docRoot}guide/topics/security/permissions.html">Permissions</a></li> 33 </ul> 34 </div></div> 35 36 37 38 <p>The Secure Sockets Layer (SSL)—now technically known as <a 39 href="http://en.wikipedia.org/wiki/Transport_Layer_Security">Transport Layer Security 40 (TLS)</a>—is a 41 common building block for encrypted communications between clients and servers. It's possible that 42 an application might use SSL incorrectly such that malicious entities may 43 be able to intercept an app's data over the network. To help you ensure that this does not happen 44 to your app, this article highlights the common pitfalls when using secure network protocols and addresses some larger concerns about using <a 45 href="http://en.wikipedia.org/wiki/Public-key_infrastructure">Public-Key Infrastructure (PKI)</a>. 46 47 48 <h2 id="Concepts">Concepts</h2> 49 50 <p>In a typical SSL usage scenario, a server is configured with a certificate containing a 51 public key as well as a matching private key. As part of the handshake between an SSL client 52 and server, the server proves it has the private key by signing its certificate with <a 53 href="http://en.wikipedia.org/wiki/Public-key_cryptography">public-key cryptography</a>.</p> 54 55 <p>However, anyone can generate their own certificate and private key, so a simple handshake 56 doesn't prove anything about the server other than that the server knows the private key that 57 matches the public key of the certificate. One way to solve this problem is to have the client 58 have a set of one or more certificates it trusts. If the certificate is not in the set, the 59 server is not to be trusted.</p> 60 61 <p>There are several downsides to this simple approach. Servers should be able to 62 upgrade to stronger keys over time ("key rotation"), which replaces the public key in the 63 certificate with a new one. Unfortunately, now the client app has to be updated due to what 64 is essentially a server configuration change. This is especially problematic if the server 65 is not under the app developer's control, for example if it is a third party web service. This 66 approach also has issues if the app has to talk to arbitrary servers such as a web browser or 67 email app.</p> 68 69 <p>In order to address these downsides, servers are typically configured with certificates 70 from well known issuers called <a 71 href="http://en.wikipedia.org/wiki/Certificate_authority">Certificate Authorities (CAs)</a>. 72 The host platform generally contains a list of well known CAs that it trusts. 73 As of Android 4.2 (Jelly Bean), Android currently contains over 100 CAs that are updated 74 in each release. Similar to a server, a CA has a certificate and a private key. When issuing 75 a certificate for a server, the CA <a 76 href="http://en.wikipedia.org/wiki/Digital_signature">signs</a> 77 the server certificate using its private key. The 78 client can then verify that the server has a certificate issued by a CA known to the platform.</p> 79 80 <p>However, while solving some problems, using CAs introduces another. Because the CA issues 81 certificates for many servers, you still need some way to make sure you are talking to the 82 server you want. To address this, the certificate issued by the CA identifies the server 83 either with a specific name such as <em>gmail.com</em> or a wildcarded set of 84 hosts such as <em>*.google.com</em>. </p> 85 86 <p>The following example will make these concepts a little more concrete. In the snippet below 87 from a command line, the <a href="http://www.openssl.org/docs/apps/openssl.html">{@code openssl}</a> 88 tool's {@code s_client} command looks at Wikipedia's server certificate information. It 89 specifies port 443 because that is the default for <acronym title="Hypertext Transfer 90 Protocol Secure">HTTPS</acronym>. The command sends 91 the output of {@code openssl s_client} to {@code openssl x509}, which formats information 92 about certificates according to the <a 93 href="http://en.wikipedia.org/wiki/X.509">X.509 standard</a>. Specifically, 94 the command asks for the subject, which contains the server name information, 95 and the issuer, which identifies the CA.</p> 96 97 <pre class="no-pretty-print"> 98 $ openssl s_client -connect wikipedia.org:443 | openssl x509 -noout -subject -issuer 99 <b>subject=</b> /serialNumber=sOrr2rKpMVP70Z6E9BT5reY008SJEdYv/C=US/O=*.wikipedia.org/OU=GT03314600/OU=See www.rapidssl.com/resources/cps (c)11/OU=Domain Control Validated - RapidSSL(R)/<b>CN=*.wikipedia.org</b> 100 <b>issuer=</b> /C=US/O=GeoTrust, Inc./CN=<b>RapidSSL CA</b> 101 </pre> 102 103 <p>You can see that the certificate was issued for servers matching <em>*.wikipedia.org</em> by 104 the RapidSSL CA.</p> 105 106 107 108 <h2 id="HttpsExample">An HTTPS Example</h2> 109 110 <p>Assuming you have a web server with a 111 certificate issued by a well known CA, you can make a secure request with code as 112 simple this:</p> 113 114 <pre> 115 URL url = new URL("https://wikipedia.org"); 116 URLConnection urlConnection = url.openConnection(); 117 InputStream in = urlConnection.getInputStream(); 118 copyInputStreamToOutputStream(in, System.out); 119 </pre> 120 121 <p>Yes, it really can be that simple. If you want to tailor the HTTP request, you can cast to 122 an {@link java.net.HttpURLConnection}. The Android documentation for 123 {@link java.net.HttpURLConnection} has further examples about how to deal with request 124 and response headers, posting content, managing cookies, using proxies, caching responses, 125 and so on. But in terms of the details for verifying certificates and hostnames, the Android 126 framework takes care of it for you through these APIs. 127 This is where you want to be if at all possible. That said, below are some other considerations.</p> 128 129 130 131 <h2 id="CommonProblems">Common Problems Verifying Server Certificates</h2> 132 133 <p>Suppose instead of receiving the content from {@link java.net.URLConnection#getInputStream 134 getInputStream()}, it throws an exception:</p> 135 136 <pre class="no-pretty-print"> 137 javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found. 138 at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374) 139 at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209) 140 at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478) 141 at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433) 142 at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290) 143 at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240) 144 at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282) 145 at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177) 146 at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271) 147 </pre> 148 149 <p>This can happen for several reasons, including: 150 <ol> 151 <li><a href="#UnknownCa">The CA that issued the server certificate was unknown</a></li> 152 <li><a href="#SelfSigned">The server certificate wasn't signed by a CA, but was self signed</a></li> 153 <li><a href="#MissingCa">The server configuration is missing an intermediate CA</a></li> 154 </ol> 155 156 <p>The following sections discuss how to address these problems while keeping your 157 connection to the server secure. 158 159 160 161 <h3 id="UnknownCa">Unknown certificate authority</h3> 162 163 <p>In this case, the {@link javax.net.ssl.SSLHandshakeException} occurs 164 because you have a CA that isn't trusted by the system. It could be because 165 you have a certificate from a new CA that isn't yet trusted by Android or your app is 166 running on an older version without the CA. More often a CA is unknown because it isn't a 167 public CA, but a private one issued by an organization such as a government, corporation, 168 or education institution for their own use.</p> 169 170 <p>Fortunately, you can teach {@link javax.net.ssl.HttpsURLConnection} 171 to trust a specific set of CAs. The procedure 172 can be a little convoluted, so below is an example that takes a specific CA from 173 an {@link java.io.InputStream}, uses it to create a {@link java.security.KeyStore}, 174 which is then used to create and initialize a 175 {@link javax.net.ssl.TrustManager}. A {@link javax.net.ssl.TrustManager} is what the system 176 uses to validate certificates from the server 177 and—by creating one from a {@link java.security.KeyStore} with one or more CAs—those 178 will be the only CAs trusted by that {@link javax.net.ssl.TrustManager}.</p> 179 180 <p>Given the new {@link javax.net.ssl.TrustManager}, 181 the example initializes a new {@link javax.net.ssl.SSLContext} which provides 182 an {@link javax.net.ssl.SSLSocketFactory} you can use to override the default 183 {@link javax.net.ssl.SSLSocketFactory} from 184 {@link javax.net.ssl.HttpsURLConnection}. This way the 185 connection will use your CAs for certificate validation.</p> 186 187 <p>Here is the example in 188 full using an organizational CA from the University of Washington:</p> 189 190 <pre> 191 // Load CAs from an InputStream 192 // (could be from a resource or ByteArrayInputStream or ...) 193 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 194 // From https://www.washington.edu/itconnect/security/ca/load-der.crt 195 InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt")); 196 Certificate ca; 197 try { 198 ca = cf.generateCertificate(caInput); 199 System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); 200 } finally { 201 caInput.close(); 202 } 203 204 // Create a KeyStore containing our trusted CAs 205 String keyStoreType = KeyStore.getDefaultType(); 206 KeyStore keyStore = KeyStore.getInstance(keyStoreType); 207 keyStore.load(null, null); 208 keyStore.setCertificateEntry("ca", ca); 209 210 // Create a TrustManager that trusts the CAs in our KeyStore 211 String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); 212 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); 213 tmf.init(keyStore); 214 215 // Create an SSLContext that uses our TrustManager 216 SSLContext context = SSLContext.getInstance("TLS"); 217 context.init(null, tmf.getTrustManagers(), null); 218 219 // Tell the URLConnection to use a SocketFactory from our SSLContext 220 URL url = new URL("https://certs.cac.washington.edu/CAtest/"); 221 HttpsURLConnection urlConnection = 222 (HttpsURLConnection)url.openConnection(); 223 urlConnection.setSSLSocketFactory(context.getSocketFactory()); 224 InputStream in = urlConnection.getInputStream(); 225 copyInputStreamToOutputStream(in, System.out); 226 </pre> 227 228 <p>With a custom {@link javax.net.ssl.TrustManager} that knows about your CAs, 229 the system is able to validate 230 that your server certificate come from a trusted issuer.</p> 231 232 <p class="caution"><strong>Caution:</strong> 233 Many web sites describe a poor alternative solution which is to install a 234 {@link javax.net.ssl.TrustManager} that does nothing. If you do this you might as well not 235 be encrypting your communication, because anyone can attack your users at a public Wi-Fi hotspot 236 by using <acronym title="Domain Name System">DNS</acronym> tricks to send your users' 237 traffic through a proxy of their own that pretends to be your server. The attacker can then 238 record passwords and other personal data. This works because the attacker can generate a 239 certificate and—without a {@link javax.net.ssl.TrustManager} that actually 240 validates that the certificate comes from a trusted 241 source—your app could be talking to anyone. So don't do this, not even temporarily. You can 242 always make your app trust the issuer of the server's certificate, so just do it.</p> 243 244 245 246 <h3 id="SelfSigned">Self-signed server certificate</h3> 247 248 <p>The second case of {@link javax.net.ssl.SSLHandshakeException} is 249 due to a self-signed certificate, which means the server is behaving as its own CA. 250 This is similar to an unknown certificate authority, so you can use the 251 same approach from the previous section.</p> 252 253 <p>You can create yout own {@link javax.net.ssl.TrustManager}, 254 this time trusting the server certificate directly. This has all of the 255 downsides discussed earlier of tying your app directly to a certificate, but can be done 256 securely. However, you should be careful to make sure your self-signed certificate has a 257 reasonably strong key. As of 2012, a 2048-bit RSA signature with an exponent of 65537 expiring 258 yearly is acceptable. When rotating keys, you should check for <a 259 href="http://csrc.nist.gov/groups/ST/key_mgmt/index.html">recommendations</a> from an 260 authority (such as <a href="http://www.nist.gov/">NIST</a>) about what is acceptable.</p> 261 262 263 264 <h3 id="MissingCa">Missing intermediate certificate authority</h3> 265 266 <p>The third case of {@link javax.net.ssl.SSLHandshakeException} 267 occurs due to a missing intermediate CA. Most public 268 CAs don't sign server certificates directly. Instead, they use their main CA certificate, 269 referred to as the root CA, to sign intermediate CAs. They do this so the root CA can be stored 270 offline to reduce risk of compromise. However, operating systems like Android typically 271 trust only root CAs directly, which leaves a short gap of trust between the server 272 certificate—signed by the intermediate CA—and the certificate verifier, 273 which knows the root CA. To solve 274 this, the server doesn't send the client only it's certificate during the SSL handshake, but 275 a chain of certificates from the server CA through any intermediates necessary to reach a 276 trusted root CA.</p> 277 278 <p>To see what this looks like in practice, here's the <em>mail.google.com</em> certificate 279 chain as viewed by the <a href="http://www.openssl.org/docs/apps/openssl.html">{@code openssl}</a> 280 {@code s_client} command:</p> 281 282 <pre class="no-pretty-print"> 283 $ openssl s_client -connect mail.google.com:443 284 --- 285 Certificate chain 286 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=mail.google.com 287 i:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA 288 1 s:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA 289 i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority 290 --- 291 </pre> 292 293 294 <p>This shows that the server sends a certificate for <em>mail.google.com</em> 295 issued by the <em>Thawte SGC</em> CA, which is an intermediate CA, and a second certificate 296 for the <em>Thawte SGC</em> CA issued by a <em>Verisign</em> CA, which is the primary CA that's 297 trusted by Android.</p> 298 299 <p>However, it is not uncommon to configure a server to not include the necessary 300 intermediate CA. For example, here is a server that can cause an error in Android browsers and 301 exceptions in Android apps:</p> 302 303 <pre class="no-pretty-print"> 304 $ openssl s_client -connect egov.uscis.gov:443 305 --- 306 Certificate chain 307 0 s:/C=US/ST=District Of Columbia/L=Washington/O=U.S. Department of Homeland Security/OU=United States Citizenship and Immigration Services/OU=Terms of use at www.verisign.com/rpa (c)05/CN=egov.uscis.gov 308 i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=Terms of use at https://www.verisign.com/rpa (c)10/CN=VeriSign Class 3 International Server CA - G3 309 --- 310 </pre> 311 312 <p>What is interesting to note here is that visiting this server in most desktop browsers 313 does not cause an error like a completely unknown CA or self-signed server certificate would 314 cause. This is because most desktop browsers cache trusted intermediate CAs over time. Once 315 a browser has visited and learned about an intermediate CA from one site, it won't 316 need to have the intermediate CA included in the certificate chain the next time.</p> 317 318 <p>Some sites do this intentionally for secondary web servers used to serve resources. For 319 example, they might have their main HTML page served by a server with a full certificate 320 chain, but have servers for resources such as images, CSS, or JavaScript not include the 321 CA, presumably to save bandwidth. Unfortunately, sometimes these servers might be providing 322 a web service you are trying to call from your Android app, which is not as forgiving.</p> 323 324 <p>There are two approaches to solve this issue:</p> 325 <ul> 326 <li>Configure the server to 327 include the intermediate CA in the server chain. Most CAs provide documentation on how to do 328 this for all common web servers. This is the only approach if you need the site to work with 329 default Android browsers at least through Android 4.2.</li> 330 <li>Or, treat the 331 intermediate CA like any other unknown CA, and create a {@link javax.net.ssl.TrustManager} 332 to trust it directly, as done in the previous two sections.</li> 333 </ul> 334 335 336 <h2 id="CommonHostnameProbs">Common Problems with Hostname Verification</h2> 337 338 <p>As mentioned at the beginning of this article, 339 there are two key parts to verifying an SSL connection. The first 340 is to verify the certificate is from a trusted source, which was the focus of the previous 341 section. The focus of this section is the second part: making sure the server you are 342 talking to presents the right certificate. When it doesn't, you'll typically see an error 343 like this:</p> 344 345 <pre class="no-pretty-print"> 346 java.io.IOException: Hostname 'example.com' was not verified 347 at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:223) 348 at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:446) 349 at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290) 350 at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240) 351 at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282) 352 at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177) 353 at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271) 354 </pre> 355 356 357 <p>One reason this can happen is due to a server configuration error. The server is 358 configured with a certificate that does not have a subject or subject alternative name fields 359 that match the server you are trying to reach. It is possible to have one certificate be used 360 with many different servers. For example, looking at the <em>google.com</em> certificate with 361 <a href="http://www.openssl.org/docs/apps/openssl.html">{@code openssl}</a> {@code 362 s_client -connect google.com:443 | openssl x509 -text} you can see that a subject 363 that supports <em>*.google.com</em> but also subject alternative names for <em>*.youtube.com</em>, 364 <em>*.android.com</em>, and others. The error occurs only when the server name you 365 are connecting to isn't listed by the certificate as acceptable.</p> 366 367 <p>Unfortunately this can happen for another reason as well: <a 368 href="http://en.wikipedia.org/wiki/Virtual_hosting">virtual hosting</a>. When sharing a 369 server for more than one hostname with HTTP, the web server can tell from the HTTP/1.1 request 370 which target hostname the client is looking for. Unfortunately this is complicated with 371 HTTPS, because the server has to know which certificate to return before it sees the HTTP 372 request. To address this problem, newer versions of SSL, specifically TLSv.1.0 and later, 373 support <a href="http://en.wikipedia.org/wiki/Server_Name_Indication">Server Name Indication 374 (SNI)</a>, which allows the SSL client to specify the intended 375 hostname to the server so the proper certificate can be returned.</p> 376 377 <p>Fortunately, {@link javax.net.ssl.HttpsURLConnection} supports 378 SNI since Android 2.3. Unfortunately, Apache 379 HTTP Client does not, which is one of the many reasons we discourage its use. One workaround 380 if you need to support Android 2.2 (and older) or Apache HTTP Client is to set up an alternative 381 virtual host on a unique port so that it's unambiguous which server certificate to return.</p> 382 383 <p>The more drastic alternative is to replace {@link javax.net.ssl.HostnameVerifier} 384 with one that uses not the 385 hostname of your virtual host, but the one returned by the server by default.</p> 386 387 <p class="caution"><strong>Caution:</strong> Replacing {@link javax.net.ssl.HostnameVerifier} 388 can be <strong>very dangerous</strong> if the other virtual host is 389 not under your control, because a man-in-the-middle attack could direct traffic to another 390 server without your knowledge.</p> 391 392 <p>If you are still sure you want to override hostname verification, here is an example 393 that replaces the verifier for a single {@link java.net.URLConnection} 394 with one that still verifies that the hostname is at least on expected by the app:</p> 395 396 <pre> 397 // Create an HostnameVerifier that hardwires the expected hostname. 398 // Note that is different than the URL's hostname: 399 // example.com versus example.org 400 HostnameVerifier hostnameVerifier = new HostnameVerifier() { 401 @Override 402 public boolean verify(String hostname, SSLSession session) { 403 HostnameVerifier hv = 404 HttpsURLConnection.getDefaultHostnameVerifier(); 405 return hv.verify("example.com", session); 406 } 407 }; 408 409 // Tell the URLConnection to use our HostnameVerifier 410 URL url = new URL("https://example.org/"); 411 HttpsURLConnection urlConnection = 412 (HttpsURLConnection)url.openConnection(); 413 urlConnection.setHostnameVerifier(hostnameVerifier); 414 InputStream in = urlConnection.getInputStream(); 415 copyInputStreamToOutputStream(in, System.out); 416 </pre> 417 418 <p>But remember, if you find yourself replacing hostname verification, especially 419 due to virtual hosting, it's still <strong>very dangerous</strong> if the other virtual host is 420 not under your control and you should find an alternative hosting arrangement 421 that avoids this issue.</p> 422 423 424 425 426 <h2 id="WarningsSslSocket">Warnings About Using SSLSocket Directly</h2> 427 428 <p>So far, the examples have focused on HTTPS using {@link javax.net.ssl.HttpsURLConnection}. 429 Sometimes apps need to use SSL separate from HTTP. For example, an email app might use SSL variants 430 of SMTP, POP3, or IMAP. In those cases, the app would want to use {@link javax.net.ssl.SSLSocket} 431 directly, much the same way that {@link javax.net.ssl.HttpsURLConnection} does internally.</p> 432 433 <p>The techniques described so 434 far to deal with certificate verification issues also apply to {@link javax.net.ssl.SSLSocket}. 435 In fact, when using a custom {@link javax.net.ssl.TrustManager}, what is passed to 436 {@link javax.net.ssl.HttpsURLConnection} is an {@link javax.net.ssl.SSLSocketFactory}. 437 So if you need to use a custom {@link javax.net.ssl.TrustManager} with an 438 {@link javax.net.ssl.SSLSocket}, follow 439 the same steps and use that {@link javax.net.ssl.SSLSocketFactory} to create your 440 {@link javax.net.ssl.SSLSocket}.</p> 441 442 <p class="caution"><strong>Caution:</strong> 443 {@link javax.net.ssl.SSLSocket} <strong>does not</strong> perform hostname verification. It is 444 up the your app to do its own hostname verification, preferably by calling {@link 445 javax.net.ssl.HttpsURLConnection#getDefaultHostnameVerifier()} with the expected hostname. Further 446 beware that {@link javax.net.ssl.HostnameVerifier#verify HostnameVerifier.verify()} 447 doesn't throw an exception on error but instead returns a boolean result that you must 448 explicitly check.</p> 449 450 <p>Here is an example showing how you can do this. It shows that when connecting to 451 <em>gmail.com</em> port 443 without SNI support, you'll receive a certificate for 452 <em>mail.google.com</em>. This is expected in this case, so check to make sure that 453 the certificate is indeed for <em>mail.google.com</em>:</p> 454 455 <pre> 456 // Open SSLSocket directly to gmail.com 457 SocketFactory sf = SSLSocketFactory.getDefault(); 458 SSLSocket socket = (SSLSocket) sf.createSocket("gmail.com", 443); 459 HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier(); 460 SSLSession s = socket.getSession(); 461 462 // Verify that the certicate hostname is for mail.google.com 463 // This is due to lack of SNI support in the current SSLSocket. 464 if (!hv.verify("mail.google.com", s)) { 465 throw new SSLHandshakeException("Expected mail.google.com, " 466 "found " + s.getPeerPrincipal()); 467 } 468 469 // At this point SSLSocket performed certificate verificaiton and 470 // we have performed hostname verification, so it is safe to proceed. 471 472 // ... use socket ... 473 socket.close(); 474 </pre> 475 476 477 478 <h2 id="Blacklisting">Blacklisting</h2> 479 480 <p>SSL relies heavily on CAs to issue certificates to only the properly verified owners 481 of servers and domains. In rare cases, CAs are either tricked or, in the case of <a 482 href="http://en.wikipedia.org/wiki/Comodo_Group#Breach_of_security">Comodo</a> or <a 483 href="http://en.wikipedia.org/wiki/DigiNotar">DigiNotar</a>, breached, 484 resulting in the certificates for a hostname to be issued to 485 someone other than the owner of the server or domain.</p> 486 487 <p>In order to mitigate this risk, Android has the ability to blacklist certain certificates or even 488 whole CAs. While this list was historically built into the operating system, starting in 489 Android 4.2 this list can be remotely updated to deal with future compromises.</p> 490 491 492 493 <h2 id="Pinning">Pinning</h2> 494 495 <p>An app can further protect itself from fraudulently issued certificates by a 496 technique known as pinning. This is basically using the example provided in the unknown CA case 497 above to restrict an app's trusted CAs to a small set known to be used by the app's servers. This 498 prevents the compromise of one of the other 100+ CAs in the system from resulting in a breach of 499 the apps secure channel.</p> 500 501 502 503 <h2 id="ClientCert">Client Certificates</h2> 504 505 <p>This article has focused on the user of SSL to secure communications with servers. SSL also 506 supports the notion of client certificates that allow the server to validate the identity of a 507 client. While beyond the scope of this article, the techniques involved are similar to specifying 508 a custom {@link javax.net.ssl.TrustManager}. 509 See the discussion about creating a custom {@link javax.net.ssl.KeyManager} in the documentation for 510 {@link javax.net.ssl.HttpsURLConnection}.</p> 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542