OpenSSL CA with Yubikey Neo
My notes to setup an OpenSSL Certificate Authority with CA private key stored on the Yubikey Neo with PIV applet
I'm currently looking for a way to use the Yubikey Neo as a smart card to store the private key of a Certificate Authority which can then subsequently be used to sign certificate requests. The CA is based on OpenSSL and therefore the Neo should integrate with OpenSSL as neatly as possible.
All the information you find here is already out there on the web, I just decided to put everything together in this post to avoid searching for bits and pieces of the solution.
Assumptions
You already have an OpenSSL based certification authority in place for which you have previously generated a certificate and key pair. The CA's certificate and key pair is available in the form of a p12 container. Alternatively you could also choose the route of generating the private key directly on the Neo and then creating the CA certificate form there. Although this is a 'more secure' approach from security point of view it's not recommendable for this specific use case since you might want to recover or duplicate your private key in case the Yubikey Neo dies on you. This is only possible if you generate the private key outside of the Yubikey and then import it later on.
You have a Yubikey Neo with the PIV applet preloaded at your disposal
Configuring Yubikey Neo for smart card (CCID) interface support
Recently yubico released a gui application called neo-manager allowing you to configure the neo. The current version (0.1.0) can be downloaded from here .
For common use it is recommended to configure the Yubikey Neo to use the HID + CCID with touch eject mode. This allows the Neo to act as a smart card (CCID) and OTP simultaneously. It does so by acting as a smart card whenever it is connected to a system, unless the button is pushed. In this case it will eject the smartcard, act as a regular yubikey OTP and after that insert the smartcard again.
For our specific purpose we could configure Neo to act only as a smart card (CCID) because we don't want to use our yubikey for anything other then (securely) storing the Certification Authority private key.
Getting our system to see neo as a smartcard
With the yubikey neo configured to act as a CCID device we need to get our system to interface with it. In my setup I will be using an Ubuntu Server 14.04 64bit system running inside of a VMWare Fusion virtual machine (USB 2.0 compatibility) for testing purposes, the steps required to get this to work on other Linux or OS X systems should be fairly similar.
We start by installing the opensc package on our system which contains the tools and drivers we need to get our yubikey piv up and running.
dennisverslegers@ubuntu:~$ apt-get install opensc
Now let's test if we can access our yubikey neo using opensc:
dennisverslegers@ubuntu:~$ opensc-tool -l
# Detected readers (pcsc)
Nr. Card Features Name
0 Yes Yubico Yubikey NEO CCID 00 00
Assuming everything went well you should see the Yubikey Neo listed as a detected card reader. Check your version of opensc if this is not the case, we are running version 0.13
dennisverslegers@ubuntu:~$ opensc-tool -i
opensc 0.13.0 [gcc 4.8.2]
Enabled features: zlib readline openssl pcsc(libpcsclite.so.1)
Before we continue we should make sure that the Yubikey is not only detected as a reader but also as a smart card:
dennisverslegers@ubuntu:~$ opensc-tool --reader 0 --name
PIV-II card
We should now be able to list the contents of the PIV applet which should be, for the time being, empty.
dennisverslegers@ubuntu:~$ pkcs15-tool --list-data-objects
Using reader with a card: Yubico Yubikey NEO CCID 00 00
Data object 'Card Capability Container'
applicationName: Card Capability Container
applicationOID: 2.16.840.1.101.3.7.1.219.0
Path: db00
Data object read failed: File not found
Data object 'Card Holder Unique Identifier'
applicationName: Card Holder Unique Identifier
applicationOID: 2.16.840.1.101.3.7.2.48.0
Path: 3000
Data (61 bytes): 3B3019D4E739DA7...
Data object 'Unsigned Card Holder Unique Identifier'
applicationName: Unsigned Card Holder Unique Identifier
applicationOID: 2.16.840.1.101.3.7.2.48.2
Path: 3010
Data object read failed: File not found
Data object 'X.509 Certificate for PIV Authentication'
applicationName: X.509 Certificate for PIV Authentication
applicationOID: 2.16.840.1.101.3.7.2.1.1
Path: 0101
Data object read failed: File not found
Data object 'Cardholder Fingerprints'
applicationName: Cardholder Fingerprints
applicationOID: 2.16.840.1.101.3.7.2.96.16
Path: 6010
Auth ID: 01
Data object 'Printed Information'
applicationName: Printed Information
applicationOID: 2.16.840.1.101.3.7.2.48.1
Path: 3001
Auth ID: 01
Data object 'Cardholder Facial Image'
applicationName: Cardholder Facial Image
applicationOID: 2.16.840.1.101.3.7.2.96.48
Path: 6030
Auth ID: 01
Data object 'X.509 Certificate for Digital Signature'
applicationName: X.509 Certificate for Digital Signature
applicationOID: 2.16.840.1.101.3.7.2.1.0
Path: 0100
Data object read failed: File not found
Data object 'X.509 Certificate for Key Management'
applicationName: X.509 Certificate for Key Management
applicationOID: 2.16.840.1.101.3.7.2.1.2
Path: 0102
Data object read failed: File not found
Data object 'X.509 Certificate for Card Authentication'
applicationName: X.509 Certificate for Card Authentication
applicationOID: 2.16.840.1.101.3.7.2.5.0
Path: 0500
Data object read failed: File not found
Data object 'Security Object'
applicationName: Security Object
applicationOID: 2.16.840.1.101.3.7.2.144.0
Path: 9000
Data object read failed: File not found
Data object 'Discovery Object'
applicationName: Discovery Object
applicationOID: 2.16.840.1.101.3.7.2.96.80
Path: 6050
Data (20 bytes): 7E124F0BA0000003080000100001005F2F024000
Data object 'Cardholder Iris Image'
applicationName: Cardholder Iris Image
applicationOID: 2.16.840.1.101.3.7.2.16.21
Path: 1015
Data object read failed: File not found
The lines containing Data object read failed: File not found indicate that there is currently no data loaded onto the PIV applet. Let's change that by loading a CA certificate and private key.
Importing the CA certificate and private key onto the Yubikey Neo
In order to load the p12 containing the certificate and private key onto to the Yubikey Neo we need to install the yubico-piv-tool from here
Let's install the packages we need to compile the yubico-piv-tool in case they would not yet be present on our system:
dennisverslegers@ubuntu:~$ sudo apt-get install gcc autoconf libssl-dev make pcscd libccid libpcsclite-dev
With those in place we can continue to download and compile the yubico-piv-tool:
dennisverslegers@ubuntu:~$ cd /tmp
dennisverslegers@ubuntu:/tmp$ wget http://opensource.yubico.com/yubico-piv-tool/releases/yubico-piv-tool-0.0.2.tar.gz
dennisverslegers@ubuntu:/tmp$ tar -vxzf yubico-piv-tool-0.0.2.tar.gz
dennisverslegers@ubuntu:/tmp$ cd yubico-piv-tool-0.0.2
dennisverslegers@ubuntu:/tmp/yubico-piv-tool-0.0.2$ ./configure
dennisverslegers@ubuntu:/tmp/yubico-piv-tool-0.0.2$ make
dennisverslegers@ubuntu:/tmp/yubico-piv-tool-0.0.2$ sudo make install
Now we should be able to import our p12 container containing both the certificate and private key onto the yubikey. The yubico-piv-tool indicates that the yubikey piv applet has four distinct key slots.
-s, --slot=ENUM What key slot to operate on (possible values="9a",
"9c", "9d", "9e")
9a is for PIV Authentication
9c is for Digital Signature (PIN always checked)
9d is for Key Management
9e is for Card Authentication (PIN never checked)
In our case we only want to load the CA certificate onto the yubikey neo which will be used for digital signatures (of other certificates). Therefore we instruct the piv-tool to load the private key in slot 9c.
dennisverslegers@ubuntu:~$ yubico-piv-tool -s 9c -i Documents/project1ca.p12 -K PKCS12 -p demo -a import-key -a import-cert
Successfully imported a new private key.
Successfully imported a new certificate.
You can verify the successful import by issuing the pkcs15-tool list data objects command again.
dennisverslegers@ubuntu:~$ pkcs15-tool --list-data-objects
Using reader with a card: Yubico Yubikey NEO CCID 00 00
...
Data object 'X.509 Certificate for Digital Signature'
applicationName: X.509 Certificate for Digital Signature
applicationOID: 2.16.840.1.101.3.7.2.1.0
Path: 0100
Data (1159 bytes): 53820483
...
As you can see the Data section for X.509 Certificate for Digital Signature now indicates that data is present in this slot.With this in place we can now continue and configure openssl to use the CA certificate present on the Neo for signing of future certificate requests.
Configuring OpenSSL CA to access the CA private key located on the yubikey Neo
Before we can continue we need to determine the key ID of the CA private key on the piv applet for future use by OpenSSL.
dennisverslegers@ubuntu:~$ pkcs15-tool --list-keys
Using reader with a card: Yubico Yubikey NEO CCID 00 00
Private RSA Key [SIGN key]
Object Flags : [0x1], private
Usage : [0x20E], decrypt, sign, signRecover, nonRepudiation
Access Flags : [0x1D], sensitive, alwaysSensitive, neverExtract, local
ModLength : 2048
Key ref : 156 (0x9C)
Native : yes
Auth ID : 01
ID : 02
GUID : 024fc9a7cd8f541ecad4e39ab21a95a5
The ID of our private key located on the Neo is indicated by the ID field, in this case 02. Take a note of this somewhere for future use.
Now let's continue by installing the pkcs11 OpenSSL library:
dennisverslegers@ubuntu:~$ sudo apt-get install libengine-pkcs11-openssl
To configure OpenSSL to use the PKCS11 engine you can issue the following command from the OpenSSL prompt:
OpenSSL> engine dynamic -pre SO_PATH:/usr/lib/engines/engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:opensc-pkcs11.so
(dynamic) Dynamic engine loading support
Success: SO_PATH:/usr/lib/engines/engine_pkcs11.so
Success: ID:pkcs11
Success: LIST_ADD:1
Success: LOAD
Success: MODULE_PATH:opensc-pkcs11.so
Loaded: (pkcs11) pkcs11 engine
Note For Mac OS X the following command should be used to load the PKCS11 engine:
engine dynamic -pre SO_PATH:/Library/OpenSC/lib/engines/engine_pkcs11.so -pre ID:pkcs11 -pre LIST_ADD:1 -pre LOAD -pre MODULE_PATH:/usr/lib/opensc-pkcs11.so
We can also configure OpenSSL to load the PKCS11 engine automatically at startup my modifying the openssl configuration file like so:
openssl_conf = openssl_def
[openssl_def]
engines = engine_section
[engine_section]
pkcs11 = pkcs11_section
[pkcs11_section]
engine_id = pkcs11
dynamic_path = /usr/lib/engines/engine_pkcs11.so
MODULE_PATH = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
init = 0
Additionally you can add a pin entry in the pkcs11_section of the openssl configuration file to add the pin code to be used when accessing the smart card(s).
With everything in place you should be able to issue the following command to sign a certificate request using the private key located on the smartcard:
dennisverslegers@ubuntu:~/Documents/demo_pki_root$ openssl ca -engine pkcs11 -keyfile 01:02 -keyform e -config ./openssl.cnf -name Project1CA -out demo_user.crt -infiles .demo_user.csr
Using configuration from ./openssl.cnf
engine "pkcs11" set.
PKCS#11 token PIN:
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number: 5 (0x5)
Validity
Not Before: Apr 28 13:28:30 2014 GMT
Not After : Apr 28 13:28:30 2015 GMT
Subject:
countryName = BE
stateOrProvinceName = Vlaams-Brabant
localityName = Leuven
organizationName = AUSY
organizationName = not used
organizationalUnitName = Demo CA project
commonName = demo_user
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
Netscape Cert Type:
SSL Client, S/MIME
Netscape Comment:
OpenSSL Generated Client Certificate
X509v3 Subject Key Identifier:
2B:7C:DE:9E:B7:20:51:4E:60:4C:AD:F8:10:AF:97:2A:1D:6B:45:0D
X509v3 Authority Key Identifier:
keyid:CE:9B:8C:9B:C8:59:66:42:49:1A:B4:F8:35:1B:9D:7F:D4:BC:90:75
DirName:/C=BE/ST=Vlaams-Brabant/L=Leuven/O=AUSY/O=not used/OU=Demo CA project/CN=RootCA
serial:01
Certificate is to be certified until Apr 28 13:28:30 2015 GMT (365 days)
Sign the certificate? [y/n]:
Some interesting things to know:
- default pin: 123456
- default unblock pin: 12345678
- default admin key (3des key): 010203040506070801020304050607080102030405060708
Needless to say it is recommended to say that changing the pin codes is absolutely mandatory. This can be done using the yubico-piv-tool.
... Regularly reinventing a slightly different wheel ...