Esta documentación es válida para CryptoApplet versión 2.0.1 o superiores.
CryptoApplet es un applet de realización de firma que pretende ser versatil y flexible adaptándose desde los entornos más simples a los entornos más exigentes.
Este applet ofrece un entorno de trabajo, inicialmente para la creación de firma en diversos formatos, se prevee que su evolución sea hacia un entorno completo de creación y verificación de firma debido a su diseño modular. Para obtener información más general sobre el proyecto, visite http://cryptoapplet.nisu.org
El proyecto se compone de cuatro módulos:
Como se comenta en la introducción de la página web del proyecto, el applet recibe una entrada de datos desde una fuente, permite al usuario realizar un firma y envía el resultado a su destino. En el contexto del applet existen dos formas de obtener la entrada de datos que son desde una URL y como un parámetro a una de sus funciones exportadas. En cuanto a la salida, el applet la ofrece también de dos formas distintas, la primera realizando una llamada a una función javascript que contiene como parámetro la firma y la segunda forma haciendo un post a una URL determinada. Para más información con respecto al comportamiento de las funciones ver el punto “Funciones Javascript”.
En Cryptoapplet, los formatos de firma se especifican mediante la función exportada a javascript
setSignatureOutputFormat(String format);
En adelante nos referiremos a cadenas de formato siendo estos el parámetro que debe recibir la función anterior en cada caso.
Para el formato raw, la cadena debe ser RAW, al indicar este formato de salida, el applet obtendra los datos de entrada, los resumirá utilizando el algorítmo de firma SHA1 y devolverá un PKCS#1 con padding que contendrá el hash de los datos de entrada firmados.
Otra posibilidad para el formato de salida es que el applet genere un PKCS#7, a partir de los datos de entrada se calculará el resumen SHA1 de los mismos, se generará una estructura PKCS#7 y se ofrecerá como resultado. Cabe indicar en este punto que el PKCS#7 generado únicamente contiene el certificado del firmante y no los certificados de CAs intermedias como permite el estándar, de esta forma la verificación debe realizarse contra toda la cadena de certificación que expidió el certificado del firmante.
La cadena de formato que debe utilizarse para obtener la firma en formato PKCS#7 es CMS
setSignatureOutputFormat("CMS");
En algunos entornos puede ser interesante realizar la firma a partir resumen de los datos, a pesar de que esto podría vulnerar el derecho del firmante a ver el contenido que firma parece razonable en entornos como los sistemas de envio de mail utilizar esta metodología. Si pensamos en un Mail User Agent basado en el Web y en una situación en la que un usuario pretenda enviar adjuntos de suficiente tamaño, el servidor debería devolver al cliente el MIME compuesto con todos los adjuntos para que este pudiera calcular la firma, si utilizamos únicamente el hash, el servidor devolverá los 20 bytes de los que se compone el resumen y el cliente tendrá suficiente información para componer la firma. Obviamente el cliente podría enviarse una copia de ese correo para comprobar los datos que ha firmado. Puede verse un ejemplo de lo expuesto en http://cryptoapplet.nisu.org/samples/v2/signmail.php
La cadena de formato que debe utilizarse para obtener la firma en formato PKCS#7 a partir del hash es CMS_HASH
setSignatureOutputFormat("CMS_HASH");
CryptoApplet utiliza las bibliotecas iText (http://www.lowagie.com/iText/) para realizar la firma electrónica sobre documentos pdf, dada la entrada de datos, CryptoApplet sitúa una firma invisible en el documento pdf que puede ser verificada por Adobe Reader. Los campos Reason, Location y Contact de la firma son configurables (véase abajo el punto relativo a la configuración). En la firma generada se incluye el certificado del firmante y el de la CA raíz o intermedia que lo expidió.
Este formato, permite también añadir un Sello de Tiempo gracias al parche desarrollado por Aiken Sam y Martin Brunecky para iText. La activación de esta característica así como la dirección URL desde donde se debe obtener la marca de tiempo, se configuran en el fichero de configuración.
La cadena de formato que debe utilizarse para obtener la firma de un PDF es PDF
setSignatureOutputFormat("PDF");
Hay que tener en cuenta que para la obtención de este formato de firma sólo podemos proporcionar como entrada un documento PDF.
Este applet hace uso de una versión de la biblioteca JDigiDoc considerablemente modificada por nosotros que genera una representación de firma compatible compatible con la especificación TS 101 903 - V1.1.1 del ETSI, siendo capaz de generar los formatos XAdES, XAdES-T y XAdES-X-L. El applet generará uno u otro formato dependiendo de la configuración. (véase abajo el punto relativo a la configuración) Las particularidades, de un modo general, de estos formatos son:
La cadena de formato que debe utilizarse para obtener la firma en formato DigiDoc es XADES
setSignatureOutputFormat("XADES");
El applet también soporta la realización de firmas en paralelo para el formato XAdES, de forma que en un mismo documento XML se encuentre el contenido sobre el cual se realizó la firma y a continuación uno por uno el resultado de todos los procedimientos de firma que se llevaron a cabo sobre él. Cabe mencionar con respecto a este método que la entrada de datos debe ser un documento en formato DigiDoc previamente firmado con el applet utilizando el formato de firma “XAdES”.
La cadena de formato que debe utilizarse para obtener cofirma en XAdES es XADES_COSIGN
setSignatureOutputFormat("XADES_COSIGN");
En la versión 2.0.1 del applet se ha implementado también el soporte para la generación de firma XMLDsig enveloped siendo ésta soportada por la versión de la máquina virtual de java (y su plugin) 1.6 o superior. En el código fuente del applet puede obtenerse un ejemplo de validación de esta modalidad de firma, concretamente en el paquete es.uji.dsign.crypto.test
Este formato de salida recibe datos en formato XML como entrada con los datos y genera la representación de la firma en formato XMLDsig.
La cadena de formato que debe utilizarse para obtener la firma en formato XMLDsig es XMLDSIG
setSignatureOutputFormat("XMLDSIG");
La interacción con el Applet se realiza plenamente mediante funciones JavaScript. Para comprender mejor el procedimiento general, comentaremos el siguiente código:
En primer lugar el siguiente código HTML instancia el applet y crea un botón cuya acción será invocar la función javascript Sign(), este botón se encuentra deshabilitado para impedir que el usuario lo presione antes de que el applet se cargue.
<applet id="CryptoApplet" name="CryptoApplet" code="es.uji.dsign.applet2.SignatureApplet" width="0" height="0" codebase="applet" archive="ujiApplet-2.0.1-signed.jar,ujiCrypto-2.0.1-signed.jar,ujiUtils-2.0.1-signed.jar,ujiConfig-2.0.1.jar, bcprov-jdk15-138.jar,bcmail-jdk15-138.jar,jakarta-log4j-1.2.6.jar" mayscript> </applet> <input id="bt1" type="button" disabled="true" value="Sign" onClick="Sign();">
El código JavaScript más básico que podemos implementar en la página es el siguiente:
<script language="javascript"> function onInitOk(){ document.getElementById("bt1").disabled=false; } function onSignOk(signature){ alert(signature); } function onSignOkFinalize(signature){ alert(signature); } function onSignError(errorDesc){ alert(errorDesc); } function onSignCancel(){ alert("User Canceled"); } function Sign(){ CryptoApplet= document.getElementById('CryptoApplet'); CryptoApplet.setInputDataEncoding("PLAIN"); CryptoApplet.setSignatureOutputFormat("CMS"); CryptoApplet.signDataUrlToFunc("http://www.foo.com","onSignOk"); } </script>
El flujo de ejecución del proceso de firma es el siguiente, el applet se instanciará y se invocará su método init, una vez hecho esto, él mismo invocará la función JavaScript onInitOk. El usuario presionará el botón y le aparecerá la ventana principal del applet, durante el proceso de selección de certificado, introducción de password y realización de firma, si el usuario cancela la operación o sucede algún error, las funciones onSignCancel y onSignError serán invocadas respectivamente, en caso contrario, si la realización de la firma ha sido correcta se invocará la función javaScript que se haya indicado como segundo parámetro de la función signDataUrlToFunc, por defecto se invocará la función onSignOk.
En el caso anterior, la función Sign, indica al Applet que la codificación de los datos de entrada es “texto plano”, que el formato de representación de firma debe ser CMS y que se utilizará como entrada / salida de datos la url http://www.foo.com y la función onSignOk respectivamente.
| Signatura función | Valor parámetros | Descripción |
|---|---|---|
| setInputDataEncoding(final String encoding) | “PLAIN”, “HEX”, “BASE64” | Esta función permite seleccionar el tipo de codificación que tiene la entrada de datos, el applet decodificará esos datos antes de realizar el proceso de firma. |
| setJavaScriptCallbackFunctions(String ok, String error, String cancel, String windowShow) | “funcionOk”,”funcionError”,”funcionCancel”, ignorado | Permite seleccionar las funciones javascript que deberá invocar el applet en cada caso particular. |
| setLanguage(String lang) | “EN_en”, “ES_es”, “CA_ca” | Selecciona el lenguaje del applet. |
| setSignatureOutputFormat(String format) | “RAW”, “CMS”, “CMS_HASH”, “XADES”, “XADES_COSIGN”, “PDF”, “XMLDSIG” | Selecciona el formato de salida para la firma de acuerdo con lo explicado en “Formatos de salida de la firma”. |
| setSSLServerCertificateVerification(String value) | “true”, “false” | Indica al applet si debe verificar (true) o no (false) los certificados de servidor que intervienen en conexiones SSL. |
| signDataParamToFunc(String toSign, String funcOut) | “texto”, “funcionSalida” | Inicia el proceso de firma con los datos fuente “texto” y ofrece la salida como parámetro a la función funcionSalida. |
| signDataParamToURL(String toSign, String outputURL) | “texto”, “UrlSalida” | Inicia el proceso de firma con los datos fuente “texto” y realiza un POST HTTP a la dirección url indicada como segundo parámetro incluyendo en la variable el resultado de la firma. |
| signDataParamToURL(String toSign, String outputURL, String postVariableName) | “texto”, “UrlSalida”, “variablePost” | Inicia el proceso de firma con los datos fuente “texto” y realiza un POST HTTP a la dirección url indicada como segundo parámetro incluyendo en la variable postVarialbeName el resultado de la firma. |
| signDataUrlToFunc(String inputURLs, String funcOut) | "url1|url|2url3",”funcionSalida” | Recibe una lista de urls y una función de salida, realiza el procedimiento de firma sobre cada una de ellas e invoca la función “funcionSalida” una vez por cada resultado ofreciendo el mismo como parámetro |
| signDataUrlToUrl(String inputURLs, String outputURL) | "url1|url|2url3",”urlSalida” | Recibe una lista de urls y una url de salida, realiza el procedimiento de firma sobre cada una de ellas y realiza un POST HTTP a la url indicada como segundo parámetro utilizando la variable content para ofrecer la representación de la firma y la variable item para indicar el orden de la firma, esto es para url1 item sería 1, para url2 item sería 2 y así sucesivamente. |
| signDataUrlToUrl(String inputURLs, String outputURL, String postVariableName) | "url1|url|2url3",”urlSalida”, “variablePost” | Tiene el mismo comportamiento que la función anterior pero permite cambiar el nombre de la variable que se recibe por POST. |
| setXadesSignerRole(String signerrole) | “SignerRole” | Permite establecer el valor de este campo (SignerRole) para la modalidad de firma XAdES |
| verifyXAdESDataUrl(String input) | “URL” | Obtiene una representación de firma XAdES-X-L, la verifica y devuelve el resultado como un String[], la verificación será correcta si este valor devuelto es null y en caso contrario se encontrarán las razones de si no validación en las posiciones 0 a n del array devuelto |
A continuación puede verse código fuente de ejemplos de utilización del applet para los diferentes formatos de firma.
DigiDoc (XAdES-X-L) signature.
La instalación es sencilla, únicamente hay que obtener la última versión de la página de descargas y descomprimir el fichero en el directorio destinado a tal fin dentro de la estructura de la página web para la cual va a ser utilizado. Esto nos creará un directorio CryptoApplet_VX.Y.Z que contiene los ficheros .jar principales y un directorio libs que contiene las bibliotecas necesarias para la correcta ejecución del applet, puesto que en cada caso, las bibliotecas necesarias son distintas, a contnuación puede verse una tabla que relaciona el formato de firma de salida con las bibliotecas necesarias. Estas bibliotecas deben ser especificadas en el atributo “archive” de la etiqueta applet que configura su instanciación.
Para todos los formatos deben incluirse las bibliotecas ujiUtils-x.y.z-signed.jar, ujiApplet-x.y.z-signed.jar, ujiCrypto-x.y.z-signed.jar si además pretende utilizarse la configuración de ejemplo ujiConfig-x.y.z.jar deberá ser incluido, en caso contrario deberá incluirse otro fichero jar que contenga la configuración específica.
| Formato de firma | Bibliotecas necesarias |
|---|---|
| RAW | bcprov-jdk15-138.jar, jakarta-log4j-1.2.6.jar |
| CMS | bcprov-jdk15-138.jar,bcmail-jdk15-138.jar,jakarta-log4j-1.2.6.jar |
| bcprov-jdk15-138.jar,jakarta-log4j-1.2.6.jar,itext-1.4.8.jar | |
| XMLDsig | bcprov-jdk15-138.jar,jakarta-log4j-1.2.6.jar |
| XAdES-X-L | bcprov-jdk15-138.jar,bcmail-jdk15-138.jar,bctsp-jdk15-138.jar,xalan.jar,xmlsec.jar,myxmlsec.jar,jakarta-log4j-1.2.6.jar |
La configuración se establece por medio del fichero ujiCrypto.conf, éste fichero contiene pares nombre=valor que determinan el comportamiento y algunas de las características del applet durante el proceso de firma. Por el momento, solo existen opciones que afectan a las modalidades de firma XAdES-X-L y PDF. Podemos ver estas opciones a continuación de forma tabulada.
| Opción | Valor | Descripción |
|---|---|---|
| DIGIDOC_OCSP_RESPONDER_COUNT | Número | Indica el número de OCSP responders que vienen a continuación |
| DIGIDOC_OCSP_RESPONDER_URLX | Url | X es el número de orden de este responder (1,2,3,..). Ejemplo: DIGIDOC_OCSP_RESPONDER_URL1=http://ocsp.pki.gva.es |
| SIGN_OCSP_REQUESTS=false | false | Debe permanecer a false, indica si las peticiones OCSP deben ser firmadas, cryptoapplet no soporta el envío de peticiones firmadas |
| DIGIDOC_CA_CERTS | Número | Indica el número de CAs que se definen a continuación, estas CAs son necesarias para permitir al usuario firmar con certificados expedidos por las mismas |
| DIGIDOC_CA_CERT1=jar://cagva.pem | Referencia jar:// | Fichero certificado X509 en formato Base64 que se encontrará en alguno de los .jar includidos en el atributo archive de la etiqueta applet |
| DIGIDOC_CA_CERT2=jar://rootca.pem | Referencia jar:// | … |
| DIGIDOC_CA_CERT3=jar://accv-ca2.pem | Referencia jar:// | … |
| DIGIDOC_CA_CERT4=jar://ACDNIE002-SHA1.pem | Referencia jar:// | … |
| DIGIDOC_OCSP_COUNT=1 | Número | Indica el número de certificados correspondientes a servicios OCSP se tienen que considerar. |
| DIGIDOC_OCSP1_CN=ocsp-gva | Common Name | Indica el Common Name del certificado que utilizará el servidor OCSP |
| DIGIDOC_OCSP1_CERT=jar://ocsp-gva.crt | Referencia jar:// | Indica donde encontrar el certificado en si |
| DIGIDOC_OCSP1_CA_CERT=jar://cagva.pem | Referencia jar:// | Certificado de la autoridad raíz que expidió el certificado OCSP |
| DIGIDOC_OCSP1_CA_CN=CAGVA | Common Name | Common Name de la autoridad raíz que expidió el certificado OCSP |
| DIGIDOC_CERT_VERIFIER=OCSP | OCSP|CRL | Indica si se debe utilizar OCSP o CRL para la validación de los certificados |
| DIGIDOC_SIGNATURE_VERIFIER=OCSP | OCSP|CRL | |
| DIGIDOC_DEMAND_OCSP_CONFIRMATION_ON_VERIFY=true | true|false | Verificar certificado mediante OCSP ante una validación de firma |
| DIGIDOC_TSA_COUNT=1 | Número | Certificado de autoridades de sellado de tiempo que vienen a continuación |
| DIGIDOC_TSA1_CERT=jar://tsa1_accv.der | Referencia jar:// | Certificado de la autoridad que firmará el sello de tiempo |
| DIGIDOC_TSA1_CA_CERT=jar://tsa1_accv.der | Referencia jar:// | Certificado de la autoridad que expidió el certificado con el que se firmará el sello de tiempo |
| DIGIDOC_TSA1_USE_NONCE=true | true|false | Utilizar un numero único para cada petición |
| DIGIDOC_TSA1_ASK_CERT=false | true|false | Solicitar que la autoridad de sellado de tiempo nos envie el certificado |
| DIGIDOC_TSA1_URL=http://tss.accv.es:8318/tsa | URL | Url que alberga el servicio de sellado de tiempo |
| DIGIDOC_MAX_TSA_TIME_ERR_SECS=60 | Número | Tiempo que se debe esperar antes de que venza el timeout |
Para más información relacionada con las opciones de esta modalidad de firma puede consultarse la documentación del proyecto JDigiDoc.
| Opción | Valor | Descripción |
|---|---|---|
| PDFSIG_REASON | Texto | Texto que aparecerá en el campo reason de la firma en el documento PDF |
| PDFSIG_LOCATION | Texto | Texto que aparecerá en el campo location de la firma del documento PDF |
| PDFSIG_CONTACT | Texto | Texto que aparecerá en el campo contact de la firma en el documento PDF |
| PDFSIG_CA_CERTS | Número | Número de certificados que indicamos a continuación. El applet únicamente firmará documentos PDF con certificados directamente expedidos por alguna de las CAs indicadas a continuación. |
| PDFSIG_CA_CERTX | Referencia a fichero. (Ejemplo: PDFSIG_CA_CERT1=cagva.pem) | Indica el nombre del fichero que contiene el certificado. |
| PDFSIG_TIMESTAMPING=true | true|false | Indica si debe llevarse a cabo un sellado de tiempo sobre la firma (true) o no (false) |
| PDFSIG_TSA_URL=http://tss.accv.es:8318/tsa | URL | Indica la url desde la cual se obtendrá el sello de tiempo. |
El interfaz del applet utiliza conjuntos de propiedades para permitir la internacionalización, de forma que mediante la función exportada javascript setLanguage(lang); y el uso de los ficheros i18n_XY_ZT.properties consguimos que el applet muestre los mensajes en el idioma deseado. Por el momento, el applet dispone de las siguientes traducciones: