365 Digital Signature

Digital Signature

Sign a PDF with an X.509 certificate (RSA 2048 + SHA-256). The signature is stored inside the PDF - Adobe Acrobat Reader shows it in the Signatures panel - and any change to the file afterwards breaks it. You can also add a hand-drawn signature to the visible stamp.

Sign a document

Hand-drawn signature (optional) - draw with the mouse or finger

Signing certificate

SubjectC=TH,O=Northwind Print Co. Ltd.,CN=PrintDoc Lab Signing Authority
Valid25 Oct 2026 - 23 Oct 2036
KeyRSA SHA256withRSA
SHA-256A8:8A:5F:46:BF:7A:16:56:01:1D:40:25:74:D8:C8:04:F2:9B:67:30:A1:35:A4:B1:45:1D:1A:C7:C9:1A:C9:D9

Self-signed and created on the first start (data/signing/lab-signer.p12). Readers show it as "validity unknown" until you trust it - in real life a certificate authority signs it.

Download certificate (.cer)

Verify a signed PDF

Try it: download a signed file, change one byte (or "print to PDF" it again) and verify - the result turns red.

Signed documents

table signed_document
WhenDocumentSignerReasonSHA-256 (signed file)Size
Nothing signed yet.
How it works
  1. Key + certificate: Java KeyPairGenerator (RSA 2048) and Bouncy Castle JcaX509v3CertificateBuilder, saved in a PKCS#12 keystore.
  2. Visible stamp: OpenPDF PdfStamper.getOverContent(lastPage) draws the box and the drawn signature PNG.
  3. Signature: PDFBox reserves space in the file and hands the bytes around it to our callback; Bouncy Castle creates a detached CMS (PKCS#7) signature over them; saveIncremental writes it in.
  4. Verify: take the signed byte range, check the CMS signature with the certificate inside it, and check the byte range reaches the end of the file (nothing was appended later).
PDSignature sig = new PDSignature();
sig.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
sig.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
sig.setName("Somchai Prasert"); sig.setReason("I approve this document");
doc.addSignature(sig, content -> {
    CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
    ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA").build(privateKey);
    gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digestProvider).build(signer, certificate));
    gen.addCertificates(new JcaCertStore(List.of(certificate)));
    return gen.generate(new CMSProcessableByteArray(content.readAllBytes()), false).getEncoded();
});
doc.saveIncremental(out);

Files: service/SignatureService.java, web/ShareSecureController.java.