Benjamín Alcalde G.667 downloadsZero-dependency cryptographic digital signing (PAdES/PKCS#7) and custom running footer stamping for exported PDFs in Obsidian.
Requires Obsidian 1.13.0 or newer, matching the declarative settings refresh API used by this plugin. An independent TypeScript-symbol compatibility check now runs before every build and release; feature guards and ESLint suppression comments cannot bypass it. Historical releases retain their original minimum versions in versions.json.
Third-party copyright and license notices are included in the distributed main.js and in THIRD-PARTY-NOTICES.txt. node-forge is used under its BSD-3-Clause option. Bundled libraries include pdf-lib, its font/image/compression dependencies, tslib, node-forge, and the @signpdf packages.
On a new installation, explicitly choose Integrity signature or Certify before signing; the choice is remembered. Existing saved choices are preserved. Certify requests no later changes under DocMDP P=1; compatible readers evaluate that policy, but software can still edit a PDF.
New self-signed certificates use a local directory outside the vault, separated by vault. Existing certificate paths are preserved and files are not moved. Settings warn if a certificate is inside the vault, linked into it, or its location cannot be established. Review sync and backup exposure even when a path appears external. New PKCS#12 files encrypt the private key with AES-256/PBES2, PBKDF2 with SHA-256 PRF and 100,000 iterations. The node-forge writer still uses HMAC-SHA1 for the container MAC; this limitation is disclosed without claiming a modern MAC.
Export signing waits for a stable, complete PDF and validates it instead of sleeping for a fixed delay. The default deadline is 15 seconds, configurable from 5 to 60. Export integration is isolated in an adapter; when unsupported, manual PDF commands remain available. Verification presents signed-revision integrity and current-file coverage separately; trust, revocation and trusted timestamps are explicitly not checked.
Interoperability fixtures include synthetic PDFs generated independently with pyHanko and independently verified expected results. A real PDF containing two digital signatures is reported as unsupported by this limited checker. This is not a claim of universal interoperability, certificate trust or legal sufficiency. Incremental signing, TSA services and trust-list validation are not supported.
Use the PDF file's context menu or the commands for the active PDF to sign or check it. Signing an existing PDF opens a review of the file, certificate and signature mode, then creates a new .signed.pdf copy (with a unique suffix if needed); the original is preserved. Exported PDFs are signed after export. If a file changes while waiting in the signing queue, the job is refused so the current document is not signed with stale settings. If Windows blocks replacement of an exported PDF, the plugin creates a signed .signed.pdf copy without forcing a write to the locked file; the displayed filename and the PDF opened afterwards refer to that copy.
Certificate details show the subject, issuer and SHA-256 fingerprint stated by the certificate, plus whether it is self-signed. These details help identify the configured certificate; they do not establish identity or trust. Creating a self-signed certificate is an explicit Settings action. If the configured file exists, a new file is chosen and the previous certificate is preserved; this does not renew a provider-issued certificate.
Input limits are 64 MiB per PDF and 4 MiB per PKCS#12 certificate. Signed output is also limited to 64 MiB; a PDF close to the input limit can be rejected after signing increases its size. Before saving, every generated signature must pass the plugin's local cryptographic and complete-file coverage checks. This is an integrity check, not a trust or legal assessment.
P=1. Compatible readers can reject later changes against that policy. Software that ignores it can still edit the PDF.Configure an existing .pfx/.p12 and its password, or explicitly create a self-signed certificate using Settings. Missing certificates are not silently replaced. Self-signed certificates can help with personal integrity checks; recipients must establish trust separately.
Use Check PDF signature integrity from the command palette or PDF file menu. It checks supported signatures and complete-file coverage, detecting appended bytes. Unsupported structures receive an explicit unsupported result. It does not validate trust chains, revocation, trusted timestamps, permitted modifications, PAdES compliance or legal sufficiency. For optional independent validation and trust configuration, see pyHanko's guide.
Trusted timestamps, PAdES T/LT/LTA, provider tokens and remote signing are unsupported. PAdES B compliance is not claimed. Technical profiles differ from legal signature categories.
References: ETSI PAdES, European Commission FAQ, Chile — Law 19,799, UK ICO, US — 15 USC 7001.
Languages / Idiomas / Lingue: 🇬🇧 English | 🇪🇸 Español | 🇧🇷 Português | 🇮🇹 Italiano | 🇫🇷 Français
No external tools: JavaScript / TypeScript
PDF Digital Signature is a lightweight plugin with bundled JavaScript libraries for Obsidian that seamlessly integrates cryptographic digital signatures (PKCS#7 / X.509) and custom running footers into your exported PDF documents.
The signature allows a PDF reader to check whether the signed content has changed. Trust in the signer depends on the certificate and the reader’s trust settings. A self-signed certificate is not automatically trusted.
.pfx / .p12). Detects changes to signed content; it does not prevent editing the PDF.page / total) on the bottom-right across all pages.node-forge + pdf-lib + @signpdf). No Python, no OpenSSL, no terminal commands required.en), Spanish (es), Portuguese (pt), Italian (it), and French (fr), automatically matching your Obsidian display language.Ctrl + P / Cmd + P ➔ Export to PDF)..pfx certificate.https://github.com/Benhaman9/obsidian-pdf-digital-signaturemain.js, manifest.json, and styles.css from the Latest Release.pdf-digital-signature in your vault's .obsidian/plugins/ directory.In Obsidian's Settings ➔ PDF Digital Signature:
| Setting | Description | Default |
|---|---|---|
| Cryptographically sign by default | Applies the PKCS#7 signature independently from footer content. | true |
| Show signer name by default | Whether the signer name appears at the bottom-left. | true |
| Signer name (Running footer) | The text displayed when the signer-name option is enabled. | Name of Signer |
| Display page number | Displays page / total on the bottom-right. |
true |
| Maximum export wait | Deadline for a complete, stable PDF; configurable from 5 to 60 seconds. | 15 seconds |
| Open PDF after signing | Automatically opens your default PDF viewer once signed. | true |
| Certificate file path | Existing paths are retained; new certificates use a local directory outside the vault. | Per-vault local path outside the vault |
| Certificate password | Password used to decrypt your certificate. | Randomly generated on first load |
| Reason / Location | Signature metadata displayed in Adobe Acrobat. | Generic placeholders |
If you own an accredited digital signature (such as a commercial X.509 certificate in .p12 or .pfx format), keep it in a protected location outside your vault and enter its absolute path and password in the settings.
This project is licensed under the MIT License.
Made with ❤️ by Benjamín Alcalde G.
A random password is generated on first load. You can change it before creating a certificate; a blank password is refused for new certificates. Obsidian 1.13.0 or newer is required. The password is kept in the vault's local SecretStorage instead of the plugin's data.json; existing passwords are migrated when the plugin loads. Configure it separately on each device. Older vault backups or sync history may still contain the former plaintext value, so review those copies and rotate the certificate if it was exposed. Creating a self-signed certificate never overwrites the configured certificate. Expired or not-yet-valid certificates cannot be used to sign. Existing signed PDFs are rejected because this plugin rewrites the PDF rather than adding an incremental signature. The signature uses adbe.pkcs7.detached; full PAdES profile conformance, trusted timestamps and long-term validation are not claimed.
Malformed PDF objects are rejected rather than recovered during signing. XRef streams are checked before allocating entries: safe counts and byte widths, enough decoded bytes, and at most 100,000 entries per stream. Widths above four bytes are unsupported by the pinned parser's bitwise implementation. These limits prevent the reviewed count-amplification path. Version 1.0.13 also caps decoded stream buffers at 64 MiB each and 128 MiB of cumulative buffer growth per document load, before allocation, across supported decoding filters. Documents exceeding these limits fail explicitly. These are parser allocation guards, not a total process-memory or CPU limit on every PDF feature.
Adobe: certificate trust · Signing library
This desktop plugin uses Node filesystem APIs to sign the export destination selected by the user and to read the configured PKCS#12 certificate, including paths outside the vault. New certificate locations default outside the vault to reduce accidental sync exposure. The fallback PDF picker enumerates vault file paths and filters them to PDFs; it does not read every file's contents. Signing, certificate generation, and signature inspection run locally without network requests.
Use Node 24, then run npm ci, npm run lint, npm run typecheck, npm run check:api, npm run build, and npm test. The official Obsidian ESLint configuration is checked with zero warnings. The build rejects an installed node-forge version that differs from the pinned dependency, so stale dependencies cannot silently enter a release.
Settings use searchable definitions on the minimum supported version, Obsidian 1.13.0. The certificate-password row retains its SecretStorage handler rather than automatic JSON persistence.
To release, push the version commit and matching tag, create a draft GitHub release, and dispatch the Build, attest, and publish release workflow with that tag. The workflow checks the bundle against the committed source, runs the checks, uploads the three assets, creates provenance attestations, and publishes the draft only after those attestations exist. Disable its publish input to inspect the attested draft first. Verify a downloaded asset with gh attestation verify main.js --repo Benhaman9/obsidian-pdf-digital-signature.