summaryrefslogtreecommitdiffstats
path: root/bcprov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
diff options
context:
space:
mode:
authorSergio Giro <sgiro@google.com>2016-02-01 18:52:42 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-02-01 18:52:42 +0000
commit9218edabd1ef9852bc2f13115dcadc81b442dd6c (patch)
tree8229ff72c8cbb06f49dce3a8382930919fa6fc2b /bcprov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
parent9b30eb05e5be69d51881a0d1b31e503e97acd784 (diff)
parent397d32894b89b506dc318e0f83446187c9b76ebe (diff)
downloadandroid_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/x509/PKIXCertPathReviewer.java')
-rw-r--r--bcprov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java2543
1 files changed, 2543 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java b/bcprov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
new file mode 100644
index 0000000..3271aa9
--- /dev/null
+++ b/bcprov/src/main/java/org/bouncycastle/x509/PKIXCertPathReviewer.java
@@ -0,0 +1,2543 @@
+package org.bouncycastle.x509;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PolicyNode;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509CRLEntry;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+
+import javax.security.auth.x500.X500Principal;
+
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DERIA5String;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.x509.AccessDescription;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
+import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.CRLDistPoint;
+import org.bouncycastle.asn1.x509.DistributionPoint;
+import org.bouncycastle.asn1.x509.DistributionPointName;
+import org.bouncycastle.asn1.x509.GeneralName;
+import org.bouncycastle.asn1.x509.GeneralNames;
+import org.bouncycastle.asn1.x509.GeneralSubtree;
+import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
+import org.bouncycastle.asn1.x509.NameConstraints;
+import org.bouncycastle.asn1.x509.PolicyInformation;
+import org.bouncycastle.asn1.x509.X509Extensions;
+import org.bouncycastle.asn1.x509.qualified.Iso4217CurrencyCode;
+import org.bouncycastle.asn1.x509.qualified.MonetaryValue;
+import org.bouncycastle.asn1.x509.qualified.QCStatement;
+import org.bouncycastle.i18n.ErrorBundle;
+import org.bouncycastle.i18n.LocaleString;
+import org.bouncycastle.i18n.filter.TrustedInput;
+import org.bouncycastle.i18n.filter.UntrustedInput;
+import org.bouncycastle.i18n.filter.UntrustedUrlInput;
+import org.bouncycastle.jce.provider.AnnotatedException;
+import org.bouncycastle.jce.provider.PKIXNameConstraintValidator;
+import org.bouncycastle.jce.provider.PKIXNameConstraintValidatorException;
+import org.bouncycastle.jce.provider.PKIXPolicyNode;
+import org.bouncycastle.util.Integers;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+/**
+ * PKIXCertPathReviewer<br>
+ * Validation of X.509 Certificate Paths. Tries to find as much errors in the Path as possible.
+ */
+public class PKIXCertPathReviewer extends CertPathValidatorUtilities
+{
+
+ private static final String QC_STATEMENT = X509Extensions.QCStatements.getId();
+ private static final String CRL_DIST_POINTS = X509Extensions.CRLDistributionPoints.getId();
+ private static final String AUTH_INFO_ACCESS = X509Extensions.AuthorityInfoAccess.getId();
+
+ private static final String RESOURCE_NAME = "org.bouncycastle.x509.CertPathReviewerMessages";
+
+ // input parameters
+
+ protected CertPath certPath;
+
+ protected PKIXParameters pkixParams;
+
+ protected Date validDate;
+
+ // state variables
+
+ protected List certs;
+
+ protected int n;
+
+ // output variables
+
+ protected List[] notifications;
+ protected List[] errors;
+ protected TrustAnchor trustAnchor;
+ protected PublicKey subjectPublicKey;
+ protected PolicyNode policyTree;
+
+ private boolean initialized;
+
+ /**
+ * Initializes the PKIXCertPathReviewer with the given {@link CertPath} and {@link PKIXParameters} params
+ * @param certPath the {@link CertPath} to validate
+ * @param params the {@link PKIXParameters} to use
+ * @throws CertPathReviewerException if the certPath is empty
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} is already initialized
+ */
+ public void init(CertPath certPath, PKIXParameters params)
+ throws CertPathReviewerException
+ {
+ if (initialized)
+ {
+ throw new IllegalStateException("object is already initialized!");
+ }
+ initialized = true;
+
+ // check input parameters
+ if (certPath == null)
+ {
+ throw new NullPointerException("certPath was null");
+ }
+ this.certPath = certPath;
+
+ certs = certPath.getCertificates();
+ n = certs.size();
+ if (certs.isEmpty())
+ {
+ throw new CertPathReviewerException(
+ new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.emptyCertPath"));
+ }
+
+ pkixParams = (PKIXParameters) params.clone();
+
+ // 6.1.1 - Inputs
+
+ // a) done
+
+ // b)
+
+ validDate = getValidDate(pkixParams);
+
+ // c) part of pkixParams
+
+ // d) done at the beginning of checkSignatures
+
+ // e) f) g) part of pkixParams
+
+ // initialize output parameters
+
+ notifications = null;
+ errors = null;
+ trustAnchor = null;
+ subjectPublicKey = null;
+ policyTree = null;
+ }
+
+ /**
+ * Creates a PKIXCertPathReviewer and initializes it with the given {@link CertPath} and {@link PKIXParameters} params
+ * @param certPath the {@link CertPath} to validate
+ * @param params the {@link PKIXParameters} to use
+ * @throws CertPathReviewerException if the certPath is empty
+ */
+ public PKIXCertPathReviewer(CertPath certPath, PKIXParameters params)
+ throws CertPathReviewerException
+ {
+ init(certPath, params);
+ }
+
+ /**
+ * Creates an empty PKIXCertPathReviewer. Don't forget to call init() to initialize the object.
+ */
+ public PKIXCertPathReviewer()
+ {
+ // do nothing
+ }
+
+ /**
+ *
+ * @return the CertPath that was validated
+ */
+ public CertPath getCertPath()
+ {
+ return certPath;
+ }
+
+ /**
+ *
+ * @return the size of the CertPath
+ */
+ public int getCertPathSize()
+ {
+ return n;
+ }
+
+ /**
+ * Returns an Array of Lists which contains a List of global error messages
+ * and a List of error messages for each certificate in the path.
+ * The global error List is at index 0. The error lists for each certificate at index 1 to n.
+ * The error messages are of type.
+ * @return the Array of Lists which contain the error messages
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public List[] getErrors()
+ {
+ doChecks();
+ return errors;
+ }
+
+ /**
+ * Returns an List of error messages for the certificate at the given index in the CertPath.
+ * If index == -1 then the list of global errors is returned with errors not specific to a certificate.
+ * @param index the index of the certificate in the CertPath
+ * @return List of error messages for the certificate
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public List getErrors(int index)
+ {
+ doChecks();
+ return errors[index + 1];
+ }
+
+ /**
+ * Returns an Array of Lists which contains a List of global notification messages
+ * and a List of botification messages for each certificate in the path.
+ * The global notificatio List is at index 0. The notification lists for each certificate at index 1 to n.
+ * The error messages are of type.
+ * @return the Array of Lists which contain the notification messages
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public List[] getNotifications()
+ {
+ doChecks();
+ return notifications;
+ }
+
+ /**
+ * Returns an List of notification messages for the certificate at the given index in the CertPath.
+ * If index == -1 then the list of global notifications is returned with notifications not specific to a certificate.
+ * @param index the index of the certificate in the CertPath
+ * @return List of notification messages for the certificate
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public List getNotifications(int index)
+ {
+ doChecks();
+ return notifications[index + 1];
+ }
+
+ /**
+ *
+ * @return the valid policy tree, <b>null</b> if no valid policy exists.
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public PolicyNode getPolicyTree()
+ {
+ doChecks();
+ return policyTree;
+ }
+
+ /**
+ *
+ * @return the PublicKey if the last certificate in the CertPath
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public PublicKey getSubjectPublicKey()
+ {
+ doChecks();
+ return subjectPublicKey;
+ }
+
+ /**
+ *
+ * @return the TrustAnchor for the CertPath, <b>null</b> if no valid TrustAnchor was found.
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public TrustAnchor getTrustAnchor()
+ {
+ doChecks();
+ return trustAnchor;
+ }
+
+ /**
+ *
+ * @return if the CertPath is valid
+ * @throws IllegalStateException if the {@link PKIXCertPathReviewer} was not initialized
+ */
+ public boolean isValidCertPath()
+ {
+ doChecks();
+ boolean valid = true;
+ for (int i = 0; i < errors.length; i++)
+ {
+ if (!errors[i].isEmpty())
+ {
+ valid = false;
+ break;
+ }
+ }
+ return valid;
+ }
+
+ protected void addNotification(ErrorBundle msg)
+ {
+ notifications[0].add(msg);
+ }
+
+ protected void addNotification(ErrorBundle msg, int index)
+ {
+ if (index < -1 || index >= n)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ notifications[index + 1].add(msg);
+ }
+
+ protected void addError(ErrorBundle msg)
+ {
+ errors[0].add(msg);
+ }
+
+ protected void addError(ErrorBundle msg, int index)
+ {
+ if (index < -1 || index >= n)
+ {
+ throw new IndexOutOfBoundsException();
+ }
+ errors[index + 1].add(msg);
+ }
+
+ protected void doChecks()
+ {
+ if (!initialized)
+ {
+ throw new IllegalStateException("Object not initialized. Call init() first.");
+ }
+ if (notifications == null)
+ {
+ // initialize lists
+ notifications = new List[n+1];
+ errors = new List[n+1];
+
+ for (int i = 0; i < notifications.length; i++)
+ {
+ notifications[i] = new ArrayList();
+ errors[i] = new ArrayList();
+ }
+
+ // check Signatures
+ checkSignatures();
+
+ // check Name Constraints
+ checkNameConstraints();
+
+ // check Path Length
+ checkPathLength();
+
+ // check Policy
+ checkPolicy();
+
+ // check other critical extensions
+ checkCriticalExtensions();
+
+ }
+ }
+
+ private void checkNameConstraints()
+ {
+ X509Certificate cert = null;
+
+ //
+ // Setup
+ //
+
+ // (b) and (c)
+ PKIXNameConstraintValidator nameConstraintValidator = new PKIXNameConstraintValidator();
+
+ //
+ // process each certificate except the last in the path
+ //
+ int index;
+ int i;
+
+ try
+ {
+ for (index = certs.size()-1; index>0; index--)
+ {
+ i = n - index;
+
+ //
+ // certificate processing
+ //
+
+ cert = (X509Certificate) certs.get(index);
+
+ // b),c)
+
+ if (!isSelfIssued(cert))
+ {
+ X500Principal principal = getSubjectPrincipal(cert);
+ ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(principal.getEncoded()));
+ ASN1Sequence dns;
+
+ try
+ {
+ dns = (ASN1Sequence)aIn.readObject();
+ }
+ catch (IOException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ncSubjectNameError",
+ new Object[] {new UntrustedInput(principal)});
+ throw new CertPathReviewerException(msg,e,certPath,index);
+ }
+
+ try
+ {
+ nameConstraintValidator.checkPermittedDN(dns);
+ }
+ catch (PKIXNameConstraintValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedDN",
+ new Object[] {new UntrustedInput(principal.getName())});
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+
+ try
+ {
+ nameConstraintValidator.checkExcludedDN(dns);
+ }
+ catch (PKIXNameConstraintValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedDN",
+ new Object[] {new UntrustedInput(principal.getName())});
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+
+ ASN1Sequence altName;
+ try
+ {
+ altName = (ASN1Sequence)getExtensionValue(cert, SUBJECT_ALTERNATIVE_NAME);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.subjAltNameExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+
+ if (altName != null)
+ {
+ for (int j = 0; j < altName.size(); j++)
+ {
+ GeneralName name = GeneralName.getInstance(altName.getObjectAt(j));
+
+ try
+ {
+ nameConstraintValidator.checkPermitted(name);
+ nameConstraintValidator.checkExcluded(name);
+ }
+ catch (PKIXNameConstraintValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedEmail",
+ new Object[] {new UntrustedInput(name)});
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+// switch(o.getTagNo()) TODO - move resources to PKIXNameConstraints
+// {
+// case 1:
+// String email = DERIA5String.getInstance(o, true).getString();
+//
+// try
+// {
+// checkPermittedEmail(permittedSubtreesEmail, email);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedEmail",
+// new Object[] {new UntrustedInput(email)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// try
+// {
+// checkExcludedEmail(excludedSubtreesEmail, email);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedEmail",
+// new Object[] {new UntrustedInput(email)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// break;
+// case 4:
+// ASN1Sequence altDN = ASN1Sequence.getInstance(o, true);
+//
+// try
+// {
+// checkPermittedDN(permittedSubtreesDN, altDN);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// X509Name altDNName = new X509Name(altDN);
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedDN",
+// new Object[] {new UntrustedInput(altDNName)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// try
+// {
+// checkExcludedDN(excludedSubtreesDN, altDN);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// X509Name altDNName = new X509Name(altDN);
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedDN",
+// new Object[] {new UntrustedInput(altDNName)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// break;
+// case 7:
+// byte[] ip = ASN1OctetString.getInstance(o, true).getOctets();
+//
+// try
+// {
+// checkPermittedIP(permittedSubtreesIP, ip);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedIP",
+// new Object[] {IPtoString(ip)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+//
+// try
+// {
+// checkExcludedIP(excludedSubtreesIP, ip);
+// }
+// catch (CertPathValidatorException cpve)
+// {
+// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedIP",
+// new Object[] {IPtoString(ip)});
+// throw new CertPathReviewerException(msg,cpve,certPath,index);
+// }
+// }
+ }
+ }
+ }
+
+ //
+ // prepare for next certificate
+ //
+
+ //
+ // (g) handle the name constraints extension
+ //
+ ASN1Sequence ncSeq;
+ try
+ {
+ ncSeq = (ASN1Sequence)getExtensionValue(cert, NAME_CONSTRAINTS);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ncExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+
+ if (ncSeq != null)
+ {
+ NameConstraints nc = NameConstraints.getInstance(ncSeq);
+
+ //
+ // (g) (1) permitted subtrees
+ //
+ GeneralSubtree[] permitted = nc.getPermittedSubtrees();
+ if (permitted != null)
+ {
+ nameConstraintValidator.intersectPermittedSubtree(permitted);
+ }
+
+ //
+ // (g) (2) excluded subtrees
+ //
+ GeneralSubtree[] excluded = nc.getExcludedSubtrees();
+ if (excluded != null)
+ {
+ for (int c = 0; c != excluded.length; c++)
+ {
+ nameConstraintValidator.addExcludedSubtree(excluded[c]);
+ }
+ }
+ }
+
+ } // for
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage(),cpre.getIndex());
+ }
+
+ }
+
+ /*
+ * checks: - path length constraints and reports - total path length
+ */
+ private void checkPathLength()
+ {
+ // init
+ int maxPathLength = n;
+ int totalPathLength = 0;
+
+ X509Certificate cert = null;
+
+ int i;
+ for (int index = certs.size() - 1; index > 0; index--)
+ {
+ i = n - index;
+
+ cert = (X509Certificate) certs.get(index);
+
+ // l)
+
+ if (!isSelfIssued(cert))
+ {
+ if (maxPathLength <= 0)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.pathLenghtExtended");
+ addError(msg);
+ }
+ maxPathLength--;
+ totalPathLength++;
+ }
+
+ // m)
+
+ BasicConstraints bc;
+ try
+ {
+ bc = BasicConstraints.getInstance(getExtensionValue(cert,
+ BASIC_CONSTRAINTS));
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.processLengthConstError");
+ addError(msg,index);
+ bc = null;
+ }
+
+ if (bc != null)
+ {
+ BigInteger _pathLengthConstraint = bc.getPathLenConstraint();
+
+ if (_pathLengthConstraint != null)
+ {
+ int _plc = _pathLengthConstraint.intValue();
+
+ if (_plc < maxPathLength)
+ {
+ maxPathLength = _plc;
+ }
+ }
+ }
+
+ }
+
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.totalPathLength",
+ new Object[]{Integers.valueOf(totalPathLength)});
+
+ addNotification(msg);
+ }
+
+ /*
+ * checks: - signatures - name chaining - validity of certificates - todo:
+ * if certificate revoked (if specified in the parameters)
+ */
+ private void checkSignatures()
+ {
+ // 1.6.1 - Inputs
+
+ // d)
+
+ TrustAnchor trust = null;
+ X500Principal trustPrincipal = null;
+
+ // validation date
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certPathValidDate",
+ new Object[] {new TrustedInput(validDate), new TrustedInput(new Date())});
+ addNotification(msg);
+ }
+
+ // find trust anchors
+ try
+ {
+ X509Certificate cert = (X509Certificate) certs.get(certs.size() - 1);
+ Collection trustColl = getTrustAnchors(cert,pkixParams.getTrustAnchors());
+ if (trustColl.size() > 1)
+ {
+ // conflicting trust anchors
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.conflictingTrustAnchors",
+ new Object[]{Integers.valueOf(trustColl.size()),
+ new UntrustedInput(cert.getIssuerX500Principal())});
+ addError(msg);
+ }
+ else if (trustColl.isEmpty())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.noTrustAnchorFound",
+ new Object[]{new UntrustedInput(cert.getIssuerX500Principal()),
+ Integers.valueOf(pkixParams.getTrustAnchors().size())});
+ addError(msg);
+ }
+ else
+ {
+ PublicKey trustPublicKey;
+ trust = (TrustAnchor) trustColl.iterator().next();
+ if (trust.getTrustedCert() != null)
+ {
+ trustPublicKey = trust.getTrustedCert().getPublicKey();
+ }
+ else
+ {
+ trustPublicKey = trust.getCAPublicKey();
+ }
+ try
+ {
+ CertPathValidatorUtilities.verifyX509Certificate(cert, trustPublicKey,
+ pkixParams.getSigProvider());
+ }
+ catch (SignatureException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustButInvalidCert");
+ addError(msg);
+ }
+ catch (Exception e)
+ {
+ // do nothing, error occurs again later
+ }
+ }
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage());
+ }
+ catch (Throwable t)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.unknown",
+ new Object[] {new UntrustedInput(t.getMessage()), new UntrustedInput(t)});
+ addError(msg);
+ }
+
+ if (trust != null)
+ {
+ // get the name of the trustAnchor
+ X509Certificate sign = trust.getTrustedCert();
+ try
+ {
+ if (sign != null)
+ {
+ trustPrincipal = getSubjectPrincipal(sign);
+ }
+ else
+ {
+ trustPrincipal = new X500Principal(trust.getCAName());
+ }
+ }
+ catch (IllegalArgumentException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustDNInvalid",
+ new Object[] {new UntrustedInput(trust.getCAName())});
+ addError(msg);
+ }
+
+ // test key usages of the trust anchor
+ if (sign != null)
+ {
+ boolean[] ku = sign.getKeyUsage();
+ if (ku != null && !ku[5])
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.trustKeyUsage");
+ addNotification(msg);
+ }
+ }
+ }
+
+ // 1.6.2 - Initialization
+
+ PublicKey workingPublicKey = null;
+ X500Principal workingIssuerName = trustPrincipal;
+
+ X509Certificate sign = null;
+
+ AlgorithmIdentifier workingAlgId = null;
+ ASN1ObjectIdentifier workingPublicKeyAlgorithm = null;
+ ASN1Encodable workingPublicKeyParameters = null;
+
+ if (trust != null)
+ {
+ sign = trust.getTrustedCert();
+
+ if (sign != null)
+ {
+ workingPublicKey = sign.getPublicKey();
+ }
+ else
+ {
+ workingPublicKey = trust.getCAPublicKey();
+ }
+
+ try
+ {
+ workingAlgId = getAlgorithmIdentifier(workingPublicKey);
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ catch (CertPathValidatorException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustPubKeyError");
+ addError(msg);
+ workingAlgId = null;
+ }
+
+ }
+
+ // Basic cert checks
+
+ X509Certificate cert = null;
+ int i;
+
+ for (int index = certs.size() - 1; index >= 0; index--)
+ {
+ //
+ // i as defined in the algorithm description
+ //
+ i = n - index;
+
+ //
+ // set certificate to be checked in this round
+ // sign and workingPublicKey and workingIssuerName are set
+ // at the end of the for loop and initialied the
+ // first time from the TrustAnchor
+ //
+ cert = (X509Certificate) certs.get(index);
+
+ // verify signature
+ if (workingPublicKey != null)
+ {
+ try
+ {
+ CertPathValidatorUtilities.verifyX509Certificate(cert, workingPublicKey,
+ pkixParams.getSigProvider());
+ }
+ catch (GeneralSecurityException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.signatureNotVerified",
+ new Object[] {ex.getMessage(),ex,ex.getClass().getName()});
+ addError(msg,index);
+ }
+ }
+ else if (isSelfIssued(cert))
+ {
+ try
+ {
+ CertPathValidatorUtilities.verifyX509Certificate(cert, cert.getPublicKey(),
+ pkixParams.getSigProvider());
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.rootKeyIsValidButNotATrustAnchor");
+ addError(msg, index);
+ }
+ catch (GeneralSecurityException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.signatureNotVerified",
+ new Object[] {ex.getMessage(),ex,ex.getClass().getName()});
+ addError(msg,index);
+ }
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.NoIssuerPublicKey");
+ // if there is an authority key extension add the serial and issuer of the missing certificate
+ byte[] akiBytes = cert.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+ if (akiBytes != null)
+ {
+ try
+ {
+ AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance(
+ X509ExtensionUtil.fromExtensionValue(akiBytes));
+ GeneralNames issuerNames = aki.getAuthorityCertIssuer();
+ if (issuerNames != null)
+ {
+ GeneralName name = issuerNames.getNames()[0];
+ BigInteger serial = aki.getAuthorityCertSerialNumber();
+ if (serial != null)
+ {
+ Object[] extraArgs = {new LocaleString(RESOURCE_NAME, "missingIssuer"), " \"", name ,
+ "\" ", new LocaleString(RESOURCE_NAME, "missingSerial") , " ", serial};
+ msg.setExtraArguments(extraArgs);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ // ignore
+ }
+ }
+ addError(msg,index);
+ }
+
+ // certificate valid?
+ try
+ {
+ cert.checkValidity(validDate);
+ }
+ catch (CertificateNotYetValidException cnve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certificateNotYetValid",
+ new Object[] {new TrustedInput(cert.getNotBefore())});
+ addError(msg,index);
+ }
+ catch (CertificateExpiredException cee)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certificateExpired",
+ new Object[] {new TrustedInput(cert.getNotAfter())});
+ addError(msg,index);
+ }
+
+ // certificate revoked?
+ if (pkixParams.isRevocationEnabled())
+ {
+ // read crl distribution points extension
+ CRLDistPoint crlDistPoints = null;
+ try
+ {
+ ASN1Primitive crl_dp = getExtensionValue(cert,CRL_DIST_POINTS);
+ if (crl_dp != null)
+ {
+ crlDistPoints = CRLDistPoint.getInstance(crl_dp);
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlDistPtExtError");
+ addError(msg,index);
+ }
+
+ // read authority information access extension
+ AuthorityInformationAccess authInfoAcc = null;
+ try
+ {
+ ASN1Primitive auth_info_acc = getExtensionValue(cert,AUTH_INFO_ACCESS);
+ if (auth_info_acc != null)
+ {
+ authInfoAcc = AuthorityInformationAccess.getInstance(auth_info_acc);
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlAuthInfoAccError");
+ addError(msg,index);
+ }
+
+ Vector crlDistPointUrls = getCRLDistUrls(crlDistPoints);
+ Vector ocspUrls = getOCSPUrls(authInfoAcc);
+
+ // add notifications with the crl distribution points
+
+ // output crl distribution points
+ Iterator urlIt = crlDistPointUrls.iterator();
+ while (urlIt.hasNext())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlDistPoint",
+ new Object[] {new UntrustedUrlInput(urlIt.next())});
+ addNotification(msg,index);
+ }
+
+ // output ocsp urls
+ urlIt = ocspUrls.iterator();
+ while (urlIt.hasNext())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ocspLocation",
+ new Object[] {new UntrustedUrlInput(urlIt.next())});
+ addNotification(msg,index);
+ }
+
+ // TODO also support Netscapes revocation-url and/or OCSP instead of CRLs for revocation checking
+ // check CRLs
+ try
+ {
+ checkRevocation(pkixParams, cert, validDate, sign, workingPublicKey, crlDistPointUrls, ocspUrls, index);
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage(),index);
+ }
+ }
+
+ // certificate issuer correct
+ if (workingIssuerName != null && !cert.getIssuerX500Principal().equals(workingIssuerName))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certWrongIssuer",
+ new Object[] {workingIssuerName.getName(),
+ cert.getIssuerX500Principal().getName()});
+ addError(msg,index);
+ }
+
+ //
+ // prepare for next certificate
+ //
+ if (i != n)
+ {
+
+ if (cert != null && cert.getVersion() == 1)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCACert");
+ addError(msg,index);
+ }
+
+ // k)
+
+ BasicConstraints bc;
+ try
+ {
+ bc = BasicConstraints.getInstance(getExtensionValue(cert,
+ BASIC_CONSTRAINTS));
+ if (bc != null)
+ {
+ if (!bc.isCA())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCACert");
+ addError(msg,index);
+ }
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noBasicConstraints");
+ addError(msg,index);
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.errorProcesingBC");
+ addError(msg,index);
+ }
+
+ // n)
+
+ boolean[] _usage = cert.getKeyUsage();
+
+ if ((_usage != null) && !_usage[KEY_CERT_SIGN])
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCertSign");
+ addError(msg,index);
+ }
+
+ } // if
+
+ // set signing certificate for next round
+ sign = cert;
+
+ // c)
+
+ workingIssuerName = cert.getSubjectX500Principal();
+
+ // d) e) f)
+
+ try
+ {
+ workingPublicKey = getNextWorkingKey(certs, index);
+ workingAlgId = getAlgorithmIdentifier(workingPublicKey);
+ workingPublicKeyAlgorithm = workingAlgId.getObjectId();
+ workingPublicKeyParameters = workingAlgId.getParameters();
+ }
+ catch (CertPathValidatorException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.pubKeyError");
+ addError(msg,index);
+ workingAlgId = null;
+ workingPublicKeyAlgorithm = null;
+ workingPublicKeyParameters = null;
+ }
+
+ } // for
+
+ trustAnchor = trust;
+ subjectPublicKey = workingPublicKey;
+ }
+
+ private void checkPolicy()
+ {
+ //
+ // 6.1.1 Inputs
+ //
+
+ // c) Initial Policy Set
+
+ Set userInitialPolicySet = pkixParams.getInitialPolicies();
+
+ // e) f) g) are part of pkixParams
+
+ //
+ // 6.1.2 Initialization
+ //
+
+ // a) valid policy tree
+
+ List[] policyNodes = new ArrayList[n + 1];
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ policyNodes[j] = new ArrayList();
+ }
+
+ Set policySet = new HashSet();
+
+ policySet.add(ANY_POLICY);
+
+ PKIXPolicyNode validPolicyTree = new PKIXPolicyNode(new ArrayList(), 0,
+ policySet, null, new HashSet(), ANY_POLICY, false);
+
+ policyNodes[0].add(validPolicyTree);
+
+ // d) explicit policy
+
+ int explicitPolicy;
+ if (pkixParams.isExplicitPolicyRequired())
+ {
+ explicitPolicy = 0;
+ }
+ else
+ {
+ explicitPolicy = n + 1;
+ }
+
+ // e) inhibit any policy
+
+ int inhibitAnyPolicy;
+ if (pkixParams.isAnyPolicyInhibited())
+ {
+ inhibitAnyPolicy = 0;
+ }
+ else
+ {
+ inhibitAnyPolicy = n + 1;
+ }
+
+ // f) policy mapping
+
+ int policyMapping;
+ if (pkixParams.isPolicyMappingInhibited())
+ {
+ policyMapping = 0;
+ }
+ else
+ {
+ policyMapping = n + 1;
+ }
+
+ Set acceptablePolicies = null;
+
+ //
+ // 6.1.3 Basic Certificate processing
+ //
+
+ X509Certificate cert = null;
+ int index;
+ int i;
+
+ try
+ {
+ for (index = certs.size() - 1; index >= 0; index--)
+ {
+ // i as defined in the algorithm description
+ i = n - index;
+
+ // set certificate to be checked in this round
+ cert = (X509Certificate) certs.get(index);
+
+ // d) process policy information
+
+ ASN1Sequence certPolicies;
+ try
+ {
+ certPolicies = (ASN1Sequence) getExtensionValue(
+ cert, CERTIFICATE_POLICIES);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+ if (certPolicies != null && validPolicyTree != null)
+ {
+
+ // d) 1)
+
+ Enumeration e = certPolicies.getObjects();
+ Set pols = new HashSet();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+ ASN1ObjectIdentifier pOid = pInfo.getPolicyIdentifier();
+
+ pols.add(pOid.getId());
+
+ if (!ANY_POLICY.equals(pOid.getId()))
+ {
+ Set pq;
+ try
+ {
+ pq = getQualifierSet(pInfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+
+ boolean match = processCertD1i(i, policyNodes, pOid, pq);
+
+ if (!match)
+ {
+ processCertD1ii(i, policyNodes, pOid, pq);
+ }
+ }
+ }
+
+ if (acceptablePolicies == null || acceptablePolicies.contains(ANY_POLICY))
+ {
+ acceptablePolicies = pols;
+ }
+ else
+ {
+ Iterator it = acceptablePolicies.iterator();
+ Set t1 = new HashSet();
+
+ while (it.hasNext())
+ {
+ Object o = it.next();
+
+ if (pols.contains(o))
+ {
+ t1.add(o);
+ }
+ }
+
+ acceptablePolicies = t1;
+ }
+
+ // d) 2)
+
+ if ((inhibitAnyPolicy > 0) || ((i < n) && isSelfIssued(cert)))
+ {
+ e = certPolicies.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ PolicyInformation pInfo = PolicyInformation.getInstance(e.nextElement());
+
+ if (ANY_POLICY.equals(pInfo.getPolicyIdentifier().getId()))
+ {
+ Set _apq;
+ try
+ {
+ _apq = getQualifierSet(pInfo.getPolicyQualifiers());
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+ List _nodes = policyNodes[i - 1];
+
+ for (int k = 0; k < _nodes.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode) _nodes.get(k);
+
+ Iterator _policySetIter = _node.getExpectedPolicies().iterator();
+ while (_policySetIter.hasNext())
+ {
+ Object _tmp = _policySetIter.next();
+
+ String _policy;
+ if (_tmp instanceof String)
+ {
+ _policy = (String) _tmp;
+ }
+ else if (_tmp instanceof ASN1ObjectIdentifier)
+ {
+ _policy = ((ASN1ObjectIdentifier) _tmp).getId();
+ }
+ else
+ {
+ continue;
+ }
+
+ boolean _found = false;
+ Iterator _childrenIter = _node
+ .getChildren();
+
+ while (_childrenIter.hasNext())
+ {
+ PKIXPolicyNode _child = (PKIXPolicyNode) _childrenIter.next();
+
+ if (_policy.equals(_child.getValidPolicy()))
+ {
+ _found = true;
+ }
+ }
+
+ if (!_found)
+ {
+ Set _newChildExpectedPolicies = new HashSet();
+ _newChildExpectedPolicies.add(_policy);
+
+ PKIXPolicyNode _newChild = new PKIXPolicyNode(
+ new ArrayList(), i,
+ _newChildExpectedPolicies,
+ _node, _apq, _policy, false);
+ _node.addChild(_newChild);
+ policyNodes[i].add(_newChild);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // (d) (3)
+ //
+ for (int j = (i - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode) nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(
+ validPolicyTree, policyNodes, node);
+ if (validPolicyTree == null)
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // d (4)
+ //
+ Set criticalExtensionOids = cert.getCriticalExtensionOIDs();
+
+ if (criticalExtensionOids != null)
+ {
+ boolean critical = criticalExtensionOids.contains(CERTIFICATE_POLICIES);
+
+ List nodes = policyNodes[i];
+ for (int j = 0; j < nodes.size(); j++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode) nodes.get(j);
+ node.setCritical(critical);
+ }
+ }
+
+ }
+
+ // e)
+
+ if (certPolicies == null)
+ {
+ validPolicyTree = null;
+ }
+
+ // f)
+
+ if (explicitPolicy <= 0 && validPolicyTree == null)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noValidPolicyTree");
+ throw new CertPathReviewerException(msg);
+ }
+
+ //
+ // 6.1.4 preparation for next Certificate
+ //
+
+ if (i != n)
+ {
+
+ // a)
+
+ ASN1Primitive pm;
+ try
+ {
+ pm = getExtensionValue(cert, POLICY_MAPPINGS);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyMapExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence) pm;
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence) mappings.getObjectAt(j);
+ ASN1ObjectIdentifier ip_id = (ASN1ObjectIdentifier) mapping.getObjectAt(0);
+ ASN1ObjectIdentifier sp_id = (ASN1ObjectIdentifier) mapping.getObjectAt(1);
+ if (ANY_POLICY.equals(ip_id.getId()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicyMapping");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ if (ANY_POLICY.equals(sp_id.getId()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicyMapping");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ }
+ }
+
+ // b)
+
+ if (pm != null)
+ {
+ ASN1Sequence mappings = (ASN1Sequence)pm;
+ Map m_idp = new HashMap();
+ Set s_idp = new HashSet();
+
+ for (int j = 0; j < mappings.size(); j++)
+ {
+ ASN1Sequence mapping = (ASN1Sequence)mappings.getObjectAt(j);
+ String id_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(0)).getId();
+ String sd_p = ((ASN1ObjectIdentifier)mapping.getObjectAt(1)).getId();
+ Set tmp;
+
+ if (!m_idp.containsKey(id_p))
+ {
+ tmp = new HashSet();
+ tmp.add(sd_p);
+ m_idp.put(id_p, tmp);
+ s_idp.add(id_p);
+ }
+ else
+ {
+ tmp = (Set)m_idp.get(id_p);
+ tmp.add(sd_p);
+ }
+ }
+
+ Iterator it_idp = s_idp.iterator();
+ while (it_idp.hasNext())
+ {
+ String id_p = (String)it_idp.next();
+
+ //
+ // (1)
+ //
+ if (policyMapping > 0)
+ {
+ try
+ {
+ prepareNextCertB1(i,policyNodes,id_p,m_idp,cert);
+ }
+ catch (AnnotatedException ae)
+ {
+ // error processing certificate policies extension
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyExtError");
+ throw new CertPathReviewerException(msg,ae,certPath,index);
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ // error building qualifier set
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ throw new CertPathReviewerException(msg,cpve,certPath,index);
+ }
+
+ //
+ // (2)
+ //
+ }
+ else if (policyMapping <= 0)
+ {
+ validPolicyTree = prepareNextCertB2(i,policyNodes,id_p,validPolicyTree);
+ }
+
+ }
+ }
+
+ //
+ // h)
+ //
+
+ if (!isSelfIssued(cert))
+ {
+
+ // (1)
+ if (explicitPolicy != 0)
+ {
+ explicitPolicy--;
+ }
+
+ // (2)
+ if (policyMapping != 0)
+ {
+ policyMapping--;
+ }
+
+ // (3)
+ if (inhibitAnyPolicy != 0)
+ {
+ inhibitAnyPolicy--;
+ }
+
+ }
+
+ //
+ // i)
+ //
+
+ try
+ {
+ ASN1Sequence pc = (ASN1Sequence) getExtensionValue(cert,POLICY_CONSTRAINTS);
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject) policyConstraints.nextElement();
+ int tmpInt;
+
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < explicitPolicy)
+ {
+ explicitPolicy = tmpInt;
+ }
+ break;
+ case 1:
+ tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt < policyMapping)
+ {
+ policyMapping = tmpInt;
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyConstExtError");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+
+ //
+ // j)
+ //
+
+ try
+ {
+ ASN1Integer iap = (ASN1Integer)getExtensionValue(cert, INHIBIT_ANY_POLICY);
+
+ if (iap != null)
+ {
+ int _inhibitAnyPolicy = iap.getValue().intValue();
+
+ if (_inhibitAnyPolicy < inhibitAnyPolicy)
+ {
+ inhibitAnyPolicy = _inhibitAnyPolicy;
+ }
+ }
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyInhibitExtError");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ }
+
+ }
+
+ //
+ // 6.1.5 Wrap up
+ //
+
+ //
+ // a)
+ //
+
+ if (!isSelfIssued(cert) && explicitPolicy > 0)
+ {
+ explicitPolicy--;
+ }
+
+ //
+ // b)
+ //
+
+ try
+ {
+ ASN1Sequence pc = (ASN1Sequence) getExtensionValue(cert, POLICY_CONSTRAINTS);
+ if (pc != null)
+ {
+ Enumeration policyConstraints = pc.getObjects();
+
+ while (policyConstraints.hasMoreElements())
+ {
+ ASN1TaggedObject constraint = (ASN1TaggedObject)policyConstraints.nextElement();
+ switch (constraint.getTagNo())
+ {
+ case 0:
+ int tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue();
+ if (tmpInt == 0)
+ {
+ explicitPolicy = 0;
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch (AnnotatedException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyConstExtError");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+
+
+ //
+ // (g)
+ //
+ PKIXPolicyNode intersection;
+
+
+ //
+ // (g) (i)
+ //
+ if (validPolicyTree == null)
+ {
+ if (pkixParams.isExplicitPolicyRequired())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.explicitPolicy");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ intersection = null;
+ }
+ else if (isAnyPolicy(userInitialPolicySet)) // (g) (ii)
+ {
+ if (pkixParams.isExplicitPolicyRequired())
+ {
+ if (acceptablePolicies.isEmpty())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.explicitPolicy");
+ throw new CertPathReviewerException(msg,certPath,index);
+ }
+ else
+ {
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ _validPolicyNodeSet.add(_iter.next());
+ }
+ }
+ }
+ }
+
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!acceptablePolicies.contains(_validPolicy))
+ {
+ //validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+ else
+ {
+ //
+ // (g) (iii)
+ //
+ // This implementation is not exactly same as the one described in RFC3280.
+ // However, as far as the validation result is concerned, both produce
+ // adequate result. The only difference is whether AnyPolicy is remain
+ // in the policy tree or not.
+ //
+ // (g) (iii) 1
+ //
+ Set _validPolicyNodeSet = new HashSet();
+
+ for (int j = 0; j < policyNodes.length; j++)
+ {
+ List _nodeDepth = policyNodes[j];
+
+ for (int k = 0; k < _nodeDepth.size(); k++)
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_nodeDepth.get(k);
+
+ if (ANY_POLICY.equals(_node.getValidPolicy()))
+ {
+ Iterator _iter = _node.getChildren();
+ while (_iter.hasNext())
+ {
+ PKIXPolicyNode _c_node = (PKIXPolicyNode)_iter.next();
+ if (!ANY_POLICY.equals(_c_node.getValidPolicy()))
+ {
+ _validPolicyNodeSet.add(_c_node);
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // (g) (iii) 2
+ //
+ Iterator _vpnsIter = _validPolicyNodeSet.iterator();
+ while (_vpnsIter.hasNext())
+ {
+ PKIXPolicyNode _node = (PKIXPolicyNode)_vpnsIter.next();
+ String _validPolicy = _node.getValidPolicy();
+
+ if (!userInitialPolicySet.contains(_validPolicy))
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, _node);
+ }
+ }
+
+ //
+ // (g) (iii) 4
+ //
+ if (validPolicyTree != null)
+ {
+ for (int j = (n - 1); j >= 0; j--)
+ {
+ List nodes = policyNodes[j];
+
+ for (int k = 0; k < nodes.size(); k++)
+ {
+ PKIXPolicyNode node = (PKIXPolicyNode)nodes.get(k);
+ if (!node.hasChildren())
+ {
+ validPolicyTree = removePolicyNode(validPolicyTree, policyNodes, node);
+ }
+ }
+ }
+ }
+
+ intersection = validPolicyTree;
+ }
+
+ if ((explicitPolicy <= 0) && (intersection == null))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicy");
+ throw new CertPathReviewerException(msg);
+ }
+
+ validPolicyTree = intersection;
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage(),cpre.getIndex());
+ validPolicyTree = null;
+ }
+ }
+
+ private void checkCriticalExtensions()
+ {
+ //
+ // initialise CertPathChecker's
+ //
+ List pathCheckers = pkixParams.getCertPathCheckers();
+ Iterator certIter = pathCheckers.iterator();
+
+ try
+ {
+ try
+ {
+ while (certIter.hasNext())
+ {
+ ((PKIXCertPathChecker)certIter.next()).init(false);
+ }
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certPathCheckerError",
+ new Object[] {cpve.getMessage(),cpve,cpve.getClass().getName()});
+ throw new CertPathReviewerException(msg,cpve);
+ }
+
+ //
+ // process critical extesions for each certificate
+ //
+
+ X509Certificate cert = null;
+
+ int index;
+
+ for (index = certs.size()-1; index >= 0; index--)
+ {
+ cert = (X509Certificate) certs.get(index);
+
+ Set criticalExtensions = cert.getCriticalExtensionOIDs();
+ if (criticalExtensions == null || criticalExtensions.isEmpty())
+ {
+ continue;
+ }
+ // remove already processed extensions
+ criticalExtensions.remove(KEY_USAGE);
+ criticalExtensions.remove(CERTIFICATE_POLICIES);
+ criticalExtensions.remove(POLICY_MAPPINGS);
+ criticalExtensions.remove(INHIBIT_ANY_POLICY);
+ criticalExtensions.remove(ISSUING_DISTRIBUTION_POINT);
+ criticalExtensions.remove(DELTA_CRL_INDICATOR);
+ criticalExtensions.remove(POLICY_CONSTRAINTS);
+ criticalExtensions.remove(BASIC_CONSTRAINTS);
+ criticalExtensions.remove(SUBJECT_ALTERNATIVE_NAME);
+ criticalExtensions.remove(NAME_CONSTRAINTS);
+
+ // process qcStatements extension
+ if (criticalExtensions.contains(QC_STATEMENT))
+ {
+ if (processQcStatements(cert,index))
+ {
+ criticalExtensions.remove(QC_STATEMENT);
+ }
+ }
+
+ Iterator tmpIter = pathCheckers.iterator();
+ while (tmpIter.hasNext())
+ {
+ try
+ {
+ ((PKIXCertPathChecker)tmpIter.next()).check(cert, criticalExtensions);
+ }
+ catch (CertPathValidatorException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.criticalExtensionError",
+ new Object[] {e.getMessage(),e,e.getClass().getName()});
+ throw new CertPathReviewerException(msg,e.getCause(),certPath,index);
+ }
+ }
+ if (!criticalExtensions.isEmpty())
+ {
+ ErrorBundle msg;
+ Iterator it = criticalExtensions.iterator();
+ while (it.hasNext())
+ {
+ msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.unknownCriticalExt",
+ new Object[] {new ASN1ObjectIdentifier((String) it.next())});
+ addError(msg, index);
+ }
+ }
+ }
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addError(cpre.getErrorMessage(),cpre.getIndex());
+ }
+ }
+
+ private boolean processQcStatements(
+ X509Certificate cert,
+ int index)
+ {
+ try
+ {
+ boolean unknownStatement = false;
+
+ ASN1Sequence qcSt = (ASN1Sequence) getExtensionValue(cert,QC_STATEMENT);
+ for (int j = 0; j < qcSt.size(); j++)
+ {
+ QCStatement stmt = QCStatement.getInstance(qcSt.getObjectAt(j));
+ if (QCStatement.id_etsi_qcs_QcCompliance.equals(stmt.getStatementId()))
+ {
+ // process statement - just write a notification that the certificate contains this statement
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcEuCompliance");
+ addNotification(msg,index);
+ }
+ else if (QCStatement.id_qcs_pkixQCSyntax_v1.equals(stmt.getStatementId()))
+ {
+ // process statement - just recognize the statement
+ }
+ else if (QCStatement.id_etsi_qcs_QcSSCD.equals(stmt.getStatementId()))
+ {
+ // process statement - just write a notification that the certificate contains this statement
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcSSCD");
+ addNotification(msg,index);
+ }
+ else if (QCStatement.id_etsi_qcs_LimiteValue.equals(stmt.getStatementId()))
+ {
+ // process statement - write a notification containing the limit value
+ MonetaryValue limit = MonetaryValue.getInstance(stmt.getStatementInfo());
+ Iso4217CurrencyCode currency = limit.getCurrency();
+ double value = limit.getAmount().doubleValue() * Math.pow(10,limit.getExponent().doubleValue());
+ ErrorBundle msg;
+ if (limit.getCurrency().isAlphabetic())
+ {
+ msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueAlpha",
+ new Object[] {limit.getCurrency().getAlphabetic(),
+ new TrustedInput(new Double(value)),
+ limit});
+ }
+ else
+ {
+ msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueNum",
+ new Object[]{Integers.valueOf(limit.getCurrency().getNumeric()),
+ new TrustedInput(new Double(value)),
+ limit});
+ }
+ addNotification(msg,index);
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcUnknownStatement",
+ new Object[] {stmt.getStatementId(),new UntrustedInput(stmt)});
+ addNotification(msg,index);
+ unknownStatement = true;
+ }
+ }
+
+ return !unknownStatement;
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcStatementExtError");
+ addError(msg,index);
+ }
+
+ return false;
+ }
+
+ private String IPtoString(byte[] ip)
+ {
+ String result;
+ try
+ {
+ result = InetAddress.getByAddress(ip).getHostAddress();
+ }
+ catch (Exception e)
+ {
+ StringBuffer b = new StringBuffer();
+
+ for (int i = 0; i != ip.length; i++)
+ {
+ b.append(Integer.toHexString(ip[i] & 0xff));
+ b.append(' ');
+ }
+
+ result = b.toString();
+ }
+
+ return result;
+ }
+
+ protected void checkRevocation(PKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate sign,
+ PublicKey workingPublicKey,
+ Vector crlDistPointUrls,
+ Vector ocspUrls,
+ int index)
+ throws CertPathReviewerException
+ {
+ checkCRLs(paramsPKIX, cert, validDate, sign, workingPublicKey, crlDistPointUrls, index);
+ }
+
+ protected void checkCRLs(
+ PKIXParameters paramsPKIX,
+ X509Certificate cert,
+ Date validDate,
+ X509Certificate sign,
+ PublicKey workingPublicKey,
+ Vector crlDistPointUrls,
+ int index)
+ throws CertPathReviewerException
+ {
+ X509CRLStoreSelector crlselect;
+ crlselect = new X509CRLStoreSelector();
+
+ try
+ {
+ crlselect.addIssuerName(getEncodedIssuerPrincipal(cert).getEncoded());
+ }
+ catch (IOException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlIssuerException");
+ throw new CertPathReviewerException(msg,e);
+ }
+
+ crlselect.setCertificateChecking(cert);
+
+ Iterator crl_iter;
+ try
+ {
+ Collection crl_coll = CRL_UTIL.findCRLs(crlselect, paramsPKIX);
+ crl_iter = crl_coll.iterator();
+
+ if (crl_coll.isEmpty())
+ {
+ // notifcation - no local crls found
+ crl_coll = CRL_UTIL.findCRLs(new X509CRLStoreSelector(),paramsPKIX);
+ Iterator it = crl_coll.iterator();
+ List nonMatchingCrlNames = new ArrayList();
+ while (it.hasNext())
+ {
+ nonMatchingCrlNames.add(((X509CRL) it.next()).getIssuerX500Principal());
+ }
+ int numbOfCrls = nonMatchingCrlNames.size();
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.noCrlInCertstore",
+ new Object[]{new UntrustedInput(crlselect.getIssuerNames()),
+ new UntrustedInput(nonMatchingCrlNames),
+ Integers.valueOf(numbOfCrls)});
+ addNotification(msg,index);
+ }
+
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlExtractionError",
+ new Object[] {ae.getCause().getMessage(),ae.getCause(),ae.getCause().getClass().getName()});
+ addError(msg,index);
+ crl_iter = new ArrayList().iterator();
+ }
+ boolean validCrlFound = false;
+ X509CRL crl = null;
+ while (crl_iter.hasNext())
+ {
+ crl = (X509CRL)crl_iter.next();
+
+ if (crl.getNextUpdate() == null
+ || paramsPKIX.getDate().before(crl.getNextUpdate()))
+ {
+ validCrlFound = true;
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.localValidCRL",
+ new Object[] {new TrustedInput(crl.getThisUpdate()), new TrustedInput(crl.getNextUpdate())});
+ addNotification(msg,index);
+ break;
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.localInvalidCRL",
+ new Object[] {new TrustedInput(crl.getThisUpdate()), new TrustedInput(crl.getNextUpdate())});
+ addNotification(msg,index);
+ }
+ }
+
+ // if no valid crl was found in the CertStores try to get one from a
+ // crl distribution point
+ if (!validCrlFound)
+ {
+ X509CRL onlineCRL = null;
+ Iterator urlIt = crlDistPointUrls.iterator();
+ while (urlIt.hasNext())
+ {
+ try
+ {
+ String location = (String) urlIt.next();
+ onlineCRL = getCRL(location);
+ if (onlineCRL != null)
+ {
+ // check if crl issuer is correct
+ if (!cert.getIssuerX500Principal().equals(onlineCRL.getIssuerX500Principal()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.onlineCRLWrongCA",
+ new Object[] {new UntrustedInput(onlineCRL.getIssuerX500Principal().getName()),
+ new UntrustedInput(cert.getIssuerX500Principal().getName()),
+ new UntrustedUrlInput(location)});
+ addNotification(msg,index);
+ continue;
+ }
+
+ if (onlineCRL.getNextUpdate() == null
+ || pkixParams.getDate().before(onlineCRL.getNextUpdate()))
+ {
+ validCrlFound = true;
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.onlineValidCRL",
+ new Object[] {new TrustedInput(onlineCRL.getThisUpdate()),
+ new TrustedInput(onlineCRL.getNextUpdate()),
+ new UntrustedUrlInput(location)});
+ addNotification(msg,index);
+ crl = onlineCRL;
+ break;
+ }
+ else
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.onlineInvalidCRL",
+ new Object[] {new TrustedInput(onlineCRL.getThisUpdate()),
+ new TrustedInput(onlineCRL.getNextUpdate()),
+ new UntrustedUrlInput(location)});
+ addNotification(msg,index);
+ }
+ }
+ }
+ catch (CertPathReviewerException cpre)
+ {
+ addNotification(cpre.getErrorMessage(),index);
+ }
+ }
+ }
+
+ // check the crl
+ X509CRLEntry crl_entry;
+ if (crl != null)
+ {
+ if (sign != null)
+ {
+ boolean[] keyusage = sign.getKeyUsage();
+
+ if (keyusage != null
+ && (keyusage.length < 7 || !keyusage[CRL_SIGN]))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCrlSigningPermited");
+ throw new CertPathReviewerException(msg);
+ }
+ }
+
+ if (workingPublicKey != null)
+ {
+ try
+ {
+ crl.verify(workingPublicKey, "BC");
+ }
+ catch (Exception e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlVerifyFailed");
+ throw new CertPathReviewerException(msg,e);
+ }
+ }
+ else // issuer public key not known
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlNoIssuerPublicKey");
+ throw new CertPathReviewerException(msg);
+ }
+
+ crl_entry = crl.getRevokedCertificate(cert.getSerialNumber());
+ if (crl_entry != null)
+ {
+ String reason = null;
+
+ if (crl_entry.hasExtensions())
+ {
+ ASN1Enumerated reasonCode;
+ try
+ {
+ reasonCode = ASN1Enumerated.getInstance(getExtensionValue(crl_entry, X509Extensions.ReasonCode.getId()));
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlReasonExtError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+ if (reasonCode != null)
+ {
+ reason = crlReasons[reasonCode.getValue().intValue()];
+ }
+ }
+
+ if (reason == null)
+ {
+ reason = crlReasons[7]; // unknown
+ }
+
+ // i18n reason
+ LocaleString ls = new LocaleString(RESOURCE_NAME, reason);
+
+ if (!validDate.before(crl_entry.getRevocationDate()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certRevoked",
+ new Object[] {new TrustedInput(crl_entry.getRevocationDate()),ls});
+ throw new CertPathReviewerException(msg);
+ }
+ else // cert was revoked after validation date
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.revokedAfterValidation",
+ new Object[] {new TrustedInput(crl_entry.getRevocationDate()),ls});
+ addNotification(msg,index);
+ }
+ }
+ else // cert is not revoked
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notRevoked");
+ addNotification(msg,index);
+ }
+
+ //
+ // warn if a new crl is available
+ //
+ if (crl.getNextUpdate() != null && crl.getNextUpdate().before(pkixParams.getDate()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlUpdateAvailable",
+ new Object[] {new TrustedInput(crl.getNextUpdate())});
+ addNotification(msg,index);
+ }
+
+ //
+ // check the DeltaCRL indicator, base point and the issuing distribution point
+ //
+ ASN1Primitive idp;
+ try
+ {
+ idp = getExtensionValue(crl, ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.distrPtExtError");
+ throw new CertPathReviewerException(msg);
+ }
+ ASN1Primitive dci;
+ try
+ {
+ dci = getExtensionValue(crl, DELTA_CRL_INDICATOR);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.deltaCrlExtError");
+ throw new CertPathReviewerException(msg);
+ }
+
+ if (dci != null)
+ {
+ X509CRLStoreSelector baseSelect = new X509CRLStoreSelector();
+
+ try
+ {
+ baseSelect.addIssuerName(getIssuerPrincipal(crl).getEncoded());
+ }
+ catch (IOException e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlIssuerException");
+ throw new CertPathReviewerException(msg,e);
+ }
+
+ baseSelect.setMinCRLNumber(((ASN1Integer)dci).getPositiveValue());
+ try
+ {
+ baseSelect.setMaxCRLNumber(((ASN1Integer)getExtensionValue(crl, CRL_NUMBER)).getPositiveValue().subtract(BigInteger.valueOf(1)));
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlNbrExtError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+
+ boolean foundBase = false;
+ Iterator it;
+ try
+ {
+ it = CRL_UTIL.findCRLs(baseSelect, paramsPKIX).iterator();
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlExtractionError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+ while (it.hasNext())
+ {
+ X509CRL base = (X509CRL)it.next();
+
+ ASN1Primitive baseIdp;
+ try
+ {
+ baseIdp = getExtensionValue(base, ISSUING_DISTRIBUTION_POINT);
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.distrPtExtError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+
+ if (idp == null)
+ {
+ if (baseIdp == null)
+ {
+ foundBase = true;
+ break;
+ }
+ }
+ else
+ {
+ if (idp.equals(baseIdp))
+ {
+ foundBase = true;
+ break;
+ }
+ }
+ }
+
+ if (!foundBase)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noBaseCRL");
+ throw new CertPathReviewerException(msg);
+ }
+ }
+
+ if (idp != null)
+ {
+ IssuingDistributionPoint p = IssuingDistributionPoint.getInstance(idp);
+ BasicConstraints bc = null;
+ try
+ {
+ bc = BasicConstraints.getInstance(getExtensionValue(cert, BASIC_CONSTRAINTS));
+ }
+ catch (AnnotatedException ae)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlBCExtError");
+ throw new CertPathReviewerException(msg,ae);
+ }
+
+ if (p.onlyContainsUserCerts() && (bc != null && bc.isCA()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyUserCert");
+ throw new CertPathReviewerException(msg);
+ }
+
+ if (p.onlyContainsCACerts() && (bc == null || !bc.isCA()))
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyCaCert");
+ throw new CertPathReviewerException(msg);
+ }
+
+ if (p.onlyContainsAttributeCerts())
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyAttrCert");
+ throw new CertPathReviewerException(msg);
+ }
+ }
+ }
+
+ if (!validCrlFound)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noValidCrlFound");
+ throw new CertPathReviewerException(msg);
+ }
+
+ }
+
+ protected Vector getCRLDistUrls(CRLDistPoint crlDistPoints)
+ {
+ Vector urls = new Vector();
+
+ if (crlDistPoints != null)
+ {
+ DistributionPoint[] distPoints = crlDistPoints.getDistributionPoints();
+ for (int i = 0; i < distPoints.length; i++)
+ {
+ DistributionPointName dp_name = distPoints[i].getDistributionPoint();
+ if (dp_name.getType() == DistributionPointName.FULL_NAME)
+ {
+ GeneralName[] generalNames = GeneralNames.getInstance(dp_name.getName()).getNames();
+ for (int j = 0; j < generalNames.length; j++)
+ {
+ if (generalNames[j].getTagNo() == GeneralName.uniformResourceIdentifier)
+ {
+ String url = ((DERIA5String) generalNames[j].getName()).getString();
+ urls.add(url);
+ }
+ }
+ }
+ }
+ }
+ return urls;
+ }
+
+ protected Vector getOCSPUrls(AuthorityInformationAccess authInfoAccess)
+ {
+ Vector urls = new Vector();
+
+ if (authInfoAccess != null)
+ {
+ AccessDescription[] ads = authInfoAccess.getAccessDescriptions();
+ for (int i = 0; i < ads.length; i++)
+ {
+ if (ads[i].getAccessMethod().equals(AccessDescription.id_ad_ocsp))
+ {
+ GeneralName name = ads[i].getAccessLocation();
+ if (name.getTagNo() == GeneralName.uniformResourceIdentifier)
+ {
+ String url = ((DERIA5String) name.getName()).getString();
+ urls.add(url);
+ }
+ }
+ }
+ }
+
+ return urls;
+ }
+
+ private X509CRL getCRL(String location) throws CertPathReviewerException
+ {
+ X509CRL result = null;
+ try
+ {
+ URL url = new URL(location);
+
+ if (url.getProtocol().equals("http") || url.getProtocol().equals("https"))
+ {
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setUseCaches(false);
+ //conn.setConnectTimeout(2000);
+ conn.setDoInput(true);
+ conn.connect();
+ if (conn.getResponseCode() == HttpURLConnection.HTTP_OK)
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509","BC");
+ result = (X509CRL) cf.generateCRL(conn.getInputStream());
+ }
+ else
+ {
+ throw new Exception(conn.getResponseMessage());
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ "CertPathReviewer.loadCrlDistPointError",
+ new Object[] {new UntrustedInput(location),
+ e.getMessage(),e,e.getClass().getName()});
+ throw new CertPathReviewerException(msg);
+ }
+ return result;
+ }
+
+ protected Collection getTrustAnchors(X509Certificate cert, Set trustanchors) throws CertPathReviewerException
+ {
+ Collection trustColl = new ArrayList();
+ Iterator it = trustanchors.iterator();
+
+ X509CertSelector certSelectX509 = new X509CertSelector();
+
+ try
+ {
+ certSelectX509.setSubject(getEncodedIssuerPrincipal(cert).getEncoded());
+ byte[] ext = cert.getExtensionValue(X509Extensions.AuthorityKeyIdentifier.getId());
+
+ if (ext != null)
+ {
+ ASN1OctetString oct = (ASN1OctetString)ASN1Primitive.fromByteArray(ext);
+ AuthorityKeyIdentifier authID = AuthorityKeyIdentifier.getInstance(ASN1Primitive.fromByteArray(oct.getOctets()));
+
+ certSelectX509.setSerialNumber(authID.getAuthorityCertSerialNumber());
+ byte[] keyID = authID.getKeyIdentifier();
+ if (keyID != null)
+ {
+ certSelectX509.setSubjectKeyIdentifier(new DEROctetString(keyID).getEncoded());
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustAnchorIssuerError");
+ throw new CertPathReviewerException(msg);
+ }
+
+ while (it.hasNext())
+ {
+ TrustAnchor trust = (TrustAnchor) it.next();
+ if (trust.getTrustedCert() != null)
+ {
+ if (certSelectX509.match(trust.getTrustedCert()))
+ {
+ trustColl.add(trust);
+ }
+ }
+ else if (trust.getCAName() != null && trust.getCAPublicKey() != null)
+ {
+ X500Principal certIssuer = getEncodedIssuerPrincipal(cert);
+ X500Principal caName = new X500Principal(trust.getCAName());
+ if (certIssuer.equals(caName))
+ {
+ trustColl.add(trust);
+ }
+ }
+ }
+ return trustColl;
+ }
+}