** Description changed: [Impact] If you enable smartcard authentication on Ubuntu Desktop on Jammy, and set it up so the smartcard must be present for all authentication attempts, enforced by PAM's require_cert_auth, if you remove the smartcard, it will fall back to password authentication. What is worse is that the password authentication will work, skipping the point of having a smartcard in the first place. require_cert_auth should enforce the smartcard be present, and should not fallback to password authentication. [Testcase] This testcase is courtesy of Fabio Miranda Martins, who diligently researched and explained it in excellent detail. In order to reproduce the issue following the same steps as I'm using, you will need at least one Windows Active Directory enabled with Active Directory Certificate Services [1] and one Yubikey to be used as a smartcard [2], but it should be possible to reproduce the same problem with any smartcard and most likely any sort of smartcard based authentication using SSSD [3] [4]. [1] https://learn.microsoft.com/en-us/windows-server/identity/ad-cs/active-directory-certificate-services-overview [2] https://www.yubico.com/ [3] https://ubuntu.com/server/docs/smart-card-authentication [4] https://ubuntu.com/tutorials/how-to-use-smart-card-authentication-in-ubuntu-desktop#1-overview Launch one Jammy desktop and one Noble desktop VMs, so you can compare the behavior on both, and then: 0. Prereqs and Joining the Domain: - sudo add-apt-repository ppa:yubico/stable - sudo apt-get update - sudo apt upgrade -y - sudo apt install libpam-sss opensc-pkcs11 pcscd libpam-pkcs11 sssd opensc sssd-dbus sssd-tools yubico-piv-tool sssd-ad realmd adcli vim krb5-user krb5-pkinit -y - - sudo realm -v discover <domain controller> - sudo realm -v join <domain controller> - + sudo add-apt-repository ppa:yubico/stable + sudo apt-get update + sudo apt upgrade -y + sudo apt install libpam-sss opensc-pkcs11 pcscd libpam-pkcs11 sssd opensc sssd-dbus sssd-tools yubico-piv-tool sssd-ad realmd adcli vim krb5-user krb5-pkinit -y + + sudo realm -v discover <domain controller> + sudo realm -v join <domain controller> + 1. Generate a private key: - yubico-piv-tool -a generate -s 9a -A RSA2048 -o fabiopub.key + yubico-piv-tool -a generate -s 9a -A RSA2048 -o fabiopub.key 2. Generate a CSR: - yubico-piv-tool -a verify-pin -a request-certificate -s 9a -S + yubico-piv-tool -a verify-pin -a request-certificate -s 9a -S '/CN=Fabio Martins/OU=Users/O=fabiomirmar.net/' -i fabiopub.key -o fabiocsr.pem 3. cat the content of fabiocsr.pem and paste into the Active Directory Certificate Services website to issue the certificate (https://<active_directory_ip_address>/certsrv/). Make sure to login as the Domain user for which you want to issue the certificate. Click Request a certificate, advanced certificate request, and paste the content of the csr file. 4. Download the certificate and the CA from the tool and save back into the Ubuntu VM 5. Convert the certificate to pem format: - openssl x509 -in ./fabioissued.cer -out fabioissued.pem -outform pem + openssl x509 -in ./fabioissued.cer -out fabioissued.pem -outform pem 6. Make sure it looks OK: - cat fabioissued.pem | openssl x509 -text -noout + cat fabioissued.pem | openssl x509 -text -noout 7. If you need the certificate in der format for some reason you can use: - openssl x509 -in ./fabioissued.pem -out fabioissued.der -outform der + openssl x509 -in ./fabioissued.pem -out fabioissued.der -outform der 8. Import the certificate to yubikey: - yubico-piv-tool -a import-certificate -s 9a -k -i fabioissued.pem + yubico-piv-tool -a import-certificate -s 9a -k -i fabioissued.pem 9. You don't need to use ldapmodify to add the certificate to the user. You can query the user with ldapsearch and will notice that the certificate is already added by AD when it issued the certificate: - ldapsearch -x -H ldap://<domain controller> -D + ldapsearch -x -H ldap://<domain controller> -D "administra...@fabiomirmar.net" -W -b "CN=Fabio Martins,CN=Users,DC=fabiomirmar,DC=net" 10. If you would like to confirm that the certificate in the ldapsearch output matches the one you downloaded from ADCS, you can save the content from the userCertificate field into a tempfile. That's a base64 encoded DER formatted certificate. Then you can convert from DER to PEM and compare (they should match): - cat ldapcertoutput.base64 | tr -d '\n' | base64 -d > ldapcertoutput.der - openssl x509 -in ./ldapcertoutput.der -out ldapcertoutput.pem -outform pem - diff ldapcertoutput.pem fabioissued.pem + cat ldapcertoutput.base64 | tr -d '\n' | base64 -d > ldapcertoutput.der + openssl x509 -in ./ldapcertoutput.der -out ldapcertoutput.pem -outform pem + diff ldapcertoutput.pem fabioissued.pem 11. Make sure the certificate from yubikey looks correct: - pkcs15-tool --read-certificate 1 > card-cert.pem - openssl x509 -text -noout -in card-cert.pem + pkcs15-tool --read-certificate 1 > card-cert.pem + openssl x509 -text -noout -in card-cert.pem 12. When you downloaded the CA certificate, it was provided in a DER format. Convert it to PEM: - openssl x509 -in ./cacert.cer -out cacert.crt -outform pem + openssl x509 -in ./cacert.cer -out cacert.crt -outform pem 13. Add the CA to the Ubuntu VM: - sudo cp cacert.crt /usr/local/share/ca-certificates/ - sudo update-ca-certificates + sudo cp cacert.crt /usr/local/share/ca-certificates/ + sudo update-ca-certificates 14. This is duplicate effort, but you can also add to the CA file being used by SSSD and kerberos. In our Lab: - sudo mkdir /etc/sssd/pki/ - cat cacert.crt | sudo tee -a /etc/sssd/pki/sssd_auth_ca_db.pem + sudo mkdir /etc/sssd/pki/ + cat cacert.crt | sudo tee -a /etc/sssd/pki/sssd_auth_ca_db.pem 15. Check that openssl is able to validate the certificate against the CA: - openssl verify -verbose card-cert.pem - openssl verify -verbose -CAfile /etc/sssd/pki/sssd_auth_ca_db.pem card-cert.pem + openssl verify -verbose card-cert.pem + openssl verify -verbose -CAfile /etc/sssd/pki/sssd_auth_ca_db.pem card-cert.pem Both should say "OK" 16. Make sure you configure sssd.conf with the appropriate certmap. This is how my file look like: - [pam] - pam_cert_auth = True - pam_cert_db_path = /etc/sssd/pki/sssd_auth_ca_db.pem - - [certmap/fabiomirmar.net/fabio] - matchrule = <SUBJECT>CN=Fabio.* - maprule = (userCertificate;binary={cert!bin}) - - [sssd] - certificate_verification = partial_chain - domains = fabiomirmar.net - config_file_version = 2 - services = nss, pam - default_domain_suffix = fabiomirmar.net - - [domain/fabiomirmar.net] - default_shell = /bin/bash - ad_server = <domain controller> - krb5_store_password_if_offline = True - cache_credentials = True - krb5_realm = FABIOMIRMAR.NET - realmd_tags = manages-system joined-with-adcli - id_provider = ad - fallback_homedir = /home/%u - ad_domain = fabiomirmar.net - use_fully_qualified_names = True - ldap_id_mapping = True - access_provider = ad + [pam] + pam_cert_auth = True + pam_cert_db_path = /etc/sssd/pki/sssd_auth_ca_db.pem + + [certmap/fabiomirmar.net/fabio] + matchrule = <SUBJECT>CN=Fabio.* + maprule = (userCertificate;binary={cert!bin}) + + [sssd] + certificate_verification = partial_chain + domains = fabiomirmar.net + config_file_version = 2 + services = nss, pam + default_domain_suffix = fabiomirmar.net + + [domain/fabiomirmar.net] + default_shell = /bin/bash + ad_server = <domain controller> + krb5_store_password_if_offline = True + cache_credentials = True + krb5_realm = FABIOMIRMAR.NET + realmd_tags = manages-system joined-with-adcli + id_provider = ad + fallback_homedir = /home/%u + ad_domain = fabiomirmar.net + use_fully_qualified_names = True + ldap_id_mapping = True + access_provider = ad 17. Make sure to configure krb5.conf correctly: NOTE: Setting pkinit_kdc_hostname and pkinit_eku_checking were required for this to work. Depending on the ADCS / Certificate configuration, you might not need this: - # cat /etc/krb5.conf - - [libdefaults] - udp_preference_limit = 0 - default_realm = FABIOMIRMAR.NET - pkinit_anchors = FILE:/etc/sssd/pki/sssd_auth_ca_db.pem - pkinit_kdc_hostname = <domain controller> - pkinit_eku_checking = none - #rdns = false - #dns_lookup_realm = false - - [domain_realm] - - [plugins] - localauth = { - module = sssd:/usr/lib/x86_64-linux-gnu/sssd/modules/sssd_krb5_localauth_plugin.so - } + # cat /etc/krb5.conf + + [libdefaults] + udp_preference_limit = 0 + default_realm = FABIOMIRMAR.NET + pkinit_anchors = FILE:/etc/sssd/pki/sssd_auth_ca_db.pem + pkinit_kdc_hostname = <domain controller> + pkinit_eku_checking = none + #rdns = false + #dns_lookup_realm = false + + [domain_realm] + + [plugins] + localauth = { + module = sssd:/usr/lib/x86_64-linux-gnu/sssd/modules/sssd_krb5_localauth_plugin.so + } 18. Configure PAM: - For noble: - $ sudo pam-auth-update --disable sss-smart-card-optional --enable + $ sudo pam-auth-update --disable sss-smart-card-optional --enable sss-smart-card-required - For jammy: Edit /etc/pam.d/common-auth and add: + + auth [success=3 ignore=ignore default=die] pam_sss.so + allow_missing_name require_cert_auth + + The order matters, and I've been using the exact same order as we get in + noble. Example: + + ubuntu@jammy-desktop:~$ sudo cat /etc/pam.d/common-auth + # here are the per-package modules (the "Primary" block) + auth [success=3 ignore=ignore default=die] pam_sss.so allow_missing_name require_cert_auth + auth [success=2 default=ignore] pam_unix.so nullok + auth [success=1 default=ignore] pam_sss.so use_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 + + Also on both jammy and noble, configure pam to automatically create the + home directory: + + sudo pam-auth-update --enable mkhomedir + + 19. Restart SSSD + + systemctl restart sssd + + 20. Check that the certmap is working: + + pkcs15-tool --read-certificate 1 > card-cert.pem + + 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 + + Now you should be able to login both on console and GDM using the + smartcard. + + After loging in using GDM, open a terminal and try to run a sudo + command: + + - Noble: + + fa...@fabiomirmar.net@noble-desktop2:~$ sudo -i + PIN for Users: + fa...@fabiomirmar.net is not in the sudoers file. + + - Jammy: + + fa...@fabiomirmar.net@jammy-desktop:~$ sudo -i + PIN for Users: + fa...@fabiomirmar.net is not in the sudoers file. This incident will be reported. + + So far so good. Now, remove the smartcard and try again: + + - Noble: + + fa...@fabiomirmar.net@noble-desktop2:~$ sudo -i + Please insert smart card + Please (re)insert (different) Smartcard + Please (re)insert (different) Smartcard + + - Jammy: + + fa...@fabiomirmar.net@jammy-desktop:~$ sudo -i + Please insert smart card + [sudo] password for fa...@fabiomirmar.net: + fa...@fabiomirmar.net is not in the sudoers file. This incident will be reported. + + As you can see from above, on Jammy it fallsback to password based + authentication, and that works if you type the correct password. + + If you enable the following ppa, the issue is fixed and jammy now + behaves like Kinetic or later. + + https://launchpad.net/~mruffell/+archive/ubuntu/sf395104-test + + ubuntu@jammy-desktop:~$ apt-cache policy sssd | grep Installed + Installed: 2.6.3-1ubuntu3.3+sf395104v20240916b1 + + fa...@fabiomirmar.net@jammy-desktop:~$ sudo -i + Please insert smart card + Please (re)insert (different) Smartcard + Please (re)insert (different) Smartcard + + Additional testcase, covering (f) of comment #2: + + Remove smartcard requirement, and go back to password authentication: + + Run: + + sudo update-alternatives --set gdm-smartcard /etc/pam.d/gdm-smartcard-sssd-or-password + + And then also comment out the following line in /etc/pam.d/common-auth: auth [success=3 ignore=ignore default=die] pam_sss.so allow_missing_name require_cert_auth - The order matters, and I've been using the exact same order as we get in - noble. Example: - - ubuntu@jammy-desktop:~$ sudo cat /etc/pam.d/common-auth - # here are the per-package modules (the "Primary" block) - auth [success=3 ignore=ignore default=die] pam_sss.so allow_missing_name require_cert_auth - auth [success=2 default=ignore] pam_unix.so nullok - auth [success=1 default=ignore] pam_sss.so use_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 - - Also on both jammy and noble, configure pam to automatically create the - home directory: - - sudo pam-auth-update --enable mkhomedir - - 19. Restart SSSD - - systemctl restart sssd - - 20. Check that the certmap is working: - - pkcs15-tool --read-certificate 1 > card-cert.pem - - 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 - - Now you should be able to login both on console and GDM using the - smartcard. - - After loging in using GDM, open a terminal and try to run a sudo - command: - - - Noble: - - fa...@fabiomirmar.net@noble-desktop2:~$ sudo -i - PIN for Users: - fa...@fabiomirmar.net is not in the sudoers file. - - - Jammy: - - fa...@fabiomirmar.net@jammy-desktop:~$ sudo -i - PIN for Users: - fa...@fabiomirmar.net is not in the sudoers file. This incident will be reported. - - So far so good. Now, remove the smartcard and try again: - - - Noble: - - fa...@fabiomirmar.net@noble-desktop2:~$ sudo -i - Please insert smart card - Please (re)insert (different) Smartcard - Please (re)insert (different) Smartcard - - - Jammy: - - fa...@fabiomirmar.net@jammy-desktop:~$ sudo -i - Please insert smart card - [sudo] password for fa...@fabiomirmar.net: - fa...@fabiomirmar.net is not in the sudoers file. This incident will be reported. - - As you can see from above, on Jammy it fallsback to password based - authentication, and that works if you type the correct password. - - If you enable the following ppa, the issue is fixed and jammy now - behaves like Kinetic or later. - - https://launchpad.net/~mruffell/+archive/ubuntu/sf395104-test - - ubuntu@jammy-desktop:~$ apt-cache policy sssd | grep Installed - Installed: 2.6.3-1ubuntu3.3+sf395104v20240916b1 - - fa...@fabiomirmar.net@jammy-desktop:~$ sudo -i - Please insert smart card - Please (re)insert (different) Smartcard - Please (re)insert (different) Smartcard + Attempt a login through SSH, sudo, and GDM. All authentication attempts + should be presented with a password prompt, and domain password should + succeed. [Where problems could occur] We are changing the behaviour of require_cert_auth to actually do what it says on the tin, which is to enforce that the smartcard is present, and has the correct certificate in order for authentication to succeed. require_cert_auth works in some cases, namely at the GDM login screen, but doesn't in other places, like sudo. The changes to require_cert_auth could potentially lock users out of their systems, if they were relying on the broken behaviour of password fallbacks. Users of these systems should hopefully have their smartcard present and working in order to log in. If they don't, they will be locked out of their systems. It is very difficult to estimate if there is anyone relying on faulty behaviour. Since this changes how smartcards authenticate, if a regression were to occur, it could affect anyone that uses smartcards with sssd / libpam- sss. [Other info] Upstream bug: https://github.com/SSSD/sssd/issues/6022 https://github.com/SSSD/sssd/issues/6023 Commits that fix the issue, landed in 2.7.0 present in Kinetic or later. commit 731b3e668c6a659922466aee7fa8093412707325 Author: Sumit Bose <sb...@redhat.com> Date: Tue Apr 13 17:12:24 2021 +0200 Subject: pam: add more checks for require_cert_auth Link: https://github.com/SSSD/sssd/commit/731b3e668c6a659922466aee7fa8093412707325 commit 4d2277f8c3065771a8c3bbc7938309a4905640f0 Author: Sumit Bose <sb...@redhat.com> Date: Mon Feb 21 18:02:47 2022 +0100 Subject: pam: better SC fallback message Link: https://github.com/SSSD/sssd/commit/4d2277f8c3065771a8c3bbc7938309a4905640f0
-- You received this bug notification because you are a member of Ubuntu Bugs, which is subscribed to Ubuntu. https://bugs.launchpad.net/bugs/2081129 Title: libpam-sss: require_cert_auth is not absolute, will fall back to password auth on smartcard removal To manage notifications about this bug go to: https://bugs.launchpad.net/ubuntu/+source/sssd/+bug/2081129/+subscriptions -- ubuntu-bugs mailing list ubuntu-bugs@lists.ubuntu.com https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs