xml signature DS prefix?

18,932

Solution 1

if anyone know a solution, i need to sign it like that cause the software importing it verifies it with "ds:signature" , so with "ds" prefix

The prefix should be unimportant - all that should matter is what namespace the element is in. It shouldn't matter how that namespace is expressed. If it does, that shows brokenness in the verifying code, I'd say.

However, if you really want to do this, is there any reason you don't want to just replace the element with one with the same contents, but using the prefix you want? It shouldn't be hard to do that in LINQ to XML.

Solution 2

i found the solution here

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

Solution 3

I tried these solutions, but they didn't worked out. However, by looking at .NET source code (http://referencesource.microsoft.com/) we can see that this can be acomplished easily by providing a derived XmlDocument class to SignedXml, where namespace can be added. However, having the "ds" prefix within 'SignedInfo' and descendants will cause siganture to fail. Here is the best I could do without breaking the signature:


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

This is used on the SignedXml Creation:

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

You can see full source files at:

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

Share:
18,932

Related videos on Youtube

George Dima
Author by

George Dima

Updated on June 29, 2022

Comments

  • George Dima
    George Dima almost 2 years

    Is there a way to sign an XML file with RSA and to have the namespace prefix "ds:Signature" instead of "Signature"? I spent many hourstrying to solve this and from what I can see there is no solution.

    It seems that it is hard-coded in the class System.Security.Cryptography.Xml.Signature.

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

    If anyone knows a solution, I need to sign it like that cause the software importing it verifies it with "ds:signature", so with "ds" prefix the software verifies it like this:

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

    normally it signs like this:

    <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>
    

    and I need it to do it like this:

    <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>
    
    • George Dima
      George Dima
      if you modify any of the xml content after signing the signaturevalue will not match...
    • George Dima
      George Dima
      i think you don't understant. even if you add a whitespace in the signed xml text it cannot be verified . check first post, i added details
    • George Dima
      George Dima
      @Riki_VaL , that solution is not valid, it will fail verification, you didn't understood the initial question. i already gave final solution.
  • George Dima
    George Dima over 11 years
    i edited first post to see how the software that receives the XML verifies it... , you can't replace the elements prefix , because then the signaturevalue would differ...
  • John Gibb
    John Gibb about 10 years
    @GeorgeDima I'm playing around with this, and modifying the signature block in the xml doesn't seem to affect the signatureValue. Therefore, it should be safe to do this after the signature has been generated. Are you sure that didn't work for you?
  • George Dima
    George Dima about 10 years
    yes, only my solution posted here worked for me, i mean to get it verified.
  • Oxygen
    Oxygen about 8 years
    Hi George, how your verification works? I am trying the same steps but it fails. Could you pleas post your code of signing and verification? It will help a lot
  • tarrball
    tarrball over 7 years
    this didn't work for me, signature block ended up the same without the prefix