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
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.
⚠️ 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.
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):
| 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
jqpipelines. - Trust anchors: the bundled national CA certificates, how trust is pinned and refreshed, and the state of revocation.
- 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-identityandlist-readerscommands 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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file firmauy-1.1.0.tar.gz.
File metadata
- Download URL: firmauy-1.1.0.tar.gz
- Upload date:
- Size: 112.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aac02b81014ac3dde419b5f88f2b723850a2a95773a26cfd016815210c520f1a
|
|
| MD5 |
ddf73145966dc37be72aa6ba331cf456
|
|
| BLAKE2b-256 |
0ced5222d1f597890bb55ab8a28dc71b4ccc3b319e01bca2f1baa73a117b83cd
|
File details
Details for the file firmauy-1.1.0-py3-none-any.whl.
File metadata
- Download URL: firmauy-1.1.0-py3-none-any.whl
- Upload date:
- Size: 76.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.24 {"installer":{"name":"uv","version":"0.11.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
32356f6f755e0034c498f6474ed06aae27f414f367743b973c1c7a742b11e08f
|
|
| MD5 |
a7404f6213d1ed71d528a27c8c4980eb
|
|
| BLAKE2b-256 |
f5767173515d0b9575dd6bacda92413341cc6662f036f4a61c3aad3422921ec1
|