diff options
author | Sergio Giro <sgiro@google.com> | 2016-02-01 18:52:42 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2016-02-01 18:52:42 +0000 |
commit | 9218edabd1ef9852bc2f13115dcadc81b442dd6c (patch) | |
tree | 8229ff72c8cbb06f49dce3a8382930919fa6fc2b /bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java | |
parent | 9b30eb05e5be69d51881a0d1b31e503e97acd784 (diff) | |
parent | 397d32894b89b506dc318e0f83446187c9b76ebe (diff) | |
download | android_external_bouncycastle-9218edabd1ef9852bc2f13115dcadc81b442dd6c.tar.gz android_external_bouncycastle-9218edabd1ef9852bc2f13115dcadc81b442dd6c.tar.bz2 android_external_bouncycastle-9218edabd1ef9852bc2f13115dcadc81b442dd6c.zip |
Merge "Merge remote-tracking branch 'aosp/upstream-master' into merge-152-from-upstream"
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java')
-rw-r--r-- | bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java new file mode 100644 index 0000000..115c198 --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/jce/provider/PKIXAttrCertPathBuilderSpi.java @@ -0,0 +1,361 @@ +package org.bouncycastle.jce.provider; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.Principal; +import java.security.cert.CertPath; +import java.security.cert.CertPathBuilderException; +import java.security.cert.CertPathBuilderResult; +import java.security.cert.CertPathBuilderSpi; +import java.security.cert.CertPathParameters; +import java.security.cert.CertPathValidator; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateParsingException; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathBuilderResult; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.jcajce.PKIXCertStoreSelector; +import org.bouncycastle.jcajce.PKIXExtendedBuilderParameters; +import org.bouncycastle.jce.exception.ExtCertPathBuilderException; +import org.bouncycastle.util.Encodable; +import org.bouncycastle.util.Selector; +import org.bouncycastle.util.Store; +import org.bouncycastle.util.StoreException; +import org.bouncycastle.x509.ExtendedPKIXBuilderParameters; +import org.bouncycastle.x509.ExtendedPKIXParameters; +import org.bouncycastle.x509.X509AttributeCertStoreSelector; +import org.bouncycastle.x509.X509AttributeCertificate; +import org.bouncycastle.x509.X509CertStoreSelector; +import org.bouncycastle.x509.X509Store; + +public class PKIXAttrCertPathBuilderSpi + extends CertPathBuilderSpi +{ + + /** + * Build and validate a CertPath using the given parameter. + * + * @param params PKIXBuilderParameters object containing all information to + * build the CertPath + */ + public CertPathBuilderResult engineBuild(CertPathParameters params) + throws CertPathBuilderException, InvalidAlgorithmParameterException + { + if (!(params instanceof PKIXBuilderParameters) + && !(params instanceof ExtendedPKIXBuilderParameters) + && !(params instanceof PKIXExtendedBuilderParameters)) + { + throw new InvalidAlgorithmParameterException( + "Parameters must be an instance of " + + PKIXBuilderParameters.class.getName() + " or " + + PKIXExtendedBuilderParameters.class.getName() + + "."); + } + + List targetStores = new ArrayList(); + + PKIXExtendedBuilderParameters paramsPKIX; + if (params instanceof PKIXBuilderParameters) + { + PKIXExtendedBuilderParameters.Builder paramsPKIXBldr = new PKIXExtendedBuilderParameters.Builder((PKIXBuilderParameters)params); + + if (params instanceof ExtendedPKIXParameters) + { + ExtendedPKIXBuilderParameters extPKIX = (ExtendedPKIXBuilderParameters)params; + + paramsPKIXBldr.addExcludedCerts(extPKIX.getExcludedCerts()); + paramsPKIXBldr.setMaxPathLength(extPKIX.getMaxPathLength()); + targetStores = extPKIX.getStores(); + } + + paramsPKIX = paramsPKIXBldr.build(); + } + else + { + paramsPKIX = (PKIXExtendedBuilderParameters)params; + } + + Collection targets; + Iterator targetIter; + List certPathList = new ArrayList(); + X509AttributeCertificate cert; + + // search target certificates + + Selector certSelect = paramsPKIX.getBaseParameters().getTargetConstraints(); + if (!(certSelect instanceof X509AttributeCertStoreSelector)) + { + throw new CertPathBuilderException( + "TargetConstraints must be an instance of " + + X509AttributeCertStoreSelector.class.getName() + + " for "+this.getClass().getName()+" class."); + } + + + try + { + targets = findCertificates((X509AttributeCertStoreSelector)certSelect, targetStores); + } + catch (AnnotatedException e) + { + throw new ExtCertPathBuilderException("Error finding target attribute certificate.", e); + } + + if (targets.isEmpty()) + { + throw new CertPathBuilderException( + "No attribute certificate found matching targetContraints."); + } + + CertPathBuilderResult result = null; + + // check all potential target certificates + targetIter = targets.iterator(); + while (targetIter.hasNext() && result == null) + { + cert = (X509AttributeCertificate) targetIter.next(); + + X509CertStoreSelector selector = new X509CertStoreSelector(); + Principal[] principals = cert.getIssuer().getPrincipals(); + Set issuers = new HashSet(); + for (int i = 0; i < principals.length; i++) + { + try + { + if (principals[i] instanceof X500Principal) + { + selector.setSubject(((X500Principal)principals[i]).getEncoded()); + } + PKIXCertStoreSelector certStoreSelector = new PKIXCertStoreSelector.Builder(selector).build(); + issuers.addAll(CertPathValidatorUtilities.findCertificates(certStoreSelector, paramsPKIX.getBaseParameters().getCertStores())); + issuers.addAll(CertPathValidatorUtilities.findCertificates(certStoreSelector, paramsPKIX.getBaseParameters().getCertificateStores())); + } + catch (AnnotatedException e) + { + throw new ExtCertPathBuilderException( + "Public key certificate for attribute certificate cannot be searched.", + e); + } + catch (IOException e) + { + throw new ExtCertPathBuilderException( + "cannot encode X500Principal.", + e); + } + } + if (issuers.isEmpty()) + { + throw new CertPathBuilderException( + "Public key certificate for attribute certificate cannot be found."); + } + Iterator it = issuers.iterator(); + while (it.hasNext() && result == null) + { + result = build(cert, (X509Certificate)it.next(), paramsPKIX, certPathList); + } + } + + if (result == null && certPathException != null) + { + throw new ExtCertPathBuilderException( + "Possible certificate chain could not be validated.", + certPathException); + } + + if (result == null && certPathException == null) + { + throw new CertPathBuilderException( + "Unable to find certificate chain."); + } + + return result; + } + + private Exception certPathException; + + private CertPathBuilderResult build(X509AttributeCertificate attrCert, X509Certificate tbvCert, + PKIXExtendedBuilderParameters pkixParams, List tbvPath) + + { + // If tbvCert is readily present in tbvPath, it indicates having run + // into a cycle in the + // PKI graph. + if (tbvPath.contains(tbvCert)) + { + return null; + } + // step out, the certificate is not allowed to appear in a certification + // chain + if (pkixParams.getExcludedCerts().contains(tbvCert)) + { + return null; + } + // test if certificate path exceeds maximum length + if (pkixParams.getMaxPathLength() != -1) + { + if (tbvPath.size() - 1 > pkixParams.getMaxPathLength()) + { + return null; + } + } + + tbvPath.add(tbvCert); + + CertificateFactory cFact; + CertPathValidator validator; + CertPathBuilderResult builderResult = null; + + try + { + cFact = CertificateFactory.getInstance("X.509", BouncyCastleProvider.PROVIDER_NAME); + validator = CertPathValidator.getInstance("RFC3281", BouncyCastleProvider.PROVIDER_NAME); + } + catch (Exception e) + { + // cannot happen + throw new RuntimeException( + "Exception creating support classes."); + } + + try + { + // check whether the issuer of <tbvCert> is a TrustAnchor + if (CertPathValidatorUtilities.findTrustAnchor(tbvCert, pkixParams.getBaseParameters().getTrustAnchors(), + pkixParams.getBaseParameters().getSigProvider()) != null) + { + CertPath certPath; + PKIXCertPathValidatorResult result; + try + { + certPath = cFact.generateCertPath(tbvPath); + } + catch (Exception e) + { + throw new AnnotatedException( + "Certification path could not be constructed from certificate list.", + e); + } + + try + { + result = (PKIXCertPathValidatorResult) validator.validate( + certPath, pkixParams); + } + catch (Exception e) + { + throw new AnnotatedException( + "Certification path could not be validated.", + e); + } + + return new PKIXCertPathBuilderResult(certPath, result + .getTrustAnchor(), result.getPolicyTree(), result + .getPublicKey()); + + } + else + { + List stores = new ArrayList(); + + stores.addAll(pkixParams.getBaseParameters().getCertificateStores()); + // add additional X.509 stores from locations in certificate + try + { + stores.addAll(CertPathValidatorUtilities.getAdditionalStoresFromAltNames(tbvCert.getExtensionValue(Extension.issuerAlternativeName.getId()), pkixParams.getBaseParameters().getNamedCertificateStoreMap())); + } + catch (CertificateParsingException e) + { + throw new AnnotatedException( + "No additional X.509 stores can be added from certificate locations.", + e); + } + Collection issuers = new HashSet(); + // try to get the issuer certificate from one + // of the stores + try + { + issuers.addAll(CertPathValidatorUtilities.findIssuerCerts(tbvCert, pkixParams.getBaseParameters().getCertStores(), stores)); + } + catch (AnnotatedException e) + { + throw new AnnotatedException( + "Cannot find issuer certificate for certificate in certification path.", + e); + } + if (issuers.isEmpty()) + { + throw new AnnotatedException( + "No issuer certificate for certificate in certification path found."); + } + Iterator it = issuers.iterator(); + + while (it.hasNext() && builderResult == null) + { + X509Certificate issuer = (X509Certificate) it.next(); + // TODO Use CertPathValidatorUtilities.isSelfIssued(issuer)? + // if untrusted self signed certificate continue + if (issuer.getIssuerX500Principal().equals( + issuer.getSubjectX500Principal())) + { + continue; + } + builderResult = build(attrCert, issuer, pkixParams, tbvPath); + } + } + } + catch (AnnotatedException e) + { + certPathException = new AnnotatedException( + "No valid certification path could be build.", e); + } + if (builderResult == null) + { + tbvPath.remove(tbvCert); + } + return builderResult; + } + + protected static Collection findCertificates(X509AttributeCertStoreSelector certSelect, + List certStores) + throws AnnotatedException + { + Set certs = new HashSet(); + Iterator iter = certStores.iterator(); + + while (iter.hasNext()) + { + Object obj = iter.next(); + + if (obj instanceof Store) + { + Store certStore = (Store)obj; + try + { + certs.addAll(certStore.getMatches(certSelect)); + } + catch (StoreException e) + { + throw new AnnotatedException( + "Problem while picking certificates from X.509 store.", e); + } + } + } + return certs; + } +} |