-
Notifications
You must be signed in to change notification settings - Fork 3
8. Intermediate symmetric keys for encrypted attributes
The library publishes the intermediate symmetric keys used for encrypting each of the attributes (starting with version v1.2.4)
This is useful for Signing Service Providers which need to save all necessary information when signing documents. To to be more precise - information which will allow 3rd parties to verify the signed documents - like the document id attribute, the raw xml SAML assertion (which contains the encrypted attributes and digital signature), the decrypted attributes values (like consumer legal last name, or birthday), and also the keys to decrypt the encrypted attributes.
You can access programatically the symmetric keys when using the library in your applications; this is possible by accesing a new property called AttributesEncryptionKeys. It is an array of SamlAttributesEncryptionKey objects, where each object contains the attribute name and the encryption key; the exactly type used varies from one programming language to other. Should be noted that the position is important - meaning that the order in array represents the order in which those encrypted attributes appear in raw xml SAML assertion.
public class SamlAttributesEncryptionKey
{
public string AttributeName { get; set; }
public byte[] AesKey { get; set; }
}The library contains a set of unit tests as examples of how this new attribute can be used.
In the unit test below you can see how you can access the library to get the value of ConsumerPrefLastName attribute.
The same value can be calculated based on the raw xml (response.RawMessage), the symetric key associated with that attribute (key = keys[2].AesKey;), and the position in the raw xml (which is 2).
Note: how the '2' is computed is not part of the unit test, but you can easily iterate through keys and search the item which matches based on ['AttributeName'].
public void RecomputeAttributeValueBasedOnAttributesEncryptionKeys()
{
var response = Invoke("StatusResponse-Sample");
var expected = "John";
response.SamlResponse.GetAttributeValue(SamlAttribute.ConsumerPrefLastName).ShouldBe(expected);
var attribute = response.SamlResponse.AttributesEncryptionKeys.FirstOrDefault(x => x.AttributeName == SamlAttribute.ConsumerPrefLastName);
attribute.ShouldNotBe(null);
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(response.RawMessage);
var result = DecryptAttributeElement(xmlDoc, 2, attribute.AesKey);
result.ShouldBe(expected);
}The next helper methods are used for actually searching the rawxml and decrypt the attribute. The code can be used by 3rd parties which want to verify the signed documents (provided that the signed documents contains the 3 parameters).
private static string DecryptAttributeElement(XmlDocument xmlDoc, int attributeIndex, byte[] symetricKey)
{
var xmlElementsXPaths = new[] { "//*[local-name() = 'EncryptedID']", "//*[local-name() = 'EncryptedAttribute']" };
var attributeCount = 0;
foreach (var xmlElementsXPath in xmlElementsXPaths)
{
var encryptedElements = xmlDoc.SelectNodes(xmlElementsXPath);
if (encryptedElements == null)
{
continue;
}
foreach (XmlNode encryptedElement in encryptedElements)
{
if (attributeIndex != attributeCount)
{
attributeCount++;
}
else
{
var encryptedDataElement = encryptedElement.Clone().SelectSingleNode("//*[local-name() = 'EncryptedData']") as XmlElement;
var encryptedData = new EncryptedData();
encryptedData.LoadXml(encryptedDataElement);
var symmetricAlgorithm = new AesManaged();
symmetricAlgorithm.Padding = PaddingMode.ISO10126;
symmetricAlgorithm.Key = symetricKey;
var output = new EncryptedXml { Mode = CipherMode.CBC, Padding = PaddingMode.ISO10126 };
var data = output.DecryptData(encryptedData, symmetricAlgorithm);
XmlDocument docElement = new XmlDocument();
MemoryStream ms = new MemoryStream(data);
docElement.Load(ms);
return docElement.InnerText;
}
}
}
return "";
}