# How to Implement Digital Signatures Using the CertSignController in Stirling-PDF

> Learn how to implement digital signatures with CertSignController in Stirling-PDF. This guide details using the POST endpoint for cryptographically signed documents and visible overlays with Apache PDFBox.

- Repository: [Stirling Tools/Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF)
- Tags: how-to-guide
- Published: 2026-03-01

---

**The CertSignController exposes a POST endpoint at `/api/v1/security/cert-sign` that consumes multipart certificate files and PDFs to generate cryptographically signed documents using Apache PDFBox and BouncyCastle, supporting both visible digital signature overlays and invisible certification.**

The **Stirling-Tools/Stirling-PDF** repository provides a Spring Boot-based backend for PDF manipulation. To **implement digital signatures using the CertSignController**, you interact with the [`app/core/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/core/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java) class, which orchestrates keystore creation, certificate chain validation, and PDF cryptographic signing through a standardized multipart HTTP interface.

## CertSignController Endpoint Architecture

The controller exposes a single REST endpoint mapped via `@AutoJobPostMapping` to handle certificate-based signing operations.

### Request Mapping and DTO Binding

The endpoint listens at `POST /api/v1/security/cert-sign` and consumes `multipart/form-data`. Spring automatically binds incoming requests to the `SignPDFWithCertRequest` DTO defined in [`app/core/src/main/java/stirling/software/SPDF/model/api/security/SignPDFWithCertRequest.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/core/src/main/java/stirling/software/SPDF/model/api/security/SignPDFWithCertRequest.java).

This DTO extends `PDFFile` and encapsulates:

- The source PDF file (`fileInput`)
- Certificate files (PEM key pairs, PKCS12/PFX stores, or JKS keystores)
- Passwords for encrypted private keys
- Visual signature options (page number, coordinates, logo display, signer metadata)

### Certificate Type Handling

The controller supports four certificate input modes via the `certType` parameter:

1. **PEM**: Separate private key and certificate files parsed using BouncyCastle helpers (`getPrivateKeyFromPEM`, `getCertificateFromPEM`)
2. **PKCS12/PFX**: Standard `.p12` or `.pfx` keystore files
3. **JKS**: Java KeyStore format
4. **SERVER**: Server-side keystore retrieved via `ServerCertificateServiceInterface`

Based on the type, the controller constructs a Java `KeyStore` containing the private key and certificate chain (lines 93-124). The static initializer registers BouncyCastle as a security provider (`Security.addProvider(new BouncyCastleProvider())`) to enable PEM parsing and cryptographic operations.

## PDF Signing Implementation

The actual signing logic resides in the inner class `CreateSignature`, which extends PDFBox's `CreateSignatureBase`, and the static `sign` helper method.

### Signature Engine Initialization

When processing a request, the controller instantiates `CreateSignature` with the prepared `KeyStore`. The constructor (lines 107-125 in [`CertSignController.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CertSignController.java)) loads an optional logo image (`signature.png`) from resources for visual signatures and initializes the cryptographic parameters.

### Document Signing Process

The static `sign` method (lines 165-199) performs the following operations:

- Loads the input PDF using `CustomPDFDocumentFactory` to create a `PDDocument` instance
- Constructs a `PDSignature` object with metadata (reason, location, signer name, date)
- Determines signature visibility based on the `showSignature` flag
- For visible signatures, creates `SignatureOptions` and calls `instance.createVisibleSignature`
- For invisible signatures, applies the cryptographic signature without visual artifacts
- Writes the signed PDF bytes to an `OutputStream`

### Visual Signature Generation

The `createVisibleSignature` method (lines 128-170) generates the visual overlay by:

- Creating a form XObject for the signature appearance on the specified page
- Rendering the optional logo via `PDImageXObject`
- Drawing signer information extracted from the X.509 certificate (name, date, reason)

The final signed PDF bytes are wrapped in a `ResponseEntity<byte[]>` via `WebResponseUtils.bytesToWebResponse` (lines 262-264) with the filename pattern `*_signed.pdf`.

## Implementation Examples

### cURL HTTP Request

For command-line integration or testing, submit a multipart POST request:

```bash
curl -X POST "http://localhost:8080/api/v1/security/cert-sign" \
  -F "fileInput=@sample.pdf" \
  -F "certType=PKCS12" \
  -F "p12File=@mycert.p12" \
  -F "password=secret123" \
  -F "showSignature=true" \
  -F "pageNumber=1" \
  -F "showLogo=true" \
  -F "reason=Approved" \
  -F "location=New York" \
  -F "name=John Doe" \
  -o signed_sample.pdf

```

The multipart fields map directly to properties of `SignPDFWithCertRequest`.

### Java Client Using Spring RestTemplate

For programmatic integration in Java applications:

```java
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
body.add("fileInput", new FileSystemResource("sample.pdf"));
body.add("certType", "PEM");
body.add("privateKeyFile", new FileSystemResource("private_key.pem"));
body.add("certFile", new FileSystemResource("certificate.pem"));
body.add("password", "myPassword");
body.add("showSignature", true);
body.add("pageNumber", 1);
body.add("showLogo", true);
body.add("reason", "Contract approval");
body.add("location", "Berlin");
body.add("name", "Alice Smith");

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);

HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(body, headers);
ResponseEntity<byte[]> response = restTemplate.postForEntity(
        "http://localhost:8080/api/v1/security/cert-sign",
        request,
        byte[].class);

Files.write(Paths.get("sample_signed.pdf"), response.getBody());

```

Spring automatically populates the `SignPDFWithCertRequest` DTO from the multipart map.

### Unit Testing the Controller

For internal testing or custom extensions, invoke the controller directly:

```java
@MockBean private ServerCertificateServiceInterface serverCertificateService;
@Autowired private CertSignController certSignController;
@Autowired private CustomPDFDocumentFactory pdfFactory;

@Test
void signPdfWithPem() throws Exception {
    MockMultipartFile pdf = new MockMultipartFile("fileInput", "doc.pdf",
            "application/pdf", Files.readAllBytes(Paths.get("src/test/resources/doc.pdf")));
    MockMultipartFile key = new MockMultipartFile("privateKeyFile", "key.pem",
            "application/octet-stream", Files.readAllBytes(Paths.get("src/test/resources/key.pem")));
    MockMultipartFile cert = new MockMultipartFile("certFile", "cert.pem",
            "application/octet-stream", Files.readAllBytes(Paths.get("src/test/resources/cert.pem")));

    SignPDFWithCertRequest req = new SignPDFWithCertRequest();
    req.setFileInput(pdf);
    req.setCertType("PEM");
    req.setPrivateKeyFile(key);
    req.setCertFile(cert);
    req.setPassword("");   // PEM keys may be unencrypted
    req.setShowSignature(true);
    req.setPageNumber(1);
    req.setShowLogo(true);
    req.setReason("Test");
    req.setLocation("Test Lab");
    req.setName("Tester");

    ResponseEntity<byte[]> resp = certSignController.signPDFWithCert(req);
    assertEquals(HttpStatus.OK, resp.getStatusCode());
    assertTrue(resp.getBody().length > 0);
}

```

This test bypasses the HTTP layer while exercising the same code path used by the REST endpoint.

## Key Source Files and Dependencies

Understanding the controller requires familiarity with these components:

- **[`CertSignController.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CertSignController.java)**: Main orchestrator located at [`app/core/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/core/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java) that handles request mapping, certificate validation, and response generation.
- **[`SignPDFWithCertRequest.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/SignPDFWithCertRequest.java)**: DTO at [`app/core/src/main/java/stirling/software/SPDF/model/api/security/SignPDFWithCertRequest.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/app/core/src/main/java/stirling/software/SPDF/model/api/security/SignPDFWithCertRequest.java) defining the multipart request structure.
- **[`CustomPDFDocumentFactory.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CustomPDFDocumentFactory.java)**: Wrapper service for PDFBox `PDDocument` loading with application-specific memory and configuration handling.
- **[`ServerCertificateServiceInterface.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/ServerCertificateServiceInterface.java)**: Service interface for retrieving server-side keystores when using `certType=SERVER`.
- **[`WebResponseUtils.java`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/WebResponseUtils.java)**: Utility class for converting byte arrays to proper `ResponseEntity` objects with correct HTTP headers.
- **Apache PDFBox**: Provides core PDF manipulation primitives (`PDDocument`, `PDSignature`, `SignatureOptions`, `CreateSignatureBase`).
- **BouncyCastle**: Enables PEM parsing and cryptographic provider services via `PEMParser` and `JcaPEMKeyConverter`.

## Summary

- The **CertSignController** exposes `POST /api/v1/security/cert-sign` for certificate-based PDF signing in Stirling-PDF.
- It supports **PEM, PKCS12/PFX, JKS, and SERVER** certificate types through BouncyCastle-backed keystore creation.
- The **CreateSignature** inner class extends PDFBox's `CreateSignatureBase` to handle cryptographic signing and optional visual overlays.
- **Visual signatures** include configurable logos, signer names, dates, and reasons rendered via PDFBox form XObjects.
- The controller returns signed PDF bytes wrapped in a `ResponseEntity` with standardized headers via `WebResponseUtils`.

## Frequently Asked Questions

### What certificate formats does CertSignController support?

The controller supports four certificate formats: **PEM** (separate key and certificate files), **PKCS12/PFX** (standard keystores), **JKS** (Java KeyStore), and **SERVER** (server-side keystore retrieval). PEM files are parsed using BouncyCastle helpers, while PKCS12 and JKS files are loaded directly into a Java `KeyStore` object. The SERVER type delegates keystore retrieval to the `ServerCertificateServiceInterface` implementation.

### How does the controller handle visual versus invisible signatures?

The `showSignature` parameter in the request DTO determines visibility. When `true`, the controller calls `createVisibleSignature` to render a signature appearance containing the signer name, date, reason, and optional logo on the specified page. When `false`, the controller applies a cryptographic signature without visual artifacts, certifying the document without modifying its visible content.

### Can I use the CertSignController for batch processing or automated workflows?

Yes, the endpoint is annotated with `@AutoJobPostMapping`, indicating integration with Stirling-PDF's job automation framework. The multipart interface accepts standard HTTP clients, making it suitable for batch scripts using cURL or automated Java clients using `RestTemplate` or `WebClient`. For high-volume server-side signing, configure the **SERVER** certificate type to avoid transferring certificate files with each request.

### What dependencies are required for the cryptographic operations?

The implementation requires **Apache PDFBox** for PDF manipulation and **BouncyCastle** for cryptographic operations and PEM parsing. The controller registers BouncyCastle as a security provider during class initialization. The `CustomPDFDocumentFactory` provides additional application-specific PDF loading configuration, while Spring Boot handles the REST layer and multipart file binding.