/*
* Copyright (c) 2011 ICM Uniwersytet Warszawski All rights reserved.
* See LICENCE file for licensing information.
*/
package eu.emi.security.authn.x509.helpers.pkipath;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.cert.CertPath;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.i18n.ErrorBundle;
import org.bouncycastle.jcajce.PKIXExtendedParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.CertPathReviewerException;
import org.bouncycastle.x509.PKIXCertPathReviewer;
import eu.emi.security.authn.x509.RevocationParameters;
import eu.emi.security.authn.x509.ValidationError;
import eu.emi.security.authn.x509.ValidationErrorCode;
import eu.emi.security.authn.x509.ValidationResult;
import eu.emi.security.authn.x509.helpers.CertificateHelpers;
import eu.emi.security.authn.x509.helpers.JavaAndBCStyle;
import eu.emi.security.authn.x509.helpers.ObserversHandler;
import eu.emi.security.authn.x509.helpers.pkipath.bc.FixedBCPKIXCertPathReviewer;
import eu.emi.security.authn.x509.helpers.proxy.ExtendedProxyType;
import eu.emi.security.authn.x509.helpers.proxy.ProxyHelper;
import eu.emi.security.authn.x509.impl.CertificateUtils;
import eu.emi.security.authn.x509.impl.FormatMode;
import eu.emi.security.authn.x509.impl.X500NameUtils;
import eu.emi.security.authn.x509.proxy.ProxyUtils;
/**
* Low-level certificate validator based on the BC {@link PKIXCertPathReviewer}
* with additional support for proxy certificates.
* @author K. Benedyczak
*/
public class BCCertPathValidator
{
public static final long PROXY_VALIDATION_GRACE_PERIOD = 5*60000;
/**
* Performs validation. Expects correctly set up parameters.
* <p>
* If the proxy support is turned off or the chain has no proxy certificate then
* normal X.509 path validation is performed (see below).
* <p>
* If the proxy support is turned on and the chain has at least one proxy then the
* following checks are performed:
* <ul>
* <li> The chain is split into two chains A and B, where B ends with the
* first element of A and it is the first not proxy certificate in the original chain
* (i.e. the EEC which is the split point).
* <li> The chain A is validated using normal X.509 path validation.
* <li> The chain B is also validated with the X.509 path validation
* but PROXY extension OIDs are recognized, the only trust anchor is the EEC, the
* CRLs are ignored, the CA constraint is not required on any issuing certificate
* and the certificate sign bit is also not required.
* <li> The chain B is iterated over and on each pair additional checks from the
* RFC 3820 are verified, along with the proxy path limit.
* </ul>
* <p>
* The normal path validation is performed as follows:
* <ul>
* <li> First all basically correct (i.e. fulfilling name chaining rules)
* certificate paths are tried to be constructed from the input chain. This step
* produces from zero to many paths (in 99%: 0 or 1).
* Those paths can differ from the input e.g. by having self-signed intermediary
* CA certificate removed.
* <li> If there were no path constructed, the input chain is used as-is, as the only
* possible path. At this step we already know it is invalid, but we anyway continue to
* establish complete and detailed list of errors.
* <li> All constructed paths are validated using PKIX rules, and errors found are
* recorded. If at least one path validates successfully the algorithm ends.
* <li> If all paths were invalid, the one with the least number of errors is selected
* and those errors are reported as the validation result.
* </ul>
*
* @param toCheck chain to check
* @param proxySupport proxy support
* @param trustAnchors trust anchors
* @param crlStore crl store
* @param revocationParams revocation params
* @param observersHandler observers handler
* @return validation result
* @throws CertificateException if some of the certificates in the chain can not
* be parsed
*/
public ValidationResult validate(X509Certificate[] toCheck, boolean proxySupport,
Set<TrustAnchor> trustAnchors, CertStore crlStore,
RevocationParameters revocationParams, ObserversHandler observersHandler)
throws CertificateException
{
if (toCheck == null || toCheck.length == 0)
throw new IllegalArgumentException("Chain to be validated must be non-empty");
List<ValidationError> errors = new ArrayList<ValidationError>();
Set<String> unresolvedExtensions = new HashSet<String>();
if (trustAnchors.isEmpty())
{
//Empty trust anchors set is fine for ExtPKIXParameters but not for the plain PKIXParamters.
//As we can possibly use them when checking proxy chains
//make a proper error and return it, instead of ugly exception.
errors.add(new ValidationError(toCheck, -1, ValidationErrorCode.noTrustAnchorFound));
errors.add(new ValidationError(toCheck, 0, ValidationErrorCode.noIssuerPublicKey));
return new ValidationResult(false, errors, unresolvedExtensions, null);
}
if (!proxySupport || !ProxyUtils.isProxy(toCheck))
{
ExtPKIXParameters2 params = createPKIXParameters(toCheck, proxySupport,
trustAnchors, crlStore, revocationParams, observersHandler);
List<X509Certificate> chain = checkNonProxyChain(toCheck, params, errors, unresolvedExtensions, 0, toCheck);
return new ValidationResult(errors.size() == 0, errors, unresolvedExtensions, chain);
}
//now we know that we have proxies in the chain and proxy support is turned on
int split = getFirstProxy(toCheck);
if (split == toCheck.length-1)
{
errors.add(new ValidationError(toCheck, -1, ValidationErrorCode.proxyNoIssuer));
return new ValidationResult(false, errors, unresolvedExtensions, null);
}
X509Certificate[] baseChain = new X509Certificate[toCheck.length-split-1];
X509Certificate[] proxyChain = new X509Certificate[split+2];
for (int i=split+1; i<toCheck.length; i++)
baseChain[i-split-1] = toCheck[i];
for (int i=0; i<split+2; i++)
proxyChain[i] = toCheck[i];
ExtPKIXParameters2 params = createPKIXParameters(baseChain, proxySupport,
trustAnchors, crlStore, revocationParams, observersHandler);
List<X509Certificate> validatedChain = checkNonProxyChain(baseChain, params, errors, unresolvedExtensions, split+1, toCheck);
Set<TrustAnchor> trustForProxyChain;
if (baseChain.length > 1)
trustForProxyChain = Collections.singleton(new TrustAnchor(baseChain[1], null));
else
trustForProxyChain = trustAnchors;
checkProxyChainWithBC(proxyChain, trustForProxyChain, errors, unresolvedExtensions);
checkProxyChainMain(proxyChain, errors, unresolvedExtensions, params.getBaseParameters().getDate());
if (errors.size() == 0 && validatedChain != null)
{
for (int j=proxyChain.length-2; j>=0; j--)
validatedChain.add(0, proxyChain[j]);
}
return new ValidationResult(errors.size() == 0, errors, unresolvedExtensions, validatedChain);
}
protected ExtPKIXParameters2 createPKIXParameters(X509Certificate[] toCheck, boolean proxySupport,
Set<TrustAnchor> trustAnchors, CertStore crlStore,
RevocationParameters revocationParams, ObserversHandler observersHandler)
{
X509CertSelector endSelector = new X509CertSelector();
endSelector.setCertificate(toCheck[0]);
PKIXParameters baseOfBase;
try
{
baseOfBase = new PKIXParameters(trustAnchors);
} catch (InvalidAlgorithmParameterException e)
{
throw new IllegalStateException("Can't create PKIXParameters, shouldn't happen", e);
}
baseOfBase.setTargetCertConstraints(endSelector);
baseOfBase.setDate(new Date());
baseOfBase.addCertStore(crlStore);
CertStore certStore;
try
{
certStore = CertStore.getInstance("Collection",
new CollectionCertStoreParameters(Arrays.asList(toCheck)),
BouncyCastleProvider.PROVIDER_NAME);
} catch (Exception e1)
{
throw new RuntimeException("Can't create an instance of a " +
"simple Collection certificate store, using the BC provider, BUG?", e1);
}
baseOfBase.addCertStore(certStore);
PKIXExtendedParameters.Builder baseBuilder = new PKIXExtendedParameters.Builder(baseOfBase);
ExtPKIXParameters2.Builder paramsBuilder = new ExtPKIXParameters2.Builder(
baseBuilder, baseOfBase, trustAnchors, observersHandler);
paramsBuilder.setRevocationParams(revocationParams);
paramsBuilder.setProxySupport(proxySupport);
return paramsBuilder.build();
}
protected int getFirstProxy(X509Certificate[] toCheck)
{
int j;
for (j=toCheck.length-1; j>=0; j--)
if (ProxyUtils.isProxy(toCheck[j]))
return j;
//can't happen as we call this method with at least one proxy
throw new RuntimeException("No proxy found, while it should be in chain?? BUG");
}
/*
* Performs checking of the chain which has no proxies (or at least should not have proxies),
* using JCA CertPathBuilder, from BC provider. This is not used in production,
* rather is an alternative implementation useful in testing and debugging.
* @param baseChain
* @param params
* @param errors
* @param unresolvedExtensions
* @throws CertificateException
*/
/*
protected void checkNonProxyChain2(X509Certificate[] baseChain,
ExtendedPKIXBuilderParameters params, List<ValidationError> errors,
Set<String> unresolvedExtensions, int posDelta, X509Certificate[] cc) throws CertificateException
{
CertPathBuilder builder;
try
{
builder = CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
} catch (Exception e1)
{
throw new RuntimeException("Can't instantiate PKIX CertPathBuilder " +
"using the BC provider, really shouldn't happen", e1);
}
try
{
CertPathBuilderResult res = builder.build(params);
res.getCertPath();
} catch (CertPathBuilderException e)
{
e.printStackTrace();
Throwable cause = e.getCause();
if (cause != null && cause instanceof ExtCertPathValidatorException) {
errors.add(new ValidationError(cc, -1, ValidationErrorCode.unknownMsg, cause.toString()));
} else
errors.add(new ValidationError(cc, -1, ValidationErrorCode.unknownMsg, e.toString()));
} catch (InvalidAlgorithmParameterException e)
{
throw new RuntimeException("BUG, shouldn't happen, parameters " +
"for the BC CertPathBuilder were prepared correctly.", e);
}
}
*/
/**
* Performs checking of the chain which has no proxies (or at least should not have proxies),
* using {@link FixedBCPKIXCertPathReviewer}. In future, when BC implementation is fixed
* it should use {@link PKIXCertPathReviewer} instead.
* @param baseChain base chain
* @param params parameters
* @param errors errors
* @param unresolvedExtensions unresolved extensions
* @param posDelta position delta
* @param cc certificate chain
* @return validated chain or null
* @throws CertificateException certificate exception
*/
protected List<X509Certificate> checkNonProxyChain(X509Certificate[] baseChain,
ExtPKIXParameters2 params, List<ValidationError> errors,
Set<String> unresolvedExtensions, int posDelta, X509Certificate[] cc)
throws CertificateException
{
NonValidatingCertPathBuilder builder = new NonValidatingCertPathBuilder();
List<CertPath> certPaths;
List<ValidationError> buildPathErrors = null;
try
{
certPaths = builder.buildPath(params.getBaseBuildParameters(), baseChain[0], cc);
} catch (ValidationErrorException e1)
{
buildPathErrors = e1.getErrors();
certPaths = Collections.singletonList(CertificateHelpers.toCertPath(baseChain));
}
// PKIXCertPathReviewer baseReviewer;
FixedBCPKIXCertPathReviewer baseReviewer;
List<ValidationError> validationErrors = null;
List<?>[] rawErrors = null;
for (int i=0; i<certPaths.size(); i++)
{
try
{
baseReviewer = new FixedBCPKIXCertPathReviewer(certPaths.get(i), params);
// baseReviewer = new PKIXCertPathReviewer(certPaths.get(i), params);
} catch (CertPathReviewerException e)
{
//really shoudn't happen - we have checked the arguments
throw new IllegalStateException("Can't init PKIXCertPathReviewer, bug?", e);
}
if (buildPathErrors != null && baseReviewer.isValidCertPath())
{
//ups!!! bad! PKIXCertPAthReviewer validated while the path was not even build
throw new IllegalStateException("PKIXCertPAthReviewer validated while the path was not even " +
"build correctly. Build path error: " + buildPathErrors.get(0));
}
List<ValidationError> processedErrors = convertErrors(baseReviewer.getErrors(), false, posDelta, cc);
if (processedErrors.size() == 0)
{
X509Certificate ta = baseReviewer.getTrustAnchor().getTrustedCert();
if (ta == null)
return null;
List<? extends Certificate> path = certPaths.get(i).getCertificates();
List<X509Certificate> ret = new ArrayList<X509Certificate>(path.size()+1);
for (int j=0; j<path.size(); j++)
ret.add((X509Certificate) path.get(j));
ret.add(ta);
return ret;
}
if (validationErrors == null || validationErrors.size() > processedErrors.size())
{
validationErrors = processedErrors;
rawErrors = baseReviewer.getErrors();
}
}
if (validationErrors != null)
{
//let's report errors from the validation which had a smallest number of them
errors.addAll(validationErrors);
if (rawErrors != null)
unresolvedExtensions.addAll(getUnresolvedExtensionons(rawErrors));
} else
{
throw new IllegalStateException("PKIXCertPAthReviewer BUG: validationErrors is null, " +
"tested chain: " + CertificateUtils.format(baseChain, FormatMode.FULL));
}
return null;
}
/**
* Checks chain with proxies, starting with the EEC using X.509 path validation.
* EEC issuer is used as the only trust anchor. CRLs are ignored, proxy extension OIDs
* are marked as handled. The error resulting from the missing CA extension is
* ignored as well as validity time errors. The latter are checked manually later on.
* @param proxyChain proxy chain
* @param trustAnchor trust anchor
* @param errors errors
* @param unresolvedExtensions unresolved extensions
* @throws CertificateException certificate exception
*/
protected void checkProxyChainWithBC(X509Certificate[] proxyChain,
Set<TrustAnchor> trustAnchor,
List<ValidationError> errors, Set<String> unresolvedExtensions)
throws CertificateException
{
CertPath proxyCertPath = CertificateHelpers.toCertPath(proxyChain);
PKIXCertPathReviewer proxyReviewer;
try
{
PKIXParameters proxyParams = new PKIXParameters(trustAnchor);
proxyParams.addCertPathChecker(new PKIXProxyCertificateChecker());
proxyParams.setRevocationEnabled(false);
proxyReviewer = new PKIXCertPathReviewer(proxyCertPath, proxyParams);
} catch (InvalidAlgorithmParameterException e1)
{
//really shoudn't happen - we have checked the arguments
throw new RuntimeException("Can't init PKIXParameters, bug?", e1);
} catch (CertPathReviewerException e)
{
//really shoudn't happen - we have checked the arguments
throw new RuntimeException("Can't init PKIXCertPathReviewer, bug?", e);
}
errors.addAll(convertErrors(proxyReviewer.getErrors(), true, 0, proxyChain));
unresolvedExtensions.addAll(getUnresolvedExtensionons(proxyReviewer.getErrors()));
}
/**
* Performs a validation loop of the proxy chain checking each pair in chain
* for the rules not otherwise verified by the base check. Additionally chain length
* restriction is verified.
* @param proxyChain proxy chain
* @param errors errors
* @param unresolvedExtensions unresolved extensions
* @param validDate valid date
* @throws CertificateException certificate exception
*/
protected void checkProxyChainMain(X509Certificate[] proxyChain,
List<ValidationError> errors, Set<String> unresolvedExtensions, Date validDate)
throws CertificateException
{
int remainingLen = Integer.MAX_VALUE;
int last = proxyChain.length-1;
for (int i=last; i>0; i--)
{
try
{
checkPairWithProxy(proxyChain[i], proxyChain[i-1], errors, i-1, proxyChain, validDate);
if (i != last && remainingLen != Integer.MIN_VALUE)
{
int lenRestriction = ProxyHelper.getProxyPathLimit(proxyChain[i]);
if (lenRestriction < remainingLen)
remainingLen = lenRestriction-1;
else
{
if (remainingLen != Integer.MAX_VALUE)
remainingLen--;
}
if (remainingLen < 0)
{
remainingLen = Integer.MIN_VALUE;
errors.add(new ValidationError(proxyChain, i-1, ValidationErrorCode.proxyLength));
}
}
} catch (CertPathValidatorException e)
{
break;
} catch (IOException e)
{
throw new CertificateException("Can't parse the proxy path limit information", e);
}
}
}
/**
* Checks if the certificate passed as the 2nd argument is a correct proxy
* certificate including checks w.r.t. chain rules with the certificate passed
* as the 1st argument being its issuing certificate. The checks are:
* <ul>
* <li> proxyCert is a real proxy cert of any type
* <li> issuer may not be a CA (3.1)
* <li> issuer must have subject set (3.1)
* <li> proxy must have issuer equal to issuerCert subject (3.1)
* <li> If the Proxy Issuer certificate has the KeyUsage extension, the
* Digital Signature bit MUST be asserted. (3.1)
* <li> no issuer alternative name extension (3.2)
* <li> proxy subject must be the issuerCert subject with appended one CN component (3.4)
* <li> no subject alternative name extension (3.5)
* <li> no cA basic constraint (3.7)
* <li> time constraints for the proxy are checked here (as we allow for a grace time to work around clock skews)
* <li> proxy certificate type (RFC, draft RFC or legacy) must be the same for both certificates
* <li> if the issuerCert is restricted then proxyCert must be restricted too.
* </ul>
* The numbers in brackets refer to the RFC 3820 sections. The last two rules were added in the version 1.1.0 of
* the library.
* <p>
*
* @param issuerCert certificate of the issuer
* @param proxyCert certificate to be checked
* @param errors out arg - list of errors found
* @param position position in original chain to be used in error reporting
* @param proxyChain proxy chain
* @param validationTime validation time
* @throws CertPathValidatorException certificate path validator exception
* @throws CertificateParsingException certificate parsing exception
*/
protected void checkPairWithProxy(X509Certificate issuerCert, X509Certificate proxyCert,
List<ValidationError> errors, int position, X509Certificate[] proxyChain, Date validationTime)
throws CertPathValidatorException, CertificateParsingException
{
if (!ProxyUtils.isProxy(proxyCert))
{
errors.add(new ValidationError(proxyChain, position, ValidationErrorCode.proxyEECInChain));
throw new CertPathValidatorException();
}
if (proxyCert.getBasicConstraints() >= 0)
errors.add(new ValidationError(proxyChain, position, ValidationErrorCode.proxyCASet));
if (proxyCert.getIssuerAlternativeNames() != null)
errors.add(new ValidationError(proxyChain, position, ValidationErrorCode.proxyIssuerAltNameSet));
if (proxyCert.getSubjectAlternativeNames() != null)
errors.add(new ValidationError(proxyChain, position, ValidationErrorCode.proxySubjectAltNameSet));
if (issuerCert.getBasicConstraints() >= 0)
errors.add(new ValidationError(proxyChain, position+1, ValidationErrorCode.proxyIssuedByCa));
X500Principal issuerDN = issuerCert.getSubjectX500Principal();
if ("".equals(issuerDN.getName()))
{
errors.add(new ValidationError(proxyChain, position+1, ValidationErrorCode.proxyNoIssuerSubject));
throw new CertPathValidatorException();
}
if (!X500NameUtils.rfc3280Equal(issuerDN, proxyCert.getIssuerX500Principal()))
errors.add(new ValidationError(proxyChain, position, ValidationErrorCode.proxySubjectInconsistent));
boolean[] keyUsage = issuerCert.getKeyUsage();
if (keyUsage != null && !keyUsage[0])
errors.add(new ValidationError(proxyChain, position+1, ValidationErrorCode.proxyIssuerNoDsig));
checkLastCNNameRule(proxyCert.getSubjectX500Principal(), issuerDN, errors, position, proxyChain);
checkProxyTime(proxyCert, validationTime, proxyChain, errors, position);
if (position+2 != proxyChain.length) //we won't check it for the first pair as it contains an EEC
{
ExtendedProxyType issuerType = ProxyHelper.getProxyType(issuerCert);
ExtendedProxyType proxyType = ProxyHelper.getProxyType(proxyCert);
if (issuerType != proxyType)
errors.add(new ValidationError(proxyChain, position, ValidationErrorCode.proxyTypeInconsistent));
try
{
if (ProxyHelper.isLimited(issuerCert) && !ProxyHelper.isLimited(proxyCert))
errors.add(new ValidationError(proxyChain, position, ValidationErrorCode.proxyInconsistentlyLimited));
} catch (IOException e)
{
throw new CertificateParsingException("Can't establish whether the proxy is limited", e);
}
}
}
protected void checkProxyTime(X509Certificate proxyCert, Date validationTime, X509Certificate[] proxyChain,
List<ValidationError> errors, int position)
{
if (validationTime.getTime() > proxyCert.getNotAfter().getTime() + PROXY_VALIDATION_GRACE_PERIOD)
{
errors.add(new ValidationError(proxyChain, position,
ValidationErrorCode.certificateExpired, proxyCert.getNotAfter()));
}
if (validationTime.getTime() < proxyCert.getNotBefore().getTime()-PROXY_VALIDATION_GRACE_PERIOD)
{
errors.add(new ValidationError(proxyChain, position,
ValidationErrorCode.certificateNotYetValid, proxyCert.getNotBefore()));
}
}
protected void checkLastCNNameRule(X500Principal srcP, X500Principal issuerP,
List<ValidationError> errors, int position, X509Certificate[] proxyChain) throws CertPathValidatorException
{
X500Name src = CertificateHelpers.toX500Name(srcP);
X500Name issuer = CertificateHelpers.toX500Name(issuerP);
RDN[] srcRDNs = src.getRDNs();
if (srcRDNs.length < 2)
{
errors.add(new ValidationError(proxyChain, position+1, ValidationErrorCode.proxySubjectOneRDN));
throw new CertPathValidatorException();
}
if (srcRDNs[srcRDNs.length-1].isMultiValued())
{
errors.add(new ValidationError(proxyChain, position+1, ValidationErrorCode.proxySubjectMultiLastRDN));
throw new CertPathValidatorException();
}
AttributeTypeAndValue lastAVA = srcRDNs[srcRDNs.length-1].getFirst();
if (!lastAVA.getType().equals(BCStyle.CN))
{
errors.add(new ValidationError(proxyChain, position+1, ValidationErrorCode.proxySubjectLastRDNNotCN));
throw new CertPathValidatorException();
}
RDN[] finalRDNs = Arrays.copyOf(srcRDNs, srcRDNs.length-1);
JavaAndBCStyle style = new JavaAndBCStyle();
X500Name truncatedName = new X500Name(style, finalRDNs);
if (!style.areEqual(issuer, truncatedName))
errors.add(new ValidationError(proxyChain, position+1, ValidationErrorCode.proxySubjectBaseWrong));
}
protected List<ValidationError> convertErrors(List<?>[] bcErrorsA,
boolean ignoreProxyErrors, int positionDelta, X509Certificate[] cc)
{
List<ValidationError> ret = new ArrayList<ValidationError>();
for (int i=0; i<bcErrorsA.length; i++)
{
List<?> bcErrors = bcErrorsA[i];
for (Object bcError: bcErrors)
{
if (bcError instanceof ErrorBundle)
{
ErrorBundle error = (ErrorBundle) bcError;
if (ignoreProxyErrors)
{
String id = error.getId();
if (id.equals("CertPathReviewer.noBasicConstraints"))
continue;
if (id.equals("CertPathReviewer.noCACert"))
continue;
if (id.equals("CertPathReviewer.noCertSign"))
continue;
if (id.equals("CertPathReviewer.certificateNotYetValid"))
continue;
if (id.equals("CertPathReviewer.certificateExpired"))
continue;
}
ret.add(BCErrorMapper.map(error, i-1+positionDelta, cc));
} else
{
SimpleValidationErrorException error = (SimpleValidationErrorException) bcError;
if (ignoreProxyErrors)
{
ValidationErrorCode id = error.getCode();
if (id.equals(ValidationErrorCode.noBasicConstraints))
continue;
if (id.equals(ValidationErrorCode.noCACert))
continue;
if (id.equals(ValidationErrorCode.noCertSign))
continue;
if (id.equals(ValidationErrorCode.certificateExpired))
continue;
if (id.equals(ValidationErrorCode.certificateNotYetValid))
continue;
}
ret.add(new ValidationError(cc, i-1+positionDelta,
error.getCode(), error.getArguments()));
}
}
}
return ret;
}
protected Set<String> getUnresolvedExtensionons(List<?>[] bcErrorsA)
{
Set<String> ret = new HashSet<String>();
for (int i=0; i<bcErrorsA.length; i++)
{
List<?> bcErrors = bcErrorsA[i];
for (Object bcError: bcErrors)
{
if (bcError instanceof ErrorBundle)
{
ErrorBundle error = (ErrorBundle) bcError;
if (error.getId().equals("CertPathReviewer.unknownCriticalExt"))
{
ASN1ObjectIdentifier extId = (ASN1ObjectIdentifier) error.getArguments()[0];
ret.add(extId.getId());
}
} else
{
SimpleValidationErrorException error = (SimpleValidationErrorException) bcError;
if (error.getCode().equals(ValidationErrorCode.unknownCriticalExt))
{
ASN1ObjectIdentifier extId = (ASN1ObjectIdentifier) error.getArguments()[0];
ret.add(extId.getId());
}
}
}
}
return ret;
}
}