title: Error loading PKCS keystore with multiple card readers
body: <p>I am running into a weird problem when reading CAC card, in a multi terminal setup, from Nth (<strong>Except 1st</strong>) terminal.</p>
  
  <p>Environment -  JDK8_u211, Destop without any card reader, Internal card reader for laptop, USB card reader, CAC\PIV card</p>
  
  <p>USE-CASE Tried</p>
  
  <ol>
  <li>When the CAC card is plugged into <strong>internal</strong> slot of <strong>Laptop</strong>, everything works fine with and withou USB card terminal connected to laptop.</li>
  <li>When the CAC card is plugged into the USB reader and connected to the <strong>Desktop</strong>, everything works fine.</li>
  <li>When the CAC card is plugged into the USB reader and connected to the <strong>Laptop</strong>, <strong>the PKCS store instantiation fails, as the config uses slot=1</strong></li>
  <li>When the CAC card is plugged into the USB reader and connected to the <strong>Laptop</strong>, <strong>if I hard code slot=4 in the config</strong>, everything works fine.</li>
  </ol>
  
  <p>Problem: Unable to determine the correct slot to use within the config file. Somehow number of terminals is not adding up to determine the slot at runtime. </p>
  
  <p>By enabling JDK debug logs, i could verify that internally <strong>"C_GetSlotList"</strong> returns 0,4 where as I have only 2 terminals, hence using index 0 or 1.</p>
  
  <p>Does anyone know how to determine the correlation between terminal vs slot or is there something really wrong in the way i am trying to read the card ?</p>
  
  <p>Please advise.</p>
  
  <p>Sample code</p>
  
  <pre><code>    public class MultipleTerminals {
  
      private static String DLL_PATH = "C:\\opensc-pkcs11.dll";
  
      public static void main(String[] args) throws Exception {
  
          MyTerminal custTerminalObj = getSmartCardTerminal();
          CardTerminal terminal = custTerminalObj.getTerminal();
          Integer terminalIdx = custTerminalObj.getIndex();
          System.out.println("Using Terminal.Name: " + terminal.getName());
          System.out.println("Using Terminal.isCardPresent: " + ((CardTerminal)terminal).isCardPresent());
  
           if (terminal.isCardPresent()) { // duplicate check
               registerProvider(4);
               KeyStore keyStore = createKeyStore();
               printCertificate(keyStore);
           }
      }
  
      public static MyTerminal getSmartCardTerminal() {
          System.out.println("---------------------------------------------------");
          MyTerminal terminal = null;
          int terminalIdx = -1;
          try {
              TerminalFactory factory = TerminalFactory.getDefault();
              if (factory != null) {
                  List&lt;CardTerminal&gt; allTerminals = factory.terminals().list();
                  for(CardTerminal term : allTerminals) {
                      System.out.println("Terminal Name: " + term.getName());
                      System.out.println("isCardPresent: " + term.isCardPresent());
                      System.out.println("----------");                   
                  }
                  for(CardTerminal term : allTerminals) {
                      terminalIdx++;
                      if(term.isCardPresent()) {
                          terminal = new MyTerminal();
                          terminal.setIndex(terminalIdx);
                          terminal.setTerminal(term);
                          System.out.println("Using Terminal Idx: " + terminalIdx);
                      }
                  }
              }
          } catch (CardException e1) {
              terminal = null;
              System.out.println("SmartCardHelper.getSmartCardTerminal --&gt; "
                      + "Exception while accessing smart-card terminal: "
                      + e1.getMessage());
              e1.printStackTrace();
          }
  
          return terminal;
      }
  
      public static void registerProvider(Integer idx) {
          System.out.println("---------------------------------------------------");
          String ext = "attributes(*,*,*)=\n{\nCKA_TOKEN=true\nCKA_LOCAL=true\n}";
          String OPENSC_DEFAULT_PROVIDER_NAME = "PKCS#11";
          String OPENSC_PKCS11_DLL = DLL_PATH;
          String configString = "name = "
                  + OPENSC_DEFAULT_PROVIDER_NAME.replace(' ', '_') + "\n"
                  + "library = "
                  + OPENSC_PKCS11_DLL + "\n slot = " + idx + " "
                  + "\n attributes = compatibility \n" + ext;
  
          System.out.println("\tConfigString: " + configString);
  
          ByteArrayInputStream is = new ByteArrayInputStream(
                  configString.getBytes(Charset.defaultCharset()));
  
          Provider cardSecurityProvider = new sun.security.pkcs11.SunPKCS11(
                  is);
  
          displayProviders();
          Security.addProvider(cardSecurityProvider);
          displayProviders();
          System.out.println("==================");
      }
  
  
      public static KeyStore createKeyStore() throws KeyStoreException {
          KeyStore.CallbackHandlerProtection callbackHandler = new KeyStore.CallbackHandlerProtection(
                  new PIVCardPinHandler());
          KeyStore.Builder builder = KeyStore.Builder.newInstance("PKCS11", null,
                  callbackHandler);
          return builder.getKeyStore();
      }
  
      public static void displayProviders() {
          System.out.println("---------------------------------------------------");
          Provider[] objs = Security.getProviders();
          System.out.println("Provider Count: " + objs.length);
  
          String type = "KeyStore";
          String algorithm="PKCS11";
          ProviderList list = Providers.getProviderList();
          Provider provider = list.getProvider("SunPKCS11-PKCS");
          System.out.println("Provider[SunPKCS11-PKCS]: " + provider);
  
          if(provider != null) {
              Set&lt;Service&gt; svcs = provider.getServices();
              System.out.println("Service count: " + svcs.size());
          }
  
          Service firstService = list.getService(type, algorithm);
          System.out.println("Type[KeyStore], Algo[PKCS11], Service: " + firstService);       
      }
  
      public static void printCertificate(KeyStore keyStore)
              throws KeyStoreException {
          for (String alias : Collections.list(keyStore.aliases())) {
              System.out.println("Alias: " + alias);
          }
      }
  }
  
  
  class MyTerminal{
  
      private Integer index;
      private CardTerminal terminal;
  
      public MyTerminal() {
      }
  
      public Integer getIndex() {
          return index;
      }
      public void setIndex(Integer index) {
          this.index = index;
      }
      public CardTerminal getTerminal() {
          return terminal;
      }
      public void setTerminal(CardTerminal terminal) {
          this.terminal = terminal;
      }   
  }
  </code></pre>
  
  <p><strong>* Output TestCase-1 (WORKING)*</strong></p>
  
  <pre><code>---------------------------------------------------
  Terminal Name: Alcor Micro USB Smart Card Reader 0
  isCardPresent: true
  ----------
  Terminal Name: Identive SCR33xx v2.0 USB SC Reader 0
  isCardPresent: false
  ----------
  Using Terminal Idx: 0
  Using Terminal.Name: Alcor Micro USB Smart Card Reader 0
  Using Terminal.isCardPresent: true
  ---------------------------------------------------
      ConfigString: 
  name = PKCS#11
  library = C:\opensc-pkcs11.dll
   slot = 0 
   attributes = compatibility 
  attributes(*,*,*)=
  {
  CKA_TOKEN=true
  CKA_LOCAL=true
  }
  SunPKCS11 loading ---DummyConfig-1---
  sunpkcs11: Initializing PKCS#11 library C:\opensc-pkcs11.dll
  Information for provider SunPKCS11-PKCS
  Library info:
    cryptokiVersion: 2.20
    manufacturerID: DUMMY_VALUE                  
    flags: 0
    libraryDescription: DUMMY_VALUE      
    libraryVersion: 0.19
  All slots: 0, 4
  Slots with tokens: 0, 4
  Slot info for slot 0:
    slotDescription: Alcor Micro USB Smart Card Reader 0                             
    manufacturerID: DUMMY_VALUE
    flags: CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE | CKF_HW_SLOT
    hardwareVersion: 0.00
    firmwareVersion: 0.00
  Token info for token in slot 0:
    label: DUMMY_VALUE            
    manufacturerID: DUMMY_VALUE                          
    model: PKCS#15 emulated
    serialNumber: DUMMY_VALUE
    flags: CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED
    ulMaxSessionCount: CK_EFFECTIVELY_INFINITE
    ulSessionCount: 0
    ulMaxRwSessionCount: CK_EFFECTIVELY_INFINITE
    ulRwSessionCount: 0
    ulMaxPinLen: 8
    ulMinPinLen: 4
    ulTotalPublicMemory: CK_UNAVAILABLE_INFORMATION
    ulFreePublicMemory: CK_UNAVAILABLE_INFORMATION
    ulTotalPrivateMemory: CK_UNAVAILABLE_INFORMATION
    ulFreePrivateMemory: CK_UNAVAILABLE_INFORMATION
    hardwareVersion: 0.00
    firmwareVersion: 0.00
    utcTime: 
  ---------------------------------------------------
  Provider Count: 10
  Provider[SunPKCS11-PKCS]: null
  Type[KeyStore], Algo[PKCS11], Service: null
  ---------------------------------------------------
  Provider Count: 11
  Provider[SunPKCS11-PKCS]: SunPKCS11-PKCS version 1.8
  Service count: 26
  Type[KeyStore], Algo[PKCS11], Service: SunPKCS11-PKCS: KeyStore.PKCS11 -&gt; sun.security.pkcs11.P11KeyStore
    aliases: [PKCS11-PKCS]
   (KeyStore)
  ==================
  sunpkcs11: caller passed NULL pin
  </code></pre>
  
  <p><strong>* Output TestCase-3 (NOT WORKING)*</strong></p>
  
  <pre><code>---------------------------------------------------
  Terminal Name: Alcor Micro USB Smart Card Reader 0
  isCardPresent: false
  ----------
  Terminal Name: Identive SCR33xx v2.0 USB SC Reader 0
  isCardPresent: true
  ----------
  Using Terminal Idx: 1
  Using Terminal.Name: Identive SCR33xx v2.0 USB SC Reader 0
  Using Terminal.isCardPresent: true
  ---------------------------------------------------
      ConfigString: 
  name = PKCS#11
  library = C:\opensc-pkcs11.dll
   slot = 1 
   attributes = compatibility 
  attributes(*,*,*)=
  {
  CKA_TOKEN=true
  CKA_LOCAL=true
  }
  SunPKCS11 loading ---DummyConfig-1---
  sunpkcs11: Initializing PKCS#11 library C:\opensc-pkcs11.dll
  Information for provider SunPKCS11-PKCS
  Library info:
    cryptokiVersion: 2.20
    manufacturerID: DUMMY_VALUE                  
    flags: 0
    libraryDescription: DUMMY_VALUE      
    libraryVersion: 0.19
  All slots: 0, 4
  Slots with tokens: 0, 4
  ---------------------------------------------------
  Provider Count: 10
  Provider[SunPKCS11-PKCS]: null
  Type[KeyStore], Algo[PKCS11], Service: null
  ---------------------------------------------------
  Provider Count: 11
  Provider[SunPKCS11-PKCS]: SunPKCS11-PKCS version 1.8
  Service count: 0
  Type[KeyStore], Algo[PKCS11], Service: null
  ==================
  Exception in thread "main" java.security.KeyStoreException: KeyStore instantiation failed
      at java.security.KeyStore$Builder$2.getKeyStore(KeyStore.java:1967)
  
  Caused by: java.security.KeyStoreException: PKCS11 not found
      at java.security.KeyStore.getInstance(KeyStore.java:851)
      at java.security.KeyStore$Builder$2$1.run(KeyStore.java:1923)
      at java.security.KeyStore$Builder$2$1.run(KeyStore.java:1918)
      at java.security.AccessController.doPrivileged(Native Method)
      at java.security.KeyStore$Builder$2.getKeyStore(KeyStore.java:1964)
      ... 2 more
  Caused by: java.security.NoSuchAlgorithmException: PKCS11 KeyStore not available
      at sun.security.jca.GetInstance.getInstance(GetInstance.java:159)
      at java.security.Security.getImpl(Security.java:695)
      at java.security.KeyStore.getInstance(KeyStore.java:848)
      ... 6 more
  </code></pre>
  
  <p><strong>* Output TestCase-4 (WORKING)*</strong></p>
  
  <pre><code>---------------------------------------------------
  Terminal Name: Alcor Micro USB Smart Card Reader 0
  isCardPresent: false
  ----------
  Terminal Name: Identive SCR33xx v2.0 USB SC Reader 0
  isCardPresent: true
  ----------
  Using Terminal Idx: 1
  Using Terminal.Name: Identive SCR33xx v2.0 USB SC Reader 0
  Using Terminal.isCardPresent: true
  ---------------------------------------------------
      ConfigString: 
  name = PKCS#11
  library = C:\opensc-pkcs11.dll
   slot = 4 
   attributes = compatibility 
  attributes(*,*,*)=
  {
  CKA_TOKEN=true
  CKA_LOCAL=true
  }
  SunPKCS11 loading ---DummyConfig-1---
  sunpkcs11: Initializing PKCS#11 library C:\opensc-pkcs11.dll
  Information for provider SunPKCS11-PKCS
  Library info:
    cryptokiVersion: DUMMY_VALUE
    manufacturerID: DUMMY_VALUE                  
    flags: 0
    libraryDescription: DUMMY_VALUE      
    libraryVersion: DUMMY_VALUE
  All slots: 0, 4
  Slots with tokens: 0, 4
  Slot info for slot 4:
    slotDescription: DUMMY_VALUE                           
    manufacturerID: DUMMY_VALUE
    flags: CKF_TOKEN_PRESENT | CKF_REMOVABLE_DEVICE | CKF_HW_SLOT
    hardwareVersion: 0.00
    firmwareVersion: 0.00
  Token info for token in slot 4:
    label: DUMMY_LABEL            
    manufacturerID: DUMMY_VALUE                          
    model: PKCS#15 emulated
    serialNumber: DUMMY_VALUE
    flags: CKF_RNG | CKF_LOGIN_REQUIRED | CKF_USER_PIN_INITIALIZED | CKF_TOKEN_INITIALIZED
    ulMaxSessionCount: CK_EFFECTIVELY_INFINITE
    ulSessionCount: 0
    ulMaxRwSessionCount: CK_EFFECTIVELY_INFINITE
    ulRwSessionCount: 0
    ulMaxPinLen: 8
    ulMinPinLen: 4
    ulTotalPublicMemory: CK_UNAVAILABLE_INFORMATION
    ulFreePublicMemory: CK_UNAVAILABLE_INFORMATION
    ulTotalPrivateMemory: CK_UNAVAILABLE_INFORMATION
    ulFreePrivateMemory: CK_UNAVAILABLE_INFORMATION
    hardwareVersion: 0.00
    firmwareVersion: 0.00
    utcTime: 
  ---------------------------------------------------
  Provider Count: 10
  Provider[SunPKCS11-PKCS]: null
  Type[KeyStore], Algo[PKCS11], Service: null
  ---------------------------------------------------
  Provider Count: 11
  Provider[SunPKCS11-PKCS]: SunPKCS11-PKCS version 1.8
  Service count: 26
  Type[KeyStore], Algo[PKCS11], Service: SunPKCS11-PKCS: KeyStore.PKCS11 -&gt; sun.security.pkcs11.P11KeyStore
    aliases: [PKCS11-PKCS]
   (KeyStore)
  ==================
  sunpkcs11: caller passed NULL pin
  </code></pre>