#594 - Firmare digitalmente un documento XML

XML è un linguaggio molto comodo che si sta diffondendo sempre di più per contenere e rappresentare dati, dato che i documenti di questo tipo possono contenere anche informazioni che devono mantenere una integrità ed avere la possibilità di rilevare il cambiamento anche di un solo carattere.
Il W3C ha creato perciò uno standard volto a firmare documenti XML che prende il nome di XML Digital Segnature (XMLDSIG).
Una firma digitale consiste nel calcolare un digest, il risultato di un'operazione matematica della quale è impossibile fare l'operazione inversa, su un documento, criptarlo mediante un algoritmo con chiave asimmetrica (chiave private per criptare) e unire il documento XML con la rappresentazione della firma.
In questo modo chi vuole validare la firma andrà a calcolare a sua volta il digest del documento XML originale presunto e lo confronterà con il digest decriptato con la chiave pubblica. Se combaciano il documento è integro.
Il .NET Framework dispone di un insieme di classi per supportare XMLDSIG che sono contenute nel namespace System.Security.Cryptography.Xml (in unione con System.Security.Cryptography per la crittografia) dell'assembly System.Security.

Lo script proposto preleva un file XML tramite upload e restituisce il documento firmato:

// Carico il documento XML

XmlDocument doc = new XmlDocument();
doc.Load(xmlFile.PostedFile.InputStream);
 
// Elimino il nodo di dichiarazione xml (<?xml..

foreach (XmlNode n in doc.ChildNodes)
  if (n.NodeType == XmlNodeType.XmlDeclaration)
    doc.RemoveChild(n);

// Creo l'oggetto per firmare

SignedXml xs = new SignedXml();

// Creo un object con la lista degli XmlNode da firmare

// in questo caso il DocumentElement

DataObject data = new DataObject();
data.Data = doc.ChildNodes;
data.Id = "MyDocId";

// Lo aggiungo alla lista di oggetti da firmare

xs.AddObject(data);

// Indico che gli algoritmi RSA devono memorizzare

// le chiavi sulla macchina

RSACryptoServiceProvider.UseMachineKeyStore = true;

// Creo un algoritmo RSA per criptare il digest

RSA key = new RSACryptoServiceProvider();

// Indico di usare questo algoritmo

xs.SigningKey = key;

// Creo una KeyInfo sulla base dell'algoritmo

// per infomare il tipo di criptazione utilizzata

// e mostrare la chiave pubblica

KeyInfo ki = new KeyInfo();
RSAKeyValue rsa = new RSAKeyValue(key);
ki.AddClause(rsa);
xs.KeyInfo = ki;

// Aggiungo la reference al mio oggetto

// con lo stesso Uri dell'Id

Reference r = new Reference();
r.Uri = "#MyDocId";
xs.AddReference(r);

// Calcolo la firma

xs.ComputeSignature();

// Mando in output l'xml risultante

Response.Clear();
Response.ContentType = "text/xml";
Response.Write(xs.GetXml().OuterXml);
Response.End();

Il codice è ben commentato. Nell'esempio viene usato l'algoritmo RSA e le chiavi sono depositate nella macchina. Il risultato è una root Signature contenente le informazioni sul digest e la chiave pubblica per effettuare la decryption.

Nota: Questo script contiene un allegato.


Approfondimenti

Commenti

Esprimi il tuo giudizio su questo script:

Per procedere devi essere autenticato.

Aggiungi un nuovo commento »»»
Per inserire un commento, devi registrarti alla nostra community.




IN EVIDENZA
MISC