Domanda

C'è un modo per impostare il prefisso sulla firma di un documento XML firmato (classe SignedXml in Net)?

Così, invece di:

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

ho potuto avere il seguente:

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

Soluzione

Prima di tutto, non c'è davvero una buona ragione per farlo. Le due forme sono funzionalmente equivalenti. Ogni processore XML ben educati li gestirà assolutamente identico. Quindi, a meno che non si sta cercando di parlare con un'applicazione che non implementa correttamente namespace XML, è meglio (IMO) solo per lasciare il modulo predefinito da solo. (E anche in quel caso, sarebbe meglio, se possibile, per ottenere l'applicazione difettosa fisso, invece.)

Detto questo, è possibile impostare manualmente il prefisso del XmlElement restituito da SignedXml.GetXml () ed i suoi elementi figlio utilizzando XPath in questo modo:

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

Altri suggerimenti

Non si può fare. Se si modifica il codice XML dopo che è stato firmato che potrebbero non essere in grado di verificare, che era il caso nell'esempio di cui sopra. IMO questo è un difetto nella implementazione della firma digitale del MSFT che si dovrà convivere.

Un sacco di gente dirà che non v'è alcun motivo per fare questo, e sono tecnicamente corretta. Ma quando hai a che fare con un fornitore enorme (vale a dire un governo statale o bancario), buona fortuna inducendole a cambiarlo sul loro fine. La maggior parte delle implementazioni di riferimento includono esso.

UPDATE: I segni delle firme tutto nell'elemento SignedInfo, quindi se si va aggiornando l'elemento dopo il fatto, allora la firma non è più valida. Avete "manomesso" con il messaggio.

Si può fare, ma è necessario modificare la classe SignedXml per aggiungere il prefisso prima di ottenere il valore digest del nodo SignedInfo.

Il metodo ComputeSignature verrà modificare per aggiungere il parametro prefix

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

Quando questo metodo viene chiamato calcola il valore della firma digerendo il valore del nodo SignedInfo, se si ottiene questo valore senza il prefisso "ds" e quindi aggiungere il prefisso otterrete una firma non valida, quindi si dovrà aggiungere il prefisso prima di ottenere il valore digest del nodo SignedInfo.

Questo valore digest viene generato nel metodo GetC14NDigest, quindi questo metodo verrà modificare per aggiungere il parametro prefisso e di aggiungere il prefisso prima di ottenere il valore digest

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, ora avete il valore della firma dei nodi SignedInfo con il prefisso "ds", detto questo ancora non avete la xml con il prefisso ancora, quindi se si chiama il metodo GetXml si otterrà xml senza il prefisso e, naturalmente, perché il valore della firma è stato calcolato considerando i ds prefisso si avrà una firma non valida. Per evitare ciò e ottenere la struttura xml con il prefisso è necessario modificare il metodo GetXml, aggiungere il parametro prefisso, e chiamare il metodo SetPrefix wich aggiungerà la "DS" prefisso a tutti i nodi nel XML Signature

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

Lascio qui la classe con quelle modifiche

CUSTOM CLASS

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

E il modo di usarlo

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");
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top