Sign PDFs with a Uruguayan national ID (cédula) via PKCS#11, generating an advanced electronic signature compatible with standard PDF signature validators.
This project:
- is not affiliated with or endorsed by AGESIC
- does not claim official certification or compliance
- is provided for technical and educational purposes
While it uses standard cryptographic mechanisms and aims to align with Uruguayan digital signature practices, it should not be assumed to be valid for legal or regulatory use without independent verification.
Users are solely responsible for ensuring that the generated signatures meet any legal or regulatory requirements applicable to their use case.
This tool focuses on:
- technical integration with PKCS#11
- PDF signing workflows
- reproducibility of signature appearance
It does not:
- validate certificates against official trust lists
- provide legal guarantees
- replace certified signing platforms
- Smart card reader compatible with your OS
- Uruguayan ID card (cédula) with active certificate
This tool is primarily designed for Arch Linux.
sudo pacman -S pcsclite ccid pcsc-tools opensc
sudo systemctl enable --now pcscdInstall the PKCS#11 module from AUR:
yay -S cedula-uruguay-pkcs11
# or manually:
# https://aur.archlinux.org/packages/cedula-uruguay-pkcs11This 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
uv tool install cedula-uy-pdf-signThe CLI tool is invoked as firmauy. Use --help on any command to see all available options:
firmauy --help
firmauy sign --help
firmauy sign-batch --helpfirmauy sign input.pdf output_signed.pdfThe tool will prompt for the PKCS#11 PIN interactively. If the output path is omitted, the signed file is saved as <input>_firmado.pdf.
firmauy sign input.pdf output_signed.pdf --x1 20 --y1 20 --x2 225 --y2 90firmauy sign input.pdf output_signed.pdf --page 0PIN can be supplied without an interactive prompt via --pin-source:
# From an environment variable
firmauy sign input.pdf output_signed.pdf --pin-source env --pin-env-var MY_PIN
# From stdin
echo "1234" | firmauy sign input.pdf output_signed.pdf --pin-source stdin
# From a file descriptor
firmauy sign input.pdf output_signed.pdf --pin-source fd --pin-fd 3Sign multiple PDFs with a single PKCS#11 session - the card PIN is entered only once.
# Explicit file list
firmauy sign-batch file1.pdf file2.pdf file3.pdf --output-dir ~/signed
# Whole directory
firmauy sign-batch --input-dir ~/docs --output-dir ~/signed
# Whole directory, recursively
firmauy sign-batch --input-dir ~/docs --recursive --output-dir ~/signed
# Both can be combined
firmauy sign-batch extra.pdf --input-dir ~/docs --output-dir ~/signedOutput files are named <original-name>_firmado.pdf by default. Change the suffix with --suffix:
firmauy sign-batch --input-dir ~/docs --output-dir ~/signed --suffix _signedThe output directory is created automatically if it does not exist.
All options available for sign (position, PIN source, reason, TSA, etc.) are also available for sign-batch.
List all visible PKCS#11 tokens:
firmauy list-tokensList certificates available on a token:
firmauy list-certs- The default visual signature appearance was derived by analyzing documents signed with official software.
- This project focuses on practical interoperability rather than strict compliance with any specific implementation.
On Arch Linux, entering an incorrect PIN may cause the process to terminate abruptly with:
*** stack smashing detected ***: terminated
This is a bug in the PKCS#11 middleware (libgclib.so), not in cedula-uy-pdf-sign.
The middleware correctly returns CKR_PIN_INCORRECT to the caller, but then appears to corrupt its own memory during error handling. This is independently reproducible with pkcs11-tool:
pkcs11-tool --module /usr/lib/pkcs11/libgclib.so --login --test
# With wrong PIN -> process crashes with stack smashBecause the crash occurs inside native code, it cannot be caught or recovered from at the Python level.
Practical advice: double-check your PIN before invoking firmauy.
This behavior is outside the control of this application.
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.
Signed documents can be independently verified using external tools, such as the official validator provided by AGESIC: https://firma.gub.uy/
No affiliation with or endorsement by AGESIC is implied.
Bug reports, questions, and pull requests are welcome. Feel free to open an issue on GitHub.
- @nicolasgutierrezdev - provided reference for signature appearance inspired by signatures generated using the Uruguayan ID (cédula).
This project is licensed under the Apache License 2.0.
