|
|
|
package com.fr.third.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 com.fr.third.org.bouncycastle.asn1.ASN1Encodable;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.ASN1Enumerated;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.ASN1InputStream;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.ASN1Integer;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.ASN1OctetString;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.ASN1Primitive;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.ASN1Sequence;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.DERIA5String;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.DEROctetString;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.AccessDescription;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.AuthorityInformationAccess;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.CRLDistPoint;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.DistributionPoint;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.DistributionPointName;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.Extension;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.GeneralName;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.GeneralSubtree;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.IssuingDistributionPoint;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.NameConstraints;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.PolicyInformation;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.qualified.Iso4217CurrencyCode;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.qualified.MonetaryValue;
|
|
|
|
import com.fr.third.org.bouncycastle.asn1.x509.qualified.QCStatement;
|
|
|
|
import com.fr.third.org.bouncycastle.i18n.ErrorBundle;
|
|
|
|
import com.fr.third.org.bouncycastle.i18n.LocaleString;
|
|
|
|
import com.fr.third.org.bouncycastle.i18n.filter.TrustedInput;
|
|
|
|
import com.fr.third.org.bouncycastle.i18n.filter.UntrustedInput;
|
|
|
|
import com.fr.third.org.bouncycastle.i18n.filter.UntrustedUrlInput;
|
|
|
|
import com.fr.third.org.bouncycastle.jce.provider.AnnotatedException;
|
|
|
|
import com.fr.third.org.bouncycastle.jce.provider.PKIXNameConstraintValidator;
|
|
|
|
import com.fr.third.org.bouncycastle.jce.provider.PKIXNameConstraintValidatorException;
|
|
|
|
import com.fr.third.org.bouncycastle.jce.provider.PKIXPolicyNode;
|
|
|
|
import com.fr.third.org.bouncycastle.util.Integers;
|
|
|
|
import com.fr.third.org.bouncycastle.util.Objects;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 = Extension.qCStatements.getId();
|
|
|
|
private static final String CRL_DIST_POINTS = Extension.cRLDistributionPoints.getId();
|
|
|
|
private static final String AUTH_INFO_ACCESS = Extension.authorityInfoAccess.getId();
|
|
|
|
|
|
|
|
private static final String RESOURCE_NAME = "com.fr.third.org.bouncycastle.x509.CertPathReviewerMessages";
|
|
|
|
|
|
|
|
// input parameters
|
|
|
|
|
|
|
|
protected CertPath certPath;
|
|
|
|
|
|
|
|
protected PKIXParameters pkixParams;
|
|
|
|
|
|
|
|
protected Date currentDate;
|
|
|
|
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)
|
|
|
|
|
|
|
|
currentDate = new Date();
|
|
|
|
validDate = getValidityDate(pkixParams, currentDate);
|
|
|
|
|
|
|
|
// 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.pathLengthExtended");
|
|
|
|
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(currentDate)});
|
|
|
|
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.length <= 5 || !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.getAlgorithm();
|
|
|
|
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(Extension.authorityKeyIdentifier.getId());
|
|
|
|
if (akiBytes != null)
|
|
|
|
{
|
|
|
|
AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance(
|
|
|
|
DEROctetString.getInstance(akiBytes).getOctets());
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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[] keyUsage = cert.getKeyUsage();
|
|
|
|
|
|
|
|
if (keyUsage != null && (keyUsage.length <= KEY_CERT_SIGN || !keyUsage[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.getAlgorithm();
|
|
|
|
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).intValueExact();
|
|
|
|
if (tmpInt < explicitPolicy)
|
|
|
|
{
|
|
|
|
explicitPolicy = tmpInt;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
tmpInt = ASN1Integer.getInstance(constraint, false).intValueExact();
|
|
|
|
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.intValueExact();
|
|
|
|
|
|
|
|
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).intValueExact();
|
|
|
|
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 = PKIXCRLUtil.findCRLs(crlselect, paramsPKIX);
|
|
|
|
crl_iter = crl_coll.iterator();
|
|
|
|
|
|
|
|
if (crl_coll.isEmpty())
|
|
|
|
{
|
|
|
|
// notification - no local crls found
|
|
|
|
crl_coll = PKIXCRLUtil.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();
|
|
|
|
|
|
|
|
Date thisUpdate = crl.getThisUpdate();
|
|
|
|
Date nextUpdate = crl.getNextUpdate();
|
|
|
|
Object[] arguments = new Object[]{ new TrustedInput(thisUpdate), new TrustedInput(nextUpdate) };
|
|
|
|
|
|
|
|
if (nextUpdate == null || validDate.before(crl.getNextUpdate()))
|
|
|
|
{
|
|
|
|
validCrlFound = true;
|
|
|
|
ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.localValidCRL", arguments);
|
|
|
|
addNotification(msg,index);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.localInvalidCRL", arguments);
|
|
|
|
addNotification(msg,index);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if no valid crl was found in the CertStores try to get one from a
|
|
|
|
// crl distribution point
|
|
|
|
if (!validCrlFound)
|
|
|
|
{
|
|
|
|
X500Principal certIssuer = cert.getIssuerX500Principal();
|
|
|
|
|
|
|
|
X509CRL onlineCRL = null;
|
|
|
|
Iterator urlIt = crlDistPointUrls.iterator();
|
|
|
|
while (urlIt.hasNext())
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
String location = (String) urlIt.next();
|
|
|
|
onlineCRL = getCRL(location);
|
|
|
|
if (onlineCRL != null)
|
|
|
|
{
|
|
|
|
X500Principal crlIssuer = onlineCRL.getIssuerX500Principal();
|
|
|
|
|
|
|
|
// check if crl issuer is correct
|
|
|
|
if (!certIssuer.equals(crlIssuer))
|
|
|
|
{
|
|
|
|
ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.onlineCRLWrongCA",
|
|
|
|
new Object[]{ new UntrustedInput(crlIssuer.getName()), new UntrustedInput(certIssuer.getName()),
|
|
|
|
new UntrustedUrlInput(location) });
|
|
|
|
addNotification(msg,index);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Date thisUpdate = onlineCRL.getThisUpdate();
|
|
|
|
Date nextUpdate = onlineCRL.getNextUpdate();
|
|
|
|
Object[] arguments = new Object[]{ new TrustedInput(thisUpdate), new TrustedInput(nextUpdate),
|
|
|
|
new UntrustedUrlInput(location) };
|
|
|
|
|
|
|
|
if (nextUpdate == null || validDate.before(nextUpdate))
|
|
|
|
{
|
|
|
|
validCrlFound = true;
|
|
|
|
ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.onlineValidCRL",
|
|
|
|
arguments);
|
|
|
|
addNotification(msg, index);
|
|
|
|
crl = onlineCRL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.onlineInvalidCRL",
|
|
|
|
arguments);
|
|
|
|
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 <= CRL_SIGN || !keyUsage[CRL_SIGN]))
|
|
|
|
{
|
|
|
|
ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCrlSigningPermited");
|
|
|
|
throw new CertPathReviewerException(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (workingPublicKey != null)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// [BouncyCastle]
|
|
|
|
crl.verify(workingPublicKey, "FR_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, Extension.reasonCode.getId()));
|
|
|
|
}
|
|
|
|
catch (AnnotatedException ae)
|
|
|
|
{
|
|
|
|
ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlReasonExtError");
|
|
|
|
throw new CertPathReviewerException(msg,ae);
|
|
|
|
}
|
|
|
|
if (reasonCode != null)
|
|
|
|
{
|
|
|
|
reason = crlReasons[reasonCode.intValueExact()];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
//
|
|
|
|
Date nextUpdate = crl.getNextUpdate();
|
|
|
|
if (!(nextUpdate == null || validDate.before(nextUpdate)))
|
|
|
|
{
|
|
|
|
ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.crlUpdateAvailable",
|
|
|
|
new Object[]{ new TrustedInput(nextUpdate) });
|
|
|
|
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 = PKIXCRLUtil.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 (Objects.areEqual(idp, 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)
|
|
|
|
{
|
|
|
|
// [BouncyCastle]
|
|
|
|
CertificateFactory cf = CertificateFactory.getInstance("X.509","FR_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(Extension.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;
|
|
|
|
}
|
|
|
|
}
|