如何使用 SHA256 和 X.509 正确地签署 XML?
How to sign XML with SHA256 & X.509 correctly?
我想使用自签名 X.509 证书使用 SHA256 签署 XML。我受 Whosebug 中许多文章的启发并使用了这段代码:
X509Certificate2 cert = new X509Certificate2();
X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 cert2 in store.Certificates)
{
if (cert2.Subject == "CN=TestCerificate")
{
cert = cert2;
break;
}
}
store.Close();
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
var exportedKeyMaterial = cert.PrivateKey.ToXmlString(true);
var key = new RSACryptoServiceProvider(new CspParameters(24));
key.PersistKeyInCsp = false;
key.FromXmlString(exportedKeyMaterial);
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load("test.xml");
SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = key;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
Reference reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.Uri = "";
reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
signedXml.AddReference(reference);
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(cert));
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();
doc.Save("testSig.xml");
之后,生成的 "testSig.xml" 的签名 XML 部分如下所示:
<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/2000/09/xmldsig#dsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>ghOEPeYtAUs5Kb8VMOCIS3f2wIY=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>HANI0GrICbyc5tlmvtU9cB7txdxtuY4uDsntp5XVzaRQbts76ff3Qg==</SignatureValue>
</Signature>
如您所见,XML 表示 "SHA1" 用于签署 XML(参见节点 "SignatureMethod" 和 "DigestMethod")。但我希望,必须在这些节点中声明 SHA256-URL。这个假设是否正确?如果是,有人知道如何解决这个问题吗?我使用 C# 4.6.0.
谨致问候,
迈克尔
虽然您成功调用了仅进行计算的 signedXml.ComputeSignature()
,但它不会将签名元素插入到文档中(您在构造函数中传递的 XmlDocument 正是文档 GetXml()
的内容节点将成为父节点)。
您需要调用 signedXml.GetXml()
(在 ComputeSignature
之后)以获取计算的 ds:Signature
元素,然后将其插入到您的文档中。
您的文档中已有签名节点这一事实令人困惑。我的第一个想法是 test.xml
中已经有那个签名,但你的评论说它只是来自其他地方的一些糟糕代码。吸取教训,我想 :).
我想使用自签名 X.509 证书使用 SHA256 签署 XML。我受 Whosebug 中许多文章的启发并使用了这段代码:
X509Certificate2 cert = new X509Certificate2();
X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 cert2 in store.Certificates)
{
if (cert2.Subject == "CN=TestCerificate")
{
cert = cert2;
break;
}
}
store.Close();
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
var exportedKeyMaterial = cert.PrivateKey.ToXmlString(true);
var key = new RSACryptoServiceProvider(new CspParameters(24));
key.PersistKeyInCsp = false;
key.FromXmlString(exportedKeyMaterial);
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.Load("test.xml");
SignedXml signedXml = new SignedXml(doc);
signedXml.SigningKey = key;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
Reference reference = new Reference();
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.Uri = "";
reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
signedXml.AddReference(reference);
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(new KeyInfoX509Data(cert));
signedXml.KeyInfo = keyInfo;
signedXml.ComputeSignature();
doc.Save("testSig.xml");
之后,生成的 "testSig.xml" 的签名 XML 部分如下所示:
<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/2000/09/xmldsig#dsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>ghOEPeYtAUs5Kb8VMOCIS3f2wIY=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>HANI0GrICbyc5tlmvtU9cB7txdxtuY4uDsntp5XVzaRQbts76ff3Qg==</SignatureValue>
</Signature>
如您所见,XML 表示 "SHA1" 用于签署 XML(参见节点 "SignatureMethod" 和 "DigestMethod")。但我希望,必须在这些节点中声明 SHA256-URL。这个假设是否正确?如果是,有人知道如何解决这个问题吗?我使用 C# 4.6.0.
谨致问候, 迈克尔
虽然您成功调用了仅进行计算的 signedXml.ComputeSignature()
,但它不会将签名元素插入到文档中(您在构造函数中传递的 XmlDocument 正是文档 GetXml()
的内容节点将成为父节点)。
您需要调用 signedXml.GetXml()
(在 ComputeSignature
之后)以获取计算的 ds:Signature
元素,然后将其插入到您的文档中。
您的文档中已有签名节点这一事实令人困惑。我的第一个想法是 test.xml
中已经有那个签名,但你的评论说它只是来自其他地方的一些糟糕代码。吸取教训,我想 :).