A digital signature is cryptographically secure and verifies that someone with your private signing key (in other words, you) has seen the document and authorized it.

The visual representation of a digital signature in a PDF document is a widget annotation. A widget annotation is a specific type of annotation.

In PDF, you have the actual content of a page. This content is stored in a content stream. A page is defined in a page dictionary. There's a /Contents entry in this page dictionary that refers to one of more content streams. Together these content streams contain the syntax that describes the content of a page.

Annotations are not part of any of those streams. Annotations are referred to from the page dictionary using the /Annots entry. In your case, there is an /Annots entry that refers to a widget annotation with the appearance of your signature.

You can read more about PDF digital signatures here but before continue let's first talk about some key concepts.

1 Introduction

1.1 Private key

To sign a PDF document you need to access the private key. But sometimes this can not be safe.

How do I get a private key that is on my smart card ? There would be a serious security problem if you could extract a private key from a smart card. Your private key is secret, and the smart card should be designed to keep this secret safe. You don’t want an external application to use your private key. Instead, you send a hash to the card, and the card returns a signature or a PKCS#7 message. PKCS refers to a group of Public Key Cryptography Standards, and PKCS#7 defines the Cryptographic Message Syntax Standard.

Signing a PDF document using a smart-card reader involves middleware, and the code will depend on the type of smart-card reader you’re using. To get an idea of what needs to be done, we’ll look at some examples where the digest is made or signed externally.

Now let’s discuss some technologies that provide extra security features.

1.2 CRLs, OCSP, and timestamping

Suppose you receive a contract from person X who works at company Y. You can safely assume that the document is genuine, unless … person X was fired, but he still owns a copy of the private key of company Y. Such a contract probably wouldn’t be legal. Surely there must be a way for company Y to revoke the certificate for employee X so that he no longer can act on behalf of his former company.

1.2.1 Certificate Revocation List (CRL)

Every certificate authority keeps lists of certificates that are no longer valid, whether because the owner thinks the private key was compromised, or the token containing the private key was lost or stolen, or the original owner of the key is no longer entitled to use it. Such a list is called a certificate revocation list (CRL), and they are made public at one or more URLs provided by the CA who signed the certificate.

An array of CRL objects can be passed as a parameter to the sign method. However, CRLs are generally large, and this technique is considered to be "old technology."

It might be a better idea to use the Online Certificate Status Protocol (OCSP).

1.2.2 Online Certificate Status Protocol (OCSP)

OCSP is an internet protocol for obtaining the revocation status of a certificate online. You can post a request to check the status of a certificate over HTTP, and the CA’s OCSP server will send you a response. You no longer need to parse and embed long CRLs. An OCSP response is small and constant in size, and can easily be included in the PKCS#7 object.

Revocation information in a PDF document is a signed attribute, which means that the signing software must capture the revocation information before signing. A similar requirement in this use case applies to the chain of certificates. The signing software must capture and validate the certificate’s chain before signing. CRLs will lead to bigger PDF documents, and using OCSP will not take as much space. But the OCSP connection to check the status can take time, whereas CRLs can easily be cached on the filesystem. It’s always a tradeoff.

Now let’s look at another problem that might arise. Suppose somebody sends you a signed contract. He has used a private key that is still valid, and you’re sure that the document you’ve received is genuine. However, at some point the author of the document regrets what he’s written. By resetting the clock on his computer, he could create a new document with a new digital signature that is as valid as the first one. This way, you could end up with two documents signed with the same private key at almost the same time, but with slightly different content. How can anybody know which document is more genuine?

1.2.3 Timestamping

This problem can be solved by involving a third party: a timestamping authority (TSA). The TSA will take the hash of the document and concatenate a timestamp to it. This is done on a timestamp server that is contacted during the signing process. The time-stamp server will return a hash that is signed using the private key of the TSA.

2 Sign

You can sign a PDF document using PDFSignOptions configurator.

Copy
<script>

var ksm = new Ax.ks.KeyStoreManager("https://bitbucket.org/deister/axional-docs-resources/raw/master/KeyStores/swview/jks-files/jack.jks", "secret");
var pdf = new Ax.pdf.Signer(new Ax.net.URL('https://bitbucket.org/deister/axional-docs-resources/raw/master/PDF/scanned.pdf'));

var out = pdf.sign(ksm.getKeyStore(), "jack", "moon", options => {
// Top left corner
options.setRectangle(10, 748, 220, 780);
options.setReason("The reason");
options.setLocation("The location");

// Provide a image

// DESCRIPTION, NAME_AND_DESCRIPTION, GRAPHIC_AND_DESCRIPTION, GRAPHIC
options.setRenderingMode("GRAPHIC_AND_DESCRIPTION");

options.setTSAClientURL("https://freetsa.org/tsr");
});

new Ax.io.File("/tmp/signed.pdf").write(out);

</script>

3 Verify

Verify on a PDF returns a JSON (map) with PKCS#7 properties. The field verify will be true if the signature checks out, false otherwise. Other fields are part of PKCS#7 properties.

Copy
<script>

var pdf  = new Ax.pdf.PDFSigner(new Ax.io.File("/tmp/signed.pdf"));
var info = pdf.verify();
for (var key of info.keySet()) {
console.log(Ax.lang.String.format("%20s: %s", key, info.get(key)));
}

</script>