简体   繁体   English

参考 KeyInfo 为 XML 创建数字签名

[英]Create Digital Signature for XML with reference to KeyInfo

I need to create a digital signature for an XML with ISO20022 standard.我需要为符合 ISO20022 标准的 XML 创建数字签名。

The example shows 3 references, one of which is for KeyInfo element (the one with #_33d232d2-4591-4b49-b28d-3cb825fbeaa4 URI).该示例显示了 3 个引用,其中一个用于 KeyInfo 元素(具有 #_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但是,当我尝试对 .NET 6 执行相同操作时,出现以下异常

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.检查 SignedXml 类,似乎BuildDigestedReferences方法中的CanonicalXmlNodeList中缺少 KeyInfo。 Is there any way around this?有没有办法解决?


This is my code for signing the XML这是我签署 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();
}

it seems that KeyInfo is missing from the CanonicalXmlNodeList in the BuildDigestedReferences method. BuildDigestedReferences 方法中的 CanonicalXmlNodeList 似乎缺少 KeyInfo。

That's because it's not part of the document.那是因为它不是文档的一部分。

Is there any way around this?有没有办法解决?

Add it to the document.将其添加到文档中。 Rather than try to construct it by hand I doctored up your code to make two different SignedXml objects, one which puts the nodes in to be signed and the other does the final signature.我没有尝试手动构建它,而是修改了您的代码以创建两个不同的 SignedXml 对象,一个将节点放入以进行签名,另一个进行最终签名。

Commented out lines of code are lines that I had to change or remove to make your snippet otherwise work.注释掉的代码行是我必须更改或删除以使您的代码段正常工作的行。

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 transform = new XmlDsigExcC14NTransform();
    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";
    // The code in the question didn't assign Uri, and since no transform did an inherent
    // node resolution, signing failed.
    documentReference.Uri = "";
    documentReference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
    documentReference.AddTransform(transform);
    references.Add(documentReference);

    foreach (Reference 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#";
    XmlElement qualifyingPropertiesRoot = doc.CreateElement("xades", "QualifyingProperties", URI);

    XmlElement signaturePropertiesRoot = doc.CreateElement("xades", "SignedProperties", URI);
    signaturePropertiesRoot.SetAttribute("Id", idKeyInfoProps);

    XmlElement SignedSignatureProperties = doc.CreateElement("xades", "SignedSignatureProperties", URI);
    XmlElement 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 tmp = new SignedXml(doc)
    {
        SigningKey = signedXml.SigningKey,
        KeyInfo = signedXml.KeyInfo,
    };

    foreach (DataObject obj in signedXml.Signature.ObjectList)
    {
        tmp.AddObject(obj);
    }
    
    tmp.AddReference(new Reference(""));
    tmp.ComputeSignature();

    XmlTextWriter prettyOut = new XmlTextWriter(System.Console.Out);
    prettyOut.Formatting = Formatting.Indented;

    Console.WriteLine("Original document");
    doc.WriteTo(prettyOut);
    Console.WriteLine();
    Console.WriteLine();

    XmlElement elem = tmp.GetXml();
    doc.DocumentElement.AppendChild(elem);
    Console.WriteLine("Stage 1 signed");
    doc.WriteTo(prettyOut);
    Console.WriteLine();
    Console.WriteLine();

    signedXml.ComputeSignature();
    doc.DocumentElement.RemoveChild(elem);
    doc.DocumentElement.AppendChild(signedXml.GetXml());
    Console.WriteLine("Stage 2 signed");
    doc.WriteTo(prettyOut);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM