2012-05-11 138 views
8

Abbiamo scritto un sistema di gestione dei documenti e vorremmo firmare digitalmente i documenti utilizzando il client web. La nostra applicazione client Java è già in grado di applicare e controllare la firma digitale, ma vorremmo fare una firma anche con il nostro client web. Questo è scritto in GWT e quindi, quando viene eseguito dal lato client, è un'applicazione JavaScript.Come creare una firma digitale in un'applicazione Web (JavaScript) utilizzando una smartcard?

Non vogliamo creare un'applet Java e scaricarlo sul client ed eseguirlo. Vorremmo utilizzare il dispositivo di sicurezza del browser o l'API del browser per firmare un documento. Vorremmo anche mantenere il lato server del documento completo e spostare sul client solo l'hash del documento.

riteniamo che questo dovrebbe essere possibile utilizzare NSS o NPAPI/NPRuntime, ma non abbiamo trovato informazioni su questo. (A proposito, npruntime è disponibile anche in IE? Dovremmo usare ActiveX per ottenere lo stesso risultato con IE?)

Hai qualche suggerimento?

risposta

9

Dopo un po 'di ricerca su google ho trovato la risposta. Mozilla esporta parte del suo modulo NSS tramite l'oggetto window.crypto. Un modo più standard per eseguire tale operazione è probabilmente tramite DOMCrypt, che è attualmente discusses in W3C. Lo sviluppatore di Google Chrome aspetterà W3C per standardizzare DOMCrypt, mentre Microsoft richiede l'uso di un oggetto ActiveX as explained here (funziona anche con Firefox/Chrome/Opera su Windows).

+0

* Il collegamento a DOMCrypt * non è quello che dovrebbe essere. – ares

+0

Grazie a @ares, il DNS di DOMcrypt.org sembra essere assegnato a un proprietario diverso ora. Ho cambiato il link a una pagina diversa con contenuti molto simili. – eppesuig

+0

window.crypto non è stato [rimosso] (https://wiki.mozilla.org/SecurityEngineering/Removing_Proprietary_window.crypto_Functions) dopo Firefox 33? – marcellorvalle

0

In Win/IE è ancora possibile utilizzare CAPICOM http://en.wikipedia.org/wiki/CAPICOM senza ActiveX di terze parti o librerie esterne.
Questo funziona ovunque sia installato IE.
Tuttavia, si sta ritirando.

Di seguito è riportato ciò che sto utilizzando per accedere a IE. Lo chiamo con ad esempio: var signature = signDigest (stringToBeSigned);

function signDigest(text) { 
if (window.event) 
    window.event.cancelBubble = true; 

var dest = sign(text); //TODO 

return dest; 
} 

// CAPICOM constants 

var CAPICOM_STORE_OPEN_READ_ONLY = 0; 
var CAPICOM_CURRENT_USER_STORE = 2; 
var CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0; 
var CAPICOM_CERTIFICATE_FIND_EXTENDED_PROPERTY = 6; 
var CAPICOM_CERTIFICATE_FIND_TIME_VALID = 9; 
var CAPICOM_CERTIFICATE_FIND_KEY_USAGE = 12; 
var CAPICOM_DIGITAL_SIGNATURE_KEY_USAGE = 0x00000080; 
var CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0; 
var CAPICOM_INFO_SUBJECT_SIMPLE_NAME = 0; 
var CAPICOM_ENCODE_BASE64 = 0; 
var CAPICOM_E_CANCELLED = -2138568446; 
var CERT_KEY_SPEC_PROP_ID = 6; 

function IsCAPICOMInstalled() { 
    if (typeof (oCAPICOM) == "object") { 
     if ((oCAPICOM.object != null)) { 
      // We found CAPICOM! 
      return true; 
     } 
    } 
} 

function FindCertificateByHash() { 

    try { 
     // instantiate the CAPICOM objects 
     var MyStore = new ActiveXObject("CAPICOM.Store"); 
     // open the current users personal certificate store 
     MyStore.Open(CAPICOM_CURRENT_USER_STORE, "My", CAPICOM_STORE_OPEN_READ_ONLY); 

     // find all of the certificates that have the specified hash 
     var FilteredCertificates = MyStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, strUserCertigicateThumbprint); 

     var Signer = new ActiveXObject("CAPICOM.Signer"); 
     Signer.Certificate = FilteredCertificates.Item(1); 
     return Signer; 

     // Clean Up 
     MyStore = null; 
     FilteredCertificates = null; 
    } 
    catch (e) { 
     if (e.number != CAPICOM_E_CANCELLED) { 
      return new ActiveXObject("CAPICOM.Signer"); 
     } 
    } 
} 

function sign(src) { 
    if (window.crypto && window.crypto.signText) 
     return sign_NS(src); 
    else 

     return sign_IE(src); 
} 

function sign_NS(src) { 
    var s = crypto.signText(src, "ask"); 
    return s; 
} 

function sign_IE(src) { 
    try { 
     // instantiate the CAPICOM objects 
     var SignedData = new ActiveXObject("CAPICOM.SignedData"); 
     var TimeAttribute = new ActiveXObject("CAPICOM.Attribute"); 

     // Set the data that we want to sign 
     SignedData.Content = src; 
     var Signer = FindCertificateByHash(); 


     // Set the time in which we are applying the signature 
     var Today = new Date(); 
     TimeAttribute.Name = CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME; 
     TimeAttribute.Value = Today.getVarDate(); 
     Today = null; 
     Signer.AuthenticatedAttributes.Add(TimeAttribute); 

     // Do the Sign operation 
     var szSignature = SignedData.Sign(Signer, true, CAPICOM_ENCODE_BASE64); 
     return szSignature; 
    } 
    catch (e) { 
     if (e.number != CAPICOM_E_CANCELLED) { 
      alert("An error occurred when attempting to sign the content, the error was: " + e.description); 
     } 
    } 
    return ""; 
} 

ho avuto alcuni problemi con la codifica, ecc, quindi ho incluso il mio controller (.net), nonché

 byte[] decbuff = Convert.FromBase64String(signature); 


    //CAPICOM USES 16 BIT ENCODING 
    Encoding utf16Enc = Encoding.GetEncoding("UTF-16LE"); 


    byte[] utf16Data = utf16Enc.GetBytes(getContent); 


    ContentInfo content = new ContentInfo(utf16Data); 

    System.Security.Cryptography.Pkcs.SignedCms cms = new System.Security.Cryptography.Pkcs.SignedCms(content,true); 
    cms.Decode(decbuff); 

    int length = decbuff.Length;   

    X509Certificate2 cert = cms.SignerInfos[0].Certificate; 


    X509Chain chain = new X509Chain(); 
    bool theVal = chain.Build(cert); 
    cms.CheckHash();  
    cms.CheckSignature(false); 
+0

Sto anche utilizzando CAPICOM per firmare xml con il segno X509Certificate2. Quando scelgo un certificato dal negozio, non mi chiede dopo di inserire nome utente e password per quel certificato. È la stessa situazione e con il tuo codice sopra? – SeaSide

+0

Solo a volte se è "incasinato" - chiudo il browser, apro e chiede le credenziali. Ogni tanto ottengo un punto in cui smette di chiedere, ma ricaricare il browser sembra sempre risolvere questo problema. – Yablargo

-1

Ora è possibile farlo. Le applicazioni Web basate su smart card o token PKCS # 11 possono essere implementate utilizzando la versione Silverlight di NCryptoki. Vedere http://www.ncryptoki.com

Hai due chanches:

1) utilizzando la versione di Silverlight di NCryptoki e sviluppare il proprio controllo utente Silverlight che implementa la logica, una firma digitale nel tuo caso, utilizzando PKCS # 11 funzioni forniti dal smart card

2) utilizzando il plugin jQuery basata sulla versione di Silverlight sopra e implementare l'applicazione in JavaScript chiamando i PKCS # 11 funzioni in JavaScript

Inoltre, è possibile utilizzare la versione di Silverlight di NDigitSign (vedi di nuovo http://www.ncryptoki.com) questo fa tutto il necessario e può essere implementato in qualsiasi browser web.

+0

Grazie per aver segnalato questa soluzione. Non ero a conoscenza del progetto ncryptoki, ma dal momento che è basato su Silverlight, richiede ancora il software di installazione sul computer client (come per l'applet Java) e, cosa più importante, probabilmente funzionerebbe solo su macchine Windows. Infine, ciò richiederebbe di scrivere un'applicazione che usi direttamente PKCS # 11, e vorrei davvero evitare questo programma. – eppesuig

4

Attualmente (maggio 2016) non è possibile.

Chrome ha abbandonato il supporto Java. 'Bordo Windows' non avrà. Il supporto di IE11 è negativo e Oracle ha deciso di interrompere il plugin java. Sarebbe possibile solo con Firefox, versioni precedenti di IE e il plugin Java.

Il nuovo standard WebCryptographyApi fornisce il supporto della firma digitale per i browser, ma non ha PCKS # 11 di supporto

soluzione

reale di e-goverment per risolvere questo: 1) Installare un'applicazione Java locale sul PC dell'utente. L'applicazione è in ascolto su una porta come, ad esempio 5678 2) Nella tua pagina, javascript rileva se esiste il supporto per le applet 3) Se non c'è supporto, si connette all'applicazione nel modulo http://127.0.01:5678/sign e invia i dati da firmare. 4) La domanda è locale e non ha avuto problemi con l'archivio di chiavi sistema operativo, che include i driver PKCS # 11. Fai la firma digitale e prepara il risultato 5) pagina javascript interrogare periodicamente il risultato e recupera quando pronto

+0

Le applet Java possono essere avviate tramite Java Web Start. Funziona su tutti i browser desktop, anche se è necessario un ulteriore sforzo. –

+0

C'è una soluzione in Spagna nell'e-government per risolvere questo problema. Lo documenterò nella risposta – pedrofb

0

One progetto che sono stato coinvolto con fatto con Chrome e Native Messaging:

https://github.com/CACBridge/ChromeCAC

Ciò richiede l'installazione del plugin Chrome, ma per il resto funziona alla grande. Ideale per es. Intranet/ambienti di gruppo in cui sai che dovrai farlo in anticipo.