Skip to content

Conversation

@ikerexxe
Copy link
Contributor

@ikerexxe ikerexxe commented Oct 3, 2024

Expand the passkey_child to detect whether a FIDO2 device needs a PIN
and the number of attempts left for the PIN. This is needed to improve
the overall user experience by providing a way for SSSD to detect these
features before the user is requested to interact with them.

Expected input to run passkey_child: --preflight, --domain and
--key-handle.

Output: whether PIN is needed (boolean) and number of PIN attempts left
(integer) in JSON. Example:
{"pin_required": true, "attempts": 8}

@ikerexxe ikerexxe added Waiting for review passkey Issues and PRs related to 'passkey' feature labels Oct 3, 2024
@ikerexxe ikerexxe force-pushed the passkey_pin branch 2 times, most recently from ad8168c to fdb0520 Compare October 3, 2024 11:10
@ikerexxe ikerexxe changed the title Passkey pin passkey: implement preflight option Oct 3, 2024
@alexey-tikhonov
Copy link
Member

Isn't this ("whether PIN is needed and number of PIN attempts left") security sensitive information?

@ikerexxe
Copy link
Contributor Author

ikerexxe commented Oct 3, 2024

Yes, but there's nothing an attacker can do that they couldn't do before knowing that information. Moreover, this information can be obtained by other tools already present in the system.

Generally speaking, if an attacker wants to block a given FIDO2 key, then they just need to enter the PIN at most 8 times incorrectly, as that's the maximum number. As for the PIN request, they can always try to authenticate once and enter an empty PIN to see whether that's accepted.

&& (data->domain == NULL || data->public_key_list == NULL
|| data->key_handle_list == NULL)) {
DEBUG(SSSDBG_OP_FAILURE,
"Too few arguments for preflight action.\n");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK there is no way to tell what arguments should be provided to passkey_child --preflight

/usr/libexec/sssd/passkey_child --preflight --help does not say and /usr/libexec/sssd/passkey_child only prints Invalid argument(s).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as with other options. In this particular case this option is going to be executed by SSSD and not by the user, so I don't see a reason why we should indicate which options are missing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me this seems like we are hiding how to actually use passkey_child inside SSSD codebase. At least for troubleshooting some users may end up wanting to execute passkey_child directly outside of SSSD. I don't insist about it, maybe we can create a separate ticket to improve this.

For comparison I noticed p11_child provides some hints about which arguments are missing.

justin@fedora:~$ /usr/libexec/sssd/p11_child --auth

Missing CA DB path: --ca_db must be specified.

Usage: p11_child [-?] [-?|--help] [--usage] [-d|--debug-level=INT] [--debug-timestamps=INT] [--debug-microseconds=INT] [--dumpable=INT] [--debug-fd=INT] [--logger=stderr|files|journald] [--auth] [--pre] [--wait_for_card]
        [--verification] [--pin] [--keypad] [--verify=STRING] [--ca_db=STRING] [--module_name=STRING] [--token_name=STRING] [--key_id=STRING] [--label=STRING] [--certificate=STRING] [--uri=STRING] [--chain-id=LONG]
justin@fedora:~$ /usr/libexec/sssd/p11_child --ca_db test --auth

Missing PIN mode for authentication, either --pin or --keypad must be specified.
Usage: p11_child [-?] [-?|--help] [--usage] [-d|--debug-level=INT] [--debug-timestamps=INT] [--debug-microseconds=INT] [--dumpable=INT] [--debug-fd=INT] [--logger=stderr|files|journald] [--auth] [--pre] [--wait_for_card]
        [--verification] [--pin] [--keypad] [--verify=STRING] [--ca_db=STRING] [--module_name=STRING] [--token_name=STRING] [--key_id=STRING] [--label=STRING] [--certificate=STRING] [--uri=STRING] [--chain-id=LONG]

Copy link
Contributor

@justin-stephenson justin-stephenson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some comments/concerns. I'm not sure but perhaps a sssctl wrapper for the --preflight operation would be useful if we anticipate admins to request this information?

I also see some compiler warnings,:

../src/passkey_child/passkey_child_devices.c: In function ‘list_devices’:
../src/passkey_child/passkey_child_devices.c:54:12: warning: ‘ret’ may be used uninitialized [-Wmaybe-uninitialized]

passkey_child/passkey_child_devices.c: In function ‘get_device_pin_retries’:
../src/passkey_child/passkey_child_devices.c:267:12: warning: ‘ret’ may be used uninitialized [-Wmaybe-uninitialized]

@ikerexxe
Copy link
Contributor Author

ikerexxe commented Oct 4, 2024

Added some comments/concerns. I'm not sure but perhaps a sssctl wrapper for the --preflight operation would be useful if we anticipate admins to request this information?

I don't think this is specially useful for them. In fact, it is possible that at some point we will need to add options to look at these kinds of parameters, but not in this way. For now, let's be happy that there are already other tools that allow you to check these options.

I also see some compiler warnings,:

../src/passkey_child/passkey_child_devices.c: In function ‘list_devices’:
../src/passkey_child/passkey_child_devices.c:54:12: warning: ‘ret’ may be used uninitialized [-Wmaybe-uninitialized]

passkey_child/passkey_child_devices.c: In function ‘get_device_pin_retries’:
../src/passkey_child/passkey_child_devices.c:267:12: warning: ‘ret’ may be used uninitialized [-Wmaybe-uninitialized]

Fixed, and thanks for reporting them.

@ikerexxe
Copy link
Contributor Author

ikerexxe commented Oct 9, 2024

This is blocked by #7637

@ikerexxe
Copy link
Contributor Author

Although #7637 was clarified Justin still has to implement his part to make this PR meaningful, so for the moment I am moving to draft.

@ikerexxe ikerexxe marked this pull request as draft October 29, 2024 15:09
@ikerexxe ikerexxe force-pushed the passkey_pin branch 2 times, most recently from 58f1672 to e8f233d Compare May 7, 2025 09:01
@justin-stephenson
Copy link
Contributor

justin-stephenson commented May 14, 2025

Hi @ikerexxe

I found that passkey_child returns FIDO_ERR_PIN_AUTH_BLOCKED after 3 consecutive PIN failure attempts during passkey kerberos authentication

27:(2025-05-14 11:16:34): [passkey_child[758402]] [request_assert] (0x0040): fido_dev_get_assert failed [49]: FIDO_ERR_PIN_INVALID.
54:(2025-05-14 11:16:48): [passkey_child[758435]] [request_assert] (0x0040): fido_dev_get_assert failed [49]: FIDO_ERR_PIN_INVALID.
81:(2025-05-14 11:17:01): [passkey_child[758450]] [request_assert] (0x0040): fido_dev_get_assert failed [52]: FIDO_ERR_PIN_AUTH_BLOCKED.

then FIDO_ERR_PIN_BLOCKED after 8 total PIN attempt failures.

https://support.yubico.com/hc/en-us/articles/4402836718866-Understanding-YubiKey-PINs

If the FIDO2 PIN is entered incorrectly 3 times in a row, the key will need to be reinserted before it will accept additional PIN attempts (reinserting "reboots" the device). If the PIN is entered incorrectly a total of 8 times in a row, the FIDO2 function will become blocked, requiring that it be reset.

Can this --preflight operation check for this and return some output which indicates if the '3 consecutive PIN failure attempts' condition has occurred? This would allow prompting the user to remove and re-insert the Token, to continue PIN attempts until the total 8 attempts is reached.

@ikerexxe
Copy link
Contributor Author

Can this --preflight operation check for this and return some output which indicates if the '3 consecutive PIN failure attempts' condition has occurred? This would allow prompting the user to remove and re-insert the Token, to continue PIN attempts until the total 8 attempts is reached.

I think the idea is good, but is it doable? I don't see any API providing this information.

@justin-stephenson
Copy link
Contributor

Can this --preflight operation check for this and return some output which indicates if the '3 consecutive PIN failure attempts' condition has occurred? This would allow prompting the user to remove and re-insert the Token, to continue PIN attempts until the total 8 attempts is reached.

I think the idea is good, but is it doable? I don't see any API providing this information.

Maybe not, I don't know. The GUI Yubikey manager program shows this information but only after attempting a change PIN operation.

image

@ikerexxe
Copy link
Contributor Author

I have opened Yubico/libfido2#871 to discuss this topic with libfido2 community.

@ikerexxe
Copy link
Contributor Author

Yubico answered and there isn't any method in their API to manage whether a power cycle is required (this is the name of this functionality). Recent versions of CTAP (2.1) added an (optional) way of communicating whether a power cycle is required, but it isn't implemented neither in libfido2 nor in the devices themselves. Seeing that in addition YubiKey firmware is not upgradable I don't see any viable option in the near term to implement such a thing.

I opened https://issues.redhat.com/browse/RHELDOCS-20197 to update the documentation to take into account this scenario.

@sumit-bose
Copy link
Contributor

Hi,

@justin-stephenson mentioned earlier

I found that passkey_child returns FIDO_ERR_PIN_AUTH_BLOCKED after 3 consecutive PIN failure attempts during passkey kerberos authentication ... then FIDO_ERR_PIN_BLOCKED after 8 total PIN attempt failures.
Wouldn't it be possible to use those different error codes, maybe together with the number of remaining attempts to decide if the user should be asked to reinsert/power cycle the device?

bye,
Sumit

@ikerexxe
Copy link
Contributor Author

The logic Justin is referring to triggers after an authentication attempt. We need this specific step to occur before the attempt starts.

Putting this into the preflight would mean calling fido_dev_get_assert(), which would require the user PIN. This defeats the purpose of a preflight being a non-interactive check and something that happens in the background.

@justin-stephenson
Copy link
Contributor

Yubico answered and there isn't any method in their API to manage whether a power cycle is required (this is the name of this functionality). Recent versions of CTAP (2.1) added an (optional) way of communicating whether a power cycle is required, but it isn't implemented neither in libfido2 nor in the devices themselves. Seeing that in addition YubiKey firmware is not upgradable I don't see any viable option in the near term to implement such a thing.

I opened https://issues.redhat.com/browse/RHELDOCS-20197 to update the documentation to take into account this scenario.

Thank you for investigating this.

The logic Justin is referring to triggers after an authentication attempt. We need this specific step to occur before the attempt starts.

Putting the 'preflight' operation part aside, should we send some message to the terminal if passkey_child returns FIDO_ERR_PIN_AUTH_BLOCKED during authentication? Is something similar done for smartcard ?

@ikerexxe
Copy link
Contributor Author

Putting the 'preflight' operation part aside, should we send some message to the terminal if passkey_child returns FIDO_ERR_PIN_AUTH_BLOCKED during authentication? Is something similar done for smartcard ?

AFAIK, child processes return binary values (OK/ERROR) not the actual error codes. @sumit-bose can you confirm?

@sumit-bose
Copy link
Contributor

Putting the 'preflight' operation part aside, should we send some message to the terminal if passkey_child returns FIDO_ERR_PIN_AUTH_BLOCKED during authentication? Is something similar done for smartcard ?

AFAIK, child processes return binary values (OK/ERROR) not the actual error codes. @sumit-bose can you confirm?

Hi,

I think we currently only use EXIT_SUCCESS and EXIT_FAILURE with child processes from the SSSD tree but in general you can return more, like e.g. the sssd binary is doing it. See e.g. WEXITSTATUS() in man waitpid for details.

HTH

bye,
Sumit

@alexey-tikhonov
Copy link
Member

@ikerexxe, see

CA_DB_NOT_FOUND_EXIT_CODE = 50,

as an example.

@justin-stephenson
Copy link
Contributor

justin-stephenson commented May 28, 2025

Output: whether PIN is needed (boolean) and number of PIN attempts left (integer). Example: 1 8

@ikerexxe For consistency, can this output be provided in JSON? Something like...

{"pin_required": 1, "attempts": 8}

@ikerexxe
Copy link
Contributor Author

ikerexxe commented Jun 2, 2025

I have updated the code to return a special error code (PIN_AUTH_BLOCKED_EXIT_CODE) when the power cycle is required and the passkey output for the preflight option is formatted in JSON.

@ikerexxe For consistency, can this output be provided in JSON? Something like...

{"pin_required": 1, "attempts": 8}

Yes, but the final result is {“pin_required”: true, “attempts”: 8}

@justin-stephenson
Copy link
Contributor

@ikerexxe I created #7983 in Draft state to add the SSSD code to execute the passkey preflight operation. Please check it when you have time and feel free to comment in that PR.

ikerexxe added 4 commits June 30, 2025 11:27
Include a new man page for passkey to explain the behaviour of
`user_verification` option in the different scenarios. It is a complex
option, so it has been decided to add a table to simplify its
understanding.

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Timeout to search for a device should be imposed by the action that
wants to be performed. Thus, refactor the high level functions and
list_devices() to take it as an argument.

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
Expand the passkey_child to detect whether a FIDO2 device needs a PIN
and the number of attempts left for the PIN. This is needed to improve
the overall user experience by providing a way for SSSD to detect these
features before the user is requested to interact with them.

Expected input to run passkey_child: `--preflight`, `--domain` and
`--key-handle`.

Output: whether PIN is needed (boolean) and number of PIN attempts left
(integer) in JSON. Example:
{"pin_required": true, "attempts": 8}

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
When performing a passkey authentication and the PIN is entered 3 times
incorrectly the FIDO2 device requires a power cycle (disconnect and
reconnect the device to the USB port). libfido2 recognizes this with a
special error code and the passkey child should return it so that the
SSSD responder is aware of it.

Signed-off-by: Iker Pedrosa <ipedrosa@redhat.com>
@ikerexxe
Copy link
Contributor Author

ikerexxe commented Jul 1, 2025

This PR was superseded by #7983 so I'm closing it

@ikerexxe ikerexxe closed this Jul 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport-to-sssd-2-9 Blocked passkey Issues and PRs related to 'passkey' feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants