是否有一种方法来设置上的签名的XML文档(在.net SignedXml类)?

的签名前缀 因此的

代替:

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#>
...
</Signature>

我可以有以下内容:

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#>
...
</ds:Signature>
有帮助吗?

解决方案

首先,实在是没有什么好理由这样做。这两种形式在功能上等同。任何乖巧的XML处理器将处理它们绝对相同。所以,除非你正在试图说服一个不正确地实现XML命名空间的应用程序,它的更好(IMO)只是独自离开默认的形式。 (即使在这种情况下,它会更好,如果可能的话,要得到,而不是固定的应用程序错误。)

也就是说,可以手动设置在由SignedXml.GetXml(返回的XmlElement前缀),并使用XPath这样其子元素:

XmlElement signature = signedXml.GetXml();
foreach (XmlNode node in signature.SelectNodes(
    "descendant-or-self::*[namespace-uri()='http://www.w3.org/2000/09/xmldsig#']"))
{
    node.Prefix = "ds";
}

其他提示

它不能这样做。如果修改了XML的它已经签署后的它可能无法得到验证,这是在上面的例子中的情况。 IMO这是MSFT的数字签名实现一个缺陷,你将不得不忍受。

很多人会说,没有理由这样做,而且他们在技术上是正确的。但是,当你正在处理一个巨大的供应商(即州政府或银行),好运气让他们改变他们的结束。最参考实现包括它。

更新:签名标志的所有 SignedInfo元素,所以如果你在事后更新该元素,那么签名不再有效。你有“篡改”与该消息。

这是可以做到的,但有必要修改SignedXml类获得的SignedInfo节点的摘要值前加上前缀。

在ComputeSignature方法进行修改,添加前缀参数

public void ComputeSignature(string prefix){...}

当这个方法被调用它计算通过消化的SignedInfo节点的值,如果你没有“DS”前缀得到这个值,然后添加前缀,你会得到一个无效签名的签名值,所以你必须要添加前缀之前获得的SignedInfo节点的摘要值。

此摘要值在该方法中生成的GetC14NDigest,所以这种方法将被修改以添加前缀参数和添加前缀之前得到的摘要值

private byte[] GetC14NDigest(HashAlgorithm hash, string prefix)
{
    XmlDocument document = new XmlDocument();
    document.PreserveWhitespace = false;
    XmlElement e = this.SignedInfo.GetXml(); //get the signedinfo nodes
    document.AppendChild(document.ImportNode(e, true));        
    Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject;       
    SetPrefix(prefix, document.DocumentElement); /*Set the prefix before getting the HASH*/
    canonicalizationMethodObject.LoadInput(document);
    return canonicalizationMethodObject.GetDigestedOutput(hash);
}

好了,现在你必须通过SignedInfo节点与“DS”前缀签名值,这就是说,你还没有带前缀的XML还,所以如果你只是调用的getXML方法你会得到不带前缀,当然,因为签名值计算考虑了DS xml前缀,你将有一个无效的签名。 为了避免这种情况,并获得与前缀XML结构,你必须修改的getXML方法,添加前缀参数,并调用SetPrefix方法至极将在签名的Xml添加“DS”前缀到所有节点

public XmlElement GetXml(string prefix)
{
    XmlElement e = this.GetXml();
    SetPrefix(prefix, e); //return the xml structure with the prefix
    return e;
}

我要离开这里的类与修改

自定义类

internal sealed class CustomSignedXml : SignedXml
{
    XmlElement obj = null;
    public CustomSignedXml (XmlDocument xml)
        : base(xml)
    {
    }

    public CustomSignedXml (XmlElement xmlElement)
        : base(xmlElement)
    {

    }

    public XmlElement GetXml(string prefix)
    {
        XmlElement e = this.GetXml();
        SetPrefix(prefix, e);
        return e;
    }

    public void ComputeSignature(string prefix)
    {
        this.BuildDigestedReferences();
        AsymmetricAlgorithm signingKey = this.SigningKey;
        if (signingKey == null)
        {
            throw new CryptographicException("Cryptography_Xml_LoadKeyFailed");
        }
        if (this.SignedInfo.SignatureMethod == null)
        {
            if (!(signingKey is DSA))
            {
                if (!(signingKey is RSA))
                {
                    throw new CryptographicException("Cryptography_Xml_CreatedKeyFailed");
                }
                if (this.SignedInfo.SignatureMethod == null)
                {
                    this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
                }
            }
            else
            {
                this.SignedInfo.SignatureMethod = "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
            }
        }
        SignatureDescription description = CryptoConfig.CreateFromName(this.SignedInfo.SignatureMethod) as SignatureDescription;
        if (description == null)
        {
            throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated");
        }
        HashAlgorithm hash = description.CreateDigest();
        if (hash == null)
        {
            throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed");
        }
        this.GetC14NDigest(hash, prefix);
        this.m_signature.SignatureValue = description.CreateFormatter(signingKey).CreateSignature(hash);
    }         

    private byte[] GetC14NDigest(HashAlgorithm hash, string prefix)
    {

        XmlDocument document = new XmlDocument();
        document.PreserveWhitespace = false;
        XmlElement e = this.SignedInfo.GetXml();
        document.AppendChild(document.ImportNode(e, true));               

        Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject;            
        SetPrefix(prefix, document.DocumentElement); //Set the prefix before getting the HASH
        canonicalizationMethodObject.LoadInput(document);
        return canonicalizationMethodObject.GetDigestedOutput(hash);
    }

    private void BuildDigestedReferences()
    {
        Type t = typeof(SignedXml);
        MethodInfo m = t.GetMethod("BuildDigestedReferences", BindingFlags.NonPublic | BindingFlags.Instance);
        m.Invoke(this, new object[] { });
    }

    private void SetPrefix(string prefix, XmlNode node)
    {
       foreach (XmlNode n in node.ChildNodes)
          SetPrefix(prefix, n);
       node.Prefix = prefix;
    }
}

并使用它的方式

CustomSignedXml signedXml = new CustomSignedXml();
.
.//your code
. 

//compute the signature with the "ds" prefix

signedXml.ComputeSignature("ds");

//get the xml of the signature with the "ds" prefix

XmlElement xmlDigitalSignature = signedXml.GetXml("ds");
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top