This discussion is archived
3 Replies Latest reply: Mar 7, 2012 11:58 AM by 921780 RSS

SunPKCS11 provider and Rainbow iKey 2032 USB token - can't load keys

843811 Newbie
Currently Being Moderated
Hi All,

I've encountered a problem getting aliases from key store after I log in to my iKey USB token.
I use a machine running Windows XP.

I use JDK 1.6.0 update 2.

The provider initializes fine, the debug message even tells me that I successfully log in, but when i try to get aliases from the keystore, i get an empty string enumeration.

This is a part of my code responsible for initialization (it seems to work without problems):
public void initialize( String libraryPath, String pin, String newProviderName ) throws Exception {
     // create configuration data
     String p11ConfigSettings = "name = ";
     p11ConfigSettings += newProviderName;
     p11ConfigSettings += "\nlibrary = ";
     p11ConfigSettings += libraryPath;
     p11ConfigSettings += "\n";
     byte[] p11ConfigSettingsBytes = p11ConfigSettings.getBytes();
     ByteArrayInputStream p11ConfigStream = new ByteArrayInputStream( p11ConfigSettingsBytes );
     
     try {
          // dynamically instantiate the provider
          Class<?> p11Class = Class.forName( "sun.security.pkcs11.SunPKCS11" );
          Constructor<?> p11Constructor = p11Class.getConstructor( java.io.InputStream.class );
          p11Provider = (Provider) p11Constructor.newInstance( p11ConfigStream );
          Security.addProvider( p11Provider );
     }
     catch ( Exception e ) {
          System.out.println( "Could not instantiate the provider!" );
          throw e;
     }
     
     try {
          // get key store instance
          p11KeyStore = KeyStore.getInstance( "pkcs11", p11Provider );
     }
     catch ( Exception e ) {
          System.out.println( "Could not get key store instance!" );
          throw e;
     }

     try {
          // load the key store (logging in to the card)
          char[] pinChars = pin.toCharArray();
          p11KeyStore.load( null, pinChars );
     }
     catch ( Exception e ) {
          System.out.println( "Could not load key store!" );
          throw e;
     }
}
Some details to the shown part:
- libraryPath is "C:/windows/system32/dkck201.dll"
- I've also tried dkck232.dll, but no difference


And this is another part of my code, responsible for loading any key found on the token:
public PrivateKey getSignatureToken() throws Exception {
     // try to search for keys on the token
     Enumeration<String> aliasEnumeration = p11KeyStore.aliases();
     while ( aliasEnumeration.hasMoreElements() ) {
          // something found, take it
          String alias = aliasEnumeration.nextElement();
          return (PrivateKey)p11KeyStore.getKey( alias, null );
     }
     
     // no keys were found on the token
     throw new Exception( "The key store is empty!" );
}
My problem is that p11KeyStore.aliases() always returns an empty enumeration, while an other application (neither using SunPKCS11, nor written in Java) can see the certificate and also use the private key for signing etc.

BTW... previously I wasn't even able to log in, because during "p11KeyStore.load( null, pinChars );" an exception occurred ("PKCS11 not found").
I avoided this adding a debug argument ("-Djava.security.debug=sunpkcs11,pkcs11") to Java VM arguments.

Unfortunately I wasn't able to overcome this problem using JDK's keytool utility at all, so I can't provide its output (except for the "PKCS11 not found" exception).

Isn't there a provider configuration attribute or a KeyStore load parameter that could solve this?
Is there any alternative to SunPKCS11 provider working with an arbitrary PKCS#11 library?

Your help is greatly appreciated!
Thanks.

Message was edited by:
mk0x55
  • 1. Re: SunPKCS11 provider and Rainbow iKey 2032 USB token - can't load keys
    843811 Newbie
    Currently Being Moderated
    Hi,
    after gathering and use the info from this forum, I'm able to access token, encrypt, decrypt using my USB PKI device (Rainbow iKey 2032).
    Just to share...

    //the imports:------------------------------------------------------------------------------
    import java.io.*;
    import java.util.*;
    import java.sql.*;
    import java.text.*;
    import java.math.*;
    import java.security.*;
    import java.security.cert.*;
    import java.security.interfaces.*;
    import javax.crypto.interfaces.*;
    import javax.net.ssl.*;
    import javax.crypto.*;
    import java.security.KeyStore.*;

    //the pkcs11.cfg content:-------------------------------------------------------------------
    name = rainbow_token          //coz I'm using Rainbow iKey 2023 USB device
    library = c:/windows/system32/dkck201.dll //coz this is the device driver
    slotListIndex = 0               //coz this slot contain certificate (0..to..4)
    //use CIP tool to view token in device
    //the program:------------------------------------------------------------------------------
    private String configName = "C:/pkcs11.cfg"; //make sure this pkcs11.cfg file exist!
         
    //sets the security configuration dynamically
    //if this setting is wrong then you'll get 'pkcs11 not found..'
    Provider p = new sun.security.pkcs11.SunPKCS11(configName);
    Security.addProvider(p);

    KeyStore ks = null;
    try
    {
    char pin[] = "PASSWORD".toCharArray(); //set the proper password!

    ks = KeyStore.getInstance("PKCS11"); //this reads the USB device
    ks.load(null,pin); //this verify the password in USB device

    //this gets the keys (pub/prv)
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA",p);
    KeyPair kp = kpg.genKeyPair();
    kpg.initialize(1024, new java.security.SecureRandom());

    //set files to be encrypted
    FileInputStream in = new FileInputStream("E:/originalFile.txt");
    FileOutputStream out = new FileOutputStream("E:/encryptedFile.txt");

    //this sets the cipher type and mode
    Cipher cp = Cipher.getInstance("RSA/ECB/PKCS1Padding", p);
    cp.init(cp.ENCRYPT_MODE,kp.getPublic());

    //write cipher result to a file
    CipherOutputStream cout = new CipherOutputStream(out,cp);
    byte[] input = new byte[8];
    int byteread=in.read(input);
    while(byteread!=-1)
    {
    cout.write(input,0,byteread);
    byteread=in.read(input);
    }
    cout.flush();
    in.close();
    cout.close();

    //set files to be decrypted
    FileInputStream in1 = new FileInputStream("E:/encryptedFile.txt");
    FileOutputStream out1 = new FileOutputStream("E:/decryptedFile.txt");

    //this sets the cipher type and mode
    Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", p);
    AlgorithmParameters algParams = cipher.getParameters();
    cipher.init(Cipher.DECRYPT_MODE,kp.getPrivate(),algParams);

    //write cipher result to a file
    CipherInputStream cin1 = new CipherInputStream(in1,cipher);
    byte[] input1=new byte[8];
    int byteread1=cin1.read(input1);
    while(byteread1!=-1)
    {
    out1.write(input1,0,byteread1);
    byteread1=cin1.read(input1);
    }
    out1.flush();
    in1.close();
    out1.close();
    cin1.close();
    }
    catch(KeyStoreException e1){
    System.out.println("error 1: "+e1);
    }
    catch(NoSuchAlgorithmException e2){
    System.out.println("Error 2: "+e2);
    }
    catch(CertificateException e3){
    System.out.println("error 3: "+e3);
    }
    catch(IOException e4){
    System.out.println("error 4: "+e4);
    }
    -------------------------------------------------------------------------------------------
    I'm using Java 1.6 ...

    This is a goooood reference site:
    http://java.sun.com/j2se/1.5.0/docs/guide/security/p11guide.html

    regards
  • 2. Re: SunPKCS11 provider and Rainbow iKey 2032 USB token - can't load keys
    843811 Newbie
    Currently Being Moderated
    I realize this is a late reply, however I can't seem to get my program to work. It's all the same idea, but the program does not detect the token in the right slot. When it creates the provider object it's looking at slot 10, the default, instead of slot 11 where the token resides.

    So I get a PKCS11 not found error. However, if I change the value of the slot in the debugger, the program proceeds normally.

    Suggestions?
  • 3. Re: SunPKCS11 provider and Rainbow iKey 2032 USB token - can't load keys
    921780 Newbie
    Currently Being Moderated
    Hi,

    I could solve the problem with slot configuration like these.

    Fortunately SunPKCS11 implementation exposes the native interface through sun.security.pkcs11.wrapper
    So I implemented a method that loads a driver and asks all slots have tokens inserted for the given driver.
        public long[] getSlotsWithTokens(String libraryPath) throws IOException{
            CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS();
            String functionList = "C_GetFunctionList";
    
            initArgs.flags = CKF_OS_LOCKING_OK;
            PKCS11 tmpPKCS11 = null;
            long[] slotList = null;
            try {
                try {
                    tmpPKCS11 = PKCS11.getInstance(libraryPath, functionList, initArgs, false);
                } catch (IOException ex) {
                    ex.printStackTrace();
                    throw ex;
                }
            } catch (PKCS11Exception e) {
                try {
                    initArgs = null;
                    tmpPKCS11 = PKCS11.getInstance(libraryPath, functionList, initArgs, true);
                } catch (IOException ex) {
                   ex.printStackTrace();
                } catch (PKCS11Exception ex) {
                   ex.printStackTrace();
                }
            }
    
            try {
                slotList = tmpPKCS11.C_GetSlotList(true);
    
                for (long slot : slotList){
                    CK_TOKEN_INFO tokenInfo = tmpPKCS11.C_GetTokenInfo(slot);
                    System.out.println("slot: "+slot+"\nmanufacturerID: "
                            + String.valueOf(tokenInfo.manufacturerID) + "\nmodel: "
                            + String.valueOf(tokenInfo.model));
                }
            } catch (PKCS11Exception ex) {
                    ex.printStackTrace();
            } catch (Throwable t) {
                t.printStackTrace()
            }
    
            return slotList;
    
        }
    With this information you can create a configuration string and instantiates and install the provider, like this:
    long[] slots = getSlotsWithTokens("/driver/library/path");
    if (slots.length > 0){
        String tokenConfiguration = new String("name = " + name + "_" + slots[0] + "\n" +
           "library = " + libraryPath + "\nslot = " + slots[0] +"\n");
        Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(tokenConfiguration.getBytes()));
        Security.addProvider(pkcs11Provider);
    }
    Edited by: Esakol on Mar 7, 2012 4:58 PM