1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 /*
3  * Copyright (C) 2016 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 // License from Apache Harmony:
19 /*
20  *  Licensed to the Apache Software Foundation (ASF) under one or more
21  *  contributor license agreements.  See the NOTICE file distributed with
22  *  this work for additional information regarding copyright ownership.
23  *  The ASF licenses this file to You under the Apache License, Version 2.0
24  *  (the "License"); you may not use this file except in compliance with
25  *  the License.  You may obtain a copy of the License at
26  *
27  *     http://www.apache.org/licenses/LICENSE-2.0
28  *
29  *  Unless required by applicable law or agreed to in writing, software
30  *  distributed under the License is distributed on an "AS IS" BASIS,
31  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32  *  See the License for the specific language governing permissions and
33  *  limitations under the License.
34  */
35 
36 package com.android.org.conscrypt;
37 
38 import com.android.org.conscrypt.ct.CTLogStore;
39 import com.android.org.conscrypt.ct.CTPolicy;
40 import com.android.org.conscrypt.ct.CTVerificationResult;
41 import com.android.org.conscrypt.ct.CTVerifier;
42 import java.lang.reflect.InvocationTargetException;
43 import java.lang.reflect.Method;
44 import java.net.Socket;
45 import java.security.InvalidAlgorithmParameterException;
46 import java.security.KeyStore;
47 import java.security.KeyStoreException;
48 import java.security.cert.CertPath;
49 import java.security.cert.CertPathValidator;
50 import java.security.cert.CertPathValidatorException;
51 import java.security.cert.Certificate;
52 import java.security.cert.CertificateException;
53 import java.security.cert.CertificateFactory;
54 import java.security.cert.CertificateParsingException;
55 import java.security.cert.PKIXCertPathChecker;
56 import java.security.cert.PKIXParameters;
57 import java.security.cert.PKIXRevocationChecker;
58 import java.security.cert.PKIXRevocationChecker.Option;
59 import java.security.cert.TrustAnchor;
60 import java.security.cert.X509Certificate;
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.Collection;
64 import java.util.Collections;
65 import java.util.Comparator;
66 import java.util.Enumeration;
67 import java.util.HashSet;
68 import java.util.List;
69 import java.util.Set;
70 import java.util.logging.Logger;
71 import javax.net.ssl.HttpsURLConnection;
72 import javax.net.ssl.SSLEngine;
73 import javax.net.ssl.SSLParameters;
74 import javax.net.ssl.SSLSession;
75 import javax.net.ssl.SSLSocket;
76 import javax.net.ssl.X509ExtendedTrustManager;
77 
78 /**
79  *
80  * TrustManager implementation. The implementation is based on CertPathValidator
81  * PKIX and CertificateFactory X509 implementations. This implementations should
82  * be provided by some certification provider.
83  *
84  * @see javax.net.ssl.X509ExtendedTrustManager
85  * @hide This class is not part of the Android public SDK API
86  */
87 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
88 @Internal
89 public final class TrustManagerImpl extends X509ExtendedTrustManager {
90     private static final Logger logger = Logger.getLogger(TrustManagerImpl.class.getName());
91 
92     /**
93      * Comparator used for ordering trust anchors during certificate path building.
94      */
95     private static final TrustAnchorComparator TRUST_ANCHOR_COMPARATOR =
96             new TrustAnchorComparator();
97 
98     private static ConscryptHostnameVerifier defaultHostnameVerifier;
99 
100     /**
101      * The AndroidCAStore if non-null, null otherwise.
102      */
103     private final KeyStore rootKeyStore;
104 
105     /**
106      * The CertPinManager, which validates the chain against a host-to-pin mapping
107      */
108     private CertPinManager pinManager;
109 
110     /**
111      * The backing store for the AndroidCAStore if non-null. This will
112      * be null when the rootKeyStore is null, implying we are not
113      * using the AndroidCAStore.
114      */
115     private final ConscryptCertStore trustedCertificateStore;
116 
117     private final CertPathValidator validator;
118 
119     /**
120      * An index of TrustAnchor instances that we've seen.
121      */
122     private final TrustedCertificateIndex trustedCertificateIndex;
123 
124     /**
125      * An index of intermediate certificates that we've seen. These certificates are NOT implicitly
126      * trusted and must still form a valid chain to an anchor.
127      */
128     private final TrustedCertificateIndex intermediateIndex;
129 
130     /**
131      * This is lazily initialized in the AndroidCAStore case since it
132      * forces us to bring all the CAs into memory. In the
133      * non-AndroidCAStore, we initialize this as part of the
134      * constructor.
135      */
136     private final X509Certificate[] acceptedIssuers;
137 
138     private final Exception err;
139     private final CertificateFactory factory;
140     private final CertBlocklist blocklist;
141     private CTVerifier ctVerifier;
142     private CTPolicy ctPolicy;
143 
144     private ConscryptHostnameVerifier hostnameVerifier;
145 
146     // Forces CT verification to always to done. For tests.
147     private boolean ctEnabledOverride;
148 
149     /**
150      * Creates X509TrustManager based on a keystore
151      */
152     @android.compat.annotation
153             .UnsupportedAppUsage
154             @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
TrustManagerImpl(KeyStore keyStore)155             public TrustManagerImpl(KeyStore keyStore) {
156         this(keyStore, null);
157     }
158 
TrustManagerImpl(KeyStore keyStore, CertPinManager manager)159     public TrustManagerImpl(KeyStore keyStore, CertPinManager manager) {
160         this(keyStore, manager, null);
161     }
162 
163     @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
TrustManagerImpl( KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore)164     public TrustManagerImpl(
165             KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore) {
166         this(keyStore, manager, certStore, null);
167     }
168 
TrustManagerImpl(KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore, CertBlocklist blocklist)169     public TrustManagerImpl(KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore,
170             CertBlocklist blocklist) {
171         this(keyStore, manager, certStore, blocklist, null, null, null);
172     }
173 
174     /**
175      * For testing only.
176      */
TrustManagerImpl(KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore, CertBlocklist blocklist, CTLogStore ctLogStore, CTVerifier ctVerifier, CTPolicy ctPolicy)177     public TrustManagerImpl(KeyStore keyStore, CertPinManager manager, ConscryptCertStore certStore,
178             CertBlocklist blocklist, CTLogStore ctLogStore, CTVerifier ctVerifier,
179             CTPolicy ctPolicy) {
180         CertPathValidator validatorLocal = null;
181         CertificateFactory factoryLocal = null;
182         KeyStore rootKeyStoreLocal = null;
183         ConscryptCertStore trustedCertificateStoreLocal = null;
184         TrustedCertificateIndex trustedCertificateIndexLocal = null;
185         X509Certificate[] acceptedIssuersLocal = null;
186         Exception errLocal = null;
187         try {
188             validatorLocal = CertPathValidator.getInstance("PKIX");
189             factoryLocal = CertificateFactory.getInstance("X509");
190 
191             // if we have an AndroidCAStore, we will lazily load CAs
192             if ("AndroidCAStore".equals(keyStore.getType())
193                     && Platform.supportsConscryptCertStore()) {
194                 rootKeyStoreLocal = keyStore;
195                 trustedCertificateStoreLocal =
196                     (certStore != null) ? certStore : Platform.newDefaultCertStore();
197                 acceptedIssuersLocal = null;
198                 trustedCertificateIndexLocal = new TrustedCertificateIndex();
199             } else {
200                 rootKeyStoreLocal = null;
201                 trustedCertificateStoreLocal = certStore;
202                 acceptedIssuersLocal = acceptedIssuers(keyStore);
203                 trustedCertificateIndexLocal
204                         = new TrustedCertificateIndex(trustAnchors(acceptedIssuersLocal));
205             }
206 
207         } catch (Exception e) {
208             errLocal = e;
209         }
210 
211         if (blocklist == null) {
212             blocklist = Platform.newDefaultBlocklist();
213         }
214         if (ctLogStore == null) {
215             ctLogStore = Platform.newDefaultLogStore();
216         }
217 
218         if (ctPolicy == null) {
219             ctPolicy = Platform.newDefaultPolicy(ctLogStore);
220         }
221 
222         this.pinManager = manager;
223         this.rootKeyStore = rootKeyStoreLocal;
224         this.trustedCertificateStore = trustedCertificateStoreLocal;
225         this.validator = validatorLocal;
226         this.factory = factoryLocal;
227         this.trustedCertificateIndex = trustedCertificateIndexLocal;
228         this.intermediateIndex = new TrustedCertificateIndex();
229         this.acceptedIssuers = acceptedIssuersLocal;
230         this.err = errLocal;
231         this.blocklist = blocklist;
232         this.ctVerifier = new CTVerifier(ctLogStore);
233         this.ctPolicy = ctPolicy;
234     }
235 
236     @SuppressWarnings("JdkObsolete") // KeyStore#aliases is the only API available
acceptedIssuers(KeyStore ks)237     private static X509Certificate[] acceptedIssuers(KeyStore ks) {
238         try {
239             // Note that unlike the PKIXParameters code to create a Set of
240             // TrustAnchors from a KeyStore, this version takes from both
241             // TrustedCertificateEntry and PrivateKeyEntry, not just
242             // TrustedCertificateEntry, which is why TrustManagerImpl
243             // cannot just use an PKIXParameters(KeyStore)
244             // constructor.
245 
246             // TODO remove duplicates if same cert is found in both a
247             // PrivateKeyEntry and TrustedCertificateEntry
248             List<X509Certificate> trusted = new ArrayList<X509Certificate>();
249             for (Enumeration<String> en = ks.aliases(); en.hasMoreElements();) {
250                 final String alias = en.nextElement();
251                 final X509Certificate cert = (X509Certificate) ks.getCertificate(alias);
252                 if (cert != null) {
253                     trusted.add(cert);
254                 }
255             }
256             return trusted.toArray(new X509Certificate[trusted.size()]);
257         } catch (KeyStoreException e) {
258             return new X509Certificate[0];
259         }
260     }
261 
trustAnchors(X509Certificate[] certs)262     private static Set<TrustAnchor> trustAnchors(X509Certificate[] certs) {
263         Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>(certs.length);
264         for (X509Certificate cert : certs) {
265             trustAnchors.add(new TrustAnchor(cert, null));
266         }
267         return trustAnchors;
268     }
269 
270     @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
271     @Override
checkClientTrusted(X509Certificate[] chain, String authType)272     public void checkClientTrusted(X509Certificate[] chain, String authType)
273             throws CertificateException {
274         checkTrusted(chain, authType, null, null, true /* client auth */);
275     }
276 
277     /**
278      * For backward compatibility with older Android API that used String for the hostname only.
279      */
checkClientTrusted(X509Certificate[] chain, String authType, String hostname)280     public List<X509Certificate> checkClientTrusted(X509Certificate[] chain, String authType,
281             String hostname) throws CertificateException {
282         return checkTrusted(chain, null /* ocspData */, null /* tlsSctData */, authType, hostname,
283                 true);
284     }
285 
getHandshakeSessionOrThrow(SSLSocket sslSocket)286     private static SSLSession getHandshakeSessionOrThrow(SSLSocket sslSocket)
287             throws CertificateException {
288         SSLSession session = sslSocket.getHandshakeSession();
289         if (session == null) {
290             throw new CertificateException("Not in handshake; no session available");
291         }
292         return session;
293     }
294 
295     @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
296     @Override
checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)297     public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)
298             throws CertificateException {
299         SSLSession session = null;
300         SSLParameters parameters = null;
301         if (socket instanceof SSLSocket) {
302             SSLSocket sslSocket = (SSLSocket) socket;
303             session = getHandshakeSessionOrThrow(sslSocket);
304             parameters = sslSocket.getSSLParameters();
305         }
306         checkTrusted(chain, authType, session, parameters, true /* client auth */);
307     }
308 
309     @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
310     @Override
checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)311     public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
312             throws CertificateException {
313         SSLSession session = engine.getHandshakeSession();
314         if (session == null) {
315             throw new CertificateException("Not in handshake; no session available");
316         }
317         checkTrusted(chain, authType, session, engine.getSSLParameters(), true /* client auth */);
318     }
319 
320     @Override
checkServerTrusted(X509Certificate[] chain, String authType)321     public void checkServerTrusted(X509Certificate[] chain, String authType)
322             throws CertificateException {
323         checkTrusted(chain, authType, null, null, false /* client auth */);
324     }
325 
326     /**
327      * For backward compatibility with older Android API that used String for the hostname only.
328      */
329     @android.compat.annotation
330             .UnsupportedAppUsage
331             @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
checkServerTrusted(X509Certificate[] chain, String authType, String hostname)332             public List<X509Certificate> checkServerTrusted(X509Certificate[] chain,
333                     String authType, String hostname) throws CertificateException {
334         return checkTrusted(chain, null /* ocspData */, null /* tlsSctData */, authType, hostname,
335                 false);
336     }
337 
338     /**
339      * Returns the full trusted certificate chain found from {@code certs}.
340      *
341      * Throws {@link CertificateException} when no trusted chain can be found from {@code certs}.
342      */
343     @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
getTrustedChainForServer( X509Certificate[] certs, String authType, Socket socket)344     public List<X509Certificate> getTrustedChainForServer(
345             X509Certificate[] certs, String authType, Socket socket) throws CertificateException {
346         SSLSession session = null;
347         SSLParameters parameters = null;
348         if (socket instanceof SSLSocket) {
349             SSLSocket sslSocket = (SSLSocket) socket;
350             session = getHandshakeSessionOrThrow(sslSocket);
351             parameters = sslSocket.getSSLParameters();
352         }
353         return checkTrusted(certs, authType, session, parameters, false /* client auth */);
354     }
355 
356     /**
357      * Returns the full trusted certificate chain found from {@code certs}.
358      *
359      * Throws {@link CertificateException} when no trusted chain can be found from {@code certs}.
360      */
361     @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
getTrustedChainForServer(X509Certificate[] certs, String authType, SSLEngine engine)362     public List<X509Certificate> getTrustedChainForServer(X509Certificate[] certs, String authType,
363             SSLEngine engine) throws CertificateException {
364         SSLSession session = engine.getHandshakeSession();
365         if (session == null) {
366             throw new CertificateException("Not in handshake; no session available");
367         }
368         return checkTrusted(certs, authType, session, engine.getSSLParameters(),
369                 false /* client auth */);
370     }
371 
372     @Override
checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)373     public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)
374             throws CertificateException {
375         getTrustedChainForServer(chain, authType, socket);
376     }
377 
378     @Override
checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)379     public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)
380             throws CertificateException {
381         getTrustedChainForServer(chain, authType, engine);
382     }
383 
384     /**
385      * Validates whether a server is trusted. If session is given and non-null
386      * it also checks if chain is pinned appropriately for that peer host. If
387      * null, it does not check for pinned certs. The return value is a list of
388      * the certificates used for making the trust decision.
389      */
checkServerTrusted(X509Certificate[] chain, String authType, SSLSession session)390     public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
391             SSLSession session) throws CertificateException {
392         return checkTrusted(chain, authType, session, null, false /* client auth */);
393     }
394 
395     @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
handleTrustStorageUpdate()396     public void handleTrustStorageUpdate() {
397         if (acceptedIssuers == null) {
398             trustedCertificateIndex.reset();
399         } else {
400             trustedCertificateIndex.reset(trustAnchors(acceptedIssuers));
401         }
402     }
403 
checkTrusted(X509Certificate[] certs, String authType, SSLSession session, SSLParameters parameters, boolean clientAuth)404     private List<X509Certificate> checkTrusted(X509Certificate[] certs, String authType,
405             SSLSession session, SSLParameters parameters, boolean clientAuth)
406                     throws CertificateException {
407         byte[] ocspData = null;
408         byte[] tlsSctData = null;
409         String hostname = null;
410         if (session != null) {
411             hostname = session.getPeerHost();
412             ocspData = getOcspDataFromSession(session);
413             tlsSctData = getTlsSctDataFromSession(session);
414         }
415 
416         if (session != null && parameters != null) {
417             String identificationAlgorithm = parameters.getEndpointIdentificationAlgorithm();
418             if ("HTTPS".equalsIgnoreCase(identificationAlgorithm)) {
419                 ConscryptHostnameVerifier verifier = getHttpsVerifier();
420                 if (!verifier.verify(certs, hostname, session)) {
421                     throw new CertificateException("No subjectAltNames on the certificate match");
422                 }
423             }
424         }
425         return checkTrusted(certs, ocspData, tlsSctData, authType, hostname, clientAuth);
426     }
427 
428     @SuppressWarnings("unchecked")
getOcspDataFromSession(SSLSession session)429     private static byte[] getOcspDataFromSession(SSLSession session) {
430         List<byte[]> ocspResponses = null;
431         if (session instanceof ConscryptSession) {
432             ConscryptSession opensslSession = (ConscryptSession) session;
433             ocspResponses = opensslSession.getStatusResponses();
434         } else {
435             Method m_getResponses;
436             try {
437                 m_getResponses = session.getClass().getDeclaredMethod("getStatusResponses");
438                 m_getResponses.setAccessible(true);
439                 Object rawResponses = m_getResponses.invoke(session);
440                 if (rawResponses instanceof List) {
441                     ocspResponses = (List<byte[]>) rawResponses;
442                 }
443             } catch (NoSuchMethodException | SecurityException | IllegalAccessException
444                     | IllegalArgumentException ignored) {
445                 // Method not available, fall through and return null
446             } catch (InvocationTargetException e) {
447                 throw new RuntimeException(e.getCause());
448             }
449         }
450 
451         if (ocspResponses == null || ocspResponses.isEmpty()) {
452             return null;
453         }
454 
455         return ocspResponses.get(0);
456     }
457 
getTlsSctDataFromSession(SSLSession session)458     private byte[] getTlsSctDataFromSession(SSLSession session) {
459         if (session instanceof ConscryptSession) {
460             ConscryptSession opensslSession = (ConscryptSession) session;
461             return opensslSession.getPeerSignedCertificateTimestamp();
462         }
463 
464         byte[] data = null;
465         try {
466             Method m_getTlsSctData = session.getClass().getDeclaredMethod("getPeerSignedCertificateTimestamp");
467             m_getTlsSctData.setAccessible(true);
468             Object rawData = m_getTlsSctData.invoke(session);
469             if (rawData instanceof byte[]) {
470                 data = (byte[]) rawData;
471             }
472         } catch (NoSuchMethodException | SecurityException | IllegalAccessException
473                 | IllegalArgumentException ignored) {
474             // Method not available, fall through and return null
475         } catch (InvocationTargetException e) {
476             throw new RuntimeException(e.getCause());
477         }
478         return data;
479     }
480 
checkTrusted(X509Certificate[] certs, byte[] ocspData, byte[] tlsSctData, String authType, String host, boolean clientAuth)481     private List<X509Certificate> checkTrusted(X509Certificate[] certs, byte[] ocspData,
482             byte[] tlsSctData, String authType, String host, boolean clientAuth)
483             throws CertificateException {
484         if (certs == null || certs.length == 0 || authType == null || authType.length() == 0) {
485             throw new IllegalArgumentException("null or zero-length parameter");
486         }
487         if (err != null) {
488             throw new CertificateException(err);
489         }
490         Set<X509Certificate> used = new HashSet<X509Certificate>();
491         ArrayList<X509Certificate> untrustedChain = new ArrayList<X509Certificate>();
492         ArrayList<TrustAnchor> trustedChain = new ArrayList<TrustAnchor>();
493         // Initialize the chain to contain the leaf certificate. This potentially could be a trust
494         // anchor. If the leaf is a trust anchor we still continue with path building to build the
495         // complete trusted chain for additional validation such as certificate pinning.
496         X509Certificate leaf = certs[0];
497         TrustAnchor leafAsAnchor = findTrustAnchorBySubjectAndPublicKey(leaf);
498         if (leafAsAnchor != null) {
499             trustedChain.add(leafAsAnchor);
500             used.add(leafAsAnchor.getTrustedCert());
501         } else {
502             untrustedChain.add(leaf);
503         }
504         used.add(leaf);
505         return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth,
506                 untrustedChain, trustedChain, used);
507     }
508 
509     /**
510      * Recursively build certificate chains until a valid chain is found or all possible paths are
511      * exhausted.
512      *
513      * The chain is built in two sections, the complete trusted path is the the combination of
514      * {@code untrustedChain} and {@code trustAnchorChain}. The chain begins at the leaf
515      * certificate and ends in the final trusted root certificate.
516      *
517      * @param certs the bag of certs provided by the peer. No order is assumed.
518      * @param host the host being connected to.
519      * @param clientAuth if a client is being authorized instead of a server.
520      * @param untrustedChain the untrusted section of the chain built so far. Must be mutable.
521      * @param trustAnchorChain the trusted section of the chain built so far. Must be mutable.
522      * @param used the set certificates used so far in path building. Must be mutable.
523      *
524      * @return The entire valid chain starting with the leaf certificate. This is the
525      * concatenation of untrustedChain and trustAnchorChain.
526      *
527      * @throws CertificateException If no valid chain could be constructed. Note that there may be
528      * multiple reasons why no valid chain exists and there is no guarantee that the most severe is
529      * reported in this exception. As such applications MUST NOT use the specifics of this error
530      * for trust decisions (e.g. showing the user a click through page based on the specific error).
531      */
checkTrustedRecursive(X509Certificate[] certs, byte[] ocspData, byte[] tlsSctData, String host, boolean clientAuth, ArrayList<X509Certificate> untrustedChain, ArrayList<TrustAnchor> trustAnchorChain, Set<X509Certificate> used)532     private List<X509Certificate> checkTrustedRecursive(X509Certificate[] certs, byte[] ocspData,
533             byte[] tlsSctData, String host, boolean clientAuth,
534             ArrayList<X509Certificate> untrustedChain, ArrayList<TrustAnchor> trustAnchorChain,
535             Set<X509Certificate> used) throws CertificateException {
536         CertificateException lastException = null;
537         X509Certificate current;
538         if (trustAnchorChain.isEmpty()) {
539             current = untrustedChain.get(untrustedChain.size() - 1);
540         } else {
541             current = trustAnchorChain.get(trustAnchorChain.size() - 1).getTrustedCert();
542         }
543 
544         // Check that the certificate isn't blocklisted.
545         checkBlocklist(current);
546 
547         // 1. If the current certificate in the chain is self-signed verify the chain as is.
548         if (current.getIssuerDN().equals(current.getSubjectDN())) {
549             return verifyChain(untrustedChain, trustAnchorChain, host, clientAuth, ocspData,
550                     tlsSctData);
551         }
552 
553         // 2. Try building a chain via any trust anchors that issued the current certificate.
554         // Note that we do not stop at the first trust anchor since it is possible that the trust
555         // anchor is not self-signed and its issuer may be needed for additional validation such as
556         // certificate pinning. In the common case the first trust anchor will be self-signed or
557         // its issuer's certificate will be missing.
558         Set<TrustAnchor> anchors = findAllTrustAnchorsByIssuerAndSignature(current);
559         boolean seenIssuer = false;
560         for (TrustAnchor anchor : sortPotentialAnchors(anchors)) {
561             X509Certificate anchorCert = anchor.getTrustedCert();
562             // Avoid using certificates that have already been used.
563             if (used.contains(anchorCert)) {
564                 continue;
565             }
566             seenIssuer = true;
567             used.add(anchorCert);
568             trustAnchorChain.add(anchor);
569             try {
570                 return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth,
571                         untrustedChain, trustAnchorChain, used);
572             } catch (CertificateException ex) {
573                 lastException = ex;
574             }
575             // Could not form a valid chain via this certificate, remove it from this chain.
576             trustAnchorChain.remove(trustAnchorChain.size() - 1);
577             used.remove(anchorCert);
578         }
579 
580         // 3. If we were unable to find additional trusted issuers, verify the current chain.
581         // This may happen if the root of trust is not self-signed and the issuer is not
582         // present in the trusted set.
583         if (!trustAnchorChain.isEmpty()) {
584             if (!seenIssuer) {
585                 return verifyChain(untrustedChain, trustAnchorChain, host, clientAuth, ocspData,
586                         tlsSctData);
587             }
588 
589             // Otherwise all chains based on the current trust anchor were rejected, fail.
590             throw lastException;
591         }
592 
593         // 4. Use the certificates provided by the peer to grow the chain.
594         // Ignore the first certificate, as that is the leaf certificate.
595         for (int i = 1; i < certs.length; i++) {
596             X509Certificate candidateIssuer = certs[i];
597             // Avoid using certificates that have already been used.
598             if (used.contains(candidateIssuer)) {
599                 continue;
600             }
601             if (current.getIssuerDN().equals(candidateIssuer.getSubjectDN())) {
602                 // Check the strength and validity of the certificate to prune bad certificates
603                 // early.
604                 try {
605                     candidateIssuer.checkValidity();
606                     ChainStrengthAnalyzer.checkCert(candidateIssuer);
607                 } catch (CertificateException ex) {
608                     lastException = new CertificateException("Unacceptable certificate: "
609                             + candidateIssuer.getSubjectX500Principal(), ex);
610                     continue;
611                 }
612                 used.add(candidateIssuer);
613                 untrustedChain.add(candidateIssuer);
614                 try {
615                     return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth,
616                             untrustedChain, trustAnchorChain, used);
617                 } catch (CertificateException ex) {
618                     lastException = ex;
619                 }
620                 // Could not form a valid chain via this certificate, remove it from this chain.
621                 used.remove(candidateIssuer);
622                 untrustedChain.remove(untrustedChain.size() - 1);
623             }
624         }
625 
626         // 5. Finally try the cached intermediates to handle server that failed to send them.
627         Set<TrustAnchor> intermediateAnchors =
628                 intermediateIndex.findAllByIssuerAndSignature(current);
629         for (TrustAnchor intermediate : sortPotentialAnchors(intermediateAnchors)) {
630             X509Certificate intermediateCert = intermediate.getTrustedCert();
631             // Avoid using certificates that have already been used.
632             if (used.contains(intermediateCert)) {
633                 continue;
634             }
635             used.add(intermediateCert);
636             untrustedChain.add(intermediateCert);
637             try {
638                 return checkTrustedRecursive(certs, ocspData, tlsSctData, host, clientAuth,
639                         untrustedChain, trustAnchorChain, used);
640             } catch (CertificateException ex) {
641                 lastException = ex;
642             }
643             // Could not form a valid chain via this certificate, remove it from this chain.
644             untrustedChain.remove(untrustedChain.size() - 1);
645             used.remove(intermediateCert);
646         }
647 
648         // 6. We were unable to build a valid chain, throw the last error encountered.
649         if (lastException != null) {
650             throw lastException;
651         }
652 
653         // 7. If no errors were encountered above then verifyChain was never called because it was
654         // not possible to build a valid chain to a trusted certificate.
655         CertPath certPath = factory.generateCertPath(untrustedChain);
656         throw new CertificateException(new CertPathValidatorException(
657                 "Trust anchor for certification path not found.", null, certPath, -1));
658     }
659 
verifyChain(List<X509Certificate> untrustedChain, List<TrustAnchor> trustAnchorChain, String host, boolean clientAuth, byte[] ocspData, byte[] tlsSctData)660     private List<X509Certificate> verifyChain(List<X509Certificate> untrustedChain,
661             List<TrustAnchor> trustAnchorChain, String host, boolean clientAuth, byte[] ocspData,
662             byte[] tlsSctData)
663             throws CertificateException {
664         try {
665             // build the cert path from the list of certs sans trust anchors
666             // TODO: check whether this is slow and should be replaced by a minimalistic CertPath impl
667             // since we already have built the path.
668             CertPath certPath = factory.generateCertPath(untrustedChain);
669 
670             // Check that there are at least some trust anchors
671             if (trustAnchorChain.isEmpty()) {
672                 throw new CertificateException(new CertPathValidatorException(
673                         "Trust anchor for certification path not found.", null, certPath, -1));
674             }
675 
676             List<X509Certificate> wholeChain = new ArrayList<X509Certificate>();
677             wholeChain.addAll(untrustedChain);
678             for (TrustAnchor anchor : trustAnchorChain) {
679                 wholeChain.add(anchor.getTrustedCert());
680             }
681 
682             if (pinManager != null) {
683                 pinManager.checkChainPinning(host, wholeChain);
684             }
685             // Check whole chain against the blocklist
686             for (X509Certificate cert : wholeChain) {
687                 checkBlocklist(cert);
688             }
689 
690             // Check CT (if required).
691             if (!clientAuth &&
692                     (ctEnabledOverride || (host != null && Platform
693                             .isCTVerificationRequired(host)))) {
694                 checkCT(host, wholeChain, ocspData, tlsSctData);
695             }
696 
697             if (untrustedChain.isEmpty()) {
698                 // The chain consists of only trust anchors, skip the validator
699                 return wholeChain;
700             }
701 
702             ChainStrengthAnalyzer.check(untrustedChain);
703 
704             // Validate the untrusted part of the chain
705             try {
706                 Set<TrustAnchor> anchorSet = new HashSet<TrustAnchor>();
707                 // We know that untrusted chains to the first trust anchor, only add that.
708                 anchorSet.add(trustAnchorChain.get(0));
709                 PKIXParameters params = new PKIXParameters(anchorSet);
710                 params.setRevocationEnabled(false);
711                 X509Certificate endPointCert = untrustedChain.get(0);
712                 setOcspResponses(params, endPointCert, ocspData);
713                 params.addCertPathChecker(
714                         new ExtendedKeyUsagePKIXCertPathChecker(clientAuth, endPointCert));
715                 validator.validate(certPath, params);
716             } catch (InvalidAlgorithmParameterException e) {
717                 throw new CertificateException("Chain validation failed", e);
718             } catch (CertPathValidatorException e) {
719                 throw new CertificateException("Chain validation failed", e);
720             }
721             // Add intermediate CAs to the index to tolerate sites
722             // that assume that the browser will have cached these.
723             // http://b/3404902
724             for (int i = 1; i < untrustedChain.size(); i++) {
725                 intermediateIndex.index(untrustedChain.get(i));
726             }
727             return wholeChain;
728         } catch (CertificateException e) {
729             logger.fine("Rejected candidate cert chain due to error: " + e.getMessage());
730             throw e;
731         }
732     }
733 
checkBlocklist(X509Certificate cert)734     private void checkBlocklist(X509Certificate cert) throws CertificateException {
735         if (blocklist != null && blocklist.isPublicKeyBlockListed(cert.getPublicKey())) {
736             throw new CertificateException("Certificate blocklisted by public key: " + cert);
737         }
738     }
739 
checkCT(String host, List<X509Certificate> chain, byte[] ocspData, byte[] tlsData)740     private void checkCT(String host, List<X509Certificate> chain, byte[] ocspData, byte[] tlsData)
741             throws CertificateException {
742         CTVerificationResult result =
743                 ctVerifier.verifySignedCertificateTimestamps(chain, tlsData, ocspData);
744 
745         if (!ctPolicy.doesResultConformToPolicy(result, host,
746                     chain.toArray(new X509Certificate[chain.size()]))) {
747             throw new CertificateException(
748                     "Certificate chain does not conform to required transparency policy.");
749         }
750     }
751 
752     /**
753      * Sets the OCSP response data that was possibly stapled to the TLS response.
754      */
setOcspResponses(PKIXParameters params, X509Certificate cert, byte[] ocspData)755     private void setOcspResponses(PKIXParameters params, X509Certificate cert, byte[] ocspData) {
756         if (ocspData == null) {
757             return;
758         }
759 
760         PKIXRevocationChecker revChecker = null;
761         List<PKIXCertPathChecker> checkers =
762                 new ArrayList<PKIXCertPathChecker>(params.getCertPathCheckers());
763         for (PKIXCertPathChecker checker : checkers) {
764             if (checker instanceof PKIXRevocationChecker) {
765                 revChecker = (PKIXRevocationChecker) checker;
766                 break;
767             }
768         }
769 
770         if (revChecker == null) {
771             // Only new CertPathValidatorSpi instances will support the
772             // revocation checker API.
773             try {
774                 revChecker = (PKIXRevocationChecker) validator.getRevocationChecker();
775             } catch (UnsupportedOperationException e) {
776                 return;
777             }
778 
779             checkers.add(revChecker);
780 
781             /*
782              * If we add a new revocation checker, we should set the option for
783              * end-entity verification only. Otherwise the CertPathValidator will
784              * throw an exception when it can't verify the entire chain.
785              */
786             revChecker.setOptions(Collections.singleton(Option.ONLY_END_ENTITY));
787         }
788 
789         revChecker.setOcspResponses(Collections.singletonMap(cert, ocspData));
790         params.setCertPathCheckers(checkers);
791     }
792 
793     /**
794      * Sort potential anchors so that the most preferred for use come first.
795      *
796      * @see CertificatePriorityComparator
797      */
sortPotentialAnchors(Set<TrustAnchor> anchors)798     private static Collection<TrustAnchor> sortPotentialAnchors(Set<TrustAnchor> anchors) {
799         if (anchors.size() <= 1) {
800             return anchors;
801         }
802         List<TrustAnchor> sortedAnchors = new ArrayList<TrustAnchor>(anchors);
803         Collections.sort(sortedAnchors, TRUST_ANCHOR_COMPARATOR);
804         return sortedAnchors;
805     }
806 
807 
808     /**
809      * Comparator for sorting {@link TrustAnchor}s using a {@link CertificatePriorityComparator}.
810      */
811     private static class TrustAnchorComparator implements Comparator<TrustAnchor> {
812         private static final CertificatePriorityComparator CERT_COMPARATOR =
813                 new CertificatePriorityComparator();
814         @Override
compare(TrustAnchor lhs, TrustAnchor rhs)815         public int compare(TrustAnchor lhs, TrustAnchor rhs) {
816             X509Certificate lhsCert = lhs.getTrustedCert();
817             X509Certificate rhsCert = rhs.getTrustedCert();
818             return CERT_COMPARATOR.compare(lhsCert, rhsCert);
819         }
820     }
821 
822     /**
823      * If an EKU extension is present in the end-entity certificate,
824      * it MUST contain an appropriate key usage. For servers, this
825      * includes anyExtendedKeyUsage, serverAuth, or the historical
826      * Server Gated Cryptography options of nsSGC or msSGC.  For
827      * clients, this includes anyExtendedKeyUsage and clientAuth.
828      */
829     private static class ExtendedKeyUsagePKIXCertPathChecker extends PKIXCertPathChecker {
830 
831         private static final String EKU_OID = "2.5.29.37";
832 
833         private static final String EKU_anyExtendedKeyUsage = "2.5.29.37.0";
834         private static final String EKU_clientAuth = "1.3.6.1.5.5.7.3.2";
835         private static final String EKU_serverAuth = "1.3.6.1.5.5.7.3.1";
836         private static final String EKU_nsSGC = "2.16.840.1.113730.4.1";
837         private static final String EKU_msSGC = "1.3.6.1.4.1.311.10.3.3";
838 
839         private static final Set<String> SUPPORTED_EXTENSIONS
840                 = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(EKU_OID)));
841 
842         private final boolean clientAuth;
843         private final X509Certificate leaf;
844 
ExtendedKeyUsagePKIXCertPathChecker(boolean clientAuth, X509Certificate leaf)845         private ExtendedKeyUsagePKIXCertPathChecker(boolean clientAuth, X509Certificate leaf) {
846             this.clientAuth = clientAuth;
847             this.leaf = leaf;
848         }
849 
850         @Override
init(boolean forward)851         public void init(boolean forward) throws CertPathValidatorException {
852         }
853 
854         @Override
isForwardCheckingSupported()855         public boolean isForwardCheckingSupported() {
856             return true;
857         }
858 
859         @Override
getSupportedExtensions()860         public Set<String> getSupportedExtensions() {
861             return SUPPORTED_EXTENSIONS;
862         }
863 
864         @SuppressWarnings("ReferenceEquality")
865         @Override
check(Certificate c, Collection<String> unresolvedCritExts)866         public void check(Certificate c, Collection<String> unresolvedCritExts)
867                 throws CertPathValidatorException {
868             // We only want to validate the EKU on the leaf certificate.
869             if (c != leaf) {
870                 return;
871             }
872             List<String> ekuOids;
873             try {
874                 ekuOids = leaf.getExtendedKeyUsage();
875             } catch (CertificateParsingException e) {
876                 // A malformed EKU is bad news, consider it fatal.
877                 throw new CertPathValidatorException(e);
878             }
879             // We are here to check EKU, but there is none.
880             if (ekuOids == null) {
881                 return;
882             }
883 
884             boolean goodExtendedKeyUsage = false;
885             for (String ekuOid : ekuOids) {
886                 // anyExtendedKeyUsage for clients and servers
887                 if (ekuOid.equals(EKU_anyExtendedKeyUsage)) {
888                     goodExtendedKeyUsage = true;
889                     break;
890                 }
891 
892                 // clients
893                 if (clientAuth) {
894                     if (ekuOid.equals(EKU_clientAuth)) {
895                         goodExtendedKeyUsage = true;
896                         break;
897                     }
898                     continue;
899                 }
900 
901                 // servers
902                 if (ekuOid.equals(EKU_serverAuth)) {
903                     goodExtendedKeyUsage = true;
904                     break;
905                 }
906                 if (ekuOid.equals(EKU_nsSGC)) {
907                     goodExtendedKeyUsage = true;
908                     break;
909                 }
910                 if (ekuOid.equals(EKU_msSGC)) {
911                     goodExtendedKeyUsage = true;
912                     break;
913                 }
914             }
915             if (goodExtendedKeyUsage) {
916                 // Mark extendedKeyUsage as resolved if present.
917                 unresolvedCritExts.remove(EKU_OID);
918             } else {
919                 throw new CertPathValidatorException("End-entity certificate does not have a valid "
920                                                      + "extendedKeyUsage.");
921             }
922         }
923     }
924 
925     /**
926      * Find all possible issuing trust anchors of {@code cert}.
927      */
findAllTrustAnchorsByIssuerAndSignature(X509Certificate cert)928     private Set<TrustAnchor> findAllTrustAnchorsByIssuerAndSignature(X509Certificate cert) {
929         Set<TrustAnchor> indexedAnchors =
930                 trustedCertificateIndex.findAllByIssuerAndSignature(cert);
931         if (!indexedAnchors.isEmpty() || trustedCertificateStore == null) {
932             return indexedAnchors;
933         }
934         Set<X509Certificate> storeAnchors = trustedCertificateStore.findAllIssuers(cert);
935         if (storeAnchors.isEmpty()) {
936             return indexedAnchors;
937         }
938         Set<TrustAnchor> result = new HashSet<TrustAnchor>(storeAnchors.size());
939         for (X509Certificate storeCert : storeAnchors) {
940             result.add(trustedCertificateIndex.index(storeCert));
941         }
942         return result;
943     }
944 
945     /**
946      * Check the trustedCertificateIndex for the cert to see if it is
947      * already trusted and failing that check the KeyStore if it is
948      * available.
949      */
findTrustAnchorBySubjectAndPublicKey(X509Certificate cert)950     private TrustAnchor findTrustAnchorBySubjectAndPublicKey(X509Certificate cert) {
951         TrustAnchor trustAnchor = trustedCertificateIndex.findBySubjectAndPublicKey(cert);
952         if (trustAnchor != null) {
953             return trustAnchor;
954         }
955         if (trustedCertificateStore == null) {
956             // not trusted and no TrustedCertificateStore to check.
957             return null;
958         }
959         // probe KeyStore for a cert. AndroidCAStore stores its
960         // contents hashed by cert subject on the filesystem to make
961         // this faster than scanning all key store entries.
962         X509Certificate systemCert = trustedCertificateStore.getTrustAnchor(cert);
963         if (systemCert != null) {
964             // Don't index the system certificate here, that way the only place that adds anchors to
965             // the index are findAllTrustAnchorsByIssuerAndSignature.
966             // This allows findAllTrustAnchorsByIssuerAndSignature to avoid checking the
967             // TrustedCertificateStore if the TrustedCertificateIndex contains any issuers for the
968             // certificate because it will have cached all certificates contained in the
969             // TrustedCertificateStore.
970             return new TrustAnchor(systemCert, null);
971         }
972         return null;
973     }
974 
975     @Override
getAcceptedIssuers()976     public X509Certificate[] getAcceptedIssuers() {
977         return (acceptedIssuers != null) ? acceptedIssuers.clone() : acceptedIssuers(rootKeyStore);
978     }
979 
980     /**
981      * Set the default hostname verifier that will be used for HTTPS endpoint identification.  If
982      * {@code null} (the default), endpoint identification will use the default hostname verifier
983      * set in {@link HttpsURLConnection#setDefaultHostnameVerifier(javax.net.ssl.HostnameVerifier)}.
984      */
setDefaultHostnameVerifier(ConscryptHostnameVerifier verifier)985     synchronized static void setDefaultHostnameVerifier(ConscryptHostnameVerifier verifier) {
986         defaultHostnameVerifier = verifier;
987     }
988 
989     /**
990      * Returns the currently-set default hostname verifier.
991      *
992      * @see #setDefaultHostnameVerifier(ConscryptHostnameVerifier)
993      */
getDefaultHostnameVerifier()994     synchronized static ConscryptHostnameVerifier getDefaultHostnameVerifier() {
995         return defaultHostnameVerifier;
996     }
997 
998     /**
999      * Set the hostname verifier that will be used for HTTPS endpoint identification.  If
1000      * {@code null} (the default), endpoint identification will use the default hostname verifier
1001      * set in {@link #setDefaultHostnameVerifier(ConscryptHostnameVerifier)}.
1002      */
setHostnameVerifier(ConscryptHostnameVerifier verifier)1003     void setHostnameVerifier(ConscryptHostnameVerifier verifier) {
1004         this.hostnameVerifier = verifier;
1005     }
1006 
1007     /**
1008      * Returns the currently-set hostname verifier for this instance.
1009      *
1010      * @see #setHostnameVerifier(ConscryptHostnameVerifier)
1011      */
getHostnameVerifier()1012     ConscryptHostnameVerifier getHostnameVerifier() {
1013         return hostnameVerifier;
1014     }
1015 
getHttpsVerifier()1016     private ConscryptHostnameVerifier getHttpsVerifier() {
1017         if (hostnameVerifier != null) {
1018             return hostnameVerifier;
1019         }
1020         return Platform.getDefaultHostnameVerifier();
1021     }
1022 
setCTEnabledOverride(boolean enabled)1023     public void setCTEnabledOverride(boolean enabled) {
1024         this.ctEnabledOverride = enabled;
1025     }
1026 
1027     // Replace the CTVerifier. For testing only.
setCTVerifier(CTVerifier verifier)1028     public void setCTVerifier(CTVerifier verifier) {
1029         this.ctVerifier = verifier;
1030     }
1031 
1032     // Replace the CTPolicy. For testing only.
setCTPolicy(CTPolicy policy)1033     public void setCTPolicy(CTPolicy policy) {
1034         this.ctPolicy = policy;
1035     }
1036 }
1037