Adobe CDS, or, how to ensure your Signature no longer has problems in Acrobat
The Problem
It's very easy to digitally sign a PDF. In Acrobat, you select "Save As Certified" from the File menu. In our PDF Viewer you select "Invisibly Sign Document" from the "Tools" menu. Using our API, you can do it in about 10 lines of code. However all these approaches have one thing in common.
The phrase "this signature has problems" refers to the fact the signature is not created by a trusted identity: one certified by a trusted chain of certificates going back to the Adobe root certificate.
It's very easy to get around: simply bring up the signature properties, select the "Signer" tab, bring up the certificate and select "Trust this Identity". But if you want to create a document that's trusted by default, this is a little more complicated. This article describes how to achieve this with our PDF Library. Here's an example PDF.
Adobe CDS
In order for a document to be trusted in a new install of Acrobat, the signer must be certified by a Certificate Document Service Provider. These are simply Certification Authorities who work with Adobe, and include the big players you'd expect - VeriSign and Entrust, amongst others. In order for them to certify a key it has to meet certain conditions, the main one being that it's stored on a "Hardware Security Module", or HSM, that meets FIPS 140-2 (Level 2 or higher).
In this article we're going to cover the steps required to
- Set up your HSM to work with Java
- Get your CDS certified digital identity
- Use that identity to sign a PDF with our PDF Library
The following should work with Sun Java 6.0 on Windows 32-bit or UNIX - we tested
with Ubuntu
Linux 10.04. However, for reasons known best to the developers at Sun, Windows 64-bit JVMs
are not supported (the sun.security.pkcs11.SunPKCS11
class is missing from the
Java Runtime). We haven't tested with IBM Java.
1. Setup
1.1 Obtaining your HSM
Your first step to getting a CDS certified key is obtaining an HSM. There are a number to choose from, ranging from network-attached HSMs in the four-figure price range, all the way down to the humble Safenet eToken Pro, a USB Token we managed to pick up for about USD$100. It doesn't matter what you go for, but if you want it to work with Java it must have a PKCS#11 interface - most do - and drivers for your OS, as the Java PKCS#11 classes need to reference a native library.
Some CDS Providers will supply an HSM when you purchase a Key, so it's worth checking before you buy one.
1.2. Obtaining your Key
A CDS certified identity is technically no different to a regular certified identity, and the procedures for purchasing one should be roughly the same. Naturally each company will have their own requirements and those will be subject to change, so while we believe the following to be correct at the time of writing it is subject to change.
- TrustCenter (part of Symantec) were the company we used for the proof of concept behind this article. You can purchase their TC Business ID for Adobe certificates online, and there's a complete guide to installing and initializing the token and generating the key here - we'd suggest you follow their guide exactly, rather than the steps here. You will need to obtain your own eToken before starting.
- Symantec also bought Verisign's Authentication Services, and their Adobe CDS page is their entry-point. At the time of writing, we understand that they have two broad types of product: a low-volume key which is supplied on an Aladdin eToken, or for higher volumes you supply your own HSM and they will sign your key as normal. No special drivers are required, and we've been told both products can be used with Java.
- Entrust have a similar model for their CDS Certificates, but we were told their "Individual" and "Group" certificates, which are supplied on an eToken, are not usable with Java due to custom drivers being required. Their higher volume certificates are installed on your own HSM, and so should work correctly.
1.3a. Installing a Safenet eToken in Windows
The HSM we used was a Safenet eToken. On Windows XP we installed the Safenet Authentication Client v8.0 SP2, which recognised our token instantly. If your token wasn't supplied by your CA with a key on it, you'll need to initialize it. Open the GUI client and initialize the token with a new administrator password and "token password" (in all the examples on this page, we assume the "token password" was set to "secret"). Click the "Advanced" button and select "FIPS" (see enlargeable screenshort to the right), then initialize.
In order to access the eToken from the Java keytool.exe
program, you'll need a configuration
file containing the two lines
name = eToken library = C:\Windows\system32\eTPKCS11.dll
Save this file somewhere on your system - we've called ours keytool-etoken.cfg
. The format of
this file is described here,
but those two lines are all that's needed for an eToken.
1.3b. Installing a Safenet eToken in Linux
As you might expect, the procedure in Linux is more complicated.
First, install the pcscd and
opensc packages (called pcscd
and
opensc
on Ubuntu). You'll also need the the
SafeNet
Authentication Client supplied with your eToken - the package we installed was
SafenetAuthenticationClient-8.0.5-0_i386.deb
, although a newer version may be available.
If you're using a brand new token, now is the time to initialize it. In general we'd
recommend following
the steps recommended by the HSM supplier, but some issues with Safenet's client prevented
this for us. We
did manage to initialize the token using the pkcs11-tool
from the pcscd
package.
Here's how:
# Initialize the token, set the "administrator password" pkcs11-tool --module /usr/lib/libeTPkcs11.so --init-token --label MyToken --so-pin adminsecret # Set the "token password" pkcs11-tool --module /usr/lib/libeTPkcs11.so --init-pin --pin secret
Finally, in order to access the token from Java you'll need to edit the file /etc/eToken.conf
and
add the line TolerantX509Attributes=1
under the [GENERAL]
section. As under Windows,
you'll also need to create a configuration file for the Java keytool
program - we used the
following and saved it as keytool-etoken.cfg
:
name = eToken library = /usr/lib/libeTPkcs11.so
2. Using the HSM from Java
Now your HSM is set up with a key, you need to get it working with Java and then with our API. Here's how:
2.1 Accessing the HSM from Java's keytool
You can now use the Java keytool
program to access the token as a regular Java
java.security.KeyStore
. So for example, to list which keys are on the token:
keytool -list -keystore NONE -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg keytool-etoken.cfg -storepass secretor to generate a new key:
keytool -genkeypair -alias testkey -validity 365 -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -keystore NONE -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg keytool-etoken.cfg -storepass secret
Note the arguments above: the providerArg
is the full path to the configuration file
keytool-etoken.cfg
you created in step 1.3 above, and the
storepass
is the token password you set when you
were initializing the token. If you're generating your own keys, it's also important
to specify
RSA
as the key algorithm.
2.2 Confirming the certificate chain
In order for a signed PDF to be trusted in Acrobat, the certificate chain must be embedded in the PDF and the chain must be signed by the "Adobe Root CA". These certificates are supplied with Acrobat but are not included with our PDF Library, so it may be necessary to import them into the KeyStore before signing (as it was for us with our TrustCenter-supplied certificate).
You can check the certificate chain in the KeyStore with the keytool -list
code above: the key
you're using to Sign PDFs should have a "Certificate Chain Length" of at least 3,
and the final Certificate
should belong to the "Adobe Root CA". Check this annotated output from the
keytool command to see what the results should look like.
If you don't have all the required certificates, you need to import them. This is
a Java-focused blog so we've
tried to do this with keytool
, but frankly we couldn't get it working with our eToken. We'd suggest
you import the certificates you require using the interface supplied by your HSM manufacturer
- for us, it was
a matter of downloading the TrustCenter
CA Certificate and the Adobe
Root CA Certificate and importing them onto the eToken, as shown on the screenshot to the right (click
to enlarge).
2.3 Accessing the HSM from Java
Signing a PDF with our API means supplying ajava.security.KeyStore
to the FormSignature
class, and this is very simple to do. The following code will open the eToken from
Java:
// "config" contains the same data as "keytool-etoken.cfg" byte[] config = "name=eToken\n library=/usr/lib/libeTPkcs11.so\n".getBytes("ISO-8859-1"); char[] password = "secret".toCharArray(); // "token password" String alias = "mykey"; // The key alias in the KeyStore Provider provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(config)); KeyStore ks = KeyStore.getInstance("PKCS11", provider); ks(null, password);
Rather than referencing the keytool-etoken.cfg
file we created earlier, we're passing in the
contents of the configuration file as an InputStream
instead - much neater, as no external
configuration file is required. Once you have this KeyStore
you can use it as you would any other,
with the proviso that modifications are made immediately: calling keystore.save()
is not required.
2.4 Accessing the HSM from the PDF Viewer
Configuring our PDF Viewer to use the HSM as aKeyStore
can be done with a single property:
org.faceless.pdf2.viewer2.KeyStoreManager.params
. This can be specified on the command line
like so for Linux:
java -Dorg.faceless.pdf2.viewer2.KeyStoreManager.params= "type=pkcs11;name=eToken;library=/usr/lib/libeTPkcs11.so; password=secret" org.faceless.pdf2.viewer2.PDFViewer
or, if you're on Windows
java -Dorg.faceless.pdf2.viewer2.KeyStoreManager.params= "type=pkcs11;name=eToken; library=C:\Windows\System32\eTPKCS11.dll;password=secret" org.faceless.pdf2.viewer2.PDFViewer
These parameters are a combination of those defined in the
Java
PKCS#11 Reference and those defined in the
API Docs for
KeyStoreManager
- no external configuration file is required.
Note: Although the examples above refer to a Safenet eToken HSM, you can access any PKCS#11 compliant HSM from Java using the same approach: only the "name" and "library" in the configuration are likely to change