2010-12-11 22 views
8

Posso eseguire correttamente la convalida del riferimento manuale (canonicalizzare ogni elemento di riferimento -> SHA1 -> Base64 -> verificare se è lo stesso del contenuto di DigestValue) ma non riesco con la verifica di SignatureValue. Ecco il SignedInfo per canonicalize e hash:Verifica manuale della firma XML

<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:

MCEwCQYFKw4DAhoFAAQ U3M24VwKG02yUu6jlEH + u6R4N8Ig =

Ecco 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 dai due calcoli. Eventuali suggerimenti? Grazie.

+0

"Ater rimuove tutti gli spazi tra i tag" ... è giusto? Guardando http://www.w3.org/TR/2001/REC-xml-c14n-20010315#Example-WhitespaceInContent sembra che tu stia rimuovendo troppo spazio bianco. –

+0

Grazie per la risposta. Capisco il tuo punto ma, come ho detto all'inizio della domanda, posso fare validamente riferimento alla validazione (due riferimenti, non può essere un incidente) dello stesso messaggio SOAP e solo rimuovendo quegli spazi, quindi devo assumere è giusto. – Johnca

+0

La Canonizzazione è molto più che rimuovere gli spazi bianchi. Gestisce i problemi del prefisso dello spazio dei nomi, l'ordinamento degli attributi e in generale tutto ciò che modifica l'ordine dei byte del file phisicaly (e quindi il digest dell'hash), ma non modifica l'infoset XML (== il significato del payload dell'XML) – m0sa

risposta

8

MCEwCQYFKw4DAhoFAAQU3M24VwKG02yUu6jlEH+u6R4N8Ig= è codifica Base64 per una struttura ASN.1 DER-encoded: un SEQUENCE contenente primo un AlgorithmIdentifier (che indica che questo è SHA-1, senza parametri dal SHA-1 accetta nessuno), quindi un OCTET STRING che contiene il valore effettivo a 20 byte. In esadecimale, il valore è: dccdb8570286d36c94bba8e5107faee91e0df088.

Questa struttura ASN.1 fa parte del meccanismo standard RSA signature. Si utilizza RSA decrittografia per accedere a tale struttura, che non è standard. Sei davvero fortunato ad ottenere qualsiasi cosa, dal crittografia RSA e firma RSA sono due algoritmi distinti. Accade così che entrambi si nutrano dello stesso tipo di coppie di chiavi e che gli schemi di firma e crittografia "vecchio stile" (ovvero "PKCS # 1 v1.5") utilizzino tecniche di riempimento simili (simili ma non identiche; già un po 'sorprendente che l'implementazione di Java di RSA non ha soffocato sul riempimento della firma quando usato in modalità decrittografia).

In ogni caso, 6l26iBH7il/yrCQW6eEfv/VqAVo= è la codifica Base64 per un valore di 20 byte, che in esadecimale è: ea5dba8811fb8a5ff2ac2416e9e11fbff56a015a. Questo è ciò che ottieni tagliando la struttura XML che mostri sopra, dopo aver rimosso tutti gli spazi bianchi tra i tag. La rimozione di tutti gli spazi vuoti è non canonicalizzazione corretta. In realtà, per quanto ne so, lo spazio bianco è influenzato solo tra gli attributi, all'interno dei tag, ma lo spazio bianco esterno deve essere mantenuto invariato (tranne per la normalizzazione di fine riga [la cosa LF/CR + LF]).

Il valore utilizzato per la generazione della firma (dccdb85...) può essere ottenuto utilizzando l'oggetto XML visualizzato e rimuovendo gli spazi iniziali. Per essere chiari: copia + incolla l'XML in un file, quindi rimuovi gli spazi iniziali (da 0 a 3 spazi) su ogni riga. Assicurati che tutti i fine linea utilizzino un singolo LF (byte 0x0A) e rimuovi l'ultimo LF (quello immediatamente dopo </ds:SignedInfo>). Il file risultante deve avere una lunghezza di 930 byte e il suo hash SHA-1 è il valore dccdb85... previsto.

+0

GRAZIE per la risposta chiara e risolvente !!! Da dove viene l'idea di "rimuovere spazi iniziali"? In ogni caso mi chiedo perché org.apache.xml.security .c14n.Canonicalizer non li rimuove e perché ho bisogno di due diverse rappresentazioni xml per le due attività: per la validazione di riferimento devo rimuovere tutti gli spazi tra tag mentre per la convalida della firma devo fare quello che hai scritto. il messaggio xml è stato inviato da un servlet distribuito JBoss e ricevuto da un servizio Web JBoss. Forse JBoss esegue lavori non standard? – Johnca

+0

Ho visto "rimuovere gli spazi iniziali" su una pagina Web che tenta di spiegare la canonicalizzazione (non ricordo La canonicalizzazione mantiene inalterato il contenuto del testo, compresi gli spazi (il canonizzatore di Apache è corretto nel non rimuoverli). Poiché gli spazi sono fastidiosi, è _consigliato_ creare inizialmente l'XML senza ny indentation (cioè nessuno spazio principale). La mia ipotesi è che l'XML originale non avesse gli spazi iniziali, e sono stati aggiunti ad un certo punto (_after_ signature computation) come "helper di lettura" (che mette a disagio la firma). –

0

Guardando il tuo particolare token XML, posso dirti alcune cose.

  • Si utilizza il metodo di canonizzazione XML Esclusivo canonica versione 1.0. Si tratta di un fattore molto IMPORTANTE nel garantire che si producano i valori e la firma corretti.

  • Si utilizza lo stesso metodo di canonizzazione sia per calcolare i digest di riferimento, e per la canonicalizing 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 Recommendation. Se stai calcolando i tuoi valori manualmente, assicurati di conformarti esattamente alle specifiche, perché la canonicalizzazione è una cosa difficile da correggere, ed è molto importante farlo correttamente, altrimenti i tuoi valori saranno errati.

Ho appena scritto un ampio articolo che descrive il processo di convalida della firma XML. L'articolo si trova a my blog. Descrive il processo in modo molto più dettagliato rispetto alla mia risposta, poiché ci sono molte complicazioni in XML Signature. Contiene anche collegamenti a specifiche prevalenti e RFC.