Ren*_*ira 13 c# xml prefixes digital-signature
我对XML文件进行数字签名,但需要签名标记包含名称空间前缀"ds".我研究了很多谷歌,发现了许多相同的问题,但没有令人满意的答案.
我试图手动将"ds"放在文件中,但签名变得无效.标记"SignatureValue"对标记"SignedInfo"进行签名,因此签名变为无效.
有人可以告诉我如何生成标签"SignatureValue"的值,这样我可以在添加前缀"ds"后替换签名吗?
小智 11
显然很多人都遇到了同样的问题.在调查了Signature类的源代码之后,我得出结论,微软旨在帮助我们.LoadXml()方法中有硬编码前缀"ds".因此,可以生成签名,然后向其添加名称空间前缀"ds",加载修改后的签名并重新计算"SignatureValue".库中不幸的错误让事情变得比他们需要的更难.下面是带有解决方法和注释的代码.
public static void SignXml(XmlDocument xmlDoc, X509Certificate2 cert)
{
// transformation cert -> key omitted
RSACryptoServiceProvider key;
// Create a SignedXml object.
SignedXml signedXml = new SignedXml(xmlDoc);
// Add the key to the SignedXml document.
signedXml.SigningKey = key;
signedXml.SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
// Create a reference to be signed.
Reference reference = new Reference();
reference.Uri = "#foo";
reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
// Add an enveloped transformation to the reference.
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
signedXml.AddReference(reference);
KeyInfo keyInfo = new KeyInfo();
KeyInfoX509Data keyInfoData = new KeyInfoX509Data();
keyInfoData.AddIssuerSerial(cert.IssuerName.Format(false), cert.SerialNumber);
keyInfo.AddClause(keyInfoData);
signedXml.KeyInfo = keyInfo;
// Compute the signature.
signedXml.ComputeSignature();
// Add prefix "ds:" to signature
XmlElement signature = signedXml.GetXml();
SetPrefix("ds", signature);
// Load modified signature back
signedXml.LoadXml(signature);
// this is workaround for overcoming a bug in the library
signedXml.SignedInfo.References.Clear();
// Recompute the signature
signedXml.ComputeSignature();
string recomputedSignature = Convert.ToBase64String(signedXml.SignatureValue);
// Replace value of the signature with recomputed one
ReplaceSignature(signature, recomputedSignature);
// Append the signature to the XML document.
xmlDoc.DocumentElement.InsertAfter(xmlDoc.ImportNode(signature, true), xmlDoc.DocumentElement.FirstChild);
}
private static void SetPrefix(string prefix, XmlNode node)
{
node.Prefix = prefix;
foreach (XmlNode n in node.ChildNodes)
{
SetPrefix(prefix, n);
}
}
private static void ReplaceSignature(XmlElement signature, string newValue)
{
if (signature == null) throw new ArgumentNullException(nameof(signature));
if (signature.OwnerDocument == null) throw new ArgumentException("No owner document", nameof(signature));
XmlNamespaceManager nsm = new XmlNamespaceManager(signature.OwnerDocument.NameTable);
nsm.AddNamespace("ds", SignedXml.XmlDsigNamespaceUrl);
XmlNode signatureValue = signature.SelectSingleNode("ds:SignatureValue", nsm);
if (signatureValue == null)
throw new Exception("Signature does not contain 'ds:SignatureValue'");
signatureValue.InnerXml = newValue;
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4871 次 |
最近记录: |