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