Firmare digitalmente un documento XML

di Cristian Civera, in UserScript, ASP.NET, C#,

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.

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

I più letti di oggi