# Linux smart card authentication – PAM

(This is part of my howto on smart card authentication in Linux.)

PAM (Pluggable Authentication Modules) is an authentication framework which uses modules to authenticate users using a wide variety of methods. A PKCS#11 PAM module exists, which allows us to use smart cards to authenticate against any service which uses PAM. The most obvious usage of PAM is system logins, either console or graphical, but a lof of other services, for example sudo, use it (you can have a look in /etc/pam.d to see all currently installed services which use PAM).

The PKCS#11 PAM module can be found in the libpam-pkcs11 package in the repositories.

Several methods can be used to map a smart card to a user (i.e., determine to which user the inserted smart card belongs), I will not describe them all here. The only method I will cover is pwent, which will check the CN (Common Name) field of the X.509 certificate associated with a key, and grant access only if it matches either the login name or the real name of the user. Other mapping methods are documented here.

### Initial configuration

The package does not do any initial configuration for you, so you will have to do it yourself. First, create the configuration directory. The module expects it to be at /etc/pam_pkcs11, so it’s a good idea to put it there:

sudo mkdir /etc/pam_pkcs11

Copy the default config file to this directory:

zcat /usr/share/doc/libpam-pkcs11/examples/pam_pkcs11.conf.example.gz | sudo tee /etc/pam_pkcs11/pam_pkcs11.conf

We also need some additional directories. cacerts will store the certificates of trusted CAs: a certificate will only be accepted if it has been signed by one of those CAs. crls will store the Certificate Revocation Lists sent by the CAs, to let the PAM module know which certificates are no longer valid (revoked).

sudo mkdir /etc/pam_pkcs11/cacerts /etc/pam_pkcs11/crls

Since we will use the pwent mapper, edit the use_mappers line in /etc/pam_pkcs11/pam_pkcs11.conf to list only pwent. It is also a good idea to comment out the debug line, otherwise it produces a lot of output when you use your card.

If you have not done so already, generate an X.509 certificate for the key stored on your smart card and store it on the card as well, as described in the post about OpenSSL. Remember that the Common Name (CN) field will be used to match the certificate to your account, so make sure to put either your login or your real name in that field (or at least, your real name as stored on the system, if you don’t know it, it’s on your line in /etc/passwd, you can safely edit the file if you want to change it).

Note that some systems will put three commas after your real name in /etc/passwd, because historically this field (called the GECOS field) contained other information besides the real name of the user. The CN field of your certificate must match the entire GECOS field, so if the three commas are present in your /etc/passwd file, you must either delete them or include them in the CN field of your certificate when you create it.

Finally, copy the certificate of the CA who signed your own certificate (if your certificate is self-signed, that’s the certificate itself) into /etc/pam_pkcs11/cacerts and rehash the list of CA certificates with:

cd /etc/pam_pkcs11/cacerts
sudo pkcs11_make_hash_link

### First Test: sudo

We will first test PAM authentication with sudo. It is a good idea to test with sudo first because you will not have to log out and try to log back in in order to test your configuration.

Edit /etc/pam.d/sudo. It will look like this:

#%PAM-1.0

@include common-auth
@include common-account
@include common-session-noninteractive

Modify it like this:

#%PAM-1.0

auth sufficient pam_pkcs11.so
@include common-auth
@include common-account
@include common-session-noninteractive

Test:

firas@tsukino ~ % sudo -i
Smartcard authentification starts
Smart card found.
Welcome Firas Kraiem (User PIN)!
Smart card PIN:
verifying certificate
Checking signature
tsukino ~ # 

All right! Edit /etc/pam.d/sudo back to its original state (unless for some reason you want to use your card only with sudo), we will configure PAM to use your smart card for all login authentication mechanisms.

If you looked closely at /etc/pam.d/sudo, you saw that it includes common-auth. Actually, all login services (gdm, login, samba…) include this file, so we can just add our pam_pkcs11 module to it, and it will get used for all login purposes.

Edit /etc/pam.d/common-auth. It will look like this:

#
# /etc/pam.d/common-auth - authentication settings common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the
#
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
# To take advantage of this, it is recommended that you configure any
# local modules either before or after the default block, and use
# pam-auth-update to manage selection of other modules.  See
# pam-auth-update(8) for details.

# here are the per-package modules (the "Primary" block)
auth	[success=2 default=ignore]	pam_unix.so nullok_secure
auth	[success=1 default=ignore]	pam_winbind.so krb5_auth krb5_ccache_type=FILE cached_login try_first_pass
# here's the fallback if no module succeeds
auth	requisite			pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth	required			pam_permit.so
# and here are more per-package modules (the "Additional" block)
auth	optional			pam_cap.so
# end of pam-auth-update config

Modify it like this:

#
# /etc/pam.d/common-auth - authentication settings common to all services
#
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the
#
# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
# To take advantage of this, it is recommended that you configure any
# local modules either before or after the default block, and use
# pam-auth-update to manage selection of other modules.  See
# pam-auth-update(8) for details.

auth    [success=3 default=ignore]      pam_pkcs11.so
# here are the per-package modules (the "Primary" block)
auth	[success=2 default=ignore]	pam_unix.so nullok_secure
auth	[success=1 default=ignore]	pam_winbind.so krb5_auth krb5_ccache_type=FILE cached_login try_first_pass
# here's the fallback if no module succeeds
auth	requisite			pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth	required			pam_permit.so
# and here are more per-package modules (the "Additional" block)
auth	optional			pam_cap.so
# end of pam-auth-update config

With this configuration, smart card authentication will be tried first, and if it fails, PAM will fall back to normal password authentication. You can also disable password authentication for your account (the same way Ubuntu “disables” the root account) with:

sudo passwd -l whoami

And smart card authentication will be required (you will still be prompted for a password if it fails, but the password will always fail).

### Other Services?

I don’t really use any other service which uses PAM so I can’t really test it, but other individual services should be configurable in the same way as sudo above. Feel free to report any success or failure in the comments.