Cómo firmar digitalmente un documento PDF mediante Python. Además, generamos un certificado autofirmado propio (pfx, pem) y firmamos con este certificado generado. No necesitaremos un certificado expedido por una autoridad de certificación y no necesitaremos validar con autoridades de certificación externas. La aplicación permitirá insertar una firma en imagen en las coordenadas que indiquemos X,Y. Si el documento tiene varias páginas podremos elegir en cuales de ellas se insertará la imagen con la firma. También permitirá firmar varios documentos PDF a la vez, todos los que estén en una carpeta indicada.

Instalar paquetes Python necesarios PDFNetPython3 y pyOpenSSL

En primer lugar necesitaremos tener instalado Python en nuestro equipo. En el siguiente artículo explicamos cómo hacerlo:

Instalaremos los componentes (librerías, paquetes) que usaremos para la generación de un certificado autofirmado y para firmar el documento PDF. Para ello, desde la línea de comandos, ejecutaremos el siguiente comando:

pip install PDFNetPython3 pyOpenSSL

Este comando instalará en nuestro sistema las últimas versiones de PDFNetPython3 (en el momento de la realización de este artículo la 9.1.0) y pyOpenSSL (la versión 21.0.0), además, instalará otros paquetes dependientes: cryptography 36.0.0, pycparser 2.21 y cffi 1.15.0:

Instalar paquetes Python necesarios PDFNetPython3 y pyOpenSSL

El paquete PDFNetPython3 dejó de ser gratuito en las últimas versiones. Por ello, para que funcione nuestra aplicación, tendremos que adquirir dicho paquete o bien usar una clave de prueba, que podemos obtener directamente (sin registro) desde su web oficial:

https://www.pdftron.com/pws/get-key

Copiaremos la clave de demostración y la pegaremos en la línea de código:

PDFNet.Initialize(«demo:1638008198625:7b6e5d3b030000000000ad6c0848ed2c55e035c1937ec70d40b850090b»)

(el código fuente lo veremos en el siguiente punto de este artículo)

Hay que tener en cuenta que PDFTron recopilará datos del uso de su SDK en nuestra aplicación Python y lo enviará a sus servidores. Así lo indica en la obtención de la clave de prueba (trial key):

PDFTron collects some data regarding your usage of the SDK for product improvement.

Si usamos la versión 8.1.0 de PDFTron (PDFNetPython3), no necesitaremos clave de licencia pues es gratuita, la instalaríamos con el comando:

pip install PDFNetPython3==8.1.0 pyOpenSSL==20.0.1

Y en la línea de código (que mostramos más adelante):

PDFNet.Initialize(«demo:1638008198625:7b6e5d3b030000000000ad6c0848ed2c55e035c1937ec70d40b850090b»)

La cambiaríamos por:

PDFNet.Initialize()

De esta forma usaríamos una versión gratuita y tampoco aparecería el mensaje:

PDFNet is running in demo mode.

Cada vez que ejecutemos nuestro programa.

Código fuente Python para generar certificado autofirmado y firmar documentos PDF

A continuación mostramos el código fuente completo de nuestra aplicación Python. Todas las líneas importantes de código van comentadas con su uso. También comentamos y explicamos para qué se usa cada método.

El script Python, que guardaremos con el nombre «firmar_pdf.py«, tendrá el siguiente código (se puede descargar aquí):

En el código hemos incluido como Nombre Común del certificado «Proyecto A». Este dato aparecerá en los detalles del certificado al consultar las firmas del documento PDF, en el campo «Emisor«. Además, el campo «Número de serie» también lo generamos desde el código Python, de forma aleatoria en función de la hora actual del sistema (multiplicándola por 10). Estableceremos la validez del certificado a 10 años:

Código fuente Python para generar certificado autofirmado y firmar documentos PDF

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Explicamos ahora cómo funciona la aplicación Python. La aplicación admite varios parámetros, que podemos mostrar ejecutando:

«C:/Program Files/python.exe» d:/ProyectoA_Python/PDF/Firmar/firmar_pdf.py –help

(suponemos que tenemos instalado python.exe en la carpeta C:/Program Files/python.exe y que tenemos el script python en d:/ProyectoA_Python/PDF/Firmar/ )

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Los parámetros posibles son:

  • -h, –help: muestra la pantalla de ayuda con los parémetros posibles y su uso.
  • -g, –GenerarCertificado: genera un certificado autofirmado en la carpeta «static» de la ruta donde se encuentre el script (esta carpeta «static» debe estar creada previamente). Generará los ficheros .cer, .pem (clave pública y clave privada) y .pfx.
  • -i CARPETAPDF, –carpetaPDF CARPETAPDF: fichero PDF que se firmará. Si se indica sólo una carpeta, la aplicación firmará todos los documentos PDF que existan en esa carpeta. Permite firmar o bien un único fichero PDF o bien todos los PDF de una carpeta y subcarpeta indicadas.
  • -f IDFIRMA, –IDFirma IDFIRMA: nombre del firmate.
  • -p PAGINAS, –paginas PAGINAS: páginas del fichero (o ficheros) PDF en las que se agregará la imagen de la firma escaneada (cogida del fichero img_firma.jpg). Indicaremos las páginas con el formato [1,2,3,4]. Por ejemplo, si el documento PDF tiene 4 páginas y queremos incluir la imagen de la firma en la página 1 y la página cuatro, agregaremos el parámetro -p [1,4]
  • -x COORDENADAX, –coordenadaX COORDENADAX: coordenada X de la posición en la que se incluirá la imagen de la firma.
  • -y COORDENADAY, –coordenadaY COORDENADAY: coordenada Y de la posición en la que se incluirá la imagen de la firma.
  • -r true/false, –recursivo true/false: si se indica una carpeta en lugar de un fichero PDF, y se indica este parámetro a true, firmará todos los documentos PDF de todas las subcarpetas contenidas en la carpeta indicada.

En primer lugar crearemos la carpeta «static» en la carpeta donde tengamos el fichero de script Python:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

A continuación generaremos el certificado autofirmado (no requiere de entidad certificadora externa) ejecutando el comando:

«C:/Program Files/python.exe» d:/ProyectoA_Python/PDF/Firmar/firmar_pdf.py g

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

El comando anterior habrá generado el fichero de certificado certificate.cer, el contenedor container.pfx y los ficheros PEM de la clave pública public_key.pem y la clave privada private_key.pem:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Por otro lado, si queremos que se inserte una imagen con la firma escaneada, colocaremos el fichero de la imagen con formato jpg, con el nombre img_firma.jpg, en la carpeta static:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

A partir de ahora podremos firmar documentos PDF con este certificado generado. Por ejemplo, para firmar el documento PDF «documento_ejemplo_1_pagina.pdf» (con una sola página), ubicado en «D:\ProyectoA_Python\PDF\Firmar\PDF«, insertándole el fichero de imagen de firma en la posición (330,100), y el fichero firmado PDF con el nombre «documento_ejemplo_1_pagina_firmado.pdf«, usaremos el comando:

«C:/Program Files/python.exe» d:/ProyectoA_Python/PDF/Firmar/firmar_pdf.py -i «D:\ProyectoA_Python\PDF\Firmar\PDF\documento_ejemplo_1_pagina.pdf» -f «ProyectoA» -x 330 -y 100 -o «D:\ProyectoA_Python\PDF\Firmar\PDF\documento_ejemplo_1_pagina_firmado.pdf»

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Nos habrá generado el documento documento_ejemplo_1_pagina_firmado.pdf , copia del documento documento_ejemplo_1_pagina.pdf, pero con la firma digital (usando nuestro certificado autofirmado) y con la firma en imagen:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Como vemos, al abrirlo nos mostrará un mensaje indicando «Hay al menos una firma que presenta problemas». El motivo de esta advertencia es que Acrobat Reader intenta validar el certificado en una identidad de confianza de Acrobat Reader. En este punto explicamos cómo evitar este mensaje. El certificado generado es un certificado «normal» y pueden consultarse sus datos pulsando en «Panel de firma» o pulsando en la imagen de firma escaneada. Pulsaremos en «Propiedades de la firma…»:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Y pulsaremos en «Mostrar certificado del firmante…»:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Nos mostrará los datos del certificado:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Para firmar todos los documentos PDF contenidos en una carpeta podemos ejecutar el comando:

«C:/Program Files/python.exe» d:/ProyectoA_Python/PDF/Firmar/firmar_pdf.py -i «D:\ProyectoA_Python\PDF\Firmar\PDF\» -f «ProyectoA» -x 330 -y 100 -p [1,7] -r true

Firmará todos los documentos PDF que haya en la carpeta D:\ProyectoA_Python\PDF\Firmar\PDF\, si tienen varias páginas incluirá la firma de imagen en las páginas 1 y 7. Y al indicar el parámetro -r true, será recursivo y firmará todos los PDF que haya en las subcarpetas de la carpeta indicada:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

El comando anterior generará un fichero duplicado de cada PDF, añadiendo al nombre …_firmado.pdf con el PDF firmado:

Ejecución de la aplicación Python para firmar documentos PDF con certificado autofirmado propio

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Cuando abrimos el documento PDF firmado, nos aparecerá un mensaje en el panel de firma indicando: Hay al menos una firma que presenta problemas. Este mensaje no significa que la firma digital no sea válida, indica que Adobe Acrobat Reader no puede validar automáticamente la firma digital agregada (con certificado autofirmado) porque el certificado no está en la lista de identidades de confianza.

Si queremos evitar este mensaje de aviso, podremos agregar nuestro certificado autofirmado a las identidades de confianza. Para ello abriremos Adobe Acrobat Reader, pulsaremos en el menú «Edición» – «Preferencias»:

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Seleccionaremos la categoría «Firmas» a la izquierda, y a la derecha pulsaremos en «Más…» en el grupo «Identidades y certificados de confianza»:

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Pulsaremos en «Certificados de confianza» en la izquierda y en la barra de botones pulsaremos en «Importar»:

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Elegiremos el fichero de certificado autofirmado generado con nuestra aplicación Python certificate.cer (de la carpeta static):

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Pulsaremos en «Importar»:

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Nos indicará que se ha importado un certificado emisor. Pulsaremos «Aceptar»:

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Seleccionaremos el certificado importado (en nuestro caso «Proyecto A») y pulsaremos en el botón «Editar confianza»:

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Marcaremos el check «Utilizar este certificado como raíz de confianza» y pulsaremos «Aceptar»:

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

A partir de ahora Acrobat Reader considerará esta identidad como de confianza y el panel de firma lo mostrará en verde con el mensaje «Firmado y todas las firmas son válidas»:

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Si pulsamos en el panel de firma o en la propia imagen de firma ahora nos mostrará un mensaje indicando: La firma es VÁLIDA, firmada por Proyecto A. No ha havido modificaciones en: documento desde que se firmó. La identidad del firmaten es válida.

Agregar certificado generado a identidades de confianza en Adobe Acrobat Reader

Descarga del fichero con el código fuente completo en Python para firmar documentos PDF

La descarga del fichero firmar_pdf.py con el código fuente completo de la aplicación que genera certificados autofirmados y firma digitalmente con este certificado documentos PDF: