Ir al contenido

Firma Digital

SUNAT exige que todos los documentos electrónicos estén firmados digitalmente con un certificado X.509 válido. openUBL expone un endpoint dedicado para firmar cualquier XML UBL previamente generado.

  • Certificado digital X.509 y clave privada en formato PEM (.crt/.pem + .key/.pem), o
  • Certificado digital en formato PFX/P12 (.pfx o .p12) protegido con su frase de clave.
  • El XML debe seguir la estructura UBL 2.1 de SUNAT

Si posees un certificado en formato .pfx o .p12, también puedes usar la librería core para extraer PEM:

from openubl.signer import load_pfx
with open("certificado.pfx", "rb") as f:
pfx_bytes = f.read()
key_pem, cert_pem = load_pfx(pfx_bytes, password="mi_clave")
Ventana de terminal
POST /api/v1/sign
CampoTipoDescripción
cert_pemstringCertificado X.509 en formato PEM (modo PEM)
key_pemstringClave privada en formato PEM (modo PEM)
pfx_base64stringContenido del archivo PFX/P12 codificado en base64 estándar (modo PFX)
pfx_passwordstringContraseña del archivo PFX/P12 (modo PFX)
xmlstringXML UBL 2.1 a firmar
import requests
with open("certificado.pem", "r") as f:
cert_pem = f.read()
with open("llave_privada.pem", "r") as f:
key_pem = f.read()
xml_generado = "<?xml version='1.0' encoding='UTF-8'?>..."
response = requests.post(
"http://localhost:8000/api/v1/sign",
json={
"cert_pem": cert_pem,
"key_pem": key_pem,
"xml": xml_generado,
},
)
signed_xml = response.json()["signed_xml"]
import base64
import requests
with open("certificado.pfx", "rb") as f:
pfx_base64 = base64.b64encode(f.read()).decode("ascii")
xml_generado = "<?xml version='1.0' encoding='UTF-8'?>..."
response = requests.post(
"http://localhost:8000/api/v1/sign",
json={
"pfx_base64": pfx_base64,
"pfx_password": "mi_clave",
"xml": xml_generado,
},
)
signed_xml = response.json()["signed_xml"]

openUBL firma con XMLDSig (no XAdES-EPES), colocando la firma dentro de ext:UBLExtensions/ext:UBLExtension/ext:ExtensionContent, conforme a la estructura exigida por SUNAT en el Manual del Programador y las Reglas de validación actualizado al 24.04.2026.

Los algoritmos aplicados son los exigidos por la infraestructura de certificación peruana:

ParámetroURI / Valor
Canonicalizaciónhttp://www.w3.org/TR/2001/REC-xml-c14n-20010315 (C14N)
Digesthttp://www.w3.org/2001/04/xmlenc#sha256 (SHA-256)
Firmahttp://www.w3.org/2001/04/xmldsig-more#rsa-sha256 (RSA-SHA-256)
TransformEnveloped Signature
  • RS N.° 300-2014/SUNAT y modificatorias: establecen la estructura XMLDSig y la ubicación de la firma en UBLExtension/ExtensionContent.
  • Resolución de Secretaría N.° 007-2024-PCM/SGTD: aprueba la Directiva N.° 002-2024-PCM/SGTD, que regula el uso de la firma digital en entidades públicas y remite a estándares ETSI y a la Guía de Acreditación de Aplicaciones de Software de la IOFE/INDECOPI.
  • INDECOPI/IOFE — Guía de Acreditación de Entidades de Certificación: exige algoritmos de firma de la familia SHA-2 (RSA-SHA-256/384/512 o ECDSA) para certificados digitales. La política de certificación de Entidades de Certificación acreditadas (2024) ya fija RSA 4096 bits — SHA-256 como configuración mínima.
  1. Genera el XML con el endpoint correspondiente (/invoice/create, /credit-note/create, etc.).
  2. Envía el XML al endpoint /api/v1/sign con tu certificado.
  3. Recibe el XML firmado (signed_xml) listo para enviar a SUNAT. `,