2016-01-21 40 views
0


我的小應用程序使用智能卡簽署PDF文檔時出現問題。它適用於不合格的證書,但不適合合格證書。我正在使用SunPKCS11提供程序。它是CryptoTech卡。這裏有一個代碼,在那裏我試圖在此提供操作部分:使用合格證書籤署PDF文檔 - 智能卡

String pkcs11config = "name = " + PROVIDER + "\nlibrary = \"" + value + "\""; 
byte[] pkcs11configBytes = pkcs11config.getBytes(); 
final ByteArrayInputStream configStream = new ByteArrayInputStream(pkcs11configBytes); 
pkcs11Provider = new sun.security.pkcs11.SunPKCS11(configStream); 
Security.addProvider(pkcs11Provider); 

這裏是代碼,當問題發生:

final KeyStore keyStore = KeyStore.getInstance(TYPE, pkcs11Provider); 
     keyStore.load(null, PIN); 

而且常量:

public static final String PROVIDER = "CryptoTech"; 
private static final String TYPE = "PKCS11"; 

以下是異常堆棧跟蹤:

java.io.IOException: load failed 
    at sun.security.pkcs11.P11KeyStore.engineLoad(P11KeyStore.java:763) 
    at java.security.KeyStore.load(Unknown Source) 
    at pl.emsi.sign.card.CardManager.getKey(CardManager.java:165) 
    at pl.emsi.sign.logic.DocumentLogic$1.success(DocumentLogic.java:79) 
    at pl.emsi.sign.card.CardManager$1.driverSelected(CardManager.java:92) 
    at pl.emsi.sign.card.CardManager$2.driverSelected(CardManager.java:121) 
    at pl.emsi.sign.card.CardManager$7.actionPerformed(CardManager.java:414) 
    at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) 
    at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source) 
    at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source) 
    at javax.swing.DefaultButtonModel.setPressed(Unknown Source) 
    at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source) 
    at java.awt.Component.processMouseEvent(Unknown Source) 
    at javax.swing.JComponent.processMouseEvent(Unknown Source) 
    at java.awt.Component.processEvent(Unknown Source) 
    at java.awt.Container.processEvent(Unknown Source) 
    at java.awt.Component.dispatchEventImpl(Unknown Source) 
    at java.awt.Container.dispatchEventImpl(Unknown Source) 
    at java.awt.Component.dispatchEvent(Unknown Source) 
    at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source) 
    at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source) 
    at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source) 
    at java.awt.Container.dispatchEventImpl(Unknown Source) 
    at java.awt.Window.dispatchEventImpl(Unknown Source) 
    at java.awt.Component.dispatchEvent(Unknown Source) 
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source) 
    at java.awt.EventQueue.access$500(Unknown Source) 
    at java.awt.EventQueue$3.run(Unknown Source) 
    at java.awt.EventQueue$3.run(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source) 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source) 
    at java.awt.EventQueue$4.run(Unknown Source) 
    at java.awt.EventQueue$4.run(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source) 
    at java.awt.EventQueue.dispatchEvent(Unknown Source) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) 
    at java.awt.WaitDispatchSupport$2.run(Unknown Source) 
    at java.awt.event.InvocationEvent.dispatch(Unknown Source) 
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source) 
    at java.awt.EventQueue.access$500(Unknown Source) 
    at java.awt.EventQueue$3.run(Unknown Source) 
    at java.awt.EventQueue$3.run(Unknown Source) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source) 
    at java.awt.EventQueue.dispatchEvent(Unknown Source) 
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source) 
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source) 
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source) 
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source) 
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source) 
    at java.awt.EventDispatchThread.run(Unknown Source) 
Caused by: javax.security.auth.login.LoginException 
    at sun.security.pkcs11.SunPKCS11.login(SunPKCS11.java:1238) 
    at sun.security.pkcs11.P11KeyStore.login(P11KeyStore.java:849) 
    at sun.security.pkcs11.P11KeyStore.engineLoad(P11KeyStore.java:753) 
    ... 54 more 
Caused by: sun.security.pkcs11.wrapper.PKCS11Exception: CKR_PIN_LOCKED 
    at sun.security.pkcs11.wrapper.PKCS11.C_Login(Native Method) 
    at sun.security.pkcs11.SunPKCS11.login(SunPKCS11.java:1222) 
    ... 56 more 

我已經檢查過PIN碼未被鎖定,因爲其他應用程序(無需提及此應用程序的名稱)在沒有任何問題的情況下對PDF文檔簽名。 PIN碼也是100%正確的。

如果缺少一些信息,請告訴我。

EDIT1:
到:「它工作正常的沒有資格證書,但不會爲合格的」我的意思是,沒有資格證書放置在不同的智能卡比這個資格證書。

+2

智能卡有時需要不同的引腳用於不同的用途。如果智能卡例如對於合格簽名和僅僅是高級簽名(第一次簽署合同,第二次簽名在電子門鎖進行驗證)都有關鍵材料,通常可以獨立選擇各自的PIN。 – mkl

+2

這可能有助於使用一些pkcs11記錄器(例如[this one])(https://github.com/jariq/pkcs11-logger))來檢查正在發生的事情(您可以比較不同的程序與不同的卡片會發現差異)。祝你好運! – vlp

+0

@vlp對於非開源應用程序,這種記錄器不是「付費使用」嗎? – null

回答

1

解決

好吧,我發現我的問題的解決方案。

事實證明,提供商試圖默認使用ID爲0的卡槽。出現問題的卡片在三個第一個插槽上具有非合格證書。這些插槽上的令牌未初始化。我試圖使用的合格證書放在第四個插槽上。

我用IAIK PKCS11 Wrapper得到這張卡的Tokens的信息。這裏的代碼示例:

 try { 
      Module module = Module.getInstance(value); 
      module.initialize(null); 
      Slot[] slots = module.getSlotList(true); 
      TokenInfo[] infos = new TokenInfo[slots.length]; 
      for (int i = 0; i < slots.length; i++) { 
       infos[i] = slots[i].getToken().getTokenInfo(); 
      } 
      printTokenInfos(infos); 
      if (slots.length == 0) { 
       System.err.println("No token available!"); 
       return; 
      } 
     } catch (TokenException | IOException e1) { 
      e1.printStackTrace(); 
     } 

     [...] 

    private void printTokenInfos(TokenInfo[] infos) { 
     int counter = 0; 
     for (TokenInfo info : infos) { 
      System.out.println("Token: " + counter++); 
      System.out.println(info); 
     } 
    } 

    //"value" passed to Module's getInstance method is th path for .dll module 
    //used for one's type of card. 

從這個地方我可以確定我應該使用哪個插槽。可以通過將slotListIndex參數添加到提供者的配置輸入流來完成。例如。

String pkcs11config = "name = " + PROVIDER + "\nlibrary = \"" + value + "\"\nslotListIndex = " + slotIndex; 

有用的網站針對此問題:
IAIK JCA/JCE
https://javaczysen.blogspot.com/ - 遺憾的是,只有在打磨。

1

在keyStore.load方法(keyStore.load(null,null))中傳遞null來代替PIN參數將導致來自各個令牌驅動程序的密碼提示。您可以驗證PIN這樣...

+0

已經通過提供PasswordCallback檢查了此方法 - 仍然是同樣的問題。 – null

相關問題