I'm trying to sign some XML with C# according to the spec sheet laid out to us for our test application. We have to:
- Canonicalize the message.
- Use the Digest algorithm to create digest of the entire message.
- Add the digest to the Signed Info element.
- Canonicalize the Signed Info.
- Input private key and canonicalized signed Info into the specified signing algorithm to generate digital signature.
- Add generated digital signature to the signature element.
This is what I currently have.
public static XmlElement Sign(XmlDocument msgDoc)
{
XmlDsigExcC14NTransform transform = new XmlDsigExcC14NTransform();
transform.LoadInput(msgDoc);
msgDoc.Load(transform.GetOutput() as Stream);
var signedXml = new SignedXml(msgDoc)
{
SigningKey = Certificate.GetRSAPrivateKey(),
};
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
var reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform(true));
reference.AddTransform(new XmlDsigC14N11Transform()); // Custom transform
reference.Uri = string.Empty;
reference.DigestMethod = SignedXml.XmlDsigSHA256Url;
signedXml.SignedInfo.AddReference(reference);
KeyInfo keyInfo = new KeyInfo();
var keyInfoData = new KeyInfoX509Data();
keyInfoData.AddIssuerSerial(CertManager.Certificate.Issuer, CertManager.Certificate.SerialNumber);
keyInfoData.AddSubjectName(CertManager.Certificate.Subject);
keyInfo.AddClause(keyInfoData);
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();
XmlElement signature = signedXml.GetXml();
// This part until the return was done to ensure we get the 'ds' prefix.
// Code taken from: https://stackoverflow.com/questions/30579938/generate-digital-signature-but-with-a-specific-namespace-prefix-ds
SetPrefix("ds", signature);
signedXml.LoadXml(signature);
signedXml.SignedInfo.References.Clear();
signedXml.ComputeSignature();
ReplaceSignature(signature, Convert.ToBase64String(signedXml.SignatureValue));
XmlNode signatureElement = msgDoc.ImportNode(signature, true);
return msgDoc.DocumentElement.InsertAfter(msgDoc.ImportNode(signature, true), msgDoc.DocumentElement.FirstChild) as XmlElement;
}
The digest algorithm is: http://www.w3.org/2001/04/xmlenc#sha256
The canonicalization algorithm is: http://www.w3.org/2001/10/xml-exc-c14n#
We are using two transforms: http://www.w3.org/2000/09/xmldsig#enveloped-signature and http://www.w3.org/2006/12/xml-c14n11
I've enabled tracing on the other side which is supposed to validate the message and this appears to be the only place where something is failing in the trace log:
[SignedXml#0071d445, VerificationFailure] Verification failed checking SignedInfo.
I've ensured that the Certificate
being used in the signing process is my private certificate and the other side is using the public certificate for their verification process.
What else am I missing?
Edit:
We are able to validate messages that we receive from their side. I cannot provide any code to how they validate messages because it's not given to us.
This is an example of what we are sending over:
<Message xmlns="urn:tch">
<AppHdr>
<head:Fr xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
<head:ID>
<head:MemberId>1234245</head:MemberId>
</head:ID>
</head:Fr>
<head:To xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
<head:ID>
<head:MemberId>123345345</head:MemberId>
</head:ID>
<head:Date xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">2020-03-16T22:03:24</head:Date>
<head:Sgntr xmlns:head="urn:iso:std:iso:20022:tech:xsd:head.001.001.01">
<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/2001/04/xmldsig-more#rsa-sha256" />
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/2006/12/xml-c14n11" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
<ds:DigestValue>fV61VLaSYGyW+G+LxZaLfGdOlAVmpJvusoJ792IKblw=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>xlg1Q4hdQoCo+x4rJKWn1UwLwdshonx0dg5Z0bIAsFuBWOJGyVescQBFEZEbUHcgLq2TQZT6PBhH3F2RR4aYTnc9IY0mHRq5rJEpVfXnQZdwCw7SIhkMMIOi5rAgQ5gdLmQlbLWFm8V4+1DTE7QWiCALEkarJQcdU4n9E2rGrSM48H1NFHHC+m8J5eHcGFyRcBwSF712ihGDNvweGhwneR4JeGxyQ3Dc1pSkzkr0oOJDY0vgwIuMZIMvl6Fh98D3QByDadZqFah88uv+TWZy01B9rdfhgCP7gdeiP9fof90jnitQ4c/3XksjieLbWQxWmQ1TPoRQswDuXf731T6kmw==</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=ABC, DC=AAA, DC=BBB, DC=CCC</ds:X509IssuerName>
<ds:X509SerialNumber>75822323454364025267732697561489775234425345</ds:X509SerialNumber>
</ds:X509IssuerSerial>
<ds:X509SubjectName>E=something@somewhere.com, CN=ABC.com, OU=Internet Services, O=AAA, L=Someplace, S=somewhere, C=US</ds:X509SubjectName>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
</head:Sgntr>
</AppHdr>
<TestMessage>
<mr:zzzz.002.001.01 xmlns:mr="urn:iso:std:iso:20022:tech:xsd:zzzz.002.001.01">
<mr:Ref>
<mr:Ref>20200316220315134567890122203156779</mr:Ref>
</mr:Ref>
</TestMessage>
</Message>
Edit: If somebody and create an example using the above information for signing I will accept the answer.