After some work on getting the Austrian Bürgerkarte to work under Linux, I have now decided to acquire some know-how about using more general smart cards under Linux. After some quick research, the Aladdin smart cards seem to be supported fairly well, so I ordered a bunch of different types. This page details how to make them work (my principal systems are running Debian or Ubuntu, but most should be applicable to any Linux distribution).
Middleware/library support under Linux: OpenSC
For nearly all applications that use smart cards under Linux, the OpenSC library/middleware is going to be involved in some way. This is good, because theoretically one only needs to get this set up correctly to get all the application support. For the following, I have used the Debian testing/unstable packages opensc (0.11.13-1), mozilla-opensc (0.11.13-1), openct (0.6.20-1.1), gnupg-pkcs11-scd (0.06-7), libpcsclite1 (1.5.5-3), pcscd (1.5.5-3), ifd-cyberjack2 (3.0.5-1), and libctapi-cyberjack2 (3.0.5-1).
Note: Under Debian and Ubuntu, users who should be allowed to use the openct-control daemon (for the CT-API implementation) must be members of the scard group. If you see messages like "Error: can't open /var/run/openct/status: Permission denied" when running opensc-tool , then most probably the user does not belong to this group.
Sidenote: When using a Reiner SCT cyberJack reader, the user should also be a member of the cyberjack group.
Aladdin eToken PRO SmartCard 32k
For accessing a smart card, one obviously needs a reader. As documented on my page about using the Bürgerkarte, I have both a SCM SPR532 and a Reiner SCT cyberJack e-Com. OpenSC should be able to find the readers before trying anything else. PC/SC 2.0 support seems to work fairly well with both readers, so in this case I recommend to have pcscd running and let OpenSC talk to it. In contrast to using the openct API, this allows to use displays and pinpads if the readers have them (at the time of this writing, pcscd supports these hardware components, while openct doesn't seem to).
should then list the connected readers:
Readers known about: Nr. Driver Name 0 pcsc SCM SPR 532 (60201EC1) 00 00 1 pcsc REINER SCT CyberJack ecom_a (9060564230) 00 00 2 openct OpenCT reader (detached) 3 openct OpenCT reader (detached) 4 openct OpenCT reader (detached) 5 openct OpenCT reader (detached) 6 openct OpenCT reader (detached)
And, when e.g. putting the eToken PRO smart card into the Reiner reader, the card should be "readable" with
opensc-tool -r 1 -f
(or -r 0 for using the first reader):
3f00 type: DF, size: 27285 select[N/A] lock[NONE] delete[NONE] create[NONE] rehab[NONE] inval[NONE] list[N/A] sec: 00:00:00:00:00:00:FF:00 prop: 01:04:00 ....
Since the new and thus empty card just waits to be filled, we can easily generate a first public/private key pair along with a basic X.509 certificate and store it on the card. For Linux OpenSC (and other systems) support, new smart cards need to be "formatted" for PKCS#15 support (which means that data is stored in the card's directory 5015). This can be done with OpenSC by executing
pkcs15-init -r 1 --erase-card --create-pkcs15 --no-so-pin --label 'rmayrhofer'
(obviously replacing the number behind -r with your reader number and the label with something that makes sense for you to identify this card).
This command will not return any output when it runs correctly, but now there should be more "files" on the card as listed by
opensc-tool -r 1 -f:
3f00 type: DF, size: 22242 select[N/A] lock[NONE] delete[NONE] create[NONE] rehab[NONE] inval[NONE] list[N/A] sec: 00:00:00:00:00:00:FF:00 prop: 01:04:00 .... Empty directory 3f005015 type: DF, size: 22242 select[N/A] lock[NEVR] delete[NONE] create[NONE] rehab[NONE] inval[NONE] list[N/A] sec: 00:FF:00:00:00:00:00:00:00 prop: 01:10:00 ... 3f0050155032 type: wEF, ef structure: transpnt, size: 62 read[NONE] update[NONE] write[NONE] erase[NONE] rehab[NONE] inval[NONE] sec: 00:00:00:00:00:00:00:00:00 prop: 01 00000000: 30 3C 02 01 00 04 06 24 7E 4F 0B 0F 11 0C 0E 4F 0<.....$~O.....O 00000010: 70 65 6E 53 43 20 50 72 6F 6A 65 63 74 80 0A 72 penSC Project..r 00000020: 6D 61 79 72 68 6F 66 65 72 03 02 04 10 85 0F 32 mayrhofer......2 00000030: 30 30 38 30 32 31 36 31 39 30 33 31 35 5A 0080216190315Z 3f0050154946 type: wEF, ef structure: transpnt, size: 128 read[NONE] update[NONE] write[NONE] erase[NONE] rehab[NONE] inval[NONE] sec: 00:00:00:00:00:00:00:00:00 prop: 01 00000000: 01 06 70 6B 63 73 31 35 00 00 00 00 00 00 00 00 ..pkcs15........ 00000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 3f002f00 type: wEF, ef structure: transpnt, size: 128 read[NONE] update[NONE] write[NONE] erase[NONE] rehab[NONE] inval[NONE] sec: 00:00:00:00:00:00:00:00:00 prop: 01 00000000: 61 20 4F 0C A0 00 00 00 63 50 4B 43 53 2D 31 35 a O.....cPKCS-15 00000010: 50 0A 72 6D 61 79 72 68 6F 66 65 72 51 04 3F 00 P.rmayrhoferQ.?. 00000020: 50 15 00 00 00 00 00 00 00 00 00 00 00 00 00 00 P............... 00000030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ 00000070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
The directory number 5015 and some OpenSC and PKCS#15 strings should be visible in plain (marked bold in the above output). Next step is to define a PIN that will be used to secure private key objects, by executing
pkcs15-init -r 1 --store-pin --label 'rmayrhofer PIN' --auth-id 01
The authentication id is used to reference this PIN on the card, while the label may be displayed by user interfaces when querying for it. Again, this should be meaningful to whoever is going to use the card. What I don't like about this right now is that the pin pads of both readers are not used but opensc-tool asks for the PIN. I haven't yet managed to use the external pin pad although "enable_pinpad = true;" is set in /etc/opensc/opensc.conf.
Now, after having initialized the PKCS#15 structure and a PIN, we can store public/private keypairs on the card. Either by generating a new keypair directly on the card which will never leave the card and is thus the more secure option, or by importing an existing keypair that is available e.g. in PEM or PKCS#12 format. The former option (generating a new keypair) can be done with
pkcs15-init -r 1 --generate-key 'rsa/1024' --auth-id 01 --label 'test key 1' --public-key-label 'public test key 1' --split-key
This command actually creates two keypairs, one for encryption and one for signing, which is the generally recommended way of handling things securely. If you want only one key, then a specific key usage can be optionally specified with --key-usage <usage>. After entering the PIN set earlier, the keypair should be stored now. By not explicitly specfying an application profile with --id, the default ID 45 is chosen, which stands for authentication purposes.
if the error message "Failed to generate key: Key length/algorithm not supported by card" appears, well, then the card can't deal with this type of key (I found that my Aladdin eToken 32k smart card does not support 2048 bit RSA keys, which should be considered poor in 2008...).
The current contents of the card (PIN, private, and public key) can be queried using pkcs15-tool:
[rene@styx /tmp]$ pkcs15-tool --reader 1 --list-pins PIN [rmayrhofer PIN] 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 : 3f005015 [rene@styx /tmp]$ pkcs15-tool --reader 1 --list-keys Private RSA Key [test key 1] Com. Flags : 3 Usage : [0x4], sign Access Flags: [0x1D], sensitive, alwaysSensitive, neverExtract, local ModLength : 1024 Key ref : 16 Native : yes Path : 3f005015 Auth ID : 01 ID : 45 [rene@styx /tmp]$ pkcs15-tool --reader 1 --list-public-keys Public RSA Key [public test key 1] Com. Flags : 2 Usage : [0x4], sign Access Flags: [0x0] ModLength : 1024 Key ref : 0 Native : no Path : 3f0050153048 Auth ID : ID : 45 [rene@styx /tmp]$ pkcs15-tool --reader 5 --read-ssh-key 45 1024 3641655447 1567616951789183060996864331079825027265767876665133888921191 ... 41906056772820672860765467848748063955241847604374432359017940202114406833022 ... 45993538341311478227464323962431424387970861928249841377070839751756224976219 ... 09869443414111901728734477057908703596265547255119470405017359755532492936938 ... 37062897365384371 ssh-rsa AAAAB3NzaC1yc2EAAAAFANkPQJcAAACBAN88brBD/98zJQ0rgjNioTVxk7iUsZdDjzfZ5Z ... YLAbcQIiDCpCpt7EhNlDJOXD8sm/493TroAF8zR2wwUl8aYSgSN8eJjc81drJnoG32CZOksV6ZtlXw ... iynhI26gD2th9vJjUwVsZ33RTHike1cj7Mqj7uQSXSLHW3JhwfOb83yz
The last command actually outputs the created public key in SSH format so that it could be place directly into ~/.ssh/authorized_keys.
Instead of generating the key directly on the card, an existing X.509 certificate can be imported using
pkcs15-init -r 1 --store-private-key gibraltar/CA/private/styx.key --id 45 --auth-id 01 --label 'test key 2 for IPSec' --key-usage sign,decrypt --split-key
which will use the same PIN as for the first key. The corresponding certificate (the public key object has already created alongside the private key object) can be loaded to the card with
pkcs15-init -r 1 --store-certificate gibraltar/CA/styx.pem --id 45 --auth-id 01 --label 'public test certificate 2 for IPSec'
Alternatively, a PKCS#12 file (which contains both the certificate and the private key) can be imported with
pkcs15-init -r 1 --store-private-key gibraltar/CA/private/styx.p12 --format PKCS12 --id 45 --auth-id 01 --label 'test key 2 for IPSec' --usage sign,decrypt --split-key
which will ask for the passphrase the PKCS#12 file was created with.
Note: The labels are optional and don't have to be specified.
Some applications will not work with a single key that is marked for signing and encryption/decryption, and it might help to import with the --split-key option set (already added to the above lines and the cheat sheet below, as it doesn't seem to have any negative effect besides slightly more space usage).
Note: The proprietary Aladdin tools (for Windows and Linux) use another format and won't be able to read these certificates.
Aladdin eToken PRO 64k (USB dongle)
Note: When pcscd is running, opensc-tool -f will work, but pkcs11-tool seems unable to communicate with the USB token. I therefore recommend to stop pcscd (or remove the pcscd pckage completely) when using the Aladdin eToken USB version.
OpenCT, at least in the version I tested, already supports the eToken USB versions. Connecting it to a USB port and executing
should already list it as one of the known "readers" (pcscd not running in this case, so my other two readers are not visible here):
winscard_clnt.c:3471:SCardCheckDaemonAvailability() PCSC Not Running Readers known about: Nr. Driver Name 0 openct Aladdin eToken PRO 64k 1 openct OpenCT reader (detached) 2 openct OpenCT reader (detached) 3 openct OpenCT reader (detached)
All the other commands work equivalently for this token, one just needs to use the correct "reader" number. One noteworthy change when I tried the above commands on this device is that I didn't restrict myself to using only numerics for PINs, because they will never be entered via a restricted reader's keypad anyway. The PIN is therefore more like a (maximum 8 characters long) password.
The USB version of the Aladdin eToken supports 2048 bit RSA keys without a problem.
Aladdin eToken NG-OTP (USB dongle)
Mozilla Firefox and Thunderbird
KMail and Konqueror
Starting with version 1:5.4p1-2, the openssh-client Debian package now supports PKCS#11 engines with the parameter "-s /usr/lib/opensc-pkcs11.so" for ssh-add. Simply calling
ssh-add -s -s /usr/lib/opensc-pkcs11.so
will ask for the password/PIN of the private key and add it to the SSH agent.
Outdated instructions, not required anymore: Previous versionf of openssh-client were - unfortunately - not compiled with OpenSC support. If you want/need to use an older package version, the configure option "--with-opensc=/usr" must be set and the package recompiled with libopensc2-devbeing installed. That way, ssh, ssh-add, and ssh-keygen should support all readers and smart cards that OpenSC supports.
After importing a keypair and corresponding certificate (interestingly, openssh seems to need the X.509 certificate to be present on the card although it doesn't use any parts of it - a key generated directly on the card was not accessed by the ssh tools), the public key can be printed in ssh format with ssh-keygen -D 1 (with the reader number being 1 in this example), which should produce the same output as the pkcs15-tool command mentioned above. This private key can then be added to a running ssh-agent with ssh-add -s 1 (again with the reader number).
Strongswan has been compiled with OpenSC support for quite a while now, and using it is thus as simple as adding
to the respective connection in /etc/ipsec.conf and
: PIN %smartcard:1 %prompt
to /etc/ipsec.secrets to prompt for the PIN upon startup.
Starting with version 2.1~rc15-1 of the openvpn Debian package, PKCS#11 support uses an external helper library such as the one provided by OpenSC. To configure the certificate and key pair to use, the available "slots" can be queried with openvpn itself:
/usr/sbin/openvpn --show-pkcs11-ids /usr/lib/opensc-pkcs11.so
After finding the correct one, add it to the respective OpenVPN client config file:
Not that single quotes should be used around the serialized ID as printed by openvpn --show-pkcs11-ids.
OpenSC summary cheat sheet
- To get reader numbers for other commands:
- "Formatting" a card with PKCS#15 structures:
pkcs15-init -r X --erase-card --create-pkcs15 --no-so-pin --label 'rmayrhofer'
Note: If this command fails with an error message "Failed to erase card: Authentication method blocked", then the token has somehow been locked (most probably by entering repeatedly the wrong user/key and/or administrator/SO password/PIN). I am not aware of a method to remedy this problem with Linux-only tools or OpenSC/OpenCT. The only way seems to be to re-initialize the complete token (sometimes also referred to as "formatting" it), which can only be done with the Aladdin tools under Windows. (If there's another way, please drop me an email.) Unfortunately, they are pretty hard to get hold of when they were not shipped with the eTokens. As we bought our eTokens without any software support (we always wanted to use them with Linux and/or OpenSC/OpenCT), I acquired an evaluation version of the "PKI client" version 5.0 for Windows, which previously was called the "RTE" (seemingly up to version 3.65, which doesn't work with Windows 7). Installing this under Windows 7 was straight-forward and immediately offered the option to re-initialize the token. Registry changes are no longer required (as they were documented for version 3.65). When re-initializing, I recommend to set the "Advanced" option flags to retain compatibility with version 3.65 and to support 2048 Bit keys when re-formatting an eToken 64k.
One public web page that hosts current releases of the Aladdin PKI client is this one. I verified that this version works perfectly for re-initializing the eToken PRO 64k USB, but have not tried any other functionality (as I use OpenSC for everything else).
This will erase any data already stored on the card and create a new PKCS#15 structure. This structure is not compatible with the one the Aladdin tools (on any of the supported operating systems) write on the tokens. That is, keys and certificates written with OpenSC PKCS#15 support can not be accessed by the Aladdin tools and vice versa. However, as long as there is sufficient free space on the token, both structures can be used along each other. With this suggested command, no so-called security officer (SO) PIN will be defined. That is, the structure on the card will be readable and changeable without providing a PIN - the secret keys will have their own PINs and are thus safe.
- Defining a new PIN:
pkcs15-init -r X --store-pin --label 'rmayrhofer PIN' --auth-id 01
- Generating a new keypair on the card:
pkcs15-init -r X --generate-key 'rsa/1024' --auth-id 01 --label 'test key 1' --public-key-label 'public test key 1' --split-key # maybe add -u sign,encrypt here
- Importing an existing keypair and corresponding X.509 certificate:
pkcs15-init -r X --store-private-key gibraltar/CA/private/styx.key --id 45 --auth-id 01 --label 'test key 2 for IPSec' --split-key # maybe add -u sign,encrypt here
pkcs15-init -r X --store-certificate gibraltar/CA/styx.pem --id 45 --auth-id 01 --label 'public test certificate 2 for IPSec'
- Importing a PKCS#12 file containing the certificate and private key:
pkcs15-init -r X --store-private-key gibraltar/CA/private/styx.p12 --format PKCS12 --id 45 --auth-id 01 --label 'test key 2 for IPSec' --split-key # maybe add -u sign,encrypt here
- Listing PINs that can be used (or are already used) for protecting keys:
pkcs15-tool --reader X --list-pins
- Listing private and corresponding public keys:
pkcs15-tool --reader X --list-keys
pkcs15-tool --reader X --list-public-keys
- Listing X.509 certificates stored on the card:
pkcs15-tool --reader X --list-certificates
- Querying a key and output in ssh format:
pkcs15-tool --reader X --read-ssh-key 45
- Querying the unique key identifier in openvpn format:
/usr/sbin/openvpn --show-pkcs11-ids /usr/lib/opensc-pkcs11.so
More links for smart cards (unsorted)
- https://twiki.cern.ch/twiki/bin/view/Main/ITGD-eToken also includes a link to the Aladdin drivers
- http://www.sysmic.org/dotclear/index.php?post/2010/03/24/Convert-keys-betweens-GnuPG%2C-OpenSsh-and-OpenSSL tor instructions on how to convert RSA keys between openssl, openssh, and gnupg formats