import java.security.cert.X509Certificate;
+import org.opensaml.SAMLSignedObject;
+
import edu.internet2.middleware.shibboleth.metadata.RoleDescriptor;
/**
*/
public interface Trust {
- /**
+ /**
+ * Verifies that a certificate or ordered chain of certificates represents a valid credential set for a specific
+ * action by a specific entity.
+ *
+ * @param certificateEE
+ * the end-entity certificate being validated
+ * @param certificateChain
+ * additional certificates supplied by the entity (may also contain the end-entity certificate)
+ * @param descriptor
+ * the SAML 2 role descriptor of the entity purported to be performing the action
+ * @return true if the validation was successful and false if it was not successful
+ */
+ public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor);
+
+ /**
* Verifies that a certificate or ordered chain of certificates represents a valid credential set for a specific
* action by a specific entity.
*
- * @param descriptor
- * the SAML 2 role descriptor of the entity purported to be performing the action
+ * @param certificateEE
+ * the end-entity certificate being validated
* @param certificateChain
- * the credentials supplied by the entity (if this contains a certificate chain, it should be ordered
- * with the end-entity certificate first
- * @param keyUse
- * the action being performed (must be valid <code>KeyDescriptor</code> usage type
+ * additional certificates supplied by the entity (may also contain the end-entity certificate)
+ * @param descriptor
+ * the SAML 2 role descriptor of the entity purported to be performing the action
+ * @param checkName
+ * whether the check the name of the certificate during the validation process, normally true unless
+ * the name has already been checked as part of other processing (for example, TLS)
* @return true if the validation was successful and false if it was not successful
*/
- public boolean validate(RoleDescriptor descriptor, X509Certificate[] certificateChain, int keyUse);
+ public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor, boolean checkName);
+
+ /**
+ * Verifies that a certificate or ordered chain of certificates represents a valid credential set for a specific
+ * action by a specific entity.
+ *
+ * @param token
+ * the signed object to validate
+ * @param descriptor
+ * the SAML 2 role descriptor of the entity purported to be performing the action
+ * @return true if the validation was successful and false if it was not successful
+ */
+ public boolean validate(SAMLSignedObject token, RoleDescriptor descriptor);
}
\ No newline at end of file
import org.apache.log4j.Logger;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.keys.keyresolver.KeyResolverException;
+import org.opensaml.SAMLSignedObject;
import edu.internet2.middleware.shibboleth.common.Trust;
import edu.internet2.middleware.shibboleth.metadata.KeyDescriptor;
private static Logger log = Logger.getLogger(BasicTrust.class.getName());
/*
- * @see edu.internet2.middleware.shibboleth.common.Trust#validate(edu.internet2.middleware.shibboleth.metadata.RoleDescriptor,
- * java.security.cert.X509Certificate[], int)
+ * @see edu.internet2.middleware.shibboleth.common.Trust#validate(java.security.cert.X509Certificate,
+ * java.security.cert.X509Certificate[], edu.internet2.middleware.shibboleth.metadata.RoleDescriptor, boolean)
*/
- public boolean validate(RoleDescriptor descriptor, X509Certificate[] certificateChain, int keyUse) {
+ public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor, boolean checkName) {
- if (descriptor == null || certificateChain == null || certificateChain.length < 1) {
+ if (descriptor == null || certificateEE == null) {
log.error("Appropriate data was not supplied for trust evaluation.");
return false;
}
while (keyDescriptors.hasNext()) {
// Look for a key descriptor with the right usage bits
KeyDescriptor keyDescriptor = (KeyDescriptor) keyDescriptors.next();
- if (keyDescriptor.getUse() != KeyDescriptor.UNSPECIFIED && keyDescriptor.getUse() != keyUse) {
- log.debug("Role contains a key descriptor, but the usage specification is not valid for this action.");
+ if (keyDescriptor.getUse() == KeyDescriptor.ENCRYPTION) {
+ log.debug("Skipping key descriptor with inappropriate usage indicator.");
continue;
}
log.debug("Attempting to match X509 certificate.");
try {
X509Certificate metaCert = keyInfo.getX509Certificate();
- if (certificateChain != null && certificateChain.length > 0
- && Arrays.equals(metaCert.getEncoded(), certificateChain[0].getEncoded())) {
+ if (Arrays.equals(metaCert.getEncoded(), certificateEE.getEncoded())) {
log.debug("Match successful.");
return true;
} else {
}
return false;
}
+
+ /*
+ * @see edu.internet2.middleware.shibboleth.common.Trust#validate(java.security.cert.X509Certificate, java.security.cert.X509Certificate[], edu.internet2.middleware.shibboleth.metadata.RoleDescriptor)
+ */
+ public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor) {
+ return validate(certificateEE, certificateChain, descriptor, true);
+ }
+
+ /*
+ * @see edu.internet2.middleware.shibboleth.common.Trust#validate(org.opensaml.SAMLSignedObject, edu.internet2.middleware.shibboleth.metadata.RoleDescriptor)
+ */
+ public boolean validate(SAMLSignedObject token, RoleDescriptor descriptor) {
+ // TODO Auto-generated method stub
+
+ /*
+ * Proposed algorithm for this is just to walk each KeyDescriptor with keyUse of signing
+ * and try and extract a public key to use and try and verify the token. If it works, we're
+ * done.
+ */
+ return false;
+ }
}
\ No newline at end of file
import org.apache.xml.security.keys.content.X509Data;
import org.apache.xml.security.keys.content.x509.XMLX509CRL;
import org.apache.xml.security.keys.content.x509.XMLX509Certificate;
+import org.opensaml.SAMLSignedObject;
import edu.internet2.middleware.shibboleth.common.Trust;
import edu.internet2.middleware.shibboleth.metadata.EntitiesDescriptor;
private static Logger log = Logger.getLogger(ShibbolethTrust.class.getName());
private static Pattern regex = Pattern.compile(".*?CN=([^,/]+).*");
- /*
- * @see edu.internet2.middleware.shibboleth.common.Trust#validate(edu.internet2.middleware.shibboleth.metadata.RoleDescriptor,
- * java.security.cert.X509Certificate[], int)
- */
- public boolean validate(RoleDescriptor descriptor, X509Certificate[] certificateChain, int keyUse) {
+ /*
+ * @see edu.internet2.middleware.shibboleth.common.Trust#validate(java.security.cert.X509Certificate, java.security.cert.X509Certificate[], edu.internet2.middleware.shibboleth.metadata.RoleDescriptor)
+ */
+ public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor) {
+ return validate(certificateEE, certificateChain, descriptor, true);
+ }
+
+ /*
+ * @see edu.internet2.middleware.shibboleth.common.Trust#validate(org.opensaml.SAMLSignedObject, edu.internet2.middleware.shibboleth.metadata.RoleDescriptor)
+ */
+ public boolean validate(SAMLSignedObject token, RoleDescriptor descriptor) {
+ // TODO Auto-generated method stub
+
+ /*
+ * Proposed algorithm for this (will modify C++ to match:
+ *
+ * - get the certificates from the token
+ * - iterate over them in order, until one verifies the signature
+ * - pass that as the EE cert to the other validate method, with the full set as a chain
+ */
+ return false;
+ }
+
+ /*
+ * @see edu.internet2.middleware.shibboleth.common.Trust#validate(java.security.cert.X509Certificate,
+ * java.security.cert.X509Certificate[], edu.internet2.middleware.shibboleth.metadata.RoleDescriptor, boolean)
+ */
+ public boolean validate(X509Certificate certificateEE, X509Certificate[] certificateChain, RoleDescriptor descriptor, boolean checkName) {
// If we can successfully validate with an inline key, that's fine
- boolean defaultValidation = super.validate(descriptor, certificateChain, keyUse);
+ boolean defaultValidation = super.validate(certificateEE, certificateChain, descriptor, checkName);
if (defaultValidation == true) { return true; }
// Make sure we have the data we need
- if (descriptor == null || certificateChain == null || certificateChain.length < 1) {
+ if (descriptor == null || certificateEE == null) {
log.error("Appropriate data was not supplied for trust evaluation.");
return false;
}
// First, we want to see if we can match a keyName from the metadata against the cert
// Iterator through all the keys in the metadata
- Iterator keyDescriptors = descriptor.getKeyDescriptors();
- while (keyDescriptors.hasNext()) {
- // Look for a key descriptor with the right usage bits
- KeyDescriptor keyDescriptor = (KeyDescriptor) keyDescriptors.next();
- if (keyDescriptor.getUse() != KeyDescriptor.UNSPECIFIED && keyDescriptor.getUse() != keyUse) {
- log.debug("Role contains a key descriptor, but the usage specification is not valid for this action.");
- continue;
- }
-
- // We found one, see if we can match the metadata's keyName against the cert
- KeyInfo keyInfo = keyDescriptor.getKeyInfo();
- if (keyInfo.containsKeyName()) {
- for (int i = 0; i < keyInfo.lengthKeyName(); i++) {
- try {
- if (matchKeyName(certificateChain[0], keyInfo.itemKeyName(i))) {
- // If we find a match, try to do path validation against any key authorities we might have
- // in the metadata
- if (pkixValidate(certificateChain, descriptor.getEntityDescriptor())) { return true; }
- }
- } catch (XMLSecurityException e) {
- log.error("Problem retrieving key name from metadata: " + e);
- }
- }
- }
- }
- return false;
+ if (checkName) {
+ Iterator keyDescriptors = descriptor.getKeyDescriptors();
+ while (checkName && keyDescriptors.hasNext()) {
+ // Look for a key descriptor with the right usage bits
+ KeyDescriptor keyDescriptor = (KeyDescriptor) keyDescriptors.next();
+ if (keyDescriptor.getUse() == KeyDescriptor.ENCRYPTION) {
+ log.debug("Skipping key descriptor with inappropriate usage indicator.");
+ continue;
+ }
+
+ // We found one, see if we can match the metadata's keyName against the cert
+ KeyInfo keyInfo = keyDescriptor.getKeyInfo();
+ if (keyInfo.containsKeyName()) {
+ for (int i = 0; i < keyInfo.lengthKeyName(); i++) {
+ try {
+ if (matchKeyName(certificateChain[0], keyInfo.itemKeyName(i))) {
+ checkName = false;
+ break;
+ }
+ } catch (XMLSecurityException e) {
+ log.error("Problem retrieving key name from metadata: " + e);
+ }
+ }
+ }
+ }
+ }
+
+ if (checkName) {
+ log.error("cannot match certificate subject against acceptable key names based on KeyDescriptors");
+ return false;
+ }
+
+ if (pkixValidate(certificateEE, certificateChain, descriptor.getEntityDescriptor())) { return true; }
+ return false;
}
- private boolean pkixValidate(X509Certificate[] certChain, EntityDescriptor entity) {
+ private boolean pkixValidate(X509Certificate certEE, X509Certificate[] certChain, EntityDescriptor entity) {
if (entity instanceof ExtendedEntityDescriptor) {
Iterator keyAuthorities = ((ExtendedEntityDescriptor) entity).getKeyAuthorities();
// if we have any key authorities, construct a flat list of trust anchors representing each and attempt to
// validate against them in turn
while (keyAuthorities.hasNext()) {
- if (pkixValidate(certChain, (KeyAuthority) keyAuthorities.next())) { return true; }
+ if (pkixValidate(certEE, certChain, (KeyAuthority) keyAuthorities.next())) { return true; }
}
}
// nested entities and attempt to validate at each group level
EntitiesDescriptor group = entity.getEntitiesDescriptor();
if (group != null) {
- if (pkixValidate(certChain, group)) { return true; }
+ if (pkixValidate(certEE, certChain, group)) { return true; }
}
// We've walked the entire metadata chain with no success, so fail
return false;
}
- private boolean pkixValidate(X509Certificate[] certChain, EntitiesDescriptor group) {
+ private boolean pkixValidate(X509Certificate certEE, X509Certificate[] certChain, EntitiesDescriptor group) {
log.debug("Attemping to validate against parent group.");
if (group instanceof ExtendedEntitiesDescriptor) {
// if we have any key authorities, construct a flat list of trust anchors representing each and attempt to
// validate against them in turn
while (keyAuthorities.hasNext()) {
- if (pkixValidate(certChain, (KeyAuthority) keyAuthorities.next())) { return true; }
+ if (pkixValidate(certEE, certChain, (KeyAuthority) keyAuthorities.next())) { return true; }
}
}
// If not, attempt to walk up the chain for validation
EntitiesDescriptor parent = group.getEntitiesDescriptor();
if (parent != null) {
- if (pkixValidate(certChain, parent)) { return true; }
+ if (pkixValidate(certEE, certChain, parent)) { return true; }
}
return false;
}
- private boolean pkixValidate(X509Certificate[] certChain, KeyAuthority authority) {
+ private boolean pkixValidate(X509Certificate certEE, X509Certificate[] certChain, KeyAuthority authority) {
Set anchors = new HashSet();
Set crls = new HashSet();
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
X509CertSelector selector = new X509CertSelector();
- selector.setCertificate(certChain[0]);
+ selector.setCertificate(certEE);
PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, selector);
params.setMaxPathLength(authority.getVerifyDepth());
List storeMaterial = new ArrayList(crls);
}
// Make sure that the suppplied credential is valid for the provider to which the artifact was issued
- if (!support.getTrust().validate(role,
- (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate"),
- KeyDescriptor.ENCRYPTION)) {
+ X509Certificate[] chain = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
+ if (!support.getTrust().validate((chain != null && chain.length > 0) ? chain[0] : null, chain, role)) {
log.error("Supplied credential ("
+ credential.getSubjectX500Principal().getName(X500Principal.RFC2253)
+ ") is NOT valid for provider (" + mapping.getServiceProviderId()
// Make sure that the suppplied credential is valid for the
// selected relying party
- if (support.getTrust().validate(role,
- (X509Certificate[]) req.getAttribute("javax.servlet.request.X509Certificate"),
- KeyDescriptor.ENCRYPTION)) {
+ X509Certificate[] chain = (X509Certificate[])req.getAttribute("javax.servlet.request.X509Certificate");
+ if (support.getTrust().validate((chain != null && chain.length > 0) ? chain[0] : null, chain, role)) {
log.info("Supplied credential validated for this provider.");
log.info("Request from service provider: (" + relyingParty.getProviderId() + ").");
return relyingParty.getProviderId();
// Try to validate against the metadata
Trust validator = new BasicTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{cert}, KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(cert, new X509Certificate[]{cert}, role);
if (!successful) {
fail("Validation should have succeeded.");
}
// Try to validate against the metadata
Trust validator = new BasicTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{cert}, KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(cert, new X509Certificate[]{cert}, role);
if (successful) {
fail("Validation should have failed.");
}
// Try to validate against the metadata
Trust validator = new ShibbolethTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{cert}, KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(cert, new X509Certificate[]{cert}, role);
if (!successful) {
fail("Validation should have succeeded.");
}
// Try to validate against the metadata
Trust validator = new ShibbolethTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{cert}, KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(cert, new X509Certificate[]{cert}, role);
if (!successful) {
fail("Validation should have succeeded.");
}
// Try to validate against the metadata
Trust validator = new ShibbolethTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{cert}, KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(cert, new X509Certificate[]{cert}, role);
if (!successful) {
fail("Validation should have succeeded.");
}
// Try to validate against the metadata
Trust validator = new ShibbolethTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{endEntity, intermediate},
- KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(endEntity, new X509Certificate[]{endEntity, intermediate}, role);
if (successful) {
fail("Validation should not have succeeded.");
}
// Try to validate against the metadata
Trust validator = new ShibbolethTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{endEntity, intermediate},
- KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(endEntity, new X509Certificate[]{endEntity, intermediate}, role);
if (!successful) {
fail("Validation should have succeeded.");
}
// Try to validate against the metadata
Trust validator = new ShibbolethTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{cert}, KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(cert, new X509Certificate[]{cert}, role);
if (successful) {
fail("Validation should not have succeeded.");
}
// Try to validate against the metadata
Trust validator = new ShibbolethTrust();
- boolean successful = validator.validate(role, new X509Certificate[]{cert}, KeyDescriptor.ENCRYPTION);
+ boolean successful = validator.validate(cert, new X509Certificate[]{cert}, role);
if (!successful) {
fail("Validation should have succeeded.");
}