.NET подписанный префикс XML - PullRequest
11 голосов
/ 19 декабря 2008

Есть ли способ установить префикс для подписи подписанного XML-документа (класс SignedXml в .Net)?

Так что вместо:

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

Я мог бы иметь следующее:

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

Ответы [ 3 ]

8 голосов
/ 04 апреля 2009

Это не может быть сделано. Если вы измените XML после того, как он будет подписан , его невозможно будет проверить, как это было в примере выше. IMO, это недостаток в реализации цифровой подписи MSFT, с которым вам придется жить.

Многие люди скажут, что для этого нет причин, и они технически правильны. Но когда вы имеете дело с огромным поставщиком (то есть правительством штата или банком), удачи вам в том, чтобы он изменил его со своей стороны. Большинство эталонных реализаций включают его.

ОБНОВЛЕНИЕ: подпись подписывает все в элементе SignedInfo, поэтому, если вы обновите этот элемент после факта, подпись больше не будет действительной. Вы "подделали" сообщение.

6 голосов
/ 19 декабря 2008

Прежде всего, на самом деле нет веских причин для этого. Две формы функционально эквивалентны. Любой хорошо ведущий себя XML-процессор будет обрабатывать их абсолютно одинаково. Поэтому, если вы не пытаетесь общаться с приложением, которое не реализует должным образом пространства имен XML, лучше (IMO) просто оставить форму по умолчанию в покое. (И даже в этом случае было бы лучше, если это вообще возможно, вместо этого исправить неисправное приложение.)

Тем не менее, вы можете вручную установить префикс для XmlElement, который возвращается SignedXml.GetXml () и его дочерних элементов, используя 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";
}
1 голос
/ 08 июня 2017

Это можно сделать, но необходимо изменить класс SignedXml, чтобы добавить префикс перед получением значения дайджеста узла SignedInfo.

Метод ComputeSignature будет изменен для добавления параметра префикса

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

Когда этот метод вызывается, он вычисляет значение подписи, переваривая значение узла SignedInfo, если вы получите это значение без префикса "ds", а затем добавите префикс, вы получите недопустимую подпись, поэтому вам придется добавьте префикс ДО получения значения дайджеста для подписанного узла.

Это значение дайджеста генерируется в методе 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);
}

Хорошо, теперь у вас есть значение Signature для узлов SignedInfo с префиксом "ds", что говорит о том, что у вас еще нет xml с префиксом, поэтому, если вы просто вызовете метод GetXml, вы получите XML без префикса и, конечно, потому что значение подписи было рассчитано с учетом префикса ds, у вас будет недопустимая подпись. Чтобы избежать этого и получить структуру xml с префиксом, необходимо изменить метод GetXml, добавить параметр prefix и вызвать метод SetPrefix, который добавит префикс "ds" ко всем узлам в Signature Xml

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");
...