Class SamlEncryption
- Namespace
- Fdyay.IdentityServer.Saml.Xml
- Assembly
- Fdyay.IdentityServer.Saml.dll
Seals and opens an <EncryptedAssertion> (XML Encryption, SAML 2.0 core ยง2.3.4).
public static class SamlEncryption
- Inheritance
-
SamlEncryption
- Inherited Members
Remarks
Decryption happens before anything is verified, which sounds backwards and is not: the assertion's signature is inside the ciphertext, so there is nothing to verify until this has run. What that costs is a small amount of work on behalf of an unauthenticated sender โ an RSA unwrap and an AES pass โ and what it must not cost is the verification itself. The caller replaces the encrypted element with the plaintext and then runs the same signature checks on the result, so every wrapping defence in SamlSignature applies to what actually came out.
Only RSA-OAEP unwraps a content key here. RSA-1.5 is the padding Bleichenbacher's attack targets, and a decryption oracle is exactly what an endpoint that accepts assertions from the network is.
Methods
Decrypt(XmlElement, RSA)
Replaces encryptedAssertion with the assertion inside it.
public static XmlElement? Decrypt(XmlElement encryptedAssertion, RSA decryptionKey)
Parameters
encryptedAssertionXmlElementdecryptionKeyRSA
Returns
- XmlElement
The plaintext assertion element, or null when it cannot be opened.
Encrypt(XmlElement, X509Certificate2)
Replaces assertion with an <EncryptedAssertion> carrying it.
public static XmlElement Encrypt(XmlElement assertion, X509Certificate2 recipient)
Parameters
assertionXmlElementrecipientX509Certificate2
Returns
- XmlElement
The
EncryptedAssertionelement that replaced it.
Remarks
The mirror of Decrypt(XmlElement, RSA), and the order is the whole of what makes it correct: the caller signs the assertion first, so the signature is encrypted along with everything else. A receiver then verifies the plaintext that came out of the ciphertext rather than an envelope somebody wrapped around it โ which is the property SamlSignature's wrapping defences exist to protect, and it is lost entirely by encrypting before signing.
A fresh AES-256 content key per assertion, wrapped with RSA-OAEP. Neither is configurable: the padding this refuses to read is the padding it must therefore never write, and a content key reused across two assertions is a content key worth attacking.