首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >XML验证失败,SignedXml.CheckSignature总是返回false。

XML验证失败,SignedXml.CheckSignature总是返回false。
EN

Stack Overflow用户
提问于 2016-09-06 22:01:32
回答 1查看 1.6K关注 0票数 0

我试图按照微软的指令验证一个签名的XML文档,但是CheckSignature总是返回false。我使用的是.NET 4.5。最初,我没有使用C14转换,但这不起作用,在.NET 4.5中建议使用它作为解决方案,但不起作用。请注意,对于签名和验证,保留空白是正确的。

在代码片段中,为了简单起见,我删除了错误检查代码。是的,我检查了类似的问题,但没有找到答案。

证书(.PFX和.CER)

签名和验证是通过文件(而不是存储区)上的证书完成的:

  • 使用PluralSight SelfCert自签名证书工具
  • 为数字签名创建了一个个人自签名证书,该证书具有可导出的带有密码保护的私钥。我可以使用certmgr.msc在我的个人商店中看到证书
  • 我通过签名包含公钥和私钥的证书(.PFX)进行保存。
  • 我使用certmgr.msc导出没有私钥的证书,所以只导出公钥。这仅用于验证,并保存到一个.CER文件中。

到目前为止,证书还不错。个人存储显示我的签名证书与证书和密钥图标。

签名XML文档

现在,对于签名XML,我使用以下代码:

代码语言:javascript
复制
static void SignXML(XmlDocument xmlDoc, RSA Key)
{
        SignedXml signedXml = new SignedXml(xmlDoc);
        if (Properties.Settings.Default.UseC14Transform)
        {
            // http://stackoverflow.com/questions/13632630/signedxml-checksignature-fails-in-net-4-but-it-works-in-net-3-5-3-or-2
            signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
        }

        // Add the key to the SignedXml document.
        signedXml.SigningKey = Key;

        // Create a reference to be signed.
        Reference reference = new Reference();
        reference.Uri = "";
        if (Properties.Settings.Default.UseC14Transform)
        {
            reference.AddTransform(new XmlDsigExcC14NTransform());  // required to match doc
            XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
            reference.AddTransform(env);
        }
        else
        {
            // Add an enveloped transformation to the reference.
            XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
            reference.AddTransform(env);
        }

        // Add the reference to the SignedXml object.
        signedXml.AddReference(reference);

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

        // Get the XML representation of the signature and save
        // it to an XmlElement object.
        XmlElement xmlDigitalSignature = signedXml.GetXml();

        // Append the element to the XML document.
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
}

签名代码如下所示:

代码语言:javascript
复制
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
using (StringWriter _writer = new StringWriter())
{
    XmlSerializer serializer = new XmlSerializer(typeof(Models.Protected), new Type[] { param1.GetType() });
    serializer.Serialize(_writer, param1);
    doc.LoadXml(_writer.ToString());
}
// get RSA key from certificate (.PFX file)
 X509Certificate2 cert = new X509Certificate2(certPrivateKeyFilePath, certFilePwd);
RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider)cert.PrivateKey;
 SignXML(doc, rsaKey);
 return Convert.ToBase64String(Encoding.UTF8.GetBytes(doc.OuterXml));

签名的验证

我的验证方法如下所示:

代码语言:javascript
复制
static Boolean VerifyXml(XmlDocument Doc, X509Certificate2 cert)
{
    RSACryptoServiceProvider rsaKey = (RSACryptoServiceProvider)cert.PublicKey.Key;
    SignedXml signedXml = new SignedXml(Doc);
    XmlNodeList nodeList = Doc.GetElementsByTagName("Signature");
    signedXml.LoadXml((XmlElement)nodeList[0]);
    return signedXml.CheckSignature(rsaKey);
}

这反过来又会被这样调用:

代码语言:javascript
复制
Models.Protected mdl = null;
try
{   // The certificate is in a .CER file, only has PUBLIC key
    X509Certificate2 cert = new X509Certificate2(certPubKeyFilePath);
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.PreserveWhitespace = true; 
      xmlDoc.LoadXml(DocEncoding.GetString(Convert.FromBase64String(b64String)));
    if (VerifyXml(xmlDoc, cert)
    {
         XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");
         xmlDoc.DocumentElement.RemoveChild(nodeList[0]);
         XmlSerializer _serializer = new XmlSerializer(typeof(Models.Protected), new Type[] { typeof(Models.Protected) });
         using (StringReader _reader = new StringReader(_safeXML))
                {
                    _safe = (Models.Protected)_serializer.Deserialize(_reader);
                }
    }
 }
 catch { /* something here */ }

    return _safe;
}

其他

要签名的对象是一个可序列化的Models.Protected类。我已经证实了它是正确序列化的,所以问题不在于此。

签名过程生成一个带有预期XML签名的有效XL文件,然后将其转换为Base64字符串。

验证过程读取一个Base64字符串,我已经验证了该字符串与生成的字符串相同。这个解码时读取的B64字符串产生的签名文档与签名时生成的文档完全相同。

生成的两个已签名的MD5的MD5哈希与验证之前获得的签名XML的MD5哈希相同。因此,他们是绝对平等的,他们的签名也是如此。

因此,我无法理解为什么CheckSignature返回false,尽管内容是相同的,并且正确地生成了证书(.PFX和.CER)。任何地方都不会抛出任何异常,它只是返回false。

有人能发现我做错了什么吗?

EN

回答 1

Stack Overflow用户

发布于 2016-09-08 19:05:43

由于@bartonjs的巨大提示,我可以验证在符号中发现的模数,并验证证书是不一样的。正如我所提到的,我在问题发生时和在新的(固定)情况下都使用了PluralSight免费SelfCert GUI。

没有对代码进行任何更改,问题就在证书上,即使用于验证的.CER文件是从存储的证书中生成的。

差别是可以运作的。如果让SelfCert.exe在存储上安装证书,验证方法就会失败。另一方面,在生成.PFX文件之后,我使用了而不是,使用了GUI上的"Save“按钮,而是使用生成的.PFX文件在存储区手动安装了带有私钥的证书,然后才使用存储的证书将其导出为.CER文件。现在模数相同,签名/验证过程顺利进行,没有失败。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39358493

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档