Seamless Smartcard login with pam_pkcs11, and pam_krb5 against an Active Directory Domain using Red Hat Enterprise Linux 5 (Part 2)

In part 1 I discussed how to configure NSS and OpenSSL. In this part, I’ll discuss how to configure pam_pkcs11 and how to test a smartcard against the NSS database we set up.
[toc title=”Table of Contents”]

What does pam_pkcs11 do for me?

The pam_pkcs11 module will do a couple things for us:

  1. Allow/Require smartcard login
  2. Map an attribute from the card to a login name

For a basic configuration, we’ll have to edit three files; /etc/pam_pkcs11/pam_pkcs11.conf, /etc/pam_pkcs11/cn_map, and /etc/pam.d/system-auth.

Configuring pam_pkcs11 and testing smart card access

Edit /etc/pam_pkcs11/pam_pkcs11.conf; this file is kind of long, so I’ll just touch on specific configuration lines, and only the basic configuration lines needed to get the authentication working.

enable_ocsp = false;

The above line tells pam_pkcs11 whether we wish to use OCSP or not. Notice that in general it is good to use OCSP if you have an OCSP available. If you do not have an OCSP server, you’ll have to manually add CRLs to your centralized NSS database. We’ll leave this set to false for testing purposes.

use_pkcs11_module = coolkey;

The above line specifies which module the system should use to access the smart card. You should keep this configured to coolkey.

pkcs11_module coolkey {
  module =;
  description = "Cool Key"
  # Slot-number to use. One for the first, two for the second and so
  # on. The default value is zero which means to use the first slot
  # with an available token.
  slot_num = 0;

  # Path to the directory where the CA certificates are stored. The
  # directory must contain an openssl hash-link to each certificate.
  # The default value is /etc/pam_pkcs11/cacerts.
  ca_dir = /etc/pam_pkcs11/cacerts;
  nss_dir = /etc/pki/nssdb;

  # Path to the directory where the CRLs are stored. The directory
  # must contain an openssl hash-link to each CRL. The default value
  # is /etc/pam_pkcs11/crls.
  crl_dir = /etc/pam_pkcs11/crls;

  # Sets the CRL verification policy. None performs no verification
  # at all, online downloads the CRL form the location given by the
  # CRL distribution point extension of the certificate and offline
  # uses the locally stored CRLs. Auto is a combination of online and
  # offline; it first tries to download the CRL from a possibly
  # given CRL distribution point and if this fails, uses the local
  # CRLs. The default setting is none.
  # crl_policy={none, online, offline, auto}
  crl_policy = none;


The above section configures the coolkey module. You should ensure “nss_dir = /etc/pki/nssdb;” and that “module = <path_to_your_module>;“. Notice that in the example above, I have the module line pointing explicitly to the dynamic module on the system. If you are using a 64 bit OS, this may not be the correct configuration. Since RHEL uses NSS and not OpenSSL for pam_pkcs11, we can ignore the ca_dir, crl_dir, and crl_policy lines.

use_mappers = cn, null;

The above line specifies which mapping modules we wish to use, and in what order to use them. I have configured pam_pkcs11 to only use the cn module (the null module always fails by default).

mapper cn {
      debug = false;
      module = internal;
      # module = /usr/$LIB/pam_pkcs11/;
      ignorecase = true;
      mapfile = file:///etc/pam_pkcs11/cn_map;

The above section configures the cn mapping module. The important line is “mapfile = file:///etc/pam_pkcs11/cn_map;“. This line tells pam_pkcs11 where to find cn to user name mappings.

Now we’ll need to edit the /etc/pam_pkcs11/cn_map file, and add cn to user name mappings.

RYAN.LANE -> laner
TEST.USER -> usert
external_user -> usere

The above lines placed in the cn_map file tell pam_pkcs11 that the CNs on the left match the user names on the right. If you don’t know what the CN of the user on the card is, you can find out using the pkcs11_inspect command.

$ pkcs11_inspect

Before we modify PAM, we should ensure we can access the smart card, and map CNs to user names. Using the pklogin_finder command, we can both test access to the smart card, and whether the mapping is working properly. The output of the command should return the user name. If it returns nothing, the mapping module probably isn’t mapping the user properly. For more detailed information, you can run “pklogin_finder debug“; as a warning, running this command with debug will print your pin to the screen.

$ pklogin_finder
$ pklogin_finder debug
DEBUG:pam_config.c:188: Using config file /etc/pam_pkcs11/pam_pkcs11.conf
DEBUG:pkcs11.c:65: Initializing NSS ...
DEBUG:pkcs11.c:75: Initializing NSS ... database=/etc/pki/nssdb
DEBUG:pkcs11.c:89: ...  NSS Complete
DEBUG:pklogin_finder.c:67: loading pkcs #11 module...
DEBUG:pkcs11.c:101: Looking up module in list
DEBUG:pkcs11.c:104: modList = 0x8b1ad50 next = 0x8b2a870
DEBUG:pkcs11.c:105: dllName= <null>
DEBUG:pkcs11.c:104: modList = 0x8b2a870 next = 0x0
DEBUG:pkcs11.c:105: dllName= /usr/lib/
DEBUG:pklogin_finder.c:75: initialising pkcs #11 module...
DEBUG:pklogin_finder.c:87: no token available

Notice the above debug output is telling me that I don’t have a smart card inserted…

Configuring PAM

The only file we need to configure for smart card login is /etc/pam.d/system-auth; your file should look something like this:

auth        required
auth        [success=1 default=ignore] service notin login:gdm:xdm:kdm:xscreensaver:gnome-screensaver:kscreensaver quiet use_uid
auth        [success=done authinfo_unavail=ignore ignore=ignore default=die]
auth        sufficient likeauth
auth        required

account     required broken_shadow
account     sufficient
account     required

password    optional
password    requisite retry=3 dcredit=-2 ucredit=-2 ocredit=-2 lcredit=-2 minlen=10
password    sufficient md5 shadow try_first_pass use_authtok
password    required

session     optional revoke
session     required
session     [success=1 default=ignore] service in crond quiet use_uid
session     required

Notice that the important lines are:

auth        [success=1 default=ignore] service notin login:gdm:xdm:kdm:xscreensaver:gnome-screensaver:kscreensaver quiet use_uid

This tells PAM that pam_pkcs11 should only be used if it is in one of the following services: login:gdm:xdm:kdm:xscreensaver:gnome-screensaver:kscreensaver. This ensures that the smartcard won’t be accessed if someone logs in via a service like SSH, or FTP, where smartcard login doesn’t make sense.

auth        [success=done authinfo_unavail=ignore ignore=ignore default=die]

This tells PAM to succeed if pam_pkcs11 logs the user in, and maps their user name properly, but to ignore the module otherwise. In this case, regular unix password authentication is still allowed. If you wish to disallow password authentication, you should set authinfo_unavail and ignore to die.

password    optional

This optionally allows PAM to reset the password/pin on the smartcard. This line isn’t likely needed, and you can leave it out if you wish.

After saving the file, you should test your PAM configuration before logging out. You can do so by going to a virtual console, and logging in. Do the following:

  1. Insert your smart card
  2. At the Username prompt, hit the spacebar once and hit enter
  3. Type in your PIN when requested
    • If you are using the number pad, make sure num lock is on!

Conclusion and next part in the series

With this, you should be able to log users into a system using a smartcard. In the next part of this series, I’ll discuss how to add pam_krb5 into the mix to automatically get a Kerberos ticket from an Active Directory domain using PKINIT.

Update 12/08/08: Removed the stuff about pointing explicitly to the coolkey module. I tested this recently, and it was working fine without (for the first time). Pointing to the module explicitly definitely causes issues with 64-bit RHEL. Maybe Red Hat fixed this in a later release?