Procédure : vérifier les signatures numériques de documents XML

Vous pouvez utiliser les classes de l'espace de noms System.Security.Cryptography.Xml pour vérifier les données XML signées avec une signature numérique. Les signatures numériques XML (XMLDSIG) vous permettent de vérifier que les données n'ont pas été modifiées après leur signature. Pour plus d’informations sur la norme XMLDSIG, consultez la spécification W3C (World Wide Web Consortium) à l’adresse https://www.w3.org/TR/xmldsig-core/.

Notes

Le code de cet article s’applique à Windows.

L'exemple de code de cette procédure montre comment vérifier une signature numérique XML contenue dans un élément <Signature>. L'exemple récupère une clé publique RSA d'un conteneur de clé, puis utilise cette clé pour vérifier la signature.

Pour plus d'informations sur la création d'une signature numérique qui peut être vérifiée à l'aide de cette technique, consultez Comment : signer des documents XML avec des signatures numériques.

Pour vérifier la signature numérique d'un document XML

  1. Pour vérifier le document, vous devez utiliser la même clé asymétrique que celle utilisée pour la signature. Créez un objet CspParameters et spécifiez le nom du conteneur de clé qui a été utilisé pour la signature.

    CspParameters cspParams = new()
    {
        KeyContainerName = "XML_DSIG_RSA_KEY"
    };
    
    Dim cspParams As New CspParameters()
    cspParams.KeyContainerName = "XML_DSIG_RSA_KEY"
    
  2. Récupérez la clé publique à l'aide de la classe RSACryptoServiceProvider. La clé est automatiquement chargée depuis le conteneur de clé quand vous passez l'objet CspParameters au constructeur de la classe RSACryptoServiceProvider.

    RSACryptoServiceProvider rsaKey = new(cspParams);
    
    Dim rsaKey As New RSACryptoServiceProvider(cspParams)
    
  3. Créez un objet XmlDocument en chargeant un fichier XML à partir du disque. L'objet XmlDocument contient le document XML signé à vérifier.

    XmlDocument xmlDoc = new()
    {
        // Load an XML file into the XmlDocument object.
        PreserveWhitespace = true
    };
    xmlDoc.Load("test.xml");
    
    Dim xmlDoc As New XmlDocument()
    
    ' Load an XML file into the XmlDocument object.
    xmlDoc.PreserveWhitespace = True
    xmlDoc.Load("test.xml")
    
  4. Créez un objet SignedXml et passez-lui l'objet XmlDocument.

    SignedXml signedXml = new(xmlDoc);
    
    Dim signedXml As New SignedXml(xmlDoc)
    
  5. Recherchez l’élément <signature> et créez un nouvel objet XmlNodeList.

    XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");
    
    Dim nodeList As XmlNodeList = xmlDoc.GetElementsByTagName("Signature")
    
  6. Chargez le code XML du premier élément <signature> dans l’objet SignedXml.

    signedXml.LoadXml((XmlElement?)nodeList[0]);
    
    signedXml.LoadXml(CType(nodeList(0), XmlElement))
    
  7. Vérifiez la signature à l'aide de la méthode CheckSignature et de la clé publique RSA. Cette méthode retourne une valeur booléenne qui indique la réussite ou l'échec.

    return signedXml.CheckSignature(key);
    
    Return signedXml.CheckSignature(key)
    

Exemple

Cet exemple suppose qu'un fichier nommé "test.xml" se trouve dans le même répertoire que le programme compilé. Le fichier "test.xml" doit être signé à l'aide des techniques décrites dans Comment : signer des documents XML avec des signatures numériques.

using System;
using System.Runtime.Versioning;
using System.Security.Cryptography;
using System.Security.Cryptography.Xml;
using System.Xml;

[SupportedOSPlatform("Windows")]
public class VerifyXML
{
    public static void Main(string[] args)
    {
        try
        {
            // Create a new CspParameters object to specify
            // a key container.
            CspParameters cspParams = new()
            {
                KeyContainerName = "XML_DSIG_RSA_KEY"
            };

            // Create a new RSA signing key and save it in the container.
            RSACryptoServiceProvider rsaKey = new(cspParams);

            // Create a new XML document.
            XmlDocument xmlDoc = new()
            {
                // Load an XML file into the XmlDocument object.
                PreserveWhitespace = true
            };
            xmlDoc.Load("test.xml");

            // Verify the signature of the signed XML.
            Console.WriteLine("Verifying signature...");
            bool result = VerifyXml(xmlDoc, rsaKey);

            // Display the results of the signature verification to
            // the console.
            if (result)
            {
                Console.WriteLine("The XML signature is valid.");
            }
            else
            {
                Console.WriteLine("The XML signature is not valid.");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    // Verify the signature of an XML file against an asymmetric
    // algorithm and return the result.
    public static bool VerifyXml(XmlDocument xmlDoc, RSA key)
    {
        // Check arguments.
        if (xmlDoc == null)
             throw new ArgumentException(null, nameof(xmlDoc));
        if (key == null)
            throw new ArgumentException(null, nameof(key));

        // Create a new SignedXml object and pass it
        // the XML document class.
        SignedXml signedXml = new(xmlDoc);

        // Find the "Signature" node and create a new
        // XmlNodeList object.
        XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");

        // Throw an exception if no signature was found.
        if (nodeList.Count <= 0)
        {
            throw new CryptographicException("Verification failed: No Signature was found in the document.");
        }

        // This example only supports one signature for
        // the entire XML document.  Throw an exception
        // if more than one signature was found.
        if (nodeList.Count >= 2)
        {
            throw new CryptographicException("Verification failed: More that one signature was found for the document.");
        }

        // Load the first <signature> node.
        signedXml.LoadXml((XmlElement?)nodeList[0]);

        // Check the signature and return the result.
        return signedXml.CheckSignature(key);
    }
}
Imports System.Security.Cryptography
Imports System.Security.Cryptography.Xml
Imports System.Xml

Module VerifyXML
    Sub Main(ByVal args() As String)
        Try
            ' Create a new CspParameters object to specify
            ' a key container.
            Dim cspParams As New CspParameters()
            cspParams.KeyContainerName = "XML_DSIG_RSA_KEY"
            ' Create a new RSA signing key and save it in the container. 
            Dim rsaKey As New RSACryptoServiceProvider(cspParams)
            ' Create a new XML document.
            Dim xmlDoc As New XmlDocument()

            ' Load an XML file into the XmlDocument object.
            xmlDoc.PreserveWhitespace = True
            xmlDoc.Load("test.xml")
            ' Verify the signature of the signed XML.
            Console.WriteLine("Verifying signature...")
            Dim result As Boolean = VerifyXml(xmlDoc, rsaKey)

            ' Display the results of the signature verification to 
            ' the console.
            If result Then
                Console.WriteLine("The XML signature is valid.")
            Else
                Console.WriteLine("The XML signature is not valid.")
            End If

        Catch e As Exception
            Console.WriteLine(e.Message)
        End Try
    End Sub

    ' Verify the signature of an XML file against an asymmetric 
    ' algorithm and return the result.
    Function VerifyXml(ByVal xmlDoc As XmlDocument, ByVal key As RSA) As [Boolean]
        ' Check arguments.
        If xmlDoc Is Nothing Then
            Throw New ArgumentException(
                "The XML doc cannot be nothing.", NameOf(xmlDoc))
        End If
        If key Is Nothing Then
            Throw New ArgumentException(
                "The key cannot be nothing.", NameOf(key))
        End If
        ' Create a new SignedXml object and pass it
        ' the XML document class.
        Dim signedXml As New SignedXml(xmlDoc)
        ' Find the "Signature" node and create a new
        ' XmlNodeList object.
        Dim nodeList As XmlNodeList = xmlDoc.GetElementsByTagName("Signature")
        ' Throw an exception if no signature was found.
        If nodeList.Count <= 0 Then
            Throw New CryptographicException("Verification failed: No Signature was found in the document.")
        End If

        ' This example only supports one signature for
        ' the entire XML document.  Throw an exception 
        ' if more than one signature was found.
        If nodeList.Count >= 2 Then
            Throw New CryptographicException("Verification failed: More that one signature was found for the document.")
        End If

        ' Load the first <signature> node.  
        signedXml.LoadXml(CType(nodeList(0), XmlElement))
        ' Check the signature and return the result.
        Return signedXml.CheckSignature(key)
    End Function
End Module

Compilation du code

Sécurité .NET

La clé privée d'une paire de clés asymétriques ne doit jamais être stockée ni transférée en texte brut. Pour plus d’informations sur les clés de chiffrement symétriques et asymétriques, consultez Génération de clés pour le chiffrement et le déchiffrement.

N'incorporez jamais une clé privée directement dans votre code source. Les clés incorporées peuvent être lues facilement à partir d’un assembly à l’aide du Désassembleur IL (Ildasm.exe). Vous pouvez également, pour cela, ouvrir l’assembly dans un éditeur de texte tel que le Bloc-notes.

Voir aussi