Pregunta

¿Hay una manera de establecer el prefijo de la firma de un documento XML Firmado (clase SignedXml en .Net)?

Así que en lugar de:

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

Podría tener lo siguiente:

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#>
...
</ds:Signature>
¿Fue útil?

Solución

En primer lugar, en realidad no hay ninguna buena razón para hacer esto. Las dos formas son funcionalmente equivalentes. Cualquier procesador XML buen comportamiento se encargará de ellos absolutamente idéntica. Así que a menos que usted está tratando de comunicarse con una aplicación que no implementa adecuadamente los espacios de nombres XML, que es mejor (OMI) sólo para salir del formulario predeterminado solo. (E incluso en ese caso, sería mejor, si es posible, para conseguir la aplicación defectuosa fijo en su lugar.)

Dicho esto, se puede establecer manualmente el prefijo de la XmlElement que es devuelto por SignedXml.GetXml () y sus elementos secundarios utilizando XPath como esto:

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

Otros consejos

No se puede hacer. Si modifica el código XML después de que haya sido firmado puede que no sea capaz de ser verificada, como fue el caso en el ejemplo anterior. OMI esto es una falla en la implementación de la firma digital MSFT que va a tener que vivir.

Mucha gente va a decir que no hay ninguna razón para hacer esto, y son técnicamente correcto. Pero cuando se trata de un gran proveedor (es decir, un gobierno estatal o banco), buena suerte conseguir que la cambien en su extremo. La mayoría de las implementaciones de referencia incluyen a él.

ACTUALIZACIÓN: Los signos de la firma todo en el elemento SignedInfo, así que si usted va a actualizar ese elemento después del hecho, entonces la firma ya no es válida. Usted ha "manipulado" con el mensaje.

Se puede hacer, pero es necesario modificar la clase SignedXml añadir el prefijo antes de obtener el valor de resumen del nodo SignedInfo.

El método ComputeSignature será modificar para añadir el parámetro prefijo

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

Cuando se llama a este método que calcula el valor de firma digiriendo el valor del nodo SignedInfo, si se obtiene este valor sin el prefijo "DS" y luego agrega el prefijo obtendrá una firma no válida, por lo que tendrá que añadir el prefijo antes de obtener el valor de resumen del nodo SignedInfo.

Este valor digerir se genera en el método GetC14NDigest, por lo que este método será modificar para añadir el parámetro prefijo y añadir el prefijo antes de obtener el valor de resumen

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

Ok, por lo que ahora tiene el valor de firma de los nodos SignedInfo con el prefijo "DS", que se dice que todavía no tienen el xml con el prefijo sin embargo, así que si sólo llama al método GetXml usted recibirá el XML sin el prefijo y, por supuesto, porque el valor de firma se calcula teniendo en cuenta los ds prefijo que tendrá una firma no válida. Para evitar eso y la estructura XML con el prefijo tiene que modificar el método GetXml, agregar el parámetro prefijo, y llamar al método wich SetPrefix añadirá el "DS" prefijo a todos los nodos en el XML Signature

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

Lo dejo aquí la clase con esas modificaciones

clase personalizada

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

Y la manera de utilizarlo

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");
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top