Question

Y at-il un moyen de définir le préfixe sur la signature d'un document XML signé (classe SignedXml en .Net)?

Ainsi, au lieu de:

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

Je pourrais avoir:

<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#>
...
</ds:Signature>
Était-ce utile?

La solution

Tout d'abord, il n'y a vraiment aucune bonne raison de le faire. Les deux formes sont fonctionnellement équivalentes. Tout processeur XML bien comportés va les traiter absolument identique. Donc, à moins que vous essayez de parler à une application qui ne pas correctement mettre en œuvre espaces de noms XML, il est préférable (OMI), juste pour laisser le formulaire par défaut seul. (Et même dans ce cas, il serait préférable, si possible, pour obtenir l'application défectueuse fixe à la place.)

Cela dit, vous pouvez définir manuellement le préfixe du XmlElement qui est retourné par SignedXml.GetXml () et ses éléments enfants en utilisant XPath comme ceci:

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

Autres conseils

Il ne peut pas être fait. Si vous modifiez le XML après qu'il a été signé il peut ne pas être en mesure de vérifier, ce qui était le cas dans l'exemple ci-dessus. OMI, est une faille dans la mise en œuvre de la signature numérique MSFT que vous devrez vivre avec.

Beaucoup de gens vont dire qu'il n'y a pas de raison de le faire, et ils sont techniquement corrects. Mais quand vous avez affaire à un grand fournisseur (à savoir un gouvernement ou d'une banque d'Etat), bonne chance de les amener à changer leur fin. La plupart des implémentations de référence de l'inclure.

Mise à jour: Les signes de signature tout dans l'élément SignedInfo, donc si vous allez mettre à jour cet élément après le fait, la signature n'est plus valide. Vous avez "falsifié" avec le message.

Il peut être fait, mais il est nécessaire de modifier la classe SignedXml pour ajouter le préfixe avant d'obtenir la valeur digest du nœud SignedInfo.

La méthode ComputeSignature sera modifier pour ajouter le paramètre préfixe

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

Lorsque cette méthode est appelée, elle calcule la valeur de signature en digérant la valeur du nœud SignedInfo, si vous obtenez cette valeur sans le préfixe « ds », puis ajoutez le préfixe, vous obtiendrez une signature non valide, donc vous devrez ajouter le préfixe avant d'obtenir la valeur digest du noeud SignedInfo.

Cette valeur est générée dans la digestion de la méthode GetC14NDigest, cette méthode sera modifier pour ajouter le paramètre de préfixe et ajouter le préfixe avant d'obtenir la valeur 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, donc maintenant vous avez la valeur de signature des noeuds SignedInfo avec le préfixe « ds », cela dit vous encore ne pas avoir le xml avec le préfixe encore, donc si vous appelez simplement la méthode GetXml vous obtiendrez le code XML sans le préfixe et bien sûr parce que la valeur de signature a été calculée en tenant compte du préfixe ds, vous aurez une signature non valide. Pour éviter cela et d'obtenir la structure xml avec le préfixe que vous devez modifier la méthode de GetXml, ajoutez le paramètre de préfixe et appeler la méthode setPrefix Wich ajoutera le préfixe « ds » à tous les noeuds dans la signature Xml

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

Je laisse ici la classe avec ces modifications

CLASSE CUSTOM

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

Et la façon de l'utiliser

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");
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top