Commit graph

556 commits

Author SHA1 Message Date
Vitor Mattos
73615a77d4
fix: use correct Nextcloud instanceid in PKI path initialization
The initializePkiConfigPath method was using a variable named
'instanceId' from getSystemValue('instanceid') which could be confused
with LibreSign's instance_id. Changed to 'systemInstanceId' for clarity
and consistency with getConfigPathByParams method.

This ensures the PKI directories are created in the correct appdata path
using Nextcloud's system instance ID, while the directory name itself
contains LibreSign's CA identifier with its own instance ID.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-17 02:36:56 -03:00
Vitor Mattos
3d4bdf0294
fix: filter CA ID from OU only when certificate not generated
The CA ID (libresign-ca-id:...) in OrganizationalUnit should only be
filtered out when the certificate is not generated (isSetupOk() returns
false). When the certificate is successfully generated, the CA ID must
be preserved in the API response.

This ensures:
- Generated certificates: CA ID is visible (expected behavior)
- Failed/not generated: CA ID is filtered to prevent stale data in form

Integration tests validated:
- features/account/signature.feature:2 (OpenSSL)
- features/account/signature.feature:23 (CFSSL)
- features/admin/certificate_openssl.feature:2
- features/admin/certificate_openssl.feature:35

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-15 17:39:24 -03:00
Vitor Mattos
249f0837b0
fix: prevent stale configPath and CA ID exposure in root certificate API
Filter configPath from API response when certificate is not generated to prevent
form pre-population with outdated generation numbers that cause validation errors.

Filter CA ID (libresign-ca-id:*) from OrganizationalUnit field to prevent users
from submitting stale generation values that conflict with certificate validation.

Refactor toArray() method by extracting logic into dedicated methods:
- getConfigPathForApi(): Returns empty string for non-generated certificates
- removeCaIdFromOrganizationalUnit(): Filters CA IDs from OU arrays

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-15 16:57:17 -03:00
Vitor Mattos
9274075bf8
chore: update dependencies and handler
Update composer.json and Pkcs12Handler changes from refactoring.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-15 15:53:02 -03:00
Vitor Mattos
04c79e4018
Merge pull request #6128 from LibreSign/fix/prevent-error-when-folder-doesnt-exists
fix: prevent error when folder doesn't exists
2025-12-11 16:25:48 -03:00
Vitor Mattos
abd1a97d19
Merge pull request #6054 from LibreSign/feat/disable-identify-methods-none-engine
feat: disable identify methods none engine
2025-12-09 13:03:10 -03:00
Vitor Mattos
ab271dfb11
fix: validate CFSSL-specific config files in isSetupOk()
When switching from OpenSSL to CFSSL engine without configuring CFSSL,
the configure-check was incorrectly showing 'success' status instead of
'error'. This happened because isSetupOk() only checked for ca.pem and
ca-key.pem files, which are common to both engines and shared in the
same config_path directory.

Now isSetupOk() also verifies the presence of CFSSL-specific files
(csr_server.json and config_server.json) to ensure it's a valid CFSSL
configuration and not just leftover OpenSSL files.

This fix ensures the certificate_engine_switch integration test passes.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-09 12:48:33 -03:00
Vitor Mattos
ca05fe55f2
feat: add setEngine method to configure identify methods
Add setEngine() method to IEngineHandler interface and implement
in AEngineHandler to automatically configure identify methods based
on certificate engine selection.

When engine is 'none', only account identification is enabled since
no certificate infrastructure is available for other methods.

Related to #5145

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-09 12:42:00 -03:00
Vitor Mattos
0dd43eb364
feat: add DocMDP validation handler for PDF signature permissions
- Implement DocMdpHandler to validate PDF Document Modification Detection and Prevention (DocMDP)
- Add allowsAdditionalSignatures() method to check if PDF permits additional signatures
- Support detection of DocMDP level 1 (no changes allowed) certification
- Parse PDF signature dictionaries and transformation parameters
- Prevent signatures on DocMDP level 1 certified documents per PDF specification
- Enable compliance with PDF document certification and signature workflows

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-08 16:53:50 -03:00
Vitor Mattos
9d65c3b07b
feat: add DocMdpHandler::allowsAdditionalSignatures()
Add public method to check if DocMDP level allows additional signatures.
Returns false only for CERTIFIED_NO_CHANGES_ALLOWED (level 1).

Required for FileService to validate signature requests against DocMDP policy.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-08 16:53:49 -03:00
Vitor Mattos
6b6634c87c
style: fix code style (phpcs)
Remove unused import and fix PHPDoc formatting:
- Remove unused DocMdpLevel import from JSignPdfHandler
- Fix trailing whitespace in AdminController PHPDoc

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-08 16:53:49 -03:00
Vitor Mattos
89a5eb9dd4
feat: integrate DocMDP certification level in JSignPdfHandler
Add DocMDP support to JSignPdf signing process:
- Inject DocMdpConfigService to access admin configuration
- Add getCertificationLevel() to retrieve enabled level name
- Append -cl parameter to JSignParam when DocMDP is enabled
- Uses enum->name directly for JSignPdf compatibility

When DocMDP is enabled, JSignPdf will certify PDFs with configured level:
NOT_CERTIFIED, CERTIFIED_NO_CHANGES_ALLOWED, CERTIFIED_FORM_FILLING,
or CERTIFIED_FORM_FILLING_AND_ANNOTATIONS.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-08 16:53:48 -03:00
Vitor Mattos
957114bf3d
refactor: update DocMdpHandler to use new enum names
Update all references to DocMdpLevel enum cases:
- NONE → NOT_CERTIFIED
- NO_CHANGES → CERTIFIED_NO_CHANGES_ALLOWED
- FORM_FILL → CERTIFIED_FORM_FILLING
- FORM_FILL_AND_ANNOTATIONS → CERTIFIED_FORM_FILLING_AND_ANNOTATIONS

Updated in:
- ALLOWED_MODIFICATIONS constant
- extractDocMdpLevel() fallback values
- getAllowedModificationMessage() match expression
- getViolationMessage() match expression
- validateModifications() condition checks

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-06 17:56:27 -03:00
Vitor Mattos
45827cd70c
fix: validate empty commonName in certificate generation
- Add validation to prevent empty Common Name (CN) in OpenSslHandler and CfsslHandler
- Throw EmptyCertificateException with clear message when CN is empty
- Fix JSignPdfHandlerTest to use valid commonName 'Test Root CA'
- Add unit test to verify empty CN validation works correctly

The owner field in libresign_crl table is mandatory without default value.
Previously, generateRootCert('') would fail at database level with unclear
error. Now it fails early with proper validation message.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-06 17:50:00 -03:00
Vitor Mattos
a7c214325d
fix(phpcs): add space after fn keyword in closures
Follow PHP-CS-Fixer standards for short arrow function syntax.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-06 16:38:34 -03:00
Vitor Mattos
e73eed6b7c
feat(DocMdpHandler): implement full ISO 32000-1 DocMDP validation
Implement complete validation of DocMDP (Modification Detection and Prevention)
according to ISO 32000-1:2008 and ICP-Brasil ITI requirements.

ISO 32000-1 compliance:
- Section 12.8.2.2.1: Enforce single DocMDP signature per document
- Section 12.8.2.2.1: Validate DocMDP is first certifying signature
- Table 252: Validate signature dictionary (/Type /Sig, /Filter, /ByteRange)
- Table 253: Validate signature reference (/TransformMethod /DocMDP)
- Table 254: Validate TransformParams (/P, /V /1.2)

ICP-Brasil ITI requirements:
- Extract DocMDP from /Reference (not /Perms) per ITI recommendation
- Support indirect references (168 0 R → 170 0 R pattern)
- Require /V /1.2 version in TransformParams
- Handle both inline and indirect TransformParams

Code improvements:
- Add ALLOWED_MODIFICATIONS constant for configuration-based validation
- Extract helper methods: validateIsoCompliance(), extractPValue()
- Create parsePdfObjects() to eliminate regex duplication
- Simplify validateModifications() using match expressions
- Pattern-based modification detection in analyzeModificationType()
- Comprehensive docblocks with ISO/ITI references

Refs: ISO 32000-1:2008 §12.8.2.2, ITI Guia Desenvolvedor Cap VI
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-06 16:38:34 -03:00
Vitor Mattos
1cc4d2eb4b
refactor: integrate DocMdpHandler in Pkcs12Handler
- Inject DocMdpHandler in constructor
- Delegate DocMDP extraction to dedicated handler
- Simplify extractDocMdpData() to single delegation call
- Remove DocMDP logic from signature processing handler
- Improve separation of concerns

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-06 16:38:34 -03:00
Vitor Mattos
73cec936dd
feat: create DocMdpHandler for PDF modification detection
- Create dedicated handler for DocMDP (Document Modification Detection and Prevention)
- Implement extractDocMdpData() as single public API
- Add private methods for level extraction, modification detection, and validation
- Support all DocMDP levels with proper validation logic
- Clean architecture with minimal dependencies (only IL10N required)

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-06 16:15:30 -03:00
Vitor Mattos
91df5fbc82
refactor: inject TemplateVariables into FooterHandler via DI
- Add TemplateVariables as constructor parameter
- Remove manual instantiation with 'new TemplateVariables()'
- Add getTemplateVariablesMetadata() method exposing metadata
- Update tests to use real TemplateVariables instance instead of mock
- Test getTemplateVariablesMetadata returns complete metadata structure

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 21:13:37 -03:00
Vitor Mattos
7530a83000
refactor: add IL10N injection and metadata to TemplateVariables
- Add IL10N dependency injection for translations
- Replace const ALLOWED_VARIABLES with instance property
- Add initializeVariablesMetadata() method with full metadata
- Add getVariablesMetadata() method returning associative array
- Include type, description, example, and optional default for each variable
- Add defaults for signedBy, linkToSite, and validateIn variables
- Update tests with IL10N mock and comprehensive coverage
- Add DataProviders for testing defaults and types

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 21:12:17 -03:00
Vitor Mattos
241e74c25f
chore: move footer.twig SPDX headers to REUSE.toml
- Remove inline SPDX comment from footer.twig template
- Add lib/Handler/Templates/footer.twig to REUSE.toml annotations

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 17:23:17 -03:00
Vitor Mattos
2fb9a577fe
feat: add getDefaultTemplate method to FooterHandler
Extract default template loading into a separate public method
to allow other services to access the default template content.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 16:32:46 -03:00
Vitor Mattos
10b5dde339
feat: make FooterHandler::getTemplate() public
Expose getTemplate() method to allow external access to the
footer template logic (custom or default).

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 15:42:34 -03:00
Vitor Mattos
5c2a7c7179
style: sort TemplateVariables constants and PHPDoc alphabetically
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 13:58:01 -03:00
Vitor Mattos
6c27ee100a
fix: cs
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 13:50:13 -03:00
Vitor Mattos
5d06f355d1
refactor: use TemplateVariables value object in FooterHandler
Replace raw array with TemplateVariables class for better type safety
and explicit contract of available template variables.

Changes:
- Use TemplateVariables instance instead of array
- Replace array access with typed getters/setters
- Maintain backward compatibility via setTemplateVar()
- Improved code readability with explicit method names

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 13:49:13 -03:00
Vitor Mattos
cb795f2775
feat: add TemplateVariables value object with type validation
Introduces a type-safe collection class for footer template variables
using magic methods (__call) with runtime type validation.

Benefits:
- Whitelist of allowed variables with expected types
- Runtime type checking for all setters
- Fluent interface for method chaining
- Clean API with only ~70 lines of code
- Prevents invalid variables or type mismatches

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 13:49:13 -03:00
Vitor Mattos
36cab0f7cf
fix: prevent error when generating QR code without validationSite
Only generate QR code if validationSite is available in templateVars.
This prevents undefined array key error when uuid is not set.

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 13:49:13 -03:00
Vitor Mattos
2f62c302f0
refactor: decouple FooterHandler from FileEntity
Breaking changes:
- getFooter() now accepts only array $dimensions parameter
- UUID must be set via setTemplateVar('uuid', $uuid) before calling getFooter()

Changes:
- Remove FileEntity dependency from getFooter() signature
- Allow customization of all template variables via setTemplateVar()
- Only fetch default values from appConfig if not already customized
- Check if 'uuid' exists in templateVars before building validationSite

Benefits:
- Reduced coupling - no dependency on FileEntity
- More flexible - all variables customizable via same API
- Cleaner design - consistent use of setTemplateVar() for all variables
- Easier testing - no need to mock FileEntity

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 13:49:06 -03:00
Vitor Mattos
ce69c0a77f
refactor: reduce coupling in FooterHandler
- Remove $file property to reduce coupling
- Make getMetadata() public and accept File as parameter
- Change getFooter() to receive dimensions array instead of File
- This allows more flexibility and reduces dependencies

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-04 09:07:34 -03:00
Vitor Mattos
9adaadaece
Merge pull request #5916 from LibreSign/fix/handle-corrupted-signature-data
fix: handle corrupted signature data
2025-12-02 10:58:18 -03:00
Vitor Mattos
3ec5e3871f
fix: handle corrupted signature data in PDF validation
When processing PDF signatures, hex2bin() and stream_get_contents()
can fail and return false when dealing with corrupted or malformed
signature data. Previously, this would cause a TypeError when false
was passed to processSignature() which expects ?string.

Now, invalid signatures are properly reported to users with a
'Digest Mismatch' validation error instead of causing a fatal error.

This fix:
- Validates hex2bin() return value before yielding
- Validates stream_get_contents() return value before processing
- Returns null for corrupted signatures which are then reported as invalid
- Suppresses expected hex2bin() warnings for non-hexadecimal data

Fixes the issue reported where users encountered:
TypeError: Argument #2 ($signature) must be of type ?string, false given

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-02 10:44:20 -03:00
Vitor Mattos
3885c7376f
fix: preserve specific error messages in certificate generation
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-02 10:31:55 -03:00
Vitor Mattos
754fc024f0
feat: improve error messages for revoked/expired root certificates
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-02 10:31:48 -03:00
Vitor Mattos
6e745cd10e
feat: integrate certificate type in OpenSSL and CFSSL handlers
- Pass CertificateType::ROOT->value for root certificate generation
- Pass CertificateType::LEAF->value for user certificate generation
- Include issuer and subject DN data in serial number generation
- Ensure proper enum to string conversion for database storage

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 19:16:17 -03:00
Vitor Mattos
f2b699f8e2
feat: validate root cert validity at config page
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 16:32:51 -03:00
Vitor Mattos
b5074c5086
fix: prevent error when directory does not exsits
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 16:11:45 -03:00
Vitor Mattos
fa79baf0a9
chore: error handler
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 15:47:37 -03:00
Vitor Mattos
1e72bc83b6
chore: remove docblock
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 15:45:32 -03:00
Vitor Mattos
f34df31452
chore: use full FQCN
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 15:44:38 -03:00
Vitor Mattos
d9e0ed2bca
fix: silently skip validation when root certificate is not configured
- Return early without throwing exception if ca.pem doesn't exist
- Return early if certificate file is empty
- Only validate when a proper root certificate is actually configured
- Fixes Pkcs7HandlerTest and Pkcs12HandlerTest that run without CA setup

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 15:41:58 -03:00
Vitor Mattos
5ac4f41118
fix: add Override attribute to validateRootCertificate method
Fixes Psalm static analysis error MissingOverrideAttribute

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 15:04:03 -03:00
Vitor Mattos
b3212d099b
fix: make root certificate validation optional for unconfigured environments
- Return early if configPath is empty (test environments without CA)
- Still throw exception if CA path exists but certificate is missing/empty
- Prevents validation errors in unit tests without breaking production validation
- Fixes Pkcs7HandlerTest and Pkcs12HandlerTest failures

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 14:58:10 -03:00
Vitor Mattos
5db3867990
fix: cs
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 14:53:46 -03:00
Vitor Mattos
52f8013863
feat: validate root certificate before signing documents
- Add beforeSign() hook in SignEngineHandler base class
- Automatically validate root certificate in all sign() implementations
- Apply to JSignPdfHandler, Pkcs12Handler, and Pkcs7Handler
- Encapsulate validation logic within sign engine handlers
- Prevent signing with revoked/expired root certificates

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 14:46:46 -03:00
Vitor Mattos
9365547422
feat: validate root certificate before generating user certificates
- Call validateRootCertificate() in OpenSslHandler::generateCertificate()
- Call validateRootCertificate() in CfsslHandler::generateCertificate()
- Prevent issuing certificates from revoked/expired root CA
- Ensure root CA has sufficient validity to sign CRLs for issued certs

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 14:46:46 -03:00
Vitor Mattos
33a0289aed
feat: implement root certificate validation logic
- Add validateRootCertificate() method to check certificate health
- Verify certificate is not revoked via CRL
- Verify certificate has not expired
- Check if renewal is needed based on remaining validity
- Calculate renewal timing: remaining_days <= leaf_expiry_days
- Log warnings when renewal is recommended
- Throw LibresignException with clear messages on critical issues

Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-12-01 14:46:46 -03:00
Vitor Mattos
1019231caf
Merge pull request #5854 from LibreSign/refactor/remove-pem-fallback-crl-command
refactor: remove PEM fallback from CRL command
2025-11-29 14:10:02 -03:00
Vitor Mattos
c5a2cd959c
refactor: remove PEM fallback from CRL command
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-11-29 13:53:50 -03:00
Vitor Mattos
c7fee441f2
fix: crl serial number without zeros at left side
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com>
2025-11-29 13:51:45 -03:00