PKCS#11实例化问题

can*_*ion 6 java cryptography digital-signature pkcs#11

我正在尝试使用智能卡和PKCS#11签署pdf文件.我链接正确的.dll,我正在动态制作配置文件,但我遇到了配置问题.

String config = "name=zz\n" +
                "library=" + DLL + "\n" +
                "slotListIndex = " + getSlotsWithTokens(DLL)[0];
ByteArrayInputStream pot = new ByteArrayInputStream(config.getBytes());
Provider providerPKCS11 = new SunPKCS11(pot);
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

Exception in thread "main" java.security.ProviderException: Initialization failed
    at sun.security.pkcs11.SunPKCS11.<init>(SunPKCS11.java:376)
    at sun.security.pkcs11.SunPKCS11.<init>(SunPKCS11.java:107)
    at smartCardPKCS11.scPKCS11.main(scPKCS11.java:56)
Caused by: java.security.ProviderException: slotListIndex is 52481 but token only has 10 slots
    at sun.security.pkcs11.SunPKCS11.<init>(SunPKCS11.java:357)
    ... 2 more
Run Code Online (Sandbox Code Playgroud)

在整个插槽事情上有点困惑.有人可以帮我吗?

我的getSlotsWithTokens看起来如何:

public static long[] getSlotsWithTokens(String libraryPath) throws IOException{
        CK_C_INITIALIZE_ARGS initArgs = new CK_C_INITIALIZE_ARGS();
        String functionList = "C_GetFunctionList";

        initArgs.flags = 0;
        PKCS11 tmpPKCS11 = null;
        long[] slotList = null;
        try {
            try {
                tmpPKCS11 = PKCS11.getInstance(libraryPath, functionList, initArgs, false);
            } catch (IOException ex) {
                ex.printStackTrace();
                throw ex;
            }
        } catch (PKCS11Exception e) {
            try {
                initArgs = null;
                tmpPKCS11 = PKCS11.getInstance(libraryPath, functionList, initArgs, true);
            } catch (IOException ex) {
               ex.printStackTrace();
            } catch (PKCS11Exception ex) {
               ex.printStackTrace();
            }
        }

        try {
            slotList = tmpPKCS11.C_GetSlotList(true);

            for (long slot : slotList){
                CK_TOKEN_INFO tokenInfo = tmpPKCS11.C_GetTokenInfo(slot);
                System.out.println("slot: "+slot+"\nmanufacturerID: "
                        + String.valueOf(tokenInfo.manufacturerID) + "\nmodel: "
                        + String.valueOf(tokenInfo.model));
            }
        } catch (PKCS11Exception ex) {
                ex.printStackTrace();
        } catch (Throwable t) {
            t.printStackTrace();
        }

        return slotList;

    }
Run Code Online (Sandbox Code Playgroud)

更新后的版本:

所以我按照@albciff建议进行了更改:这里是完整的代码:

import java.io.ByteArrayInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.Security;
import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import sun.security.pkcs11.SunPKCS11;
import sun.security.pkcs11.wrapper.CK_C_INITIALIZE_ARGS;
import sun.security.pkcs11.wrapper.CK_TOKEN_INFO;
import sun.security.pkcs11.wrapper.PKCS11;
import sun.security.pkcs11.wrapper.PKCS11Exception;

import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.log.LoggerFactory;
import com.itextpdf.text.log.SysoLogger;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfSignatureAppearance;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.security.BouncyCastleDigest;
import com.itextpdf.text.pdf.security.CrlClient;
import com.itextpdf.text.pdf.security.CrlClientOnline;
import com.itextpdf.text.pdf.security.DigestAlgorithms;
import com.itextpdf.text.pdf.security.ExternalDigest;
import com.itextpdf.text.pdf.security.ExternalSignature;
import com.itextpdf.text.pdf.security.MakeSignature;
import com.itextpdf.text.pdf.security.PrivateKeySignature;
import com.itextpdf.text.pdf.security.TSAClient;
import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
import com.itextpdf.text.pdf.security.OcspClient;
import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;

public class sPKCS11  {
    public static final String SRC = "src/Test.pdf";
    public static final String DEST = "src/scTest.pdf";
    public static final String DLL = "c:/windows/system32/aetpkss1.dll";

    public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
        LoggerFactory.getInstance().setLogger(new SysoLogger());
        String pkcs11ConfigSettings = "name=aet\n"+"library="+DLL;
        byte[] pkcs11ConfigBytes = pkcs11ConfigSettings.getBytes();
        ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11ConfigBytes);

        SunPKCS11 pkcs11 = new SunPKCS11(confStream);
        Security.addProvider(pkcs11);

        BouncyCastleProvider providerBC = new BouncyCastleProvider();
        Security.addProvider(providerBC);

        KeyStore ks = KeyStore.getInstance("PKCS11");
        ks.load(null, null);
        Enumeration<String> aliases = ks.aliases();
        while (aliases.hasMoreElements()) {
            System.out.println(aliases.nextElement());
        }
        // alias is here just for the sake of keeping things private
        smartcardsign(pkcs11.getName(), ks, "alias");
    }

    public static void smartcardsign(String provider, KeyStore ks, String alias) throws GeneralSecurityException, IOException, DocumentException {
        PrivateKey pk = (PrivateKey)ks.getKey(alias, null);
        Certificate[] chain = ks.getCertificateChain(alias);
        OcspClient ocspClient = new OcspClientBouncyCastle();
        List<CrlClient> crlList = new ArrayList<CrlClient>();
        crlList.add(new CrlClientOnline(chain));
        scPKCS11 app = new scPKCS11();
        app.sign(SRC, String.format(DEST, alias), chain, pk, DigestAlgorithms.SHA256, provider, CryptoStandard.CMS,
                "Test", "B", crlList, ocspClient, null, 0);
    }

    public void sign(String src, String dest,
            Certificate[] chain, PrivateKey pk,
            String digestAlgorithm, String provider, CryptoStandard subfilter,
            String reason, String location,
            Collection<CrlClient> crlList,
            OcspClient ocspClient,
            TSAClient tsaClient,
            int estimatedSize)
                    throws GeneralSecurityException, IOException, DocumentException {
        // Creating the reader and the stamper
        PdfReader reader = new PdfReader(src);
        FileOutputStream os = new FileOutputStream(dest);
        PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
        // Creating the appearance
        PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
        appearance.setReason(reason);
        appearance.setLocation(location);
        appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
        appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
        // Creating the signature
        ExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
        ExternalDigest digest = new BouncyCastleDigest();
        MakeSignature.signDetached(appearance, digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是新的错误消息:

Exception in thread "main" java.security.KeyStoreException: PKCS11 not found
    at java.security.KeyStore.getInstance(Unknown Source)
    at smartCardPKCS11.sPKCS11.main(sPKCS11.java:65)
Caused by: java.security.NoSuchAlgorithmException: PKCS11 KeyStore not available
    at sun.security.jca.GetInstance.getInstance(Unknown Source)
    at java.security.Security.getImpl(Unknown Source)
    ... 2 more
Run Code Online (Sandbox Code Playgroud)

我知道这是非常愚蠢的事情,欢迎帮助.

alb*_*iff 3

slotListIndex在配置中告知它是可选的(但是该方法getSlotsWithTokens()没有返回您期望的值)。slotListIndex参数说明可以参见PKCS11 Reference

这是与该提供程序实例关联的槽索引。它是 PKCS#11 函数 C_GetSlotList 返回的所有槽列表的索引。例如,0 表示列表中的第一个槽。最多可以指定 slot 或 slotListIndex 之一。如果两者均未指定,则默认 slotListIndex 为 0。

因此,仅配置namelibrary参数来配置您的PKCS11提供程序以避免异常:

// Configure the Sun PKCS#11 provider. It requires a stream 
// containing the configuration parameters - "name" and "library".
String pkcs11ConfigSettings = "name = " + pkcs11ID + "\n" + "library = " + libraryPath;
byte[] pkcs11ConfigBytes = pkcs11ConfigSettings.getBytes();
ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11ConfigBytes);

// instantiate the provider
SunPKCS11 pkcs11 = new SunPKCS11(confStream);
Security.addProvider(pkcs11);   
...
Run Code Online (Sandbox Code Playgroud)

编辑:

现在,在您的代码中,您正在正确加载提供程序,因此java.security.KeyStoreException: PKCS11 not found在后续调用中会抛出 ,KeyStore ks = KeyStore.getInstance("PKCS11");因为您的智能卡未插入,或者如果插入,则提供程序可能存在一些问题(两个问题都抛出相同的异常),因此请尝试通过提供者显式地使用以下方法到实例getInstance(String,Provider)

使用:

SunPKCS11 pkcs11 = new SunPKCS11(confStream);
KeyStore ks = KeyStore.getInstance("PKCS11", pkcs11);
Run Code Online (Sandbox Code Playgroud)

代替:

KeyStore ks = KeyStore.getInstance("PKCS11");
Run Code Online (Sandbox Code Playgroud)

此外,您的代码中存在错误:您必须提供PKCS11密码,而不是null在尝试加载密钥库时提供。

所以使用:

ks.load(null, "yourPassword".toCharArray());
Run Code Online (Sandbox Code Playgroud)

代替:

ks.load(null, null);
Run Code Online (Sandbox Code Playgroud)

请注意,使用密码回调处理程序访问PKCS11密钥库也很常见。

总而言之,代码可能是:

// Configure the Sun PKCS#11 provider. It requires a stream 
// containing the configuration parameters - "name" and "library".
String pkcs11ConfigSettings = "name = " + pkcs11ID + "\n" + "library = " + libraryPath;
byte[] pkcs11ConfigBytes = pkcs11ConfigSettings.getBytes();
ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11ConfigBytes);

// instantiate the provider
SunPKCS11 pkcs11 = new SunPKCS11(confStream);
Security.addProvider(pkcs11);   
KeyStore ks = KeyStore.getInstance("PKCS11", pkcs11);
ks.load(null, "yourPassword".toCharArray());
Run Code Online (Sandbox Code Playgroud)