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