【问题标题】:How to sign a jar with a smartcard如何使用智能卡对 jar 进行签名
【发布时间】:2015-12-22 16:19:04
【问题描述】:

我在工作中使用 PKCS11 智能卡,并希望使用 jarsigner 使用我卡上的证书对 jar 文件进行签名。

我主要在 Linux 上工作。 Coolkey 可以看到卡片。

Oracle's documentation 提到智能卡:

jarsigner -keystore NONE -storetype PKCS11 \
    -providerName SunPKCS11-SmartCard \
    -list

但显然没有该名称的实际提供程序,并且 jarsigner 的 -list 参数似乎不存在。

我终于让 jarsigner 看到了这张卡,但它报告它不是一个有效的条目并且没有私钥:

jarsigner -keystore NONE -storetype PKCS11 \
  -providerClass sun.security.pkcs11.SunPKCS11 \
  -providerArg smartcard.config \
  -storepass notmyrealpass \
  myjarfile.jar 'Identity #0'

jarsigner: Certificate chain not found for: Identity #0.
  Identity #0 must reference a valid KeyStore key entry
  containing a private key and corresponding public key
  certificate chain.

smartcard.config 在哪里:

name=Kittens
library=/usr/lib/pkcs11/libcoolkeypk11.so

我通过在 Java 中加载卡以编程方式获得了别名列表 [“Identity #0”来自该列表]:

String conf = "name=Kittens\nlibrary=/usr/lib/pkcs11/libcoolkeypk11.so";
InputStream s = new ByteArrayInputStream(conf.getBytes());
Provider p = new sun.security.pkcs11.SunPKCS11(s);
KeyStore keyStore = KeyStore.getInstance("PKCS11", p);
keyStore.load(null, "notmyrealpass".toCharArray());
Enumeration<String> aliases = keyStore.aliases();
// Aliases contains "Identity #0", "Identity #1", "Identity #2"

这些智能卡的全部意义在于私钥保留在卡上,而卡是签名的对象;有没有办法让 jarsigner 做我想做的事?

编辑:

经过一番摸索,我注意到我似乎无法使用 SHA1withDSA,只能使用 SHA1withRSA:

Set<Provider.Service> services = p.getServices();
for(Provider.Service service : services) {
    System.out.println(service.getAlgorithm());
}

打印此列表:SHA512withRSA、SHA256withRSA、SHA1withRSA、MD5withRSA、RSA/ECB/PKCS1Padding、SHA384withRSA、MD2withRSA、RSA、PKCS11

但我注意到签名的 jar 似乎都使用 DSA;这可能是问题吗?

【问题讨论】:

  • 没有直接经验,但您是否尝试使用keytool 和pkcs#11 后端(即-providerClass-providerArg)生成密钥对+证书?
  • isKeyEntry 为您的别名返回什么?请注意,Java 仅处理附加了证书链的密钥。
  • isKeyEntry 返回真;我也可以做 keyStore.getCertificateChain(alias) 并毫无问题地取出证书链

标签: java jar cryptography smartcard jarsigner


【解决方案1】:

我将 -sigalg 添加到可用的算法 [SHA256withRSA,在这种情况下],这很有帮助。另外:

jarsigner: This jar contains entries whose certificate chain is not validated

我无意中混合了来自几个不同 JDK 的二进制文件。

所以,我使用的最后一个命令行是:

jarsigner \
    -tsa http://timestamp.digicert.com \
    -keystore NONE \
    -storetype PKCS11 \
    -providerClass sun.security.pkcs11.SunPKCS11 \
    -providerArg card_linux.config \
    -storepass `cat ~/cardpass` \
    -sigalg SHA256withRSA \
    dist/sup2rtam.jar \
    'Identity #0'

其中 ~/cardpass 是一个只包含 notmyrealpass 的文件,而 card_linux.config 是

name=CAC
library=/usr/lib/pkcs11/libcoolkeypk11.so

【讨论】:

  • 很高兴你让它工作;我不得不从头开始重新编程整个 Java 签名,因为我无法让它工作...... 15 年前。
【解决方案2】:

与@Gary B 的上述类似,除了我使用的是 OpenSC,这是我的命令:

jarsigner -tsa http://timestamp.digicert.com \
    -keystore NONE -storetype PKCS11 \
    -providerClass sun.security.pkcs11.SunPKCS11 \
    -providerArg /Library/Java/Extensions/pkcs11.cfg 
    -sigalg SHA256withRSA \
    testjni_signed.jar \
    'Certificate for Digital Signature'

我使用的卡是 PIV(也适用于 CAC)。 pkcs11.cfg 是

name = OpenSC
library = /Library/OpenSC/lib/opensc-pkcs11.dylib
description = OpenSC PKCS#11 interface for SmartCard
#showInfo = true
slot = 0

在命令行中不包括卡 PIN 会提示输入 PIN(也称为 Keystore 的密码)。

以上内容已使用 CAC 和 Yubikey NEO(PIV 配置)、JDK-1.8.0_102 和 Github mouse07410/OpenSC 进行了测试。

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 2011-01-09
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 2020-01-19
    • 2011-05-11
    相关资源
    最近更新 更多