I need to create a digital signature for an XML with ISO20022 standard.
The example shows 3 references, one of which is for KeyInfo element (the one with #_33d232d2-4591-4b49-b28d-3cb825fbeaa4 URI).
<ds:Signature
xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<ds:Reference URI="#_33d232d2-4591-4b49-b28d-3cb825fbeaa4">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>h9toHGSlK/x1zE7egK0yEj06W2D9wAEK/VAuiwU8+R8=</ds:DigestValue>
</ds:Reference>
<ds:Reference Type="http://uri.etsi.org/01903/v1.3.2#SignedProperties" URI="#_aba0ee84-5f37-499e-a8e8-caa7f398341c-signedprops">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>Ot7tqqOtgtguRadTQi0fh5FU3XL/4/mHIv7Eoy67t/s=</ds:DigestValue>
</ds:Reference>
<ds:Reference>
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>1ZZln0/NzN/eB1wIrxyp/c3SOjKWnk00Lh1bKTXlTAE=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>VRn+Q7K6snvKrFPwtH302iKPjAx1k97TKIvjysdH+/I8EMyzWg20gZ1fO1gjKk245nfzXIsiuoVIZJtBKNSE9Tp+VXegJxyAoXx1bz8fMZIbdjjhXaYzdx2yCGh9Fllrbg+y9RZy9VvG7sLQeu91gOge7GHNIxO6jck96yVsY8k=</ds:SignatureValue>
<ds:KeyInfo Id="_33d232d2-4591-4b49-b28d-3cb825fbeaa4">
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>C=SE, O=CMA Small Systems AB, CN=Test CA</ds:X509IssuerName>
<ds:X509SerialNumber>12345678</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
</ds:KeyInfo>
<ds:Object>
<xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#">
<xades:SignedProperties Id="_aba0ee84-5f37-499e-a8e8-caa7f398341csignedprops">
<xades:SignedSignatureProperties>
<xades:SigningTime>2019-08-23T19:01:41+12:00</xades:SigningTime>
</xades:SignedSignatureProperties>
</xades:SignedProperties>
</xades:QualifyingProperties>
</ds:Object>
</ds:Signature>
However when I try to do the same with .NET 6 I get the following exception
System.Security.Cryptography.CryptographicException: Malformed reference element.
at System.Security.Cryptography.Xml.Reference.CalculateHashValue(XmlDocument document, CanonicalXmlNodeList refList)
at System.Security.Cryptography.Xml.Reference.UpdateHashValue(XmlDocument document, CanonicalXmlNodeList refList)
at System.Security.Cryptography.Xml.SignedXml.BuildDigestedReferences()
at System.Security.Cryptography.Xml.SignedXml.ComputeSignature()
Inspecting the SignedXml class, it seems that KeyInfo is missing from the CanonicalXmlNodeList in the BuildDigestedReferences method. Is there any way around this?
This is my code for signing the XML
static void SignXmlWithCert(XmlDocument doc, X509Certificate2 cert)
{
const string signedPropsIdSuffix = "-signedprops";
var signedXml = new SignedXml(doc)
{
SigningKey = cert.GetRSAPrivateKey()
};
signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
var idKeyInfo = "_" + Guid.NewGuid();
var idKeyInfoProps = "_" + Guid.NewGuid() + signedPropsIdSuffix;
#region keyinfo
var keyInfo = new KeyInfo();
var keydata = new KeyInfoX509Data(cert, X509IncludeOption.None);
keydata.AddIssuerSerial(cert.Issuer, cert.SerialNumber);
keyInfo.AddClause(keydata);
keyInfo.Id = idKeyInfo;
signedXml.KeyInfo = keyInfo;
#endregion keyinfo
#region References
var transform = new XmlDsigEnvelopedSignatureTransform() { Algorithm = "http://www.w3.org/2001/10/xml-exc-c14n#" };
var references = new List<Reference>();
// first reference
var keyInfoReference = new Reference();
keyInfoReference.Uri = "#" + keyInfo.Id;
keyInfoReference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
keyInfoReference.AddTransform(transform);
references.Add(keyInfoReference);
//second reference
var signaturePropertiesReference = new Reference();
signaturePropertiesReference.Type = "http://uri.etsi.org/01903/v1.3.2#SignedProperties";
signaturePropertiesReference.Uri = "#" + idKeyInfoProps;
signaturePropertiesReference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
signaturePropertiesReference.AddTransform(transform);
references.Add(signaturePropertiesReference);
//third reference
var documentReference = new Reference();
documentReference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
documentReference.AddTransform(transform);
references.Add(documentReference);
foreach (var reference in references)
{
signedXml.AddReference(reference);
}
#endregion
#region 4. Set up <ds:Object> with <QualifiyingProperties> inside that includes SigningTime
var URI = "http://uri.etsi.org/01903/v1.3.2#";
var qualifyingPropertiesRoot = doc.CreateElement("xades", "QualifyingProperties", URI);
var signaturePropertiesRoot = doc.CreateElement("xades", "SignedProperties", URI);
signaturePropertiesRoot.SetAttribute("Id", idKeyInfoProps);
var SignedSignatureProperties = doc.CreateElement("xades", "SignedSignatureProperties", URI);
var timestamp = doc.CreateElement("xades", "SigningTime", URI);
timestamp.InnerText = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:sszzz"); // primero de la lista
signaturePropertiesRoot.AppendChild(SignedSignatureProperties);
SignedSignatureProperties.AppendChild(timestamp);
qualifyingPropertiesRoot.AppendChild(signaturePropertiesRoot);
var qualifyingPropertiesObject = new DataObject
{
Data = qualifyingPropertiesRoot.SelectNodes("."),
Id = idKeyInfoProps
};
signedXml.AddObject(qualifyingPropertiesObject);
#endregion
signedXml.ComputeSignature();
}