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