Skip to main content

Sign and verify PDF (PAdES), XML (XAdES) and arbitrary files (CAdES/.p7s) with a Uruguayan national ID card (cédula) via PKCS#11. Standards-based; not affiliated with AGESIC.

Project description

FirmaUY

FirmaUY banner

Your cédula is a signing key. FirmaUY brings it to the terminal.

Sign and verify PDF, XML and any file with your Uruguayan national ID card over PKCS#11. Open-standard signatures (PAdES, XAdES, CAdES) that verify in any compliant validator, with the whole trust chain checked locally against the Uruguayan national root. Your documents stay on your machine.

CI PyPI version Python versions License: Apache 2.0 DeepWiki

⚠️ Disclaimer: This tool performs local, technical signing and verification using open standards. It is experimental, community-maintained, not affiliated with AGESIC, not officially certified, and does not guarantee legal validity. For official validation, use the official AGESIC validator; see Legal and compliance for details.

Quick start

Requires Linux with the Uruguayan cédula PKCS#11 middleware installed. The full smart-card setup is in Requirements and Setup on Arch Linux.

uv tool install firmauy                # install
firmauy doctor                         # check the setup (pcscd, PKCS#11 module, card, CAs)
firmauy list-tokens                    # confirm the card is detected
firmauy sign-pdf input.pdf             # sign -> input_firmado.pdf (prompts for the PIN)
firmauy verify input_firmado.pdf       # verify (auto-detects format; offline chain check)

Overview

FirmaUY provides a local, developer-oriented workflow for signing and verifying documents and files with a Uruguayan national ID card (cédula) using PKCS#11 middleware: PDF (PAdES), XML (XAdES) and detached CAdES/.p7s signatures for arbitrary files.

Each format has a batch variant and optional RFC 3161 timestamping. Verification runs locally with certificate-chain validation to the Uruguayan national root, and needs no card. FirmaUY also reads the card's public data without a PIN (biographical data and photo), validates a cédula's check digit offline, and diagnoses the local setup.

See Commands for the full list, with every command's options behind firmauy <command> --help.

Supported signature formats

Format Command Output Verification Timestamping
PDF / PAdES sign-pdf signed .pdf verify-pdf / verify optional (external TSA)
XML / XAdES sign-xml signed .xml verify-xml / verify optional (external TSA)
Any file / CAdES sign-any detached .p7s verify-any / verify optional (external TSA)

The full AdES triad (PAdES / XAdES / CAdES), signed locally with the cédula and verifiable with standard validators; local verification anchors the chain to the Uruguayan national root. Each command has a batch variant (sign-pdf-batch, sign-xml-batch, sign-any-batch).

Timestamping is optional and bring-your-own: it works with any external RFC 3161 TSA via --tsa-url, but it is not part of the standard cédula flow, and Uruguay has no free public TSA (the accredited qualified ones are gated). See Timestamping.

Requirements

Hardware

  • Smart card reader compatible with your OS
  • Uruguayan ID card (cédula) with active certificate

Operating system

This tool targets Linux and is primarily developed and tested on Arch Linux.

Other Linux distributions may work if the required smart card stack, PKCS#11 middleware, and Python environment are correctly configured.

Windows and macOS are not currently supported or tested.

Python

Python 3.10 or newer.

PKCS#11 middleware

The default PKCS#11 module expected by this tool is:

/usr/lib/pkcs11/libgclib.so

On Arch Linux, this is provided by the cedula-uruguay-pkcs11 AUR package.

Native mode (optional): every signing command also accepts --native, which talks to the cédula directly over PC/SC (pcscd and a reader) and needs no PKCS#11 middleware at all. It is experimental and not officially certified, though its output is accepted by the AGESIC validator. See Native signing and the card protocol reference.

Setup on Arch Linux

1. Install smart card stack

sudo pacman -S pcsclite ccid pcsc-tools opensc
sudo systemctl enable --now pcscd

2. Install PKCS#11 library for the Uruguayan ID card

Install the PKCS#11 module from AUR:

yay -S cedula-uruguay-pkcs11
# or manually:
# https://aur.archlinux.org/packages/cedula-uruguay-pkcs11

This is a community-maintained AUR package that repackages the official cédula drivers distributed by the Uruguayan government. It is not an official government package.

It provides the default PKCS#11 module used by this tool:

/usr/lib/pkcs11/libgclib.so

Use version 7.5.0-2 or later; older versions could crash the process when a wrong PIN was entered.

Installation

Installation with uv

uv tool install firmauy

Commands

Run firmauy --help, or firmauy <command> --help for the full options of any command. Step-by-step examples for every command are in the usage guide, and task-oriented recipes (privacy, automation, jq pipelines) are in the cookbook.

Signing (prompts for the PKCS#11 PIN, unless a non-interactive source is given). Add --native to any of these to sign over PC/SC without PKCS#11:

Command Description
sign / sign-batch Sign a file (or a mixed folder in one session), auto-detecting the type: PDF -> PAdES, XML -> XAdES, anything else -> detached CAdES. --as forces the type
sign-pdf / sign-pdf-batch Sign a PDF, or a whole folder in one session, with a visible signature (PAdES)
sign-xml / sign-xml-batch Sign XML documents (XAdES-BES, or XAdES-T with --tsa-url)
sign-any / sign-any-batch Produce a detached .p7s for any file (CAdES-BES)

Verifying (offline chain validation to the national root, exit 0 VALID / 1 INVALID / 2 INDETERMINATE):

Command Description
verify Verify any signed file, auto-detecting PDF / XML / .p7s
verify-pdf / verify-xml / verify-any Format-specific verification

Card and identity (no PIN required):

Command Description
fetch-identity Read the cardholder's biographical data over PC/SC
fetch-photo Save the cardholder's photo (to a file, a stream, or a JSON record)
validate-ci Validate (or complete) a cédula's check digit, offline, with no card
list-readers List the available PC/SC smart card readers
list-tokens List the PKCS#11 tokens in the library
list-certs List the certificates on the card (--pem / --json)

Setup and maintenance:

Command Description
doctor Diagnose the local environment (pcscd, PKCS#11 module, card, CAs)
fetch-cas Optional: refresh the bundled national CA certificates from the network

Documentation

  • Usage guide: step-by-step examples for every command.
  • Cookbook: task-oriented recipes for signing, verifying, privacy, automation and jq pipelines.
  • Trust anchors: the bundled national CA certificates, how trust is pinned and refreshed, and the state of revocation.
  • Card protocol reference: the cédula's data model and the APDU-level signing protocol behind --native (native, PKCS#11-free signing).
  • Development: running from source with uv, the test suite, and developing without the card (SoftHSM2).

Security considerations

  • Never pass the PIN directly as a command-line argument.
  • Prefer interactive PIN entry for manual use.
  • For automation, prefer protected file descriptors or controlled environments.
  • Review every document before signing it.
  • Use batch signing only in trusted workflows.
  • Keep your smart card, reader, PIN, and PKCS#11 middleware under your own control.

Privacy

This tool is designed to run entirely locally.

It does not collect, transmit, or store any user data externally.

All cryptographic operations are performed on the user's machine and/or the connected smart card.

Note: Optional features such as timestamping (TSA) may involve external network requests, depending on user configuration.

Note: the signing commands print a summary that includes identifying data (signer name, certificate issuer, certificate serial number and PKCS#11 key ID). This stays on your machine, but in batch or automated pipelines that output can end up in CI or centralized logs. Pass --quiet (-q) to the sign-pdf, sign-pdf-batch, sign-xml, sign-xml-batch, sign-any and sign-any-batch commands to suppress that block while still signing.

Note: fetch-identity reads and prints the cardholder's biographical data (names, birth date, birthplace, document number, MRZ), and fetch-photo outputs the cardholder's photo (to a file, a redirected stream, or a JSON record). This data is accessible from the card without PIN authentication, but it is still personal: pass --redact to fetch-identity to replace every field with [REDACTED] before sharing its output, use fetch-photo --json --redact for a metadata-only photo record, and treat any non-redacted output (file, redirected stream, or receiving application) as sensitive.

Additional notes

  • The default visual signature appearance was modeled on real documents signed with the Uruguayan ID card.
  • This project focuses on practical interoperability rather than strict compliance with any specific implementation.

Legal and compliance

This project is copyright-registered, experimental, community-maintained, and not officially certified.

It is intended for developers and technically proficient users who understand the implications of using smart cards, PKCS#11 middleware, and digital signatures.

This project:

  • is not affiliated with or endorsed by AGESIC
  • does not claim official certification or compliance
  • does not guarantee the legal validity of generated signatures
  • is provided for technical and educational purposes

While it uses standard cryptographic mechanisms and aims to align with Uruguayan digital signature practices, the generated signatures should not be assumed valid for legal or regulatory use without independent verification. Users are solely responsible for ensuring that generated signatures meet any legal or regulatory requirements applicable to their use case.

Intended use

Local, developer-oriented signing and verification using a Uruguayan ID card through PKCS#11. It is especially aimed at users who want to:

  • sign PDFs (PAdES), XML documents (XAdES), and arbitrary files (CAdES/.p7s) locally
  • verify those signatures locally, including the certificate chain to the national root
  • understand and reproduce a PKCS#11-based signing workflow
  • experiment with smart card integration on Linux
  • build automation around signing and verification under their own responsibility

It is not intended to replace official, certified, or legally guaranteed signing platforms.

Scope

This tool focuses on technical integration with PKCS#11: signing (PDF/PAdES, XML/XAdES, files/CAdES) and local, standards-based verification, including certificate-chain validation to the Uruguayan national root.

It is not an official validator: it does not consult the official trust-service status list (TSL) or evaluate accreditation / qualified status, provide legal guarantees, or replace certified signing platforms.

For authoritative or legal verification, use AGESIC's official validator at firma.gub.uy.

Copyright / software registration

This software has been registered as a computer program with the Uruguayan Dirección Nacional de la Propiedad Industrial y Registro de Software.

The registration was published in the official Boletín de la Propiedad Industrial Nº 357:

  • Entry: Software (w/000235)
  • Filing date: 2026-04-15
  • Applicant: Carlos Andrés Planchón Prestes [UY]
  • Title: cedula-uy-pdf-sign
  • Classification: Programa de ordenador
  • Official publication: Boletín de la Propiedad Industrial Nº 357

The project was later renamed to FirmaUY (PyPI package and CLI: firmauy). The registration above is under its original title, cedula-uy-pdf-sign.

This registration concerns only the authorship of the software as a copyrighted work. It does not imply certification or legal validity. See Legal and compliance.

Development

The project uses uv. Clone, set up the environment and run the tests:

git clone https://github.com/carlosplanchon/firmauy.git
cd firmauy
uv sync
uv run pytest

The full workflow, the project layout, and developing without the card (SoftHSM2, since a wrong PIN can block the cédula) are in docs/development.md.

Contributing & reporting issues

Bug reports, questions, and pull requests are welcome.

Feel free to open an issue on GitHub.

Cookbook contributions welcome

Cookbook recipes (see docs/cookbook.md) are welcome, and one of the best ways to help: they open the project to people who will not necessarily touch the PKCS#11, APDU or XAdES internals but can still share real, useful workflows. A good recipe shows a real workflow with minimal commands, the expected output, privacy notes, and the environment where it was tested.

Please do not include real names, document numbers, MRZ data, certificates, photos, or unredacted verification output. Use --redact whenever sharing command output.

Acknowledgements

  • @nicolasgutierrezdev: contributed the fetch-identity and list-readers commands for reading the cardholder's biographical data over PC/SC (#1). Also provided reference for the signature appearance inspired by signatures generated using the Uruguayan ID card (cédula), and helped test the XAdES (XML) signing feature.

License

This project is licensed under the Apache License 2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

firmauy-1.3.0.tar.gz (129.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

firmauy-1.3.0-py3-none-any.whl (86.2 kB view details)

Uploaded Python 3

File details

Details for the file firmauy-1.3.0.tar.gz.

File metadata

  • Download URL: firmauy-1.3.0.tar.gz
  • Upload date:
  • Size: 129.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for firmauy-1.3.0.tar.gz
Algorithm Hash digest
SHA256 3cb9480af3522858988a9dbc0dd9f5b1450f5dd91c31618812d914e62c9fec77
MD5 8883238a6ad372594bb35554085ecec3
BLAKE2b-256 aba1c0ed17a0ce23197bdea380ac49b9f5edecccc9038ea949d95b929dc3fff7

See more details on using hashes here.

File details

Details for the file firmauy-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: firmauy-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 86.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for firmauy-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 093a37a19010fcca37158614522ab91532980524cde5fb8ea7e07b20978e520f
MD5 8473bc7c333555d1f86612aac1be8e58
BLAKE2b-256 8f7e83009f317d1a8af869c6951210cbb9956ef40f8cb73f6e78fe75dbd12bc6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page