Java Mailing List Archive

http://www.junlu.com/

Home » Home (12/2007) » iText »

Re: [iText-questions] Where to get Certificates for PDF Signing:
 PKCS11 works

Martin Brunecky

2007-07-16



Well,
My other inquiries confirm that Adobe has made sure that their certificates
(I mean the ones rooted in Adobe CA) are truly "trusted" - level 2
certificates. Hence, in products with a broad population of signed/certified
document recipients, the VeriSign (formerly Geotrust) Adobe Certified
Document Services is probably the best source.

From: Harakiri <harakiri_23@(protected)
>I dont believe another source exists - EVEN if it does
>exist Adobe has made it a rule that anyone issuing a
>certificate from their Adobe CA *must* be on a secure
>storage - so it will always be at least USB or Smart
>Card - no way to get in simply pkcs7 file format.
>
>I have the same problem and wondering if the USB token
>would be accessable through java or if it is only
>compatible with the adobe writer software
>

The good news is that iText and Sun PKCS#11 DOES DO work together, at least
for the Rainbow Technologies (now SafeNet) iKey 2032, used by GeoTrust (now
VeriSign) Adobe Certified Document Services (CDS).

The problem I see on this mailing list and WEB in general (and thru my own
pain and suffering) is that accessing USB tokens and/or smart cards via Sun
PKCS#11 implementation is very error prone: one minor mistake and you are in
the deep woods, and errors you are getting are just dragging you deeper (and
web searches make you believe that it can't work).

There are, however, several issues to be aware off (as of this writing: July
15 2007):

1) You _must_ supply iText interfaces not only with the private key and
certificate chain, but ALSO the "right" provider name (internally used to
create Signature object). Under Sun PKCS11, the provider name is
_dynamically_ generated, you MUST retrieve the provider name from the loaded
PKCS11 provider (see below); it is NOT "pkcs11".

2) For the iKey2032 you must use the "right" PKCS11 interface
implementation. I found that the obvious library
(c:\windows\system32\dkck232.dll) does not work, use the
c:\windows\system32\dkck201.dll. There may be even better-newer driver(s)
and DLL(s), but dkck201.dll works with JDK 1.5.0_03-b07 and later. See my
PKCS11 configuration file below.

3) The USB token (iKey 2032) provided by the Adobe CDS _only_ contains your,
leaf certificate. However, it is issued by "GeotTrust CA for Adobe", which
is then signed by "Adobe Root CA". If you sign using Acrobat, it will add
"GeoTrust CA for Adobe" to the certificate chain (from iKey) for you. If you
use iText as I do, I found that I have to add that certificate myself to the
"chain of 1" returned from the iKey (you can export it from Acrobat or get
it directly from GeoTrust). BEWARE that on the machine where you did the CDS
installation, Adobe products will find the GeoTrust certificate - but send
your PDF to some other machine, and "GeoTrust CA for Adobe" will be missing
- resulting in a signature that can not be validated. Note you do not add
"Adobe Root CA" - that one is installed in Adobe products.
However, if you use iText to validate your signatures, you will need to make
sure that trusted keystore you use for verification contains the "Adobe Root
CA" (it is not present in the default, JRE provided trusted cacerts).

PKCS#11 Configuration file that works for me:

name = rainbow_token
library = c:\windows\system32\dkck201.dll
attributes = compatibility


To have a uniform way for passing around crypto parameters, I am using
several (PKCS7, JCE, PKCS11) implementations of the following interface:

package sign;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.cert.Certificate;

public interface SignerKeystore {
  public PrivateKey getPrivateKey() ;
  public Certificate[] getChain() ;
  public Provider getProvider();
}

The PKCS#11 implementation is a bit 'bulky', because it has to fetch the
'additional' certificate(s) used to complete the certification chain for
'my' certificate stored on the GeoTrust/VeriSign issued iKey 2032 (note
constructors use Streams so that I can embed data as Java class resources).

package sign;
import java.io.InputStream;
import java.security.*;
import java.security.cert.Certificate;
import java.util.Enumeration;
// import org.apache.commons.logging.Log;
// import org.apache.commons.logging.LogFactory;

public class SignerKeystorePKCS11 implements SignerKeystore {
  // private final static Log log =
LogFactory.getLog(SignerKeystorePKCS11.class);
  private static Provider prov = null;

  private KeyStore   ks;
  private String     alias;
  private String     pwd;

  private PrivateKey   key;
  private Certificate[] chain;

  /**
  * @param config - Sun PKCS#11 configuration file
  * @param passw - PKCS#11 hardware token password
  * @param addKs - Java JKS keystore containing additional signing
certificate(s)  
  *           to add to the certificate chain returned from the
token.
  */
  public SignerKeystorePKCS11(InputStream config, String passw,
InputStream addKs) throws Exception {
    try {
      long start = System.currentTimeMillis();
      // This should be done once only for the provider, otherwise
      // we get a lot of confusion...
      if (prov == null) {
         this.prov = new sun.security.pkcs11.SunPKCS11(config);
         Security.addProvider(prov);
      }

      this.pwd = passw;
      this.ks = KeyStore.getInstance("pkcs11");
      this.ks.load(null, passw.toCharArray());

      Enumeration<String> aliases = ks.aliases();
      while (aliases.hasMoreElements()) {
          String curr = (String) aliases.nextElement();
          this.alias = curr;
          this.key = (PrivateKey) ks.getKey(alias, pwd.toCharArray());
          this.chain = ks.getCertificateChain(alias);
          // log.info("Alias " + curr + " certificate chain length: "
+ this.chain.length);
          break;
      }

      // Now, since the PKCS11 chain may be incomplete, add additional
      // certificates from the given keystore
      if (addKs != null) {
         this.chain = addCerts(this.chain, addKs);
      }
      long stop = System.currentTimeMillis();
      // log.info("Keystore " + getProvider().getName() + " loaded in "
+ (stop-start) + "ms");
    }
    catch(Throwable t) {
      // log.error("Keystore load failed", t);
      throw new Exception("Keystore load failed: " + t);
    }
 }

  public PrivateKey getPrivateKey() {
    return key;
  }

  public Certificate[] getChain() {
    return chain;
  }

  public Provider getProvider() {
    return prov;
  }


  // Add (append) certificate(s) from the keystore given by input stream
  protected Certificate[] addCerts(Certificate[] chain, InputStream fin)
throws Exception {
    KeyStore ks = KeyStore.getInstance("JKS");
    ks.load(fin, null);
    return addCerts(chain, ks);
  }

  // Recursively add signing certificate from keystore
  private Certificate[] addCerts(Certificate[] chain, KeyStore ks) throws
Exception {
    Certificate last = chain[chain.length - 1];
    for (Enumeration aliases = ks.aliases(); aliases.hasMoreElements();
) {
       String alias = (String) aliases.nextElement();
       if (ks.isCertificateEntry(alias)) {
          Certificate cert = ks.getCertificate(alias);
          try {
            last.verify(cert.getPublicKey());
            log.info("Adding certificate " + alias);
            int len = chain.length;
            Certificate[] res = new Certificate[len + 1];
            System.arraycopy(chain, 0, res, 0, len);
            res[len] = cert;
            return addCerts(res, ks);
          } catch (Exception e) {
            // No-op - we simply do not match this alias
          }
       }
    }
    return chain;
  }
}


The PKCS12 implemnation, which works well with all Windows ".pks" (and other
extensions) certificates such as certificates used as Digital Mail ID (note
those require "enable Windows integration in Reader" to validate) is simple:

package sign;

import java.io.InputStream;
import java.security.*;
import java.security.cert.Certificate;


public class SignerKeystorePKCS12 implements SignerKeystore {
  private KeyStore ks;
  private String alias;
  private String pwd;

  private PrivateKey key;
  private Certificate[] chain;

  public SignerKeystorePKCS12(InputStream inp, String passw) throws
Exception {
    this.ks = KeyStore.getInstance("pkcs12");
    this.pwd = passw;
    this.ks.load(inp, pwd.toCharArray());
    this.alias = (String)ks.aliases().nextElement();
    this.key  = (PrivateKey)ks.getKey(alias, pwd.toCharArray());
    this.chain = ks.getCertificateChain(alias);
  }

  public PrivateKey getPrivateKey() {
    return key;
  }

  public Certificate[] getChain() {
    return chain;
  }

  public Provider getProvider() {
    return ks.getProvider();
  }
}



>--- Martin Brunecky <mbrunecky@(protected)
>> A naïve question: Where to go for certificates for
>> digital signing of PDF
>> Documents?
>>
>>
>>
>> In theory, one can sign PDF with a variety of
>> certificates, from self-signed
>> and simple mail ID from VeriSign to level 2 and 3
>> certificates(well, SSL
>> certificates do not work).
>>
>>
>>
>> However, there is a problem: Adobe Reader (and
>> probably Acrobat) come out
>> of the box with only one _trusted_, root
>> certificate that of Adobe Inc.
>>
>> And thus, certificates issued by any ‘other’ CA
>> (veriSign, ) all scare the
>> reader:
>>
>> Authenticity of this certificate can not be
>> verified.
>>
>>
>>
>> A simple fix is enabling the Reader Windows
>> Integration and voila all
>> the standard, Windows trusted CAs become available
>> and my signatures now
>> verify nicely. UNFORTUNATELY, enabling Windows
>> Integration is somewhat
>> hidden in Reader interfaces, and I can list all
>> those steps in my signature,
>> and a normal web user gets scared when looking at my
>> documents
>>
>>
>>
>> Hence, it comes to where can I get certificates
>> rooted in Adobe CA?
>>
>> And it seems that the only source for such
>> certificates is the VeriSign
>> (formerly GeoTrust) Adobe Certified Document
>> Services program which
>> (besides the pricing) has a drawback of utilizing
>> USB iKey 2032 (which I am
>> having a real difficulty interfacing).
>>
>>
>>
>> Does anyone know about some other source of Adobe CA
>> rooted certificates?
>>


-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
iText-questions mailing list
iText-questions@(protected)
https://lists.sourceforge.net/lists/listinfo/itext-questions
Buy the iText book: http://itext.ugent.be/itext-in-action/
©2008 junlu.com - Jax Systems, LLC, U.S.A.