JAVA Toolkit
| home | contact




Frequently Asked Questions

I have problems, what shall I do?
 The first thing recommended to do is to call Stiftung SIC, you might even try to call late, as sometimes we are working overtime.

NO! This was a Joke!

faq

We have made the experience, that many questions occuring are answered by

a) reading the documentation or

b) looking into the mailinglist archives or newsgroup archives.

If you still can't solve your problem, you also can buy support - and if you have bought one of our toolkits you already might be owning support-points you can make use of.

 

Q:

When using IAIK-JCE and trying to get an JCE engine an ExceptionInInitializerError is thrown saying "Cannot set up certs for trusted CAs". I am using JDK 1.4.

A:

With JDK1.4 the JCE framework (JAVAX CRYPTO) has been incorporated into the standard JDK. Because of export regulations a JCE provider only maybe used with JDK1.4 (or JCE 1.2.1) if it is signed. IAIK-JCE provides signed and unsigned versions of its jar files (iaik_jce.jar, iaik_jce_full.jar). Using the unsigned version with JDK 1.4 will cause the ExceptionInInitializerError "Cannot set up certs for trusted CAs". Please use the signed jar file. You also may ensure that the right JCE policy files are installed in the lib/security directory. 

Q:

When installing the IAIK provider (signed version) as first provider and trying to get an JCE engine a stack overflow error occurs. I am using JDK 1.4.

A:

Due to a bug in the JDK jar file verification mechanism it may be necessary that the original SUN provider is installed as first provider. So insert the Stiftung SIC provider as second provider and explicitly request an IAIK engine when calling getInstance:

Security.insertProviderAt(new IAIK(), 2);
Cipher c = Cipher.getInstance("DES/CBC/PKCS5Padding", "IAIK");

Alternatively you may use static method addAsJDK14Provider of the IAIK-JCE provider main class. This method uses a work around that allows to use IAIK as first provider for JDK1.4, too:

IAIK.addAsJDK14Provider();

JDK 1.5.0_02 and later already have fixed the jar file verification problem. For this versions the IAIK provider
 can be installed as first provider in the convential way (or registered statically):

Security.insertProviderAt(new IAIK(), 1);

Q:

Using IAIK-JCE (signed version) and trying to perform a TripleDES encryption gives a InvalidKeyException. It works with JDK 1.3, but not with JDK1.4. (This exception may occur wrapped into an InternalErrorException when, for instance, trying to de/encrypt PKCS#8 or PKCS#12 files).

A:

Due to import control restrictions of some countries, JDK1.4 per default comes with jurisdiction policy files allowing "strong" but limited cryptography; so keys that exceed the allowed strength are not allowed to be used by this policy. If you are entitled to do so, you may download and install an "unlimited strength" version of these files ( http://java.sun.com/j2se/1.4/download.html).

Q:

With former versions of IAIK-JCE I have has used method getExtensionValue of class X509Certificate to get the extension value of some specific extension. When, for instance, quering for a BasicConstraints extension I got the DER encoding of the SEQUENCE representing the ASN.1 representation of a BasicContraints extension. Now I get the DER encoding of an OCTET STRING.

A:

To be compatible with the standard JDK certificate API we had to change method getExtensionValue to return the encoding of the OCTET STRING extnValue:

Extension ::= SEQUENCE { extnID OBJECT IDENTIFIER, critical BOOLEAN DEFAULT FALSE, extnValue OCTET STRING }

The value of the extnValue OCTET_STRING represents the DER encoding of the Extension in mind itself; so you may have to add a second decoding step, e.g.:

byte[] extnValueEnc = cert.getExtensionValue(); 
 OCTET_STRING extnValue = DerCoder.decode(extnValueEnc); 
 ASN1Object asn1Extension = DerCoder.decode(extnValue.getValue());

However, generally it might be more appropriate to call method getExtension immediately (except when forced to produce provider independent code):

BasicConstraints bc = (BasicConstraints)cert.getExtension(BasicConstraints.oid);

Q:

When trying to parse a PKCS#7 SignedData object I get an decoding error saying "Next ASN.1 object is no INTEGER!"

A:

In practice PKCS#7 objects like SignedData or EnvelopedData are wrapped into a ContentInfo before transmission to tell the recipient the PKCS#7 content type (s)he has to deal with. When parsing your SignedData object you first have to unwrap the ContentInfo as shown in demo.pkcs.TestContentInfo, e.g.:

// the stream from which to read the PKCS#7 object InputStream is = ...;
// the stream from which to read the content in explicit mode InputStream message = ...;
// create the ContentInfo object
ContentInfoStream cis = new ContentInfoStream(is);
System.out.println("This ContentInfo holds content of type " + cis.getContentType().getName());
SignedDataStream signed_data = null;
if (message == null) {
  // implicitly signed; get the content
  signed_data = (SignedDataStream)cis.getContent();
} else {
  // explicitly signed; set the data stream for digesting the message;
  // we assume here that SHA-1 and MD5 have been used for digesting
  AlgorithmID[] algIDs = { AlgorithmID.sha1, AlgorithmID.md5 };
  signed_data = new SignedDataStream(message, algIDs);
}
// get an InputStream for reading the signed content
InputStream data = signed_data.getInputStream();
OutputStream os = ...;
StreamCopier sc = new StreamCopier(data, os);
sc.copyStream();
if (message != null) {
  // if explicitly signed now decode the SignedData
  signed_data.decode(cis.getContentInputStream());
}
// now you may verify the signature(s)
System.out.println("SignedData contains the following signer information:");
SignerInfo[] signer_infos = signed_data.getSignerInfos();
for (int i=0; i<signer_infos.length; i++) {
  try {
    // verify the signed data using the SignerInfo at index i
    X509Certificate signer_cert = signed_data.verify(i);
    // if the signature is OK the certificate of the signer is returned
    System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN());
  } catch (SignatureException ex) {
    // if the signature is not OK a SignatureException is thrown
    System.out.println("Signature ERROR from signer: "+ signed_data.getCertificate(signer_infos[i].getIssuerAndSerialNumber()).getSubjectDN());
    ex.printStackTrace();
  }
}

Q:

A certificate generated with IAIK-JCE causes Netscape 4.7 to crash. The certificate contains non printable characters in its subjectDN common name. 

A:

RFC2459 recommends to use UTF8String as default encoding. Where the character set is sufficient, PrintableString maybe used. For that reason IAIK-JCE uses PrintableString as default encoding for AVA string attribute values, but switches to UTF8String if the string value does contain non printable characters.
  
 UTF8String, however, may not be handled by older versions of  certificate processing applications like Netscape 4.7. You either may switch do a more recent version of Netscape or use static method setNonPrintableDefaultEncoding of class AVA to change the default secondary encoding to be used for string values containing non printable characters, e.g.:

AVA.setNonPrintableDefaultEncoding(ASN.BMPString);

Q:

I have created a PKCS#7 signature using Microsoft CAPICOM. If the content is included in the SignedData object (implicit mode) I have no problems to verify the signature with the PKCS#7 library of IAIK-JCE. However, if the content is not included (explicit mode) I get a SignatureException saying that the message hash is incorrect: "Signature verification error: message hash!".

A:

In explicit mode (where the content data is not included in the signature) we have observed that it might be necessary to apply "UnicodeLittleUnmarked" encoding to the data before verifying the Capicom signature, or to avoid using this encoding format right at the sender side as suggested in a former posting to this Newsgroup:

From the signing side (Capicom), the following code was used to read the file
 and avoid Unicode formatting:
       
 -------------------
 Dim objUtilities As New CAPICOM.Utilities
 Open strPathDocToBeSigned For Binary Access Read As #1
       
 ' Removing EOF
 ReDim abytFile(LOF(1) - 1)
 Get #1, , abytFile
 Close #1
       
 strFileContents = objUtilities.ByteArrayToBinaryString(abytFile)
 -------------------
       
 and after this the normal signing process of strFileContents.

However, with the following sample code you should be able to verify both, explicit and implicit signatures (use the stream based classes if you have to deal with big amounts of data):

  import java.io.IOException;
  import java.io.InputStream;
  import java.io.FileInputStream;
  import java.security.NoSuchAlgorithmException;
  import java.security.SignatureException;
                      
  import iaik.asn1.CodingException;
  import iaik.asn1.ObjectID;
  import iaik.asn1.structures.AlgorithmID;
  import iaik.asn1.structures.Attribute;
  import iaik.asn1.structures.ChoiceOfTime;
  import iaik.pkcs.PKCSException;
  import iaik.pkcs.pkcs7.ContentInfo;
  import iaik.pkcs.pkcs7.SignedData;
  import iaik.pkcs.pkcs7.SignerInfo;
  import iaik.security.provider.IAIK;
  import iaik.utils.ASN1InputStream;
  import iaik.x509.X509Certificate;
                      
  public class SignedDataParse {
  public static void main(String[] args) {
                      
      InputStream is = null;
      try {
      byte[] data = null;
      IAIK.addAsJDK14Provider();
         // read in the PKCS#7 SignedData encoding
      is = new FileInputStream("...");
  /*
      uncomment the follwing line to supply the data in explicit mode;
  */
      // data = "...".getBytes("UnicodeLittleUnmarked");
      ASN1InputStream asn1In = new ASN1InputStream(is);
      byte[] content = getSignedData(asn1In, data);
  /*
      uncomment the follwing if the data represents an (UnicodeLittleUnmarked) encoded string
  */        
  //String s1 = new String(content, "UnicodeLittleUnmarked");
  //System.out.println(s1);
  
  System.out.println("Ready");
  } catch (Exception ex) {
      ex.printStackTrace();
  } finally {
  if (is != null) {
    try {
      is.close();
      } catch (IOException ex) {
      }
    }
  }
 }
                      
  /**
  * Parses a PKCS#7 SignedData object and verifies the signature.
  *
  * @param is the input stream supplying the BER encoded PKCS#7 SignedData object.
  * @param message the content data supplied by other means (only required in explicit mode)
  *
  * @return the content data
  *
  * @exception PKCSException if an error occurs when parsing the SignedData
  * @exception IOException if an error occurs when reading from the stream
  */
  static byte[] getSignedData(InputStream is, byte[] message) throws PKCSException, IOException {
                      
  // create a content info from the encoding
      ContentInfo ci = new ContentInfo(is);
      System.out.println("This ContentInfo holds content of type " + ci.getContentType().getName());
                      
      SignedData signed_data = null;
      if (message == null) {
        //in implicit mode we simply can get the content:
        signed_data = (SignedData)ci.getContent();
      } else {
        // explicitly signed; set the data for digesting the message; we assume SHA-1 and MD5
        AlgorithmID[] algIDs = { AlgorithmID.sha1, AlgorithmID.md5 };
        try {
          signed_data = new SignedData(message, algIDs);
          // now explicit decode the DER encoded signedData obtained from the contentInfo:
          signed_data.decode(ci.getContentInputStream());
        } catch (NoSuchAlgorithmException ex) {
          throw new PKCSException(ex.getMessage());
        }
     }
                      
      System.out.println("SignedData contains the following signer information:");
      SignerInfo[] signer_infos = signed_data.getSignerInfos();
                      
      for (int i=0; i<<<font  id="ezfont"><<font  id="ezfont">font  id="ezfont">font id='ezfont'</font>>signer_infos.length; i++) {
       try {
         // verify the signed data using the SignerInfo at index i
         X509Certificate signer_cert = signed_data.verify(i);
         // if the signature is OK the certificate of the signer is returned
         System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN());
         Attribute signingTime = signer_infos[i].getAuthenticatedAttribute(ObjectID.signingTime);
         if (signingTime != null) {
          ChoiceOfTime cot = new ChoiceOfTime(signingTime.getValue()[0]);
          System.out.println("This message has been signed at " + cot.getDate());
         }
         Attribute contentType = signer_infos[i].getAuthenticatedAttribute(ObjectID.contentType);
         if (contentType != null) {
          System.out.println("The content has PKCS#7 content type " + contentType.getValue()[0]);
         }
       } catch (SignatureException ex) {
        // if the signature is not OK a SignatureException is thrown
        System.out.println("Signature ERROR from signer: "+ 
        signed_data.getCertificate(signer_infos[i].getIssuerAndSerialNumber()).getSubjectDN()); ex.printStackTrace();
       } catch (CodingException ex) {
        System.out.println("Attribute decoding error: " + ex.getMessage());
       }
     }
     return signed_data.getContent();
   }
 }

Q:

When creating a PKCS#7 EnvelopedData, is it possible to use OAEP padding when RSA encrypting the secret content encryption key with the recipient´s public key?

A:

There are several ways for using OAEP padding (for instance you may encrypt the content encryption key outside with OAEP and then use the
 constructor to supply the already encrypted key), but the most simple way might be to override the RSACipherProvider to use RSA with OEAP padding and set it for the RecipientInfos for which you want to use OAEP (note that you will have to specify a proper AlgorithmID for RSAEncryptionOAEP), e.g.:
  

public class RSACipherProviderOAEP extends RSACipherProvider { ... 
/**
  * En/deciphers the given data using RSA with OAEP padding.
  * 
  * @param mode the cipher mode, either ENCRYPT (1) or DECRYPT (2)
  * @param key the key to be used
  * @param data the data to be en/deciphered:
  * <ul>
  * <li>for RecipientInfo cek encryption: the raw content encryption key
  * <li>for RecipientInfo cek decryption: the encrypted content encryption key
  * </ul>
  * 
  * @return the en/deciphered data:
  * <ul>
  * <li>for RecipientInfo cek encryption: the encrypted content encryption key
  * <li>for RecipientInfo cek decryption: the raw (decrypted) content encryption key
  * </ul>
  *
  * @exception NoSuchProviderException if any of the crypto providers of this RSACipherProvider is not suitable
  * for requested operation
  * @exception NoSuchAlgorithmException if RSA ciphering is not supported
  * @exception InvalidKeyException if the supplied key is invalid
  * @exception GeneralSecurityException if a general security problem occurs
  */
  protected byte[] cipher(int mode, Key key, byte[] data) 
      throws NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, GeneralSecurityException {
    Cipher rsa = Cipher.getInstance("RSA/ECB/OAEP");
    rsa.init(mode, key);
    return rsa.doFinal(data);
  } 
}

 
 On the sender side set your RSA cipher provider for each RecipientInfo you which to use it:

 // specify an AlgorithmID for RSA with OAEP padding
 AlgorithmID rsaEncryptionOAEP = new AlgorithmID("1.2.840.113549.1.1.6", "RSAEncryptionOAEP");
 // the recipient certificate
 X509Certificate recipientCert = ...;
 // create the RecipientInfo
 RecipientInfo recipient = new RecipientInfo(recipientCert, rsaEncryptionOAEP);
 // set the RSA cipher provider for using RSA with OAEP padding
 recipients[0].setRSACipherProvider(new RSACipherProviderOAEP());

 
 On the receiving side set yout RSA cipher provider before decrypting the encrypted content encryption key:
  

// the RSA OAEP provider to be used
 RSACipherProviderOAEP rsaCipherProviderOAEP = new RSACipherProviderOAEP();
 ...
 // get the RecipientInfos  
 RecipientInfo[] recipients = enveloped_data.getRecipientInfos();
 for (int i=0; i<recipients.length; i++) {
   System.out.println("Recipient: "+(i+1));
   System.out.print(recipients[i].getIssuerAndSerialNumber());
   // set the RSA cipher provider for using RSA with OAEP padding
   recipients[i].setRSACipherProvider(rsaCipherProviderOAEP);
 }
 // decrypt the message
       
 envelopedData.setupCipher(recipientPrivateKey, recipientInfoIndex);

 
print    tip a friend
back to previous page back  |  top to the top of the page