2

I'm using a PKCS11 smartcard at work, and would like to use jarsigner to sign jar files using the certificate on my card.

I'm mostly working on Linux. Coolkey can see the card.

Oracle's documentation mentions smartcards:

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

But there's apparently no actual provider by that name, and the -list argument to jarsigner doesn't appear to exist.

I finally got jarsigner to see the card, but it reports that it isn't a valid entry and doesn't have a private key:

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.

Where smartcard.config is:

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

I got the list of aliases [from which "Identity #0" comes] programmatically by loading the card in Java:

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"

The whole point of these smartcards is that the private key stays on the card, and the card is what does the signing; is there no way to make jarsigner do what I want?

EDIT:

After some more noodling, I noticed that I don't seem to be able to use SHA1withDSA, only SHA1withRSA:

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

prints this list: SHA512withRSA, SHA256withRSA, SHA1withRSA, MD5withRSA, RSA/ECB/PKCS1Padding, SHA384withRSA, MD2withRSA, RSA, PKCS11

But I notice that signed jars all seem to use DSA; is this likely to be the issue?

Gary B
  • 523
  • 4
  • 15
  • Have no direct experience, but did you try to generate the keypair+certificate using the `keytool` with the pkcs#11 backend (i.e. with `-providerClass` and `-providerArg`)? – vlp Sep 24 '15 at 22:36
  • What does [`isKeyEntry`](http://docs.oracle.com/javase/7/docs/api/java/security/KeyStore.html#isKeyEntry(java.lang.String)) return for your aliases? Note that Java only handles keys that have certificate chains attached to them. – Maarten Bodewes Sep 24 '15 at 23:10
  • isKeyEntry returns true; I can also do keyStore.getCertificateChain(alias) and get the certificate chain out without issue – Gary B Sep 25 '15 at 00:27

2 Answers2

3

I added -sigalg to an algortihm that was available [SHA256withRSA, in this case], and that helped. Also:

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

I was mixing binaries from a couple different JDKs by accident.

So, the final command line I'm using is:

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'

Where ~/cardpass is a file containing nothing but notmyrealpass, and card_linux.config is

name=CAC
library=/usr/lib/pkcs11/libcoolkeypk11.so
Community
  • 1
  • 1
Gary B
  • 523
  • 4
  • 15
  • Glad you got it to work; I had to reprogram the entire Java signing from scratch because I could not get it to work...15 years ago. – Maarten Bodewes Sep 29 '15 at 00:35
1

Similar to the above by @Gary B, except that I'm using OpenSC, and here's my command:

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'

The card I use is PIV (works for CAC too). pkcs11.cfg is

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

Not including the card PIN in the command line makes it prompt for the PIN (aka Passphrase for Keystore).

The above has been tested with CAC and Yubikey NEO (in PIV configuration), JDK-1.8.0_102, and Github mouse07410/OpenSC.

Mouse
  • 542
  • 6
  • 9