These are my notes for my GovCamp presentation in Brussels (September 21, 2006; between OSCon and DrupalCon).
I was asked to talk about the Belgian eID; the eID is the new Belgian identity card in the form of a smartcard.
I am not an eID expert, so I decided to change the focus of the presentation to a technology I know rather well: the Portable Document Format (PDF).
In this article you will learn:
The conclusion will be that you really don't need to be an eID expert to achieve all this. If I can do it, so can you ;-)
In chapter 15 of the book on iText you will find examples to create PDF documents with an AcroForm containing button fields, choice fields and text fields, but as I already mentioned on page 1 of this article, a form can also contain signature fields.
In chapter 16 you'll learn how to add a signature field at an absolute position using a private/public key pair. There's also an example that shows how to add an invisible signature. For this demo, we'll create a PDF document with two empty signature fields, and we'll use two different eIDs to sign these fields afterwards. But before we talk about empty signature fields, let's spend some more time on AcroForms.
On the previous page we have created a PDF document with a PDF form that was filled using the data retrieved from an eID (EIDFormAutoFilled1.pdf). We are now going to open this file using PdfReader and we'll retrieve the default value of the fields to create a new document EIDFormUnsigned.pdf (see EIDFormWithSignature.java).
PdfReader reader = new PdfReader("EIDFormAutoFilled1.pdf");
AcroFields form = reader.getAcroFields();
String name = form.getField(EIDForm.NAME);
Note that this won't work if we use EIDFormAutoFilled2.pdf.
The form structure in this 'flattened' PDF is lost. We can no longer retrieve the form field keys and their values.
Just below the table with the personal data of Robert Specimen, we'll add two signature fields:
PdfAcroForm acroform = writer.getAcroForm();
acroform.addSignature("Signature1", 54, 440, 234, 566);
acroform.addSignature("Signature2", 360, 440, 540, 566);
The values [54, 440, 234, 566] and [360, 440, 540, 566] represent the coordinates of a rectangle.
Have a look at figure 3.1 to see where the two signature fields were added.
figure 3.1: a PDF document with two empty signature fields
Before we sign this document, it is important to understand the different types of signatures that are supported in PDF.
I have extracted two pages from the PDF Reference (fifth edition; Portable Document Format version 1.6). I summarized these pages as follows:
a PDF document may contain the following standard types of signatures:
In the examples that follow, we'll use iText to add two recipient signatures to EIDFormUnsigned.pdf, then we'll try to add two 'author' signatures to see what happens.
These examples also use the GoDot library written by Danny De Cock. There is one caveat. When you want to use your eID to add your digital signature to a document, you need to enter a PIN code (that's rather obvious: otherwise rogue software could sign any document as soon as you put your eID into a smartcard reader.). The GoDot software uses hardware specific middleware to achieve this. More specifically: these examples will only work with the Vasco Digipass Desk850.
figure 3.2: Vasco Digipass Desk850
This digipass offers secure PIN entry facilities. If you use another smartcard reader, you will need to find the middleware that works with that specific device.
Suppose our unsigned form is an official document that needs to be read and approved by two different persons, first by me, then by Robert Specimen himself.
First I'll add my own signature using EIDFormRecipient1.java. This code was inspired by an example sent to the iText mailinglist by Philippe Frankinet. This example was in turn inspired by the article How to sign a PDF using iText by Paulo Soares.
(1) BelpicCard scd = new BelpicCard("");
Certificate[] certs = new Certificate[1];
certs[0] = scd.getNonRepudiationCertificate();
(2) PdfReader reader = new PdfReader("EIDFormUnsigned.pdf");
FileOutputStream fout = new FileOutputStream("EIDFormSigned1.pdf");
(3) PdfStamper stamper = PdfStamper.createSignature(reader, fout, '\0');
PdfSignatureAppearance sap = stamper.getSignatureAppearance();
sap.setCrypto(null, certs, null, PdfSignatureAppearance.SELF_SIGNED);
(4) sap.setReason("GovCamp example: eID and PDF (first recipient)");
sap.setLocation("Belgium");
(5) sap.setVisibleSignature("Signature1");
(6) sap.setExternalDigest(new byte[128], new byte[20], "RSA");
sap.preClose();
PdfPKCS7 sig = sap.getSigStandard().getSigner();
byte[] content = streamToByteArray(sap.getRangeStream());
byte[] hash= MessageDigest.getInstance("SHA-1").digest(content);
(7) byte[] signatureBytes = scd.generateNonRepudiationSignature(hash);
sig.setExternalDigest(signatureBytes, null, "RSA");
PdfDictionary dic = new PdfDictionary();
dic.put(PdfName.CONTENTS, new PdfString(sig.getEncodedPKCS1()).setHexWriting(true));
sap.close(dic);
This code snippet is a little bit too technical to explain in a presentation that may not exceed half an hour, but we can distinguish different parts:
When we execute this code, we will be asked to enter our PIN code on the pinpad of the Vasco Digipass 850. If we enter this PIN correctly, the document shown in figure 3.3, EIDFormSigned1.pdf, will be the result.
figure 3.3: a PDF document with a signature; the validity has not been checked
The validity is unknown because the Belgian state used self-signed certificates. Only certificates that are signed by a Certificate Authority (e.g. VeriSign) will be trusted automatically. If we want this specific signature to be validated, we will have to add the certificate of 'Bruno Lowagie' to the list of trusted identities (See chapter 16). Once we have done this, the signature will show a green check mark as is shown in figure 3.4.
figure 3.4: a PDF document with a valid signature.
Now if somebody wants to secretly change the contents of the PDF document, the signature will be invalidated. As an example, we could add the sentence "This changes the revision of the document that was signed by Bruno" with EIDFormSignatureInvalid.java. The result, EIDFormInvalidSignature.pdf, is shown in figure 3.5.
figure 3.5: a PDF document that was changed after being signed
This doesn't mean we can't change the document at all. If we want a document to be signed by multiple recipients, it would be quite annoying if every new signature invalidated all the previous signatures.
We will solve this problem by doing an incremental update of the document. This is a code snippet of EIDFormRecipient2.java:
PdfStamper stamper = PdfStamper.createSignature(reader, fout, '\0', null, true);
Please compare this line with the line marked (3) in the previous code snippet. This line makes sure we don't change the previous revision of the document (and therefore don't invalidate the signature). The rest of the code in EIDFormRecipient2.java is almost identical to EIDFormRecipient1.java
The result is shown in figure 3.6.
figure 3.6: a PDF document with 2 signatures (in different revisions)
You could add Robert Specimen's certificate to the list of trusted identities to validate the signature. If we have a close look to the first signature in EIDFormSigned2.pdf, we see that it is marked with a small yellow triangle containing an exclamation point. That's because the document as we see it now is a second revision. The first signature only covers the first revision.
In chapter 16 of iText in Action, you can learn how to verify signatures programmatically, and how to extract the original revision that was signed by the first recipient.
Adding an author signature is almost as simple as adding a recipient signature. It's sufficient to add one line (please compare EIDFormAuthor1.java with EIDFormRecipient1.java).
sap.setCertified(true);
When we open the EIDFormCertified1.pdf a special dialog box will open saying the document was certified by Bruno Lowagie (assuming that you have added my certificate in your list of trusted identities).
figure 3.7: a dialog box saying the document was certified by Bruno Lowagie
Figure 3.8 shows how the signature field is visualized.
figure 3.8: a document with a modification detection and prevention signature
Now when we try to change this certified document, for instance by adding a second author signature with EIDFormCertified2.java, the dialog box will warn us that the certification is invalid.
figure 3.9: a warning that the document certification is invalid
We have tried to add two author signatures to one document, but this is not valid according to the PDF Reference, so we end up with a PDF document with an invalid signature: EIDFormInvalid.pdf (see figure 3.10).
figure 3.10: a document can contain only one MDP signature
This example concludes my presentation on PDF Forms and the eID.
