2. PDF and digital signatures
3.3 Adding a timestamp
Before we jump into an example, let’s try to understand why it’s important to know when a document was signed. We already know that certificates can be revoked, but certificates also have an expiration date. What happens if a certificate expires?
3.3.1 Dealing with expiration and revocation dates
Suppose that Alice has acquired a private key with a certificate that is valid until 2014. As long as the expiration date hasn’t passed, Alice can sign documents and these documents will be validated by Adobe Reader.
After the expiration date, Alice can no longer use her private key to sign documents (which is to be expected), but there’s more! Adobe Reader will inspect the certificate and see that it has expired. If there’s no embedded CRL, no embedded OCSP response, and no timestamp, Adobe Reader won’t show a green check mark anymore, but it will give a warning saying: I can’t trust this signature anymore because the expiration date is in the past. See figure 3.9.
Figure 3.9: Alice signs a document without CRL and without timestamp
It gets even worse if the certificate is revoked. This doesn’t always mean that Alice’s key was stolen.
It’s also possible that Alice has left the company she used to work for. She had a key she could use to sign company documents until 2014, but if she leaves the company in 2013, the company will most probably want to revoke that key. Figure 3.10 shows the consequences if that ever happens:
Digital Signatures for PDF documents 2012
Figure 3.10: Alice leaves the company in 2013, her key is revoked
Apart from the fact that Alice can no longer sign documents from 2013 on, all signatures she created before that date can no longer be trusted if no CRL, OCSP response or timestamp was added. There’s no way for the consumer of the document to verify if the document is valid. The certificate was revoked, and there’s no certainty about the date the document was signed. After all, Alice could have changed the clock on her computer.
What we need, is a situation as shown in figure 3.11:
Figure 3.11: Alice leaves the company; all documents she signed in the past remain valid
Can we achieve this merely by adding a CRL or an OCSP response? No, because Alice could have cached the information about the certificate revocation before leaving the company. The only way we can assure that a document remains valid, is by also adding a timestamp.
A document that was signed by Alice in 2012 will contain revocation information dating from 2012 saying that her certificate wasn’t revoked at that time; the timestamp will assure that the document was certainly signed in 2012. This signature will survive the revocation and expiration date.
But how do we add a timestamp to a digital signature in a PDF document?
Digital Signatures for PDF documents 2012
3.3.2 Connecting to a timestamp server
To solve this problem, we need to involve another third party: a Time Stamping Authority (TSA). A TSA provides an online service, signing signature bytes and concatenating a timestamp to it. This is done on a timestamp server that is contacted during the signing process. The timestamp server will return a hash and authenticated attributes that are signed using the private key of the TSA.
NOTE: You need to be online to create a signature with a timestamp. Connecting to a timestamp server sending and receiving the hash takes time. If you need to sign thousands of documents in batch, you could ask the TSA to provide a time stamping certificate. This certificate will usually be stored on a Hardware Security Module.
You can subscribe to a time stamping service, in which case you get an URL and account information (a username and password). Or you can use a certificate that contains an URL of the time stamping server. With code sample 3.12, we try to find out if CAcert also offers timestamping services.
Code sample 3.12: Extracting the TSA URL from a certificate
BouncyCastleProvider provider = new BouncyCastleProvider();
Security.addProvider(provider);
KeyStore ks = KeyStore.getInstance("pkcs12", provider.getName());
ks.load(new FileInputStream(path), pass.toCharArray());
String alias = (String)ks.aliases().nextElement();
Certificate[] chain = ks.getCertificateChain(alias);
for (int i = 0; i < chain.length; i++) {
X509Certificate cert = (X509Certificate)chain[i];
System.out.println(String.format("[%s] %s", i, cert.getSubjectDN()));
System.out.println(CertificateUtil.getTSAURL(cert));
}
This code returns null for both certificates, meaning CAcert probably doesn’t offer any TSA services. Checking their web site confirms this.
Fortunately, I received an account for a timestamp server at GlobalSign. For some accounts you need an URL, a username and a password. In that case, you can create a TSAClient instance as is done in code sample 3.13.
Code sample 3.13: Creating a TSAClient
TSAClient tsaClient = new TSAClientBouncyCastle(tsaUrl, tsaUser, tsaPass);
Observe that we’re again using an implementation that uses the Bouncy Castle library, just like we did for the OcspClient. Sometimes you only need an URL containing a token identifying the user.
In this case you can drop the parameters tsaUser and tsaPass. There’s also a constructor that accepts an estimated size and a digest algorithm. We’ll learn more about the estimated size in the final section of this chapter.
How to recognize a document that has a timestamp
Let’s take a look at the result. In figure 3.12, we’ve opened the document, and we’re looking at the Date/Time information in the Signature properties. We’ve also opened the Certificate viewer for the timestamp certificate.
Digital Signatures for PDF documents 2012
Figure 3.12: Looking at the timestamp info
Instead of saying “Signing time is from the clock on the signer’s computer” as was the case with all previous documents we signed, we can now read “The signature includes an embedded timestamp”
along with the exact time the document was signed and the certificate of the TSA, in this case the
“SEIKO Timestamp Service. Advanced A02-004” from GlobalSign.
Retrieving TSA information during the time stamping process
We can follow the signing process, by adding a Logger instance to the LoggerFactory. We can see which CRLs iText is fetching. iText will also send a message to the Logger when a document gets its timestamp, but we may want to store that info somewhere. For instance: we may want to store the exact time returned from the TSA in a database. Let’s take a look at code sample 3.14:
Code sample 3.14: Adding an event to a TSAClientBouncyCastle instance
TSAClientBouncyCastle tsaClient =
new TSAClientBouncyCastle(tsaUrl, tsaUser, tsaPass);
tsaClient.setTSAInfo(
new TSAInfoBouncyCastle() {
public void inspectTimeStampTokenInfo(TimeStampTokenInfo info) { System.out.println(info.getGenTime());
} } );
In this example, we implement the TSAInfoBouncyCastle interface. As soon as iText receives a response from a TSA, it will trigger the inspectTimeStampTokenInfo() method. In this case, we write the generation time (a Date object) to the System.out.
NOTE: Check out the API of Bouncy Castle’s TimeStampTokenInfo class, and you’ll discover that there’s much more information you can retrieve. Instead of just writing this
Digital Signatures for PDF documents 2012
info to a console, you could easily pass it to other objects to create your own logs in the form of a file or records in a database.
We’ve finally created a PDF document that complies with the best practices. There’s only one thing that still bothers us: why do we have to add the root certificate of the CA to the Trusted Identities manually? Why can’t Adobe Reader show a green check mark now that we’ve followed the rules by the book? Aren’t there easier ways to trust root certificates?