Procedura: verificare le firme digitali dei documenti XML
È possibile usare le classi nello spazio dei nomi System.Security.Cryptography.Xml per verificare i dati XML firmati con una firma digitale. Le firme digitali XML (XMLDSIG) consentono di verificare che i dati non siano stati alterati dopo la firma. Per altre informazioni sullo standard XMLDSIG, vedere la specifica World Wide Web Consortium (W3C) all'indirizzo https://www.w3.org/TR/xmldsig-core/.
Nota
Il codice in questo articolo fa riferimento a Windows.
L'esempio di codice nella procedura mostra come verificare una firma digitale XML contenuta in un elemento <Signature
>. L'esempio recupera una chiave pubblica RSA da un contenitore di chiavi, quindi usa la chiave per verificare la firma.
Per informazioni su come creare una firma digitale verificabile con questa tecnica, vedere Procedura: Firmare documenti XML con firme digitali.
Per verificare la firma digitale di un documento XML
Per verificare il documento, è necessario usare la stessa chiave asimmetrica usata per la firma. Creare un oggetto CspParameters e specificare il nome del contenitore di chiavi usato per la firma.
CspParameters cspParams = new() { KeyContainerName = "XML_DSIG_RSA_KEY" };
Dim cspParams As New CspParameters() cspParams.KeyContainerName = "XML_DSIG_RSA_KEY"
Recuperare la chiave pubblica usando la classe RSACryptoServiceProvider. La chiave viene caricata automaticamente dal contenitore di chiavi in base al nome quando si passa l'oggetto CspParameters al costruttore della classe RSACryptoServiceProvider.
RSACryptoServiceProvider rsaKey = new(cspParams);
Dim rsaKey As New RSACryptoServiceProvider(cspParams)
Creare un oggetto XmlDocument caricando un file XML dal disco. L'oggetto XmlDocument contiene il documento XML firmato da verificare.
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")
Creare un nuovo oggetto SignedXml e passare a esso l'oggetto XmlDocument.
SignedXml signedXml = new(xmlDoc);
Dim signedXml As New SignedXml(xmlDoc)
Trovare l'elemento <
signature
> e creare un nuovo oggetto XmlNodeList.XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");
Dim nodeList As XmlNodeList = xmlDoc.GetElementsByTagName("Signature")
Caricare i dati XML del primo elemento <
signature
> nell'oggetto SignedXml.signedXml.LoadXml((XmlElement?)nodeList[0]);
signedXml.LoadXml(CType(nodeList(0), XmlElement))
Controllare la firma usando il metodo CheckSignature e la chiave pubblica RSA. Il metodo restituisce un valore booleano che indica l'esito positivo o negativo.
return signedXml.CheckSignature(key);
Return signedXml.CheckSignature(key)
Esempio
Questo esempio presuppone che sia presente un file denominato "test.xml"
nella stessa directory del programma compilato Il file "test.xml"
deve essere firmato usando le tecniche descritte in Procedura: Firmare documenti XML con firme digitali.
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
Compilazione del codice
In un progetto destinato a .NET Framework includere un riferimento a
System.Security.dll
.In un progetto destinato a .NET Core o .NET 5 installare il pacchetto NuGet System.Security.Cryptography.Xml.
Includere gli spazi dei nomi seguenti: System.Xml, System.Security.Cryptography e System.Security.Cryptography.Xml.
Sicurezza .NET
Non archiviare né trasferire mai in testo non crittografato la chiave privata di una coppia di chiavi asimmetriche. Per altre informazioni sulle chiavi crittografiche simmetriche e asimmetriche, vedere Generazione di chiavi per crittografia e decrittografia.
Non incorporare mai una chiave privata direttamente nel codice sorgente. Le chiavi incorporate possono essere lette facilmente da un assembly mediante Ildasm.exe (IL Disassembler) oppure aprendo l'assembly in un editor di testo quale Blocco note.