@@ -72,11 +72,16 @@ public final class TrustManagerImpl implements X509TrustManager {
72
72
private final CertPathValidator validator ;
73
73
74
74
/**
75
- * An index of TrustAnchor instances that we've seen. Unlike the
76
- * TrustedCertificateStore, this may contain intermediate CAs.
75
+ * An index of TrustAnchor instances that we've seen.
77
76
*/
78
77
private final TrustedCertificateIndex trustedCertificateIndex ;
79
78
79
+ /**
80
+ * An index of intermediate certificates that we've seen. These certificates are NOT implicitly
81
+ * trusted and must still form a valid chain to an anchor.
82
+ */
83
+ private final TrustedCertificateIndex intermediateIndex ;
84
+
80
85
/**
81
86
* This is lazily initialized in the AndroidCAStore case since it
82
87
* forces us to bring all the CAs into memory. In the
@@ -145,6 +150,7 @@ public TrustManagerImpl(KeyStore keyStore, CertPinManager manager) {
145
150
this .validator = validatorLocal ;
146
151
this .factory = factoryLocal ;
147
152
this .trustedCertificateIndex = trustedCertificateIndexLocal ;
153
+ this .intermediateIndex = new TrustedCertificateIndex ();
148
154
this .acceptedIssuers = acceptedIssuersLocal ;
149
155
this .err = errLocal ;
150
156
}
@@ -300,7 +306,7 @@ private List<X509Certificate> checkTrusted(X509Certificate[] chain, String authT
300
306
// will have been removed in
301
307
// cleanupCertChainAndFindTrustAnchors. http://b/3404902
302
308
for (int i = 1 ; i < newChain .length ; i ++) {
303
- trustedCertificateIndex .index (newChain [i ]);
309
+ intermediateIndex .index (newChain [i ]);
304
310
}
305
311
} catch (InvalidAlgorithmParameterException e ) {
306
312
throw new CertificateException (e );
@@ -361,7 +367,28 @@ private X509Certificate[] cleanupCertChainAndFindTrustAnchors(X509Certificate[]
361
367
}
362
368
}
363
369
364
- // 2. Find the trust anchor in the chain, if any
370
+ // 2. Add any missing intermediates to the chain
371
+ while (true ) {
372
+ TrustAnchor nextIntermediate =
373
+ intermediateIndex .findByIssuerAndSignature (chain [currIndex ]);
374
+ if (nextIntermediate == null ) {
375
+ break ;
376
+ }
377
+ // Append intermediate
378
+ X509Certificate cert = nextIntermediate .getTrustedCert ();
379
+ // don't mutate original chain, which may be directly from an SSLSession
380
+ if (chain == original ) {
381
+ chain = original .clone ();
382
+ }
383
+ // Grow the chain if needed
384
+ if (currIndex == chain .length - 1 ) {
385
+ chain = Arrays .copyOf (chain , chain .length * 2 );
386
+ }
387
+ chain [currIndex + 1 ] = cert ;
388
+ currIndex ++;
389
+ }
390
+
391
+ // 3. Find the trust anchor in the chain, if any
365
392
int anchorIndex ;
366
393
for (anchorIndex = 0 ; anchorIndex <= currIndex ; anchorIndex ++) {
367
394
// If the current cert is a TrustAnchor, we can ignore the rest of the chain.
@@ -373,13 +400,13 @@ private X509Certificate[] cleanupCertChainAndFindTrustAnchors(X509Certificate[]
373
400
}
374
401
}
375
402
376
- // 3 . If the chain is now shorter, copy to an appropriately sized array.
403
+ // 4 . If the chain is now shorter, copy to an appropriately sized array.
377
404
int chainLength = anchorIndex ;
378
405
X509Certificate [] newChain = ((chainLength == chain .length )
379
406
? chain
380
407
: Arrays .copyOf (chain , chainLength ));
381
408
382
- // 4 . If we didn't find a trust anchor earlier, look for one now
409
+ // 5 . If we didn't find a trust anchor earlier, look for one now
383
410
if (trustAnchors .isEmpty ()) {
384
411
TrustAnchor trustAnchor = findTrustAnchorByIssuerAndSignature (newChain [anchorIndex -1 ]);
385
412
if (trustAnchor != null ) {
0 commit comments