Grupo Sauken S.A. — Manual técnico

Manual de Integración S-FiDE

Sistema de Firma Digital Extendido — todo lo que un integrador necesita: qué hace cada programa, cómo invocarlo, los tres mecanismos de firma disponibles y cuándo usar cada uno, la especialización de comercio exterior ALADI/MERCOSUR, y las especificaciones completas del producto.

Versión del producto: 1.3.0 Documento: 05/09/2026 Licencia: GNU GPL v2+
01

Introducción y filosofía

¿Ya integraste S-FiDE 1.0.0?

Casi todo lo agregado en 1.1.1 es aditivo y no requiere ningún cambio de tu lado — pero hay un puñado de casos puntuales donde cambió el comportamiento de un jar que ya usabas. Antes de actualizar, revisá la Guía de migración desde 1.0.0 al final de la sección 13.

¿Buscás usar la interfaz gráfica?

Este manual está pensado para integradores por línea de comandos. Para operar S-FiDE GUI haciendo clic, con capturas reales de cada pantalla, ver la Guía de Usuario S-FiDE GUI.

S-FiDE (Sistema de Firma Digital Extendido) es una suite de programas Java independientes para firmar y verificar firmas digitales en documentos XML y PDF, y para extraer o inspeccionar certificados digitales desde tokens criptográficos (PKCS#11), archivos PKCS#12 o el almacén de certificados de Windows.

El diseño responde a un principio central: cada capacidad es un programa independiente, invocable por línea de comandos, que cualquier aplicación externa puede ejecutar como proceso hijo sin integrar ninguna librería Java. No existe una "librería S-FiDE" para enlazar — se distribuye como un conjunto de archivos .jar ejecutables, más una interfaz gráfica opcional que orquesta esos mismos programas.

Principios de diseño

  • Contrato uniforme de proceso. Todo se invoca como java -jar Programa.jar <argumentos>. Código de salida 0 = éxito, 1 = error.
  • Salidas separadas y limpias. Resultado normal por stdout, errores por stderr, siempre como texto simple. Nunca un stack trace de Java al usuario final.
  • UTF-8 de punta a punta, en cualquier sistema operativo.
  • Multiplataforma — Windows, Linux y macOS, salvo los dos módulos de almacén de Windows (exclusivos de ese sistema por diseño).
  • La GUI no es un atajo privilegiado. Invoca exactamente los mismos .jar con los mismos argumentos que usaría un integrador externo.
  • Vocabulario de comandos especiales unificado. Todos los módulos aceptan las mismas familias de alias: -version/-v/--version, -ayuda/-h/--help, -licencia/--license. Unificado en 1.1.1 — ver sección 13.
02

Especificaciones técnicas del producto

ÍtemDetalle
Lenguaje / runtimeJava 23 (OpenJDK 23.0.1)
Interfaz gráficaJavaFX 23.0.1 (solo s_fide_gui)
Sistema de buildApache Maven, multi-módulo (14 módulos)
EmpaquetadoJars autocontenidos ("fat jars") — sin classpath externo
Sistemas operativosWindows, GNU/Linux, macOS (64 bits) — CSP/KSP exclusivo de Windows
Arquitectura de CPUx86-64 (64 bits obligatorio)
Requisito mínimo WindowsWindows 10 de 64 bits o superior
Estándares de firmaXML-DSig (XML), CMS/PKCS#7 detached conforme ETSI EN 319 142 (PDF)
Algoritmos al firmarRSA 2048 bits, SHA-256, PKCS#1 v1.5
Algoritmos al verificarSHA-256 y SHA-1 (compatibilidad con firmas de terceros) — sección 7.6
Acceso a hardwarePKCS#11, PKCS#12, CryptoAPI/CNG (CSP/KSP)
Validación de revocaciónOCSP y CRL (requiere Internet para validación completa)
Portable por diseño

La distribución final embebe su propio runtime de Java y su propio SDK de JavaFX — no requiere Java preinstalado en el equipo destino. Puede ejecutarse desde una carpeta portable, incluyendo un pendrive, en un Windows, Linux o macOS "limpios".

Sobre números de versión de estándares

El código de S-FiDE no declara ni verifica una versión puntual de PKCS#11 o PKCS#12 (p. ej. "v2.20"/"v1.1") — se accede vía los proveedores del JDK, cuya conformidad depende del propio OpenJDK. Documentación previa que citaba versiones puntuales no estaba respaldada por el código y fue corregida.

03

Software de terceros y dependencias

ComponenteVersiónUsoLicencia
BouncyCastle1.85Primitivos criptográficos, ASN.1, DigestInfoMIT-like
iText8.0.5Firma y verificación PDFAGPL v3 / comercial
Apache Santuario (xmlsec)4.0.4Soporte de firma XML adicionalApache 2.0
JavaFX23.0.1GUI únicamenteGPLv2 + Classpath Exception
SLF4J2.0.17Fachada de loggingMIT
Logback1.5.18Implementación de loggingEPL 1.0 / LGPL 2.1
Apache Maven3.9.xBuild del proyectoApache 2.0
Compatibilidad de licencias

iText 8.x es AGPL v3 (o comercial). Los fuentes de S-FiDE son GPLv2 "o cualquier versión posterior" — esa cláusula habilita la compatibilidad de combinación con AGPLv3 (§13). No hace falta ningún trámite adicional para usar S-FiDE tal como se distribuye.

04

Licencia de uso

S-FiDE se distribuye bajo la Licencia Pública General GNU (GPL), versión 2 o cualquier versión posterior, publicada por la Free Software Foundation.

  • Es software libre: se puede redistribuir y/o modificar bajo esos términos.
  • Se distribuye con la intención de que sea útil, sin garantía de ningún tipo.
  • Texto completo en el archivo LICENSE.txt de cada módulo, y en gnu.org/licenses/gpl-2.0.html.
  • Copyright © 2024 Juan Carlos Ríos y Juan Ignacio Ríos, Grupo Sauken S.A.
  • El soporte técnico es un servicio con cargo, independiente de la libertad de uso del software.
05

Código fuente y repositorio

Compilar desde el código fuente:

git clone https://github.com/Grupo-Sauken-S-A/S-FIDE.git
cd S-FIDE
./mvnw clean install

Requiere JDK 23 — el proyecto incluye Maven Wrapper, no hace falta Maven instalado aparte. El código fuente completo está disponible conforme a la GPLv2: cualquier integrador puede auditar qué hace cada programa antes de confiar en él para documentos con validez legal.

06

Arquitectura de integración

Aplicación integradora (cualquier lenguaje) java -jar Modulo.jar (proceso independiente) spawn stdout / stderr / exit code S-FiDE GUI (JavaFX, uso manual) spawn (idéntico)

Tanto una aplicación integradora externa como la propia GUI invocan los módulos exactamente igual: como proceso hijo, mismos argumentos, misma salida. No hay una API interna distinta para "uso avanzado" — el contrato de línea de comandos es la API.

Cada módulo recibe sus parámetros por argumentos de línea de comandos (nunca por variables de entorno ni configuración, salvo la excepción documentada de sfide-defaults.properties que usa solo la GUI), realiza su tarea, escribe el resultado en stdout y/o un archivo, y termina con código 0 o 1.

07

Mecanismos de firma digital: PKCS#11, PKCS#12 y Windows CSP/KSP

S-FiDE soporta tres formas distintas de acceder a una clave privada para firmar. Elegir la correcta depende de dónde vive esa clave.

7.1 — PKCS#11 (tokens criptográficos y HSM)

PKCS#11 es un estándar de la industria (OASIS) que define una API en C para que cualquier aplicación hable con un dispositivo criptográfico sin conocer los detalles del fabricante. El fabricante provee una biblioteca dinámica (.dll/.so/.dylib) que la aplicación carga en tiempo de ejecución. En Java esto se hace vía el proveedor SunPKCS11, incluido en el JDK.

Hash interno vs. externo — el detalle que resolvimos en 1.1.1

Un token firma RSA-SHA256 mediante un "mecanismo" (CK_MECHANISM). Existen dos posibles:

  • CKM_SHA256_RSA_PKCS (combinado): el token calcula el hash internamente. Un solo llamado. Los tokens SafeNet/Thales lo soportan.
  • CKM_RSA_PKCS (puro): el token solo aplica padding PKCS#1 v1.5 y la operación RSA — el hash SHA-256 debe calcularlo la aplicación antes, envuelto en una estructura ASN.1 DigestInfo. En teoría, tokens en modo FIPS 140-2 Nivel 3 como el Feitian ePass2003 solo exponen este mecanismo a bajo nivel.

Desde 1.1.1, XMLSignerPKCS11 y PDFSignerPKCS11 prueban el mecanismo combinado primero y, si el token lo rechaza, calculan el hash por software y reintentan — de forma transparente. No hay ningún parámetro para elegir el mecanismo.

Hallazgo con hardware real (2026-08-30)

Contra un Feitian ePass2003 físico, el primer intento (Signature.getInstance("SHA256withRSA", provider)) nunca falló — el fallback externo de S-FiDE nunca se activó. Esto no contradice necesariamente que el token exponga solo CKM_RSA_PKCS a nivel de hardware: el propio SunPKCS11 del JDK puede componer el mecanismo combinado de forma transparente sobre CKM_RSA_PKCS, sin que sea visible desde afuera. Para efectos prácticos — qué camino de código se ejecuta al firmar con S-FiDE — el resultado observado es el mismo que un mecanismo interno nativo, por lo que se documenta como tal en la sección 8. El fallback externo sigue existiendo en el código para el token o middleware que sí lo necesite.

7.2 — PKCS#12 (archivos de certificado)

PKCS#12 es un formato de contenedor de archivo (.p12/.pfx) que empaqueta, cifrado con contraseña, un certificado X.509 junto a su clave privada — sin hardware involucrado.

Ventajas: simple, sin drivers, igual en cualquier SO. Desventajas: la clave es un archivo copiable — la seguridad depende de proteger ese archivo y su contraseña; no aceptable para trámites que exigen hardware homologado FIPS 140-2.

7.3 — Windows CSP/KSP (almacén de certificados de Windows)

En una frase, para quien no conoce PKCS#11: en Windows, la forma más simple de firmar con un token es la misma que usa Adobe Acrobat/Reader por defecto — sin indicar ninguna ruta de biblioteca de fabricante ni saber la marca/modelo exacto del token. Es lo mismo que ve un usuario al abrir el Administrador de certificados de Windows (certmgr.msc) y encontrar su certificado ya listo para usar: Acrobat, y ahora S-FiDE, lo leen directamente de ese mismo lugar.

Recomendación práctica

Si no conocés con exactitud el nombre de archivo de la biblioteca PKCS#11 de tu token, ni su marca/modelo, probá primero con CSP/KSP (XMLSignerWindowsCSP/PDFSignerWindowsCSP, secciones 9.11/9.12) antes de buscar esa información para usar los módulos PKCS#11. Es la ruta con menos pasos de configuración siempre que el certificado ya sea visible en Windows — el caso más común una vez instalado el driver del fabricante. Esta recomendación aplica a firma ocasional, con una persona presente frente al equipo — el mismo uso que le das a Adobe Acrobat. Si necesitás firmar muchos documentos por lote sin intervención humana, leé la advertencia siguiente antes de elegir CSP/KSP.

Cómo funciona, en detalle: además de PKCS#11, Windows ofrece un mecanismo nativo del sistema operativo: CryptoAPI (CAPI, legado) y su sucesor CNG, vía CSP o KSP respectivamente. Los fabricantes de tokens suelen instalar, además de PKCS#11, un minidriver CSP/KSP certificado por Microsoft — el certificado aparece automáticamente en el almacén de certificados de Windows, sin que ninguna aplicación deba configurar una ruta de biblioteca.

S-FiDE incorpora esta alternativa vía XMLSignerWindowsCSP y PDFSignerWindowsCSP, usando SunMSCAPI para acceder al almacén Windows-MY. En vez de una biblioteca .dll y un número de slot, estos dos módulos piden un alias o fragmento del nombre del titular del certificado (-listar-certificados muestra qué hay disponible). No se pasa contraseña — el acceso lo administra Windows (puede pedir el PIN con un diálogo nativo al momento de firmar), a diferencia de los módulos PKCS#11, donde el PIN se pasa como argumento del programa.

⚠️ Limitación crítica — CSP/KSP no sirve para firma desatendida por lotes

Esto no es un mal funcionamiento ni una limitación de S-FiDE: es una estrategia de seguridad distinta, diseñada así deliberadamente por Windows. Es importante entenderla bien antes de elegir CSP/KSP para integrar un flujo automatizado (por ejemplo, firmar 100 XML o PDF por línea de comandos, sin que haya una persona presente frente a cada firma).

La diferencia de fondo entre PKCS#11 y CSP/KSP:

  • PKCS#11 fue diseñado para que la aplicación controle la autenticación: el estándar define una función (C_Login) a la que la aplicación le pasa el PIN explícitamente. Por eso XMLSignerPKCS11/PDFSignerPKCS11 reciben la contraseña como argumento de línea de comandos y nunca aparece ningún diálogo — todo ocurre de forma programática, sin intervención humana.
  • CSP/KSP (CryptoAPI/CNG) tiene el diseño opuesto, y es intencional: Microsoft construyó estas interfaces para que el acceso a la clave privada quede bajo control exclusivo del proveedor criptográfico (el driver del token), no de la aplicación que pide firmar. La idea es que ninguna aplicación de terceros pueda leer o inyectar un PIN de forma silenciosa — eso es, para Windows, una protección de seguridad, no una carencia.

Por qué S-FiDE no puede evitar el diálogo: el proveedor SunMSCAPI del JDK, para el almacén Windows-MY, no acepta ninguna contraseña — su KeyStore.load() se invoca siempre con null. No es que falte implementar un parámetro: la propia API de Java para este mecanismo no tiene ningún punto de entrada para pasar un PIN. El diálogo lo dispara Windows (CryptoAPI/CNG) al usar la clave privada, completamente fuera del control de cualquier aplicación — ni S-FiDE, ni Acrobat, ni ninguna otra.

Por qué a veces pide el PIN una sola vez y otras veces en cada firma: depende de un ajuste llamado Strong Private Key Protection, definido al aprovisionar el certificado en el token (no es una configuración de S-FiDE ni de Windows en general):

  • Sin protección extra: el driver cachea el PIN durante la sesión y no lo vuelve a pedir por un rato.
  • "Preguntar una vez por sesión": pide el PIN la primera vez y lo reutiliza mientras el token siga conectado.
  • "Preguntar siempre": exige el diálogo en cada operación de firma, sin excepción — ninguna aplicación puede evitarlo, es una política del propio certificado/token. Muchos certificados de firma digital argentinos vienen aprovisionados así, precisamente para que cada firma sea un acto consciente del firmante.

El diseño de S-FiDE agrava el problema en el peor caso: cada invocación de java -jar XMLSignerWindowsCSP.jar/PDFSignerWindowsCSP.jar es un proceso nuevo (por diseño — "cada capacidad es un programa independiente", sección 1). Aunque el driver del token cachee el PIN a nivel de sesión, ese caché muchas veces queda atado al proceso que lo abrió, no al token físico — firmar 100 documentos con 100 invocaciones separadas puede disparar 100 diálogos, incluso en un token configurado como "una vez por sesión".

Conclusión — cuándo usar cada mecanismo: CSP/KSP sirve para firma interactiva y ocasional, con una persona presente frente al diálogo — el mismo escenario en el que usás Adobe Acrobat. Para integración end-to-end por lotes (firmar muchos documentos por CLI sin intervención humana), usá XMLSignerPKCS11/PDFSignerPKCS11 (PIN por argumento, cero diálogos) o XMLSignerPKCS12/PDFSignerPKCS12 (contraseña de archivo, sin token ni diálogo alguno). Ver la fila correspondiente en la tabla comparativa de la sección 7.4.

Limitación conocida (técnica)

SunMSCAPI habla CryptoAPI legado, no CNG moderno directamente — funciona porque Windows tiende un puente CAPI↔KSP automático. La actualización de Windows de octubre 2025 (KB5066835) empuja el ecosistema hacia KSP puro, así que ese puente podría no cubrir todos los tokens en el futuro.

7.4 — Comparación

PKCS#11PKCS#12Windows CSP/KSP
Dónde vive la claveHardwareArchivo cifradoHardware o software, vía almacén
MultiplataformaNo
Configurar ruta de driverNo aplicaNo
Contraseña por el programaSí (PIN)No
Apto para firma desatendida por lotesNo — puede pedir el PIN por diálogo en cada documento, sin forma de evitarlo (ver sección 7.3)
Seguridad típicaAlta (FIPS 140-2/3)Según protección del archivoIgual al hardware subyacente
Recomendado paraUso regulado (AC-ONTI)Pruebas, servidorNo conocer marca/modelo del token o el nombre de su biblioteca PKCS#11; simplicidad sobre portabilidad

7.5 — Validación de revocación: OCSP y CRL

Un certificado puede ser matemáticamente válido (no vencido, cadena de confianza correcta) y sin embargo haber sido revocado por su emisor — por ejemplo, porque el token fue robado o la clave se vio comprometida. La única forma de saberlo es consultar a la autoridad certificante; no hay manera de verificar esto sin conexión.

Al verificar una firma, XMLVerifySignatures y PDFVerifySignatures intentan dos mecanismos, en este orden:

  1. OCSP (Online Certificate Status Protocol): consulta en tiempo real al respondedor de la autoridad certificante — su URL está publicada dentro del propio certificado (extensión Authority Information Access). S-FiDE arma una solicitud identificando el certificado por su número de serie, y la autoridad responde indicando si está vigente o revocado. Es el mecanismo más preciso, refleja el estado en el instante exacto de la consulta.
  2. CRL (Certificate Revocation List): si OCSP no responde o el resultado es indeterminado, se recurre a la lista de revocados que la autoridad publica periódicamente (URL también en el certificado, extensión CRL Distribution Point). Menos preciso — puede no reflejar una revocación muy reciente — pero funciona aunque el respondedor OCSP puntual esté caído.

Tiempos de espera exactos (verificados en el código): la comprobación de conectividad usa un socket de prueba con 3 segundos de espera; las consultas HTTP a OCSP y CRL usan 5 segundos de espera de conexión cada una.

Si ninguno responde, o no hay URLs de OCSP/CRL en el certificado, el estado queda "No verificable" — esto no invalida la firma: integridad criptográfica y revocación son dos verificaciones independientes. Un documento puede salir VÁLIDO con revocación "No verificable": la firma es genuina, solo que no se pudo confirmar en ese momento que el certificado siga vigente.

Por qué hace falta Internet

Tanto la URL de OCSP como la de CRL son direcciones de la autoridad certificante en Internet. Sin conexión, ninguno de los dos mecanismos puede completarse. Un certificado de prueba autofirmado (sin autoridad certificante real) siempre da "No verificable — Sin URLs de OCSP/CRL", porque nunca declaró esas extensiones.

Fecha usada para evaluar la revocación en XML. Por defecto, XMLVerifySignatures usa la fecha y hora actual del sistema para decidir si una revocación es anterior o posterior a la firma — con una excepción deliberada para documentos ALADI/MERCOSUR, ver sección 10.

Fecha usada para evaluar la revocación en PDF — de dónde sale exactamente, verificado contra el bytecode real de iText 8.0.5. PDFVerifySignatures usa PdfPKCS7.getSignDate() como fecha de referencia. Tiene dos fuentes posibles, en este orden de prioridad:

  1. Un sello de tiempo RFC 3161 (TSA) embebido en la firma, si existe — una fecha certificada por una autoridad de sellado de tiempo independiente, no por el propio firmante.
  2. El campo /M del diccionario de firma del PDF, si no hay sello de tiempo. Lo escribe la propia aplicación firmante con la hora de su reloj de sistema al firmar (SignatureUtil.readSignatureData() lo lee vía PdfSignature.getDate() y PdfDate.decode(...)). Queda dentro del rango de bytes cubierto por la firma — no se puede alterar después sin invalidarla — pero es un dato autodeclarado por el firmante, no verificado por ningún tercero.
Ningún firmador de S-FiDE solicita sello de tiempo TSA

PDFSignerPKCS11, PDFSignerPKCS12 y PDFSignerWindowsCSP nunca piden un TSA al firmar. Para cualquier PDF firmado por S-FiDE, getSignDate() siempre recae en la opción 2: la hora del reloj local del equipo que firmó, autodeclarada. Es una diferencia real de robustez frente a XML/COD/DJO, donde la fecha de referencia sale de un dato del propio documento de negocio (sección 10) en vez de depender del reloj del equipo firmante.

Por qué un certificado revocado invalida la firma, en términos simples: la revocación significa que la autoridad certificante retiró la confianza en ese certificado — por ejemplo, porque la clave privada se filtró o el titular dejó de estar habilitado — después de haberlo emitido. Que la firma sea criptográficamente correcta solo demuestra que el documento no fue alterado y que fue producido con esa clave privada; no demuestra que esa clave siga siendo confiable. Por eso XMLVerifySignatures marca como INVÁLIDA cualquier firma cuyo certificado figure como revocado en el momento correspondiente, y lo informa explícitamente: "El certificado fue revocado por su autoridad certificante. Aunque la firma es criptográficamente correcta, esta firma se considera INVÁLIDA por ese motivo."

7.5.1 — Validación de revocación antes de firmar

Desde la versión 1.2.0, los seis módulos que aplican una firma digital (XMLSignerPKCS11, XMLSignerPKCS12, XMLSignerWindowsCSP, PDFSignerPKCS11, PDFSignerPKCS12, PDFSignerWindowsCSP) validan el estado de revocación del certificado antes de firmar, no solo después. Usa exactamente el mismo mecanismo y el mismo orden de la sección 7.5 — OCSP primero, CRL como respaldo — con una sola diferencia: la fecha de referencia es siempre el instante actual, ya que todavía no existe ningún documento firmado del cual extraer una fecha.

ResultadoComportamiento
No revocadoSe informa por consola y se firma con normalidad.
No se pudo determinar (sin Internet, sin URL de OCSP/CRL, o falló la consulta)Se informa una advertencia y se firma igual — nunca bloquea por falta de conectividad, mismo criterio que la verificación.
RevocadoNo se firma. Se informa el motivo y el programa termina con código de salida 1, sin generar ningún archivo firmado.

Flag -omitir-revocacion true: disponible en los seis módulos, por defecto false. Si se indica true, fuerza la firma incluso si el certificado está confirmado como revocado — pensado para un caso de uso legítimo puntual o para no romper una automatización existente. Su uso queda registrado en la propia línea de comando ejecutada; el mensaje de advertencia siempre deja explícito que se forzó.

Comportamiento distinto en la interfaz gráfica, en los módulos PKCS#12 y Windows CSP/KSP. La CLI nunca pregunta nada — firma en silencio ante "no se pudo determinar", pensado para automatización desatendida. La GUI, en cambio, siempre tiene un usuario presente en tiempo real: en XMLSignerPKCS12, PDFSignerPKCS12, XMLSignerWindowsCSP y PDFSignerWindowsCSP, antes de firmar consulta el estado con un nuevo modo de solo lectura (-verificar-revocacion <credenciales>, sin tocar el documento) y decide: si no está revocado, firma directo; si no se pudo determinar, muestra un diálogo "¿Desea firmar de todas formas?" (Sí firma, Cancelar no firma nada); si está confirmado revocado, nunca firma y no hay diálogo — no hay forma de forzarlo desde la GUI.

XMLSignerPKCS11/PDFSignerPKCS11 quedan fuera de este comportamiento

Mantienen el criterio silencioso de la CLI, sin diálogo. Motivo: la consulta de solo lectura para estos dos módulos igual exige cargar el KeyStore PKCS#11 con la contraseña, es decir, ingresar el PIN al token — hacerlo una vez para consultar y otra para firmar significaría dos intentos de acceso por cada firma, un riesgo real de inhabilitación que no existe en PKCS#12 (archivo local) ni en Windows CSP/KSP (la consulta no necesita la clave privada).

Limitación conocida, heredada del mismo mecanismo de los verificadores

La búsqueda del certificado emisor (necesaria para armar la consulta OCSP) solo revisa el truststore estándar del JDK (cacerts), que normalmente contiene certificados raíz, no los intermedios que en la práctica firman la mayoría de los certificados de usuario final. Si el emisor directo no está en cacerts, la consulta OCSP no puede armarse y el resultado cae en "no se pudo determinar" (se firma igual). Es la misma limitación que ya tienen XMLVerifySignatures/PDFVerifySignatures desde siempre — no es un defecto nuevo, es un límite del mecanismo reutilizado tal cual estaba definido.

Corrección (1.2.0)

Al poco de publicarse esta funcionalidad se detectó, con hardware real (token ePass2004 y un certificado real de AC-ONTI), que la validación siempre caía en "no se pudo determinar" — incluso con certificados vigentes y no revocados, que XMLVerifySignatures sí validaba correctamente por OCSP sobre el mismo certificado. La causa: BouncyCastle a veces extrae la URL de OCSP/CRL con un prefijo literal [CONTEXT N] pegado adelante (una particularidad de ciertas codificaciones ASN.1 con tag implícito); sin quitarlo, la URL queda inválida y la consulta HTTP falla antes de llegar al servidor. XMLVerifySignatures/PDFVerifySignatures ya sabían limpiar ese prefijo desde siempre; se había perdido al reutilizar esa lógica para validar antes de firmar. Corregido restaurando el saneo en los seis módulos firmadores — verificado de nuevo con el mismo token real, ahora informa correctamente el estado GOOD.

7.6 — Compatibilidad con firmas SHA-1 de aplicaciones de terceros

S-FiDE firma exclusivamente con SHA-256 — es una decisión deliberada, SHA-1 se considera criptográficamente débil para firmar documentos nuevos. Sus verificadores, en cambio, están diseñados para validar cualquier firma conforme al estándar, sin importar qué aplicación la generó ni con qué algoritmo de hash — incluyendo firmas SHA-1 de software de terceros ya discontinuado.

  • XML (XMLVerifySignatures, XMLVerifyXSDStructure): deshabilitan explícitamente el modo "validación segura" de JSR-105 (secureValidation = false), que de lo contrario rechazaría de plano cualquier firma SHA-1. Ambos reconocen rsa-sha1 y rsa-sha256.
  • PDF (PDFVerifySignatures): verifica vía PdfPKCS7.verifySignatureIntegrityAndAuthenticity() de iText, sin restricción de algoritmo — el algoritmo se informa de manera descriptiva pero nunca se usa como criterio de rechazo.
Corrección (1.1.1)

El campo "Algoritmo de firma" de PDFVerifySignatures informaba antes el algoritmo con el que la CA firmó el certificado del firmante, no el de la firma del documento en sí — dos datos que solo coinciden cuando la CA usa el mismo algoritmo que la firma. Ahora se calcula a partir de la firma real leída del PDF. Es un campo puramente informativo: nunca afectó el resultado DOCUMENTO VÁLIDO/INVÁLIDO.

Propiedad intencional, a preservar

Esta capacidad de verificar SHA-1 es independiente de qué algoritmos usan los propios firmadores de S-FiDE para producir firmas nuevas. El rol de S-FiDE como verificador es validar lo que ya fue firmado, sin importar antigüedad ni herramienta de origen.

Por qué esto es especialmente relevante para COD y DJO (sección 10): en la práctica, los elementos COD/CODEH/DJO/DJOEH de un mismo documento a veces se firman con software de distintas empresas — un exportador puede usar S-FiDE mientras que la Entidad Habilitada usa otra aplicación (o viceversa), y esas otras aplicaciones pueden seguir usando SHA-1. XMLVerifySignatures tiene que poder validar ambas firmas del mismo documento sin importar cuál de las dos las generó ni con qué algoritmo — es exactamente el escenario que este soporte está pensado para cubrir.

08

Catálogo de tokens y drivers soportados

Cualquier token PKCS#11 es utilizable. La siguiente tabla —fuente única en shared-resources/token-profiles.txt— documenta los modelos del ecosistema AC-ONTI argentino:

Marca / ModeloWindowsHashEstado
SafeNet/Thales eToken 5110/5110+eTPKCS11.dllInternoVigente — recomendado
Feitian ePass2003eps2003csp11.dllInterno (confirmado)Vigente — reemplazo estándar SCBA
mToken CryptoID nueva (140-3)lm_cryptoide_pkcs11.dllInterno (confirmado)Válido solo variante 140-3
mToken CryptoID vieja (140-2)cryptoide_pkcs11.dllExterno (sin confirmar)Discontinuado
Athena IDProtect/ASECardasepkcs.dllDesconocidoDiscontinuado, en retiro
OpenSC (genérico)opensc-pkcs11.dllDepende del tokenDriver de respaldo

Hardware validado end-to-end

Modelos efectivamente probados por Grupo Sauken S.A. contra el dispositivo físico real (no solo software/simulación), cubriendo el ciclo completo firma → verificación:

ModeloFechaMódulos probadosResultado
SafeNet/Thales eToken 5110+ (Nivel 3)2026-08Los 9 módulos que tocan certificados (PKCS#11, PKCS#12 y Windows CSP/KSP × XML/PDF × firmar/verificar)Correcto en todos los casos
mToken CryptoID nueva (Century Longmai/Macroseguridad, FIPS 140-3)2026-08TokenSlotsView, TokenCertificateExtractor, XMLSignerPKCS11 + XMLVerifySignatures (integridad y OCSP), PDFSignerPKCS11 + PDFVerifySignatures (integridad y OCSP), XMLSignerWindowsCSP, PDFSignerWindowsCSPCorrecto en todos los casos; hash confirmado como interno
Feitian ePass2003 (FIPS 140-2 Nivel 3)2026-08TokenSlotsView, TokenCertificateExtractor, XMLSignerPKCS11 + XMLVerifySignatures (integridad y OCSP), PDFSignerPKCS11 + PDFVerifySignatures (integridad y OCSP), XMLSignerWindowsCSP, PDFSignerWindowsCSPCorrecto en todos los casos; el mecanismo combinado funcionó directamente, el fallback externo nunca se activó

Un modelo que no figura en esta tabla no está descartado — solo no fue probado todavía contra hardware físico por Grupo Sauken S.A. El catálogo de arriba sigue siendo válido como guía general para cualquier token PKCS#11 conforme al estándar, esté o no en esta lista.

Ayuda de selección de driver

  • GUI: combo de marca/modelo + botón "Detectar automáticamente" (revisa qué rutas de la tabla existen en el equipo).
  • CLI: comando -listar-drivers (también aceptado como --listar-drivers) en TokenSlotsView, TokenCertificateExtractor, XMLSignerPKCS11 y PDFSignerPKCS11.
Solo un hint de UX

Esta detección nunca es la única fuente de verdad — el nombre de archivo puede cambiar entre versiones de middleware. El código de firma siempre reintenta en tiempo de ejecución según lo que el token realmente responde (sección 7.1).

09

Catálogo de aplicaciones

Convenciones comunes: código de salida 0 éxito / 1 error (salvo aclaración); todas leen y escriben en UTF-8; los comandos -version/-v/--version, -ayuda/-h/--help y -licencia/--license son idénticos en los 13 módulos de línea de comandos desde 1.1.1.

Qué significa exactamente el "número de slot"

Aplica a TokenSlotsView, TokenCertificateExtractor, XMLSignerPKCS11 y PDFSignerPKCS11. PKCS#11 tiene dos numeraciones de slot distintas y no intercambiables: el CK_SLOT_ID crudo que asigna el driver del fabricante (opaco, no necesariamente pequeño ni secuencial) y el slotListIndex, la posición del slot dentro de la lista que devuelve la biblioteca, siempre empezando en 0. S-FiDE usa exclusivamente slotListIndex en los cuatro módulos — es también el criterio que usa por defecto TokenSlotsView. En la mayoría de los tokens (SafeNet) ambas numeraciones coinciden y la distinción pasa inadvertida, pero con middleware que asigna CK_SLOT_ID no secuenciales (confirmado con el mToken CryptoID de Century Longmai/Macroseguridad) el número que muestra TokenSlotsView es el que hay que usar en los otros módulos — no corresponde tomar un "número de slot" de ninguna herramienta del fabricante, que puede estar mostrando el CK_SLOT_ID, un número distinto.

Rutas de biblioteca con espacios (p. ej. C:\Program Files (x86)\...)

Los cuatro módulos las aceptan sin que el integrador deba agregar comillas — la conversión necesaria (barra invertida a barra normal, y encomillado interno antes de pasarla al proveedor SunPKCS11) la hace el propio programa. Manejo uniforme en Windows/Linux/macOS.

9.1 — TokenSlotsView

TokenSlotsView.jar

Visualiza los slots disponibles en un token PKCS#11 y la información de certificados/claves en cada uno. Primera herramienta a usar frente a un token nuevo.

Sintaxis
java -jar TokenSlotsView.jar <biblioteca PKCS#11> <contraseña>
java -jar TokenSlotsView.jar [-version | -ayuda | -licencia | -listar-drivers]
ParámetroObligatorioDescripción
Ruta de biblioteca PKCS#11Ruta absoluta o relativa al .dll/.so/.dylib del fabricante
Contraseña del tokenPIN de usuario del dispositivo
Validaciones

Distingue entradas "Clave Privada" de "Certificado" (KeyStore.isKeyEntry/isCertificateEntry); reporta sujeto, emisor, validez y número de serie de certificados X.509.

Salida

Imprime el slotListIndex usado (siempre 0, es el único slot al que este módulo se conecta) y, por cada alias encontrado dentro de ese slot, su tipo, sujeto, emisor, validez y número de serie. Si hay más de un alias, cada uno se numera como "Entrada" — identifica la entrada dentro del slot, no es un número de slot adicional.

Errores posibles

El archivo de la biblioteca PKCS#11 no existe · El proveedor SunPKCS11 no está disponible · Contraseña incorrecta o error al acceder al token · Error al leer el token

Nota sobre exit code

Ejecutarlo sin argumentos muestra la ayuda y termina con código 1 — a diferencia de invocar -ayuda explícitamente, que termina en 0.

Ejemplo
java -jar TokenSlotsView.jar C:\Windows\System32\eTPKCS11.dll "MiPIN123"

9.2 — TokenCertificateExtractor

TokenCertificateExtractor.jar

Extrae el certificado de un slot específico de un token PKCS#11 y lo exporta como .pem.

Sintaxis
java -jar TokenCertificateExtractor.jar <biblioteca PKCS#11> <contraseña> <slot>
java -jar TokenCertificateExtractor.jar [-version | -ayuda | -licencia | -listar-drivers]
ParámetroObligatorioDescripción
Ruta de biblioteca PKCS#11Ídem TokenSlotsView
Contraseña del tokenPIN de usuario
Número de slotEntero; ver TokenSlotsView para conocerlo
Salida

Por consola: Sujeto, Emisor, Número de Serie, Válido desde/hasta, Algoritmo de Firma. Archivo <CN>.pem en el directorio de trabajo (nombre derivado del CN= del sujeto, caracteres no alfanuméricos reemplazados por _).

Errores posibles

Proveedor SunPKCS11 no disponible · Error al cargar el almacén de claves · El número de slot debe ser un número entero · No se encontró ningún certificado en el slot [n]

Ejemplo
java -jar TokenCertificateExtractor.jar C:\Windows\System32\eTPKCS11.dll "MiPIN123" 0

9.3 — PKCS12CertificateExtractor

PKCS12CertificateExtractor.jar

Equivalente al anterior, para archivos PKCS#12 — sin hardware. No aplica -listar-drivers.

Sintaxis
java -jar PKCS12CertificateExtractor.jar <archivo.p12> <password>
java -jar PKCS12CertificateExtractor.jar [-version | -ayuda | -licencia]
ParámetroObligatorioDescripción
Archivo PKCS#12Ruta al archivo .p12/.pfx
ContraseñaContraseña del archivo PKCS#12
Errores posibles

El archivo no es un PKCS#12 válido o la contraseña es incorrecta · No se encontró ningún certificado X.509 en el archivo

Ejemplo
java -jar PKCS12CertificateExtractor.jar C:\certificados\empresa.pfx "MiContraseña123"

Reglas de firma comunes a los tres firmadores XML

XMLSignerPKCS11, XMLSignerPKCS12 y XMLSignerWindowsCSP aplican, antes de firmar, dos controles obligatorios:

  1. Nunca firmar un elemento que ya tiene una firma digital aplicada — vale para cualquier XML genérico, no solo los especializados de comercio exterior. Si el elemento indicado (o el documento completo, con "") ya tiene una <ds:Signature> cuya Reference apunta a él, el programa rechaza la operación sin modificar el archivo.
  2. Regla de orden para CODEH/DJOEH (sección 10): no se puede firmar CODEH sin una firma previa sobre COD, ni firmar DJOEH sin una firma previa sobre DJO.

Ambos controles buscan <ds:Signature>/<ds:Reference> existentes en el documento — no vuelven a verificar criptográficamente la firma previa, solo confirman que existe.

Mensajes de error

El elemento '[id]' ya tiene una firma digital aplicada. No se puede firmar el mismo elemento dos veces. · El documento ya tiene una firma digital aplicada sobre todo su contenido... (con elemento vacío) · No se puede firmar el elemento CODEH: no existe una firma digital previa sobre el elemento COD. · No se puede firmar el elemento DJOEH: no existe una firma digital previa sobre el elemento DJO.

9.4 — XMLSignerPKCS11

XMLSignerPKCS11.jar

Firma un XML (completo o un elemento por su atributo Id) con un token PKCS#11. XML-DSig con canonicalización inclusiva y RSA-SHA256, con resolución automática del mecanismo de hash (sección 7.1).

Sintaxis
java -jar XMLSignerPKCS11.jar <biblioteca> <contraseña> <slot> <archivo.xml> <elemento> [-omitir-revocacion true|false]
java -jar XMLSignerPKCS11.jar [-version | -ayuda | -licencia | -listar-drivers]

Antes de firmar, valida el estado de revocación del certificado — ver sección 7.5.1. No firma si está confirmado como revocado, salvo -omitir-revocacion true.

ParámetroObligatorioDescripción
Biblioteca PKCS#11Ruta al driver del token
ContraseñaPIN del token
Número de slotEntero
Archivo XMLRuta al XML a firmar
Elemento a firmarSí (puede ser "")Vacío firma todo el documento (estándar XML-DSig). No vacío firma ese elemento embebido por Id/id/ID. COD/CODEH/DJO/DJOEH tienen además significado especializado — sección 10
Salida

Archivo <nombre>-signed.xml.

Errores posibles

El elemento o párrafo XML especificado no existe · Contraseña incorrecta · El token no admite ningún mecanismo de firma RSA-SHA256 compatible · más las reglas de firma comunes y las reglas de comercio exterior (sección 10.5)

Ejemplo
java -jar XMLSignerPKCS11.jar C:\Windows\System32\eTPKCS11.dll "MiPIN123" 0 C:\docs\certificado-origen.xml COD

9.5 — XMLSignerPKCS12

XMLSignerPKCS12.jar

Idéntico al anterior en funcionalidad y configuración criptográfica, usando un archivo PKCS#12. No aplica -listar-drivers.

Sintaxis
java -jar XMLSignerPKCS12.jar <certificado.p12> <password> <archivo.xml> <elemento> [-omitir-revocacion true|false]
java -jar XMLSignerPKCS12.jar [-version | -ayuda | -licencia]

Antes de firmar, valida el estado de revocación del certificado — ver sección 7.5.1. No firma si está confirmado como revocado, salvo -omitir-revocacion true.

ParámetroObligatorioDescripción
Archivo PKCS#12Ruta al certificado .p12/.pfx
ContraseñaContraseña del certificado
Archivo XMLRuta al XML a firmar
Elemento a firmarSí (puede ser "")Mismas reglas que XMLSignerPKCS11, incluida la especialización ALADI/MERCOSUR (sección 10)
Errores posibles

El archivo PKCS#12 no existe · El elemento o párrafo XML especificado no existe en el documento XML · más las reglas de firma comunes y las reglas de comercio exterior (sección 10.5)

Ejemplo
java -jar XMLSignerPKCS12.jar C:\certificados\empresa.pfx "MiContraseña123" C:\docs\declaracion.xml DJO

9.6 — XMLVerifySignatures

XMLVerifySignatures.jar

Verifica integridad, validez de certificado y revocación (OCSP/CRL) de las firmas de un XML. Acepta RSA-SHA256 y RSA-SHA1 de cualquier aplicación conforme a XML-DSig (sección 7.6).

Sintaxis
java -jar XMLVerifySignatures.jar <archivo.xml> [-simple]
java -jar XMLVerifySignatures.jar [-version | -ayuda | -licencia]
ParámetroObligatorioDescripción
Archivo XMLRuta al XML firmado a verificar
-simpleNoReduce el detalle de la salida
Validaciones

Integridad de cada Reference, estado del certificado, revocación OCSP→CRL. Trata como no confiable cualquier certificado con emisor vacío o que contenga "self signed"/"localhost". Para COD/CODEH/DJO/DJOEH, usa la fecha real del documento para la revocación (sección 10).

Salida por firma

Un "Estado (integridad criptográfica, sin considerar revocación)" — calculado antes del chequeo de revocación, por eso etiquetado así explícitamente — y, al final, un "Estado final de la firma #N" que sí combina integridad criptográfica y revocación; es este último el que determina el resultado consolidado del documento. Si la causa específica es un certificado revocado, lo indica: INVÁLIDA (certificado revocado — ver detalle arriba).

Código de salida especial

A diferencia de los firmadores, acá el exit code refleja el resultado de la validación: 0 si todas las firmas son válidas, 1 si alguna no lo es o si el proceso no pudo completarse (mismo código para ambos casos).

Ejemplo
java -jar XMLVerifySignatures.jar C:\docs\certificado-origen-signed.xml
java -jar XMLVerifySignatures.jar C:\docs\certificado-origen-signed.xml -simple

9.7 — XMLVerifyXSDStructure

XMLVerifyXSDStructure.jar

Valida que un XML cumpla la estructura definida por un esquema XSD (tipos, elementos obligatorios/opcionales, cardinalidad) y además verifica sus firmas (SHA-256 y SHA-1, igual que XMLVerifySignatures).

ParámetroObligatorioDescripción
Archivo XMLRuta al XML a validar
Archivo XSDNoEsquema local; si se omite, se busca y descarga automáticamente el referenciado dentro del propio XML
¿Es obligatorio un XSD externo?

No. Busca automáticamente una referencia al esquema dentro del propio XML — primero xsi:schemaLocation, luego xsi:noNamespaceSchemaLocation. Si encuentra una URL ahí, la descarga sola (requiere Internet, con reintento automático httphttps).

¿Puedo indicar un XSD propio?

Sí, como segundo argumento — para validar contra una versión local sin depender de Internet, o si el XML no declara ninguno. Si el nombre no coincide con el referenciado en el XML, avisa (no es un error) y usa el indicado:

NOTA: Diferencia en nombres de archivo XSD
├─ XSD referenciado en XML: esquema-v2.xsd
├─ XSD proporcionado: esquema-v1-local.xsd
└─ Se utilizará el archivo proporcionado: esquema-v1-local.xsd
Qué se valida

Dos pasos independientes, ambos deben pasar: (1) estructura contra el XSD, usando XML Schema 1.0 — no 1.1; (2) firmas digitales del documento (integridad y certificado, sin restricción de algoritmo de hash).

No valida revocación

A diferencia de XMLVerifySignatures, lo indica explícitamente al finalizar: "Este proceso no realiza validación de revocación de las firmas digitales aplicadas". Para confirmar que el certificado no fue revocado (sección 7.5), hay que correr además XMLVerifySignatures.

Acceso externo habilitado para poder descargar XSD

Para resolver esquemas remotos, este módulo habilita explícitamente el acceso externo a DTD/esquema (accessExternalSchema/accessExternalDTD = "all") a nivel de proceso. No aplica el bloqueo estricto de entidades externas de un parser endurecido por defecto — no usarlo contra XML de origen no confiable sin las debidas precauciones de red.

Dominio espejo para esquemas ALADI (COD/DJO) caídos

El dominio oficial de ALADI (https://www.codaladi.org/directorio/..., usado en los xsi:schemaLocation de Certificados de Origen y Declaraciones Juradas de Origen) suele estar inoperativo. Cuando el esquema se resuelve automáticamente desde el XML (nunca si se indicó un archivo XSD local) y la descarga desde codaladi.org falla — por error de red/TLS, o porque lo devuelto no es un XSD válido (p. ej. una redirección HTTP→HTTPS entre protocolos que Java no sigue sola, descargando una página de error en vez del esquema) — el módulo reintenta automáticamente contra un espejo secundario, manteniendo el nombre de archivo intacto: reemplaza https://www.codaladi.org/directorio/ por https://cod.certificadoorigen.com.ar/. Antes de reintentar, informa: "El dominio ALADI https://www.codaladi.org/ no está operativo. Se usará el dominio secundario https://cod.certificadoorigen.com.ar/ para completar la operación." Si el espejo tampoco responde, ahí sí se informa el error final.

Sintaxis
java -jar XMLVerifyXSDStructure.jar <archivo.xml> [esquema.xsd]
java -jar XMLVerifyXSDStructure.jar [-version | -ayuda | -licencia]
Errores posibles

El archivo XML no existe · Error al descargar el XSD · El contenido descargado no es un esquema XSD válido (¿redirección, página de error, o dominio inoperativo?) · No se encontró referencia a esquema XSD en el XML y no se proporcionó archivo XSD

Ejemplo
java -jar XMLVerifyXSDStructure.jar C:\docs\certificado-origen.xml
java -jar XMLVerifyXSDStructure.jar C:\docs\certificado-origen.xml C:\xsd\esquema-v2.xsd

Opciones específicas de los firmadores de PDF

PDFSignerPKCS11, PDFSignerPKCS12 y PDFSignerWindowsCSP comparten estas opciones, sin equivalente en los firmadores de XML — un XML no tiene "apariencia visual" ni concepto de página.

  • Firma visible vs. invisible. Sin -x/-y (o en 0), la firma es igual de válida criptográficamente pero no se dibuja nada. Con coordenadas, se dibuja un recuadro con firmante, fecha y el texto de -t si se indicó.
  • Sistema de coordenadas. PDF usa el estándar PostScript: origen (0,0) en la esquina inferior izquierda de la página, X crece a la derecha, Y crece hacia arriba. -x/-y ubican la esquina inferior izquierda del recuadro (160×70 puntos, tamaño fijo) — no es "de abajo a la derecha", es de abajo a la izquierda. 1 punto PDF = 1/72 de pulgada. Siempre en la página 1.
  • Texto personalizado (-t). Se agrega debajo del nombre y la fecha, dentro del mismo recuadro. Sin efecto si la firma es invisible.
  • Bloquear el documento (-k/-l true, según el módulo). Dos efectos, siempre acoplados desde 1.1.1: (1) marca la firma como certificante (permiso PDF DocMDP = "sin cambios permitidos" — solo puede haber una por documento, y debe ser la primera), y (2) cifra el PDF en AES-256 restringiendo permisos a solo impresión y lectores de pantalla.
  • Validación de firmas preexistentes. Los tres firmadores verifican, antes de firmar, que cualquier firma ya presente sea íntegra — si no lo es, no se modifica el archivo.
Corrección de consistencia — 1.1.1

Antes, PDFSignerPKCS12 solo aplicaba la certificación DocMDP si además la firma era visible; con firma invisible y bloqueo, el PDF quedaba cifrado pero sin certificar. Se corrigió para que los tres firmadores acoplen siempre ambos efectos. También se agregó a PDFSignerWindowsCSP la validación de firmas preexistentes, que antes solo hacían PDFSignerPKCS11/PDFSignerPKCS12.

⚠ Corrección crítica — 1.1.1: firma corrupta al combinar certificación y cifrado

Antes, los tres firmadores firmaban el PDF sin cifrar y después volvían a serializar todo el archivo a través de un PdfWriter cifrado en una segunda pasada — esa pasada no sabe que el campo /Contents de la firma debe quedar exento de cifrado, y lo corrompía (el documento parecía firmado, pero PDFVerifySignatures fallaba con Unknown PdfException al verificarlo). Se corrigió invirtiendo el orden: cifrar primero, firmar después en modo append sobre el archivo ya cifrado. Este defecto no es nuevo de 1.1.1: ya estaba presente desde v1.0.0 en PDFSignerPKCS12 (bloqueo + firma visible) y en PDFSignerPKCS11 (cualquier bloqueo); PDFSignerWindowsCSP es nuevo en 1.1.1. Si firmó documentos con bloqueo antes de esta corrección, verifíquelos con PDFVerifySignatures y vuelva a firmar los que fallen.

Cuidado con el bloqueo

Si se planea agregar más firmas al mismo documento más adelante, no bloquear la primera — una firma certificante impide cualquier cambio posterior, incluidas nuevas firmas.

9.8 — PDFSignerPKCS11

PDFSignerPKCS11.jar

Firma un PDF con un token PKCS#11 (ver opciones arriba). Firma detached CMS/PKCS#7, con validación previa de firmas existentes.

Sintaxis
java -jar PDFSignerPKCS11.jar -i <pdf> -l <biblioteca> -p <password> -s <slot> [-k true|false] [-x pos] [-y pos] [-t "texto"] [-omitir-revocacion true|false]
java -jar PDFSignerPKCS11.jar [-v | -h | --license | --listar-drivers]

Antes de firmar, valida el estado de revocación del certificado — ver sección 7.5.1. No firma si está confirmado como revocado, salvo -omitir-revocacion true.

FlagObligatorioDescripción
-i, --inputPDF a firmar
-l, --libraryBiblioteca PKCS#11
-p, --passwordPIN del token
-s, --slotNúmero de slot
-k, --lockNoBloquea el documento tras firmar (default false)
-x / -yNoPosición de firma visible (default 0, invisible)
-t, --textNoTexto adicional en la firma visible
Errores posibles

La biblioteca PKCS#11 no existe o no es accesible · El token no contiene una clave privada válida · No se encontró una cadena de certificados válida en el token · El token no admite ningún mecanismo de firma RSA-SHA256 compatible

Certificados de Origen

Posiciones de convención Grupo Sauken: -x 40 -y 55 Exportador, -x 310 -y 55 Funcionario Habilitado.

Ejemplo
java -jar PDFSignerPKCS11.jar -i C:\docs\certificado.pdf -l C:\Windows\System32\eTPKCS11.dll -p "MiPIN123" -s 0 -k true -x 40 -y 55 -t "Exportador"

9.9 — PDFSignerPKCS12

PDFSignerPKCS12.jar

Idéntico al anterior, con archivo PKCS#12 (-c) en vez de -l/-s.

Sintaxis
java -jar PDFSignerPKCS12.jar -i <pdf> -c <certificado.p12> -p <password> [-l true|false] [-x pos] [-y pos] [-t "texto"] [-omitir-revocacion true|false]
java -jar PDFSignerPKCS12.jar [-v | -h | --license]

Antes de firmar, valida el estado de revocación del certificado — ver sección 7.5.1. No firma si está confirmado como revocado, salvo -omitir-revocacion true.

FlagObligatorioDescripción
-i, --inputArchivo PDF a firmar
-c, --certificateRuta al archivo del certificado PKCS#12
-p, --passwordContraseña del certificado
-l, --lockNoBloquea el documento tras firmar (default false)
-x / -yNoPosición de firma visible (default 0, invisible)
-t, --textNoTexto adicional en la firma visible
Nomenclatura distinta

En este módulo el flag de bloqueo es -l/--lock (no -k) — diferencia histórica frente a los otros dos firmadores de PDF.

Ejemplo
java -jar PDFSignerPKCS12.jar -i C:\docs\certificado.pdf -c C:\certificados\empresa.pfx -p "MiContraseña123" -l true -x 40 -y 55

9.10 — PDFVerifySignatures

PDFVerifySignatures.jar

Verifica integridad, autenticidad, revocación, y si el PDF fue modificado tras la última firma. Acepta SHA-256 y SHA-1 de cualquier aplicación (sección 7.6).

Sintaxis
java -jar PDFVerifySignatures.jar <archivo.pdf> [-simple]
java -jar PDFVerifySignatures.jar [-version | -ayuda | -licencia]
ParámetroObligatorioDescripción
Archivo PDFRuta al PDF firmado a verificar
-simpleNoReduce el detalle de la salida

Igual que XMLVerifySignatures: el exit code refleja el resultado de la validación.

Errores posibles

El documento no contiene firmas digitales · Certificado revocado al momento de la firma · Certificado no confiable o autofirmado

Ejemplo
java -jar PDFVerifySignatures.jar C:\docs\certificado-signed.pdf
java -jar PDFVerifySignatures.jar C:\docs\certificado-signed.pdf -simple

9.11 — XMLSignerWindowsCSPSolo Windows

XMLSignerWindowsCSP.jar

Firma XML usando un certificado ya presente en el almacén de Windows, tal como lo hace Adobe Acrobat/Reader por defecto — sin ruta de biblioteca ni número de slot (sección 7.3). Es el punto de partida recomendado para firma ocasional si no se conoce con exactitud la biblioteca PKCS#11 o la marca/modelo del token. Alternativa a XMLSignerPKCS11. Misma configuración criptográfica (XML-DSig, RSA-SHA256).

⚠️ No usar para firma desatendida por lotes

Windows puede abrir un diálogo pidiendo el PIN en cada documento firmado, sin que este módulo (ni ningún otro) pueda evitarlo — es una política de seguridad del propio certificado/token, no un defecto de S-FiDE. Para firmar muchos documentos por CLI sin intervención humana, usar XMLSignerPKCS11 o XMLSignerPKCS12. Ver la explicación completa en la sección 7.3.

Sintaxis
java -jar XMLSignerWindowsCSP.jar <alias o fragmento del CN> <archivo.xml> <elemento> [-omitir-revocacion true|false]
java -jar XMLSignerWindowsCSP.jar [-version | -ayuda | -licencia | -listar-certificados]

Antes de firmar, valida el estado de revocación del certificado — ver sección 7.5.1. No firma si está confirmado como revocado, salvo -omitir-revocacion true.

ParámetroObligatorioDescripción
Alias o fragmento del CNAlias exacto del certificado en el almacén, o un fragmento del titular que identifique un único certificado. Usar -listar-certificados para ver los disponibles
Archivo XML
Elemento a firmarSí (o "")Mismas reglas que XMLSignerPKCS11, incluida la especialización ALADI/MERCOSUR (sección 10)

No se pasa contraseña — el acceso a la clave lo administra Windows.

Errores posibles

No se encontró ningún certificado con clave privada que coincida con "[texto]" · "[texto]" coincide con N certificados distintos · más las reglas de firma comunes y las reglas de comercio exterior (sección 10.5)

Ejemplo
java -jar XMLSignerWindowsCSP.jar "Juan Carlos Ríos" C:\docs\certificado-origen.xml COD

9.12 — PDFSignerWindowsCSPSolo Windows

PDFSignerWindowsCSP.jar

Equivalente al anterior para PDF (sección 7.3 explica en detalle cuándo conviene esta opción antes que PKCS#11), con las mismas opciones de posición/texto/bloqueo que PDFSignerPKCS11, incluida la validación de firmas preexistentes (agregada en 1.1.1).

⚠️ No usar para firma desatendida por lotes

Mismo motivo que en XMLSignerWindowsCSP — ver sección 7.3. Para firmar muchos PDF por CLI sin intervención humana, usar PDFSignerPKCS11 o PDFSignerPKCS12.

Sintaxis
java -jar PDFSignerWindowsCSP.jar -i <pdf> -a <alias o fragmento CN> [-k true|false] [-x pos] [-y pos] [-t "texto"] [-omitir-revocacion true|false]
java -jar PDFSignerWindowsCSP.jar [-v | -h | --license | --listar-certificados]

Antes de firmar, valida el estado de revocación del certificado — ver sección 7.5.1. No firma si está confirmado como revocado, salvo -omitir-revocacion true.

FlagObligatorioDescripción
-i, --inputArchivo PDF a firmar
-a, --aliasAlias exacto o fragmento del CN del certificado en el almacén de Windows
-k, --lockNoBloquea el documento tras firmar (default false)
-x / -yNoPosición de firma visible (default 0, invisible)
-t, --textNoTexto adicional en la firma visible

Tampoco pide contraseña — el acceso a la clave lo administra Windows.

Ejemplo
java -jar PDFSignerWindowsCSP.jar -i C:\docs\certificado.pdf -a "Juan Carlos Ríos" -k true -x 40 -y 55

9.13 — WindowsCertificateStoreViewSolo Windows

WindowsCertificateStoreView.jar

Visualiza los certificados del almacén "Personal" (Windows-MY) del usuario actual — el mismo almacén que usan XMLSignerWindowsCSP/PDFSignerWindowsCSP. Es el equivalente de TokenSlotsView (sección 9.1) para ese almacén: no firma ni modifica nada. Resuelve un problema práctico concreto: sin este módulo, la única forma de conocer el alias o el nombre (CN) exacto que piden los dos firmadores CSP/KSP era adivinarlo o recurrir a herramientas externas de Windows (certmgr.msc, certutil -store -user My).

Sintaxis
java -jar WindowsCertificateStoreView.jar
java -jar WindowsCertificateStoreView.jar [-version | -ayuda | -licencia | -listar-certificados]

No recibe parámetros obligatorios: ejecutado sin argumentos, lista directamente los certificados disponibles — no requiere contraseña ni configuración, a diferencia de TokenSlotsView.

Salida

Por cada certificado: alias, sujeto (incluye el CN), emisor, período de validez, número de serie en hexadecimal, y si tiene clave privada asociada — solo esas entradas son utilizables para firmar. Es habitual que convivan un certificado vencido y su renovación posterior; conviene revisar "Válido hasta" antes de elegir cuál usar.

Relación con -listar-certificados

XMLSignerWindowsCSP/PDFSignerWindowsCSP ya traían ese flag con el mismo propósito, como ayuda rápida dentro de esos mismos módulos. WindowsCertificateStoreView no lo reemplaza — es esa misma capacidad elevada a módulo propio de primera clase, con su propia pestaña en la GUI, igual que TokenSlotsView existe aparte de los firmadores PKCS#11.

Ejemplo
java -jar WindowsCertificateStoreView.jar

9.14 — S-FiDE GUI

SFide-GUI.jar

Interfaz JavaFX que expone las 13 aplicaciones como módulos elegibles desde un panel lateral de navegación, para uso manual sin línea de comandos. Invoca los mismos .jar vía ProcessBuilder — no reimplementa ninguna lógica de firma. El título de la ventana muestra la versión en ejecución.

Navegación rediseñada en 1.1.1

Hasta la 1.1.1-beta.1 los módulos se mostraban como pestañas horizontales que, con 12-14 títulos, no entraban en el ancho de la ventana y quedaban con scroll horizontal. Se reemplazó por un panel lateral vertical con ícono por categoría (ver/firmar/verificar) — el espacio vertical disponible es mucho mayor, así que la lista entra sin scroll salvo en pantallas muy bajas. El formulario del módulo elegido tiene scroll vertical propio, y el panel "Salida del Proceso" ahora se puede colapsar (arranca colapsado, se expande solo al aparecer un resultado nuevo).

Qué recuerda entre sesiones (sfide-defaults.properties)

Ruta de biblioteca PKCS#11/PKCS#12 y número de slot (se guardan al escribirlos a mano, no solo con "Examinar..."/"Detectar automáticamente", y están sincronizados en vivo entre todos los módulos que los usan); una ruta particular por cada marca/modelo de token elegida en el selector; el último módulo abierto; tamaño/posición/maximizado de la ventana; el alias del almacén de Windows; y la casilla "Salida simple" de los verificadores de XML/PDF. Nunca se persiste ninguna contraseña. Tampoco se recuerdan la posición X/Y de firma visible ni la casilla "Bloquear documento después de firmar" — a propósito, el usuario siempre debe indicarlas de nuevo en cada firma, igual que el elemento/ID de un XML a firmar.

No es para integración por proceso

No tiene un contrato de argumentos/exit-code pensado para ser invocada por otro programa. Un integrador debe usar los módulos CLI individuales de esta sección.

Instancia única por carpeta de instalación

Al arrancar, se detecta si ya hay otra instancia de la GUI corriendo desde la misma carpeta (dos instalaciones en carpetas distintas sí pueden correr en paralelo). Si la hay, se informa y la nueva instancia se cierra sin abrir ninguna ventana, sin afectar la ya abierta. Implementado con un FileLock (java.nio.channels) exclusivo sobre sfide-gui.lock, no con un flag persistido — el sistema operativo libera el lock automáticamente al terminar el proceso, sea un cierre normal o una caída, sin dejar ningún estado que limpiar a mano. Mecanismo estándar del JDK, igual en Windows/Linux/macOS.

Ventana de Ayuda: pestaña "Documentación"

Enlaces para abrir, en el navegador web predeterminado del sistema, los documentos HTML de doc/ (Guía de Usuario y Manual Técnico) como URL file://, más enlaces externos a los visualizadores de ALADI para COD/CODEH (viewcod.certificadoorigen.com.ar) y DJO/DJOEH (viewdjo.certificadoorigen.com.ar). La pestaña "Contacto" de la misma ventana incluye además un enlace a la página del proyecto en GitHub.

Botón "Abrir documento generado"

Junto al campo del documento de entrada en las seis pestañas de firma: deshabilitado hasta que la firma termina con código de salida 0 y el archivo -signed correspondiente existe realmente en disco (no se confía ciegamente en el código de salida) — al presionarlo, abre ese documento como URL file:// en el navegador predeterminado. Se deshabilita si el usuario edita el campo del documento de entrada después de firmar.

Botones de ayuda contextual ("?")

Junto a "Elemento XML (ID) a Firmar" en las tres pestañas de firma XML (qué pasa si se deja vacío, qué debe contener, y el detalle de COD/CODEH/DJO/DJOEH para comercio exterior), y junto a la posición X/Y en las tres pestañas de firma PDF (sistema de coordenadas de PDF y las posiciones recomendadas para Exportador/Funcionario Habilitado en comercio exterior).

Campos de entrada vacíos con ejemplo de carga ("placeholder")

Cada campo de texto sin valor recordado muestra, en gris claro, un valor de ejemplo realista (p. ej. C:\Documentos\factura.xml) en vez de repetir la etiqueta del campo — no es un valor real, desaparece al tipear y nunca se envía como argumento.

Diálogo "Acerca de" ampliado

Descripción del producto, nombre y ubicación de Grupo Sauken S.A., enlaces al sitio web, al repositorio en GitHub y a la página del proyecto (GitHub Pages), y una mención de la licencia (GPLv2 o posterior) con referencia a Ayuda → Licencia para el texto completo.

(Windows) Accesos directos automáticos, una sola vez por instalación

Al primer arranque de SFide-GUI.bat, se crean tres accesos directos en el escritorio y otros tres en el menú inicio (carpeta "S-FiDE"), todos con el ícono de S-FiDE — uno abre la aplicación (S-FiDE.lnk hacia el .bat), y los otros dos abren en el navegador predeterminado la Guía de Usuario y el Manual Técnico de Integración de la carpeta doc/ (archivos .url con URL=file:///...). Cada grupo se registra con su propia marca independiente en sfide-defaults.properties (desktop.shortcut.created / doc.shortcuts.created) para no repetirse, incluso si el usuario los borra después. Blindado contra políticas de seguridad corporativas restrictivas: nunca genera un error visible ni bloquea el arranque.

Nombre sin número de versión, a propósito. Antes el de la aplicación sí lo incluía (S-FiDE 1.1.1.lnk). Así, al actualizar S-FiDE a una carpeta nueva, el primer arranque de la versión nueva sobrescribe estos mismos archivos en vez de sumar íconos al lado de los de la versión anterior — que además quedarían apuntando a una ubicación inexistente si se borra la carpeta vieja, como suele pasar. También hay un ítem de menú Herramientas → Recrear accesos directos para disparar esto mismo a pedido.

10

Especialización de comercio exterior ALADI/MERCOSUR: COD, CODEH, DJO y DJOEH

Esta sección documenta una funcionalidad adicional (add-on) por encima del soporte estándar de firma XML, orientada al intercambio de documentación de comercio exterior entre países miembros de la ALADI (Asociación Latinoamericana de Integración), incluyendo el bloque MERCOSUR.

10.1 — Contexto

Los acuerdos comerciales entre países miembros de ALADI obligan a las partes a intercambiar datos de comercio exterior mediante documentos XML normalizados. Dos tipos de documento son centrales:

  • Certificado de Origen Digital, agrupado en un elemento COD (firma como Exportador) o CODEH (firma como Funcionario Habilitado del organismo emisor).
  • Declaración Jurada de Origen, agrupada en un elemento DJO (Exportador) o DJOEH (Funcionario Habilitado).

Estos documentos deben llevar firmas digitales embebidas exactamente sobre esos elementos — no sobre el documento completo — de modo que cada parte quede firmada de manera independiente y verificable por separado, dentro del mismo XML.

10.2 — Estructura real de un COD/CODEH

Ejemplo real (esquema codaladi.org/directorio/cod_ver_1.8.2.xsd):

ns1:Envelope
  ns1:CertOrigin
    CODEH (id="CODEH")            ← elemento EXTERIOR, envuelve todo
      CODExporter
        COD (id="COD")            ← elemento INTERIOR, anidado vía CODExporter
          CODVer, CODSubmitterType, Agreement, FormA18...
        [firma del Exportador]    ← Reference="#COD", justo después de </COD>
      /CODExporter
      EH (EHId, EHCountry, EHName, EHAddress, EHCity, EHTelephone, EHFax, EHEmail, EHURL)
      CertificationEH (CertificateControlCode, CertificateDate, CertificateID)
    /CODEH
    [firma del Funcionario]       ← Reference="#CODEH", justo después de </CODEH>
  /ns1:CertOrigin

Cuatro etapas estrictamente secuenciales: (1) el XML se crea con COD completo, sin firmas — en ese momento solo COD puede firmarse, porque CODEH aún no tiene EH/CertificationEH; (2) el Exportador firma COD, la firma queda hermana justo después de </COD>, dentro de CODExporter; (3) el sistema externo de gestión de certificados (no S-FiDE) agrega <EH> y <CertificationEH> dentro de CODEH, después de </CODExporter>; (4) recién ahí el Funcionario Habilitado puede firmar CODEH — esa firma queda hermana justo después de </CODEH>, y su digest cubre todo el subárbol de CODEH, incluida la firma del Exportador ya embebida.

Regla de orden (no se puede firmar CODEH sin firma válida en COD, ni sin los datos de certificación): la garantiza el sistema externo que orquesta las llamadas a S-FiDE — S-FiDE no la conoce ni la valida. Los firmadores solo firman el elemento por Id que se les indique, cuando se los invoque.

Confirmado contra el código — sin lógica especial

XMLSignerPKCS11.createSignatureContext() arma el DOMSignContext con el nodo padre y el hermano siguiente del elemento encontrado por Id, lo que coloca la firma exactamente como hermana justo después del cierre del elemento firmado. Es genérico — no hay nada hardcodeado para COD/CODEH, por eso funciona igual para DJO/DJOEH (sección 10.3).

Nombre de archivo: el contenido de <CertificateID> más .xml — p. ej. AR001A18170000043000.xml (país + código de entidad ALADI + código de acuerdo + año + número de certificado). Se recomienda enviarlo al importador dentro de un ZIP.

10.3 — Estructura real de un DJO/DJOEH

Misma mecánica de dos etapas, para una Declaración Jurada de Origen:

ns1:Envelope
  ns1:Affidavit                   ← raíz distinta a la de COD (CertOrigin)
    DJOEH (id="DJOEH")
      DJOExporter
        DJO (id="DJO")
          DJOVer, DJOSubmitterType, Agreement, Exporter, Producer,
          Declaration (DeclarationDate), FormDJO...
        [firma del Exportador]    ← Reference="#DJO"
      /DJOExporter
      EH (EHId, EHCountry, EHName, EHAddress, EHCity, EHTelephone, EHEmail, EHURL)
      ApprovalEH (ApprovalNumber, ApprovalDate, ROMCompliance)
    /DJOEH
    [firma del Funcionario]       ← Reference="#DJOEH"
  /ns1:Affidavit

Mismas cuatro etapas que COD/CODEH, con nombres propios: el bloque de certificación del funcionario se llama ApprovalEH (no CertificationEH), con campos ApprovalNumber/ApprovalDate/ROMCompliance — una declaración de cumplimiento del Régimen de Origen Mercosur, no un número de certificado.

10.4 — Validación de revocación por elemento

Un documento completo (COD o DJO) contiene dos firmas independientes, de titulares y momentos distintos. XMLVerifySignatures extrae, para cada una, la fecha correcta según a qué elemento apunta su Reference:

ReferenciaCampo de fechaCampo de paísConversión horaria
#CODDeclarationDateExporterCountrySí — país del exportador → UTC
#CODEHCertificateDateEHCountrySí — país de la Entidad Habilitada → UTC (no el del exportador)
#DJODeclarationDateNo. Literal como UTC, sin conversión
#DJOEHApprovalDateNo. Misma regla que DJO

Tabla de husos horarios (TimezoneConverter): Argentina, Bolivia, Brasil, Chile, Colombia, Cuba, Ecuador, México, Panamá, Paraguay, Perú, Uruguay y Venezuela.

Por qué DJO/DJOEH no convierten huso horario: a diferencia de un Certificado de Origen, una Declaración Jurada de Origen se opera siempre dentro de un mismo país — el que emite el XML. El valor de fecha ya representa el instante correcto tal cual está escrito.

Por qué CODEH usa EHCountry y no ExporterCountry: la firma sobre CODEH la aplica el Funcionario Habilitado, actuando por la Entidad Habilitada — su acto de firma ocurre en el país de esa entidad, no necesariamente en el del exportador.

Corrección — 2026-08-29

La implementación original usaba ExporterCountry también para CODEH, un error real que desplazaba la fecha de referencia por el huso horario incorrecto en casos donde exportador y Entidad Habilitada están en países distintos. Corregido para usar EHCountry.

Comportamiento intencional — no corregir

Esta especialización es exactamente lo que requiere el caso de uso ALADI/MERCOSUR, verificada contra ejemplos reales de COD y DJO.

10.5 — Reglas de firma obligatorias

Además de la regla genérica de no volver a firmar un elemento ya firmado, los tres firmadores XML aplican una regla de orden específica para esta especialización, reflejando la secuencia operativa real de 10.2/10.3:

  • CODEH no puede firmarse si COD no tiene ya una firma digital aplicada.
  • DJOEH no puede firmarse si DJO no tiene ya una firma digital aplicada.

Ambas verificaciones son de existencia, no de validez criptográfica completa: el firmador confirma que hay una <ds:Signature> con Reference al elemento requerido, sin volver a verificarla — la disciplina de orden real la garantiza el sistema externo que orquesta las llamadas a S-FiDE, no S-FiDE actuando como autoridad de validación completa al momento de firmar.

Mensajes de error

No se puede firmar el elemento CODEH: no existe una firma digital previa sobre el elemento COD. · No se puede firmar el elemento DJOEH: no existe una firma digital previa sobre el elemento DJO.

Regla adicional — no se permite firmar el documento completo

Los tres firmadores XML detectan automáticamente si el XML es un documento de comercio exterior: basta con que exista, en cualquier parte del documento, un elemento con Id/id/ID igual a COD o a DJO (no hace falta que sea justo el elemento que se está por firmar). Si se detecta esta condición y el elemento a firmar indicado es la cadena vacía "" (equivalente a firmar todo el documento), la operación se rechaza — en un XML de comercio exterior siempre hay que indicar explícitamente qué elemento firmar (COD, CODEH, DJO o DJOEH, según la etapa). Se suma a las reglas anteriores, no las reemplaza.

Este XML corresponde a un documento de comercio exterior (un Certificado de Origen Digital / una Declaración Jurada de Origen). No se permite firmar el documento completo: debe indicarse un elemento específico a firmar.

Mensajes informativos al firmar un documento de comercio exterior

Cuando la firma se aplica sobre un XML detectado como COD o DJO (nunca en un XML estándar), el firmador informa por consola, antes del mensaje de éxito: "El XML a firmar es un Certificado de Origen Digital de ALADI (sin verificación de contenido)." o "El XML a firmar es una Declaración Jurada de Origen (sin verificación de contenido).", seguido de "Elemento firmado: <elemento>". La aclaración "sin verificación de contenido" es intencional: S-FiDE no valida si el documento está completo o corresponde a la etapa operativa correcta (secciones 10.2/10.3) — eso es responsabilidad del sistema externo que orquesta la firma.

10.6 — Sensibilidad a mayúsculas/minúsculas

El nombre del elemento a firmar es sensible a mayúsculas y minúsculas. Para Certificados de Origen Digitales y Declaraciones Juradas de Origen, usar siempre los identificadores en mayúsculas: COD, CODEH, DJO, DJOEH.

11

Integración desde otras aplicaciones

Patrón recomendado por Grupo Sauken: redirigir stdout/stderr a archivos separados y capturar el código de salida, para que la aplicación integradora los lea una vez que el proceso terminó.

Windows (.bat)

@echo off
set SFIDE=C:\ruta\a\S-FiDE
C:
cd %SFIDE%
set JAVA_HOME=%SFIDE%\openjdk-23.0.1\windows-x64
set PATH=%JAVA_HOME%\bin;%PATH%

%JAVA_HOME%\bin\java -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -jar PKCS12CertificateExtractor.jar "C:\ruta\al\certificado.pfx" "<Contraseña>" 1>"C:\temp\salida.txt" 2>"C:\temp\error.txt"

set RESULT=%ERRORLEVEL%
echo %RESULT% > "C:\temp\result.txt"
exit /b %RESULT%
  • JAVA_HOME/PATH apuntan al runtime embebido en la propia distribución — no dependen de que el sistema tenga Java instalado.
  • -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8: recomendado incluir siempre, fuerza UTF-8 en salida y en rutas/argumentos con acentos.
  • 1>archivo / 2>archivo redirigen stdout/stderr por separado.
  • %ERRORLEVEL% es el código de salida del proceso, sin transformación.

Este patrón sirve para cualquiera de los 13 módulos — solo cambia el jar y sus argumentos.

Linux/macOS (shell)

#!/bin/sh
SFIDE=/opt/S-FiDE
cd "$SFIDE"
JAVA_HOME="$SFIDE/openjdk-23.0.1/linux-x64"   # macOS: "$SFIDE/openjdk-23.0.1/macos"
PATH="$JAVA_HOME/bin:$PATH"

"$JAVA_HOME/bin/java" -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 \
    -jar PKCS12CertificateExtractor.jar "/ruta/al/certificado.pfx" "<Contraseña>" \
    >"/tmp/salida.txt" 2>"/tmp/error.txt"

RESULT=$?
echo $RESULT > "/tmp/result.txt"
exit $RESULT
12

Distribución y despliegue

Una distribución lista para usar es una carpeta autocontenida:

S-FiDE/
├── openjdk-23.0.1/          ← runtime de Java embebido (por plataforma)
├── javafx-sdk-23.0.1/       ← SDK de JavaFX embebido (por plataforma)
├── *.jar                    ← los 14 módulos, nombre "amigable" sin versión
├── SFide-GUI.bat / .sh      ← launchers, se autodetectan solos
├── doc/  test/  xsd/        ← documentación y ejemplos

No requiere instalación ni Java preinstalado — puede copiarse a cualquier ubicación, incluido un medio removible, y correr en un equipo "limpio", gracias al runtime embebido y a que los launchers se autodetectan (sin rutas ni letras de unidad hardcodeadas).

Cómo descomprimir el ZIP de distribución

Cree primero una carpeta propia (por ejemplo C:\S-FiDE en Windows, o ~/S-FiDE en Linux/macOS) y descomprima el contenido del ZIP dentro de esa carpeta — no directamente en la raíz de una unidad, en el Escritorio ni en la carpeta de descargas. La distribución trae más de una decena de .jar sueltos y dos carpetas de varios cientos de MB (los runtimes embebidos); sin una carpeta contenedora, todo eso queda mezclado entre los demás archivos de esa ubicación — pasó en la práctica con el ZIP de Windows. Desde esta versión, SFide-GUI.bat detecta el caso de raíz de unidad y avisa recomendando moverlo; no es un error, funciona igual, pero una carpeta propia es lo correcto.

Convención de nombres — importante para integradores

El jar de distribución (XMLSignerPKCS11.jar) nunca incluye la versión, a diferencia del artefacto crudo de Maven (xml_signer_pkcs11-1.1.1-jar-with-dependencies.jar). Es deliberado: un integrador con el nombre ya hardcodeado no debe romperse cuando S-FiDE actualiza de versión.

13

Historial de versiones

v1.3.0 (2026-09-05)

  • Verificación de instancia única por carpeta de instalación: FileLock exclusivo sobre sfide-gui.lock, no un flag persistido — el sistema operativo libera el lock automáticamente al terminar el proceso, sea un cierre normal o una caída. Ver sección 9.14.
  • Nueva pestaña "Documentación" en la ventana de Ayuda, con enlaces a la Guía de Usuario y el Manual Técnico (URL file://) y a los visualizadores externos de ALADI para COD/CODEH y DJO/DJOEH. La pestaña "Contacto" suma un enlace a GitHub. Ver sección 9.14.
  • Botón "Abrir documento generado" junto al documento de entrada en las seis pestañas de firma — habilitado solo cuando la firma termina con éxito y el archivo -signed existe realmente en disco.
  • Botones de ayuda contextual ("?") junto a "Elemento XML (ID) a Firmar" (las tres pestañas de firma XML) y junto a la posición X/Y (las tres pestañas de firma PDF), y placeholders reales en todo campo de entrada vacío.
  • Revisión completa de qué se recuerda entre sesiones: "Salida simple" (verificadores) ahora se recuerda; la posición X/Y de firma visible en PDF y "Bloquear documento después de firmar" dejaron de recordarse y de compartirse entre pestañas — el usuario siempre debe indicarlas de nuevo, igual que el elemento/ID de un XML a firmar. De paso, sfide-defaults.properties pasó a resolverse junto al jar en ejecución, no al directorio de trabajo del proceso.
  • Diálogo "Acerca de" ampliado, con enlaces al repositorio en GitHub y a la página del proyecto, y una mención de la licencia.

v1.2.0 (2026-09-03)

  • Validación de revocación antes de firmar, en los seis módulos que aplican firma digital (XMLSignerPKCS11, XMLSignerPKCS12, XMLSignerWindowsCSP, PDFSignerPKCS11, PDFSignerPKCS12, PDFSignerWindowsCSP) — ver sección 7.5.1 para el detalle completo (política, flag -omitir-revocacion, y la limitación conocida heredada del mecanismo de los verificadores).
  • Diálogo de confirmación en la GUI cuando no se puede determinar el estado de revocación, en las pestañas PKCS#12 y Windows CSP/KSP (no en las de token, por el riesgo de un segundo ingreso de PIN) — ver sección 7.5.1, apartado "Comportamiento distinto en la interfaz gráfica".
  • El acceso directo a la aplicación ya no lleva el número de versión en el nombre (S-FiDE.lnk, antes S-FiDE <versión>.lnk): al actualizar de versión, el primer arranque reemplaza el ícono anterior en vez de sumar uno más al lado. Nuevo ítem de menú Herramientas → Recrear accesos directos (Windows) para recrearlos a pedido — ver sección 9, nota "(Windows) Accesos directos automáticos".

v1.1.1 (2026-09-01)

  • Compatibilidad ampliada de tokens PKCS#11 (hash externo, sección 7.1).
  • Autodetección de marca/modelo y ayuda de selección de driver.
  • Dos módulos nuevos: XMLSignerWindowsCSP y PDFSignerWindowsCSP, más un tercero, WindowsCertificateStoreView, dedicado exclusivamente a listar el almacén de Windows (equivalente de TokenSlotsView para PKCS#11).
  • Actualización de dependencias criptográficas por alertas de seguridad.
  • Corrección de dos errores hallados en QA con hardware real (SafeNet 5110+ L3).
  • Especialización ALADI/MERCOSUR completada (sección 10): corregido un error real — la revocación de la firma sobre CODEH usaba ExporterCountry en vez de EHCountry para convertir a UTC; agregado soporte de extracción de fecha para DJO/DJOEH (literal como UTC, sin conversión de huso horario); verificado contra archivos DJO reales en sus 4 etapas; agregadas dos reglas de firma obligatorias (nunca firmar un elemento ya firmado, nunca firmar CODEH/DJOEH sin firma previa en COD/DJO); mensajes de revocación de XMLVerifySignatures aclarados para explicar por qué un certificado revocado invalida la firma; XMLVerifyXSDStructure ahora reintenta contra un dominio espejo (cod.certificadoorigen.com.ar) cuando el dominio oficial de ALADI (codaladi.org) está caído, incluyendo el caso de una redirección HTTP→HTTPS que antes se descargaba como si fuera el XSD; los tres firmadores XML ahora prohíben firmar el documento completo (elemento vacío) cuando detectan un XML de comercio exterior (contiene COD o DJO), e informan en consola de qué tipo de documento se trata y qué elemento se firmó.
  • Auditoría de código y corrección de inconsistencias entre módulos hermanos: se eliminó un stack trace expuesto en XMLVerifySignatures; PDFSignerPKCS12 ahora acopla siempre certificación DocMDP + cifrado al bloquear (antes solo con firma visible); PDFSignerWindowsCSP ahora valida firmas preexistentes y rechaza PDFs ya encriptados; se unificó el vocabulario de comandos especiales en los módulos CLI; se corrigieron afirmaciones de documentación no respaldadas por el código (versión de PKCS#11/12, XAdES, XML Schema 1.1, timeouts de OCSP/CRL).
  • Validado de punta a punta con hardware real: SafeNet 5110+ L3, mToken CryptoID nueva y Feitian ePass2003, además de PKCS#12 (sección 8, "Hardware validado end-to-end").
  • Rediseño de s_fide_gui: panel lateral de navegación en vez de pestañas horizontales, panel "Salida del Proceso" colapsable, ConfigurationManager reescrito con valores observables (guardado y sincronización en vivo entre módulos), y reescritas las 10 descripciones de módulo heredadas de 1.0.0.
  • Corregido un problema real de extracción del ZIP de distribución: algunos usuarios lo descomprimieron directo en la raíz de una unidad (C:\). Se corrigió el empaquetado (los ZIP del Release ahora traen una carpeta propia) y un bug latente real en SFide-GUI.bat que en ese caso podía hacer que el programa arrancara con el directorio de trabajo equivocado (sección 12); también se corrigió para funcionar desde una carpeta con espacios en el nombre.
  • Accesos directos automáticos (Windows): al primer arranque, s_fide_gui crea accesos directos en el escritorio y el menú inicio con ícono propio, blindados para nunca fallar visiblemente ni bloquear el arranque bajo políticas de seguridad corporativas restrictivas. El alias/CN del almacén de Windows también se recuerda y sincroniza en vivo entre los dos firmadores CSP/KSP.
  • GUIUtils.executeCommand (ejecución de módulos desde la GUI) ganó un límite de tiempo de 10 minutos con cancelación automática, para no quedar colgado ante un proceso que no responde.
  • LICENSE simplificado al texto canónico exacto de la GPLv2 para que GitHub reconozca correctamente la licencia del proyecto.
  • Guía de Usuario S-FiDE GUI nueva (doc/manual-usuario-sfide-gui.html): recorrido de las 13 pantallas de la interfaz gráfica con capturas reales, para quien opera la GUI en vez de integrar por línea de comandos.
  • s_fide_gui (Windows): dos accesos directos más al primer arranque, además del de la aplicación — abren en el navegador la Guía de Usuario y este mismo Manual Técnico (ver sección 9.14).
  • Corregido un error real en PDFVerifySignatures: el campo "Algoritmo de firma" informaba el algoritmo con que la CA firmó el certificado del firmante, no el de la firma del documento — ver sección 7.6. Puramente informativo, no afecta el resultado de la verificación.
  • Migración de los tres firmadores de PDF a la API vigente de iText 8 (SignerProperties/SignatureFieldAppearance en vez de PdfSignatureAppearance, deprecado) — sin cambio de comportamiento observable, verificado firmando y verificando documentos reales.
  • Corregido en XMLVerifyXSDStructure: si la descarga del esquema XSD fallaba por un problema de certificado SSL, DNS o conexión, la advertencia mostrada exponía el mensaje interno de la excepción de Java tal cual, incluyendo nombres de clases internas de la JVM — ver sección 9.7. Ahora se traduce a un mensaje simple según el tipo de falla; puramente cosmético, no cambia si la validación termina en éxito o error.

v1.0.0 (2024-12) — primer release estable

Suite inicial de 10 módulos más la GUI JavaFX.

Guía de migración desde 1.0.0

Si ya tenías una integración funcionando contra los jars de S-FiDE 1.0.0, la gran mayoría de los cambios de 1.1.1 son aditivos (flags opcionales nuevos, módulos nuevos) y no requieren ningún cambio de tu lado. Esta guía identifica puntualmente los pocos casos donde cambió el comportamiento de un jar que ya usabas en 1.0.0. No aplica a XMLSignerWindowsCSP.jar/PDFSignerWindowsCSP.jar: son módulos nuevos, no existían en 1.0.0.

Jar (ya existía en 1.0.0)Qué cambió¿Puede romper tu integración?Qué revisar
XMLSignerPKCS11.jar, XMLSignerPKCS12.jar Tres reglas de firma nuevas: (1) ya no se puede volver a firmar un elemento ya firmado; (2) no se puede firmar CODEH/DJOEH sin firma previa en COD/DJO; (3) si el XML contiene COD o DJO, ya no se admite "" como elemento a firmar. , solo si tu integración alguna vez firmaba dos veces el mismo elemento, fuera de orden, o con elemento vacío un XML de comercio exterior. Antes esas llamadas terminaban en éxito (código 0); ahora terminan en 1 con error explícito. Si tu flujo siempre firmó el elemento correcto, una sola vez, en orden, no hay nada que cambiar. Revisá solo lógica de reintento que pudiera reinvocar el firmador sobre el mismo archivo/elemento.
PDFSignerPKCS12.jar Con -l true (bloquear) y firma invisible, antes solo se aplicaba el cifrado; ahora también la certificación DocMDP, igual que ya hacía PDFSignerPKCS11. , si tu flujo agrega más de una firma al mismo PDF y una que no era la última usaba -l true invisible esperando poder seguir firmando después. Si usás -l true solo en la última firma de cada documento, no cambia nada. Si no, movelo a la última firma del flujo.
XMLVerifySignatures.jar La revocación de CODEH ahora usa el país de la Entidad Habilitada (EHCountry) en vez del país del exportador (ExporterCountry) para convertir la fecha a UTC. Solo si exportador y Entidad Habilitada están en países distintos y hay una revocación cerca de la fecha de certificación — el resultado VÁLIDO/REVOCADO de esa firma puntual puede diferir (el de 1.0.0 era el incorrecto). Si siempre coinciden de país, sin diferencia observable. Si no, reverificá los CODEH cercanos a una revocación conocida.
XMLVerifySignatures.jar, PDFVerifySignatures.jar Cambió el texto de algunas líneas de salida ("Estado: ..." → "Estado (integridad criptográfica, sin considerar revocación): ...", nueva línea "Estado final de la firma #N"). El código de salida no cambió. Solo si tu integración lee texto de stdout en vez del exit code — algo que este manual siempre desaconsejó. Si ya usabas el exit code, no te afecta. Si buscabas el texto literal "Estado: VÁLIDA", actualizá esa búsqueda o pasá a usar el exit code.
TokenSlotsView.jar, TokenCertificateExtractor.jar, PKCS12CertificateExtractor.jar, XMLVerifyXSDStructure.jar, PDFSignerPKCS11.jar, PDFVerifySignatures.jar Sin cambios de comportamiento frente a 1.0.0, más allá de la unificación de vocabulario de comandos. No. Ninguna acción necesaria.
XMLSignerPKCS11.jar, XMLSignerPKCS12.jar, XMLSignerWindowsCSP.jar, PDFSignerPKCS11.jar, PDFSignerPKCS12.jar, PDFSignerWindowsCSP.jar (1.2.0) Ahora validan el estado de revocación del certificado antes de firmar — ver sección 7.5.1. , pero solo si alguna vez firmabas con un certificado ya revocado. Antes esa llamada terminaba en éxito (código 0) igual; ahora termina en 1 y no se genera el archivo firmado, salvo que agregues -omitir-revocacion true. Si tu flujo firma siempre con certificados vigentes, no hay nada que cambiar. Si necesitás poder firmar igual aunque el certificado esté revocado, agregá -omitir-revocacion true a la invocación.
Tres cosas que no cambiaron — verificado con git diff completo contra el tag v1.0.0

Los nombres de los jars siguen siendo los mismos, sin versión (sección 12). Ningún flag funcional cambió de nombre ni de forma — se revisó específicamente -i/--input, -l/--library, -p/--password, -s/--slot, -k/--lock, -x/--xpos, -y/--ypos, -t/--text, -c/--certificate y -simple: ninguno aparece tocado desde v1.0.0. Tampoco cambió el orden ni la cantidad de argumentos posicionales en los módulos sin flags con nombre (XMLSignerPKCS11, XMLSignerPKCS12, TokenSlotsView, TokenCertificateExtractor, PKCS12CertificateExtractor). Los comandos especiales que ya usabas siguen funcionando igual — la unificación de vocabulario (sección 9) fue puramente aditiva: se agregaron alias nuevos, ninguno de 1.0.0 se quitó ni cambió de significado.

14

Glosario

AC-ONTIAutoridad Certificante de la Oficina Nacional de Tecnologías de Información (Argentina)
ALADIAsociación Latinoamericana de Integración, incluye el bloque MERCOSUR
CAPI / CNGLas dos generaciones de la API criptográfica nativa de Windows
COD / CODEHElementos XML de un Certificado de Origen Digital, firmados por Exportador / Funcionario Habilitado (sección 10)
CRLCertificate Revocation List
CSP / KSPProveedores que implementan CAPI/CNG respectivamente
DigestInfoEstructura ASN.1 que envuelve un hash con su identificador de algoritmo
DJO / DJOEHElementos XML de una Declaración Jurada de Origen, firmados por Exportador / Funcionario Habilitado (sección 10)
DocMDPPermiso PDF aplicado por una firma certificante, restringe qué cambios son válidos después
FIPS 140-2/3Estándar de seguridad del NIST para módulos criptográficos
HSMHardware Security Module
MERCOSURMercado Común del Sur, subconjunto de países miembro de ALADI
OCSPOnline Certificate Status Protocol
PKCS#11 / #12Estándares para tokens criptográficos y contenedores cert+clave
SlotRanura lógica de un token PKCS#11
XML-DSigEstándar W3C de firma XML — único estándar de firma XML implementado por S-FiDE (no XAdES)
15

Soporte y contacto

Grupo Sauken S.A. — Córdoba, Argentina

Email: soporte@sauken.com.ar · Sitio: www.sauken.com.ar · Repositorio: github.com/Grupo-Sauken-S-A/S-FIDE

El software se distribuye libremente bajo GNU GPLv2 o posterior. El soporte técnico es un servicio comercial, con cargo, independiente de la licencia de uso.