Skip to content

pam_pkcs11 0.6.12 allows authentication bypass in error situations

Critical
frankmorgner published GHSA-7mf6-rg36-qgch Feb 8, 2025

Package

pam_pkcs11.so

Affected versions

0.6.12

Patched versions

None

Description

Hello pam_pkcs11 maintainers,

I am reporting to you a likely security issue in pam_pkcs11 introduced
in version 0.6.12. The details about the issue follow further below.

By now I have the impression that there is no active pam_pkcs11
maintainer. To prevent further loss of time please reply by
Thursday Nov 14 to confirm the report and to state the further
process. If there is no process established by then, then I will
share the information with the linux-distros mailing list and grant a
7 day embargo until all information will be published.

Coordinated Disclosure

We offer coordinated disclosure for security findings based on our disclosure
policy 1. For the coordinated disclosure process please answer the
following questions for us:

  • Do you want to perform coordinated disclosure? If yes, then please
    communicate your desired coordinated release date (CRD) for publishing the
    security issues and any patches/updates. We offer to keep the issue
    private for up to 90 days (resulting in publication latest on 2025-02-09),
    but prefer to maintain shorter time frames of about two weeks, if
    possible.

    If you don't want to perform coordinated disclosure then we will immediately
    publish all information we have on the oss-security mailing list 2 and in
    our bug tracker. For this issue we suggest to have at least a 7 day embargo
    on the linux-distros mailing list, though, since other distributors might be
    affected.

  • Do you acknowledge the individual findings? If so, will you assign CVE
    identifiers for the security issues? If yes, then please share the CVEs with
    us once they are assigned. Otherwise we can offer to request CVEs for you
    from the Mitre corporation.

Context of the Finding

Fellow SUSE engineer Marcus Rückert uses a YubiKey for login at his Linux
desktop. He recently noticed a change in behaviour in his GDM login setup. By
digging a bit deeper he noticed that in some situations login is possible
without entering a password or using the YubiKey at all.

There is a bug (or a feature?) in GDM 3 that causes YubiKeys to be treated
as smart cards, so this is one ingredient that seems to have come into play
here. It still didn't explain why login without a password has become
possible.

A number of Linux distributions use a dedicated gdm-smartcard PAM stack
configuration file for smartcard login in GDM. On openSUSE we rely on
pam_pkcs11 as the sole (proper) authentication module in this gdm-smartcard
configuration 4. It took me a long time to understand where exactly this
gdm-smartcard PAM stack is used in GDM. The logic to select this PAM stack
is found in a wholly different Gnome component, in gnome-shell 5. There some
JavaScript is responsible for detecting smart cards via the D-Bus interface of
the gnome-settings-daemon and to change the authentication mode of GDM.

I reproduced the situation by using smartcard emulation in a QEMU Virtual
machine, to be able to achieve proper smartcard detection in both GDM
and pam_pkcs11. As soon as the smartcard is properly setup in the system,
GDM switches into smartcard authentication mode (support for this is enabled
by default). A user list is no longer shown, but the username has to be
entered manually. After entering the username, the gdm-smartcard PAM stack is
executed, and with it pam_pkcs11. No password is asked for and login
succeeds.

In my setup, as well as in the real life setup using a YubiKey, pam_pkcs11
stops execution after logging "Failed to initialize crypto". After this, the
login succeeds. As I see it, the reason for this lies in pam_pkcs11, as
described in the next section.

I did not investigate why exactly this error condition occurs in the test setup or when
using a YubiKey, as I don't believe it matters (for security). Even when errors occur, the
outcome of the PAM stack execution shouldn't allow authentication without providing
credentials.

PAM_IGNORE Return Paths in pam_sm_authenticate()

The login without proper authentication seems to stem from a change that found
its way into pam_pkcs11 version 0.6.12. The following statements are based
on the Git tag pam_pkcs11-0.6.12. The code in pam_pkcs11.c has not seen
many changes since that tag, mostly in the area of fixing memory leaks, so
most of what follows should still apply to the master branch of the
repository.

I believe the issue has been introduced with commit bac6cf8 (note that
there seems to be some artifact in the Git repository: there exists a
seemingly identical commit 88a87d5 in the commit log on master).

The code in pam_pkcs11.c line 284 means that, if there is no login token name
(i.e. no login happened yet), the default return code on error
conditions will be PAM_IGNORE:

  if (!configuration->card_only || !login_token_name) {
	  /* Allow to pass to the next module if the auth isn't
         restricted to card only. */
      pkcs11_pam_fail = PAM_IGNORE;
  } else {
	pkcs11_pam_fail = PAM_CRED_INSUFFICIENT;
  }

Before this change the default return code was always PAM_CRED_INSUFFICIENT.
When a PAM module returns PAM_IGNORE, though, then this means that its
outcome should not be used to determine the result of the PAM stack execution.
As we use the required control setting for pam_pkcs11 in our
gdm-smartcard configuration, this is exactly what happens. In extended PAM
syntax required is expressed like this:

    required
        [success=ok new_authtok_reqd=ok ignore=ignore default=bad]

The required control setting here no longer does what it should when
the authentication using pam_pkcs11 fails in a lot of situations. Actually
only two return paths of pam_sm_authenticate() return anything else than
PAM_IGNORE at this point:

  • if pkcs11_login() fails
  • if verify_signature() fails

Both return paths will reset pkcs11_pam_fail to a safe PAM_AUTH_ERR value.

The following is a list of all the other return paths which will return
PAM_IGNORE:

  • line 305: if a user is logging in from remote, or can control the DISPLAY variable
    (e.g. in sudo context).
  • line 316: if the crypto_init() call fails.
  • line 328: if a screen saver context is detected and no login token is
    recorded, then an explicit jump to a PAM_IGNORE return is performed.
  • lines 343, 357: if loading or initializing the PKCS#11 module fails.
  • line 374: if the configured token is not found and card_only is not set.
    This might be okay in light of the semantics of card_only, but I still
    find it strange. If a system administrator wants to make pam_pkcs11
    authentication optional then he can do so by using the PAM stack configuration
    already. Changing the module result semantics this drastically through a PAM
    module parameter is unusual.
  • line 416: if no smart card is found even after potentially waiting for it.
  • if a smart card is found, but one of various PKCS11 functions or certificate
    checks fail, then further PAM_IGNORE returns can happen in:
    • line 432 open_pkcs11_session()
    • line 443 get_slot_login_required()
    • line 471 (when reading in a password fails)
    • line 486 (empty password was read without nullok set)
    • line 522 get_certificate_list()
    • line 597 pam_set_item(..., PAM_USER, ...)
    • line 613 match_user()
    • line 634 (no matching certificate found)
    • line 663 get_random_value()
    • line 677 sign_value()
    • line 776 close_pkcs11_session()

As a quick workaround to avoid the login without authentication I suggest to
use the following PAM configuration line instead:

auth       [success=ok default=bad]    pam_pkcs11.so        wait_for_card card_only

This way any other outcome than PAM_SUCCESS will mark the PAM stack
execution as bad and authentication will fail.

In the end I believe this needs to be fixed on source code level, though. The
PAM module should indicate a failure condition if errors occur, so that the
typical required control setting makes authentication fail. If
administrators want to ignore pam_pkcs11 instead, they can switch the
control field to optional or sufficient in the configuration, which will
similar effects.

Since there exist other distributions that ship similar gdm-smartcard PAM
configuration files as we do, I suggest to establish an embargo period of some
time (about two weeks) and prepare a bugfix release on your end. We can
involve the Linux distros mailing list to inform other Linux distributions
about the issue, before it becomes public, so they can prepare as well.

Situation on other Distributions

On current Fedora Linux pam_pkcs11 isn't used anymore for smart card
authentication, but pam_sss instead. So it's not affected, but maybe older
versions that are still in use.

The gdm-smartcard PAM stack relying on pam_pkcs11 is furthermore found in the
GDM repository for:

  • Linux from Scratch
  • Exherbo Linux
  • Arch Linux

LfS and Exherbo are pretty exotic. I tried reproducing the issue on Arch Linux.
While on Arch the gdm-smartcard stack is installed, there is no pam_pkcs11
package in the standard repositories. It can be installed from AUR, however.
When doing so and also installing the gdm and ccid packages, then the
basic security issue becomes possible as well. I only tested this in a crafted
sudo PAM stack, though, since I did not manage to get gdm into smart
card authentication mode on Arch Linux. It seems some ingredient was still
missing to trigger that.

On Arch Linux I also noticed that the AUR pam_pkcs11 package does not
place any default pam_pkcs11.conf file into /etc. This also avoids the
security problem, because when slot_num == -1 then pam_sm_authenticate()
will return early with PAM_CRED_UNAVAIL. On OpenSUSE we do ship
a default configuration with slot_num = 0, however.

Generally any setup where pam_pkcs11 is the only decisive auth
module and where a basic pam_pkcs11.conf is around it will likely be
possible to insert a faulty / invalid smart card and gain access without proper
authorization.

Severity

Critical

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Local
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

CVE ID

CVE-2025-24531

Weaknesses

No CWEs

Credits