Firmas Digitales muy Fácil con Firefox

4
39328

Firmas Digitales muy Fácil con Firefox

Introducción

Los certificados digitales son cada vez más populares y su
utilidad no se limita sólo a identificar al usuario sino que
también permite que éste “firme”
electrónicamente datos con garantías de no repudio y
reconocimiento legal en muchos paises. Particularmente útil
para que el usuario firme contratos u ordene productos/servicios, de
consentimiento con validez legal, etc.

Para implementar certificados digitales en el navegador Microsoft
Internet Explorer contamos con cuantiosa documentación y
tutoriales sobre el tema, pero en el caso de Firefox estamos más
escasos así que aquí va nuestro humilde aporte.

En la página web

Firefox implementa el objeto JavaScript 1.2
“window.crypto” que encapsula la operatorio de firma y
simplifica notablemente la etapa en cliente. Una vez en servidor,
veremos cómo validar la firma y extraer información de
la misma.

A fines de simplificar el ejemplo, copiamos una página muy
breve con el JavaScript incrustado:


<html>
<head>
<title>Prueba
de firma digital</title>
<meta
http-equiv=»Content-Type» content=»text/html;
charset=iso-8859-1″>
<script>
function
firmar(original) {
if
(navigator.appName==»Microsoft Internet Explorer»){
//
Implementar la firma digital con MS IE con CAPICOM
}
else {
return
firmarFirefox(original);
}
}
function
firmarFirefox(original) {
var
firmado = window.crypto.signText(original, «ask»);
if
(firmado.substring(0,5) ==»error») {
alert(«Su
navegador no ha generado una firma valida»);
return
«»;
}
else
if (firmado ==»no generada») {
alert(«No
ha generado la firma.»);
return
«»;
}
else
{
return
firmado ;
alert(«Firma
generada correctamente. Pulse enviar para comprobarlos en
servidor.»);
}
}
</script>
</head>
<body>
<h1>Prueba
de firma digital</h1>
<form
action=»CompruebaFirmaDigital» method=»post»>
<textarea
name=»original» cols=»20″ rows=»20″>Texto
de prueba</textarea>
<textarea
name=»firmado» cols=»20″ rows=»20″></textarea>
<input
type=»button» value=»Firmar»
onclick=»document.forms[0].firmado.value =
firmar(document.forms[0].original.value)»/>
<input
type=»submit» value=»Enviar» />
</form>
</body>
</html>

Como vemos, el formulario CompruebaFirmaDigital
tiene un campo original
donde pondremos el contenido a firmar.

Luego presionaremos el botón Firmar
y Firefox nos mostrará un pop-up donde seleccionamos el
certificado a utilizar:

En esta ventana podemos comprobar el texto a firmar, seleccionar
el certificado (podríamos tener varios instalados) e
introducir la clave del repositorio*. Al presionar OK, se generará
en firmado
la firma correspondiente.

El botón Enviar
realizará el post al servlet que veremos en la siguiente
sección.

*Si no hemos definido ninguna clave de repositorio o “master
password”, deberíamos ir a Tools / Options / Security (o
Herramientas / Opciones / Seguridad):

Y entonces seleccionar “Use a master password” y
establecer la nueva clave pinchando en el botón “Change
Master Password”:

Es interesante observar la barra “Password quality meter”
que calcula la dificultad de nuestra password en base a reglas como:
contener letras en mayúsculas y minúsculas, números,
caracteres de puntuación, etc.

En el servidor

Vamos a crear un servlet donde:

  1. Obtendremos el contenido original y el contenido firmado

  2. Verificaremos que el firmado coincida con el original

  3. Obtendremos más información desde el
    certificado

Y vamos directamente al código:


package
com.autentia.tutorial.firmaDigital.firefox.servlet;

import
java.io.IOException;
import
java.io.PrintWriter;
import
java.security.cert.X509Certificate;

import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;

import
com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

import
sun.security.pkcs.PKCS7;
import
sun.security.pkcs.SignerInfo;

public
class CompruebaFirmaDigital extends HttpServlet {

private
static final long serialVersionUID = -1691697973877536487L;

@Override
protected
void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException,
IOException
{
PrintWriter
out = response.getWriter();
String
original = request.getParameter(«original»);
String
firmado = request.getParameter(«firmado»);

try
{
PKCS7
p7 = new PKCS7(Base64.decode(firmado));
SignerInfo[]
si = null;

//
check if data is «attached» to this P7 blob
if
(p7.getContentInfo().getContentBytes() == null) {
//
do the verification on the data provided
si
= p7.verify(original.getBytes());
}
else
{
//
original data is embedded or «attached» to this
P7,implicit verification will do…
si
= p7.verify();
}

out.println(«[VERIFY
OK]»);

//
printout the p7 contents
out.println(«[P7
CONTENS]»);
out.println(p7.toString());

out.println(«[EXTRACTING
DATA]»);
//
check if data is «attached» to this P7 blob
if
(p7.getContentInfo().getContentBytes() == null) {
out.println(«No
data found»);
}
else
{
out.println(p7.getContentInfo().getContentBytes());
}
}
catch
(Exception e) {
out.print(«[ERROR
VALIDATING SIGNATURE]»);
e.printStackTrace();
}
}

}

Al enviar un mensaje firmado, se ejecutará el servlet y
obtendremos una página como la que copio a continuación:

Consideraciones

Recordemos que lo que firma el usuario es un texto, así que
si lo que queremos que firme es, por ejemplo, una solicitud de compra
de productos deberemos traducir el formulario o “carrito de la
compra” a un texto tipo “Don
Juan Perez, con DNI XXX se compromete a comprar el 30 de Junio de
2007 los siguientes productos: 2 Cartuchos de Tinta HP6546 y 1 Papel
500x90g por un valor total de 67 euros (IVA incluido) pagaderos en
efectivo y que serán enviados a C/Castellana, 1 Bajo C. En
Madrid, a los 20 dias del mes de junio de 2007.”

¿Dónde encuentro más info?

Mozilla Development Center: JavaScript crypto
http://developer.mozilla.org/en/docs/JavaScript_crypto

Introducing MS CAPICOM
http://msdn2.microsoft.com/en-us/library/ms995332.aspx

Conclusiones

Con la popularización de los certificados digitales (más
con llegada de los DNI electrónicos en España)

Muy buena herramienta, muy útil, muy estable y en constante
evolución.

En Autentia tenemos mucha experiencia en desarrollo Web y podemos
ayudarte a construir u optimizar tus portales o aplicaciones web. No
dudes en ponerte en contacto con nosotros.

4 Comentarios

  1. Hola Javier, excelente tu articulo. Lo estuve estudiando para encontrar un vinculo entre lo que escribiste y lo que yo necesito porque realmente estoy perdido, pero creo que no es lo mismo. Yo estoy tratando de generar un certificado PKCS#10 desde javascript, es decir desde el lado del cliente. Con capicom de microsoft puedo si el usuario tiene IE pero si tiene FireFox utilizando parece complicado he tratado de hacerlo con Keygen tag o crypto.generateCRMFRequest() y no lo he logrado. Tienes algo que pueda ayudarme?

  2. Hola!!!! gracias por tu artículo…… No domino mucho la creación de servlet, pero creo que lo he conseguido desde NetBeans, creando un proyecto nuevo Java Web y en web pages añadiendo el index.html y en source packages creando el servlet CompruebaFirmaDigital.java

    Me he vuelto loco porque el crypto.signText parece ser que no funciona bien con la última versión de firefox, así que he instalado una antigua la 38.05 y le he instalado la extensión signTextJS 0.7.8…

    Hasta ahí todo perfecto, pero cuando le doy a firmar me salta la ventanita que pones aquí con el texto de prueba, puedo seleccionar los certificados que tengo instalados en el navegador sin problemas, pero cuando le doy a firmar, me salta: «Su navegador no ha generado una firma válida» y no tengo ni idea de porqué es…… Cuando le doy a enviar, me salta: [ERROR VALIDATING SIGNATURE]…. pero me imagino que eso será normal, puesto que he obtenido el error anterior a la hora de firmar….. Un salido y gracias!!!!

  3. Hola, soy yo de nuevo…. resulta que estaba probando con certificados generamos por mí y se ve que estan mál creados. He probado con uno de la fnmt y lo ha tomado sin problemas….

    Bien… Ya tengo el texto codificado….. pero… ahora como lo decodificaría?????? me estoy volviendo loco y no encuentro ninguna orden para tal fin….. tiene que ser una tontería, pero…….

Dejar respuesta

Please enter your comment!
Please enter your name here