LibreSign / LibreSign/libresign
Add external digital signing to LibreSign
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 818
- Forks
- 146
- Avg merge
- 11h 31m
- Merged PRs (30d)
- 326
Description
LibreSign can already sign PDF documents when the signing process has direct access to the certificate and private key.
The next step is to support signatures where the private key stays outside LibreSign.
This is needed for signing models such as remote certificates, HSM-backed credentials and, in the future, certificates stored on local devices.
It also prepares LibreSign for services based on standards such as CSC and ICP-Brasil PSC.
[!NOTE]
This epic defines the goal, architecture and scope.
Pull requests should implement focused child issues, not the epic itself.
[!IMPORTANT]
Funding and community support needed
External signing can help LibreSign work with more digital identity and trust service ecosystems around the world.
We are looking for organizations interested in funding this work and for contributors who want to help build it.
Organizations that need remote certificates, HSM-backed signing, CSC, ICP-Brasil PSC or other external signing solutions are especially welcome to support this work.
Community contributions are also welcome. Implementation will be split into focused issues with the expected architecture and behavior already defined.
Goal
LibreSign must be able to prepare a digital signature without having the private key, send the required signing data to another component, receive the signature value and finish the signed PDF.
The existing signing methods must continue working as they do today.
Architecture
Today, the signing path expects the private key to be available inside the signing process:
flowchart LR
L["LibreSign workflow"] --> H["Sign engine handler"]
subgraph C["Current signing operation"]
P["Prepare PDF / PAdES"] --> K["Use private key"]
K --> S["Create signature"]
S --> F["Finalize PDF / PAdES"]
end
H --> P
F --> D["Signed document"]
This epic does not replace this complete flow.
It adds a new signing path for cases where the private key is outside the signing engine:
flowchart LR
L["LibreSign workflow"] --> H["Sign engine handler"]
H --> C["Existing signing path"]
C --> D["Signed document"]
H --> P["Prepare external signature"]
P --> T["Data to sign"]
T --> X["External signer"]
X --> V["Signature value"]
V --> F["Finalize external signature"]
F --> D
X -.-> R["Future remote signing"]
X -.-> LD["Future local-device signing"]
The important change is the new boundary between PDF/PAdES processing and the private-key operation.
The current signing path can remain unchanged while this new capability is added.
External signing responsibilities
The PDF/PAdES side is responsible for:
- preparing the PDF revision and signature structures;
- preserving existing signatures;
- producing the exact data that must be signed;
- receiving the returned signature value;
- finalizing a valid signed PDF.
The external signer is responsible for the cryptographic operation with the private key.
It must not need to understand PDF structure, ByteRange, incremental PDF updates or LibreSign workflows.
For an external signature, the interaction is:
sequenceDiagram
participant L as LibreSign
participant E as PDF / PAdES engine
participant S as External signer
L->>E: Prepare signature
E-->>L: Data to sign
L->>S: Send data to sign
S-->>L: Signature value
L->>E: Finalize signature
E-->>L: Signed PDF
Data to sign means the exact data prepared for the cryptographic signature.
It must not be assumed to be only the hash of the original PDF. The signing engine must prepare the correct CMS/PAdES signing data.
Integration boundary
The external signing foundation must not depend on how the private key is accessed.
Provider and device-specific communication belongs outside the PDF/PAdES layer. This includes:
- CSC;
- ICP-Brasil PSC;
- OAuth or other authorization flows;
- remote provider APIs;
- credential discovery;
- browser extensions and native bridges;
- PKCS#11 and hardware communication.
This makes the same external signing model usable by different integrations.
Remote signing will be the first main use case. Local-device signing must be supported by the architecture, but its browser, native and hardware integration is not part of this epic.
Signing engine direction
External signing must not cause every provider to implement its own PDF or PAdES logic.
LibreSign should use signing-engine support to prepare and finalize external signatures. Provider integrations should only be responsible for getting the signature value.
The related architecture discussion for signer-php is tracked in:
https://github.com/jeidison/signer-php/issues/25
PDF and CMS logic should stay in the signing layer instead of moving into future CSC, PSC or device integrations.
Incremental development
This work must be developed through normal pull requests to main.
Each completed change must be safe to merge and release on its own.
During this work:
- existing signing methods must continue working;
- incomplete external signing features must stay hidden from normal users;
- merged code must not require several future pull requests before LibreSign works again.
A long-lived feature branch is not needed.
Contribution model
Implementation work will be tracked in focused issues after the architecture for each task is defined.
An issue can be marked as good first issue even when the technical work is complex if a contributor can implement it without having to invent the architecture.
Each implementation issue should clearly define the expected behavior, boundaries, code to reuse, tests and what is outside its scope.
Contributors are welcome to discuss the proposed design if they find a problem or a better solution.
Testing
The external signing lifecycle must be testable without a real remote provider or hardware device.
Automated tests must be able to:
- prepare an external signature;
- sign the prepared data with a controlled test key;
- return the signature value;
- finalize the PDF;
- validate the resulting signed document.
Tests must also cover important failure cases and protect existing signing methods from regressions.
Real CSC, PSC or local hardware integrations are not required to test this foundation.
Out of scope
This epic does not implement:
- CSC provider integration;
- ICP-Brasil PSC provider integration;
- remote provider configuration or assignment;
- Remote Signing policies;
- remote authorization flows;
- signing session persistence;
- Remote Signing frontend flows;
- browser extensions or native bridges;
- PKCS#11 integration;
- smart card, token or other local hardware communication.
These features can use the external signing foundation created by this work.
Done when
- LibreSign can prepare a PDF/PAdES signature without access to the external private key.
- The exact data required for signing can be passed to an external signer.
- A returned signature value can be used to finalize the signed PDF.
- PDF/PAdES logic does not depend on CSC, PSC or another provider protocol.
- The architecture can support future remote and local-device signing.
- Existing signing methods continue working as before.
- Existing PDF signatures are preserved when another signature is added.
- Automated tests cover the complete external signing lifecycle.
- Related changes can remain safely in
mainbefore external signing is exposed to users.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
This is an architecture epic rather than an implementation task, and it names no LibreSign files, entry points, or test files. Start with the focused child issues described in the epic and review the related signer-php issue 25; the foundation is complete when external signing can prepare and finalize a PDF while preserving existing signing methods and passing lifecycle tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- php
- Domain
- backend-api-design, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100