c# - 签名 XML 在 api 门上返回无效签名和错误的签名检查

标签 c# .net cryptography

我在使用 X509 xades 证书签署 XML 文件时遇到问题。 APi 返回无效签名错误并且 SignatureCheck() 为 false。

我确实创建了 SSL 证书来签署文件,但 OID 顺序重要吗?就像我需要 OID 2.5.5.97,但它是该行的第一个。

经过签名和验证的 XML 与我的没有什么不同。最大的区别是因为原始的 JAVA 门在签名(:ds)上有前缀。在文档中,需要转换“http://www.w3.org/TR/1999/REC-xpath-19991116 - not(ancestor-or-self::ds:Signature)”,但带有 :ds 前缀我可以'无论如何,不​​要让它运行并在签名之后添加它会使它错误。与我无法在 .net 中创建的 SignatureValue Id 类似。

对此有什么想法吗?花了很多时间,但我不知道该怎么做,因为错误并没有真正告诉我要检查什么。我正在使用 Overriden XadesSignedXML()。

    private const string SignatureId = "-72773545-b03c-49fe-98ed-477a2f199934";
    private const string SignaturePropertiesId = "#SignedProps-72773545-b03c-49fe-98ed-477a2f199934";


    private static XmlElement SignXMLDocument(string xml, X509Certificate2 certificate, string signedXMLPath)
    {

        string XPathString = "not(ancestor-or-self::Signature)";

        var xmlDocument = new XmlDocument();
        xmlDocument.PreserveWhitespace = true;
        xmlDocument.Load(xml);

        var signedXml = new XadesSignedXml(xmlDocument);
        signedXml.Signature.Id = "Signature" + SignatureId;
        signedXml.SigningKey = certificate.PrivateKey;
        signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
        signedXml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/2001/10/xml-exc-c14n#";
        //signedXml.SignatureValue. = "SignatureValue" + SignatureId;
        
        var signatureReference = new Reference { Uri = "", };
        XmlDsigXPathTransform XPathTransform = CreateXPathTransform(XPathString);
        signatureReference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
        signatureReference.AddTransform(XPathTransform);
        signedXml.AddReference(signatureReference);
        
        var signatureReference2 = new Reference { Uri = "", };
        signatureReference2.AddTransform(new XmlDsigExcC14NTransform());
        //signatureReference2.Uri = SignaturePropertiesId;
        signatureReference2.Type = "http://uri.etsi.org/01903#SignedProperties";
        signatureReference2.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
        signedXml.AddReference(signatureReference2);
        
        var keyInfo = new KeyInfo();
        keyInfo.AddClause(new KeyInfoX509Data(certificate));
        signedXml.KeyInfo = keyInfo;
        AddXAdESProperties(xmlDocument, signedXml, certificate);
        signedXml.ComputeSignature();
        
        // Add prefix "ds:" to signature
        XmlElement signature = signedXml.GetXml();
        xmlDocument.DocumentElement.AppendChild(xmlDocument.ImportNode(signature, true));
        signedXml.CheckSignature();


        xmlDocument.Save(signedXMLPath);
        return signedXml.GetXml();
    }






public class XadesSignedXml : SignedXml
    {
        #region Public fields
        public const string XmlDsigSignatureProperties = "http://uri.etsi.org/01903#SignedProperties";
        public const string XadesProofOfApproval = "http://uri.etsi.org/01903/v1.2.2#ProofOfApproval";
        public const string XadesPrefix = "xades";
        public const string XadesNamespaceUrl = "http://uri.etsi.org/01903/v1.3.2#";
        public XmlElement PropertiesNode { get; set; }
        #endregion Public fields

        #region Private fields
        private readonly List<DataObject> _dataObjects = new List<DataObject>();
        #endregion Private fields

        #region Constructor
        public XadesSignedXml(XmlDocument document) : base(document) { }
        #endregion Constructor

        #region SignedXml
        public override XmlElement GetIdElement(XmlDocument document, string idValue)
        {
            if (String.IsNullOrEmpty(idValue)) return null;

            XmlElement xmlElement = base.GetIdElement(document, idValue);
            if (xmlElement != null) return xmlElement;


            foreach (DataObject dataObject in _dataObjects)
            {
                XmlElement nodeWithSameId = findNodeWithAttributeValueIn(dataObject.Data, "Id", idValue);
                if (nodeWithSameId != null)
                    return nodeWithSameId;
            }
            if (KeyInfo != null)
            {
                XmlElement nodeWithSameId = findNodeWithAttributeValueIn(KeyInfo.GetXml().SelectNodes("."), "Id", idValue);
                if (nodeWithSameId != null)
                    return nodeWithSameId;
            }
            return null;
        }
        public XmlElement findNodeWithAttributeValueIn(XmlNodeList nodeList, string attributeName, string value)
        {
            if (nodeList.Count == 0) return null;
            foreach (XmlNode node in nodeList)
            {
                XmlElement nodeWithSameId = findNodeWithAttributeValueIn(node, attributeName, value);
                if (nodeWithSameId != null) return nodeWithSameId;
            }
            return null;
        }

        private XmlElement findNodeWithAttributeValueIn(XmlNode node, string attributeName, string value)
        {
            string attributeValueInNode = getAttributeValueInNodeOrNull(node, attributeName);
            if ((attributeValueInNode != null) && (attributeValueInNode.Equals(value))) return (XmlElement)node;
            return findNodeWithAttributeValueIn(node.ChildNodes, attributeName, value);
        }

        private string getAttributeValueInNodeOrNull(XmlNode node, string attributeName)
        {
            if (node.Attributes != null)
            {
                XmlAttribute attribute = node.Attributes[attributeName];
                if (attribute != null) return attribute.Value;
            }
            return null;
        }

        public new void AddObject(DataObject dataObject)
        {
            base.AddObject(dataObject);
            _dataObjects.Add(dataObject);
        }
        #endregion SignedXml
    }

private static void AddXAdESProperties(XmlDocument document, XadesSignedXml xadesSignedXml, X509Certificate2 signingCertificate)
    {

        // <Object>
        var objectNode = document.CreateElement("Object", SignedXml.XmlDsigNamespaceUrl);
        XmlAttribute attr = document.CreateAttribute("Id");
        attr.Value = "Signature" + SignatureId;
        document.DocumentElement.SetAttributeNode(attr);
       // objectNode.SetAttribute("Id", $"#QualifyingInfos{SignatureId}");

        // <Object><QualifyingProperties>
        var qualifyingPropertiesNode = document.CreateElement(XadesSignedXml.XadesPrefix, "QualifyingProperties", XadesSignedXml.XadesNamespaceUrl);
        qualifyingPropertiesNode.SetAttribute("Id", $"QualifyingProps{SignatureId}");
        qualifyingPropertiesNode.SetAttribute("Target", $"#Target{SignatureId}");
        objectNode.AppendChild(qualifyingPropertiesNode);

        // <Object><QualifyingProperties><SignedProperties>
        var signedPropertiesNode = document.CreateElement(XadesSignedXml.XadesPrefix, "SignedProperties", XadesSignedXml.XadesNamespaceUrl);
        signedPropertiesNode.SetAttribute("Id", $"SignedProps{SignatureId}");
        qualifyingPropertiesNode.AppendChild(signedPropertiesNode);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties>
        var signedSignaturePropertiesNode = document.CreateElement(XadesSignedXml.XadesPrefix, "SignedSignatureProperties", XadesSignedXml.XadesNamespaceUrl);
        signedPropertiesNode.AppendChild(signedSignaturePropertiesNode);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties> </SigningTime>
        var signingTime = document.CreateElement(XadesSignedXml.XadesPrefix, "SigningTime", XadesSignedXml.XadesNamespaceUrl);
        signingTime.InnerText = $"{DateTime.UtcNow.ToString("s")}Z";
        signedSignaturePropertiesNode.AppendChild(signingTime);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties><SigningCertificate>
        var signingCertificateNode = document.CreateElement(XadesSignedXml.XadesPrefix, "SigningCertificate", XadesSignedXml.XadesNamespaceUrl);
        signedSignaturePropertiesNode.AppendChild(signingCertificateNode);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties><SigningCertificate><Cert>
        var certNode = document.CreateElement(XadesSignedXml.XadesPrefix, "Cert", XadesSignedXml.XadesNamespaceUrl);
        signingCertificateNode.AppendChild(certNode);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties><SigningCertificate><Cert><CertDigest>
        var certDigestNode = document.CreateElement(XadesSignedXml.XadesPrefix, "CertDigest", XadesSignedXml.XadesNamespaceUrl);
        certNode.AppendChild(certDigestNode);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties><SigningCertificate><Cert><CertDigest> </DigestMethod>
        var digestMethod = document.CreateElement("DigestMethod", SignedXml.XmlDsigNamespaceUrl);
        var digestMethodAlgorithmAtribute = document.CreateAttribute("Algorithm");
        digestMethodAlgorithmAtribute.InnerText = "http://www.w3.org/2001/04/xmlenc#sha256";
        digestMethod.Attributes.Append(digestMethodAlgorithmAtribute);
        certDigestNode.AppendChild(digestMethod);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties><SigningCertificate><Cert><CertDigest> </DigestMethod>
        var digestValue = document.CreateElement("DigestValue", SignedXml.XmlDsigNamespaceUrl);
        digestValue.InnerText = Convert.ToBase64String(signingCertificate.GetCertHash());
        certDigestNode.AppendChild(digestValue);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties><SigningCertificate><Cert><IssuerSerial>
        var issuerSerialNode = document.CreateElement(XadesSignedXml.XadesPrefix, "IssuerSerial", XadesSignedXml.XadesNamespaceUrl);
        certNode.AppendChild(issuerSerialNode);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties><SigningCertificate><Cert><IssuerSerial> </X509IssuerName>
        var x509IssuerName = document.CreateElement("X509IssuerName", SignedXml.XmlDsigNamespaceUrl);
        x509IssuerName.InnerText = signingCertificate.Issuer;
        issuerSerialNode.AppendChild(x509IssuerName);

        // <Object><QualifyingProperties><SignedProperties><SignedSignatureProperties><SigningCertificate><Cert><IssuerSerial> </X509SerialNumber>
        var x509SerialNumber = document.CreateElement("X509SerialNumber", SignedXml.XmlDsigNamespaceUrl);
        x509SerialNumber.InnerText = ToDecimalString(signingCertificate.SerialNumber);
        issuerSerialNode.AppendChild(x509SerialNumber);

        var dataObject = new DataObject();
        dataObject.Data = qualifyingPropertiesNode.SelectNodes(".");
        xadesSignedXml.AddObject(dataObject);
    }

    private static string ToDecimalString(string serialNumber)
    {
        BigInteger bi;

        if (BigInteger.TryParse(serialNumber, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out bi))
        {
            return bi.ToString(CultureInfo.InvariantCulture);
        }
        else
        {
            return serialNumber;
        }
    }



XML output



-<Signature Id="Signature-72773545-b03c-49fe-98ed-477a2f199934" xmlns="http://www.w3.org/2000/09/xmldsig#">
-<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
-<Reference URI="">
-<Transforms>
-<Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
 <XPath>not(ancestor-or-self::Signature)</XPath>
</Transform>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>SDYp5ETBmCIef4sWHqyIFYdE5cx2d2OkysrSaOAjIis=</DigestValue>
</Reference>
-<Reference URI="" Type="http://uri.etsi.org/01903#SignedProperties">
-<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>REcwU+gablenV+bEsnzWgvrkthDMvbku2wL49GKLsDU=</DigestValue>
</Reference>
</SignedInfo>
 <SignatureValue>GKixR6/kwjMZ2YvY7ENFejW7lLHZtm7EUMxB3gwCRM82yljLe3POky08rFVa7xk/n1FS9NQhReTQkxDz2DfsB0f+hryvln93phmBp9z+u2vWX5RPKFQaaeBnvA8f4hzD9dzE5j+XE5SvJSlhY31ywb5uPobzoKBV2sw+wG3bXMGMdRwic0bAKVXfYlAY5sA3lzXL9IwOKNWJbb9EJvOg/Mvywymni86pRdr6SxReW9l5nWlCiIdQUIM4B7HsghaovL9/ertqEZQ50XM1T5fMfOnw6XBiKP9pEnpklMjcvbZwVscdfWOhbRuUCvyNm/pwJEarTQNB8fKS/SQF4AR2fQ==</SignatureValue>
 -<KeyInfo>
 -<X509Data <X509Certificate>MIIDWzCCAkMCFGwVWs8TqOhY5Jxps/YHE/LmOOLFMA0GCSqGSIb3DQEBCwUAMGoxGjAYBgNVBAoMEUVuYWJsZSBCYW5raW5nIE95MQ4wDAYDVQQHDAVFc3BvbzELMAkGA1UEBhMCRkkxGjAYBgNVBAMMEWVuYWJsZWJhbmtpbmcuY29tMRMwEQYDVQRhDAo1MDM1NzQxODQ0MB4XDTIyMDUxNjEwMjc0MFoXDTIzMDUxNjEwMjc0MFowajEaMBgGA1UECgwRRW5hYmxlIEJhbmtpbmcgT3kxDjAMBgNVBAcMBUVzcG9vMQswCQYDVQQGEwJGSTEaMBgGA1UEAwwRZW5hYmxlYmFua2luZy5jb20xEzARBgNVBGEMCjUwMzU3NDE4NDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCidkvidq+M9J+HdpXDIqJCbUvXN4EsAGQyaJm2xzUCHrUkLBzViWq7m5t5vLbQjWluReBSAy4J18HilNhtnZhQP+KxWlFJpOK1ksPNvjjvT0Wrs8aG7bYCN04fHivAbEx8vQ2+9DtjzeQK59H28W5nF5nZzSEN1EB7PQZhTBR+k7NhpYjOoWycfECs4CU2peuK/UjoghuSmSX6Cebs4ea+WqYdJ5IN6ALdER0KDrddeM+y8YSBAgxgci8r0KbdVN2xtjq2Ce/c6FWqyXnImBFtWjXM2ztFx3PpSWUwoE6wslmWyp2MvD8+jdepYCLBXQ0GyKq+1ncpzbyId4lUVnCBAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADmmeRfFMsrixgpRvtP9blDg+7nXuXobCsisEU0DD+DVu6FHZV+NKg/SlVj0dGF6DCQD/ivEhZ0wMHMnWrn8OhyBICRUtHG852zR+B6qKm6IPsCMqHca1S1eXdPjYrlsy0FITTh6vF3apu6XZIFp8++9PibjRP4epH61im54S8N2BJWRk7odMKZhdjlGNEJG3g8pUz0JpRoKONyYQ8FiU1tSLsCf9sTyBWdZFc9QXWj5+5kW0BwrnAJo6ACuJCIG7h6SMbCZcLEBZQ4dFEloBxmSDilsQ0wYN70XaPAhE/DqUaOpWuIfshXgcqbPsqNQ1HKN9jDT8s22htph8ZFLQc0=</X509Certificate>
 </X509Data>
 </KeyInfo>
 -<Object>
 -<xades:QualifyingProperties Id="QualifyingProps-72773545-b03c-49fe-98ed-477a2f199934" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" Target="#Target-72773545-b03c-49fe-98ed-477a2f199934">
-<xades:SignedProperties Id="SignedProps-72773545-b03c-49fe-98ed-477a2f199934">
-<xades:SignedSignatureProperties>
 <xades:SigningTime>2022-05-25T10:23:22Z</xades:SigningTime>
-<xades:SigningCertificate>
-<xades:Cert>
-<xades:CertDigest>
 <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
 <DigestValue>0s2aVTeCNbnIYs5tYawTcnSnTUs=</DigestValue>
</xades:CertDigest>
-<xades:IssuerSerial>
<X509IssuerName>OID.2.5.4.97=5035741844, CN=enablebanking.com, C=FI, L=Espoo, O=Enable Banking Oy</X509IssuerName>
<X509SerialNumber>617047229468459973113617196860274611066779525829</X509SerialNumber>
</xaes:IssuerSerial>
</xades:Cert>
</xades:SigningCertificate>
</xades:SignedSignatureProperties>
</xades:SignedProperties>
 </xades:QualifyingProperties>
</Object>
</Signature>

我之前的问题。 How to add properly xml transformations to sign file

最佳答案

-<Reference URI="" Type="http://uri.etsi.org/01903#SignedProperties">
-<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>REcwU+gablenV+bEsnzWgvrkthDMvbku2wL49GKLsDU=</DigestValue>
</Reference>

这里的问题更有可能是引用

Type="http://uri.etsi.org/01903#SignedProperties"

...因为它通过 Id 引用封装内容而不是 SignedProperties 元素。即,引用应该如下所示:

-<Reference URI="#SignedProps-72773545-b03c-49fe-98ed-477a2f199934" Type="http://uri.etsi.org/01903#SignedProperties">
-<Transforms>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<DigestValue>REcwU+gablenV+bEsnzWgvrkthDMvbku2wL49GKLsDU=</DigestValue>
</Reference>

目前,您的两个引用文献都引用了相同的封装内容,但摘要不同。这显然没有通过验证。

您可以尝试修复引用,看看它是否可以帮助您解决问题。

关于c# - 签名 XML 在 api 门上返回无效签名和错误的签名检查,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72376533/

相关文章:

c# - 子窗口中的任务暂停 UI

c# - 通过 Xamarin Forms 在 XAML 中使用 LINQ

c# - 如何捕获 .NET 应用程序中的所有异常/崩溃

c# - sql server current_timestamp 与 c# datetime.now

c# - 循环序列中两个数字之间的距离

perl - 是否有 SHA256withRSA 的 perl 实现

c# - 获取字符串的一部分并在 C# 中组合它们?

hash - 为什么 SlowEquals 函数对于比较哈希密码很重要?

c# - Mono 无法将 SHA1 识别为 RSA 签名的哈希算法

c# - 将来自数据阅读器的行转换为类型化结果