Module Signing with a YubiKey Neo

I tackled this topic in the past few days because I’ve been unhappy with having my code signing private key exposed regularly on my development workstation. Yes, I might be paranoid, but why beg for trouble?
Anyways, I kept a log of the necessary steps, and thought I’d document them publicly.
[ol][li]Buy a smartcard and interface, or dongle that emulates one. It must be able to hold an RSA key pair, and be supported by the OpenSC project. There may be other tools that make this work, but this is the path recommended for the YubiKey Neo that I have kicking around.[/li]
[li]Buy an appropriate Java code signing certificate, suitable for use with Ignition’s code signing tool. I bought mine from DigiCert. Many other providers are available. The following could be adapted to a self-signed certificate, but if you are comfortable doing that, you should be comfortable modifying these instructions.[/li]
[li]Extract your private key from your keystore. All of the instructions I’ve seen for setting up java code signing for Java start with creating a key pair and certificate signing request in a new keystore. However, Java’s keytool does not provide any means to export the private key. This needs to be in a format acceptable to your smartcard’s management tool, typically PEM. With a bit of research, and inspiration from Dr. Herong Yang, I scripted the following:[code]import sys

if len(sys.argv)<5:
print “”“Usage:
%s keystore storepass alias aliaspass”"" % sys.argv[0]

from import FileInputStream
from import KeyStore
from java.util import Base64

ks = KeyStore.getInstance(“jks”)
ks.load(FileInputStream(sys.argv[1]), sys.argv[2]);
key = ks.getKey(sys.argv[3], sys.argv[4]);

print “-----BEGIN %s PRIVATE KEY-----” % key.algorithm
print Base64.getMimeEncoder().encodeToString(key.encoded)
print “-----END %s PRIVATE KEY-----” % key.algorithm[/code]I saved the output of mine to autopros-code-signer.key. Be sure to thoroughly destroy this file when you’re done with it, as this format is completely unprotected.[/li]
[li]Extract your certificate from your certificate chain, unless your smartcard can hold the entire chain. Mine cannot. OpenSSL can read the PKCS7 file you received from your certificate authority and print out the PEM format certificates within it.[code]$ openssl pkcs7 -in automation_professionals_llc.p7b -print_certs
subject=/C=US/ST=Georgia/L=Fairburn/O=Automation Professionals, LLC/CN=Automation Professionals, LLC
issuer=/C=US/O=DigiCert Inc/ SHA2 Assured ID Code Signing CA
… trimmed …

… trimmed the rest of the certificate chain …[/code]You only want to extract the certificate that has you as the subject, and only the lines from “-----BEGIN CERTIFICATE-----” to “-----END CERTIFICATE-----”. I cut and pasted mine into a file named autopros-code-signer.pem.[/li]
[li]Install smartcard software. For me, that was yubikey-neo-manager, opensc, and ykpersonalize. I use Gentoo Linux, so installations instructions wouldn’t be much use (and are likely to vary). But it seems these are all easily installed on typical Windows and Linux platforms. The Yubikey PIV Manager application can do much of the following in a GUI.[/li]
[li]Configure your smartcard/dongle for certificate mode, if needed. For the YubiKey Neo, it comes out of the box configured in One-Time-Password mode, with an info report like so:$ ykinfo -a serial: 3647291 serial_hex: 37a73b serial_modhex: eilien version: 3.4.3 touch_level: 1797 programming_sequence: 1 slot1_status: 1 slot2_status: 0 vendor_id: 1050 product_id: 114. It needs to be in “CCID” mode. I chose the CCID-only mode, which is a one-way conversion for the standard tool:[code]$ ykpersonalize -m1
Firmware version 3.4.3 Touch level 1797 Program sequence 1

The USB mode will be set to: 0x1

Commit? (y/n) [n]: y
WARNING: This tool will not be able to switch back from the selected mode, really commit? (y/n) [n]: y
[/code]After removing and re-inserting, the mode change takes effect. Empty, you see:[code]$ pkcs11-tool -L
Available slots:
Slot 0 (0x0): Yubico Yubikey NEO CCID 00 00
token label : PIV_II (PIV Card Holder pin)
token manufacturer : piv_II
token model : PKCS#15 emulated
token flags : rng, login required, PIN initialized, token initialized
hardware version : 0.0
firmware version : 0.0
serial num : 00000000

$ yubico-piv-tool -a status
CHUID: No data available
CCC: No data available
PIN tries left: 3[/code][/li][li]Install your key and certificate with the vendor-specific tools and verify:[code]$ yubico-piv-tool -s 9a -a import-key -i autopros-code-signer.key
Successfully imported a new private key.

$ yubico-piv-tool -s 9a -a import-certificate -i autopros-code-signer.pem
Successfully imported a new certificate.

$ yubico-piv-tool -a status
CHUID: No data available
CCC: No data available
Slot 9a:
Algorithm: RSA2048
Subject DN: C=US, ST=Georgia, L=Fairburn, O=Automation Professionals, LLC, CN=Automation Professionals, LLC
Issuer DN: C=US, O=DigiCert Inc,, CN=DigiCert SHA2 Assured ID Code Signing CA
Fingerprint: 3c2ef8bbb52cf79408b170c558652be21c22b250b92dbcbe70a604a74a155466
Not Before: Apr 12 00:00:00 2016 GMT
Not After: Apr 17 12:00:00 2018 GMT
PIN tries left: 3[/code]This would be the appropriate point to change your smartcard’s PIN, too. :slight_smile:[/li]
[li]Create an OpenSC configuration for Java to use with your smartcard. Place it in your workspace along with your PKCS7 file from your Certificate Authority. Then you can use Java’s keytool to verify that you can access the key in your smartcard:[code]$ cat pkcs11.cfg
name = OpenSC
library = /usr/lib64/
description = OpenSC PKCS11 Provider

$ keytool -keystore NONE -storetype PKCS11 -providerClass -providerArg pkcs11.cfg -list
Enter keystore password: {pin}

Keystore type: PKCS11
Keystore provider: SunPKCS11-OpenSC

Your keystore contains 1 entry

Certificate for PIV Authentication, PrivateKeyEntry,
Certificate fingerprint (SHA1): 0C:3A:3D:8E:10:3A:F9:F7:90:DE:CF:EF:71:70:90:C8:DC:97:54:E7[/code]Note the alias your smartcard assigned to your key. For YubiKeys under OpenSC, slot 9a is given alias “Certificate for PIV Authentication”. You need to supply this to the module signing tool, as shown below.[/li]
[li]Configure your module project to call the module signer tool with the “-pkcs11-cfg=” parameter instead of the “-keystore=” parameter, and give it the name of your OpenSC configuration file. Use the alias your smartcard shows instead of your original keystore’s alias. Supply the smartcard’s pin as both the keystore password and the alias password. I still use the Ant build system, so I call the module signer with this script:[code]

[/code][/li][/ol]I currently have a local patch in my module-signer project that adds this pkcs11 mode of operation, but you can expect to see it in the public project soon. :slight_smile:

Phil’s patch has been merged into the module signing util :thumb_left: