XML Digital Signatures
Signing a SAMLObject
Digitially signing a SAML object entails attaching and computing a Signature object to the object to be signed, where the Signature reflects the enveloped signature paradigm. Enveloped signatures are the only method formally prescribed in the XML Signature profile of the SAML specification. This is a 3-step process:
- Create and attach a
- Marshall the object tree containing the
SAMLObjectwhich is to be signed.
- Compute the the actual signature value contained within the
Attaching a Signature to the SignableSAMLObject
The first step in signing a SAMLObject is to create a Signature object and attach it to the SAMLObject. Since all SAMLObjects that can be signed implement the interface
org.opensaml.common.SignableSAMLObject the code to sign an object is always the same.
- Create a
Signatureobject using the
org.opensaml.xml.signature.impl.SignatureBuilder(this is found in the XMLTooling library). This will likely be obtained from a builder factory. See Creating SAML Objects from Scratch.
- Add the
Credentialcontaining the signing key using the
- Add the signature method algorithm URI with the method
Signature#setSignatureAlgorithm(String). Note that the algorithm URI is dependent on the type of key contained with the signing credential.
- Add the canonicalization method algorithm URI with the method
Signature#setCanonicalizationAlgorithm(String). Note that unless there is good reason to do otherwise, and the ramifications are understood, the recommended canonicalization method for SAML signature use cases is exclusive canonicalization (with or without comments).
- If desired, add a
KeyInfocontaining information about the signature verification key using
KeyInfomay be created manually, or may be generated dynamically from the signing credential using a
KeyInfoGenerator, usually obtained from a
- Add the
Signatureto the SAMLObject using the
SAMLObjectContentReferencewill automatically be added to the list of signature references exposed via
Signature#getContentReferences(), so you should NOT explicitly add a reference to the signature. Note that the
Signaturecontained within a signed element in SAML may contain only one
SignedInfo, per the SAML signature profile.
Dynamic Parameter Selection
The data inputs for steps 2-5 may be retrieved dynamically from an instance of
SecurityConfigurationand populated on
the Signatureinstance using the helper method
org.opensaml.xml.security.SecurityHelper#prepareSignatureParams. For more usage info, see the Javadocs for that method.
Marshall the Object Tree
The signing operation operates on the underlying cached DOM representation of the object. Therefore, the SAML object to be signed must be marshalled before the actual signature computation is performed. For further information on marshalling, see Writing SAML Objects to XML .
Computing the Signature Value
After you have marshalled the XMLObject tree containing the SAMLObject which is to be signed, you'll have a SAML element with a digital signature child element populated with everything but the actual signature value. To signal that it is time to compute this, using the following steps:
- Create an ordered
Listof all the
Signatureobjects that need to be processed. This is necessary because one signature could contain the a reference to another and the second signature must be computed before the first signature or it will invalidate the first signature.
- Pass the list to the
Note: if you only have one signature to be computed there is a convenience method
Signer#signObject(Signature)to allow you to sign without creating a list.
Here is an example of signing a SAML 2
Assertion with a
Credential containing an RSA private key and using the RSA SHA1 algorithm, with explicit handling of
Here is the same example, but with dynamic retrieval of parameters from the global
Verifying the Signature on a Signed SAMLObject
Verifying a Signature with a Credential
Note: This is the lowest-level method of signature verification supported by the library, providing only cryptographic verification of the signature itself. For a higher-level API, see subsequent sections.
If your code had, through some mechanism such as a
CredentialResolver, determined a
Credential to use to attempt to verify the signature, you can perform the verification as follows:
- Create an instance of a
org.opensaml.xml.signature.SignatureValidator, passing the verification credential as the constructor argument.
- Execute the
SignatureValidator#validate(Signature)method, passing in the signature you wish to validate. If an exception is thrown the signature failed cryptographic verification and the exception will given the reason. If no exception is thrown then the cryptographic verification of the signature was successful.
Preventing Signature Denial of Service Attacks
In order to prevent certain types of denial-of-service attacks associated with signature verification, it is advisable to successfully validate the
org.opensaml.security.SAMLSignatureProfileValidatorprior to attempting to cryptographically verify the signature.
Note that this signature verification mechanism does NOT establish trust of the verification credential, only that it successfully cryptographically verifies the signature. You must establish trust by other means. In particular, the
Credentialextracted from the signature's
KeyInfomust NOT be trusted without additional evaluation.
Verifying a Signature with a SignatureTrustEngine
Trust engine implementations are available which combine cryptographic verification of the signature and trust establishment of the verification credential. These trust engines implement the
org.opensaml.xml.signature.SignatureTrustEngine interface. Current implementations include:
org.opensaml.xml.signature.impl.ExplicitKeySignatureTrustEngine- implements trust by retrieving trusted credentials from a
CredentialResolverof trusted credentials.
org.opensaml.xml.signature.impl.PKIXSignatureTrustEngine- implements trust by validating the verification credential (obtained from the signature's
KeyInfo) using PKIX path validation rules. Trusted PKIX validation information is obtained from a
org.opensaml.xml.signature.impl.ChainingSignatureTrustEngine- allows chaining of signature trust engines which implement different trust models or have different sources of trust material.
For more information on trust engines, see the user guide section Trust Engines.
Verifying a Signature with SAML 2 Metadata Information
SAML 2 metadata may contain keys, key names, and certificates which are associated with a particular role for a particular entity. Validating a signature against this information provides a significantly greater level of assurance in the signature as it proves not only that the signature is valid, but that the entity that generated it is interacting with the system in a role-appropriate manner.
Using SAML 2 metadata in conjunction with signature verification usually combines usage of a
SignatureTrustEngine implementation with a trusted information resolver based on SAML 2 metadata, such as the
org.opensaml.security.MetadataCredentialResolver. To perform validation based on this mechanism see the user guide section Trust Engines.
Signature Verification Examples
Here is a simple case of low-level cryptographically verifying the signature directly:
Here is a more complex example of verifying the signature with the explicit key signature trust engine, using trusted credentials obtained from SAML 2 metadata. The example assumes that the verifier is likely a SAML 2 SP, and is verifying the signature on a SAML 2
Response received from a SAML 2 IdP over the SAML 2.0 protocol: