Decoding SAML 2 statement using .NET 4.5 (System.IdentityModel) / WIF

I am trying to decrypt an encrypted SAML 2.0 statement issued from a Java-based identity provider.

Given the following configuration of security token handlers:

X509Certificate2 cert = ... // Contains private key var serviceTokens = new List<SecurityToken>(); serviceTokens.Add(new X509SecurityToken(cert)); var issuers = new ConfigurationBasedIssuerNameRegistry(); issuers.AddTrustedIssuer("...thumbprint...", "nottherealname"); var configuration = new SecurityTokenHandlerConfiguration { AudienceRestriction = { AudienceMode = AudienceUriMode.Never }, CertificateValidationMode = X509CertificateValidationMode.None, RevocationMode = X509RevocationMode.NoCheck, IssuerNameRegistry = issuers, MaxClockSkew = TimeSpan.FromMinutes(5), ServiceTokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(serviceTokens.AsReadOnly(), false) }; var tokenHandlers = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection(configuration); 

I get an encrypted SAML statement, for example:

 <saml:EncryptedAssertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Type="http://www.w3.org/2001/04/xmlenc#Element"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" /> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <xenc:EncryptedKey> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" /> <xenc:CipherData> <xenc:CipherValue>Fwhv/zEVi3eQvQN372L1S+pVDM5JKs1Kc2I25djuiOPdwKReCXRhnd5QL4Y8wJDWZ5vAlOxHkNAZ OwOg4NsSI8KssrygNk4fwvNdVAGMB5ytI1QTGRqG6WwP4Em+uLN3VXbqiLWA9D6uO0BwATF9HdTb j/IMhGCxZ1ZKrKQF5OL2PHKf4DqyNa5d9CNZenhYyYghgYrhgZtQVl/VARAp9VKsM/lbkPsEU8Ty ow4LnTlYqBnykrOEJowN5B+HXGvfhbIBHyGzdCC+WbcEbI898zy/VhZ63VyFL2GSTdDWv10IEMy5 CHom4Qruer1xpyQMrxJ6EK30HMhVppToivgoFQ==</xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedKey> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue>...</xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </saml:EncryptedAssertion> 

When I try to read the token:

 var tokenReader = new XmlNodeReader(xmlDoc); // XML document with root element <saml:EncryptedAssertion .... if (!tokenHandlers.CanReadToken(tokenReader)) throw new Exception("Unreadable token"); var token = tokenHandlers.ReadToken(tokenReader); 

Then I get the following exception in the last line of code:

  ID4022: The key needed to decrypt the encrypted security token could not be resolved. Ensure that the SecurityTokenResolver is populated with the required key. 

According to the identity provider, the symmetric key used to encrypt the payload is encrypted with my public key. However, it seems that it is not possible to use the private key in the X509 certificate to decrypt the key. This is my interpretation of the error message. Maybe the error message is incorrect? What else could be wrong? Is my configuration incomplete?

+7
source share
2 answers

I also had this problem, and I ended up with something like the answer to this question: How to disable the key identifier in SecurityTokenResolver

Modify an existing row

 ServiceTokenResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(serviceTokens.AsReadOnly(), false) 

to

 ServiceTokenResolver = new Saml2SSOSecurityTokenResolver(serviceTokens) 

and add this class:

 private class Saml2SSOSecurityTokenResolver : SecurityTokenResolver { List<SecurityToken> _tokens; public Saml2SSOSecurityTokenResolver(List<SecurityToken> tokens) { _tokens = tokens; } protected override bool TryResolveSecurityKeyCore(System.IdentityModel.Tokens.SecurityKeyIdentifierClause keyIdentifierClause, out System.IdentityModel.Tokens.SecurityKey key) { var token = _tokens[0] as X509SecurityToken; var myCert = token.Certificate; key = null; var ekec = keyIdentifierClause as EncryptedKeyIdentifierClause; if (ekec != null) { if (ekec.EncryptionMethod == "http://www.w3.org/2001/04/xmlenc#rsa-1_5") { var encKey = ekec.GetEncryptedKey(); var rsa = myCert.PrivateKey as RSACryptoServiceProvider; var decKey = rsa.Decrypt(encKey, false); key = new InMemorySymmetricSecurityKey(decKey); return true; } var data = ekec.GetEncryptedKey(); var id = ekec.EncryptingKeyIdentifier; } return true; } protected override bool TryResolveTokenCore(System.IdentityModel.Tokens.SecurityKeyIdentifierClause keyIdentifierClause, out System.IdentityModel.Tokens.SecurityToken token) { throw new NotImplementedException(); } protected override bool TryResolveTokenCore(System.IdentityModel.Tokens.SecurityKeyIdentifier keyIdentifier, out System.IdentityModel.Tokens.SecurityToken token) { throw new NotImplementedException(); } } 
+5
source

I tried to decrypt EncryptedAssertion in different ways and ended up using this approach using https://www.nuget.org/packages/SAML2.Core (github: https://github.com/elerch/SAML2 ).

I have completed the following steps:

  • Create a pfx file (PKCS # 12) containing both your public certificate and your private key as follows:

openssl pkcs12 -export -in -inkey -out cert_key.p12

  1. Open the document with saml: EncryptedAssertion as the root element

  2. Read the pkcs12 container certificate

  3. Set document and key

  4. Decrypt a document

Full code:

  var doc = LoadXmlDocument(@"path\to\xml\withencryptedassertion"); var cert = new X509Certificate2(@"path\to\cert_key.p12", "<container_password>"); var encryptedAssertion = new SAML2.Saml20EncryptedAssertion((RSA)cert.PrivateKey, doc); encryptedAssertion.Decrypt(); var decryptedContent = encryptedAssertion.Assertion.InnerXml; 

LoadXmlDocument is the main file reader:

  public static XmlDocument LoadXmlDocument(string assertionFile) { using (var fs = File.OpenRead(assertionFile)) { var document = new XmlDocument { PreserveWhitespace = true }; document.Load(fs); fs.Close(); return document; } } 

I used https://developers.onelogin.com/saml/online-tools/ to create certificates and sample data to verify this code

+1
source

Source: https://habr.com/ru/post/1242930/


All Articles