Idioma

Como verificar as assinaturas digitais de documentos XML

Você pode usar as classes no System.Security.Cryptography.Xml namespace para verificar os dados XML assinados com uma assinatura digital. As assinaturas digitais XML (XMLDSIG) permitem verificar se os dados não foram alterados após a assinatura. Para obter mais informações sobre o padrão XMLDSIG, consulte a especificação W3C (World Wide Web Consortium) em https://www.w3.org/TR/xmldsig-core/.

Note

O código neste artigo se aplica ao Windows.

Importante

Sempre verifique as assinaturas XML usando uma sobrecarga de CheckSignature que recebe a chave de verificação ou o certificado como argumento, e obtenha essa chave ou certificado de uma fonte independente do documento assinado (por exemplo, um contêiner de chaves, conforme mostrado neste exemplo, a configuração do aplicativo ou um certificado associado ao aplicativo). Não use a sobrecarga sem parâmetros CheckSignature() para autenticar documentos de uma fonte não confiável, pois ela seleciona uma chave do elemento <KeyInfo> do próprio documento, que está sob o controle de quem o produziu; portanto, um resultado bem-sucedido não comprova que o signatário seja confiável. Para obter a lógica completa, consulte as Observações sobre SignedXml.

Importante

Uma SignedXml instância destina-se a uma única verificação. Não chame CheckSignature mais de uma vez na mesma instância e não reutilize uma instância que foi usada para assinatura. No .NET 12 e em versões posteriores, esses padrões geram InvalidOperationException; as versões anteriores do .NET não os bloqueiam, mas podem produzir resultados incorretos. Crie um novo SignedXml para cada verificação.

O exemplo de código neste procedimento demonstra como verificar uma assinatura digital XML contida em um <Signature> elemento. O exemplo recupera uma chave pública RSA de um contêiner de chave e usa a chave para verificar a assinatura.

Para obter informações sobre como criar uma assinatura digital que pode ser verificada usando essa técnica, consulte Como assinar documentos XML com assinaturas digitais.

Para verificar a assinatura digital de um documento XML

  1. Para verificar o documento, você deve usar a mesma chave assimétrica usada para assinatura. Crie um CspParameters objeto e especifique o nome do contêiner de chave que foi usado para assinatura.

    CspParameters cspParams = new()
    {
        KeyContainerName = "XML_DSIG_RSA_KEY"
    };
    
    Dim cspParams As New CspParameters()
    cspParams.KeyContainerName = "XML_DSIG_RSA_KEY"
    
  2. Recupere a chave pública usando a RSACryptoServiceProvider classe. A chave é carregada automaticamente do contêiner de chaves com base no nome quando você passa o objeto CspParameters para o construtor da classe RSACryptoServiceProvider.

    RSACryptoServiceProvider rsaKey = new(cspParams);
    
    Dim rsaKey As New RSACryptoServiceProvider(cspParams)
    
  3. Crie um XmlDocument objeto carregando um arquivo XML do disco. O XmlDocument objeto contém o documento XML assinado para verificar.

    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. Crie um novo SignedXml objeto e passe o XmlDocument objeto para ele.

    SignedXml signedXml = new(xmlDoc);
    
    Dim signedXml As New SignedXml(xmlDoc)
    
  5. Localize o <signature> elemento e crie um novo XmlNodeList objeto.

    XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");
    
    Dim nodeList As XmlNodeList = xmlDoc.GetElementsByTagName("Signature")
    
  6. Carregue o XML do primeiro <signature> elemento no SignedXml objeto.

    signedXml.LoadXml((XmlElement?)nodeList[0]);
    
    signedXml.LoadXml(CType(nodeList(0), XmlElement))
    
  7. Verifique a assinatura usando o CheckSignature método e a chave pública RSA. Esse método retorna um valor booliano que indica êxito ou falha.

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

Exemplo

Este exemplo pressupõe que exista um arquivo nomeado "test.xml" no mesmo diretório que o programa compilado. O "test.xml" arquivo deve ser assinado usando as técnicas descritas em How to: Sign XML Documents with Digital Signatures.

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

Compilando o código

Segurança do .NET

Nunca armazene ou transfira a chave privada de um par de chaves assimétricas em texto sem formatação. Para obter mais informações sobre chaves criptográficas simétricas e assimétricas, consulte Gerando chaves para criptografia e descriptografia.

Nunca insira uma chave privada diretamente no código-fonte. As chaves inseridas podem ser facilmente lidas de um assembly usando o Ildasm.exe (IL Disassembler) ou abrindo o assembly em um editor de texto, como o Bloco de Notas.

Consulte também