verifica manuale di XML Signature
-
08-10-2019 - |
Domanda
che posso fare con successo la validazione di riferimento manuale (canonicalize ogni elemento di riferimento -> SHA1 -> Base64 -> verifica se è la stessa del contenuto DigestValue) ma non con la verifica della SignatureValue. Ecco il SignedInfo per canonicalize e hash:
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:CanonicalizationMethod>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
<ds:Reference URI="#element-1-1291739860070-11803898">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>d2cIarD4atw3HFADamfO9YTKkKs=</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#timestamp">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
<ds:DigestValue>YR/fZlwJdw+KbyP24UYiyDv8/Dc=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
Ater rimuovendo tutti gli spazi tra i tag (e in modo da ottenere l'intero elemento su una sola riga), ottengo questo digest SHA1 (in Base64):
6l26iBH7il / yrCQW6eEfv / VqAVo =
Ora mi aspetto di trovare lo stesso digest dopo la decifratura del contenuto SignatureValue, ma ho un differente e più Valore:
MCEwCQYFKw4DAhoFAAQU3M24VwKG02yUu6jlEH + u6R4N8Ig =
Ecco un po 'di codice java per l'decyption:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(new File(inputFilePath));
NodeList nl = doc.getElementsByTagName("ds:SignatureValue");
if (nl.getLength() == 0) {
throw new Exception("Cannot find SignatureValue element");
}
String signature = "OZg96GMrGh0cEwbpHwv3KDhFtFcnzPxbwp9Xv0pgw8Mr9+NIjRlg/G1OyIZ3SdcOYqqzF4/TVLDi5VclwnjBAFl3SEdkyUbbjXVAGkSsxPQcC4un9UYcecESETlAgV8UrHV3zTrjAWQvDg/YBKveoH90FIhfAthslqeFu3h9U20=";
X509Certificate cert = X509Certificate.getInstance(new FileInputStream(<a file path>));
PublicKey pubkey = cert.getPublicKey();
Cipher cipher = Cipher.getInstance("RSA","SunJCE");
cipher.init(Cipher.DECRYPT_MODE, pubkey);
byte[] decodedSignature = Base64Coder.decode(signature);
cipher.update(decodedSignature);
byte[] sha1 = cipher.doFinal();
System.out.println(Base64Coder.encode(sha1));
La cosa che mi confonde tanto è che i due digest hanno dimensioni diverse, ma naturalmente ho anche bisogno di ottenere esattamente lo stesso valore dei due calcoli. Eventuali suggerimenti? Grazie.
Soluzione
MCEwCQYFKw4DAhoFAAQU3M24VwKG02yUu6jlEH+u6R4N8Ig=
è Base64 codifica per una struttura ASN.1 DER-codificato: un SEQUENCE
contenente primo un AlgorithmIdentifier
(che afferma che questa è SHA-1, senza parametri da SHA-1 accetta nessuno), quindi un OCTET STRING
che contiene la effettivo valore di 20 byte. In esadecimale, il valore è: dccdb8570286d36c94bba8e5107faee91e0df088
Questa struttura ASN.1 è parte dello standard RSA firma meccanismo. Si utilizza RSA decrittazione per l'accesso che la struttura, che è non-standard. Siete realmente fortunati ad avere qualcosa a tutti, dal momento che RSA crittografia e firma RSA sono due algoritmi distinti. Si dà il caso che entrambi nutrono lo stesso tipo di coppie di chiavi, e che il "vecchio stile" (alias "PKCS # 1 v1.5") schemi di firma e cifratura utilizzano tecniche di padding simili (simile ma non identico, ma è già un po 'sorprendente che l'implementazione Java di RSA non soffocare sul padding firma quando utilizzato in modalità decrittazione).
Comunque, 6l26iBH7il/yrCQW6eEfv/VqAVo=
è Base64 codifica per un valore di 20 byte, che, in esadecimale, è: ea5dba8811fb8a5ff2ac2416e9e11fbff56a015a
. Questo è ciò che si ottiene dal hashing la struttura XML si mostra sopra, dopo aver tolto tutti gli spazi tra i tag. Rimuovere tutti gli spazi è non corretta canonica. In realtà, per quanto ne so, spazi bianchi è influenzato solo tra gli attributi, all'interno dei tag, ma gli spazi esterni deve essere mantenuto invariato (ad eccezione di linea che termina la normalizzazione [la cosa LF / CR + LF]).
Il valore che è stato utilizzato per la generazione della firma (la dccdb85...
) può essere ottenuto utilizzando l'oggetto XML si mostra e rimuovendo gli spazi iniziali. Per essere chiari: si copia + incolla l'XML in un file, quindi rimuovere gli spazi iniziali (da 0 a 3 spazi) su ogni riga. È assicurarsi che tutte le linee di fine utilizzano un singolo LF (0x0A byte) e si rimuove la LF finale (quella appena dopo </ds:SignedInfo>
). Il file risultante deve avere lunghezza 930 byte, e il suo hash SHA-1 è il valore dccdb85...
atteso.
Altri suggerimenti
Guardando il vostro particolare di token XML, vi posso dire alcune cose.
-
Si utilizza il metodo di canonizzazione XML Exclusive Canonicalization Versione 1.0 . Questo è un Importante fattore nel garantire che si produce il diritto digerire i valori e la firma.
-
Si utilizza lo stesso metodo di canonizzazione sia per calcolare i digest di riferimento, e per canonicalizing la SignedInfo prima di produrre la firma.
La specifica per l'Exclusive XML Canonicalizaiton versione 1.0 è prodotto da W3C e può essere trovato alla sua rispettiva W3C raccomandazione . Se si Computing vostri valori manualmente, essere sicuri che si sono conformi esattamente alle specifiche, a causa canonica è una cosa difficile da ottenere di destra, ed è molto importante fare questo in modo corretto, altrimenti i valori non saranno corretti.
Ho appena scritto un lungo articolo che descrive il processo di validazione XML Signature. L'articolo è situato alla il mio blog . Esso descrive il processo in modo molto più dettagliato di quanto la mia risposta, in quanto vi sono molte complessità di XML Signature. Esso contiene inoltre collegamenti alle specifiche prevalenti e RFC.