First Steps with the Feitian ePass2003 Smart Token in OS X [updated]
This post has been updated for Yosemite and now mentions bugs in Apple's version of ssh-add
. Thanks to Fredrik Pettai for letting me know.
I don't feel at ease with private keys and other sensitive files floating around on multiple machines and backups. They are of course encrypted, but not accounted for, so it is impossible to "take them back" if ever something goes wrong with a passphrase.
Smart tokens are an attractive solution, because they combine something you know (the PIN) with something you have in the actual, physical sense. Sensitive files are still mobile, but bound to the token.
However, smart tokens are still not mainstream. The software functionality is distributed over several open source projects, which makes it necessary to assemble scattered documentation to see the big picture.
After crawling outdated forum posts on GOOZE and sourcing hardware from an obscure Hungarian web shop (with good service!), I did get token based authentication running with fewer obstacles than I expected. Once you know where to look, it's actually quite simple.
So here is a mini guide to manage SSH private keys with the Feitian ePass2003 in Mavericks and Yosemite.
Hardware
As I travel a lot, I prefer a compact smart token over a full size smart card and reader combo. The Feitian ePass2003 is a fairly recent product which implements 2048 bit RSA, 256 bit AES and SHA-256 (also DES :-), can generate keys using its own RNG and has 64 KB of storage for keys and certificates.
Software
Three pieces of software are necessary to get the token working: opensc
, libusb
and libccid
. The first two are available from Homebrew. Yosemite ships with a version of libccid
that is recent enough to detect the ePass2003. The version shipped with Mavericks is too old, so I used to build the library from source:
cd ccid-1.4.18
./MacOSX/configure
make
sudo make install
Once the three libraries are in place, the token should be recognized
$ opensc-tool -l
# Detected readers (pcsc)
Nr. Card Features Name
0 Yes Feitian ePass2003 00 00
Erasing and Formatting the Card
The ePass 2003 contains a proprietary filesystem that needs to be erased first using
pkcs15-init --erase-card
Then create a PKCS#15 compliant file system and set a password
pkcs15-init --create-pkcs15 --profile pkcs15+onepin --label "christian@sigg-iten.ch"
After a successful initialization, the following objects are present on the card
$ pkcs15-tool --dump
Using reader with a card: Feitian ePass2003 00 00
PKCS#15 Card [christian@sigg-iten.ch]:
Version : 0
Serial number : XXXXXXXXXXXXXXXX
Manufacturer ID: EnterSafe
Last update : 20141106080452Z
Flags : EID compliant
PIN [User PIN]
Object Flags : [0x3], private, modifiable
ID : 01
Flags : [0x32], local, initialized, needs-padding
Length : min_len:4, max_len:16, stored_len:16
Pad char : 0x00
Reference : 1 (0x01)
Type : ascii-numeric
Path : 3f005015
Key Generation and Storage
The ePass2003 can generate keys using its own RNG
pkcs15-init --generate-key rsa/2048 --key-usage sign,decrypt --auth-id 01 --label "christian@sigg-iten.ch"
where the authentication ID refers to the PIN ID. This way the private key never exists outside the token. Generating the key pair on a trusted computer instead is more transparent and makes it possible to backup the private key. Once generated (e.g. using ssh-keygen
), the keypair is copied to the token using
pkcs15-init --store-private-key ~/.ssh/id_rsa --auth-id 01 --key-usage sign,decrypt --label "christian@sigg-iten.ch"
Another dump shows the public and private key pair stored on the token
$ pkcs15-tool --dump
Using reader with a card: Feitian ePass2003 00 00
PKCS#15 Card [christian@sigg-iten.ch]:
Version : 0
Serial number : XXXXXXXXXXXXXXXX
Manufacturer ID: EnterSafe
Last update : 20141106080643Z
Flags : EID compliant
PIN [User PIN]
Object Flags : [0x3], private, modifiable
ID : 01
Flags : [0x32], local, initialized, needs-padding
Length : min_len:4, max_len:16, stored_len:16
Pad char : 0x00
Reference : 1 (0x01)
Type : ascii-numeric
Path : 3f005015
Private RSA Key [christian@sigg-iten.ch]
Object Flags : [0x3], private, modifiable
Usage : [0x2E], decrypt, sign, signRecover, unwrap
Access Flags : [0x1D], sensitive, alwaysSensitive, neverExtract, local
ModLength : 2048
Key ref : 0 (0x0)
Native : yes
Path : 3f0050152900
Auth ID : 01
ID : 460a943632df4d88638d86edb1ca7704a4974e13
MD:guid : {faf02afa-6da5-f738-9c36-629582716306}
:cmap flags : 0x0
:sign : 0
:key-exchange: 0
Public RSA Key [christian@sigg-iten.ch]
Object Flags : [0x2], modifiable
Usage : [0xD1], encrypt, wrap, verify, verifyRecover
Access Flags : [0x0]
ModLength : 2048
Key ref : 0 (0x0)
Native : no
Path : 3f0050153000
ID : 460a943632df4d88638d86edb1ca7704a4974e13
DirectValue : <absent>
Token Based SSH Authentication
OS X ships with an old version of OpenSSH. What is worse, ssh-add
is
buggy when used with a PKCS#11 provider. I use the Homebrew package openssh
instead.
For a token based login, extract the public key in SSH compatible format
$ pkcs15-tool --read-ssh-key 460a943632df4d88638d86edb1ca7704a4974e13
[Using reader with a card: Feitian ePass2003 00 00
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6yaaL1F6YE4ISemTt1a2qcWK9kOt4...
and append it to .ssh/authorized_keys
on the server. Then specify opensc-pkcs11.so
as the PKCS#11 provider to authenticate using the token
$ ssh -I /usr/local/lib/opensc-pkcs11.so user@host
Enter PIN for 'christian@sigg-iten.ch (User PI':
Last login: Thu Nov 6 08:51:12 2014 from x.x.x.x
[user@host ~]$
A default provider is configured by adding
PKCS11Provider opensc-pkcs11.so
to .ssh/config
. Then it is enough to just type
$ ssh user@host
Unfortunately, this configuration directive seems to conflict with an ssh-agent
based workflow. To use the agent, don't specify a default provider and use
$ eval `ssh-agent -s`
Agent pid 11996
$ ssh-add -s /usr/local/lib/opensc-pkcs11.so
Enter passphrase for PKCS#11:
Card added: /usr/local/lib/opensc-pkcs11.so
$ ssh user@host
Troubleshooting
This OpenSC wiki page describes how to enable debug logs for targeted bug report searches.