aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java')
-rw-r--r--libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java703
1 files changed, 703 insertions, 0 deletions
diff --git a/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java
new file mode 100644
index 000000000..f90154c1e
--- /dev/null
+++ b/libraries/spongycastle/prov/src/main/java/org/spongycastle/jce/provider/RFC3281CertPathUtilities.java
@@ -0,0 +1,703 @@
+package org.spongycastle.jce.provider;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertPathBuilderException;
+import java.security.cert.CertPathBuilderResult;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorResult;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.spongycastle.asn1.ASN1InputStream;
+import org.spongycastle.asn1.ASN1Primitive;
+import org.spongycastle.asn1.x509.CRLDistPoint;
+import org.spongycastle.asn1.x509.CRLReason;
+import org.spongycastle.asn1.x509.DistributionPoint;
+import org.spongycastle.asn1.x509.DistributionPointName;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.asn1.x509.GeneralNames;
+import org.spongycastle.asn1.x509.TargetInformation;
+import org.spongycastle.asn1.x509.X509Extensions;
+import org.spongycastle.jce.exception.ExtCertPathValidatorException;
+import org.spongycastle.x509.ExtendedPKIXBuilderParameters;
+import org.spongycastle.x509.ExtendedPKIXParameters;
+import org.spongycastle.x509.PKIXAttrCertChecker;
+import org.spongycastle.x509.X509AttributeCertificate;
+import org.spongycastle.x509.X509CertStoreSelector;
+
+class RFC3281CertPathUtilities
+{
+
+ private static final String TARGET_INFORMATION = X509Extensions.TargetInformation
+ .getId();
+
+ private static final String NO_REV_AVAIL = X509Extensions.NoRevAvail
+ .getId();
+
+ private static final String CRL_DISTRIBUTION_POINTS = X509Extensions.CRLDistributionPoints
+ .getId();
+
+ private static final String AUTHORITY_INFO_ACCESS = X509Extensions.AuthorityInfoAccess
+ .getId();
+
+ protected static void processAttrCert7(X509AttributeCertificate attrCert,
+ CertPath certPath, CertPath holderCertPath,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ // TODO:
+ // AA Controls
+ // Attribute encryption
+ // Proxy
+ Set set = attrCert.getCriticalExtensionOIDs();
+ // 7.1
+ // process extensions
+
+ // target information checked in step 6 / X509AttributeCertStoreSelector
+ if (set.contains(TARGET_INFORMATION))
+ {
+ try
+ {
+ TargetInformation.getInstance(CertPathValidatorUtilities
+ .getExtensionValue(attrCert, TARGET_INFORMATION));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Target information extension could not be read.", e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Target information extension could not be read.", e);
+ }
+ }
+ set.remove(TARGET_INFORMATION);
+ for (Iterator it = pkixParams.getAttrCertCheckers().iterator(); it
+ .hasNext();)
+ {
+ ((PKIXAttrCertChecker) it.next()).check(attrCert, certPath,
+ holderCertPath, set);
+ }
+ if (!set.isEmpty())
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate contains unsupported critical extensions: "
+ + set);
+ }
+ }
+
+ /**
+ * Checks if an attribute certificate is revoked.
+ *
+ * @param attrCert Attribute certificate to check if it is revoked.
+ * @param paramsPKIX PKIX parameters.
+ * @param issuerCert The issuer certificate of the attribute certificate
+ * <code>attrCert</code>.
+ * @param validDate The date when the certificate revocation status should
+ * be checked.
+ * @param certPathCerts The certificates of the certification path to be
+ * checked.
+ *
+ * @throws CertPathValidatorException if the certificate is revoked or the
+ * status cannot be checked or some error occurs.
+ */
+ protected static void checkCRLs(X509AttributeCertificate attrCert,
+ ExtendedPKIXParameters paramsPKIX, X509Certificate issuerCert,
+ Date validDate, List certPathCerts) throws CertPathValidatorException
+ {
+ if (paramsPKIX.isRevocationEnabled())
+ {
+ // check if revocation is available
+ if (attrCert.getExtensionValue(NO_REV_AVAIL) == null)
+ {
+ CRLDistPoint crldp = null;
+ try
+ {
+ crldp = CRLDistPoint.getInstance(CertPathValidatorUtilities
+ .getExtensionValue(attrCert, CRL_DISTRIBUTION_POINTS));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(
+ "CRL distribution point extension could not be read.",
+ e);
+ }
+ try
+ {
+ CertPathValidatorUtilities
+ .addAdditionalStoresFromCRLDistributionPoint(crldp,
+ paramsPKIX);
+ }
+ catch (AnnotatedException e)
+ {
+ throw new CertPathValidatorException(
+ "No additional CRL locations could be decoded from CRL distribution point extension.",
+ e);
+ }
+ CertStatus certStatus = new CertStatus();
+ ReasonsMask reasonsMask = new ReasonsMask();
+
+ AnnotatedException lastException = null;
+ boolean validCrlFound = false;
+ // for each distribution point
+ if (crldp != null)
+ {
+ DistributionPoint dps[] = null;
+ try
+ {
+ dps = crldp.getDistributionPoints();
+ }
+ catch (Exception e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Distribution points could not be read.", e);
+ }
+ try
+ {
+ for (int i = 0; i < dps.length
+ && certStatus.getCertStatus() == CertStatus.UNREVOKED
+ && !reasonsMask.isAllReasons(); i++)
+ {
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters) paramsPKIX
+ .clone();
+ checkCRL(dps[i], attrCert, paramsPKIXClone,
+ validDate, issuerCert, certStatus, reasonsMask,
+ certPathCerts);
+ validCrlFound = true;
+ }
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = new AnnotatedException(
+ "No valid CRL for distribution point found.", e);
+ }
+ }
+
+ /*
+ * If the revocation status has not been determined, repeat the
+ * process above with any available CRLs not specified in a
+ * distribution point but issued by the certificate issuer.
+ */
+
+ if (certStatus.getCertStatus() == CertStatus.UNREVOKED
+ && !reasonsMask.isAllReasons())
+ {
+ try
+ {
+ /*
+ * assume a DP with both the reasons and the cRLIssuer
+ * fields omitted and a distribution point name of the
+ * certificate issuer.
+ */
+ ASN1Primitive issuer = null;
+ try
+ {
+
+ issuer = new ASN1InputStream(
+ ((X500Principal) attrCert.getIssuer()
+ .getPrincipals()[0]).getEncoded())
+ .readObject();
+ }
+ catch (Exception e)
+ {
+ throw new AnnotatedException(
+ "Issuer from certificate for CRL could not be reencoded.",
+ e);
+ }
+ DistributionPoint dp = new DistributionPoint(
+ new DistributionPointName(0, new GeneralNames(
+ new GeneralName(GeneralName.directoryName,
+ issuer))), null, null);
+ ExtendedPKIXParameters paramsPKIXClone = (ExtendedPKIXParameters) paramsPKIX
+ .clone();
+ checkCRL(dp, attrCert, paramsPKIXClone, validDate,
+ issuerCert, certStatus, reasonsMask, certPathCerts);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = new AnnotatedException(
+ "No valid CRL for distribution point found.", e);
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ throw new ExtCertPathValidatorException(
+ "No valid CRL found.", lastException);
+ }
+ if (certStatus.getCertStatus() != CertStatus.UNREVOKED)
+ {
+ String message = "Attribute certificate revocation after "
+ + certStatus.getRevocationDate();
+ message += ", reason: "
+ + RFC3280CertPathUtilities.crlReasons[certStatus
+ .getCertStatus()];
+ throw new CertPathValidatorException(message);
+ }
+ if (!reasonsMask.isAllReasons()
+ && certStatus.getCertStatus() == CertStatus.UNREVOKED)
+ {
+ certStatus.setCertStatus(CertStatus.UNDETERMINED);
+ }
+ if (certStatus.getCertStatus() == CertStatus.UNDETERMINED)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate status could not be determined.");
+ }
+
+ }
+ else
+ {
+ if (attrCert.getExtensionValue(CRL_DISTRIBUTION_POINTS) != null
+ || attrCert.getExtensionValue(AUTHORITY_INFO_ACCESS) != null)
+ {
+ throw new CertPathValidatorException(
+ "No rev avail extension is set, but also an AC revocation pointer.");
+ }
+ }
+ }
+ }
+
+ protected static void additionalChecks(X509AttributeCertificate attrCert,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ // 1
+ for (Iterator it = pkixParams.getProhibitedACAttributes().iterator(); it
+ .hasNext();)
+ {
+ String oid = (String) it.next();
+ if (attrCert.getAttributes(oid) != null)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate contains prohibited attribute: "
+ + oid + ".");
+ }
+ }
+ for (Iterator it = pkixParams.getNecessaryACAttributes().iterator(); it
+ .hasNext();)
+ {
+ String oid = (String) it.next();
+ if (attrCert.getAttributes(oid) == null)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate does not contain necessary attribute: "
+ + oid + ".");
+ }
+ }
+ }
+
+ protected static void processAttrCert5(X509AttributeCertificate attrCert,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ try
+ {
+ attrCert.checkValidity(CertPathValidatorUtilities
+ .getValidDate(pkixParams));
+ }
+ catch (CertificateExpiredException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Attribute certificate is not valid.", e);
+ }
+ catch (CertificateNotYetValidException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Attribute certificate is not valid.", e);
+ }
+ }
+
+ protected static void processAttrCert4(X509Certificate acIssuerCert,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ Set set = pkixParams.getTrustedACIssuers();
+ boolean trusted = false;
+ for (Iterator it = set.iterator(); it.hasNext();)
+ {
+ TrustAnchor anchor = (TrustAnchor) it.next();
+ if (acIssuerCert.getSubjectX500Principal().getName("RFC2253")
+ .equals(anchor.getCAName())
+ || acIssuerCert.equals(anchor.getTrustedCert()))
+ {
+ trusted = true;
+ }
+ }
+ if (!trusted)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate issuer is not directly trusted.");
+ }
+ }
+
+ protected static void processAttrCert3(X509Certificate acIssuerCert,
+ ExtendedPKIXParameters pkixParams) throws CertPathValidatorException
+ {
+ if (acIssuerCert.getKeyUsage() != null
+ && (!acIssuerCert.getKeyUsage()[0] && !acIssuerCert.getKeyUsage()[1]))
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate issuer public key cannot be used to validate digital signatures.");
+ }
+ if (acIssuerCert.getBasicConstraints() != -1)
+ {
+ throw new CertPathValidatorException(
+ "Attribute certificate issuer is also a public key certificate issuer.");
+ }
+ }
+
+ protected static CertPathValidatorResult processAttrCert2(
+ CertPath certPath, ExtendedPKIXParameters pkixParams)
+ throws CertPathValidatorException
+ {
+ CertPathValidator validator = null;
+ try
+ {
+ validator = CertPathValidator.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Support class could not be created.", e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Support class could not be created.", e);
+ }
+ try
+ {
+ return validator.validate(certPath, pkixParams);
+ }
+ catch (CertPathValidatorException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Certification path for issuer certificate of attribute certificate could not be validated.",
+ e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // must be a programming error
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+
+ /**
+ * Searches for a holder public key certificate and verifies its
+ * certification path.
+ *
+ * @param attrCert the attribute certificate.
+ * @param pkixParams The PKIX parameters.
+ * @return The certificate path of the holder certificate.
+ * @throws AnnotatedException if
+ * <ul>
+ * <li>no public key certificate can be found although holder
+ * information is given by an entity name or a base certificate
+ * ID
+ * <li>support classes cannot be created
+ * <li>no certification path for the public key certificate can
+ * be built
+ * </ul>
+ */
+ protected static CertPath processAttrCert1(
+ X509AttributeCertificate attrCert, ExtendedPKIXParameters pkixParams)
+ throws CertPathValidatorException
+ {
+ CertPathBuilderResult result = null;
+ // find holder PKCs
+ Set holderPKCs = new HashSet();
+ if (attrCert.getHolder().getIssuer() != null)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ selector.setSerialNumber(attrCert.getHolder().getSerialNumber());
+ Principal[] principals = attrCert.getHolder().getIssuer();
+ for (int i = 0; i < principals.length; i++)
+ {
+ try
+ {
+ if (principals[i] instanceof X500Principal)
+ {
+ selector.setIssuer(((X500Principal)principals[i])
+ .getEncoded());
+ }
+ holderPKCs.addAll(CertPathValidatorUtilities
+ .findCertificates(selector, pkixParams.getStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Unable to encode X500 principal.", e);
+ }
+ }
+ if (holderPKCs.isEmpty())
+ {
+ throw new CertPathValidatorException(
+ "Public key certificate specified in base certificate ID for attribute certificate cannot be found.");
+ }
+ }
+ if (attrCert.getHolder().getEntityNames() != null)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ Principal[] principals = attrCert.getHolder().getEntityNames();
+ for (int i = 0; i < principals.length; i++)
+ {
+ try
+ {
+ if (principals[i] instanceof X500Principal)
+ {
+ selector.setIssuer(((X500Principal) principals[i])
+ .getEncoded());
+ }
+ holderPKCs.addAll(CertPathValidatorUtilities
+ .findCertificates(selector, pkixParams.getStores()));
+ }
+ catch (AnnotatedException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Public key certificate for attribute certificate cannot be searched.",
+ e);
+ }
+ catch (IOException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Unable to encode X500 principal.", e);
+ }
+ }
+ if (holderPKCs.isEmpty())
+ {
+ throw new CertPathValidatorException(
+ "Public key certificate specified in entity name for attribute certificate cannot be found.");
+ }
+ }
+ // verify cert paths for PKCs
+ ExtendedPKIXBuilderParameters params = (ExtendedPKIXBuilderParameters) ExtendedPKIXBuilderParameters
+ .getInstance(pkixParams);
+ CertPathValidatorException lastException = null;
+ for (Iterator it = holderPKCs.iterator(); it.hasNext();)
+ {
+ X509CertStoreSelector selector = new X509CertStoreSelector();
+ selector.setCertificate((X509Certificate) it.next());
+ params.setTargetConstraints(selector);
+ CertPathBuilder builder = null;
+ try
+ {
+ builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ }
+ catch (NoSuchProviderException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Support class could not be created.", e);
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new ExtCertPathValidatorException(
+ "Support class could not be created.", e);
+ }
+ try
+ {
+ result = builder.build(ExtendedPKIXBuilderParameters
+ .getInstance(params));
+ }
+ catch (CertPathBuilderException e)
+ {
+ lastException = new ExtCertPathValidatorException(
+ "Certification path for public key certificate of attribute certificate could not be build.",
+ e);
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ // must be a programming error
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+ if (lastException != null)
+ {
+ throw lastException;
+ }
+ return result.getCertPath();
+ }
+
+ /**
+ *
+ * Checks a distribution point for revocation information for the
+ * certificate <code>attrCert</code>.
+ *
+ * @param dp The distribution point to consider.
+ * @param attrCert The attribute certificate which should be checked.
+ * @param paramsPKIX PKIX parameters.
+ * @param validDate The date when the certificate revocation status should
+ * be checked.
+ * @param issuerCert Certificate to check if it is revoked.
+ * @param reasonMask The reasons mask which is already checked.
+ * @param certPathCerts The certificates of the certification path to be
+ * checked.
+ * @throws AnnotatedException if the certificate is revoked or the status
+ * cannot be checked or some error occurs.
+ */
+ private static void checkCRL(DistributionPoint dp,
+ X509AttributeCertificate attrCert, ExtendedPKIXParameters paramsPKIX,
+ Date validDate, X509Certificate issuerCert, CertStatus certStatus,
+ ReasonsMask reasonMask, List certPathCerts) throws AnnotatedException
+ {
+
+ /*
+ * 4.3.6 No Revocation Available
+ *
+ * The noRevAvail extension, defined in [X.509-2000], allows an AC
+ * issuer to indicate that no revocation information will be made
+ * available for this AC.
+ */
+ if (attrCert.getExtensionValue(X509Extensions.NoRevAvail.getId()) != null)
+ {
+ return;
+ }
+ Date currentDate = new Date(System.currentTimeMillis());
+ if (validDate.getTime() > currentDate.getTime())
+ {
+ throw new AnnotatedException("Validation time is in future.");
+ }
+
+ // (a)
+ /*
+ * We always get timely valid CRLs, so there is no step (a) (1).
+ * "locally cached" CRLs are assumed to be in getStore(), additional
+ * CRLs must be enabled in the ExtendedPKIXParameters and are in
+ * getAdditionalStore()
+ */
+
+ Set crls = CertPathValidatorUtilities.getCompleteCRLs(dp, attrCert,
+ currentDate, paramsPKIX);
+ boolean validCrlFound = false;
+ AnnotatedException lastException = null;
+ Iterator crl_iter = crls.iterator();
+
+ while (crl_iter.hasNext()
+ && certStatus.getCertStatus() == CertStatus.UNREVOKED
+ && !reasonMask.isAllReasons())
+ {
+ try
+ {
+ X509CRL crl = (X509CRL) crl_iter.next();
+
+ // (d)
+ ReasonsMask interimReasonsMask = RFC3280CertPathUtilities
+ .processCRLD(crl, dp);
+
+ // (e)
+ /*
+ * The reasons mask is updated at the end, so only valid CRLs
+ * can update it. If this CRL does not contain new reasons it
+ * must be ignored.
+ */
+ if (!interimReasonsMask.hasNewReasons(reasonMask))
+ {
+ continue;
+ }
+
+ // (f)
+ Set keys = RFC3280CertPathUtilities.processCRLF(crl, attrCert,
+ null, null, paramsPKIX, certPathCerts);
+ // (g)
+ PublicKey key = RFC3280CertPathUtilities.processCRLG(crl, keys);
+
+ X509CRL deltaCRL = null;
+
+ if (paramsPKIX.isUseDeltasEnabled())
+ {
+ // get delta CRLs
+ Set deltaCRLs = CertPathValidatorUtilities.getDeltaCRLs(
+ currentDate, paramsPKIX, crl);
+ // we only want one valid delta CRL
+ // (h)
+ deltaCRL = RFC3280CertPathUtilities.processCRLH(deltaCRLs,
+ key);
+ }
+
+ /*
+ * CRL must be be valid at the current time, not the validation
+ * time. If a certificate is revoked with reason keyCompromise,
+ * cACompromise, it can be used for forgery, also for the past.
+ * This reason may not be contained in older CRLs.
+ */
+
+ /*
+ * in the chain model signatures stay valid also after the
+ * certificate has been expired, so they do not have to be in
+ * the CRL vality time
+ */
+
+ if (paramsPKIX.getValidityModel() != ExtendedPKIXParameters.CHAIN_VALIDITY_MODEL)
+ {
+ /*
+ * if a certificate has expired, but was revoked, it is not
+ * more in the CRL, so it would be regarded as valid if the
+ * first check is not done
+ */
+ if (attrCert.getNotAfter().getTime() < crl.getThisUpdate()
+ .getTime())
+ {
+ throw new AnnotatedException(
+ "No valid CRL for current time found.");
+ }
+ }
+
+ RFC3280CertPathUtilities.processCRLB1(dp, attrCert, crl);
+
+ // (b) (2)
+ RFC3280CertPathUtilities.processCRLB2(dp, attrCert, crl);
+
+ // (c)
+ RFC3280CertPathUtilities.processCRLC(deltaCRL, crl, paramsPKIX);
+
+ // (i)
+ RFC3280CertPathUtilities.processCRLI(validDate, deltaCRL,
+ attrCert, certStatus, paramsPKIX);
+
+ // (j)
+ RFC3280CertPathUtilities.processCRLJ(validDate, crl, attrCert,
+ certStatus);
+
+ // (k)
+ if (certStatus.getCertStatus() == CRLReason.removeFromCRL)
+ {
+ certStatus.setCertStatus(CertStatus.UNREVOKED);
+ }
+
+ // update reasons mask
+ reasonMask.addReasons(interimReasonsMask);
+ validCrlFound = true;
+ }
+ catch (AnnotatedException e)
+ {
+ lastException = e;
+ }
+ }
+ if (!validCrlFound)
+ {
+ throw lastException;
+ }
+ }
+}