Using smart cards with FreeIPA – Part 1

FreeIPA 4.2 has added some nice new PKI related features. FreeIPA has long included the Dogtag Certificate Authority component, but it has been restricted to issuing certificates that are tied to services that are defined in IPA. The main use for these certificates is for enabling TLS for webservers, mail servers, and other applications. As of the 4.2 release, it is possible to define other certificate profiles which can be used for client certificates that are tied to FreeIPA users. The certificates can then be published in the FreeIPA user entries, which allows consumers of those certificates to look them up to perform client certificate authentication.

The FreeIPA API and the ‘ipa’ command-line utility have also been updated in version 4.2 to allow arbitrary certificates to be added to user entries. This is useful for cases where user certificates (and potentially smart cards) may already have been issued by some Certificate Authority other than your FreeIPA server. By adding these ‘external’ certificates to your user entry, you can allow these certificates to be used to authenticate you to services that trust the associated Certificate Authority and use FreeIPA for user/group lookup.

Along with these recent FreeIPA changes, new functionality has been added to SSSD that allow it to use these certificates when they are available in FreeIPA. In particular, SSSD can now support smart card authentication for local authentication such as system login, su, and sudo. In addition, SSSD makes is possible to use smart cards for ‘ssh’ when using systems that include OpenSSH that has been modified to support certificate authentication such as the one included in modern versions of Fedora, CentOS and Red Hat Enterprise Linux.

SSSD has also updated its InfoPipe responder to allow user entries to be looked up by certificate over D-Bus. This allows for some very powerful capabilities. A good example of how this can be used can be seen in some updates that are being made to the mod_lookup_identity Apache httpd module. This module previously allowed httpd to look up user attributes via SSSD that correspond to the user identified in the REMOTE_USER environment variable, which is set by other httpd authentication modules such as mod_auth_gssapi. The mod_lookup_identity module has some pending patches which allow it to use the new SSSD ability to look a user up by certificate, which then sets REMOTE_USER to the proper attribute from the user entry. This user identifier doesn’t even need to exist in the certificate subject DN, as the lookup is performed by matching the entire cerficiate. This allows web application developers to easily add client certificate authentication with user lookup entirely in the web server for both software certificates and smart cards. The web application simply needs to consume REMOTE_USER and the other environment variables provided by mod_lookup_identity, much like the ManageIQ and Foreman projects currently do to support Kerberos Single-Sign-On with FreeIPA.

With all of these cool new capabilities, you may be wondering how you can provision your own smart cards that can be used with your FreeIPA server. This is the first installment in a multi-part series of blog posts which will show how you can provision and use smart cards with FreeIPA. In this first part, we will cover how you can personalize a blank smart card which can be associated with your FreeIPA user.

Smart card hardware and interoperability can vary widely, even though there standards in this area. The example commands I show may have to be modified to work with your hardware. The hardware I’m using in these examples is as follows:

  • HID OmniKey 3121 USB card reader
  • Athena ASECard Crypto smart card

This smart card works nicely with OpenSC, which we will be using to provision and use our card.  This will be done using a PKCS#15 utility to personalize the card, then OpenSSL and the OpenSC PKCS#11 lib to perform the other crypto operations such as creation of the certificate signing request.  You will need to install the OpenSC package as well as the OpenSSL PKCS#11 Engine:

[nkinder@localhost ~]$ sudo yum install -y opensc engine_pkcs11

Starting with the card reader plugged into the system and no card inserted, we can verify that the system can see the reader:

[nkinder@localhost ~]$ opensc-tool --list-readers
# Detected readers (pcsc)
Nr.  Card  Features  Name
0    No              OMNIKEY AG CardMan 3121 00 00

If we then insert our blank card, we can see that the reader detects it and can run some commands that identity the card:

[nkinder@localhost ~]$ opensc-tool --list-readers
# Detected readers (pcsc)
Nr.  Card  Features  Name
0    Yes             OMNIKEY AG CardMan 3121 00 00
[nkinder@localhost ~]$ opensc-tool --reader 0 --name
Athena ASEPCOS
[nkinder@localhost ~]$ opensc-tool --reader 0 --atr
3b:d6:18:00:81:b1:80:7d:1f:03:80:51:00:61:10:30:8f

Now that we can see that our reader is communicating with the card, we can personalize it.  To do this, we will use the ‘pkcs15-tool’ utility that is a part of OpenSC.  The PKCS#15 specification defines a standard information format on the card.  The first step in personalization is called initialization, and it consists of setting a security officer PIN, a PIN unlock key (PUK), and a transport key:

[nkinder@localhost ~]$ pkcs15-init --create-pkcs15 --use-default-transport-keys
Using reader with a card: OMNIKEY AG CardMan 3121 00 00
New Security Officer PIN (Optional - press return for no PIN).
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 #0) 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 [41:53:45:43:41:52:44:2b]:

Now that our basic PKCS#15 structure and security officer PIN is set up, we can create a user PIN that will be used to protect user objects that we store on the card such as our private key.  This is a privileged operation that requires our security officer PIN.  Tokens typically support multiple user PINs, so we need to give our PIN an identifier that we will use when performing further operations on the card.  We will use an id of ’01′:

[nkinder@localhost ~]$ pkcs15-init --store-pin --auth-id 01 --label "Nathan Kinder"
Using reader with a card: OMNIKEY AG CardMan 3121 00 00
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 [Security Officer PIN] required.
Please enter Security officer PIN [Security Officer PIN]:

Our user PIN is now set up, so we can get on to more exciting things such as generating our private key!  For the purposes of this example, we will just generate a 1024-bit RSA key:

[nkinder@localhost ~]$ pkcs15-init --generate-key rsa/1024 --auth-id 01
Using reader with a card: OMNIKEY AG CardMan 3121 00 00
Security officer PIN [Security Officer PIN] required.
Please enter Security officer PIN [Security Officer PIN]: 
User PIN [Nathan Kinder] required.
Please enter User PIN [Nathan Kinder]:

We can now view some information about our private key, which we will need for later commands that use this key:

[nkinder@localhost ~]$ pkcs15-tool --list-keys
Using reader with a card: OMNIKEY AG CardMan 3121 00 00
Private RSA Key [Private Key]
    Object Flags   : [0x3], private, modifiable
    Usage          : [0x4], sign
    Access Flags   : [0x1D], sensitive, alwaysSensitive, neverExtract, local
    ModLength      : 1024
    Key ref        : 0 (0x0)
    Native         : yes
    Path           : 3f0050150100
    Auth ID        : 01
    ID             : 89015cc53f659f38d8ba2d2646b5b84c4be6820f
    GUID           : {5ce7d06d-d3f7-5e34-d23b-da1019f642a9}

We will now switch to using PKCS#11 and OpenSSL to create our certificate signing request.  PKCS#11 uses a concept of ‘slots’ that contain ‘tokens’.  We first need to find out what slot our card is in so we know how to refer to it later.  We can use ‘pkcs11-tool’ and the OpenSC PKCS#11 module to list the slots as follows:

[nkinder@localhost ~]$ pkcs11-tool --module /usr/lib64/opensc-pkcs11.so --list-slots
Available slots:
Slot 0 (0xffffffffffffffff): Virtual hotplug slot
  (empty)
Slot 1 (0x1): OMNIKEY AG CardMan 3121 00 00
  token label        : OpenSC Card (Nathan Kinder)
  token manufacturer : OpenSC Project
  token model        : PKCS#15
  token flags        : login required, PIN initialized, token initialized
  hardware version   : 0.0
  firmware version   : 0.0
  serial num         : 0C0A548021220815

We can see that slot ’1′ contains our card, and the previous command where we listed our keys shows that our private key as an ID of ’89015cc53f659f38d8ba2d2646b5b84c4be6820f’.  We need to use both of these pieces of information to refer to our private key in the next step, which is generating our certificate signing request.  To do this, we will use the ‘openssl’ utility along with it’s PKCS#11 engine, which will in turn use the OpenSC PKCS#11 module.  We can load the OpenSSL PKCS#11 engine and the OpenSC PKCS#11 module like this:

[nkinder@localhost ~]$ openssl
OpenSSL> engine dynamic -pre SO_PATH:/usr/lib64/openssl/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/lib64/openssl/engines/engine_pkcs11.so
[Success]: ID:pkcs11
[Success]: LIST_ADD:1
[Success]: LOAD
[Success]: MODULE_PATH:opensc-pkcs11.so
Loaded: (pkcs11) pkcs11 engine
OpenSSL>

We are at the OpenSSL prompt with our PKCS#11 module loaded, so we’re ready to generate the certificate signing request.  This is done by using the ‘req’ command as usual when using OpenSSL, but we have to tell the command to use the PKCS#11 engine and which key to use.  We use the slot number and private key ID we gathered in the previous steps and generate the request:

OpenSSL> req -engine pkcs11 -new -key slot_1-id_89015cc53f659f38d8ba2d2646b5b84c4be6820f -keyform engine -out /home/nkinder/card1.req -text
engine "pkcs11" set.
PKCS#11 token PIN: 
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) []:
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:Nathan Kinder
Email Address []:nkinder@redhat.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Our certificate signing request will now exist in the file we specified as the ‘-out’ option:

[nkinder@localhost ~]$ cat /home/nkinder/card1.req 
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=XX, L=Default City, O=Default Company Ltd, CN=Nathan Kinder/emailAddress=nkinder@redhat.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (1024 bit)
                Modulus:
                    00:c2:a5:78:46:16:03:80:ff:41:86:59:92:2d:15:
                    ae:5b:ba:14:c1:fe:0a:3b:a4:f7:c1:18:24:6f:9f:
                    9d:79:7f:04:2a:80:85:a3:07:91:bb:a9:95:2d:2a:
                    df:01:ca:06:3f:5b:9d:a1:ac:e6:c2:83:1d:e9:c0:
                    d9:98:c8:8e:21:0b:e9:6d:e0:bd:b3:0b:ad:24:01:
                    ba:a7:c0:68:9f:17:4a:93:40:55:aa:10:fc:2e:17:
                    82:f1:25:3f:6b:6b:8d:6e:14:ce:0f:df:47:7f:48:
                    61:62:e5:ef:43:99:f5:7c:00:48:63:d8:54:65:8e:
                    57:bb:66:b0:b3:11:50:e0:55
                Exponent: 65537 (0x10001)
        Attributes:
            a0:00
    Signature Algorithm: sha1WithRSAEncryption
         37:6d:c9:32:d2:6c:45:e1:83:48:6c:b8:98:b1:29:ff:df:e5:
         e0:33:15:8f:34:38:d0:00:48:fb:70:44:03:ad:bb:b7:37:c3:
         84:90:91:aa:40:1b:47:61:35:4f:55:ed:84:34:15:20:fd:5d:
         fa:ec:60:2e:9e:b3:9a:23:cd:5d:94:47:56:f5:5f:77:51:9d:
         56:4b:94:a9:d2:a4:5d:83:e4:5c:34:95:23:df:7f:a9:45:58:
         44:1a:0e:87:9d:f4:e9:43:56:c8:38:58:a9:04:ff:7a:fd:28:
         a2:91:dd:16:5e:1d:13:d8:18:4d:9a:53:2b:66:0d:e6:02:be:
         4b:18
-----BEGIN CERTIFICATE REQUEST-----
MIIBvTCCASYCAQAwfTELMAkGA1UEBhMCWFgxFTATBgNVBAcMDERlZmF1bHQgQ2l0
eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEWMBQGA1UEAwwNTmF0aGFu
IEtpbmRlcjEhMB8GCSqGSIb3DQEJARYSbmtpbmRlckByZWRoYXQuY29tMIGfMA0G
CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCpXhGFgOA/0GGWZItFa5buhTB/go7pPfB
GCRvn515fwQqgIWjB5G7qZUtKt8BygY/W52hrObCgx3pwNmYyI4hC+lt4L2zC60k
AbqnwGifF0qTQFWqEPwuF4LxJT9ra41uFM4P30d/SGFi5e9DmfV8AEhj2FRljle7
ZrCzEVDgVQIDAQABoAAwDQYJKoZIhvcNAQEFBQADgYEAN23JMtJsReGDSGy4mLEp
/9/l4DMVjzQ40ABI+3BEA627tzfDhJCRqkAbR2E1T1XthDQVIP1d+uxgLp6zmiPN
XZRHVvVfd1GdVkuUqdKkXYPkXDSVI99/qUVYRBoOh5306UNWyDhYqQT/ev0oopHd
Fl4dE9gYTZpTK2YN5gK+Sxg=
-----END CERTIFICATE REQUEST-----

This can be sent to your certificate authority as usual when requesting a certificate.  When you receive the signed certificate, it can then be loaded onto the card.  You will need to specify which private key this is associated with by specifying the PIN ID and the key ID:

[nkinder@localhost ~]$ pkcs15-init --store-certificate /home/nkinder/card1.pem --auth-id 01 --id 89015cc53f659f38d8ba2d2646b5b84c4be6820f --format pem
Using reader with a card: OMNIKEY AG CardMan 3121 00 00
Security officer PIN [Security Officer PIN] required.
Please enter Security officer PIN [Security Officer PIN]: 
User PIN [Nathan Kinder] required.
Please enter User PIN [Nathan Kinder]:

We can then confirm our certificate is on the card by printing it out:

[nkinder@localhost ~]$ pkcs15-tool --read-certificate 89015cc53f659f38d8ba2d2646b5b84c4be6820f
Using reader with a card: OMNIKEY AG CardMan 3121 00 00
-----BEGIN CERTIFICATE-----
MIIC2zCCAcMCAQwwDQYJKoZIhvcNAQEFBQAwbjELMAkGA1UEBhMCVVMxEzARBgNV
BAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxGDAWBgNVBAoM
D05HS3MgQ2VydCBTaGFjazEYMBYGA1UEAwwPTkdLcyBDZXJ0IFNoYWNrMB4XDTE1
MDczMTAzMDI1NloXDTE2MDczMDAzMDI1NlowfTELMAkGA1UEBhMCWFgxFTATBgNV
BAcMDERlZmF1bHQgQ2l0eTEcMBoGA1UECgwTRGVmYXVsdCBDb21wYW55IEx0ZDEW
MBQGA1UEAwwNTmF0aGFuIEtpbmRlcjEhMB8GCSqGSIb3DQEJARYSbmtpbmRlckBy
ZWRoYXQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCpXhGFgOA/0GG
WZItFa5buhTB/go7pPfBGCRvn515fwQqgIWjB5G7qZUtKt8BygY/W52hrObCgx3p
wNmYyI4hC+lt4L2zC60kAbqnwGifF0qTQFWqEPwuF4LxJT9ra41uFM4P30d/SGFi
5e9DmfV8AEhj2FRljle7ZrCzEVDgVQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQCO
1kKBM9E+E10vq/aG4GGdpMZj592zuk2Z/VOh8TKx9365bEpcO1szD0Zaoni9roUT
KFERSOQdQ85rDHnTelnhHOU1EI+nz2DOkCjJgG95GRgU3/MsbAOMWONAzD4y1zp8
VDZm0GcqjaP0UrEwqzGnV239/8PvkxUt10woIDLOpPXqgXdaUByCMYKjwSJpKAhH
3e3JE9G+0kVb/9uO19q73q7wN42+dbuUqLytukiXP0cyUo+iraTUk+UwqbP6kfos
ybR2irAiWYcGaxAmGTwjsFHHccFp87t54M9GJtT3bnu1mpoqFgnkASRbkSmPjHSs
amX5j3Jmkno0he8/aR1S
-----END CERTIFICATE-----

Our card is now fully personalized and is ready to be used by any application that supports PKCS#11.

In the next installment, we will show how the certificate authority in FreeIPA can be used to issue the user certificate that you put on your smart card, as well as how you can associate certificates from external certificate authorities with FreeIPA users.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>