[英]signing a xml document with x509 certificate
每次我尝试发送已签名的 XML 时,Web 服务验证程序都会拒绝它。
为了签署文件,我刚刚修改了微软提供的这个示例代码:
http://msdn.microsoft.com/es-es/library/ms229745(v=vs.110).aspx
我的实现:
public static XmlDocument FirmarXML(XmlDocument xmlDoc)
{
try
{
X509Certificate2 myCert = null;
var store = new X509Store(StoreLocation.CurrentUser); //StoreLocation.LocalMachine fails too
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates;
foreach (var certificate in certificates)
{
if (certificate.Subject.Contains("xxx"))
{
myCert = certificate;
break;
}
}
if (myCert != null)
{
RSA rsaKey = ((RSA)myCert.PrivateKey);
// Sign the XML document.
SignXml(xmlDoc, rsaKey);
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return xmlDoc;
}
// Sign an XML file.
// This document cannot be verified unless the verifying
// code has the key with which it was signed.
public static void SignXml(XmlDocument xmlDoc, RSA Key)
{
// Check arguments.
if (xmlDoc == null)
throw new ArgumentException("xmlDoc");
if (Key == null)
throw new ArgumentException("Key");
// Create a SignedXml object.
SignedXml signedXml = new SignedXml(xmlDoc);
// Add the key to the SignedXml document.
signedXml.SigningKey = Key;
// Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "";
// 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));
}
我想我正在使用我自己的证书执行相同的步骤,但是它没有按预期工作。
欢迎任何建议。
服务器如何知道文档是用什么证书签名的? 您似乎没有在签名文件中包含证书:
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data keyInfoData = new KeyInfoX509Data( Key );
keyInfo.AddClause( keyInfoData );
signedXml.KeyInfo = keyInfo;
如果您需要更多详细信息,请参阅我的博客条目
http://www.wiktorzychla.com/2012/12/interoperable-xml-digital-signatures-c_20.html
我已经按照Wiktor的示例进行了一些更改。 但是,签名仍然被Web服务拒绝。
我现在用来签名的方法是:
public static string SignXml(XmlDocument Document, X509Certificate2 cert)
{
SignedXml signedXml = new SignedXml(Document);
signedXml.SigningKey = cert.PrivateKey;
// Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "";
// Add an enveloped transformation to the reference.
XmlDsigEnvelopedSignatureTransform env =
new XmlDsigEnvelopedSignatureTransform(true);
reference.AddTransform(env);
//canonicalize
XmlDsigC14NTransform c14t = new XmlDsigC14NTransform();
reference.AddTransform(c14t);
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data keyInfoData = new KeyInfoX509Data(cert);
KeyInfoName kin = new KeyInfoName();
kin.Value = "Public key of certificate";
RSACryptoServiceProvider rsaprovider = (RSACryptoServiceProvider)cert.PublicKey.Key;
RSAKeyValue rkv = new RSAKeyValue(rsaprovider);
keyInfo.AddClause(kin);
keyInfo.AddClause(rkv);
keyInfo.AddClause(keyInfoData);
signedXml.KeyInfo = keyInfo;
// 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();
Document.DocumentElement.AppendChild(
Document.ImportNode(xmlDigitalSignature, true));
return Document.OuterXml;
}
签名在文档中显示如下:
<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#rsa-sha1" />
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>zRSPtja5EtX7hVbyJ11EjoYTRDk=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>Ua1/WP28WzfXaxUj....</SignatureValue>
<KeyInfo>
<KeyName>Public key of certificate</KeyName>
<KeyValue>
<RSAKeyValue>
<Modulus>0mmCc5Rlibh44o/C/k5....</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
<X509Data>
<X509Certificate>MIIF3jCCBUegAwIBAgIEPQa1....</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
当正确的文档发送到服务器时,这将返回此签名,我将其用作识别必要字段的模式:
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>nQOtmW194/aI+hedq+Dqp+n3IuU=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>kyp+a6arETylW8ZuucKJyd....</ds:SignatureValue>
<ds:KeyInfo>
<ds:KeyName>Public key of certificate</ds:KeyName>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus>t0Yial28LxcIoPj16PlLIzaV...</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
<ds:X509Data>
<ds:X509Certificate>MIIHOTCCBiGgAwIBAgICVJIwDQYJKo....</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
在我看来似乎正确。 但是仍然无法正常工作。 有任何线索吗?
自从创建此帖子以来已经很长时间了。 我遇到了同样的问题,无法验证数字签名。
谁有同样的问题。 就我而言,区别在于 XmlDocument.PreserveWhitespace 选项。
当PreserveWhitespace = true
,文档在检查公钥时无效。 PreserveWhitespace = false
使签名的 XML 有效。
我猜当将签名的 XML 保存到文件并将其发送到服务器时。 文档中插入了一些空格或特殊字符使其无效。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.