The OpenVPN Smartcard HOWTO

Foreword

This howto will explain how to set up OpenVPN with Smart Cards. The use of Smart Cards introduces Two-Factor Authentication to the OpenVPN setup. It all started when I was researching the use of Smart Cards with OpenVPN (having had very little knowledge about Smart Cards) and didn't find enough of documentation. The steps described in this document work for Linux and Windows since one of my initial goals was cross-platform compatibility (Mac OS X is still missing but on my TODO list). If you spot any mistakes, typos or have any suggestions on how to improve this document, feel free to send me a line.

Introduction

Proper Smart Card support has been implemented in OpenVPN in the 2.1 branch by adding PKCS#11 support (I don't consider the cryptoapicert option, since it is Windows only), so on the client you need OpenVPN 2.1 at least (you can still keep your OpenVPN 2.0 on the server). Besides OpenVPN 2.1, you'll also need OpenSC. OpenSC implements the PKCS#11 RSA standard, which specifies how to store cryptographic information on devices. On Linux you may want to use the packages your distribution of choice offers (that would be "apt-get install openct opensc pcscd" on Debian derived Distros), whereas on Windows you'll need the installer from the OpenSC Project. In this HOWTO I also presume you already have a PKI-based OpenVPN setup. The only additional requirement here is that the client has a OpenVPN from the 2.1 branch installed.

Hardware

First of all you need a supported smart card reader. You can find a list OpenSC supports (through OpenCT) here. For this document I used two readers:

An Omnikey 3121 CardMan USB Smard Card reader

An Omnikey PCMCIA 4040 Smart Card Reader

(For italian readers, I bought both of them from multimediait) Besides readers you'll also need proper writable (aka initializable) smart cards. Again, the recommended list from the OpenSC project website should guide your buying. I've bought two CryptoFlex 32k (not the e-Gate version) from the Axalto web store.

Certification Authority

I won't talk much about x.509 certificates, private keys and certification authorities. To quickly whip up a CA and make server and client certificates you can use TinyCA:

One important thing to keep in mind is that, you shouldn't create private keys with a length not supported by your smart card (check the specs to be sure). In my case the maximum length is 2048 bits, hence 4096 bit keys can't be stored on the card. The error you will get in such cases is: pkcs15-lib.c:1394:sc_pkcs15init_store_private_key: Card does not support this key. Failed to store private key: Key length/algorithm not supported by card

Card Initialization

From now on I assume that opensc has been correctly installed, and that on Windows systems the path C:\Program Files\OpenSC has been added to your PATH. I also assume you have set up your PKI, comprised of a CA, an OpenVPN Server Certificate and a couple of client certificates (preferably in PKCS#12 format).

As a first step we have to check that the card reader is correctly recognized by OpenSC:

$ opensc-tool -l
Readers known about:
Nr.    Driver     Name
0      pcsc       OmniKey CardMan 3121 00 00
1      openct     OpenCT reader (detached)
2      openct     OpenCT reader (detached)
3      openct     OpenCT reader (detached)
4      openct     OpenCT reader (detached)
5      openct     OpenCT reader (detached)

At nr. 0 we have our recognized Omnikey CardMan 3121 reader. Let's insert our smart card in the reader (note that when buying the card you'll also receive the TRANSPORT KEY. Make sure that the transport key proposed by OpenSC matches the one you got in the mail. You will destroy the card by entering the wrong Key three times):

Let's double check that the card is recongized by printing its ATR:

$ opensc-tool -r0 -a
3b:95:18:40:ff:62:04:01:01:05

We can also check the name of the card with the -n switch (we can omit the -r0 since we only have one reader connected):

$ opensc-tool -n
Cryptoflex 32K e-gate v4

At this point we know both the card and reader are fully recognized and functional, and we can proceed to erase the card: (You will be asked for the transport key you got in your mail)

$ pkcs15-init -E

Transport key (External authentication key #1) required.
Please enter key in hexadecimal notation (e.g. 00:11:22:aa:bb:cc),
or press return to accept default.

To use the default transport keys without being prompted,
specify the --use-default-transport-keys option on the
command line (or -T for short), or press Ctrl-C to abort.
Please enter key [2c:15:e5:26:e9:3e:8a:19]:

Now we Initialize the card and we format it the PKCS#15 way. We will be prompted for Security Officer PIN, User Unblocking PIN (PUK) and Transport Key:

$ pkcs15-init --create-pkcs15
Please enter Security Officer PIN:
Please type again to verify:
Unblock Code for New User PIN (Optional - press return for no PIN).
Please enter User unblocking PIN (PUK):
Please type again to verify:
Transport key (External authentication key #1) required.
Please enter key in hexadecimal notation (e.g. 00:11:22:aa:bb:cc),
or press return to accept default.

To use the default transport keys without being prompted,
specify the --use-default-transport-keys option on the
command line (or -T for short), or press Ctrl-C to abort.
Please enter key [2c:15:e5:26:e9:3e:8a:19]:

Storing the private key on the card

Now we'll add a PIN for the label "Michele Baldessari" and we'll associate the 01 auth id to it. We'll be prompted for the Security Officer Pin inserted one step above :

$ pkcs15-init --store-pin --auth-id 01 --label "Michele Baldessari"
New User PIN.
Please enter User PIN:
Please type again to verify:
Unblock Code for New User PIN (Optional - press return for no PIN).
Please enter User unblocking PIN (PUK):
Please type again to verify:
Security officer PIN required.
Please enter Security officer PIN:
Transport key (External authentication key #1) required.
Please enter key in hexadecimal notation (e.g. 00:11:22:aa:bb:cc),
or press return to accept default.

To use the default transport keys without being prompted,
specify the --use-default-transport-keys option on the
command line (or -T for short), or press Ctrl-C to abort.
Please enter key [2c:15:e5:26:e9:3e:8a:19]:

Now we can check the PINs stored on the card:

$ pkcs15-tool --list-pins
PIN [Security Officer PIN]
        Com. Flags: 0x3
        ID        : ff
        Flags     : [0xB2], local, initialized, needs-padding, soPin
        Length    : min_len:6, max_len:8, stored_len:8
        Pad char  : 0x00
        Reference : 2
        Type      : ascii-numeric
        Path      : 3f005015

PIN [Michele Baldessari]
        Com. Flags: 0x3
        ID        : 01
        Flags     : [0x32], local, initialized, needs-padding
        Length    : min_len:4, max_len:8, stored_len:8
        Pad char  : 0x00
        Reference : 1
        Type      : ascii-numeric
        Path      : 3f0050154b01

Now we'll store the client Certificate (stored in a PKCS#12 file name client-cert.p12) on the card and we associate it to auth-id 01, which we just created:

$ pkcs15-init -S client-cert.p12 -f PKCS12 -a 01
error:23076071:PKCS12 routines:PKCS12_parse:mac verify failure
Please enter passphrase to unlock secret key:
Importing 2 certificates:
  0: /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=Michele/emailAddress=michele@pupazzo.org
  1: /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=CA VPN/emailAddress=ca@pupazzo.org
Security officer PIN required.
Please enter Security officer PIN:
User PIN required.
Please enter User PIN:
Security officer PIN required.
Please enter Security officer PIN:

(We're asked for the PKCS#12 private key password, the Security Officer Pin and the User pin)

At this point we're set and the key is on the smartcard protected with a user pin from reading and with a security officer pin from writing.

You can double-check the certificates on the smart card with:

$ pkcs15-tool -c
X.509 Certificate [/C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=Michele/emailAddress=michele@pupazzo.org]
        Flags    : 2
        Authority: no
        Path     : 3f0050154545
        ID       : 45

X.509 Certificate [/C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=CA VPN/emailAddress=ca@pupazzo.org]
        Flags    : 2
        Authority: yes
        Path     : 3f0050154546
        ID       : 46

And the keys with:

$ pkcs15-tool -k
Private RSA Key [Private Key]
        Com. Flags  : 3
        Usage       : [0x2C], sign, signRecover, unwrap
        Access Flags: [0x1D], sensitive, alwaysSensitive, neverExtract, local
        ModLength   : 2048
        Key ref     : 0
        Native      : yes
        Path        : 3f0050154b0130450012
        Auth ID     : 01
        ID          : 45

OpenVPN Configuration

Install OpenVPN 2.1 (rc2 is the latest as of this writing) and check that the PKCS#11 slots (i.e. the card readers) are correctly identified (on Windows use openvpn.exe --show-pkcs11-slots "C:\Program Files\scb\opensc-pkcs11.dll"):

$ /usr/sbin/openvpn  --show-pkcs11-slots /usr/lib/opensc-pkcs11.so
Provider Information:
        cryptokiVersion:        2.11
        manufacturerID:         OpenSC Project (www.opensc-proje
        flags:                  0

The following slots are available for use with this provider.
Each slot shown below may be used as a parameter to a
--pkcs11-slot-type and --pkcs11-slot options.

Slots: (id - name)
        0 - OmniKey CardMan 3121 00 00
        1 - OmniKey CardMan 3121 00 00
        2 - OmniKey CardMan 3121 00 00
        3 - OmniKey CardMan 3121 00 00
        4 - OpenCT reader (detached)
        5 - OpenCT reader (detached)
        6 - OpenCT reader (detached)
        7 - OpenCT reader (detached)

You can also check that OpenVPN sees all the objects on the card (you'll be asked for your user PIN):

$ /usr/sbin/openvpn  --show-pkcs11-objects /usr/lib/opensc-pkcs11.so  0
PIN:
Token Information:
        label:          OpenSC Card (Michele Baldessari)
        manufacturerID: OpenSC Project
        model:          PKCS #15 SCard
        serialNumber:   0001079DFFFF0200
        flags:          0000040d

You can access this token using
--pkcs11-slot-type "label" --pkcs11-slot "OpenSC Card (Michele Baldessari)" options.

The following objects are available for use with this token.
Each object shown below may be used as a parameter to
--pkcs11-id-type and --pkcs11-id options.

Object
        Type:                   Private Key
        CKA_ID:
                45
        CKA_LABEL:              Private Key
        CKA_SIGN:               TRUE
        CKA_SIGN_RECOVER:       TRUE
Object
        Type:                   Certificate
        CKA_ID:
                45
        CKA_LABEL:              /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=Michele/emailAddress=michele@pupazzo.org 
        subject:                /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=Michele/emailAddress=michele@pupazzo.org
        serialNumber:           04
        notBefore:              070319141643Z
Object
        Type:                   Public Key
        CKA_ID:
                45
        CKA_LABEL:              /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=Michele/emailAddress=michele@pupazzo.org
Object
        Type:                   Certificate
        CKA_ID:
                00
        CKA_LABEL:              /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=CA VPN/emailAddress=ca@pupazzo.org
        subject:                /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=CA VPN/emailAddress=ca@pupazzo.org
        serialNumber:           BA1FB321B0503708
        notBefore:              070306120229Z
Object
        Type:                   Public Key
        CKA_ID:
                46
        CKA_LABEL:             /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=CA VPN/emailAddress=ca@pupazzo.org

The above is useful because it will help you know which label or id are on the card. You'll need to know which key ID to use when starting the authentication.

At this point a configuration file like the following will do. Note the statements beginning with pkcs11- and adapt them to your configuration:

pull
nobind
dev tap
remote 1.2.3.4
tls-client
port 1194
comp-lzo
key-method 2
verb 2
keepalive 10 120
persist-key
persist-tun
ns-cert-type server
ca /etc/ssl/myca.pem
pkcs11-providers  /usr/lib/opensc-pkcs11.so
pkcs11-slot-type label
pkcs11-slot "OpenSC Card (Michele Baldessari)"
pkcs11-id-type subject
pkcs11-id "/C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=Michele/emailAddress=michele@pupazzo.org

Running OpenVPN

If you've made it so far, you are now ready to start OpenVPN with your smart card inserted (you'll be prompted for your User PIN):

$ openvpn --config testconf.ovpn
Sat Apr  7 20:45:20 2007 LZO compression initialized
Sat Apr  7 20:45:20 2007 Control Channel MTU parms [ L:1574 D:138 EF:38 EB:0 ET:0 EL:0 ]
Sat Apr  7 20:45:20 2007 Data Channel MTU parms [ L:1574 D:1450 EF:42 EB:135 ET:32 EL:0 AF:3/1 ]
Sat Apr  7 20:45:20 2007 Local Options hash (VER=V4): 'd79ca330'
Sat Apr  7 20:45:20 2007 Expected Remote Options hash (VER=V4): 'f7df56b8'
Sat Apr  7 20:45:20 2007 Socket Buffers: R=[109568->131072] S=[109568->131072]
Sat Apr  7 20:45:20 2007 UDPv4 link local: [undef]
Sat Apr  7 20:45:20 2007 UDPv4 link remote: 1.2.3.4:1194
Sat Apr  7 20:45:20 2007 TLS: Initial packet from 1.2.3.4:1194, sid=59ebbe71 c0f847e7
Sat Apr  7 20:45:21 2007 VERIFY OK: depth=1, /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=CA VPN/emailAddress=michele@pupazzo.org
Sat Apr  7 20:45:21 2007 VERIFY OK: nsCertType=SERVER
Sat Apr  7 20:45:21 2007 VERIFY OK: depth=0, /C=IT/ST=Bozen/L=Sterzing/O=Foo/CN=vpn.foo.bar/emailAddress=michele@pupazzo.org
Enter OpenSC Card (Michele Baldessari) token Password:
Sat Apr  7 20:45:28 2007 Data Channel Encrypt: Cipher 'BF-CBC' initialized with 128 bit key
Sat Apr  7 20:45:28 2007 Data Channel Encrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Sat Apr  7 20:45:28 2007 Data Channel Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
Sat Apr  7 20:45:28 2007 Data Channel Decrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
Sat Apr  7 20:45:28 2007 Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 4096 bit RSA
Sat Apr  7 20:45:28 2007 [vpn.foo.bar] Peer Connection Initiated with 1.2.3.4:1194
Sat Apr  7 20:45:29 2007 SENT CONTROL [vpn.foo.bar]: 'PUSH_REQUEST' (status=1)
Sat Apr  7 20:45:29 2007 TUN/TAP device tap0 opened
Sat Apr  7 20:45:29 2007 TUN/TAP TX queue length set to 100
Sat Apr  7 20:45:29 2007 /sbin/ifconfig tap0 172.16.254.5 netmask 255.255.255.0 mtu 1500 broadcast 172.16.254.255
Sat Apr  7 20:45:29 2007 /sbin/route add -net 192.168.1.0 netmask 255.255.255.0 gw 172.16.254.1
Sat Apr  7 20:45:29 2007 Initialization Sequence Completed

Your VPN connection worked ;)

TODO
  • Test Mac OSX setup
  • Test with current GUI's


07 April 2007