簡體   English   中英

使用合格證書簽署PDF文檔-智能卡

[英]Signing PDF document with qualified certificate - smartcard


我的小程序在使用智能卡簽名PDF文檔時遇到問題。 它適用於沒有資格的證書,但不適用於合格的證書。 我正在使用SunPKCS11提供程序。 這是CryptoTech卡。 這是代碼的一部分,我試圖在此提供程序上進行操作:

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";

這是異常stacktrace:

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%正確的。

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

編輯1:
通過:“對於不合格的證書,它可以很好地工作,但對於不合格的證書,它是行得通的。”我的意思是,不合格的證書與該合格的證書放在不同的智能卡上。

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

解決了

好的,我找到了解決問題的方法。

事實證明,提供商默認情況下嘗試使用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/-不幸的是,只有波蘭語。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM