我可以签名,但无法使用自定义SHA256加密验证.NET 4.0中的SignedXML文档

时间:2016-04-04 14:09:19

标签: signedxml

长话短说,我可以签好文件。但每次验证它们都会返回false。我查看了google的前5或6页并找到了解决方案,但我发现的每个“修复”都无法提供帮助。任何帮助将不胜感激,因为我一直试图解决这个问题一个多星期了。此外,这些证书的私钥不可导出,也不能导出。我不确定这是否重要。此外,我现在选择不包括ValidateCertificate,因为它从来没有一次成功。它总是在CheckSignature()失败。谢谢。

我正在使用它来生成我的证书:

makecert -a SHA256 -n“CN = JEA2.me”-pe -r -len 2048 -sy 24 -sky signature -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;
        }

2 个答案:

答案 0 :(得分:2)

查看代码,我可以找到两个可能存在问题的地方:

证书有效期。

使用不带任何参数的CheckSignature()要求签名证书由受信任的根颁发机构签名。由于您已经提取了作为签名一部分的证书,我建议您进行测试,将呼叫更改为

bool validSignature = signedXml.CheckSignature(certificate);

请注意,您只知道Xml是由文件中的证书信息签名的。您无法确认签名实际上是由任何特定方完成的。我假设你在调用函数中这样做,因为它返回证书。

空白

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

参考

最后,您的代码很容易受到Xml签名包装攻击,因为您没有正确检查签名的引用。有关示例,请参阅this blog post of mine

答案 1 :(得分:0)

安德斯,谢谢你的建议。经过几周的努力,我终于得到了我的代码验证,我终于得到了一些工作,所以我想与你们分享。验证方法没有改变,Xade的东西是自定义的,不需要验证用我的代码签名的文件。最后,我使用以下2个网址作为我的起点,但谷歌的几十页也有所帮助:

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;
    }