1 package org.bouncycastle.jce.provider;
2 
3 // BEGIN android-added
4 import java.math.BigInteger;
5 // END android-added
6 import java.security.InvalidAlgorithmParameterException;
7 import java.security.PublicKey;
8 import java.security.cert.CertPath;
9 import java.security.cert.CertPathParameters;
10 import java.security.cert.CertPathValidatorException;
11 import java.security.cert.CertPathValidatorResult;
12 import java.security.cert.CertPathValidatorSpi;
13 import java.security.cert.PKIXCertPathChecker;
14 import java.security.cert.PKIXCertPathValidatorResult;
15 import java.security.cert.PKIXParameters;
16 import java.security.cert.TrustAnchor;
17 import java.security.cert.X509Certificate;
18 import java.util.ArrayList;
19 import java.util.HashSet;
20 import java.util.Iterator;
21 import java.util.List;
22 import java.util.Set;
23 
24 import org.bouncycastle.asn1.ASN1Encodable;
25 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
26 import org.bouncycastle.asn1.x500.X500Name;
27 import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
28 import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters;
29 import org.bouncycastle.jcajce.PKIXExtendedParameters;
30 import org.bouncycastle.jcajce.util.BCJcaJceHelper;
31 import org.bouncycastle.jcajce.util.JcaJceHelper;
32 import org.bouncycastle.jce.exception.ExtCertPathValidatorException;
33 import org.bouncycastle.x509.ExtendedPKIXParameters;
34 
35 /**
36  * CertPathValidatorSpi implementation for X.509 Certificate validation � la RFC
37  * 3280.
38  */
39 public class PKIXCertPathValidatorSpi
40         extends CertPathValidatorSpi
41 {
42     private final JcaJceHelper helper = new BCJcaJceHelper();
43 
PKIXCertPathValidatorSpi()44     public PKIXCertPathValidatorSpi()
45     {
46     }
47     // BEGIN android-added
48     private static class NoPreloadHolder {
49         private final static CertBlacklist blacklist = new CertBlacklist();
50     }
51     // END android-added
52 
engineValidate( CertPath certPath, CertPathParameters params)53     public CertPathValidatorResult engineValidate(
54             CertPath certPath,
55             CertPathParameters params)
56             throws CertPathValidatorException,
57             InvalidAlgorithmParameterException
58     {
59         if (!(params instanceof CertPathParameters))
60         {
61             throw new InvalidAlgorithmParameterException("Parameters must be a " + PKIXParameters.class.getName()
62                     + " instance.");
63         }
64 
65         PKIXExtendedParameters paramsPKIX;
66         if (params instanceof PKIXParameters)
67         {
68             PKIXExtendedParameters.Builder paramsPKIXBldr = new PKIXExtendedParameters.Builder((PKIXParameters)params);
69 
70             if (params instanceof ExtendedPKIXParameters)
71             {
72                 ExtendedPKIXParameters extPKIX = (ExtendedPKIXParameters)params;
73 
74                 paramsPKIXBldr.setUseDeltasEnabled(extPKIX.isUseDeltasEnabled());
75                 paramsPKIXBldr.setValidityModel(extPKIX.getValidityModel());
76             }
77 
78             paramsPKIX = paramsPKIXBldr.build();
79         }
80         else if (params instanceof PKIXExtendedBuilderParameters)
81         {
82             paramsPKIX = ((PKIXExtendedBuilderParameters)params).getBaseParameters();
83         }
84         // BEGIN android-changed
85         // else
86         else if (params instanceof PKIXExtendedParameters)
87         // END android-changed
88         {
89             paramsPKIX = (PKIXExtendedParameters)params;
90         }
91         // BEGIN android-added
92         else {
93             throw new InvalidAlgorithmParameterException("Expecting PKIX algorithm parameters");
94         }
95         // END android-added
96 
97         if (paramsPKIX.getTrustAnchors() == null)
98         {
99             throw new InvalidAlgorithmParameterException(
100                     "trustAnchors is null, this is not allowed for certification path validation.");
101         }
102 
103         //
104         // 6.1.1 - inputs
105         //
106 
107         //
108         // (a)
109         //
110         List certs = certPath.getCertificates();
111         int n = certs.size();
112 
113         if (certs.isEmpty())
114         {
115             throw new CertPathValidatorException("Certification path is empty.", null, certPath, 0);
116         }
117         // BEGIN android-added
118         {
119             X509Certificate cert = (X509Certificate) certs.get(0);
120 
121             if (cert != null) {
122                 BigInteger serial = cert.getSerialNumber();
123                 if (NoPreloadHolder.blacklist.isSerialNumberBlackListed(serial)) {
124                     // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs
125                     String message = "Certificate revocation of serial 0x" + serial.toString(16);
126                     System.out.println(message);
127                     AnnotatedException e = new AnnotatedException(message);
128                     throw new CertPathValidatorException(e.getMessage(), e, certPath, 0);
129                 }
130             }
131         }
132         // END android-added
133 
134         //
135         // (b)
136         //
137         // Date validDate = CertPathValidatorUtilities.getValidDate(paramsPKIX);
138 
139         //
140         // (c)
141         //
142         Set userInitialPolicySet = paramsPKIX.getInitialPolicies();
143 
144         //
145         // (d)
146         //
147         TrustAnchor trust;
148         try
149         {
150             trust = CertPathValidatorUtilities.findTrustAnchor((X509Certificate) certs.get(certs.size() - 1),
151                     paramsPKIX.getTrustAnchors(), paramsPKIX.getSigProvider());
152         }
153         catch (AnnotatedException e)
154         {
155             throw new CertPathValidatorException(e.getMessage(), e, certPath, certs.size() - 1);
156         }
157 
158         if (trust == null)
159         {
160             throw new CertPathValidatorException("Trust anchor for certification path not found.", null, certPath, -1);
161         }
162 
163         // RFC 5280 - CRLs must originate from the same trust anchor as the target certificate.
164         paramsPKIX = new PKIXExtendedParameters.Builder(paramsPKIX).setTrustAnchor(trust).build();
165 
166         //
167         // (e), (f), (g) are part of the paramsPKIX object.
168         //
169         Iterator certIter;
170         int index = 0;
171         int i;
172         // Certificate for each interation of the validation loop
173         // Signature information for each iteration of the validation loop
174         //
175         // 6.1.2 - setup
176         //
177 
178         //
179         // (a)
180         //
181         List[] policyNodes = new ArrayList[n + 1];
182         for (int j = 0; j < policyNodes.length; j++)
183         {
184             policyNodes[j] = new ArrayList();
185         }
186 
187         Set policySet = new HashSet();
188 
189         policySet.add(RFC3280CertPathUtilities.ANY_POLICY);
190 
191         PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0, policySet, null, new HashSet(),
192                 RFC3280CertPathUtilities.ANY_POLICY, false);
193 
194         policyNodes[0].add(validPolicyTree);
195 
196         //
197         // (b) and (c)
198         //
199         PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
200 
201         // (d)
202         //
203         int explicitPolicy;
204         Set acceptablePolicies = new HashSet();
205 
206         if (paramsPKIX.isExplicitPolicyRequired())
207         {
208             explicitPolicy = 0;
209         }
210         else
211         {
212             explicitPolicy = n + 1;
213         }
214 
215         //
216         // (e)
217         //
218         int inhibitAnyPolicy;
219 
220         if (paramsPKIX.isAnyPolicyInhibited())
221         {
222             inhibitAnyPolicy = 0;
223         }
224         else
225         {
226             inhibitAnyPolicy = n + 1;
227         }
228 
229         //
230         // (f)
231         //
232         int policyMapping;
233 
234         if (paramsPKIX.isPolicyMappingInhibited())
235         {
236             policyMapping = 0;
237         }
238         else
239         {
240             policyMapping = n + 1;
241         }
242 
243         //
244         // (g), (h), (i), (j)
245         //
246         PublicKey workingPublicKey;
247         X500Name workingIssuerName;
248 
249         X509Certificate sign = trust.getTrustedCert();
250         try
251         {
252             if (sign != null)
253             {
254                 workingIssuerName = PrincipalUtils.getSubjectPrincipal(sign);
255                 workingPublicKey = sign.getPublicKey();
256             }
257             else
258             {
259                 workingIssuerName = PrincipalUtils.getCA(trust);
260                 workingPublicKey = trust.getCAPublicKey();
261             }
262         }
263         catch (IllegalArgumentException ex)
264         {
265             throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath,
266                     -1);
267         }
268 
269         AlgorithmIdentifier workingAlgId = null;
270         try
271         {
272             workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
273         }
274         catch (CertPathValidatorException e)
275         {
276             throw new ExtCertPathValidatorException(
277                     "Algorithm identifier of public key of trust anchor could not be read.", e, certPath, -1);
278         }
279         ASN1ObjectIdentifier workingPublicKeyAlgorithm = workingAlgId.getAlgorithm();
280         ASN1Encodable workingPublicKeyParameters = workingAlgId.getParameters();
281 
282         //
283         // (k)
284         //
285         int maxPathLength = n;
286 
287         //
288         // 6.1.3
289         //
290 
291         if (paramsPKIX.getTargetConstraints() != null
292                 && !paramsPKIX.getTargetConstraints().match((X509Certificate) certs.get(0)))
293         {
294             throw new ExtCertPathValidatorException(
295                     "Target certificate in certification path does not match targetConstraints.", null, certPath, 0);
296         }
297 
298         //
299         // initialize CertPathChecker's
300         //
301         List pathCheckers = paramsPKIX.getCertPathCheckers();
302         certIter = pathCheckers.iterator();
303         while (certIter.hasNext())
304         {
305             ((PKIXCertPathChecker) certIter.next()).init(false);
306         }
307 
308         X509Certificate cert = null;
309 
310         for (index = certs.size() - 1; index >= 0; index--)
311         {
312             // BEGIN android-added
313             if (NoPreloadHolder.blacklist.isPublicKeyBlackListed(workingPublicKey)) {
314                 // emulate CRL exception message in RFC3280CertPathUtilities.checkCRLs
315                 String message = "Certificate revocation of public key " + workingPublicKey;
316                 System.out.println(message);
317                 AnnotatedException e = new AnnotatedException(message);
318                 throw new CertPathValidatorException(e.getMessage(), e, certPath, index);
319             }
320             // END android-added
321             // try
322             // {
323             //
324             // i as defined in the algorithm description
325             //
326             i = n - index;
327 
328             //
329             // set certificate to be checked in this round
330             // sign and workingPublicKey and workingIssuerName are set
331             // at the end of the for loop and initialized the
332             // first time from the TrustAnchor
333             //
334             cert = (X509Certificate) certs.get(index);
335             boolean verificationAlreadyPerformed = (index == certs.size() - 1);
336 
337             //
338             // 6.1.3
339             //
340 
341             RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey,
342                 verificationAlreadyPerformed, workingIssuerName, sign, helper);
343 
344             RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator);
345 
346             validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies,
347                     validPolicyTree, policyNodes, inhibitAnyPolicy);
348 
349             validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree);
350 
351             RFC3280CertPathUtilities.processCertF(certPath, index, validPolicyTree, explicitPolicy);
352 
353             //
354             // 6.1.4
355             //
356 
357             if (i != n)
358             {
359                 if (cert != null && cert.getVersion() == 1)
360                 {
361                     throw new CertPathValidatorException("Version 1 certificates can't be used as CA ones.", null,
362                             certPath, index);
363                 }
364 
365                 RFC3280CertPathUtilities.prepareNextCertA(certPath, index);
366 
367                 validPolicyTree = RFC3280CertPathUtilities.prepareCertB(certPath, index, policyNodes, validPolicyTree,
368                         policyMapping);
369 
370                 RFC3280CertPathUtilities.prepareNextCertG(certPath, index, nameConstraintValidator);
371 
372                 // (h)
373                 explicitPolicy = RFC3280CertPathUtilities.prepareNextCertH1(certPath, index, explicitPolicy);
374                 policyMapping = RFC3280CertPathUtilities.prepareNextCertH2(certPath, index, policyMapping);
375                 inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertH3(certPath, index, inhibitAnyPolicy);
376 
377                 //
378                 // (i)
379                 //
380                 explicitPolicy = RFC3280CertPathUtilities.prepareNextCertI1(certPath, index, explicitPolicy);
381                 policyMapping = RFC3280CertPathUtilities.prepareNextCertI2(certPath, index, policyMapping);
382 
383                 // (j)
384                 inhibitAnyPolicy = RFC3280CertPathUtilities.prepareNextCertJ(certPath, index, inhibitAnyPolicy);
385 
386                 // (k)
387                 RFC3280CertPathUtilities.prepareNextCertK(certPath, index);
388 
389                 // (l)
390                 maxPathLength = RFC3280CertPathUtilities.prepareNextCertL(certPath, index, maxPathLength);
391 
392                 // (m)
393                 maxPathLength = RFC3280CertPathUtilities.prepareNextCertM(certPath, index, maxPathLength);
394 
395                 // (n)
396                 RFC3280CertPathUtilities.prepareNextCertN(certPath, index);
397 
398                 Set criticalExtensions = cert.getCriticalExtensionOIDs();
399                 if (criticalExtensions != null)
400                 {
401                     criticalExtensions = new HashSet(criticalExtensions);
402 
403                     // these extensions are handled by the algorithm
404                     criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
405                     criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
406                     criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
407                     criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
408                     criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
409                     criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
410                     criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
411                     criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
412                     criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
413                     criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
414                 }
415                 else
416                 {
417                     criticalExtensions = new HashSet();
418                 }
419 
420                 // (o)
421                 RFC3280CertPathUtilities.prepareNextCertO(certPath, index, criticalExtensions, pathCheckers);
422 
423                 // set signing certificate for next round
424                 sign = cert;
425 
426                 // (c)
427                 workingIssuerName = PrincipalUtils.getSubjectPrincipal(sign);
428 
429                 // (d)
430                 try
431                 {
432                     workingPublicKey = CertPathValidatorUtilities.getNextWorkingKey(certPath.getCertificates(), index, helper);
433                 }
434                 catch (CertPathValidatorException e)
435                 {
436                     throw new CertPathValidatorException("Next working key could not be retrieved.", e, certPath, index);
437                 }
438 
439                 workingAlgId = CertPathValidatorUtilities.getAlgorithmIdentifier(workingPublicKey);
440                 // (f)
441                 workingPublicKeyAlgorithm = workingAlgId.getAlgorithm();
442                 // (e)
443                 workingPublicKeyParameters = workingAlgId.getParameters();
444             }
445         }
446 
447         //
448         // 6.1.5 Wrap-up procedure
449         //
450 
451         explicitPolicy = RFC3280CertPathUtilities.wrapupCertA(explicitPolicy, cert);
452 
453         explicitPolicy = RFC3280CertPathUtilities.wrapupCertB(certPath, index + 1, explicitPolicy);
454 
455         //
456         // (c) (d) and (e) are already done
457         //
458 
459         //
460         // (f)
461         //
462         Set criticalExtensions = cert.getCriticalExtensionOIDs();
463 
464         if (criticalExtensions != null)
465         {
466             criticalExtensions = new HashSet(criticalExtensions);
467             // these extensions are handled by the algorithm
468             criticalExtensions.remove(RFC3280CertPathUtilities.KEY_USAGE);
469             criticalExtensions.remove(RFC3280CertPathUtilities.CERTIFICATE_POLICIES);
470             criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_MAPPINGS);
471             criticalExtensions.remove(RFC3280CertPathUtilities.INHIBIT_ANY_POLICY);
472             criticalExtensions.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
473             criticalExtensions.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
474             criticalExtensions.remove(RFC3280CertPathUtilities.POLICY_CONSTRAINTS);
475             criticalExtensions.remove(RFC3280CertPathUtilities.BASIC_CONSTRAINTS);
476             criticalExtensions.remove(RFC3280CertPathUtilities.SUBJECT_ALTERNATIVE_NAME);
477             criticalExtensions.remove(RFC3280CertPathUtilities.NAME_CONSTRAINTS);
478             criticalExtensions.remove(RFC3280CertPathUtilities.CRL_DISTRIBUTION_POINTS);
479         }
480         else
481         {
482             criticalExtensions = new HashSet();
483         }
484 
485         RFC3280CertPathUtilities.wrapupCertF(certPath, index + 1, pathCheckers, criticalExtensions);
486 
487         PKIXPolicyNode intersection = RFC3280CertPathUtilities.wrapupCertG(certPath, paramsPKIX, userInitialPolicySet,
488                 index + 1, policyNodes, validPolicyTree, acceptablePolicies);
489 
490         if ((explicitPolicy > 0) || (intersection != null))
491         {
492             return new PKIXCertPathValidatorResult(trust, intersection, cert.getPublicKey());
493         }
494 
495         throw new CertPathValidatorException("Path processing failed on policy.", null, certPath, index);
496     }
497 
498 }
499