• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.jce.provider;
2 
3 import java.security.InvalidAlgorithmParameterException;
4 import java.security.cert.CertPath;
5 import java.security.cert.CertPathBuilderException;
6 import java.security.cert.CertPathBuilderResult;
7 import java.security.cert.CertPathBuilderSpi;
8 import java.security.cert.CertPathParameters;
9 import java.security.cert.CertificateParsingException;
10 import java.security.cert.PKIXBuilderParameters;
11 import java.security.cert.PKIXCertPathBuilderResult;
12 import java.security.cert.PKIXCertPathValidatorResult;
13 import java.security.cert.X509Certificate;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.HashSet;
17 import java.util.Iterator;
18 import java.util.List;
19 
20 import org.bouncycastle.asn1.x509.Extension;
21 import org.bouncycastle.jcajce.PKIXCertStore;
22 import org.bouncycastle.jcajce.PKIXCertStoreSelector;
23 import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters;
24 import org.bouncycastle.jcajce.PKIXExtendedParameters;
25 import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
26 import org.bouncycastle.jce.exception.ExtCertPathBuilderException;
27 import org.bouncycastle.x509.ExtendedPKIXBuilderParameters;
28 import org.bouncycastle.x509.ExtendedPKIXParameters;
29 
30 /**
31  * Implements the PKIX CertPathBuilding algorithm for BouncyCastle.
32  *
33  * @see CertPathBuilderSpi
34  */
35 public class PKIXCertPathBuilderSpi
36     extends CertPathBuilderSpi
37 {
38     /**
39      * Build and validate a CertPath using the given parameter.
40      *
41      * @param params PKIXBuilderParameters object containing all information to
42      *            build the CertPath
43      */
engineBuild(CertPathParameters params)44     public CertPathBuilderResult engineBuild(CertPathParameters params)
45         throws CertPathBuilderException, InvalidAlgorithmParameterException
46     {
47         PKIXExtendedBuilderParameters paramsPKIX;
48         if (params instanceof PKIXBuilderParameters)
49         {
50             PKIXExtendedParameters.Builder paramsPKIXBldr = new PKIXExtendedParameters.Builder((PKIXBuilderParameters)params);
51             PKIXExtendedBuilderParameters.Builder paramsBldrPKIXBldr;
52 
53             if (params instanceof ExtendedPKIXParameters)
54             {
55                 ExtendedPKIXBuilderParameters extPKIX = (ExtendedPKIXBuilderParameters)params;
56 
57  ;
58                 for (Iterator it = extPKIX.getAdditionalStores().iterator(); it.hasNext();)
59                 {
60                      paramsPKIXBldr.addCertificateStore((PKIXCertStore)it.next());
61                 }
62                 paramsBldrPKIXBldr  = new PKIXExtendedBuilderParameters.Builder(paramsPKIXBldr.build());
63 
64                 paramsBldrPKIXBldr.addExcludedCerts(extPKIX.getExcludedCerts());
65                 paramsBldrPKIXBldr.setMaxPathLength(extPKIX.getMaxPathLength());
66             }
67             else
68             {
69                 paramsBldrPKIXBldr  = new PKIXExtendedBuilderParameters.Builder((PKIXBuilderParameters)params);
70             }
71 
72             paramsPKIX = paramsBldrPKIXBldr.build();
73         }
74         else if (params instanceof PKIXExtendedBuilderParameters)
75         {
76             paramsPKIX = (PKIXExtendedBuilderParameters)params;
77         }
78         else
79         {
80             throw new InvalidAlgorithmParameterException(
81                 "Parameters must be an instance of "
82                     + PKIXBuilderParameters.class.getName() + " or "
83                     + PKIXExtendedBuilderParameters.class.getName() + ".");
84         }
85 
86         Collection targets;
87         Iterator targetIter;
88         List certPathList = new ArrayList();
89         X509Certificate cert;
90 
91         // search target certificates
92 
93         PKIXCertStoreSelector certSelect = paramsPKIX.getBaseParameters().getTargetConstraints();
94 
95         try
96         {
97             targets = CertPathValidatorUtilities.findCertificates(certSelect, paramsPKIX.getBaseParameters().getCertificateStores());
98             targets.addAll(CertPathValidatorUtilities.findCertificates(certSelect, paramsPKIX.getBaseParameters().getCertStores()));
99         }
100         catch (AnnotatedException e)
101         {
102             throw new ExtCertPathBuilderException(
103                 "Error finding target certificate.", e);
104         }
105 
106         if (targets.isEmpty())
107         {
108 
109             throw new CertPathBuilderException(
110                 "No certificate found matching targetContraints.");
111         }
112 
113         CertPathBuilderResult result = null;
114 
115         // check all potential target certificates
116         targetIter = targets.iterator();
117         while (targetIter.hasNext() && result == null)
118         {
119             cert = (X509Certificate) targetIter.next();
120             result = build(cert, paramsPKIX, certPathList);
121         }
122 
123         if (result == null && certPathException != null)
124         {
125             if (certPathException instanceof AnnotatedException)
126             {
127                 throw new CertPathBuilderException(certPathException.getMessage(), certPathException.getCause());
128             }
129             throw new CertPathBuilderException(
130                 "Possible certificate chain could not be validated.",
131                 certPathException);
132         }
133 
134         if (result == null && certPathException == null)
135         {
136             throw new CertPathBuilderException(
137                 "Unable to find certificate chain.");
138         }
139 
140         return result;
141     }
142 
143     private Exception certPathException;
144 
build(X509Certificate tbvCert, PKIXExtendedBuilderParameters pkixParams, List tbvPath)145     protected CertPathBuilderResult build(X509Certificate tbvCert,
146         PKIXExtendedBuilderParameters pkixParams, List tbvPath)
147     {
148         // If tbvCert is readily present in tbvPath, it indicates having run
149         // into a cycle in the
150         // PKI graph.
151         if (tbvPath.contains(tbvCert))
152         {
153             return null;
154         }
155         // step out, the certificate is not allowed to appear in a certification
156         // chain.
157         if (pkixParams.getExcludedCerts().contains(tbvCert))
158         {
159             return null;
160         }
161         // test if certificate path exceeds maximum length
162         if (pkixParams.getMaxPathLength() != -1)
163         {
164             if (tbvPath.size() - 1 > pkixParams.getMaxPathLength())
165             {
166                 return null;
167             }
168         }
169 
170         tbvPath.add(tbvCert);
171 
172         CertificateFactory cFact;
173         PKIXCertPathValidatorSpi validator;
174         CertPathBuilderResult builderResult = null;
175 
176         try
177         {
178             cFact = new CertificateFactory();
179             validator = new PKIXCertPathValidatorSpi();
180         }
181         catch (Exception e)
182         {
183             // cannot happen
184             throw new RuntimeException("Exception creating support classes.");
185         }
186 
187         try
188         {
189             // check whether the issuer of <tbvCert> is a TrustAnchor
190             if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getBaseParameters().getTrustAnchors(),
191                 pkixParams.getBaseParameters().getSigProvider()) != null)
192             {
193                 // exception message from possibly later tried certification
194                 // chains
195                 CertPath certPath = null;
196                 PKIXCertPathValidatorResult result = null;
197                 try
198                 {
199                     certPath = cFact.engineGenerateCertPath(tbvPath);
200                 }
201                 catch (Exception e)
202                 {
203                     throw new AnnotatedException(
204                         "Certification path could not be constructed from certificate list.",
205                         e);
206                 }
207 
208                 try
209                 {
210                     result = (PKIXCertPathValidatorResult) validator.engineValidate(
211                         certPath, pkixParams);
212                 }
213                 catch (Exception e)
214                 {
215                     throw new AnnotatedException(
216                         "Certification path could not be validated.", e);
217                 }
218 
219                 return new PKIXCertPathBuilderResult(certPath, result
220                     .getTrustAnchor(), result.getPolicyTree(), result
221                     .getPublicKey());
222 
223             }
224             else
225             {
226                 List stores = new ArrayList();
227 
228 
229                 stores.addAll(pkixParams.getBaseParameters().getCertificateStores());
230 
231                 // add additional X.509 stores from locations in certificate
232                 try
233                 {
234                     stores.addAll(CertPathValidatorUtilities.getAdditionalStoresFromAltNames(
235                         tbvCert.getExtensionValue(Extension.issuerAlternativeName.getId()), pkixParams.getBaseParameters().getNamedCertificateStoreMap()));
236                 }
237                 catch (CertificateParsingException e)
238                 {
239                     throw new AnnotatedException(
240                         "No additional X.509 stores can be added from certificate locations.",
241                         e);
242                 }
243                 Collection issuers = new HashSet();
244                 // try to get the issuer certificate from one
245                 // of the stores
246                 try
247                 {
248                     issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams.getBaseParameters().getCertStores(), stores));
249                 }
250                 catch (AnnotatedException e)
251                 {
252                     throw new AnnotatedException(
253                         "Cannot find issuer certificate for certificate in certification path.",
254                         e);
255                 }
256                 if (issuers.isEmpty())
257                 {
258                     throw new AnnotatedException(
259                         "No issuer certificate for certificate in certification path found.");
260                 }
261                 Iterator it = issuers.iterator();
262 
263                 while (it.hasNext() && builderResult == null)
264                 {
265                     X509Certificate issuer = (X509Certificate) it.next();
266                     builderResult = build(issuer, pkixParams, tbvPath);
267                 }
268             }
269         }
270         catch (AnnotatedException e)
271         {
272             certPathException = e;
273         }
274         if (builderResult == null)
275         {
276             tbvPath.remove(tbvCert);
277         }
278         return builderResult;
279     }
280 
281 }
282