# Ubuntu Smartcard (UI) login support
While we're focusing here only on login for a graphical session, once this is setup is done, it can be easily adapted to SSH logins, but this is out of scope for this document.
## Prerequisites
This assumes having a smartcard reader supported by OpenSC, but setup for other libraries supported by `p11-kit` should not differ substancially
```bash
# The SSSD PAM module, needed for authentication
sudo apt install libpam-sss
# Replace this with the pkcs11 driver supporting your device
sudo apt install opensc-pkcs11
# This is needed to expose the SmartCard reader
sudo apt install pcscd
```
## Smartcard module
There are various smartcard modules out there, most of the cards should be supported by the OpenSC module (`opensc-pkcs11` package), and this can be verified by:
```
p11-kit list-modules
p11-kit-trust: p11-kit-trust.so
library-description: PKCS#11 Kit Trust Module
library-manufacturer: PKCS#11 Kit
library-version: 0.23
token: System Trust
manufacturer: PKCS#11 Kit
model: p11-kit-trust
serial-number: 1
hardware-version: 0.23
flags:
write-protected
token-initialized
opensc-pkcs11: opensc-pkcs11.so
library-description: OpenSC smartcard framework
library-manufacturer: OpenSC Project
library-version: 0.20
token: MARCO TREVISAN (PIN CNS0)
manufacturer: IC: STMicroelectronics; mask:...
model: PKCS#15 emulated
serial-number: 6090010669298009
flags:
login-required
user-pin-initialized
token-initialized
user-pin-locked
```
### NSS Database (to be deprecated post 20.04)
Up to 20.04, SSSD and gnome-settings-daemon versions provided in ubuntu, need to have an NSS database (by default in `/etc/pki/nssdb`) that contains:
- A reference of the smartcard p11 module to use (for g-s-d up to 20.10)
- The trusted CA certificates (for SSSD)
In particular, `gnome-settings-daemon` uses is configured by default to use some Fedora specific feature, by getting all the allowed device drivers from an NSS database.
While SSSD is configured to use NSS (now deprecated even uptream) over openssl (to be the default and that is already [since 20.10](https://salsa.debian.org/sssd-team/sssd/-/commit/f4f7bfee91e9aa929585b95e5c579597d0ab156b))
Given that we don't provide one in ubuntu, we need an hack to enable the smartcard modules to work right now, creating a database and falling-back to `p11-kit` device proxy:
```bash
sudo apt install libnss3-tools
# Create a db, with an empty password
sudo mkdir /etc/pki/nssdb
sudo certutil -N -d /etc/pki/nssdb -f /dev/zero
# Sad but true... As g-s-d can need to read this when ran as user
sudo chmod 644 /etc/pki/nssdb/*
sudo modutil -dbdir /etc/pki/nssdb -add "PKCS#11 Kit modules proxy" -libfile /usr/lib/x86_64-linux-gnu/p11-kit-proxy.so
# Now you should get the Smart card info showing up
modutil -dbdir /etc/pki/nssdb -list
....
2. PKCS#11 Kit modules proxy
library name: p11-kit-proxy.so
uri: pkcs11:library-manufacturer=PKCS%2311%20Kit;library-description=PKCS%2311%20Kit%20Proxy%20Module;library-version=1.1
slots: 1 slot attached
status: loaded
slot: VMware Virtual USB CCID 00 00
token: MARCO TREVISAN (PIN CNS0)
uri: pkcs11:token=MARCO%20TREVISAN%20(PIN%20CNS0);manufacturer=IC:%20STMicroelectronics%3B%20mask:...;serial=6090010669298009;model=PKCS%2315%20emulated
# While g-s-d should list the token as well
gdbus call --session --dest org.gnome.SettingsDaemon.Smartcard --object-path /org/gnome/SettingsDaemon/Smartcard/Manager --method org.gnome.SettingsDaemon.Smartcard.Manager.GetInsertedTokens
([objectpath '/org/gnome/SettingsDaemon/Smartcard/Manager/Tokens/token_from_p11_2d_kit_2d_proxy_2e_so_slot_17'],)
```
## SmartCard certificate
To be validated, a smart card certificate should be verified by a Certificate Authority
### Certificate Authority verification
The card certificate must be allowed by a CA, these should be part of `/etc/sssd/pki/sssd_auth_ca_db.pem` in recent SSSD versions or in `/etc/pki/nssdb` for older ones (or any other location configured in `[pam]` config section of `sssd.conf` as `pam_cert_db_path`)
You can check this by using something like:
```bash
# List certificates
pkcs15-tool --list-certificates
Using reader with a card: Alcor Micro AU9560 00 00
X.509 Certificate [CNS0]
Object Flags : [0x00]
Authority : no
Path : 3f0011001101
ID : 01
Encoded serial : 02 03 3435CC
pkcs15-tool --read-certificate 1 > card-CERT.pem
# See the certificate contents with
openssl x509 -text -noout -in card-CERT.pem
# Verify it is valid for the given CA
openssl verify -verbose -CAfile CA-Auth-CERT.pem card-CERT.pem
```
### Include the CA certificates in the SSSD CA database
#### Ubuntu 20.04
In this case we need to use the NSS database, and so any certificate (one by one, as it doesn't support a certificate chain) should be added to it:
```
sudo certutil -A -d /etc/pki/nssdb -n Ca-Auth-Cert -t CT,C,C -a -i CA-Auth-CERT.pem
sudo certutil -A -d /etc/pki/nssdb -n Ca-Auth-Cert -t CT,C,C -a -i CA-Auth-CERT2.pem
```
This can be quite slow if you've a card inserted during this operation, so better if you remove it as nss will always open it on load
##### Debugging
This can be simulated using SSSD login tool using:
```bash
sudo /usr/libexec/sssd/p11_child --pre -d 10 --debug-fd=2 --nssdb=/etc/pki/nssdb
```
If everything is correct, the certificate should be printed
#### Ubuntu 20.10 (and next versions)
As per SSSD using openssl, we need to add the certificate to the SSSD well known certificate path (if not changed via `sssd.certificate_verification`), so copying the certificates (can be a chain of certificates)
```bash
sudo cat Ca-Auth-CERT*.pem >> /etc/sssd/pki/sssd_auth_ca_db.pem
```
##### Debugging
This can be simulated using SSSD login tool using:
```bash
sudo /usr/libexec/sssd/p11_child --pre -d 10 --debug-fd=2 --nssdb=/etc/sssd/pki/sssd_auth_ca_db.pem
```
If everything is correct, the certificate should be printed
##### Use Ubuntu default CA file
It's possible to use the default ubuntu ca-certificates, so that it can be easily managed using `ca-certificates` by using this:
```ini
[pam]
pam_cert_db_path = /etc/ssl/certs/ca-certificates.crt
```
To add specific CA cert files there, you only have to add your `*.crt` (extension matters, no `*.pem`!) to `/usr/local/share/ca-certificates/` (or a subfolder of it) and run `sudo update-ca-certificates`
### Ignore CA
This is not suggested, but can be done for testing, disabling the CA check in `sssd.conf`:
```ini
[sssd]
certificate_verification = no_ocsp
```
This can be simulated using SSSD login tool using:
```bash
sudo /usr/libexec/sssd/p11_child --pre -d 10 --debug-fd=2 --nssdb=/etc/ssl/certs/ca-certificates.crt --verify=no_ocsp
```
## Certificate mapping
### For local users
When using only local users, sssd can be easily configured to define an `implicit_domain` that maps all the local users.
Certificate mapping for local users it can be easily done using the certificate Subject check, in my case:
```bash
openssl x509 -noout -subject -in card-CERT.pem | sed "s/, /,/g;s/ = /=/g"
subject=C=IT,O=Actalis S.p.A.,OU=REGIONE TOSCANA,CN=TRVMRC[...data-removed...]/6090010669298009.YOrY0zOk5CdMby2Z2O/HnVRA8Ao=,GN=MARCO,SN=TREVISAN
```
So I can use
```ini
[sssd]
enable_files_domain = True
services = pam
[certmap/implicit_files/marco]
matchrule = <SUBJECT>.*CN=TRVMRC[A-Z0-9]+/6090010669298009\.YOrY0zOk5CdMby2Z2O/HnVRA8Ao.*
[pam]
pam_cert_auth = True
```
That can be tested working in versions newer than Ubuntu 20.04 with:
```bash
sudo dbus-send --system --print-reply \
--dest=org.freedesktop.sssd.infopipe \
/org/freedesktop/sssd/infopipe/Users \
org.freedesktop.sssd.infopipe.Users.ListByCertificate \
string:"$(cat card-CERT.pem)" uint32:10
# returns...
method return time=1605127192.698667 sender=:1.1628 -> destination=:1.1629 serial=6 reply_serial=2
array [
object path "/org/freedesktop/sssd/infopipe/Users/implicit_5ffiles/1000"
]
```
### Other mappings
Mapping for more complicated configurations can be done following the official [SSSD documentation](https://sssd.io/docs/design_pages/certmaps_for_LDAP_AD_file.html).
## Basic SSSD configuration
The SSSD configuration for accessing to the system is out of the scope of this document, however for smartcard access it should contain at least such values:
```ini
[sssd]
# Comma separated list of domains
;domains = your-domain1, your-domain2
# comma-separated list of SSSD services
# pam might be implicitly loaded already, so the line is optional
services = pam
# You can enable debug of the SSSD daemon
# Logs will be in /var/log/sssd/sssd.log
;debug_level = 10
# A mapping between the SC certificate and users
;[certmap/your-domain1/<username>]
;matchrule = <SUBJECT>.*CN=TRVMRC[A-Z0-9]+/6090010669298009\.YOrY0zOk5CdMby2Z2O/HnVRA8Ao.*
[pam]
pam_cert_auth = True
# The Certificate DB to be used:
# - Needs to be an openSSL certs file starting Ubuntu 20.10
# - Needs to be an NSS database for Ubuntu 20.4
;pam_cert_db_path = /etc/ssl/certs/ca-certificates.crt
# You can enable debug infos for the PAM module
# Logs will be in /var/log/sssd/sssd_pam.log
# p11 child logs are in /var/log/sssd/p11_child.log
# standard auth logs are in /var/log/auth.log
;pam_verbosity = 10
;debug_level = 10
```
In general what's in the configuration file will affect the way SSSD will call the `p11_child` tool (that is the one in charge for the actual authentication).
Check `man sssd.conf` for details.
Remember that this file should be owned by `root` and have permission set to `600`, otherwise won't be loaded and SSSD will not complain gracefully.
On errors you can test running SSSD temporary with `sudo sssd -d9 -i`.
Every time the configuration is changed sssd should be restarted (`systemctl restart sssd`).
You can see a working example for the [local users case here](#For-local-users).
## GDM / GSD configuration
GDM needs pam configuration files, those are not shipped by default until Ubuntu 21.04, so they need to be manually created.
Other than that, GDM and gnome-settings-daemon can be configured to enforce further checks
### For smartcard access with password fallback
```bash
cat << EOF | sudo tee -a /etc/pam.d/gdm-smartcard-optional
#%PAM-1.0
auth requisite pam_nologin.so
auth required pam_succeed_if.so user != root quiet_success
auth sufficient pam_sss.so allow_missing_name try_cert_auth
auth optional pam_gnome_keyring.so
@include common-auth
@include common-account
#account [default=bad success=ok user_unknown=ignore] pam_sss.so
# SELinux needs to be the first session rule. This ensures that any
# lingering context has been cleared. Without this it is possible
# that a module could execute code in the wrong domain.
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
session required pam_loginuid.so
# SELinux needs to intervene at login time to ensure that the process
# starts in the proper default security context. Only sessions which are
# intended to run in the user's context should be run after this.
# pam_selinux.so changes the SELinux context of the used TTY and configures
# SELinux in order to transition to the user context with the next execve()
# call.
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
session optional pam_keyinit.so force revoke
session required pam_limits.so
session required pam_env.so readenv=1
session required pam_env.so readenv=1 user_readenv=1 envfile=/etc/default/locale
password required pam_sss.so
@include common-session
session optional pam_gnome_keyring.so auto_start
EOF
```
Then set it as default with:
```bash
sudo ln -sfv /etc/pam.d/gdm-smartcard-optional /etc/pam.d/gdm-smartcard
```
### For smartcard-only access
```cat << EOF | sudo tee -a /etc/pam.d/gdm-smartcard-required
#%PAM-1.0
auth requisite pam_nologin.so
auth required pam_succeed_if.so user != root quiet_success
auth required pam_sss.so allow_missing_name
auth optional pam_gnome_keyring.so
@include common-account
#account [default=bad success=ok user_unknown=ignore] pam_sss.so
# SELinux needs to be the first session rule. This ensures that any
# lingering context has been cleared. Without this it is possible
# that a module could execute code in the wrong domain.
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
session required pam_loginuid.so
# SELinux needs to intervene at login time to ensure that the process
# starts in the proper default security context. Only sessions which are
# intended to run in the user's context should be run after this.
# pam_selinux.so changes the SELinux context of the used TTY and configures
# SELinux in order to transition to the user context with the next execve()
# call.
session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
session optional pam_keyinit.so force revoke
session required pam_limits.so
session required pam_env.so readenv=1
session required pam_env.so readenv=1 user_readenv=1 envfile=/etc/default/locale
@include common-session
session optional pam_gnome_keyring.so auto_start
EOF
```
Then set it as default with:
```bash
sudo ln -sfv /etc/pam.d/gdm-smartcard-required /etc/pam.d/gdm-smartcard
```
### Choose the GDM method
Once the two PAM configuration are installed, the preferred can be configured globally making the `/etc/pam.d/gdm-smartcard` symlink to point to the choosen one
### Disable password access
```bash
sudo -u gdm env DCONF_PROFILE=gdm gsettings set org.gnome.login-screen enable-password-authentication false
```
### Set action on card removal
#### User setting
This can be configured at user level for each user by just changing this gsettings key:
```bash
# Valid values can be 'none', 'lock-screen' or 'force-logout'
gsettings set org.gnome.settings-daemon.peripherals.smartcard removal-action 'lock-screen'
```
#### Global settings
This value can be locked down at user level by creating these files:
```bash
cat << EOF | sudo tee -a /etc/dconf/profile/user
user-db:user
system-db:local
EOF
sudo mkdir -p /etc/dconf/db/local.d/locks
cat << EOF | sudo tee -a /etc/dconf/db/local.d/00_gdm-smartcard-action
[org/gnome/settings-daemon/peripherals/smartcard]
# 'lock-screen' or 'force-logout' or 'none'
removal-action='lock-screen'
EOF
cat << EOF | sudo tee -a /etc/dconf/db/local.d/locks/00_gdm-smartcard-action
# Make action non-user configurable
/org/gnome/settings-daemon/peripherals/smartcard/removal-action
EOF
# Update system db
sudo dconf update
```
Read more in the [GNOME documentation](https://help.gnome.org/admin/system-admin-guide/stable/dconf-lockdown.html.en) or in `man dconf.7`.
These files can be safely removed to disable the lockdown (including the `profile/user` one, if no other override/lock is set).
### Troubleshooting
`pamtester` is your friend!
To get better debug logging, also enable it changing `/etc/sssd/sssd.conf` so that it has:
```ini
[pam]
pam_verbosity = 10
debug_level = 10
```
And `/etc/gdm3/custom.conf` with:
```ini
[debug]
Enable=true
```
You can use it to check your configuration without having to login/logout for real, by just using:
```bash
# Install it!
sudo apt install pamtester
# Run the authentication service as standalone
pamtester -v gdm-smartcard $USER authenticate
# Run the authentication service to get user from cert
pamtester -v gdm-smartcard "" authenticate
# You can check what happened in the logs, reading:
sudo less /var/log/auth.log
sudo less /var/log/sssd/sssd_pam.log
sudo less /var/log/sssd/p11_child.log
```
## Work Items
### Add PAM profiles to debian's GDM
There are currently two methdos that gdm would support
- [pam_pkcs11](https://github.com/OpenSC/pam_pkcs11)
- [pam_sss](https://sssd.io/) (SSSD PAM module)
So in debian we could provide two more packages
- `gdm3-smartcard-sssd` (depends on `libpam_sss`)
- installing `/etc/pam.d/gdm-smartcard-sssd`
- `gdm3-smartcard-pkcs11` (depends on `libpam-pkcs11`)
- installing `/etc/pam.d/gdm-smartcard-pkcs11`
### Rewrite g-s-d smartcard module to use p11-kit
This another legacy from RH usage, SSSD is not using anymore NSS for device listing, so g-s-d should not.
There's a long standing [upstream issue](https://gitlab.gnome.org/GNOME/gnome-settings-daemon/-/issues/260), and I'm working on it.
- [Merge Request](https://gitlab.gnome.org/GNOME/gnome-settings-daemon/-/merge_requests/208)
### Add `gdm-auth-config` tool upstream
Write a tool that will handle all the configurations parameters so that there's less manual intervention when it comes to GDM configuration, with an interface such as:
```bash
gdm-auth-config smartcard --{enable, disable, required}
[--removal-action=lock-screen|log-out|none|user-defined ]
gdm-auth-config fingerprint --{enable, disable}
gdm-auth-config password --{enable, disable}
gdm-auth-config show
```
- [Merge Request](https://gitlab.gnome.org/GNOME/gdm/-/merge_requests/125)
### Make SSSD to use OpenSSL in 20.04
Also according his debian maintainer, there's no drawback, as it right now points to an NSS database that simply never existed in Ubuntu and that's a Fedora/RH-ism, so nothing should depend on it right now.
Not to mention that [**NSS support has been dropped** completely from current SSSD](https://github.com/SSSD/sssd/commit/266ecc083d5fe9f576b7932a80ecb014d2d25311#diff-0462e381b2fb3286568215681c8983490a37ac9ae0f0c5ee304df7fa6426d4afL4756).
So [dropping NSS in favour of OpenSSL](https://salsa.debian.org/sssd-team/sssd/-/commit/f4f7bfee91e9aa929585b95e5c579597d0ab156b) in 20.04 would make possible to have just one way to configure SSSD that will persist across LTSes, and avoid [*hacks*](#NSS-Database-to-be-deprecated-post-2004).
In the worst case, it would technically possible also to just ship the `p11_child` component (the only one used for the SC auth) to be compiled using openssl instead.
- [Example of `p11_child`-only OpenSSL based](https://salsa.debian.org/3v1n0-guest/sssd/-/commits/p11-kit-p11_child)
- [Merge request](https://code.launchpad.net/~3v1n0/ubuntu/+source/sssd/+git/sssd/+merge/395411) to get SSSD to use OpenSSL and convert old nss-database to PEM-chain.
### Bugs
- Looks like gnome-shell doesn't select automatically the user associated with the card, so one needs to type it. Something I still have to debug.
- In 20.04 CA-verification of the card may not work as expected, even though the manual `p11_child` check works