Home | History | Annotate | Download | only in articles
      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   <li><a href="#nogotofail">Nogotofail: Network Security Testing</a></li>
     26 </ol>
     27 
     28 
     29 <h2>See also</h2>
     30 <ul>
     31 <li><a href="http://source.android.com/tech/security/index.html">Android
     32 Security Overview</a></li>
     33 <li><a href="{@docRoot}guide/topics/security/permissions.html">Permissions</a></li>
     34 </ul>
     35 </div></div>
     36 
     37 
     38 
     39 <p>The Secure Sockets Layer (SSL)&mdash;now technically known as <a
     40 href="http://en.wikipedia.org/wiki/Transport_Layer_Security">Transport Layer Security
     41 (TLS)</a>&mdash;is a
     42 common building block for encrypted communications between clients and servers. It's possible that
     43 an application might use SSL incorrectly such that malicious entities may
     44 be able to intercept an app's data over the network. To help you ensure that this does not happen
     45 to your app, this article highlights the common pitfalls when using secure network protocols and addresses some larger concerns about using <a
     46 href="http://en.wikipedia.org/wiki/Public-key_infrastructure">Public-Key Infrastructure (PKI)</a>.
     47 
     48 
     49 <h2 id="Concepts">Concepts</h2>
     50 
     51 <p>In a typical SSL usage scenario, a server is configured with a certificate containing a
     52 public key as well as a matching private key. As part of the handshake between an SSL client
     53 and server, the server proves it has the private key by signing its certificate with <a
     54 href="http://en.wikipedia.org/wiki/Public-key_cryptography">public-key cryptography</a>.</p>
     55 
     56 <p>However, anyone can generate their own certificate and private key, so a simple handshake
     57 doesn't prove anything about the server other than that the server knows the private key that
     58 matches the public key of the certificate. One way to solve this problem is to have the client
     59 have a set of one or more certificates it trusts. If the certificate is not in the set, the
     60 server is not to be trusted.</p>
     61 
     62 <p>There are several downsides to this simple approach. Servers should be able to
     63 upgrade to stronger keys over time ("key rotation"), which replaces the public key in the
     64 certificate with a new one. Unfortunately, now the client app has to be updated due to what
     65 is essentially a server configuration change. This is especially problematic if the server
     66 is not under the app developer's control, for example if it is a third party web service. This
     67 approach also has issues if the app has to talk to arbitrary servers such as a web browser or
     68 email app.</p>
     69 
     70 <p>In order to address these downsides, servers are typically configured with certificates
     71 from well known issuers called <a
     72 href="http://en.wikipedia.org/wiki/Certificate_authority">Certificate Authorities (CAs)</a>.
     73 The host platform generally contains a list of well known CAs that it trusts.
     74 As of Android 4.2 (Jelly Bean), Android currently contains over 100 CAs that are updated
     75 in each release. Similar to a server, a CA has a certificate and a private key. When issuing
     76 a certificate for a server, the CA <a
     77 href="http://en.wikipedia.org/wiki/Digital_signature">signs</a>
     78 the server certificate using its private key. The
     79 client can then verify that the server has a certificate issued by a CA known to the platform.</p>
     80 
     81 <p>However, while solving some problems, using CAs introduces another. Because the CA issues
     82 certificates for many servers, you still need some way to make sure you are talking to the
     83 server you want. To address this, the certificate issued by the CA identifies the server
     84 either with a specific name such as <em>gmail.com</em> or a wildcarded set of
     85 hosts such as <em>*.google.com</em>. </p>
     86 
     87 <p>The following example will make these concepts a little more concrete. In the snippet below
     88 from a command line, the <a href="http://www.openssl.org/docs/apps/openssl.html">{@code openssl}</a>
     89 tool's {@code s_client} command looks at Wikipedia's server certificate information. It
     90 specifies port 443 because that is the default for <acronym title="Hypertext Transfer
     91 Protocol Secure">HTTPS</acronym>. The command sends
     92 the output of {@code openssl s_client} to {@code openssl x509}, which formats information
     93 about certificates according to the <a
     94 href="http://en.wikipedia.org/wiki/X.509">X.509 standard</a>. Specifically,
     95 the command asks for the subject, which contains the server name information,
     96 and the issuer, which identifies the CA.</p>
     97 
     98 <pre class="no-pretty-print">
     99 $ openssl s_client -connect wikipedia.org:443 | openssl x509 -noout -subject -issuer
    100 <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>
    101 <b>issuer=</b> /C=US/O=GeoTrust, Inc./CN=<b>RapidSSL CA</b>
    102 </pre>
    103 
    104 <p>You can see that the certificate was issued for servers matching <em>*.wikipedia.org</em> by
    105 the RapidSSL CA.</p>
    106 
    107 
    108 
    109 <h2 id="HttpsExample">An HTTPS Example</h2>
    110 
    111 <p>Assuming you have a web server with a
    112 certificate issued by a well known CA, you can make a secure request with code as
    113 simple this:</p>
    114 
    115 <pre>
    116 URL url = new URL("https://wikipedia.org");
    117 URLConnection urlConnection = url.openConnection();
    118 InputStream in = urlConnection.getInputStream();
    119 copyInputStreamToOutputStream(in, System.out);
    120 </pre>
    121 
    122 <p>Yes, it really can be that simple. If you want to tailor the HTTP request, you can cast to
    123 an {@link java.net.HttpURLConnection}. The Android documentation for
    124 {@link java.net.HttpURLConnection} has further examples about how to deal with request
    125 and response headers, posting content, managing cookies, using proxies, caching responses,
    126 and so on. But in terms of the details for verifying certificates and hostnames, the Android
    127 framework takes care of it for you through these APIs.
    128 This is where you want to be if at all possible. That said, below are some other considerations.</p>
    129 
    130 
    131 
    132 <h2 id="CommonProblems">Common Problems Verifying Server Certificates</h2>
    133 
    134 <p>Suppose instead of receiving the content from {@link java.net.URLConnection#getInputStream
    135 getInputStream()}, it throws an exception:</p>
    136 
    137 <pre class="no-pretty-print">
    138 javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
    139         at org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:374)
    140         at libcore.net.http.HttpConnection.setupSecureSocket(HttpConnection.java:209)
    141         at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.makeSslConnection(HttpsURLConnectionImpl.java:478)
    142         at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:433)
    143         at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
    144         at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
    145         at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
    146         at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
    147         at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
    148 </pre>
    149 
    150 <p>This can happen for several reasons, including:
    151 <ol>
    152   <li><a href="#UnknownCa">The CA that issued the server certificate was unknown</a></li>
    153   <li><a href="#SelfSigned">The server certificate wasn't signed by a CA, but was self signed</a></li>
    154   <li><a href="#MissingCa">The server configuration is missing an intermediate CA</a></li>
    155 </ol>
    156 
    157 <p>The following sections discuss how to address these problems while keeping your
    158 connection to the server secure.
    159 
    160 
    161 
    162 <h3 id="UnknownCa">Unknown certificate authority</h3>
    163 
    164 <p>In this case, the {@link javax.net.ssl.SSLHandshakeException} occurs
    165 because you have a CA that isn't trusted by the system. It could be because
    166 you have a certificate from a new CA that isn't yet trusted by Android or your app is
    167 running on an older version without the CA. More often a CA is unknown because it isn't a
    168 public CA, but a private one issued by an organization such as a government, corporation,
    169 or education institution for their own use.</p>
    170 
    171 <p>Fortunately, you can teach {@link javax.net.ssl.HttpsURLConnection}
    172 to trust a specific set of CAs. The procedure
    173 can be a little convoluted, so below is an example that takes a specific CA from
    174 an {@link java.io.InputStream}, uses it to create a {@link java.security.KeyStore},
    175 which is then used to create and initialize a
    176 {@link javax.net.ssl.TrustManager}. A {@link javax.net.ssl.TrustManager} is what the system
    177 uses to validate certificates from the server
    178 and&mdash;by creating one from a {@link java.security.KeyStore} with one or more CAs&mdash;those
    179 will be the only CAs trusted by that {@link javax.net.ssl.TrustManager}.</p>
    180 
    181 <p>Given the new {@link javax.net.ssl.TrustManager},
    182 the example initializes a new {@link javax.net.ssl.SSLContext} which provides
    183 an {@link javax.net.ssl.SSLSocketFactory} you can use to override the default
    184 {@link javax.net.ssl.SSLSocketFactory} from
    185 {@link javax.net.ssl.HttpsURLConnection}. This way the
    186 connection will use your CAs for certificate validation.</p>
    187 
    188 <p>Here is the example in
    189 full using an organizational CA from the University of Washington:</p>
    190 
    191 <pre>
    192 // Load CAs from an InputStream
    193 // (could be from a resource or ByteArrayInputStream or ...)
    194 CertificateFactory cf = CertificateFactory.getInstance("X.509");
    195 // From https://www.washington.edu/itconnect/security/ca/load-der.crt
    196 InputStream caInput = new BufferedInputStream(new FileInputStream("load-der.crt"));
    197 Certificate ca;
    198 try {
    199     ca = cf.generateCertificate(caInput);
    200     System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
    201 } finally {
    202     caInput.close();
    203 }
    204 
    205 // Create a KeyStore containing our trusted CAs
    206 String keyStoreType = KeyStore.getDefaultType();
    207 KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    208 keyStore.load(null, null);
    209 keyStore.setCertificateEntry("ca", ca);
    210 
    211 // Create a TrustManager that trusts the CAs in our KeyStore
    212 String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    213 TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    214 tmf.init(keyStore);
    215 
    216 // Create an SSLContext that uses our TrustManager
    217 SSLContext context = SSLContext.getInstance("TLS");
    218 context.init(null, tmf.getTrustManagers(), null);
    219 
    220 // Tell the URLConnection to use a SocketFactory from our SSLContext
    221 URL url = new URL("https://certs.cac.washington.edu/CAtest/");
    222 HttpsURLConnection urlConnection =
    223     (HttpsURLConnection)url.openConnection();
    224 urlConnection.setSSLSocketFactory(context.getSocketFactory());
    225 InputStream in = urlConnection.getInputStream();
    226 copyInputStreamToOutputStream(in, System.out);
    227 </pre>
    228 
    229 <p>With a custom {@link javax.net.ssl.TrustManager} that knows about your CAs,
    230 the system is able to validate
    231 that your server certificate come from a trusted issuer.</p>
    232 
    233 <p class="caution"><strong>Caution:</strong>
    234 Many web sites describe a poor alternative solution which is to install a
    235 {@link javax.net.ssl.TrustManager} that does nothing. If you do this you might as well not
    236 be encrypting your communication, because anyone can attack your users at a public Wi-Fi hotspot
    237 by using <acronym title="Domain Name System">DNS</acronym> tricks to send your users'
    238 traffic through a proxy of their own that pretends to be your server. The attacker can then
    239 record passwords and other personal data. This works because the attacker can generate a
    240 certificate and&mdash;without a {@link javax.net.ssl.TrustManager} that actually
    241 validates that the certificate comes from a trusted
    242 source&mdash;your app could be talking to anyone. So don't do this, not even temporarily. You can
    243 always make your app trust the issuer of the server's certificate, so just do it.</p>
    244 
    245 
    246 
    247 <h3 id="SelfSigned">Self-signed server certificate</h3>
    248 
    249 <p>The second case of {@link javax.net.ssl.SSLHandshakeException} is
    250 due to a self-signed certificate, which means the server is behaving as its own CA.
    251 This is similar to an unknown certificate authority, so you can use the
    252 same approach from the previous section.</p>
    253 
    254 <p>You can create your own {@link javax.net.ssl.TrustManager},
    255 this time trusting the server certificate directly. This has all of the
    256 downsides discussed earlier of tying your app directly to a certificate, but can be done
    257 securely. However, you should be careful to make sure your self-signed certificate has a
    258 reasonably strong key. As of 2012, a 2048-bit RSA signature with an exponent of 65537 expiring
    259 yearly is acceptable. When rotating keys, you should check for <a
    260 href="http://csrc.nist.gov/groups/ST/key_mgmt/index.html">recommendations</a> from an
    261 authority (such as <a href="http://www.nist.gov/">NIST</a>) about what is acceptable.</p>
    262 
    263 
    264 
    265 <h3 id="MissingCa">Missing intermediate certificate authority</h3>
    266 
    267 <p>The third case of {@link javax.net.ssl.SSLHandshakeException}
    268 occurs due to a missing intermediate CA. Most public
    269 CAs don't sign server certificates directly. Instead, they use their main CA certificate,
    270 referred to as the root CA, to sign intermediate CAs. They do this so the root CA can be stored
    271 offline to reduce risk of compromise. However, operating systems like Android typically
    272 trust only root CAs directly, which leaves a short gap of trust between the server
    273 certificate&mdash;signed by the intermediate CA&mdash;and the certificate verifier,
    274 which knows the root CA. To solve
    275 this, the server doesn't send the client only it's certificate during the SSL handshake, but
    276 a chain of certificates from the server CA through any intermediates necessary to reach a
    277 trusted root CA.</p>
    278 
    279 <p>To see what this looks like in practice, here's the <em>mail.google.com</em> certificate
    280 chain as viewed by the <a href="http://www.openssl.org/docs/apps/openssl.html">{@code openssl}</a>
    281 {@code s_client} command:</p>
    282 
    283 <pre class="no-pretty-print">
    284 $ openssl s_client -connect mail.google.com:443
    285 ---
    286 Certificate chain
    287  0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=mail.google.com
    288    i:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA
    289  1 s:/C=ZA/O=Thawte Consulting (Pty) Ltd./CN=Thawte SGC CA
    290    i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
    291 ---
    292 </pre>
    293 
    294 
    295 <p>This shows that the server sends a certificate for <em>mail.google.com</em>
    296 issued by the <em>Thawte SGC</em> CA, which is an intermediate CA, and a second certificate
    297 for the <em>Thawte SGC</em> CA issued by a <em>Verisign</em> CA, which is the primary CA that's
    298 trusted by Android.</p>
    299 
    300 <p>However, it is not uncommon to configure a server to not include the necessary
    301 intermediate CA. For example, here is a server that can cause an error in Android browsers and
    302 exceptions in Android apps:</p>
    303 
    304 <pre class="no-pretty-print">
    305 $ openssl s_client -connect egov.uscis.gov:443
    306 ---
    307 Certificate chain
    308  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
    309    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
    310 ---
    311 </pre>
    312 
    313 <p>What is interesting to note here is that visiting this server in most desktop browsers
    314 does not cause an error like a completely unknown CA or self-signed server certificate would
    315 cause. This is because most desktop browsers cache trusted intermediate CAs over time. Once
    316 a browser has visited and learned about an intermediate CA from one site, it won't
    317 need to have the intermediate CA included in the certificate chain the next time.</p>
    318 
    319 <p>Some sites do this intentionally for secondary web servers used to serve resources. For
    320 example, they might have their main HTML page served by a server with a full certificate
    321 chain, but have servers for resources such as images, CSS, or JavaScript not include the
    322 CA, presumably to save bandwidth. Unfortunately, sometimes these servers might be providing
    323 a web service you are trying to call from your Android app, which is not as forgiving.</p>
    324 
    325 <p>There are two approaches to solve this issue:</p>
    326 <ul>
    327   <li>Configure the server to
    328   include the intermediate CA in the server chain. Most CAs provide documentation on how to do
    329   this for all common web servers. This is the only approach if you need the site to work with
    330   default Android browsers at least through Android 4.2.</li>
    331   <li>Or, treat the
    332   intermediate CA like any other unknown CA, and create a {@link javax.net.ssl.TrustManager}
    333   to trust it directly, as done in the previous two sections.</li>
    334 </ul>
    335 
    336 
    337 <h2 id="CommonHostnameProbs">Common Problems with Hostname Verification</h2>
    338 
    339 <p>As mentioned at the beginning of this article,
    340 there are two key parts to verifying an SSL connection. The first
    341 is to verify the certificate is from a trusted source, which was the focus of the previous
    342 section. The focus of this section is the second part: making sure the server you are
    343 talking to presents the right certificate. When it doesn't, you'll typically see an error
    344 like this:</p>
    345 
    346 <pre class="no-pretty-print">
    347 java.io.IOException: Hostname 'example.com' was not verified
    348         at libcore.net.http.HttpConnection.verifySecureSocketHostname(HttpConnection.java:223)
    349         at libcore.net.http.HttpsURLConnectionImpl$HttpsEngine.connect(HttpsURLConnectionImpl.java:446)
    350         at libcore.net.http.HttpEngine.sendSocketRequest(HttpEngine.java:290)
    351         at libcore.net.http.HttpEngine.sendRequest(HttpEngine.java:240)
    352         at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:282)
    353         at libcore.net.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:177)
    354         at libcore.net.http.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:271)
    355 </pre>
    356 
    357 
    358 <p>One reason this can happen is due to a server configuration error. The server is
    359 configured with a certificate that does not have a subject or subject alternative name fields
    360 that match the server you are trying to reach. It is possible to have one certificate be used
    361 with many different servers. For example, looking at the <em>google.com</em> certificate with
    362 <a href="http://www.openssl.org/docs/apps/openssl.html">{@code openssl}</a> {@code
    363 s_client -connect google.com:443 | openssl x509 -text} you can see that a subject
    364 that supports <em>*.google.com</em> but also subject alternative names for <em>*.youtube.com</em>,
    365 <em>*.android.com</em>, and others. The error occurs only when the server name you
    366 are connecting to isn't listed by the certificate as acceptable.</p>
    367 
    368 <p>Unfortunately this can happen for another reason as well: <a
    369 href="http://en.wikipedia.org/wiki/Virtual_hosting">virtual hosting</a>. When sharing a
    370 server for more than one hostname with HTTP, the web server can tell from the HTTP/1.1 request
    371 which target hostname the client is looking for. Unfortunately this is complicated with
    372 HTTPS, because the server has to know which certificate to return before it sees the HTTP
    373 request. To address this problem, newer versions of SSL, specifically TLSv.1.0 and later,
    374 support <a href="http://en.wikipedia.org/wiki/Server_Name_Indication">Server Name Indication
    375 (SNI)</a>, which allows the SSL client to specify the intended
    376 hostname to the server so the proper certificate can be returned.</p>
    377 
    378 <p>Fortunately, {@link javax.net.ssl.HttpsURLConnection} supports
    379 SNI since Android 2.3. One workaround
    380 if you need to support Android 2.2 (and older) 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     &#64;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 <h2 id="nogotofail">
    515   Nogotofail: A Network Traffic Security Testing Tool
    516 </h2>
    517 
    518 <p>
    519   Nogotofail is a tool gives you an easy way to confirm that your apps are safe
    520   against known TLS/SSL vulnerabilities and misconfigurations. It's an
    521   automated, powerful, and scalable tool for testing network security issues on
    522   any device whose network traffic could be made to go through it. </p>
    523 
    524   <p>Nogotofail is useful for three main use cases:
    525 </p>
    526 
    527 <ul>
    528   <li>Finding bugs and vulnerabilities.
    529   </li>
    530 
    531   <li>Verifying fixes and watching for regressions.
    532   </li>
    533 
    534   <li>Understanding what applications and devices are generating what traffic.
    535   </li>
    536 </ul>
    537 
    538 <p>
    539   Nogotofail works for Android, iOS, Linux, Windows, Chrome OS, OSX, in fact
    540   any device you use to connect to the Internet. Theres an easy-to-use client
    541   to configure the settings and get notifications on Android and Linux, as well
    542   as the attack engine itself which can be deployed as a router, VPN server, or
    543   proxy.
    544 </p>
    545 
    546 <p>
    547   You can access the tool at the <a href=
    548   "https://github.com/google/nogotofail">Nogotofail open source project</a>.
    549 </p>
    550 
    551 
    552 
    553 
    554 
    555 
    556 
    557 
    558 
    559 
    560 
    561 
    562 
    563 
    564 
    565 
    566 
    567 
    568 
    569 
    570 
    571 
    572 
    573 
    574 
    575 
    576