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