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