当前位置: 首页 > 知识库问答 >
问题:

无PIN/密码从PKCS11智能卡获取证书

那安宁
2023-03-14

摘要:在PKCS11和OpenSC上使用JCA时,在提取证书时会请求PIN。

我有一个应用程序需要使用智能卡签名。智能卡由OpenSC支持,所以我使用Java内置的pkcs11包装提供程序来使用它。出于功能原因,我需要在不需要PIN的情况下获得卡中的证书。如果用户最终签名,那么当然需要PIN。

我明白了,我可以在命令行中完成,而无需提供PIN:

pkcs11-tool --module C:\WINDOWS\system32\opensc-pkcs11.dll -r -a 50-MDS_Signature -y cert -o p.cer
Using slot 1 with a present token (0x1)

到目前为止,一切顺利。

Oracle的文档清楚地说,“生成器将根据需要使用之前配置的回调处理程序提示输入密码”(http://docs.oracle.com/javase/6/docs/technotes/guides/security/p11guide.html#Login).然而,我的代码在调用KeyStore ks0=ksbuilder0时总是以子身份请求pin。getKeyStore() 即使只提取公共信息(如证书)。

下面是代码的摘录:

private static final String PKCS11_LIB = "C:\\WINDOWS\\system32\\opensc-pkcs11.dll";
private static final String NAME = "OpenSCpkcs11";
private static final String SLOT = "1";
private static final String PIN = "11111111";
private static final String ALIAS = "myCert";

[...]

private static CallbackHandler myCallbackHandler = new CallbackHandler() {
    @Override
    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            if (callback instanceof PasswordCallback) {
                PasswordCallback passwordCallback = (PasswordCallback) callback;
                System.out.println(passwordCallback.getPrompt() + PIN);
                passwordCallback.setPassword(PIN.toCharArray());
            }
        }
    }
};

[...]

String configString = "name = "
  + NAME.replace(' ', '_')
  + "\n"
  + "library = "
  + PKCS11_LIB
  + "\n slot = "
  + SLOT
  + " "
  + "\n attributes = compatibility \n"
  + "attributes(*,*,*)=\n{\nCKA_TOKEN=true\nCKA_LOCAL=true\n}";
ByteArrayInputStream configStream = new ByteArrayInputStream(
    configString.getBytes());
SunPKCS11 pkcs11Provider0 = new SunPKCS11(configStream);
pkcs11Provider0.login(null, myCallbackHandler);
Security.addProvider(pkcs11Provider0);
KeyStore.CallbackHandlerProtection chp = new KeyStore.CallbackHandlerProtection(
    myCallbackHandler);
KeyStore.Builder ksbuilder0 = KeyStore.Builder.newInstance(
    "PKCS11", pkcs11Provider0, chp);
KeyStore ks0 = ksbuilder0.getKeyStore();
X509Certificate cert0 = (X509Certificate) ks0.getCertificate(ALIAS);
// System.out.println("Cert " + cert0.toString());
Principal p = cert0.getSubjectDN();
System.out.println("I am: " + cert0.getSubjectDN().getName());

结果是:

Contraseña de la tarjeta de claves PKCS11 [SunPKCS11-OpenSCpkcs11]: 11111111
2014-01-16 17:48:11.275 cannot lock memory, sensitive data may be paged to disk
I am: CN=pepe perez, SURNAME=pepe, L=qwerty

正如您所看到的,在获得证书之前会请求密码。通过调试,我可以看到在KeyStore ks0=ksbuilder0行中请求了密码。getKeyStore()

任何想法?没有办法按我想要的配置吗?有什么进一步的想法或测试吗?

此外:您是否知道任何其他访问智能卡的方法,例如直接通过JAVA2OpenSC包装器或类似的方式?

谢谢,


共有3个答案

夏何平
2023-03-14

最后,没有使用JCA的解决方案。最终的解决方案是直接攻击PKCS11驱动程序。我用过jacknji11(https://github.com/joelhockey/jacknji11)以及PKCS11规范(http://www.emc.com/emc-plus/rsa-labs/standards-initiatives/pkcs-11-cryptographic-token-interface-standard.htm).

贺宏富
2023-03-14

我曾经做过的是

    Provider prov = new sun.security.pkcs11.SunPKCS11("pkcs.cfg");
    Security.addProvider(prov);
    KeyStore cc = null;
    try {
        cc = KeyStore.getInstance("PKCS11");
        cc.load(null, null);
        cc.getCertificate("CITIZEN AUTHENTICATION CERTIFICATE")
    } catch (Exception ex) {
        ex.printStackTrace();
    }

pkcs.cfg是指向“libpteidpkcs11.so”库的文件,您应该能够使其适应您的代码。我的上面写着:

name = SmartCard
library = /usr/local/lib/libpteidpkcs11.so
令狐献
2023-03-14

解决了的

我找到了从智能卡获取公共证书的方法。

    String pkcs11Config = "name = SmartCard\nlibrary = /path/to/libraby.so";
    ByteArrayInputStream confStream = new ByteArrayInputStream(pkcs11Config.getBytes());
    Provider prov = new sun.security.pkcs11.SunPKCS11(confStream);
    Security.addProvider(prov);
    KeyStore cc = null;
    String pin = "";
    try {
        cc = KeyStore.getInstance("PKCS11",prov);
        KeyStore.PasswordProtection pp = new KeyStore.PasswordProtection(pin.toCharArray());
        cc.load(null ,  pp.getPassword() );
        Enumeration aliases = cc.aliases();
        while (aliases.hasMoreElements()) {
            Object alias = aliases.nextElement();
            try {
                X509Certificate cert0 = (X509Certificate) cc.getCertificate(alias.toString());
                System.out.println("I am: " + cert0.getSubjectDN().getName());
            } catch (Exception e) {
                continue;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

KeyStore.load()应提供带空引脚的Paswordprotected对象。这允许我读取公共证书并从中提取数据。

我已经用3种不同类型的智能卡测试了这个功能,并且所有的智能卡都可以使用

 类似资料:
  • 我正试图从智能卡读取证书, 这是我从http://www.developer.com/java/other/article.php/3587361/Java-Applet-for-Signing-with-a-Smart-Card.htm我将在applet中执行这段代码,问题是每个用户都必须向我指出他们的本地pkcs11。。。dll,使用java samrtcard api是否可以避免加载此dll

  • 我有一个Java应用程序,可以从智能卡读取证书,并使用它们登录用户。该应用还可以使用其他登录方法(用户名和密码)跟踪失败的登录尝试。 我想知道是否有可能在没有引脚的情况下从智能卡中读取用户信息?我想将失败的pin条目标记为失败的登录尝试,但是因为我需要pin从证书中读取别名,所以我无法知道哪个用户正在尝试登录。有没有读取这些信息没有引脚在Java? 我根据这个线程的建议尝试加载KeyStore对象

  • 我正在编写一个Java程序,该程序使用USB证书(智能卡)进行加密和签名。我有一个共享库(Windows上为.dll,Linux上为.so),它为硬件实现PKCS11。 我正在搜索现有的解决方案,并找到以下指南http://docs.oracle.com/javase/7/docs/technotes/guides/security/p11guide.html指南建议使用sun。安全pkcs11.

  • 因此,我正在尝试编写一个小applet,它使用library。智能卡与读卡器连接,现在我成功连接到智能卡并读取基本信息,如ATR和协议(T=1)。 我对此做了一些研究(例如:http://www.cardwerk.com/smartcards/smartcard_standard_ISO7816-4_5_basic_organizations.aspx#table9) 但我不知道我应该向卡上发送哪

  • 我有一个面向服务的webapp,它使用IIS 8.5和通过智能卡的客户端证书身份验证。静态服务的前端通过AJAX调用多个服务。带有证书的智能卡受PIN保护。当使用Chrome、Firefox等浏览器时,PIN提示只会出现一次,似乎会被缓存以供后续使用。 但是,我们需要将webapp嵌入Windows 10。NET桌面应用程序。webapp可以工作,但是用户需要不断地输入他们的PIN,每个服务一次,

  • 问题内容: 我尝试从KeyStore获取密钥。我通过Keytool创建了一个密钥库: keytool -genkeypair -dname“ cn = Mark Jones,ou = JavaSoft,o = Sun,c = US” -alias business2 -keypass abcdtest -keystore C:\ workspace \ XMLSample \ keystore \