Firma digital local para JSON/JWS y PDF/PAdES con soporte PKCS#11 y PKCS#12.
FirMapache es un firmador local escrito en Rust y Tauri. Expone un servicio
HTTPS local compatible con flujos POST /sign, permite aprobar firmas desde una
ventana de escritorio y soporta tokens fisicos PKCS#11 y tokens virtuales
PKCS#12/PFX para pruebas controladas.
FirMapache combina un servicio HTTPS local compatible con POST /sign, una
interfaz de escritorio Tauri con bandeja del sistema y un core Rust reutilizable
para firmar con tokens criptograficos reales. Soporta JWS compact RS256, firma
PDF ETSI.CAdES.detached, cache de tokens/certificados, validacion,
diagnostico y flujo visual de aprobacion. El PIN se solicita solo en la UI local
o comandos internos de escritorio, no se guarda y no forma parte del payload
publico de POST /sign.
- Características
- Capturas
- Requisitos
- Instalación
- Configuración
- Interfaz Tauri
- Firma manual
- API
- Validación y diagnóstico
- Seguridad
- Desarrollo
- Release v0.1.0
- Contribuir
- GitHub Topics sugeridos
- Licencia
- ✓ Firma JSON/JWS compact con RS256.
- ✓ Firma PDF con
/SubFilter /ETSI.CAdES.detached. - ✓ Compatibilidad con tokens fisicos PKCS#11.
- ✓ Compatibilidad con tokens virtuales PKCS#12/PFX para QA y desarrollo.
- ✓ Soporte probado con ePass2003 y driver Feitian
libcastle.so. - ✓ Selección por identidad/certificado de firma.
- ✓ Servicio HTTPS local en
https://localhost:4637/. - ✓ Interfaz de escritorio Tauri v2 con bandeja del sistema.
- ✓ Ventana dedicada para solicitudes de firma.
- ✓ Firma manual multiarchivo para JSON y PDF.
- ✓ Empaquetado ZIP automatico cuando se firman varios archivos manualmente.
- ✓ Autofirma configurable para entornos controlados.
- ✓ Cache de tokens/certificados y watcher PC/SC.
- ✓ Validación JWS y diagnóstico estructural PDF.
- ✓ Diagnóstico exportable sin PIN, claves privadas ni contenido de documentos.
Las capturas reales se agregaran cuando se prepare el paquete publico. La
estructura ya esta lista en docs/images/.
| Pantalla | Placeholder |
|---|---|
| Dashboard | ![]() |
| Firma manual | ![]() |
| Solicitud de firma | ![]() |
| Identidades | ![]() |
| Diagnóstico | ![]() |
- Rust estable con Cargo
- El modulo PKCS#11 correspondiente al token, por ejemplo el driver Feitian ePass2003 o OpenSC.
pcscdactivo cuando el token o lector requiera acceso PC/SC.- OpenSSL de sistema para soporte PKCS#12/PFX de desarrollo (
openssly cabeceras de desarrollo si la distribucion las separa).
PKCS#11 es la interfaz estandar que permite a una aplicacion comunicarse con
tokens criptograficos. Algunos dispositivos, como ePass2003, requieren el
modulo propietario Feitian (libcastle.so.1.0.0) aunque OpenSC pueda detectar
el lector. OpenSC provee una implementacion generica mediante
opensc-pkcs11.so. pcscd es el servicio que suele comunicar estos modulos
con lectores de tarjetas inteligentes.
El servicio selecciona el modulo en este orden:
- La ruta configurada en
FIRMAPACHE_PKCS11. - La ruta persistida en
~/.config/firmapache/config.toml. - El driver Feitian ePass2003 en su ruta comun de instalacion.
- Rutas comunes de OpenSC en Linux.
Si FIRMAPACHE_PKCS11 esta definida pero no existe, el servicio informa el
error en los endpoints PKCS#11 en lugar de usar automaticamente otro modulo.
Si una ruta persistida no existe, el servicio registra la situacion y continua
con la autodeteccion.
Al iniciar, el servicio crea y carga automaticamente:
~/.config/firmapache/config.toml
En Linux esta ruta se obtiene mediante el directorio de configuracion del usuario. El archivo inicial tiene este formato:
[server]
host = "127.0.0.1"
port = 4637
https = true
[pkcs11]
library_path = "/usr/lib/libcastle.so.1.0.0"
[cors]
allowed_origins = [
"http://localhost:3000",
"http://127.0.0.1:3000",
]
[signing]
default_identity_id = ""
[development]
enabled = false
auto_sign = false
default_identity_id = ""
pin_env = "FIRMAPACHE_DEV_PIN"
remember_pin = false
local_pin = ""
fallback_to_modal = true
[[development.pkcs12_tokens]]
id = "dev-token-qa"
label = "Token virtual QA"
path = "/home/user/certs/dev-token.p12"
password_env = "FIRMAPACHE_DEV_P12_PASSWORD"
remember_password = false
local_password = ""POST /config actualiza solo los campos enviados y persiste el resultado. La
ruta PKCS#11 actualizada se usa en las siguientes operaciones. Como el
servidor no se reinicia automaticamente, los cambios de server y cors
entran en vigor al siguiente inicio.
La variable FIRMAPACHE_PKCS11 mantiene prioridad absoluta sobre el valor
guardado en el TOML.
El bloque [signing] guarda solamente la identidad publica predeterminada para
firmar. No guarda PIN ni sesiones. Una identidad tiene la forma:
pkcs11:{token_serial}:{slot_id}:{certificate_id}
Si el token no expone serial, se usa un identificador basado en slot_id y
certificate_id.
El bloque [development] existe solo para pruebas locales. Permite autofirmar
solicitudes POST /sign usando una identidad configurada. La UI permite
ingresar el PIN/contraseña y, opcionalmente, recordarlo localmente en este
equipo para comodidad de desarrollo. La variable pin_env se mantiene como
compatibilidad, pero ya no es el flujo principal.
Tambien puede registrar tokens virtuales .p12 o .pfx para desarrollo. Al
importar o crear un token virtual desde la UI, queda registrado
automaticamente, las identidades se actualizan y puede marcarse como identidad
predeterminada. Si se usa "Recordar contraseña localmente", la contraseña se
guarda en config.toml solo para modo desarrollo. No se guarda la clave privada
desencriptada.
Con server.https = true, el servicio genera automaticamente un certificado
self-signed para localhost y 127.0.0.1 en:
~/.config/firmapache/certs/localhost.crt
~/.config/firmapache/certs/localhost.key
El certificado local no se instala en el trust store del sistema. Por eso
curl requiere -k hasta que el certificado se configure como confiable.
Al cargar un archivo creado por una version anterior sin server.https, el
antiguo puerto por defecto 4856 se migra automaticamente a 4637; puertos
personalizados se conservan.
Descargue el artefacto FirMapache_0.1.0_amd64.AppImage, marque permisos de
ejecucion y arranque la aplicacion:
chmod +x FirMapache_0.1.0_amd64.AppImage
./FirMapache_0.1.0_amd64.AppImageInstale el paquete .deb:
sudo apt install ./FirMapache_0.1.0_amd64.debDependencias runtime recomendadas:
sudo apt install pcscd pcsc-tools opensc libpcsclite1 opensslPara compilar desde fuente en Debian/Ubuntu:
sudo apt install build-essential pkg-config libssl-dev libpcsclite-dev \
libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelfPor ahora se recomienda usar el AppImage para instalacion simple. Dependencias runtime recomendadas:
sudo pacman -S --needed pcsc-tools pcsclite ccid opensc opensslPara compilar desde fuente en Arch Linux:
sudo pacman -S --needed base-devel rustup pkgconf openssl pcsclite ccid opensc \
webkit2gtk-4.1 libayatana-appindicatorFirMapache no empaqueta drivers propietarios. Para ePass2003 puede ser necesario instalar el driver Feitian y configurar una de estas rutas:
/usr/lib/libcastle.so.1.0.0
/usr/lib/ePass2003-Linux-x64/redist/libcastle.so.1.0.0
/usr/lib/ePass2003_adsib/redist/libcastle.so.1.0.0
cargo runPor defecto el servidor escucha en https://localhost:4637/.
Para desarrollo sin TLS, establezca https = false en el bloque [server];
en ese modo escucha en http://127.0.0.1:4637/.
curl http://127.0.0.1:4637/
curl http://127.0.0.1:4637/statusLa aplicacion de escritorio inicia el mismo servicio Axum local y comparte su
AppState con los comandos Tauri; no duplica operaciones PKCS#11 ni logica de
firma. Para levantarla en desarrollo:
cargo install tauri-cli --version "^2" --locked
cargo tauri devNo ejecute cargo run al mismo tiempo: la aplicacion Tauri ya arranca el
servicio local en el puerto configurado.
La ventana permite:
- Ver estado, version, modo HTTPS, puerto y driver PKCS#11 detectado.
- Editar host, puerto y modo HTTPS del servidor local.
- Elegir una biblioteca
.soo.so.*y guardarla enconfig.toml. - Consultar tokens y certificados publicos.
- Actualizar manualmente la cache de tokens/certificados.
- Firmar manualmente archivos JSON locales como JWS compact.
- Firmar manualmente archivos PDF con una firma detached
ETSI.CAdES.detached. - Ver sesiones de firma pendientes, seleccionar identidad de firma y aprobar o rechazar visualmente su flujo.
La aplicacion vive en la bandeja del sistema. Al cerrar la ventana principal, la app se oculta pero el servidor local sigue activo. Desde el tray se puede abrir FirMapache, mostrar sesiones pendientes, reiniciar el servidor embebido o salir completamente.
En Configuracion > Servidor local se pueden editar:
host, por ejemplo127.0.0.1olocalhost;port, entre1024y65535;https, activado o desactivado.
La UI muestra la URL activa, por ejemplo:
https://localhost:4637/
Los cambios se guardan en ~/.config/firmapache/config.toml, pero requieren
reiniciar el servidor local para aplicarse. Use el boton Reiniciar servidor
desde la misma seccion o desde el menu del tray.
0.0.0.0 se acepta para casos controlados, pero muestra una advertencia porque
expone el firmador en la red. No se recomienda para uso normal.
Pruebas rapidas:
curl -k https://localhost:4637/statusSi HTTPS esta desactivado:
curl http://127.0.0.1:4637/statusSi cambia el puerto, por ejemplo a 4638, reinicie el servidor y pruebe:
curl -k https://localhost:4638/statusLa autofirma viene desactivada por defecto. Cuando esta apagada, el flujo normal
no cambia: POST /sign crea una sesion pendiente y abre la ventana
Solicitud de firma para que el usuario seleccione identidad e ingrese PIN.
Configuracion de ejemplo:
[development]
enabled = true
auto_sign = true
default_identity_id = "pkcs11:..."
pin_env = "FIRMAPACHE_DEV_PIN"
remember_pin = true
local_pin = "12345678"
fallback_to_modal = trueCon enabled = true y auto_sign = true, POST /sign intenta firmar
automaticamente usando development.default_identity_id y el PIN/contraseña
configurado para desarrollo. Funciona para format = "jws" y format = "pdf".
La variable FIRMAPACHE_DEV_PIN sigue funcionando como compatibilidad si no se
recuerda un PIN local.
Si falta identidad, no hay PIN/contraseña disponible o la autofirma falla:
- con
fallback_to_modal = true, FirMapache continua con la ventana de firma interactiva normal; - con
fallback_to_modal = false,POST /signresponde un error JSON claro.
La UI incluye una seccion Configuracion > Firma con este flujo:
- Elegir Autofirma como comportamiento de firma.
- Elegir identidad.
- Ingresar PIN / contraseña.
- Opcionalmente marcar Recordar PIN localmente.
- Pulsar Probar autofirma.
Si se recuerda el PIN, queda almacenado localmente en este equipo y claramente marcado como configuracion local de autofirma. No usar esta opcion en equipos compartidos.
Advertencia: no use autofirma con tokens oficiales en entornos no controlados. Permite firmar sin confirmacion visual.
FirMapache puede importar archivos .p12 o .pfx existentes como identidades
virtuales de desarrollo (provider = "pkcs12"). Esto no reemplaza a PKCS#11 en
produccion: sirve para QA, pruebas automatizadas y ambientes locales donde no se
quiere depender de un token fisico.
Tambien puede crear un token virtual nuevo desde la UI. La app genera una clave
RSA 2048, un certificado X.509 self-signed con SHA256withRSA, KeyUsage
digitalSignature y nonRepudiation, y empaqueta clave privada + certificado
en un .p12/.pfx protegido por la contraseña indicada. La clave privada no se
escribe fuera del .p12/.pfx.
Configuracion de ejemplo:
[[development.pkcs12_tokens]]
id = "dev-token-qa"
label = "Token virtual QA"
path = "/home/user/certs/dev-token.p12"
password_env = "FIRMAPACHE_DEV_P12_PASSWORD"
remember_password = true
local_password = "clave"La UI permite importar el archivo indicando la contraseña directamente. El token
queda registrado, las identidades se actualizan y puede marcarse como
predeterminado. password_env se mantiene como compatibilidad para instalaciones
existentes. Las identidades se muestran junto a las fisicas:
[PKCS#12] Token virtual QA
CN=Certificado Dev QA
Para autofirma, seleccione la identidad pkcs12:... como identidad de
autofirma. POST /sign sigue recibiendo el mismo payload puro; no se agrega
PIN, ruta, contraseña ni identity_id al contrato publico.
En firma manual, si selecciona una identidad P12, el campo de PIN se trata como
PIN / contraseña P12 para esa firma. La contraseña no se guarda.
Crear token virtual desde la app:
- En Identidades > Tokens virtuales P12/PFX, complete ID, etiqueta, CN, organizacion, pais, vigencia y contraseña.
- Pulse Crear token virtual.
- FirMapache abre el dialogo para guardar el archivo
.p12o.pfx. - FirMapache guarda el archivo y lo registra automaticamente en
development.pkcs12_tokens. - La identidad queda disponible inmediatamente y la app pregunta si desea usarla como predeterminada.
Limitaciones de seguridad:
- no usar como modo produccion;
- el PIN/contraseña recordado queda en almacenamiento local simple de desarrollo;
- no guardar credenciales en equipos compartidos;
- no exportar contraseñas en diagnostico;
- no guardar claves privadas desencriptadas en disco;
- no mantener la clave privada cargada mas tiempo del necesario para firmar.
Cuando llega una solicitud compatible, FirMapache abre una ventana dedicada
Solicitud de firma sobre el escritorio. Esa ventana pide certificado y PIN,
muestra estados de carga como Firmando... no retire el token, y deshabilita
los botones mientras se completa la operacion. El PIN solo existe durante esa
aprobacion y no se almacena.
FirMapache carga tokens y certificados en segundo plano al iniciar Tauri para que la ventana de firma abra rapido y no repita lecturas PKCS#11 innecesarias. La cache guarda solamente metadata publica:
- tokens detectados;
- certificados publicos;
- DER publico del certificado en Base64;
- identidades de firma normalizadas;
- hora de carga y driver PKCS#11 usado.
No se cachea PIN, sesiones PKCS#11 logueadas, claves privadas ni contenido de archivos. El PIN se pide solo al firmar y se limpia despues de usarlo.
La cache se invalida cuando cambia la configuracion del driver PKCS#11, cuando se pulsa Actualizar tokens/certificados o cuando falla una lectura durante la recarga. La UI muestra cantidad de tokens, cantidad de certificados, hora de ultima carga y driver cacheado.
Los endpoints GET /tokens y GET /certificates, el modal de firma y la firma
manual prefieren la cache. Si el certificado seleccionado no esta en cache, el
core hace una recarga controlada como fallback antes de fallar.
Cada certificado utilizable se muestra como una identidad de firma agrupada
por token. Esto evita depender visualmente solo del slot_id cuando hay varios
tokens o varios certificados conectados.
La UI permite marcar una identidad con Usar como predeterminado. Si no hay predeterminada y existe una sola identidad disponible, FirMapache la selecciona automaticamente. Si la identidad guardada ya no esta conectada, se muestra como no disponible y la UI advierte:
El token o certificado seleccionado ya no está disponible. Actualice tokens/certificados.
Para invalidar o actualizar la cache, pulse Actualizar tokens/certificados. Tambien se invalida al cambiar el driver PKCS#11 o cuando una lectura detecta que el token seleccionado ya no esta disponible.
La seccion Firma manual permite seleccionar uno o varios archivos locales sin depender de una web externa. FirMapache detecta automaticamente el tipo de archivo y el formato de salida:
- JSON: genera JWS compact.
- PDF: valida header
%PDF-y marcador%%EOF, genera una firma PDF con/Filter /Adobe.PPKLite,/SubFilter /ETSI.CAdES.detached,/ByteRangey CMS/CAdES detached SHA-256. - Otros formatos: se muestran como no soportados y se omiten al firmar.
- Abrir FirMapache con
cargo tauri dev. - Esperar o pulsar Actualizar tokens/certificados si el token se conecto despues de abrir la app.
- En Firma manual, pulsar Seleccionar archivos.
- Revisar la lista:
JSON → JWS,PDF → PDF/PAdESoNo soportado. - Quitar archivos individuales si hace falta o usar Limpiar para reiniciar la lista.
- Seleccionar identidad de firma, escribir el PIN y pulsar Firmar N archivos.
- Elegir una carpeta destino.
Si se firma un solo archivo, FirMapache guarda el archivo firmado directamente:
solicitud.json -> solicitud_firmado.jws
factura.pdf -> factura_firmado.pdf
Si se firman varios archivos, FirMapache genera un ZIP unico:
firmados_dd-mm-yyyy-hh:mm:ss.zip
Dentro del ZIP, los archivos se renombran con el sufijo _firmado:
solicitud_firmado.jws
factura_firmado.pdf
contrato_firmado.pdf
reporte_firmado.jws
Si existe una colision de nombres, FirMapache agrega un contador como
factura_firmado(1).pdf sin preguntar. Si un archivo falla, registra el error,
continua con los demas y muestra un resumen final.
El archivo guardado contiene el JWS compact en texto:
header.payload.signature
Para PDF, el archivo guardado conserva el documento original con una firma digital invisible. Puede inspeccionarse con:
pdfsig archivo-firmado.pdfLa compatibilidad esperada es:
Signature Type: ETSI.CAdES.detached
Signing Hash Algorithm: SHA-256
Limitaciones actuales de PDF: no se implementa TSA, LTV, OCSP ni CRL. La firma es detached y usa el certificado seleccionado desde el token PKCS#11. El PIN no se guarda ni se registra.
La seccion Validacion y diagnostico permite revisar archivos firmados y el estado local del firmador sin exponer informacion sensible.
Validacion JWS:
- acepta JWS compact directo o
Base64(JWS compact); - separa
header.payload.signature; - muestra
alg, presencia dex5c, subject del certificado si puede parsearse y tamano del payload; - verifica la firma RS256 usando el certificado
x5c.
Validacion PDF:
- detecta
/ByteRange,/Contents,/Filter /Adobe.PPKLite,/SubFilter /ETSI.CAdES.detached,/M,/Name,/Reason,/Locationy/ContactInfo; - muestra diagnostico estructural;
- para validacion criptografica PDF completa, por ahora recomienda:
pdfsig archivo.pdfDiagnostico del sistema:
- version de la app;
- configuracion no sensible del servidor;
- ruta de driver PKCS#11 configurada y detectada;
- disponibilidad basica de PC/SC;
- tokens publicos detectados;
- certificados publicos resumidos y expiracion;
- identidades de firma disponibles;
- identidad predeterminada configurada;
- certificados expirados y certificados que vencen en menos de 30 dias;
- ultimo error PKCS#11 conocido durante el diagnostico, si existe.
El boton Exportar diagnostico guarda un .json sin PIN, claves privadas,
firmas completas, archivos firmados completos ni contenido de documentos.
El servicio habilita CORS solamente para aplicaciones web servidas desde:
http://localhost:3000http://127.0.0.1:3000
No se habilita el origen comodin (*). Las solicitudes desde otros orígenes
no reciben autorización CORS por defecto.
Ejemplo de consulta desde un componente o acción cliente de NextJS:
const response = await fetch("https://localhost:4637/certificates", {
method: "GET",
headers: {
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error("No se pudieron cargar los certificados");
}
const certificates = await response.json();Para POST /sign/hash, el navegador puede enviar JSON desde esos mismos
orígenes; el PIN debe existir solo en la solicitud iniciada por el usuario y
no debe almacenarse en el frontend.
cargo check
curl -k https://localhost:4637/
curl -k https://localhost:4637/status
curl -k https://localhost:4637/version
curl -k https://localhost:4637/config
curl -k https://localhost:4637/pkcs11/library
curl -k https://localhost:4637/tokens
curl -k https://localhost:4637/certificatesPara probar explicitamente un ePass2003 con el driver propietario:
export FIRMAPACHE_PKCS11=/usr/lib/ePass2003-Linux-x64/redist/libcastle.so.1.0.0
cargo run
curl -k https://localhost:4637/pkcs11/library
curl -k https://localhost:4637/tokens
curl -k https://localhost:4637/certificatesRespuestas esperadas:
{"status":"ok","service":"firmapache"}{"name":"FirMapache","version":"0.1.0","build_date":"2026-06-05T00:00:00Z","git_commit":"abcdef123456","release_channel":"stable"}Si el driver Feitian se selecciona automaticamente:
{"found":true,"path":"/usr/lib/ePass2003-Linux-x64/redist/libcastle.so.1.0.0","source":"auto"}Si se selecciona usando la variable de entorno, source es "env".
Si se selecciona desde config.toml, source es "config".
El listado de slots incluye datos publicos del token cuando esta presente:
[{"slot_id":1,"token_present":true,"label":"ePass2003","manufacturer":"Feitian Technologies Co., Ltd","model":"ePass2003","serial_number":"..."}]Los certificados publicos encontrados se devuelven con su identificador, certificado DER en base64 y metadatos X.509:
[{"slot_id":1,"id":"01","label":"Certificado de firma","certificate_der_base64":"MIIC...","subject":"CN=...","issuer":"CN=...","serial_number":"...","not_before":"2024-...","not_after":"2026-..."}]Consultar la configuracion activa:
curl -k https://localhost:4637/configActualizar, por ejemplo, solamente el driver PKCS#11:
curl -k -X POST https://localhost:4637/config \
-H "Content-Type: application/json" \
-d '{
"pkcs11": {
"library_path": "/usr/lib/libcastle.so.1.0.0"
}
}'La configuracion no contiene PIN, certificados privados, sesiones ni datos sensibles del token.
El endpoint POST /sign recibe el payload compatible de archivo y formato.
Actualmente soporta:
format = "jws": genera JWS compact RS256.format = "pdf": genera PDF firmado conETSI.CAdES.detached.
La solicitud HTTP queda abierta mientras espera autorizacion local.
La interfaz Tauri detecta la sesion pendiente y abre la ventana independiente
Solicitud de firma para aprobar o rechazar la operacion. La ventana solo
muestra nombres y tamanos aproximados de los archivos; no muestra su contenido
completo.
Al aprobar, el usuario selecciona un certificado, escribe el PIN del token y el core genera la firma correspondiente al formato solicitado. Para JWS genera:
BASE64URL(header).BASE64URL(payload).BASE64URL(signature)
El campo x5c del header contiene el certificado DER en Base64 estandar. El
JWS compact resultante se devuelve codificado nuevamente como Base64 estandar en
response.files[].base64.
Para PDF, response.files[].base64 contiene el PDF firmado completo en Base64
estandar y el nombre del archivo se conserva igual al recibido.
Levantar la aplicacion:
cargo tauri devPuede cerrar la ventana principal despues de iniciar: FirMapache queda en
segundo plano en el tray y el servicio https://localhost:4637/ sigue
respondiendo.
Terminal 1:
curl -k -X POST https://localhost:4637/sign \
-H "Content-Type: application/json" \
--data-raw '{
"archivo": [
{
"base64": "data:application/json;base64,eyJob2xhIjoibXVuZG8ifQ==",
"name": "solicitud.json"
}
],
"format": "jws",
"language": "es"
}'La terminal queda esperando. En la aplicacion Tauri aparece la ventana
Solicitud de firma:
- Seleccione una identidad de firma.
- Escriba el PIN del token.
- Pulse Firmar JWS o Firmar PDF, segun el formato.
La terminal responde:
{
"files": [
{
"base64": "BASE64_DEL_JWS_COMPACT",
"name": "solicitud.json"
}
]
}Para inspeccionar el JWS devuelto:
echo "BASE64_DEL_JWS_COMPACT" | base64 -dDebe verse una cadena con tres partes separadas por puntos:
header.payload.signature
Ejemplo PDF:
curl -k -X POST https://localhost:4637/sign \
-H "Content-Type: application/json" \
--data-raw '{
"archivo": [
{
"base64": "data:application/pdf;base64,BASE64_PDF",
"name": "documento.pdf"
}
],
"format": "pdf",
"language": "es"
}'La app abre Solicitud de firma; el usuario selecciona certificado, ingresa PIN
y aprueba. Para guardar la respuesta como PDF:
echo "BASE64_RESPUESTA" | base64 -d > firmado.pdf
pdfsig firmado.pdfDebe mostrar Signature Type: ETSI.CAdES.detached.
Repita la solicitud y pulse Rechazar en la ventana. El request POST /sign
pendiente responde:
{"error":"User cancelled signing operation"}El panel de sesiones tambien ofrece botones Aprobar y Rechazar. Cerrar la
ventana de firma no resuelve la solicitud: permanece pendiente y puede abrirse
nuevamente desde el panel o desde el menu del tray. Una misma sesion no genera
ventanas automaticas duplicadas.
Si falta certificado o PIN, la UI no permite aprobar. Si el login PKCS#11 falla, se muestra el error y no se reintenta automaticamente.
Los endpoints /sign/sessions/{id}/approve y /reject se conservan como
herramientas internas de desarrollo.
Si una solicitud no se resuelve en cinco minutos, responde con HTTP 408:
{"error":"Signing request expired"}El campo base64 de entrada tambien puede enviarse sin el prefijo data:;
la salida siempre contiene Base64 estandar limpio.
El endpoint POST /sign/hash acepta un hash codificado en base64 y firma sus
bytes con el mecanismo RSA_PKCS. El flujo recomendado selecciona el
certificado cuya clave privada debe utilizarse.
- Listar los certificados publicos del token y copiar el campo
idelegido:
curl -k https://localhost:4637/certificates- Generar un hash SHA-256 base64 de prueba:
HASH=$(echo -n "hola" | openssl dgst -sha256 -binary | base64)- Firmar indicando el
certificate_id. Reemplace los valores de ejemplo localmente; el PIN no se registra ni se conserva por el servicio:
curl -k -X POST https://localhost:4637/sign/hash \
-H "Content-Type: application/json" \
-d '{
"slot_id": 1,
"certificate_id": "PEGAR_ID_DEL_CERTIFICADO",
"pin": "CAMBIAR_POR_PIN_REAL",
"hash_base64": "PEGAR_HASH_BASE64",
"mechanism": "RSA_PKCS"
}'Respuesta:
{"slot_id":1,"signature_base64":"...","algorithm":"RSA_PKCS","certificate_id":"PEGAR_ID_DEL_CERTIFICADO"}Advertencia de seguridad: el token puede bloquearse tras intentos de PIN
incorrectos. firmapache realiza un solo intento de login por solicitud y
no reintenta automaticamente cuando la autenticacion falla.
Si se omite certificate_id, el servicio conserva el modo compatible anterior
y selecciona una clave privada disponible, registrando una advertencia. No se
recomienda omitirlo si el token contiene mas de un certificado.
El endpoint POST /verify/hash verifica una firma RSA_PKCS usando solo el
certificado publico devuelto por /certificates. No requiere PIN y no accede
a la clave privada ni al token.
curl -k -X POST https://localhost:4637/verify/hash \
-H "Content-Type: application/json" \
-d '{
"certificate_der_base64": "BASE64_CERT_DER_OBTENIDO_DE_CERTIFICATES",
"hash_base64": "BASE64_DEL_HASH",
"signature_base64": "BASE64_DE_LA_FIRMA",
"mechanism": "RSA_PKCS"
}'Respuesta cuando la firma corresponde al hash y certificado:
{"valid":true,"algorithm":"RSA_PKCS"}Una firma no válida responde exitosamente con "valid": false.
Si no se encuentra la biblioteca PKCS#11, /tokens responde con HTTP 500:
{"error":"PKCS#11 library not found"}src-tauri: aplicacion de escritorio y comandos que consumen el core.ui: interfaz HTML/CSS/JavaScript minima para administracion local.src/server: rutas y handlers HTTP.src/config: configuracion del servicio local.src/core: operaciones reutilizables de PKCS#11, criptografia y firma.src/error: errores convertibles a respuestas HTTP.src/models: modelos JSON de la API.src/utils: utilidades compartidas futuras.
- El PIN no forma parte del contrato publico de
POST /sign. - El PIN solo se solicita en la UI local o en comandos internos de escritorio.
- La app no guarda claves privadas desencriptadas.
- La cache guarda metadata publica de tokens/certificados, no PIN ni sesiones PKCS#11 logueadas.
- El diagnostico exportado no incluye PIN, claves privadas, firmas completas ni contenido de documentos.
- Los tokens virtuales PKCS#12/PFX son para QA, pruebas automatizadas y ambientes controlados. No se recomiendan como reemplazo de tokens fisicos en produccion.
- El certificado HTTPS local es self-signed y no se instala automaticamente en el trust store del sistema.
Para reportar vulnerabilidades, vea SECURITY.md.
Las contribuciones son bienvenidas. Antes de enviar cambios:
cargo fmt --all
cargo check
cargo test
cargo check --manifest-path src-tauri/Cargo.toml
node --check ui/app.jsVea CONTRIBUTING.md para el flujo de desarrollo, reporte de bugs y propuesta de cambios.
La primera version publica estable esta documentada en docs/releases/v0.1.0.md.
Comandos sugeridos para publicar el tag:
git tag -a v0.1.0 -m "FirMapache v0.1.0"
git push origin v0.1.0Para publicar el repositorio, se sugieren estos topics:
tauri
rust
digital-signature
pkcs11
pkcs12
jws
pades
pdf-signature
linux
pcsc
smart-card
FirMapache se distribuye bajo licencia GPL-3.0.
Vea LICENSE para mas informacion.




