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