From: Bryan Jacobs Date: Tue, 16 Apr 2024 03:12:22 +0000 (+1000) Subject: cryptenroll: Use CTAP2.1 credProtect extension X-Git-Tag: v256-rc1~167 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=12cf745cceb3dfec858bab6152636e42f1c23bb9;p=thirdparty%2Fsystemd.git cryptenroll: Use CTAP2.1 credProtect extension When enrolling a new FIDO2 token with a client PIN, this tells the authenticator to require the PIN on all uses. It also collects a PIN before attempting to create a credential. Works around #31443 in most (not all) scenarios. --- diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c index 15b7e42c848..1cc81a6c610 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -40,6 +40,7 @@ DLSYM_FUNCTION(fido_cred_id_ptr); DLSYM_FUNCTION(fido_cred_new); DLSYM_FUNCTION(fido_cred_set_clientdata_hash); DLSYM_FUNCTION(fido_cred_set_extensions); +DLSYM_FUNCTION(fido_cred_set_prot); DLSYM_FUNCTION(fido_cred_set_rk); DLSYM_FUNCTION(fido_cred_set_rp); DLSYM_FUNCTION(fido_cred_set_type); @@ -97,6 +98,7 @@ int dlopen_libfido2(void) { DLSYM_ARG(fido_cred_new), DLSYM_ARG(fido_cred_set_clientdata_hash), DLSYM_ARG(fido_cred_set_extensions), + DLSYM_ARG(fido_cred_set_prot), DLSYM_ARG(fido_cred_set_rk), DLSYM_ARG(fido_cred_set_rp), DLSYM_ARG(fido_cred_set_type), @@ -776,10 +778,21 @@ int fido2_generate_hmac_hash( if (!c) return log_oom(); - r = sym_fido_cred_set_extensions(c, FIDO_EXT_HMAC_SECRET); + int extensions = FIDO_EXT_HMAC_SECRET; + if (FLAGS_SET(lock_with, FIDO2ENROLL_PIN) || FLAGS_SET(lock_with, FIDO2ENROLL_UV)) { + /* Attempt to use the "cred protect" extension, requiring user verification (UV) for this + * credential. If the authenticator doesn't support the extension, it will be ignored. */ + extensions |= FIDO_EXT_CRED_PROTECT; + + r = sym_fido_cred_set_prot(c, FIDO_CRED_PROT_UV_REQUIRED); + if (r != FIDO_OK) + log_warning("Failed to set protection level on FIDO2 credential, ignoring: %s", sym_fido_strerr(r)); + } + + r = sym_fido_cred_set_extensions(c, extensions); if (r != FIDO_OK) return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to enable HMAC-SECRET extension on FIDO2 credential: %s", sym_fido_strerr(r)); + "Failed to enable extensions on FIDO2 credential: %s", sym_fido_strerr(r)); r = sym_fido_cred_set_rp(c, rp_id, rp_name); if (r != FIDO_OK) @@ -830,7 +843,17 @@ int fido2_generate_hmac_hash( emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", emoji_enabled() ? " " : ""); - r = sym_fido_dev_make_cred(d, c, NULL); + /* If we are using the user PIN, then we must pass that PIN to the get_assertion call below, or + * the authenticator will use the non-user-verification HMAC secret (which differs from the one when + * the PIN is passed). + * + * Rather than potentially trying and failing to create the credential, just collect the PIN first + * and then pass it to both the make_credential and the get_assertion operations. */ + if (FLAGS_SET(lock_with, FIDO2ENROLL_PIN)) + r = FIDO_ERR_PIN_REQUIRED; + else + r = sym_fido_dev_make_cred(d, c, NULL); + if (r == FIDO_ERR_PIN_REQUIRED) { if (!has_client_pin) diff --git a/src/shared/libfido2-util.h b/src/shared/libfido2-util.h index 198408fdaf3..5e40b2aafc4 100644 --- a/src/shared/libfido2-util.h +++ b/src/shared/libfido2-util.h @@ -43,6 +43,7 @@ DLSYM_PROTOTYPE(fido_cred_id_ptr); DLSYM_PROTOTYPE(fido_cred_new); DLSYM_PROTOTYPE(fido_cred_set_clientdata_hash); DLSYM_PROTOTYPE(fido_cred_set_extensions); +DLSYM_PROTOTYPE(fido_cred_set_prot); DLSYM_PROTOTYPE(fido_cred_set_rk); DLSYM_PROTOTYPE(fido_cred_set_rp); DLSYM_PROTOTYPE(fido_cred_set_type);