LibreSign / LibreSign/libresign
Define the external signing provider architecture
Nobody has claimed this yet.
- Dominant language
- PHP
- Stars
- 818
- Forks
- 146
- Avg merge
- 11h 31m
- Merged PRs (30d)
- 326
Description
This is part of #8335.
LibreSign is adding support for digital signatures where the private key stays outside LibreSign.
The PDF/PAdES side is handled separately by #8354.
The next boundary to define is the component that owns or accesses the private key and performs the cryptographic signing operation.
This may later include:
- a CSC remote signing service;
- an ICP-Brasil PSC;
- another HSM-backed signing service;
- a local-device signing bridge;
- another future signing mechanism where LibreSign does not own the private key.
Before implementing the first remote signing integration, we need a common architecture that does not make PDF/PAdES, CSC, OAuth or another specific protocol part of the shared signing domain.
[!NOTE]
This issue is for architecture and domain design.
It does not require a production-code pull request. Implementation should be handled through focused follow-up issues after these decisions are clear.
Goal
Define the common architecture LibreSign will use when the private-key operation happens outside LibreSign.
The result should be precise enough that future CSC, ICP-Brasil PSC and other integrations can be implemented without requiring each contributor to invent a different domain model.
The design must define:
- the difference between an external signer integration and a signing credential;
- which capabilities LibreSign needs to know;
- how authorization fits the signing lifecycle;
- what cryptographic information is sent for the private-key operation;
- what result comes back;
- what belongs to the common signing boundary;
- what must remain specific to each protocol or integration;
- how remote signing and future local-device signing can use the same core boundary.
Common boundary
The common signing boundary sits between LibreSign signing orchestration and the component that can use the private key.
flowchart LR
O["LibreSign signing orchestration"]
O --> S["External signer integration"]
S --> C["Credential discovery"]
S --> A["Authorization when required"]
S --> K["Private-key operation"]
K --> R["Signature result"]
E["PDF / CMS / PAdES engine"] -. "separate responsibility" .-> O
The external signer integration must not process PDF or PAdES structures.
It receives the cryptographic operation prepared by the signing layer and returns the result of the private-key operation.
Integration and credential are different concepts
The architecture must distinguish the integration from the credential used to sign.
External signer integration
An external signer integration represents the mechanism LibreSign uses to access one or more external signing credentials.
Examples may include:
CSC service
ICP-Brasil PSC
HSM-backed signing service
future local-device signing bridge
One integration may expose zero, one or many credentials to a user.
The common model must not assume:
one integration = one certificate
or:
one user = one external credential
How integrations are configured, stored or assigned is outside this issue.
Credential
A credential represents a signing identity/key available through an external signer integration.
It may expose information LibreSign needs for the signing operation, such as:
- an identifier;
- public signer certificate information;
- supported cryptographic algorithms;
- relevant signing capabilities;
- human-readable information needed to select the credential.
For remote signing, the private key must never become part of the LibreSign credential model.
Protocol-specific identifiers and metadata may exist, but they should not become part of the common domain unless LibreSign actually needs them outside that protocol implementation.
Capabilities
LibreSign needs enough information to determine whether a credential can perform the cryptographic operation prepared by the signing layer.
The architecture must define which capabilities are common across integrations.
These may include:
- supported digest algorithms;
- supported signature algorithms;
- required algorithm parameters;
- authorization requirements;
- public certificate information required by the signing engine.
Do not derive the common model only from CSC terminology.
The same model must be checked against ICP-Brasil PSC requirements.
Protocol-specific capabilities that LibreSign does not need outside the integration should remain internal to that implementation.
Authorization
Some external signing mechanisms require user authorization before the private key can be used.
Possible mechanisms include:
- OAuth-based authorization;
- redirects;
- OTP;
- PIN confirmation;
- another authentication or authorization mechanism.
The common architecture must support a lifecycle conceptually similar to:
select credential
-> authorize when required
-> perform private-key operation
Authorization may be synchronous or asynchronous.
The shared domain must not assume that authorization always means:
- OAuth;
- a browser redirect;
- an access token;
- OTP;
- any specific CSC mechanism.
The common architecture should represent the lifecycle and state that LibreSign needs to coordinate.
Protocol-specific authorization details must remain inside the concrete integration.
Cryptographic signing operation
The external signer integration must receive only the cryptographic information required to perform the private-key operation.
Conceptually:
prepared signing operation
-> external signer integration
-> private-key operation
-> signature result
The final common representation must be compatible with the real PDF/PAdES external-signing lifecycle implemented by #8354.
Do not assume in advance that every signing operation can be represented only by:
document hash
or one arbitrary:
signature algorithm
The model must be able to carry the digest, signature algorithm and required parameters established by the real signing implementation.
The external signer integration must not need to know why that cryptographic input exists or how it relates to PDF, CMS or PAdES.
Responsibility boundary
The external signer side may be responsible for:
- discovering available signing credentials;
- exposing the capabilities LibreSign needs;
- obtaining public signer certificate information;
- performing integration-specific authorization;
- communicating with the remote service or local bridge;
- performing the private-key operation;
- translating between the common LibreSign signing operation and the integration-specific protocol;
- returning the cryptographic signature result.
It must not be responsible for:
- PDF parsing;
- PDF incremental updates;
ByteRange;- CMS/PAdES construction;
- signed PDF attributes;
- PDF signature fields;
- visible signature elements;
- DocMDP or FormMDP;
- timestamp or LTV document processing;
- LibreSign workflow status;
- SignRequest business rules;
- provider assignment;
- policy evaluation;
- administration UI.
These responsibilities belong to other layers.
Remote protocol implementations
Remote signing is the first target.
The architecture should allow concrete implementations such as:
Remote signing provider
├── CSC
├── ICP-Brasil PSC
└── future remote provider types
A different company using the same supported standard should normally not require a different protocol implementation.
For example, standards-compliant CSC services should share the same CSC implementation and differ through configuration.
Provider-specific behavior should require a dedicated implementation only when it cannot be represented correctly by the supported standard adapter.
The same principle should apply to ICP-Brasil PSC.
Future local-device signing
HTTP, OAuth and remote-service concepts must not become requirements of the common external signing boundary.
A future local-device flow may look like:
LibreSign
-> browser integration
-> native bridge
-> smart card / token / operating-system certificate
From LibreSign signing orchestration, the core responsibility remains:
receive cryptographic signing operation
-> use external private key
-> return signature result
The browser/native implementation itself is outside this issue.
This issue only needs to ensure that the common architecture does not prevent that future integration or require changes to the PDF/PAdES layer.
Configuration, assignment and policy are separate
External signer runtime behavior must remain separate from:
- configuration persistence;
- provider secrets;
- administration APIs;
- assignment to users or groups;
- policy evaluation.
Those concerns will be designed separately when their implementation is needed.
The common signing domain should not depend on how configuration or assignment data is stored.
Secrets must not become part of normal signer or credential metadata exposed to callers.
Relationship with #8354
#8354 defines the real PDF/PAdES external-signing lifecycle.
This architecture must consume the cryptographic operation produced by that layer without depending on PDF/PAdES internals.
The final shape of the common signing operation must therefore be validated against the real implementation from #8354.
Do not create a competing cryptographic request model if #8354 already establishes the information that needs to cross this boundary.
This issue can progress in parallel with #8354, but it should not be considered complete until both sides are compatible.
Validate against CSC and ICP-Brasil PSC
CSC and ICP-Brasil PSC are expected to be the first remote consumers of this architecture.
Before closing this issue, review the current specifications of both ecosystems and verify that the proposed common model can represent what LibreSign needs.
The common domain must not use CSC-specific or ICP-Brasil-specific names for concepts that are actually generic.
Protocol-specific concepts should remain inside their respective integrations.
Important differences between CSC and ICP-Brasil PSC that affect the common architecture should be documented in this issue.
No speculative production code
Do not add production code only to reserve architecture for future work.
In particular, this issue should not add:
- interfaces without a real production implementation;
- reusable fake integrations;
- empty registries;
- credential DTOs without a production consumer;
- managers without real callers;
- placeholder CSC or PSC implementations.
Production abstractions should be introduced together with the first real implementation that requires them.
Architecture decisions can be documented directly in this issue.
Expected outcome
Before this issue is closed, the agreed design must answer:
- What represents an external signer integration?
- What represents a signing credential?
- Which capabilities must LibreSign know?
- What cryptographic information crosses the signing boundary?
- What does the external signer return?
- How do synchronous and asynchronous authorization fit the lifecycle?
- Which authorization state belongs to the integration and which belongs to the future signing session?
- Which concepts are common between CSC and ICP-Brasil PSC?
- Which concepts must remain protocol-specific?
- How can future local-device signing use the same core boundary?
- Where does integration runtime behavior stop and configuration begin?
- Where do assignment and policy responsibilities live?
These decisions should be recorded in this issue before implementation tasks that depend on them are opened.
Scope boundaries
Please keep this issue focused on architecture.
Do not:
- add production signing-provider abstractions;
- implement CSC;
- implement ICP-Brasil PSC;
- implement a local-device bridge;
- implement PKCS#11 communication;
- add provider database entities;
- add provider configuration APIs;
- add provider assignment;
- add policy configuration;
- add signing-session persistence;
- change existing signing methods;
- add frontend changes;
- add OAuth endpoints;
- implement PDF/PAdES logic.
Concrete implementation belongs in focused follow-up issues after the required decisions are clear.
Why this helps #8335
PDF/PAdES processing and access to the private key are separate responsibilities.
Without a common external-signing architecture, each integration could independently invent its own concepts for:
credential
authorization
capabilities
algorithm selection
signing operation
signature result
That would make CSC, ICP-Brasil PSC and future integrations harder to share and maintain.
Defining this boundary before the first provider implementation allows LibreSign to support multiple signing ecosystems without coupling remote protocols to PDF/PAdES or to one specific standard.
Done when
- External signer integration and credential have clear and separate meanings.
- Common external signer responsibilities are defined.
- PDF/PAdES responsibilities are explicitly outside this layer.
- Required credential and cryptographic capabilities are defined.
- Synchronous and asynchronous authorization flows fit the architecture.
- The cryptographic signing operation is compatible with the real external PDF lifecycle from #8354.
- Current CSC requirements have been checked against the proposed model.
- Current ICP-Brasil PSC requirements have been checked against the proposed model.
- Protocol-specific concepts that must remain outside the common domain are documented.
- Future local-device signing can fit the same architectural boundary without making remote HTTP concepts universal.
- Configuration, assignment and policy remain separate concerns.
- No speculative production code is added by this issue.
- The first concrete remote provider issue can be written without requiring its contributor to redesign the common domain.
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
Start by reading the requirements in this issue alongside #8354, then review the current CSC and ICP-Brasil PSC specifications. Record the common integration, credential, capability, authorization, cryptographic-operation, and result boundaries, including protocol-specific differences and compatibility with #8354. Done means the agreed architecture is documented here; no production code or test entry point is named.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cryptography
- Domain
- cryptography, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100