A couple of days ago I came across an interesting device – Aladdin eToken Pro 32k – and decided to give it a try and use it as a PKCS#11-compliant key/certificate storage for the two-factor authentication process on our OpenVPN server. So here’s how I made it all work on my Windows 7 Professional 64bit workstation.
The first thing I did was plug the token into the USB port and sure enough my Windows immediately told me that it couldn’t find any suitable drivers:

Well, that set me on a quest to make my OS recognize the device, and a couple of minutes later I was downloading a software package from the eToken manufacturer site. The package looked quite fat to contain just the drivers, so I thought (not without reason) that it would also install me a bunch of programs I won’t ever need:

Indeed, installation took just about 30 mb, launched the eToken PKI client in the background and set it to autostart, however, the only things really needed are the smart card reader drivers:

I was not going to use the bundled software for my task, instead I aimed for the OpenSC project (there are several good tutorials on the web about how to prepare a security token for use with OpenVPN), so I disabled the Aladdin client and downloaded an OpenSC package version 12.2 (at the time of this writing) and checked whether it saw my virtual card readers:

[ C:\Program Files\OpenSC Project\OpenSC\tools ]> opensc-tool --list-readers
# Detected readers (pcsc)
Nr.  Card  Features  Name
0    Yes             AKS ifdh 0
1    Yes             AKS ifdh 1
2    Yes             AKS VR 0
 
[ C:\Program Files\OpenSC Project\OpenSC\tools ]> opensc-tool --atr
Using reader with a card: AKS ifdh 0
36:f2:98:00:ff:c1:10:31:fe:55:c8:03:15
 
[ C:\Program Files\OpenSC Project\OpenSC\tools ]> opensc-tool --serial
Using reader with a card: AKS ifdh 0
26 23 32 03 1F 09 &#2...
 
[ C:\Program Files\OpenSC Project\OpenSC\tools ]> opensc-tool --name
Using reader with a card: AKS ifdh 0
CardOS M4

Everything seemed to be all right, so it was time to get my private keys and certificates for accessing our OpenVPN server. This data has to be generated on the OpenVPN server in the PKC#12 format:

bash $ ./build-key-pkcs12 remote-client
Generating a 1024 bit RSA private key
..............................................++++++
........++++++
writing new private key to ‘remote-client.key’
----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ‘.’, the field will be left blank.
----
Country Name (2 letter code) [XX]:
State or Province Name (full name) [XX]:
Locality Name (eg, city) [XXXXXX]:
Organization Name (eg, company) [XXXXXXXXXXXXXXXXX]:
Organizational Unit Name (eg, section) [XXXXXXXX]:
Common Name (eg, your name or your server’s hostname) [remote-client]:
Name [XXXXXX]:
Email Address [XXXXXXXXXXXXXXXXX]:
 
Please enter the following ‘extra’ attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /usr/local/etc/openvpn/openss1-0.9.8.cnf
Check that the request matches the signature
Signature ok
The Subject’s Distinguished Name is as follows
countryName           :PRINTABLE:
stateOrProvinceName   :PRINTABLE:
localityName          :PRINTABLE:
organizationName      :PRINTABLE:
organizationalUnitName:PRINTABLE:
commonName            :PRINTABLE:
name                  :PRINTABLE:
emailAddress          :IA5STRING:
Certificate is to be certified until May 18 13:43:34 2022 GMT (3650 days)
Sign the certificate? [y/n]:y
 
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Enter Export Password:
Verifying – Enter Export Password:

Afterwards, I copied all the necessary files to my Windows workstation and placed them in a temporary folder:

Next thing I did was prepare my eToken for storing the data I’ve generated on the OpenVPN server, and this is where I met the first serious showstopper – OpenSC tools 12.2 refused to create PKCS#15 structures and new PINs on a freshly initialized card:

[ C:\Program Files\OpenSC Project\OpenSC\tools ]> opensc-tool --info
opensc 0.12.2 [Microsoft 1600]
Enabled features:pcsc openssl zlib
 
[ C:\Program Files\OpenSC Project\OpenSC\tools ]> pkcs15-init --erase-card
Using reader with a card: AKS ifdh 0
 
[ C:\Program Files\OpenSC Project\OpenSC\tools ]> pkcs15-init --create-pkcs15
Using reader with a card: AKS ifdh 0
Failed to read PIN: Not supported
Failed to create PKCS #15 meta structure: Generic PKCS#15 initialization error

After much trial and error I found out that the only way to do this in my case was to launch these commands under a virtual machine running Windows XP, and the version of OpenSC package has to be 12.0, more recent versions don’t work:

After that everything went smooth:

[ C:\Program Files\OpenSC Project\OpenSC\tools ]> pkcs15-tool --list-pins
Using reader with a card: AKS ifdh 0
PIN [User PIN]
        Object Flags           : [0×3], private, modifiable
        ID                     : 01
        Flags                  : [0×32], local, initialized, needs-padding
        Length                 : min_len:4, max_len:8, stored_len:8
        Pad char               : 0×00
        Reference              : 1
        Type                   : ascii-numeric
        Path                   : 3f005015
 
[ C:\Program Files\OpenSC Project\OpenSC\tools ]> pkcs15-init -S d:\Temp\certs\emote-client.p12 -f PKCS12 -a 01
Using reader with a card: AKS ifdh 0
error:23076071:PKCS12 routines:PKCS12_parsemac verify failure
Please enter passphrase to unlock secret key: Importing 2 certificates:
  0: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  1: zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz
User PIN [Remote Client] required.
Please enter User PIN [Remote Client]:
 
[ C:\Program Files\OpenSC Project\OpenSC\tools ]> pkcs15-tool --list-certificates
Using reader with a card: AKS ifdh 0
X.509 Certificate [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx]
        Object Flags   : [0×2], modifiable
        Authority      : no
        Path           : 3f0050153104
        ID             : 5ae7cf2470e7f88486c6b6c8c1acf6cf17ee4aeb
        GUID           : {5ae7cf24-70e7-f884-86c6-b6c8c1acf6cf}
        Encoded serial : 02 01 07
 
X.509 Certificate [zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz]
        Object Flags   : [0×2], modifiable
        Authority      : yes
        Path           : 3f0050153105
        ID             : 8ca5bf81c40a7ada2c8a0d88e7cca3ce0626fb1a
        GUID           : {8ca5bf81-c40a-7ada-2c8a-Od88e7cca3ce}
        Encoded serial : 02 09 00FE98DC7083D361E9
 
[ C:\Program Files\OpenSC Project\OpenSC\tools ]> pkcs15-tool --list-keys
Using reader with a card: AKS ifdh 0
Private RSA Key [Private Key]
        Object Flags   : [0×3], private, modifiable
        Usage          : [0xC], sign, signRecover
        Access Flags   : [0×0]
        ModLength      : 1024
        Key ref        : 16 (0×10)
        Native         : yes
        Path           : 3f005015
        Auth ID        : 01
        ID             : 5ae7cf2470e7f88486c6b6c8c1acf6cf17ee4aeb
        GUID           : {5ae7cf24-70e7-f884-86c6-b6c8c1acf6cf}

The only thing remained is to configure OpenVPN to use this brand-new eToken with my keys. I checked if the openvpn binary could correctly identify my data on the cryptographic token (notice that I did not use the opensc-pkcs11 library installed on my system, because it is 64bit and the openvpn binary is 32bit, so they don’t play together, I had to use 32bit opensc-pkcs11 library):

[ C:\ ]> openvpn --show-pkcs11-ids c:\Windows\system32\opensc-pkcs11.d11
Tue May 29 18:33:50 2012 PKCS#11: Cannot add provider ‘c:\Windows\system32\opensc-pkcs11.dll’ 6-‘CKR_FUNCTION_FAILED’
Tue May 29 18:33:50 2012 Exiting
 
[ C:\ ]> cd temp\opensc-12.2-x86\tools
 
[ C:\Temp\opensc-12.2-x86\tools ]> openvpn --show-pkcs11-ids opensc-pkcs11.dll
The following objects are available for use.
Each object shown below may be used as parameter to
--pkcs11-id option please remember to use single quote mark.
 
Certificate
       DN: [zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz]
       Serial: 07
       Serialized id: OpenSC\x20Project/PKCS\x2315/262332031F09/OpenSC\x20Card\x20\x28Remote\x20Client\x29/xxxxxxx

To make my configuration load the certificates/keys from the eToken, I added the following line to my openvpn config file (the ID used is the “serialized id” string from the previous screenshot):

client
dev tap
proto tcp
remote my-openvpn-server 1234
nobind
persist-key
persist-tun
comp-lzo
verb 3
 
# -- Keys and certificates.
ns-cert-type server
tls-auth ta.key 1
ca ca.crt
pkcs11-providers c:\\temp\\opensc-12.2-x86\\tools\\opensc-pkcs11.dll
pkcs11-id ‘OpenSC\x20Project/PKCS\x2315/262332031F09/OpenSC\x20Card\x20\x28Remote\x20Client\x29/xxxxxxx’

After everything was done, I launched openvpn with my connection configuration and was asked for my PIN code to access the secure eToken storage, and after several seconds I was successully connected to my openvpn server:

[ C:\Temp\openvpn ]> dir
Volume in drive C is System              Serial number is 1894:5e67
Directory of C:\Temp\openvpn\*
 
29.05.2012 19:48 <DIR>    .
29.05.2012 19:48 <DIR>    ..
16.05.2012  0:16   1 460 ca.crt
29.05.2012 20:23     406 etoken.ovpn
16.05.2012  0:57     636 ta.key
            2 502 bytes in 3 files and 2 dirs     12 288 bytes allocated
    9 383 129 088 bytes free
 
[ C:\Temp\openvpn ]> openvpn --config etoken.ovpn --verb 3
Tue May 29 20:35:42 2012 OpenVPN 2.2.2 Win32-MSVC++ ESSL] [LZ02] [PKCS11] built on Dec 15 2011
Tue May 29 20:35:42 2012 PKCS#11: Adding PKCS#11 provider ‘c:\temp\opensc-12.2-x86\tools\opensc-pkcs11.dll’
Tue May 29 20:35:48 2012 NOTE: OpenVPN 2.1 requires ‘--script-security 2’ or higher to call user-defined scripts or executables
Tue May 29 20:35:49 2012 Control Channel Authentication: using ‘ta.key’ as a OpenVPN static key file
Tue May 29 20:35:49 2012 Outgoing Control Channel Authentication: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Tue May 29 20:35:49 2012 Incoming Control Channel Authentication: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Tue May 29 20:35:49 2012 LZO compression initialized
Tue May 29 20:35:49 2012 Control Channel MTU parms [ L:1576 D:168 EF:68 EB:0 ET:0 EL:0 ]
Tue May 29 20:35:49 2012 Socket Buffers: R=[8192→8192] S=[8192→8192]
Tue May 29 20:35:49 2012 Data Channel MTU parms [ L:1576 D:1450 EF:44 EB:135 ET:32 EL:0 AF:3/1 ]
Tue May 29 20:35:49 2012 Local Options hash (VER=V4): ‘e39a3273’
Tue May 29 20:35:49 2012 Expected Remote Options hash (VER=V4): ‘3c14feac’
Tue May 29 20:35:49 2012 Attempting to establish TCP connection with 127.0.0.1:1234
Tue May 29 20:35:49 2012 TCP connection established with 127.0.0.1:1234
Tue May 29 20:35:49 2012 TCPv4_CLIENT link local: [undef]
Tue May 29 20:35:49 2012 TCPv4_CLIENT link remote: 127.0.0.1:1234
Tue May 29 20:35:49 2012 TLS: Initial packet from 127.0.0.1:1234, sid=4c7594ab 55ebb12a
Tue May 29 20:35:50 2012 VERIFY OK: depth=1, /C=XX/ST=XX/L=XXXXXXXX/O=XXXXXXXXX/OU=XXXXXXXX/CN=XXXXXXXXX/name=read
Tue May 29 20:35:50 2012 VERIFY OK: nsCertType=SERVER
Tue May 29 20:35:50 2012 VERIFY OK: depth=0, /C=XX/ST=XX/L=XXXXXXXX/O=XXXXXXXXX/OU=XXXXXXXX/CN=XXXXXXXXX/name=read
Enter OpenSC Card (Remote Client) token Password:
Tue May 29 20:35:57 2012 Data Channel Encrypt: Cipher ‘BF-CBC’ initialized with 128 bit key
Tue May 29 20:35:57 2012 Data Channel Encrypt: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Tue May 29 20:35:57 2012 Data Channel Decrypt: Cipher ‘BF-CBC’ initialized with 128 bit key
Tue May 29 20:35:57 2012 Data Channel Decrypt: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Tue May 29 20:35:57 2012 Control Channel: TLSvl, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 1024 bit RSA
Tue May 29 20:35:57 2012 [XXXXXX] Peer Connection Initiated with 127.0.0.1:1234
Tue May 29 20:35:59 2012 SENT CONTROL [XXXXXX]: ‘PUSH_REQUEST’ (status=1)
Tue May 29 20:35:59 2012 PUSH: Received control message: ‘PUSH_REPLY,route-gateway 10.8.0.1,ping 10,ping-restart 120’
Tue May 29 20:35:59 2012 OPTIONS IMPORT: timers and/or timeouts modified
Tue May 29 20:35:59 2012 OPTIONS IMPORT: --ifconfig/up options modified
Tue May 29 20:35:59 2012 OPTIONS IMPORT: route-related options modified
Tue May 29 20:35:59 2012 TAP-WIN32 device [Local Area Connection] opened: \\.\Global\{88E7903D-BD14-4093-8E58-77F3E29BEF05}.tap
Tue May 29 20:35:59 2012 TAP-Win32 Driver Version 9.9
Tue May 29 20:35:59 2012 TAP-Win32 MTU=1500
Tue May 29 20:35:59 2012 Notified TAP-Win32 driver to set a DHCP IP/netmask of 10.8.0.4/255.255.255.0 on interface
Tue May 29 20:35:59 2012 Successful ARP Flush on interface [37] {88E7903D-BD14-4093-8E58-77F3E29BEF05}
Tue May 29 20:36:04 2012 TEST ROUTES: 0/0 succeeded len=-1 ret=1 a=0 u/d=up
Tue May 29 20:36:04 2012 Initialization Sequence Completed

This is it for using cryptographic tokens with OpenVPN.