2012-05-11 54 views
8

Hemos escrito un sistema de gestión de documentos y nos gustaría firmar digitalmente documentos utilizando el cliente web. Nuestra aplicación de cliente Java ya puede aplicar y verificar la firma digital, pero nos gustaría hacer la firma incluso con nuestro cliente web. Esto está escrito en GWT y, por lo tanto, cuando se ejecuta en el lado del cliente, es una aplicación de JavaScript.¿Cómo hacer una firma digital en una aplicación web (JavaScript) usando una tarjeta inteligente?

No queremos crear un applet de Java y descargarlo en el cliente y ejecutarlo. Nos gustaría utilizar el dispositivo de seguridad del navegador o la API del navegador para firmar un documento. También nos gustaría mantener el lado del servidor de documentos completo, y mover al cliente solo el hash del documento.

Creemos que esto debería ser posible utilizando NSS o NPAPI/NPRuntime, pero no encontramos ninguna información sobre esto. (Por cierto, ¿está npruntime disponible también en IE? ¿Deberíamos usar ActiveX para lograr el mismo resultado con IE?)

¿Tiene alguna pista?

Respuesta

9

Después de buscar más en Google encontré la respuesta. Mozilla exporta parte de su módulo NSS a través del objeto window.crypto. Una forma más estándar de hacer tal operación es probablemente a través de DOMCrypt, que actualmente es discusses in W3C. El desarrollador de Google Chrome esperará W3C para estandarizar DOMCrypt, mientras que Microsoft requiere el uso de un objeto ActiveX as explained here (esto funciona incluso con Firefox/Chrome/Opera en Windows).

+0

* El enlace DOMCrypt * no es lo que se supone que es. – ares

+0

Gracias @ares, el DNS DOMcrypt.org parece estar asignado a un propietario diferente ahora. Cambié el enlace a una página diferente con contenido muy similar. – eppesuig

+0

window.crypto no fue [eliminado] (https://wiki.mozilla.org/SecurityEngineering/Removing_Proprietary_window.crypto_Functions) después de Firefox 33? – marcellorvalle

0

En Win/IE todavía puede usar CAPICOM http://en.wikipedia.org/wiki/CAPICOM sin ninguna biblioteca ActiveX o externa de terceros.
Esto funciona en cualquier lugar donde esté instalado IE.
Esto se está retirando sin embargo.

A continuación se muestra lo que estoy usando para iniciar sesión en IE. Yo llamo esto con, por ejemplo: 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 ""; 
} 

tuve algunos problemas con la codificación, etc., por lo que he incluido mi controlador (NET), así

 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

También estoy usando CAPICOM para firmar xml con el signo X509Certificate2. Cuando elijo un certificado de la tienda, después de eso no me pide que ingrese el nombre de usuario y la contraseña para ese certificado. ¿Es la misma situación y con tu código anterior? – SeaSide

+0

Solo algunas veces, si está "en mal estado": cierro el navegador, lo abro y me pide credenciales. Ocasionalmente obtengo un punto en el que deja de preguntar, pero volver a cargar el navegador siempre parece solucionarlo. – Yablargo

-1

Ahora se puede hacer eso. La aplicación web basada en tarjetas inteligentes o tokens PKCS # 11 puede implementarse utilizando la versión de Silverlight de NCryptoki. Ver http://www.ncryptoki.com

Tiene dos chanches:

1) utilizando la versión de Silverlight de NCryptoki y desarrollar su propio control de usuario Silverlight que implementa la lógica, una firma digital en su caso, mediante PKCS # 11 funciones suministradas por el tarjeta inteligente

2) usando el plugin jQuery basa en la versión de Silverlight arriba y poner en práctica su aplicación en JavaScript llamando a los PKCS # 11 funciones en JavaScript

Además, se puede utilizar la versión de Silverlight de NDigitSign (véase de nuevo http://www.ncryptoki.com) eso hace todo lo que necesita y puede implementarse en cualquier navegador web.

+0

Gracias por señalar esta solución. No estaba al tanto del proyecto ncryptoki, pero dado que está basado en Silverlight, todavía se requiere instalar el software en la máquina cliente (como en el applet Java) y, lo que es más importante, probablemente solo funcione en las máquinas con Windows. Finalmente, eso requeriría escribir una aplicación que usa directamente PKCS # 11, y realmente me gustaría evitar dicho programa. – eppesuig

4

Actualmente (mayo de 2016) no es posible.

Chrome ha eliminado el soporte de Java. 'Windows edge' no tendrá. El soporte de IE11 es malo, y Oracle decidió suspender el complemento java. Solo sería posible con Firefox, versiones anteriores de IE y el plugin de Java.

El nuevo estándar WebCryptographyApi proporciona soporte de firma digital para los navegadores, pero no tiene PCKS # 11 de apoyo

solución

Real-gobierno electrónico para resolver esto: 1) Instalar una aplicación Java locales en el PC del usuario. La aplicación escucha en un puerto como, por ejemplo, 5678 2) En su página, javascript detecta si hay compatibilidad con los applets 3) Si no hay soporte, se conecta a la aplicación en el formulario http://127.0.01:5678/sign y envía los datos al inicio de sesión. 4) La aplicación es local y no tiene problemas para usar el almacén de claves del sistema operativo, que incluye controladores PKCS # 11. Hacer firma digital y prepara el 5) Página resultados consultar periódicamente el resultado y lo recupera cuando esté listo

+0

Los applets de Java se pueden iniciar a través de Java Web Start. Esto funciona en todos los navegadores de escritorio, aunque se necesita un esfuerzo adicional. –

+0

Hay una solución en España en el gobierno electrónico para resolver esto. Lo documentaré en la respuesta – pedrofb

0

Uno proyecto que he estado involucrado con hizo con Chrome y nativa de mensajería:

https://github.com/CACBridge/ChromeCAC

esto requiere la instalación del plug-in de cromo, pero por lo demás funciona muy bien. Ideal para, p. Entornos de intranet/grupo donde sabe que tendrá que hacer esto antes de tiempo.

Cuestiones relacionadas