= Probando implementaciones en Murachí para poder firmar y verificar documentos firmados electrónicamente con certificados con soporte digital = [[br]] Los archivos .p12 o .pfx es una formar de almacenar los [https://tibisay.cenditel.gob.ve/murachi/wiki/actividades_2018_introduccion_cer_dig certificados digitales] juntos con la clave privada, estos archivos contiene información necesario para que el usuario pueda realizar firmas electrónicas. El consumo del servicio de Murachí en principio se realizado usando certificados desde dispositivo criptográficos, el proceso de firma electrónica del servicio Murachí se realiza por parte, una parte se va a realizar en el cliente que es donde se encuentra el dispositivo criptográfico y otra parte se va a realizar en el servidor de Murachí [[Image(secuencia_Firma_v2-pdf.png​)]] Como se puede observar en el diagrama de secuencia del lado del cliente se van a realizar 3 procesos: * ''' Subir documento pdf: ''' En este paso se carga al sistema Murachí el archivo usando el recurso “:/Murachi/0.1/archivos/” y se obtiene como respuesta el identificador único del archivo pdf (:identificador_unico_de_archivo_pdf). * '''Preparar firma del archivo:''' En este caso se envía el certificado firmante al sistema Murachí junto con otros parámetros necesarios para la firma electrónica. En esta ocasión se utiliza biblioteca de JavaScript Forge y crytpto. Con esta librería podemos gestionar los archivos ''.p12'' o ''.pfx'' * '''Completar la firma del archivo:''' En este paso se va a enviar al sistema Murachí el hash cifrado utilizando el recurso '':Murachi/0.1/archivos/pdfs/resenas'', para completar la firma electrónica. Aquí se utiliza de nuevo la librería ''JavaScript Forge y Crytpto'' para acceder al archivo y firmar el ''hash'' que se obtuvo en la sección anterior, usando el recurso :firmar_hash(sign). Obtenemos del sistema Murachí el identificador único del archivo firmado. Como el servicio de firma electrónica se realiza en varios pasos vamos a dividir el ejercicio en secciones. [[br]] == Sección 1: Subir documento pdf == En la primera sección se envía al sistema Murachí el archivo ''pdf'' que se va a firmar. Entonces para esta sección se requiere de un formulario que permita tomar del sistema de archivo documentos pdf y luego enviarlo con el método ''$.ajax'' usando el recurso ''/Murachi/0.1/archivos/'' '''Característica del formulario HTML''' [[br]] '''Control:''' * Botón de envío (Submit button) * Botón de reinicializando (Reset button) * Selección de fichero (file select) '''Atributos: ''' * action: función de javaScript que procesa el formulario para esta actividad la función es “SignFilePDF()” * enctype: este atributo específica el tipo de contenido que sera usado para enviar los datos al servidor, para esta actividad se utilizará “multipart/form-data” [[br]] '''Código del formulario HTML:''' {{{

Firmar electrónica (PDF)

Seleccione el archivo que va a firmar electrónicamente








}}} [[BR]] Los elementos
del formulario con id = "sección1", “sección2” y “sección3” se utiliza para mostrar los resultados correspondientes a los 3 procesos descritos para la firma electrónica (consumo del servicio a Murachí). Como se va a utilizar certificado con soporte a software se requiere tener en la pagina una sección que me permita cargar a la pagina el archivo ''.p12'' o ''.pxf'' [[br]] '''Código del formulario HTML:''' {{{




}}} [[BR]] Ahora vamos a necesitar una función en ''javascript'' que me permita usar la librería ''Forge'' para cargar y acceder al archivo ''.p12'' o ''.pfx'' y obtener la información necesaria para realizar el proceso de firma electrónica.[[BR]] [[br]] '''Función getCertificate(e)''' {{{ function getCertificate(e) { console.log("*... getCertificate ...*"); // Get PFX var fileInput = document.getElementById('pfx'); var file = fileInput.files[0]; // Read it var reader = new FileReader(); reader.onload = function(e) { console.log("*.... cargo el archivo .p12 ....*"); var contents = e.target.result; pkcs12Der = arrayBufferToString(contents); pkcs12B64 = forge.util.encode64(pkcs12Der); var pkcs12Asn1 = forge.asn1.fromDer(pkcs12Der); var password = $('#pfxp').val(); pkcs12 = forge.pkcs12.pkcs12FromAsn1(pkcs12Asn1, false, password); // load keys for(var sci = 0; sci < pkcs12.safeContents.length; ++sci) { var safeContents = pkcs12.safeContents[sci]; for(var sbi = 0; sbi < safeContents.safeBags.length; ++sbi) { var safeBag = safeContents.safeBags[sbi]; if(safeBag.type === forge.pki.oids.keyBag) { //Found plain private key privateKey = safeBag.key; } else if(safeBag.type === forge.pki.oids.pkcs8ShroudedKeyBag) { // found encrypted private key privateKey = safeBag.key; } else if(safeBag.type === forge.pki.oids.certBag) { // this bag has a certificate... certCount = certCount +1; if(certP12bag == null) { certP12bag = safeBag.cert; certpem = "" + forge.pki.certificateToPem(certP12bag).toString(); certBytesHex = forge.util.bytesToHex(certpem); } } } } } reader.readAsArrayBuffer(file); } }}} [[BR]] Con esta función obtenemos la clave privada almacenada en la variable ''privateKey'' y el certificado almacenado en la variable ''certBytesHex''. La clave privada es un conjunto de bytes que debemos convertir a ''string'', para esto se tiene la siguiente función [[BR]] {{{ function arrayBufferToString( buffer ) { var binary = '' var bytes = new Uint8Array( buffer ) var len = bytes.byteLength for (var i = 0; i < len; i++) { binary += String.fromCharCode( bytes[ i ] ) } return binary } }}} [[BR]] '''Función SignFilePDF() Sección 1. Subir documento pdf''' En esta sección la función procesa los datos del formulario. Vamos a cargar el archivo ''.p12'' o ''.pfx'' y usando la función ''getCertificate(e)'', y se obtiene el archivo ''pdf'' seleccionado en el formulario a través del método ''document.getElementById("file-sign")'' donde ''“file-sign”'' corresponde al id del elemento input de tipo ''“file”'' del formulario. Luego se almacena en un objeto de tipo ''FormData'' que permite el envío del archivo al servidor usando el método ''$.ajax'' '''Opciones de configuración de la petición $.ajax:''' * '''ulr:''' Establece la URL en donde se realiza la petición, para esta sección es ''"https://murachi.cenditel.gob.ve/Murachi/0.1/archivos"''. * '''type:''' Establece el tipo de petición, para esta actividad vamos a utilizar ''"POST"''. * '''dataType:''' Establece el formato de la respuesta que es permitido, si el servidor devuelve información con un formato diferente al especificado el código fallará. Para este proceso se establece “json”. * '''data:''' Establece la información que se enviará al servidor. Para este proceso se envía el archivo almacenado en una variable de tipo ''FormaData''. * '''contentType:''' Establece el tipo de codificación que se va a utilizar, para esta actividad es ''"application/json"''. * '''processData:''' Establece si la información que se envía al servidor debe ser procesada a una cadena de caracteres. Para evitar esto se debe utilizar el valor ''“false”''. En esta sección sólo se quiere enviar el archivo sin ser procesado. * '''xhrFields:''' {withCredentials: true} esta característica puede usarse para establecer la propiedad de '''withCredentials'''. Si se establece ''TRUE'' permite que se pase los ''cookies'' al servidor y permitir solicitudes de dominios cruzados. * '''headers:''' {"Authorization":"Basic YWRtaW46YWRtaW4="} autenticación básica HTTP [[BR]] '''Código de la función javaScript "SignFilePDF()" sección 1''' {{{ function SignFilePDF() { //cargar el archivo .p12 getCertificate(); var fileInput = document.getElementById("file-sign"); var list = fileInput.files; var form = $('firmar')[0]; var data = new FormData(); data.append('upload', $("#file-sign")[0].files[0]); $.ajax({ url: "https://murachi.cenditel.gob.ve/Murachi/0.1/archivos", type: "post", dataType: "json", data: data, cache: false, contentType: false, processData: false, xhrFields: {withCredentials: true}, headers: {"Authorization":"Basic YWRtaW46YWRtaW4="}, success: function(response) { var responseString = JSON.stringify(response); document.getElementById("seccion1").innerHTML = responseString; } )} }}} [[BR]] La repuesta de esta sección se procesa por el método ''.done'' a través del argumento response donde podemos acceder al valor del ''JSON'' con la función ''JSON.stringify''. [[BR]] '''Código completo de la sección 1:''' {{{ Javascript firma p12 Demo