XMLSigner不再适用于4.6.2 - 格式错误的引用元素

sun*_*r20 8 c# xml asp.net cryptography signedxml

将应用程序从3.5升级到4.6.2后面的代码块不再有效.我得到"格式错误的参考元素"错误,即使它作为3.5应用程序工作得很好.代码失败,上面的错误应该是一个很好的参考.我已经尝试了我能想到的一切都无法让ASP.Net版本正常工作.我已经构建了一个测试版本作为控制台应用程序,它可以正常工作,直到它到达最后一个失败并且"无法解析Uri Signature1.jpg"的引用.我已经读过XMLSigner不接受除id,ID和Id之外的任何内容作为匹配引用的元素,但是我不相信这是因为它适用于控制台应用程序.

问题的核心是:

  1. 为什么我会收到"格式错误的参考元素" signedXMl.AddReference(new Reference("#Head01"));
  2. 如何修复对客户签名的引用"src ="Signature1.jpg""

有问题的功能:

private XmlDocument SignDoc(XmlDocument doc, RSA key, X509Certificate x509cert, ArrayList alSignatures)
    {
        string signatureID = "TamperSealer01";
        Uri uri = new Uri(ConfigurationManager.AppSettings["SomeSetting"]); 
        XmlResolver resolver = new XmlSignatureResolver(uri);
        SignedXml signedXml = new SignedXml(doc);
        signedXml.Signature.Id = signatureID;
        signedXml.Resolver = resolver;

        // Add the key to the SignedXml responseDocument. 
        signedXml.SigningKey = key;

        // Create a new KeyInfo object.
        KeyInfo keyInfo = new KeyInfo();
        keyInfo.AddClause(new RSAKeyValue(key));

        KeyInfoX509Data x509Data = new KeyInfoX509Data(x509cert);

        string subjectName = x509cert.Subject;
        subjectName = subjectName.Replace("S=", "ST=");
        string tmpSubName = subjectName;

        tmpSubName = tmpSubName.Replace("O=A", "O=B");
        tmpSubName = tmpSubName.Replace("CN=A", "CN=B");

        x509Data.AddSubjectName(tmpSubName);
        x509Data.AddIssuerSerial(x509cert.Issuer, x509cert.GetSerialNumberString()); //GetIssuerName
        keyInfo.AddClause(x509Data);
        signedXml.KeyInfo = keyInfo;

        //TIMESTAMP
        XmlElement signaturePropertiesRoot = doc.CreateElement("SignatureProperties", "http://www.w3.org/2000/09/xmldsig#");

        DataObject signatureProperties = new DataObject();
        signatureProperties.Id = "TimeStamp";
        signatureProperties.Data = signaturePropertiesRoot.SelectNodes(".");
        signedXml.AddObject(signatureProperties);

        // and add a reference to the data object
        Reference propertiesRef = new Reference();
        propertiesRef.Uri = "#TimeStamp";
        propertiesRef.Type = "http://www.w3.org/2000/09/xmldsig#SignatureProperties";
        signedXml.AddReference(propertiesRef);

        XmlElement property = doc.CreateElement("SignatureProperty", "http://www.w3.org/2000/09/xmldsig#");
        property.SetAttribute("Id", "TamperSealer01TimeStamp");
        property.SetAttribute("Target", "#" + signedXml.Signature.Id);
        signaturePropertiesRoot.AppendChild(property);

        XmlElement timestamp = doc.CreateElement("DateTimeStamp", "http://www.w3.org/2000/09/xmldsig#");
        timestamp.SetAttribute("DateTime", String.Format("{0:s}Z", DateTime.Now.ToUniversalTime()));
        property.AppendChild(timestamp);
        signedXml.ComputeSignature();

        // References contains three strings "Head01", "Data01", and "View01"
        foreach (string docRef in references) 
        {
            // Create a reference to be signed.
            Reference tempRef = new Reference();
            tempRef.Uri = "#" + docRef;
            Logger.Current.LogInformation("DocRef: #" + docRef + ".");
            // Add the reference to the SignedXml object
            signedXml.AddReference(tempRef);
            signedXml.ComputeSignature(); //Immediately Fails here
        }

        // alSignatures only contains "Signature1.jpg" in this case. Don't yell at me for this crappy code, I didn't write it and plan on fixing it when everything else works.
        int ctr = 0;
        foreach (string str in alSignatures)
        {
            Reference testRef = new Reference();
            Uri relativeUri = new Uri(alSignatures[ctr].ToString(), UriKind.RelativeOrAbsolute);
            Logger.Current.LogInformation("Signature Reference: " + alSignatures[ctr].ToString());
            testRef.Uri = alSignatures[ctr].ToString();
            signedXml.AddReference(testRef);
            ctr += 1;
        }

        // Compute the signature.
        signedXml.ComputeSignature();

        // Get the XML representation of the signature and save it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml();
        XmlElement signaturesElement = doc.CreateElement("SIGNATURES", "http://www.mismo.org");

        signaturesElement.AppendChild(signedXml.GetXml());
        doc.DocumentElement.AppendChild(signaturesElement);

        key.Clear();
        key.Dispose();
        return doc;
}
Run Code Online (Sandbox Code Playgroud)

因此,它应签署的XML最低限度:

<?xml version="1.0" encoding="UTF-8"?>
<DOCUMENT MISMOVersionIdentifier="1.02">
    <HEADER _ID="Head01">
        <SIGNATURE_MODEL>
            <SIGNER AreaIDREF="Borrower1SignatureArea" SectionIDREF="BorrowerSignatures" SignatureIDREF="Borrower1SignatureLine" SignatureType="Image" TargetsIDREFS="View01" _RoleType="Borrower" _SignatureOrderNumber="1" />
            <SIGNER SignatureIDREF="TamperSealer01" SignatureType="DigitalSignature" TargetsIDREFS="Head01 Data01 View01" _RoleType="TamperSealer" _SignatureOrderNumber="1" />
        </SIGNATURE_MODEL>
    </HEADER>
    <DATA _ID="Data01">
        <MAIN>
        </MAIN>
    </DATA>
    <VIEW _ID="View01" _MIMETypeDescription="text/html" _TaggedIndicator="True">
        <html xmlns="http://www.w3.org/1999/xhtml">
            <body>
                <span class="dataEntered" id="BORROWER_Signer-Info">
                    <SIGNATURE_SECTION _ID="BorrowerSignatures">
                        <SIGNATURE_AREA _ID="Borrower1SignatureArea">
                            <p class="right">
                                <SIGNATURE_ABOVE_LINE />
                                <SIGNATURE_IMAGE _EncodingTypeDescription="None" _ID="Borrower1SignatureLine" _MIMEType="image/jpeg">
                                    <img align="right" alt="Signature file is missing - Invalid Document" src="Signature1.jpg" />
                                </SIGNATURE_IMAGE>
                            </p>
                            <p>04/12/2011 12:00 PM</p>
                        </SIGNATURE_AREA>
                    </SIGNATURE_SECTION>
                </span>
            </body>
        </html>
    </VIEW>
</DOCUMENT>
Run Code Online (Sandbox Code Playgroud)

Ond*_*dar 4

相关代码CalculateHashValueSystem.Security.Cryptography.Xml.Reference

// for "Head01" this is "#Head01"
if (this.m_uri[0] == '#')
{
   // idFromLocalUri is set to "Head01"
   string idFromLocalUri = Utils.GetIdFromLocalUri(this.m_uri, out flag);
   ...
   // there is no element with Id="Head01" - so xmlElement is null
   var xmlElement = this.SignedXml.GetIdElement(document, idFromLocalUri);
   ...
   if (xmlElement == null)
   {
     // this is the error you're getting
     throw new CryptographicException(SecurityResources.GetResourceString("Cryptography_Xml_InvalidReference"));
   }
}
Run Code Online (Sandbox Code Playgroud)

所以你在参考验证上失败了 - 文档中没有具有此 id 的元素 - 顺便说一句。通过实验将 xml 中的“_ID”更改为“Id”解决了该问题。

好消息是该类SignedXml是可扩展的,您可以重载该XmlElement GetIdElement(XmlDocument document, string idValue)方法以将“_ID”纳入帐户。

// just a sample
class MyCustomSignedXml : SignedXml {
   ...
   override XmlElement GetIdElement(XmlDocument document, string idValue) {
     var element = document.SelectSingleNode($"//*[@_ID='{idValue}']") as XmlElement;
     if (element != null) {
       return element;
     } 

     return base.GetIdElement(document, idValue);
   }
}
Run Code Online (Sandbox Code Playgroud)