org.opensaml.xml.security.x509.CertPathPKIXTrustEvaluator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of xmltooling Show documentation
Show all versions of xmltooling Show documentation
XMLTooling-J is a low-level library that may be used to construct libraries that allow developers to work with XML in a Java beans manner.
/*
* Licensed to the University Corporation for Advanced Internet Development,
* Inc. (UCAID) under one or more contributor license agreements. See the
* NOTICE file distributed with this work for additional information regarding
* copyright ownership. The UCAID licenses this file to You under the Apache
* License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opensaml.xml.security.x509;
import java.security.GeneralSecurityException;
import java.security.cert.CRL;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.Certificate;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CRL;
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.HashSet;
import java.util.List;
import java.util.Set;
import org.opensaml.xml.security.SecurityException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* An implementation of {@link PKIXTrustEvaluator} that is based on the Java CertPath API.
*/
public class CertPathPKIXTrustEvaluator implements PKIXTrustEvaluator {
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(CertPathPKIXTrustEvaluator.class);
/**
* Responsible for parsing and serializing X.500 names to/from {@link javax.security.auth.x500.X500Principal}
* instances.
*/
private X500DNHandler x500DNHandler;
/** Options influencing processing behavior. */
private PKIXValidationOptions options;
/** Constructor. */
public CertPathPKIXTrustEvaluator() {
options = new PKIXValidationOptions();
x500DNHandler = new InternalX500DNHandler();
}
/**
* Constructor.
*
* @param newOptions PKIX validation options
*/
public CertPathPKIXTrustEvaluator(PKIXValidationOptions newOptions) {
if (newOptions == null) {
throw new IllegalArgumentException("PKIXValidationOptions may not be null");
}
options = newOptions;
x500DNHandler = new InternalX500DNHandler();
}
/** {@inheritDoc} */
public PKIXValidationOptions getPKIXValidationOptions() {
return options;
}
/**
* Set the desired PKIX validation options set.
*
* @param newOptions the new set of options
*/
public void setPKIXValidationOptions(PKIXValidationOptions newOptions) {
if (newOptions == null) {
throw new IllegalArgumentException("PKIXValidationOptions may not be null");
}
options = newOptions;
}
/**
* Get the handler which process X.500 distinguished names.
*
* Defaults to {@link InternalX500DNHandler}.
*
* @return returns the X500DNHandler instance
*/
public X500DNHandler getX500DNHandler() {
return x500DNHandler;
}
/**
* Set the handler which process X.500 distinguished names.
*
* Defaults to {@link InternalX500DNHandler}.
*
* @param handler the new X500DNHandler instance
*/
public void setX500DNHandler(X500DNHandler handler) {
if (handler == null) {
throw new IllegalArgumentException("X500DNHandler may not be null");
}
x500DNHandler = handler;
}
/** {@inheritDoc} */
public boolean validate(PKIXValidationInformation validationInfo, X509Credential untrustedCredential)
throws SecurityException {
if (log.isDebugEnabled()) {
log.debug("Attempting PKIX path validation on untrusted credential: {}",
X509Util.getIdentifiersToken(untrustedCredential, x500DNHandler));
}
try {
PKIXBuilderParameters params = getPKIXBuilderParameters(validationInfo, untrustedCredential);
log.trace("Building certificate validation path");
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
PKIXCertPathBuilderResult buildResult = (PKIXCertPathBuilderResult) builder.build(params);
if (log.isDebugEnabled()) {
logCertPathDebug(buildResult, untrustedCredential.getEntityCertificate());
log.debug("PKIX validation succeeded for untrusted credential: {}",
X509Util.getIdentifiersToken(untrustedCredential, x500DNHandler));
}
return true;
} catch (CertPathBuilderException e) {
if (log.isTraceEnabled()) {
log.trace("PKIX path construction failed for untrusted credential: "
+ X509Util.getIdentifiersToken(untrustedCredential, x500DNHandler), e);
} else {
log.error("PKIX path construction failed for untrusted credential: "
+ X509Util.getIdentifiersToken(untrustedCredential, x500DNHandler) + ": " + e.getMessage());
}
return false;
} catch (GeneralSecurityException e) {
log.error("PKIX validation failure", e);
throw new SecurityException("PKIX validation failure", e);
}
}
/**
* Creates the set of PKIX builder parameters to use when building the cert path builder.
*
* @param validationInfo PKIX validation information
* @param untrustedCredential credential to be validated
*
* @return PKIX builder params
*
* @throws GeneralSecurityException thrown if the parameters can not be created
*/
protected PKIXBuilderParameters getPKIXBuilderParameters(PKIXValidationInformation validationInfo,
X509Credential untrustedCredential) throws GeneralSecurityException {
Set trustAnchors = getTrustAnchors(validationInfo);
if (trustAnchors == null || trustAnchors.isEmpty()) {
throw new GeneralSecurityException(
"Unable to validate X509 certificate, no trust anchors found in the PKIX validation information");
}
X509CertSelector selector = new X509CertSelector();
selector.setCertificate(untrustedCredential.getEntityCertificate());
log.trace("Adding trust anchors to PKIX validator parameters");
PKIXBuilderParameters params = new PKIXBuilderParameters(trustAnchors, selector);
Integer effectiveVerifyDepth = getEffectiveVerificationDepth(validationInfo);
log.trace("Setting max verification depth to: {} ", effectiveVerifyDepth);
params.setMaxPathLength(effectiveVerifyDepth);
CertStore certStore = buildCertStore(validationInfo, untrustedCredential);
params.addCertStore(certStore);
boolean isForceRevocationEnabled = false;
boolean forcedRevocation = false;
boolean policyMappingInhibited = false;
boolean anyPolicyInhibited = false;
Set initialPolicies = null;
if (options instanceof CertPathPKIXValidationOptions) {
CertPathPKIXValidationOptions certpathOptions = (CertPathPKIXValidationOptions) options;
isForceRevocationEnabled = certpathOptions.isForceRevocationEnabled();
forcedRevocation = certpathOptions.isRevocationEnabled();
policyMappingInhibited = certpathOptions.isPolicyMappingInhibited();
anyPolicyInhibited = certpathOptions.isAnyPolicyInhibited();
initialPolicies = certpathOptions.getInitialPolicies();
}
if (isForceRevocationEnabled) {
log.trace("PKIXBuilderParameters#setRevocationEnabled is being forced to: {}", forcedRevocation);
params.setRevocationEnabled(forcedRevocation);
} else {
if (storeContainsCRLs(certStore)) {
log.trace("At least one CRL was present in cert store, enabling revocation checking");
params.setRevocationEnabled(true);
} else {
log.trace("No CRLs present in cert store, disabling revocation checking");
params.setRevocationEnabled(false);
}
}
params.setPolicyMappingInhibited(policyMappingInhibited);
params.setAnyPolicyInhibited(anyPolicyInhibited);
if (initialPolicies != null && !initialPolicies.isEmpty()) {
log.debug("PKIXBuilderParameters#setInitialPolicies is being set to: {}", initialPolicies.toString());
params.setInitialPolicies(initialPolicies);
params.setExplicitPolicyRequired(true);
}
log.trace("PKIXBuilderParameters successfully created: {}", params.toString());
return params;
}
/**
* Determine whether there are any CRL's in the {@link CertStore} that is to be used.
*
* @param certStore the cert store that will be used for validation
* @return true if the store contains at least 1 CRL instance, false otherwise
*/
protected boolean storeContainsCRLs(CertStore certStore) {
Collection extends CRL> crls = null;
try {
//Save some cycles and memory: Collection cert store allows null as specifier to return all.
//crls = certStore.getCRLs( new X509CRLSelector() );
crls = certStore.getCRLs(null);
} catch (CertStoreException e) {
log.error("Error examining cert store for CRL's, treating as if no CRL's present", e);
return false;
}
if (crls != null && !crls.isEmpty()) {
return true;
}
return false;
}
/**
* Get the effective maximum path depth to use when constructing PKIX cert path builder parameters.
*
* @param validationInfo PKIX validation information
* @return the effective max verification depth to use
*/
protected Integer getEffectiveVerificationDepth(PKIXValidationInformation validationInfo) {
Integer effectiveVerifyDepth = validationInfo.getVerificationDepth();
if (effectiveVerifyDepth == null) {
effectiveVerifyDepth = options.getDefaultVerificationDepth();
}
return effectiveVerifyDepth;
}
/**
* Creates the collection of trust anchors to use during validation.
*
* @param validationInfo PKIX validation information
*
* @return trust anchors to use during validation
*/
protected Set getTrustAnchors(PKIXValidationInformation validationInfo) {
Collection validationCertificates = validationInfo.getCertificates();
log.trace("Constructing trust anchors for PKIX validation");
Set trustAnchors = new HashSet();
for (X509Certificate cert : validationCertificates) {
trustAnchors.add(buildTrustAnchor(cert));
}
if (log.isTraceEnabled()) {
for (TrustAnchor anchor : trustAnchors) {
log.trace("TrustAnchor: {}", anchor.toString());
}
}
return trustAnchors;
}
/**
* Build a trust anchor from the given X509 certificate.
*
* This could for example be extended by subclasses to add custom name constraints, if desired.
*
* @param cert the certificate which serves as the trust anchor
* @return the newly constructed TrustAnchor
*/
protected TrustAnchor buildTrustAnchor(X509Certificate cert) {
return new TrustAnchor(cert, null);
}
/**
* Creates the certificate store that will be used during validation.
*
* @param validationInfo PKIX validation information
* @param untrustedCredential credential to be validated
*
* @return certificate store used during validation
*
* @throws GeneralSecurityException thrown if the certificate store can not be created from the cert and CRL
* material
*/
protected CertStore buildCertStore(PKIXValidationInformation validationInfo, X509Credential untrustedCredential)
throws GeneralSecurityException {
log.trace("Creating cert store to use during path validation");
log.trace("Adding entity certificate chain to cert store");
List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy