8 Replies Latest reply: Mar 6, 2013 2:14 AM by PhHein RSS

    How to re-init PKCS11

    828037
      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
          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
            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
              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
                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
                  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
                    I can't use Security.removeProvider.
                    Because?
                    • 7. Re: How to re-init PKCS11
                      995085
                      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
                        Please don't post to years old threads.

                        Moderator action: I'm locking this thread