0

长话短说,我可以很好地签署文件。但是每次验证它们都会返回错误。我浏览了 google 和 bing 的前 5 或 6 页寻找解决方案,但我发现的每一个“修复”都无济于事。任何帮助将不胜感激,因为我已经尝试解决这个问题一个多星期了。此外,这些证书的私钥不可导出,也不能。我不确定这是否重要。另外,我现在选择不包含 ValidateCertificate,因为它从来没有做到过那么远。它总是在 CheckSignature() 处失败。谢谢你。

这是我用来生成证书的内容:

makecert -a SHA256 -n "CN=JEA2.me" -pe -r -len 2048 -sy 24 -sky 签名 -sv jeame2.pvk jeame2.cer

certmgr /add jeame2.cer /s /r localmachine root

makecert -sk "jea2.me" -iv jeame2.pvk -n "CN=JEA2IIS.me" -eku 1.3.6.1.4.1.311.10.3.12 -pe -sy 24 -ss my -sr localmachine -len 2048 -sky 签名-ic Jeame2.cer IIS-ServerCert-Jeame2.cer

从这里我将它们直接安装到本地机器-> 受信任的根证书颁发机构

    private static X509Certificate2 CheckXmldsigSignature(XmlDocument document)
    {
        X509Certificate2 certificate = null;

        try
        {
            XmlNodeList nodeList = document.GetElementsByTagName("Signature", Xmldsigns);

            if (nodeList.Count != 1)
            {
                Logger.ErrorFormat("Found {0} signature elements in file", nodeList.Count);
                throw new InvalidOperationException(
                    "The XML document must have a single element with local name: \"Signature\" and namespace URI: " + Xmldsigns);
            }
            else
            {
                Logger.DebugFormat("Found Signature element successfully");
            }

            RSAPKCS1SHA256SignatureDescription.Register();
            var signatureElement = (XmlElement)nodeList[0];
            var signedXml = new SignedXml(document);
            signedXml.LoadXml(signatureElement);

            var keyInfoX509 =
                    (KeyInfoX509Data)
                    (from KeyInfoClause kic in signedXml.KeyInfo where kic is KeyInfoX509Data select kic).Single();

            if (keyInfoX509.Certificates.Count != 1)
            {
                var msg = "The signature must contain information for one certificate.";
                Logger.Error(msg);
                throw new InvalidOperationException(msg);
            }
            else
            {
                Logger.DebugFormat("Extracted X509 certificate data successfully");
            }

            certificate = (X509Certificate2)keyInfoX509.Certificates[0];
            bool validSignature = signedXml.CheckSignature(); //was null parameters. This too does not work.

            if (!validSignature)
            {
                var msg = " SignedXml.CheckSignature returned false.";
                throw new InvalidOperationException(msg);
            }
            else
            {
                Logger.DebugFormat("SignedXml.CheckSignature returned true.");
            }
        }
        catch (Exception ex)
        {
            ScriptPro.Common.Logging.LogEx.LogException(Logger, ex);
            throw;
        }

        return certificate;
    }

   private static Stream SignSHA256Stream(X509Certificate2 certificate, Stream stream)
    {
        if (certificate == null)
        {
            Logger.Error("certificate argument is null");
            throw new ArgumentNullException("certificate");
        }

        if (stream == null)
        {
            Logger.Error("stream argument is null");
            throw new ArgumentNullException("stream");
        }

        RSAPKCS1SHA256SignatureDescription.Register();

        var document = new XmlDocument();
        document.PreserveWhitespace = true; // May not be necessary.
        document.Load(stream);
        XmlNode root = document.DocumentElement;
        XmlNodeList nodeList = document.GetElementsByTagName("Signature", Xmldsigns);

        while (nodeList.Count > 0)
        {
            root.RemoveChild(nodeList[0]);
        }

        Reference reference = new Reference(string.Empty);
        reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
        reference.AddTransform(new XmlDsigExcC14NTransform());
        reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
        CspParameters csp = new CspParameters(24);
        csp.Flags = CspProviderFlags.UseMachineKeyStore;
        csp.KeyContainerName = "XML_DISG_RSA_KEY";
        RSACryptoServiceProvider key = new RSACryptoServiceProvider(csp);
        key.PersistKeyInCsp = false;
        var keyInfo = new KeyInfo();
        keyInfo.AddClause(new KeyInfoX509Data(certificate));
        SignedXml sxml = new SignedXml(document);
        sxml.KeyInfo = keyInfo;
        sxml.SigningKey = key;
        sxml.SignedInfo.SignatureMethod = Xmldsigns256;
        sxml.AddReference(reference);
        sxml.ComputeSignature();

        XmlElement xmlDigitalSignature = sxml.GetXml();

        if (document.DocumentElement == null)
        {
            document.AppendChild(document.ImportNode(xmlDigitalSignature, true));
        }
        else
        {
            document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature, true));
        }

        if (document.FirstChild is XmlDeclaration)
        {
            document.RemoveChild(document.FirstChild);
        }

        MemoryStream outStream = new MemoryStream();
        document.Save(outStream);

        return outStream;
    }
    private static void SignSHA256File(X509Certificate2 certificate, FileInfo file)
    {
        if (certificate == null)
        {
            Logger.Error("certificate argument is null");
            throw new ArgumentNullException("certificate");
        }

        if (file == null)
        {
            Logger.Error("file argument is null");
            throw new ArgumentNullException("file");
        }

        if (!file.Exists)
        {
            Logger.ErrorFormat("File {0} does not exist.", file.Name);
            throw new ArgumentException("File must exist.", "file");
        }

        if (file.IsReadOnly)
        {
            Logger.ErrorFormat("File {0} is read only.", file.Name);
            throw new ArgumentException("File is read only.", "file");
        }

        FileStream stream = file.OpenRead();

        string s = string.Empty;
        using (StreamReader reader = new StreamReader(stream))
        {
            s = reader.ReadToEnd();
        }

        MemoryStream stream2 = new MemoryStream(Encoding.Default.GetBytes(s));
        Stream inStream = SignSHA256Stream(certificate, stream2);

        XmlDocument document = new XmlDocument();
        inStream.Seek(0L, SeekOrigin.Begin);

        document.Load(inStream);

        Logger.InfoFormat("Saving {0}", file.FullName);

        document.Save(file.FullName);
    }

public class RSAPKCS1SHA256SignatureDescription : SignatureDescription
{
    private const int PROV_RSA_AES = 24;

    public RSAPKCS1SHA256SignatureDescription()
    {
        this.KeyAlgorithm = "System.Security.Cryptography.RSACryptoServiceProvider";
        this.DigestAlgorithm = "System.Security.Cryptography.SHA256CryptoServiceProvider"; // use System.Security.Cryptography.SHA256Managed for .NET 4.5
        this.FormatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureFormatter";
        this.DeformatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureDeformatter";
    }

    public static void Register()
    {
        CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
    }

    public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key)
    {
        var asymmetricSignatureDeformatter = (AsymmetricSignatureDeformatter)CryptoConfig.CreateFromName(DeformatterAlgorithm);
        asymmetricSignatureDeformatter.SetKey(key);
        asymmetricSignatureDeformatter.SetHashAlgorithm("SHA256");
        return asymmetricSignatureDeformatter;
    }

    public override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key)
    {
        var asymmetricSignatureFormatter = (AsymmetricSignatureFormatter)CryptoConfig.CreateFromName(FormatterAlgorithm);
        asymmetricSignatureFormatter.SetKey(key);
        asymmetricSignatureFormatter.SetHashAlgorithm("SHA256");
        return asymmetricSignatureFormatter;
    }
}
}

这是我的两个 XML 文件: 1.xml:

<node1>
  <node2>
  </node2>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
      <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
      <Reference URI="">
        <Transforms>
          <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
          <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
        <DigestValue>3nIr0blku+Nsu3FgibCxfQRGBtSmtZL4JGodmaU8blE=    </DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>O3ihm7QwE/vh9VZ6CtdENAhB9Ve8jceATCgdJuaQkUHpPWxrG01TftUlrw9a/dQGfW48jJMPngwgcfqnbFspmEEGsBe1xoWQd6mdy2wVRBcQSjqdReNNzs0uQz3/1wPPk4Y2UO+fL+CVNzkIcMpne+t80c2eU4cHBa1WyL5qSlc=</SignatureValue>
<KeyInfo>
  <X509Data>
    <X509Certificate>MIICFDCCAX2gAwIBAgIQ2rStbEE1JJhHRLiuA4n/0jANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwtKQUxDT1JOLm1lMjAeFw0xNjAzMzAxODE1MDFaFw0zOTEyMzEyMzU5NTlaMBkxFzAVBgNVBAMTDkpBTENPUk5JSVMubWUyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLJEzyRjaHLfK6zrg1Xdx2yO34d5sbd7ajFFVmb3zPKtVGmuJlCBPsDTC84pzHBTywVVApi3U2UwtuCh96rQu5r3nYUT/E46CtexWiFATyh0M9+wD/h3hZj1CQ0YHTEZWznOWWIdbNRAcp99tGSALrwjH2rEJhGHHpVn7otCNmZQIDAQABo2AwXjATBgNVHSUEDDAKBggrBgEFBQcDATBHBgNVHQEEQDA+gBAgVyu7w3c59jEjiSh/vma+oRgwFjEUMBIGA1UEAxMLSkFMQ09STi5tZTKCEFvqkxy0Sd+mSgbqvsCEqKcwDQYJKoZIhvcNAQELBQADgYEAAcM6GlR3UpjIY4TWWuMiSyqiUiAGgg3JetiUXj1EVZ7TZVvyoVA1L/wd8ZHt+nZu1UtJmJ8sU7eu55TMVcX/xu7QoYsp6JtbPp5abLI6rnOCwDfyorrjM4S8Rm2RCO3PhL0NC9i9QBPfNV15FEbFpeqHZGw/xmyGzEv3EWxEESE=</X509Certificate>
      </X509Data>
    </KeyInfo>
  </Signature>
</node1>

2.xml:

<metadata>
  <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
    <SignedInfo>
      <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
      <SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" />
      <Reference URI="">
        <Transforms>
          <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
          <Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
        </Transforms>
        <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256" />
        <DigestValue>wc+6kgUoF9TE7KL1OQXm0EzAIYZuVVc6w3zOKsIY8yU=    </DigestValue>
      </Reference>
    </SignedInfo>
    <SignatureValue>MDJn2QLG65LChsJOAN9zKmq4Br5JFSncaTMOmmsmL+DY4xcZt7e4VfI6/IehBkBUzDLeUJHWoE9sp7tVmArBiq/ZFm/ScB2/SRAAD+/NS0XxnxTPjvwu0JsmupNFJ364r/k31TYhI6TBmiCBIdZ6/3qV8LNPtS0iVrMkyhFw6L8=</SignatureValue>
    <KeyInfo>
      <X509Data>
        <X509Certificate>MIICFDCCAX2gAwIBAgIQ2rStbEE1JJhHRLiuA4n/0jANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDEwtKQUxDT1JOLm1lMjAeFw0xNjAzMzAxODE1MDFaFw0zOTEyMzEyMzU5NTlaMBkxFzAVBgNVBAMTDkpBTENPUk5JSVMubWUyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCLJEzyRjaHLfK6zrg1Xdx2yO34d5sbd7ajFFVmb3zPKtVGmuJlCBPsDTC84pzHBTywVVApi3U2UwtuCh96rQu5r3nYUT/E46CtexWiFATyh0M9+wD/h3hZj1CQ0YHTEZWznOWWIdbNRAcp99tGSALrwjH2rEJhGHHpVn7otCNmZQIDAQABo2AwXjATBgNVHSUEDDAKBggrBgEFBQcDATBHBgNVHQEEQDA+gBAgVyu7w3c59jEjiSh/vma+oRgwFjEUMBIGA1UEAxMLSkFMQ09STi5tZTKCEFvqkxy0Sd+mSgbqvsCEqKcwDQYJKoZIhvcNAQELBQADgYEAAcM6GlR3UpjIY4TWWuMiSyqiUiAGgg3JetiUXj1EVZ7TZVvyoVA1L/wd8ZHt+nZu1UtJmJ8sU7eu55TMVcX/xu7QoYsp6JtbPp5abLI6rnOCwDfyorrjM4S8Rm2RCO3PhL0NC9i9QBPfNV15FEbFpeqHZGw/xmyGzEv3EWxEESE=</X509Certificate>
      </X509Data>
    </KeyInfo>
  </Signature>
</metadata>

public static bool VerifyXmldsigSignature(FileInfo file, bool useSHA256 = false)
    {
        Logger.InfoFormat("Checking Digital Signature and Certificate on {0}", file.FullName);

        bool validCertificate = false;

        if (file == null)
        {
            Logger.Error("file argument is null");
            throw new ArgumentNullException("file");
        }

        if (!file.Exists)
        {
            Logger.ErrorFormat("File {0} does not exist.", file.Name);
            throw new ArgumentException("File must exist.", "file");
        }

        try
        {
            var document = new XmlDocument();
            document.PreserveWhitespace = true;     document.Load(file.FullName);

            DateTime timestamp = DateTime.UtcNow;

            bool respectCertExpiration = HasTimestamp(document);

            if (respectCertExpiration)
            {
                timestamp = CheckXadesTimestamp(document);
            }

            var certificate = CheckXmldsigSignature(document);

            validCertificate = ValidateCertificate(certificate, timestamp, respectCertExpiration);

            Logger.InfoFormat("Digital Signature and Certificate passed verification on {0}", file.FullName);
        }
        catch (Exception ex)
        {
            string message = string.Format("{0} failed signature verification.", file.FullName);
            throw;
        }
4

2 回答 2

3

查看代码,我发现有两个地方可能存在问题:

证书有效期。

在不使用CheckSignature()任何参数的情况下使用需要由受信任的根颁发机构签署的签名证书。由于您已经在提取作为签名一部分的证书,我建议您将调用更改为

bool validSignature = signedXml.CheckSignature(certificate);

请注意,您只知道验证 Xml 是否由文件中的证书信息签名。您没有验证签名实际上是由任何特定方完成的。我假设您在调用函数中执行此操作,因为它返回证书。

空白

在您设置的签名例程中PreserveWhitespace=true。这意味着空格将包含在签名的哈希计算中。确保PreserveWhitespace=true在加载文档时也设置了验证(该部分未包含在发布的代码中,所以我不知道)。

参考

最后,您的代码容易受到 Xml 签名包装攻击,因为您没有正确检查签名的引用。请参阅我的这篇博客文章以获取示例。

于 2016-04-05T05:45:12.123 回答
0

安德斯,谢谢你的建议。在玩了几个星期之后,我终于得到了我的代码来验证它,我终于有了一些工作,所以我想与你们分享它。验证方法没有改变,Xades 的东西是自定义的,不需要验证用我的代码签名的文件。最后,我使用以下 2 个 url 作为我的起点,但谷歌的几十个页面也有帮助:

https://blogs.msdn.microsoft.com/winsdk/2015/11/14/using-sha256-with-the-signedxml-class/ https://gist.github.com/sneal/f35de432115b840c4c1f#file-rsapkcs1sha256signaturedescription

private static Stream SignSHA256Stream(X509Certificate2 certificate, Stream stream)
    {
        if (certificate == null)
        {
            Logger.Error("certificate argument is null");
            throw new ArgumentNullException("certificate");
        }

        if (stream == null)
        {
            Logger.Error("stream argument is null");
            throw new ArgumentNullException("stream");
        }

        RSAPKCS1SHA256SignatureDescription.Register();

        var document = new XmlDocument();
        document.Load(stream);
        XmlNode root = document.DocumentElement;
        XmlNodeList nodeList = document.GetElementsByTagName("Signature", Xmldsigns);

        // nodeList is actively updated so we delete element [0] until there are none left.
        while (nodeList.Count > 0)
        {
            root.RemoveChild(nodeList[0]);
        }

        Reference reference = new Reference(string.Empty);
        reference.AddTransform(new XmlDsigEnvelopedSignatureTransform()); 
        reference.AddTransform(new XmlDsigExcC14NTransform());
        reference.DigestMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";

        var keyInfo = new KeyInfo();
        keyInfo.AddClause(new KeyInfoX509Data(certificate));

        SignedXml sxml = new SignedXml(document);
        sxml.KeyInfo = keyInfo;
        sxml.SigningKey = certificate.PrivateKey;
        sxml.SignedInfo.SignatureMethod = Xmldsigns256;
        sxml.AddReference(reference);
        sxml.SignedInfo.CanonicalizationMethod = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
        sxml.ComputeSignature();

        XmlElement xmlDigitalSignature = sxml.GetXml();

        if (document.DocumentElement == null)
        {
            document.AppendChild(document.ImportNode(xmlDigitalSignature, true));
        }
        else
        {
            document.DocumentElement.AppendChild(document.ImportNode(xmlDigitalSignature, true));
        }

        if (document.FirstChild is XmlDeclaration)
        {
            document.RemoveChild(document.FirstChild);
        }

        MemoryStream outStream = new MemoryStream();
        document.Save(outStream);

        return outStream;
    }
于 2016-04-08T16:00:46.733 回答