9

RSAを使用してXMLファイルに署名し、名前空間プレフィックスを「Signature」ではなく「ds:Signature」にする方法はありますか?私はこれを解決するために何時間も費やしました、そして私が見ることができるものから解決策はありません。

System.Security.Cryptography.Xml.Signatureクラスにハードコーディングされているようです。

XmlElement element = document.CreateElement("Signature", "http://www.w3.org/2000/09/xmldsig#");

誰かが解決策を知っている場合、それをインポートするソフトウェアが「ds:signature」で検証するように署名する必要があるため、「ds」プレフィックスを付けると、ソフトウェアは次のように検証します。

    public static bool VerifySignature(XmlDocument doc, RSA key, string prefix)
    {
        SignedXml xml = new SignedXml(doc);
        string str = "Signature";
        if (!string.IsNullOrEmpty(prefix))
        {
            str = string.Format("{0}:{1}", prefix, str);
        }
        XmlNodeList elementsByTagName = doc.GetElementsByTagName(str);
        xml.LoadXml((XmlElement)elementsByTagName[0]);
        return xml.CheckSignature(key);
    }

  VerifySignature(xmlDoc, rsa, "ds");

通常、次のように署名します。

<kk>blabla<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><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" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><DigestValue>rVL2nKjPTBhL9IDHYpu69OiE8gI=</DigestValue></Reference></SignedInfo><SignatureValue>CfXW9D/ErmHjzxIjy0/54/V3nst6j/XXcu7keR17LApfOZEpxjEvAlG3VnBZIi3jxQzU6t9RkmfDyngcRZccJByuuA6YDwFTQxZNRgu2GRoZxMKWnkm+MtQ0jH0Fo78GivCxV+iIewZvsrUQLzG01cXuZSH/k2eeMUaEooJaLQiYpO2aNVn5xbosTPtGlsACzFWz34E69/ZeeLZbXLc3jpDO+opxdYJ5e+Tnk/UM2Klt+N+m7Gh/sUNTPgkDiwP3q3y3O9tvCT0G2XmQaWBP4rw9TIoYHQtucm2b8R2JeggbeRKOetbRYV218RT8CK2Yuy0FIUlQXdabKyp9F96Yc55g8eNe10FGtgietH2iqquIVFLCA8fu3SZNLDPMoyHnVNKdBvI35+S8hrAaybEkMvo7iYnUSY5KrlGSfGGtfQXdaISutAzcnGPDFXgZXPNzNy7eL0u+Lt3yWWkj7wh6Zeh4fH2+nXDWYCWbLpegAEX4ZWSI5Ts6D1TplMJTGH1F0GyflehH4u+W4Lc3TvkB4dWjEuiKgnpl3hcvoj2CWFaeAxXMd/64tU/YMm8+1gSBjkVH6oV+QlI/m0z6M8FPVEVC2as0wLG2woVwmzVLcaQKyPi7NN4eO9ea7QNfaRHaofU4LQO/Y3FNJOP+uMfYlGJKWSr3qv29+BQjeNldNJY=</SignatureValue></Signature></kk>

そして私はそれをこのようにするためにそれを必要とします:

<kk>blabla<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /><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:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><ds:DigestValue>rVL2nKjPTBhL9IDHYpu69OiE8gI=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>CfXW9D/ErmHjzxIjy0/54/V3nst6j/XXcu7keR17LApfOZEpxjEvAlG3VnBZIi3jxQzU6t9RkmfDyngcRZccJByuuA6YDwFTQxZNRgu2GRoZxMKWnkm+MtQ0jH0Fo78GivCxV+iIewZvsrUQLzG01cXuZSH/k2eeMUaEooJaLQiYpO2aNVn5xbosTPtGlsACzFWz34E69/ZeeLZbXLc3jpDO+opxdYJ5e+Tnk/UM2Klt+N+m7Gh/sUNTPgkDiwP3q3y3O9tvCT0G2XmQaWBP4rw9TIoYHQtucm2b8R2JeggbeRKOetbRYV218RT8CK2Yuy0FIUlQXdabKyp9F96Yc55g8eNe10FGtgietH2iqquIVFLCA8fu3SZNLDPMoyHnVNKdBvI35+S8hrAaybEkMvo7iYnUSY5KrlGSfGGtfQXdaISutAzcnGPDFXgZXPNzNy7eL0u+Lt3yWWkj7wh6Zeh4fH2+nXDWYCWbLpegAEX4ZWSI5Ts6D1TplMJTGH1F0GyflehH4u+W4Lc3TvkB4dWjEuiKgnpl3hcvoj2CWFaeAxXMd/64tU/YMm8+1gSBjkVH6oV+QlI/m0z6M8FPVEVC2as0wLG2woVwmzVLcaQKyPi7NN4eO9ea7QNfaRHaofU4LQO/Y3FNJOP+uMfYlGJKWSr3qv29+BQjeNldNJY=</ds:SignatureValue></ds:Signature></kk>
4

6 に答える 6

8

ここで解決策を見つけました

using System;
using System.Reflection;
using System.Security.Cryptography.Xml;
using System.Security.Cryptography;
using System.Collections.Generic;
using System.Text;
using System.Xml;

namespace mysign
{
public class PrefixedSignedXML : SignedXml
{
    public PrefixedSignedXML(XmlDocument document)
        : base(document)
    { }

    public PrefixedSignedXML(XmlElement element)
        : base(element)
    { }

    public PrefixedSignedXML()
        : base()
    { }

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

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

    //Invocar por reflexión al método privado SignedXml.BuildDigestedReferences
    private void BuildDigestedReferences()
    {
        Type t = typeof(SignedXml);
        MethodInfo m = t.GetMethod("BuildDigestedReferences", BindingFlags.NonPublic | BindingFlags.Instance);
        m.Invoke(this, new object[] { });
    }

    private byte[] GetC14NDigest(HashAlgorithm hash, string prefix)
    {
        //string securityUrl = (this.m_containingDocument == null) ? null : this.m_containingDocument.BaseURI;
        //XmlResolver xmlResolver = new XmlSecureResolver(new XmlUrlResolver(), securityUrl);
        XmlDocument document = new XmlDocument();
        document.PreserveWhitespace = true;
        XmlElement e = this.SignedInfo.GetXml();
        document.AppendChild(document.ImportNode(e, true));
        //CanonicalXmlNodeList namespaces = (this.m_context == null) ? null : Utils.GetPropagatedAttributes(this.m_context);
        //Utils.AddNamespaces(document.DocumentElement, namespaces);

        Transform canonicalizationMethodObject = this.SignedInfo.CanonicalizationMethodObject;
        //canonicalizationMethodObject.Resolver = xmlResolver;
        //canonicalizationMethodObject.BaseURI = securityUrl;
        SetPrefix(prefix, document.DocumentElement); //establecemos el prefijo antes de se que calcule el hash (o de lo contrario la firma no será válida)
        canonicalizationMethodObject.LoadInput(document);
        return canonicalizationMethodObject.GetDigestedOutput(hash);
    }

    private void SetPrefix(string prefix, XmlNode node)
    {
        foreach (XmlNode n in node.ChildNodes)
            SetPrefix(prefix, n);
        node.Prefix = prefix;
    }
}
}
于 2012-09-09T21:46:31.503 に答える
8

誰かが解決策を知っている場合は、それをインポートするソフトウェアが「ds:signature」で検証するように署名する必要があるため、「ds」プレフィックスを使用します

プレフィックス重要ではありません。重要なのは、要素がどの名前空間にあるかだけです。その名前空間がどのように表現されるかは問題ではありません。もしそうなら、それは検証コードの破損を示していると思います。

ただし、本当にこれを行いたい場合は、要素を同じ内容の要素に置き換えるのではなく、必要な接頭辞を使用する理由はありますか? LINQ to XML でそれを行うのは難しくありません。

于 2012-08-31T16:40:16.747 に答える
1

これらの解決策を試しましたが、うまくいきませんでした。ただし、.NET ソース コード ( http://referencesource.microsoft.com/ ) を見ると、名前空間を追加できる SignedXml に派生 XmlDocument クラスを提供することで、これを簡単に実現できることがわかります。ただし、「SignedInfo」とその子孫に「ds」プレフィックスがあると、署名が失敗します。署名を壊さずにできる最善の方法は次のとおりです。


XmlDsigDocument.cs

using System;
using System.Collections.Generic;
using System.Security.Cryptography.Xml;
using System.Text;
using System.Xml;

namespace CustomSecurity
{
class XmlDsigDocument : XmlDocument
{
    // Constants
    public const string XmlDsigNamespacePrefix = "ds";

    /// <summary>
    /// Override CreateElement function as it is extensively used by SignedXml
    /// </summary>
    /// <param name="prefix"></param>
    /// <param name="localName"></param>
    /// <param name="namespaceURI"></param>
    /// <returns></returns>
    public override XmlElement CreateElement(string prefix, string localName, string namespaceURI)
    {
        // CAntonio. If this is a Digital signature security element, add the prefix. 
        if (string.IsNullOrEmpty(prefix))
        {
            // !!! Note: If you comment this line, you'll get a valid signed file! (but without ds prefix)
            // !!! Note: If you uncomment this line, you'll get an invalid signed file! (with ds prefix within 'Signature' object)
            //prefix = GetPrefix(namespaceURI);

            // The only way to get a valid signed file is to prevent 'Prefix' on 'SignedInfo' and descendants.
            List<string> SignedInfoAndDescendants = new List<string>();
            SignedInfoAndDescendants.Add("SignedInfo");
            SignedInfoAndDescendants.Add("CanonicalizationMethod");
            SignedInfoAndDescendants.Add("InclusiveNamespaces");
            SignedInfoAndDescendants.Add("SignatureMethod");
            SignedInfoAndDescendants.Add("Reference");
            SignedInfoAndDescendants.Add("Transforms");
            SignedInfoAndDescendants.Add("Transform");
            SignedInfoAndDescendants.Add("InclusiveNamespaces");
            SignedInfoAndDescendants.Add("DigestMethod");
            SignedInfoAndDescendants.Add("DigestValue");
            if (!SignedInfoAndDescendants.Contains(localName))
            {
                prefix = GetPrefix(namespaceURI);
            }
        }

        return base.CreateElement(prefix, localName, namespaceURI);
    }

    /// <summary>
    /// Select the standar prefix for the namespaceURI provided
    /// </summary>
    /// <param name="namespaceURI"></param>
    /// <returns></returns>
    public static string GetPrefix(string namespaceURI)
    {
        if (namespaceURI == "http://www.w3.org/2001/10/xml-exc-c14n#")
            return "ec";
        else if (namespaceURI == SignedXml.XmlDsigNamespaceUrl)
            return "ds";

        return string.Empty;
    }
}
}

これは SignedXml の作成で使用されます。

    // Create a new XML document.
    XmlDsigDocument doc = new XmlDsigDocument();

    // Load the passed XML file using its name.
    doc.Load(new XmlTextReader(FileName));

    // Create a SignedXml object.
    SignedXml signedXml = new SignedXml(doc);

完全なソース ファイルは次の場所で確認できます。

https://social.msdn.microsoft.com/Forums/en-US/cd595379-f66a-49c8-8ca2-62acdc58b252/add-prefixds-signedxml?forum=xmlandnetfx

于 2016-07-14T11:23:16.170 に答える
0

正しいかもしれません SetPrefix コードは次のようになります。

    private void SetPrefix(String prefix, XmlNode node) {
        foreach (XmlNode n in node.ChildNodes)
        {
            SetPrefix(prefix, n);
            n.Prefix = prefix;
        }
    }
于 2013-02-14T12:20:39.073 に答える