This discussion is archived
8 Replies Latest reply: Mar 6, 2013 12:14 AM by PhHein RSS

How to re-init PKCS11

828037 Newbie
Currently Being Moderated
Hi.

I wrote a little program to sign xml docs using smart-card.
I used sun.security.pkcs11.sunPKCS11 provider which use sun.security.pkcs11.wrapper.PKCS11.
When i plugged in card-reader to PC before invoke below line

pkcs11Provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));

everything it's ok.

If I invoke above line before i plug in card-reader java throw exception "java.security.ProviderException: Initialization failed". When I plug in card-reader to PC situation repet until i'm close program and run it again.

How to re-init PKCS11/sunPKCS11 without re-run my program?

String pkcs11config =
"name = SmartCard\n" +
"library = C:\\Program Files\\CryptoTech\\CryptoCard\\CCPkiP11.dll\n" +
"slot = 3\n";
pkcs11Provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));
  • 1. Re: How to re-init PKCS11
    828037 Newbie
    Currently Being Moderated
    Hi,

    I resolve my problem. Method is a little dirty.

    pkcs11config =
    "name = SmartCard\n" +
    "library = C:\\Program Files\\CryptoTech\\CryptoCard\\CCPkiP11.dll\n" +
    "slot = 3\n" +
    "showInfo = true\n"
    ;
    try {
    pkcs11Provider = new SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));
    } catch (ProviderException ex) {
    Map m = new HashMap();
    Field field = PKCS11.class.getDeclaredField("moduleMap");
    field.setAccessible(true);
    m = (Map) field.get(pkcs11Provider);
    tmpPkcs11 = (sun.security.pkcs11.wrapper.PKCS11) m.get("C:\\Program Files\\CryptoTech\\CryptoCard\\CCPkiP11.dll");
    tmpPkcs11 = PKCS11.getInstance("C:\\Program Files\\CryptoTech\\CryptoCard\\CCPkiP11.dll", "", null, true);
    tmpPkcs11.finalize();
    m.remove("C:\\Program Files\\CryptoTech\\CryptoCard\\CCPkiP11.dll");
    }

    Maybe someone has a better idea?
  • 2. Re: How to re-init PKCS11
    sabre150 Expert
    Currently Being Moderated
    Am I missing something. Can't you just remove the provider using System.removeProvider() and then add a new instance?
  • 3. Re: How to re-init PKCS11
    828037 Newbie
    Currently Being Moderated
    I can't use Security.removeProvider.

    String pkcs11config = "name = SmartCard\n" + "library = C:\Program Files\CryptoTech\CryptoCard\CCPkiP11.dll\n" + "slot = 3\n" ;
    try {
    Provider pkcs11Provider = new SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));
    } catch (ProviderException ex) {
    try {
    Map m = new HashMap();
    Field field = PKCS11.class.getDeclaredField("moduleMap");
    field.setAccessible(true);
    m = (Map) field.get(pkcs11Provider);
    tmpPkcs11 = (sun.security.pkcs11.wrapper.PKCS11) m.get("C:\Program Files\CryptoTech\CryptoCard\CCPkiP11.dll");
    try {
    tmpPkcs11.finalize();
    } catch (Throwable ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    }
    m.remove("C:\Program Files\CryptoTech\CryptoCard\CCPkiP11.dll");
    } catch (IllegalArgumentException ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    } catch (IllegalAccessException ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    } catch (NoSuchFieldException ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    } catch (SecurityException ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    } catch (Error er) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, er);
    }
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex);
    }
    Security.addProvider(pkcs11Provider);

    As you see Security.addProvider is used after Provider pkcs11Provider = new SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));

    When smartcard reader is disconnected then java has a problem with a driver initialization and throws exception in line
    Provider pkcs11Provider = new SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));
  • 4. Re: How to re-init PKCS11
    sabre150 Expert
    Currently Being Moderated
    AdamMiazga wrote:
    I can't use Security.removeProvider.
    I don't see that what you have posted demonstrates this.

    >
    String pkcs11config = "name = SmartCard\n" + "library = C:\Program Files\CryptoTech\CryptoCard\CCPkiP11.dll\n" + "slot = 3\n" ;
    try {
    Provider pkcs11Provider = new SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));
    } catch (ProviderException ex) {
    I don't see how you ever access the Provider instance since it is only referenced inside the block.

    You could be very right about needing to go though the contortions you propose but I would be very surprised and I would be contacting the manufacturer to see what I was missing. I find it difficult to believe that the manufacturer has not covered this in some more direct manner.
  • 5. Re: How to re-init PKCS11
    828037 Newbie
    Currently Being Moderated
    Ok. I unfortunately past my code.
    More correctly is that.

    String pkcs11config = "name = SmartCard\n" + "library = C:\Program Files\CryptoTech\CryptoCard\CCPkiP11.dll\n" + "slot = 3\n" ;
    try {
    Provider pkcs11Provider = new SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));
    Security.addProvider(pkcs11Provider);
    } catch (ProviderException ex) {
    try {
    Map m = new HashMap();
    Field field = PKCS11.class.getDeclaredField("moduleMap");
    field.setAccessible(true);
    m = (Map) field.get(pkcs11Provider);
    tmpPkcs11 = (sun.security.pkcs11.wrapper.PKCS11) m.get("C:\Program Files\CryptoTech\CryptoCard\CCPkiP11.dll";);
    try {
    tmpPkcs11.finalize();
    } catch (Throwable ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    }
    m.remove("C:\Program Files\CryptoTech\CryptoCard\CCPkiP11.dll";);
    } catch (IllegalArgumentException ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    } catch (IllegalAccessException ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    } catch (NoSuchFieldException ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    } catch (SecurityException ex1) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex1);
    } catch (Error er) {
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, er);
    }
    Logger.getLogger(EPodpis.class.getName()).log(Level.SEVERE, null, ex);
    }

    As I wrote

    Provider pkcs11Provider = new SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes()));
    throws ProviderException java.security.ProviderException: Initialization failed when smartcard reader is disconnected.
    If I connect smartcard reader and call again Provider pkcs11Provider = new SunPKCS11(new ByteArrayInputStream(pkcs11config.getBytes())); i get again java.security.ProviderException: Initialization failed

    Variable moduleMap in class sun.security.pkcs11.wrapper.PKCS11 is declared that

    private static final Map<String,jhmsPKCS11> moduleMap = new HashMap<String,PKCS11>();

    and method which returns an instance of PKCS11 looks that

    public static synchronized PKCS11 getInstance(String pkcs11ModulePath, String functionList,
    CK_C_INITIALIZE_ARGS pInitArgs, boolean omitInitialize)
    throws IOException, PKCS11Exception {
    // we may only call C_Initialize once per native .so/.dll
    // so keep a cache using the (non-canonicalized!) path
    PKCS11 pkcs11 = moduleMap.get(pkcs11ModulePath);
    if (pkcs11 == null) {
    if ((pInitArgs != null)
    && ((pInitArgs.flags & CKF_OS_LOCKING_OK) != 0)) {
    pkcs11 = new PKCS11(pkcs11ModulePath, functionList);
    } else {
    pkcs11 = new SynchronizedPKCS11(pkcs11ModulePath, functionList);
    }
    if (omitInitialize == false) {
    try {
    pkcs11.C_Initialize(pInitArgs);
    } catch (PKCS11Exception e) {
    // ignore already-initialized error code
    // rethrow all other errors
    if (e.getErrorCode() != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
    throw e;
    }
    }
    }
    moduleMap.put(pkcs11ModulePath, pkcs11);
    }
    return pkcs11;
    }

    Class sun.security.pkcs11.wrapper.PKCS11 is not provide any method to clear moduleMap

    [Thats look sun.security.pkcs11.wrapper.PKCS11|http://www.docjar.com/html/api/sun/security/pkcs11/wrapper/PKCS11.java.html]
  • 6. Re: How to re-init PKCS11
    EJP Guru
    Currently Being Moderated
    I can't use Security.removeProvider.
    Because?
  • 7. Re: How to re-init PKCS11
    995085 Newbie
    Currently Being Moderated
    Please look at the getInstance method posted by Adam,

    PKCS11 pkcs11 = moduleMap.get(pkcs11ModulePath);
    if (pkcs11 == null) {
    if ((pInitArgs != null)
    && ((pInitArgs.flags & CKF_OS_LOCKING_OK) != 0)) {
    pkcs11 = new PKCS11(pkcs11ModulePath, functionList);
    } else {
    pkcs11 = new SynchronizedPKCS11(pkcs11ModulePath, functionList);
    }
    if (omitInitialize == false) {
    try {
    pkcs11.C_Initialize(pInitArgs);
    } catch (PKCS11Exception e) {
    ...

    If the (failed) pkcs11 instance has been cached in the modulemap, this getInstance method will ignore the omitInitialize parameter and go out without creating a new pkcs11 instance to replace the failed one. Hence the exception will persist.

    I would think this a bug of sun.security.pkcs11.wrapper.PKCS11, at least from resiliance point of view.
    Would there be any expert / contributor monitoring this discussion thread to propose any fix or patch? Thank you.
  • 8. Re: How to re-init PKCS11
    PhHein Guru Moderator
    Currently Being Moderated
    Please don't post to years old threads.

    Moderator action: I'm locking this thread

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points