diff options
author | Luca Boccassi <luca.boccassi@microsoft.com> | 2021-05-09 14:49:55 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-09 14:49:55 +0200 |
commit | 63225fe1597816ee63d728831c7988e5ac9de14d (patch) | |
tree | 046f579ea7d31ed559247bd7c76dcec4f731e4a6 /src/shared | |
parent | Merge pull request #19552 from yuwata/fix-typo-and-coverty-issues (diff) | |
parent | FIDO2: if defined, check for FIDO_ERR_UV_BLOCKED (diff) | |
download | systemd-63225fe1597816ee63d728831c7988e5ac9de14d.tar.xz systemd-63225fe1597816ee63d728831c7988e5ac9de14d.zip |
Merge pull request #19298 from bluca/cryptsetup_nopass
cryptsetup: add 'headless' parameter to skip password/pin query, allow pin-less enroll on FIDO2, support user presence/verification flags
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/libfido2-util.c | 137 | ||||
-rw-r--r-- | src/shared/libfido2-util.h | 12 | ||||
-rw-r--r-- | src/shared/pkcs11-util.c | 7 | ||||
-rw-r--r-- | src/shared/pkcs11-util.h | 2 |
4 files changed, 113 insertions, 45 deletions
diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c index 951ed09899..24c9b76b7a 100644 --- a/src/shared/libfido2-util.c +++ b/src/shared/libfido2-util.c @@ -25,6 +25,7 @@ int (*sym_fido_assert_set_extensions)(fido_assert_t *, int) = NULL; int (*sym_fido_assert_set_hmac_salt)(fido_assert_t *, const unsigned char *, size_t) = NULL; int (*sym_fido_assert_set_rp)(fido_assert_t *, const char *) = NULL; int (*sym_fido_assert_set_up)(fido_assert_t *, fido_opt_t) = NULL; +int (*sym_fido_assert_set_uv)(fido_assert_t *, fido_opt_t) = NULL; size_t (*sym_fido_cbor_info_extensions_len)(const fido_cbor_info_t *) = NULL; char **(*sym_fido_cbor_info_extensions_ptr)(const fido_cbor_info_t *) = NULL; void (*sym_fido_cbor_info_free)(fido_cbor_info_t **) = NULL; @@ -84,6 +85,7 @@ int dlopen_libfido2(void) { DLSYM_ARG(fido_assert_set_hmac_salt), DLSYM_ARG(fido_assert_set_rp), DLSYM_ARG(fido_assert_set_up), + DLSYM_ARG(fido_assert_set_uv), DLSYM_ARG(fido_cbor_info_extensions_len), DLSYM_ARG(fido_cbor_info_extensions_ptr), DLSYM_ARG(fido_cbor_info_free), @@ -218,14 +220,14 @@ static int fido2_use_hmac_hash_specific_token( const void *cid, size_t cid_size, char **pins, - bool up, /* user presence permitted */ + Fido2EnrollFlags required, /* client pin/user presence required */ void **ret_hmac, size_t *ret_hmac_size) { _cleanup_(fido_assert_free_wrapper) fido_assert_t *a = NULL; _cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL; _cleanup_(erase_and_freep) void *hmac_copy = NULL; - bool has_up, has_client_pin; + bool has_up, has_client_pin, has_uv; size_t hmac_size; const void *hmac; int r; @@ -246,10 +248,25 @@ static int fido2_use_hmac_hash_specific_token( return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r)); - r = verify_features(d, path, LOG_ERR, NULL, &has_client_pin, &has_up, NULL); + r = verify_features(d, path, LOG_ERR, NULL, &has_client_pin, &has_up, &has_uv); if (r < 0) return r; + if (!has_client_pin && FLAGS_SET(required, FIDO2ENROLL_PIN)) + return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), + "PIN required to unlock, but FIDO2 device %s does not support it.", + path); + + if (!has_up && FLAGS_SET(required, FIDO2ENROLL_UP)) + return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), + "User presence test required to unlock, but FIDO2 device %s does not support it.", + path); + + if (!has_uv && FLAGS_SET(required, FIDO2ENROLL_UV)) + return log_error_errno(SYNTHETIC_ERRNO(EHWPOISON), + "User verification required to unlock, but FIDO2 device %s does not support it.", + path); + a = sym_fido_assert_new(); if (!a) return log_oom(); @@ -279,31 +296,33 @@ static int fido2_use_hmac_hash_specific_token( return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r)); + log_info("Asking FIDO2 token for authentication."); + if (has_up) { - r = sym_fido_assert_set_up(a, FIDO_OPT_FALSE); + r = sym_fido_assert_set_up(a, FLAGS_SET(required, FIDO2ENROLL_UP) ? FIDO_OPT_TRUE : FIDO_OPT_FALSE); if (r != FIDO_OK) return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 assertion user presence: %s", sym_fido_strerr(r)); - } - - log_info("Asking FIDO2 token for authentication."); + "Failed to %s FIDO2 user presence test: %s", + enable_disable(FLAGS_SET(required, FIDO2ENROLL_UP)), + sym_fido_strerr(r)); - r = sym_fido_dev_get_assert(d, a, NULL); /* try without pin and without up first */ - if (r == FIDO_ERR_UP_REQUIRED && up) { - - if (!has_up) - log_warning("Weird, device asked for User Presence check, but does not advertise it as feature. Ignoring."); + if (FLAGS_SET(required, FIDO2ENROLL_UP)) + log_info("User presence required to unlock."); + } - r = sym_fido_assert_set_up(a, FIDO_OPT_TRUE); + if (has_uv) { + r = sym_fido_assert_set_uv(a, FLAGS_SET(required, FIDO2ENROLL_UV) ? FIDO_OPT_TRUE : FIDO_OPT_FALSE); if (r != FIDO_OK) return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 assertion user presence: %s", sym_fido_strerr(r)); - - log_info("Security token requires user presence."); + "Failed to %s FIDO2 user verification: %s", + enable_disable(FLAGS_SET(required, FIDO2ENROLL_UV)), + sym_fido_strerr(r)); - r = sym_fido_dev_get_assert(d, a, NULL); /* try without pin but with up now */ + if (FLAGS_SET(required, FIDO2ENROLL_UV)) + log_info("User verification required to unlock."); } - if (r == FIDO_ERR_PIN_REQUIRED) { + + if (FLAGS_SET(required, FIDO2ENROLL_PIN)) { char **i; if (!has_client_pin) @@ -315,7 +334,8 @@ static int fido2_use_hmac_hash_specific_token( if (r != FIDO_ERR_PIN_INVALID) break; } - } + } else + r = sym_fido_dev_get_assert(d, a, NULL); switch (r) { case FIDO_OK: @@ -329,6 +349,11 @@ static int fido2_use_hmac_hash_specific_token( case FIDO_ERR_PIN_AUTH_BLOCKED: return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD), "PIN of security token is blocked, please remove/reinsert token."); +#ifdef FIDO_ERR_UV_BLOCKED + case FIDO_ERR_UV_BLOCKED: + return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD), + "Verification of security token is blocked, please remove/reinsert token."); +#endif case FIDO_ERR_PIN_INVALID: return log_error_errno(SYNTHETIC_ERRNO(ENOLCK), "PIN of security token incorrect."); @@ -366,7 +391,7 @@ int fido2_use_hmac_hash( const void *cid, size_t cid_size, char **pins, - bool up, /* user presence permitted */ + Fido2EnrollFlags required, /* client pin/user presence required */ void **ret_hmac, size_t *ret_hmac_size) { @@ -379,7 +404,7 @@ int fido2_use_hmac_hash( return log_error_errno(r, "FIDO2 support is not installed."); if (device) - return fido2_use_hmac_hash_specific_token(device, rp_id, salt, salt_size, cid, cid_size, pins, up, ret_hmac, ret_hmac_size); + return fido2_use_hmac_hash_specific_token(device, rp_id, salt, salt_size, cid, cid_size, pins, required, ret_hmac, ret_hmac_size); di = sym_fido_dev_info_new(allocated); if (!di) @@ -414,7 +439,7 @@ int fido2_use_hmac_hash( goto finish; } - r = fido2_use_hmac_hash_specific_token(path, rp_id, salt, salt_size, cid, cid_size, pins, up, ret_hmac, ret_hmac_size); + r = fido2_use_hmac_hash_specific_token(path, rp_id, salt, salt_size, cid, cid_size, pins, required, ret_hmac, ret_hmac_size); if (!IN_SET(r, -EBADSLT, /* device doesn't understand our credential hash */ -ENODEV /* device is not a FIDO2 device with HMAC-SECRET */)) @@ -439,6 +464,7 @@ int fido2_generate_hmac_hash( const char *user_display_name, const char *user_icon, const char *askpw_icon_name, + Fido2EnrollFlags lock_with, void **ret_cid, size_t *ret_cid_size, void **ret_salt, size_t *ret_salt_size, void **ret_secret, size_t *ret_secret_size, @@ -503,6 +529,21 @@ int fido2_generate_hmac_hash( if (r < 0) return r; + if (!has_client_pin && FLAGS_SET(lock_with, FIDO2ENROLL_PIN)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Requested to lock with PIN, but FIDO2 device %s does not support it.", + device); + + if (!has_up && FLAGS_SET(lock_with, FIDO2ENROLL_UP)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Locking with user presence test requested, but FIDO2 device %s does not support it.", + device); + + if (!has_uv && FLAGS_SET(lock_with, FIDO2ENROLL_UV)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Locking with user verification requested, but FIDO2 device %s does not support it.", + device); + c = sym_fido_cred_new(); if (!c) return log_oom(); @@ -597,6 +638,11 @@ int fido2_generate_hmac_hash( if (r == FIDO_ERR_PIN_AUTH_BLOCKED) return log_notice_errno(SYNTHETIC_ERRNO(EPERM), "Token PIN is currently blocked, please remove and reinsert token."); +#ifdef FIDO_ERR_UV_BLOCKED + if (r == FIDO_ERR_UV_BLOCKED) + return log_notice_errno(SYNTHETIC_ERRNO(EPERM), + "Token verification is currently blocked, please remove and reinsert token."); +#endif if (r == FIDO_ERR_ACTION_TIMEOUT) return log_error_errno(SYNTHETIC_ERRNO(ENOSTR), "Token action timeout. (User didn't interact with token quickly enough.)"); @@ -639,32 +685,41 @@ int fido2_generate_hmac_hash( return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r)); + log_info("Generating secret key on FIDO2 security token."); + if (has_up) { - r = sym_fido_assert_set_up(a, FIDO_OPT_FALSE); + r = sym_fido_assert_set_up(a, FLAGS_SET(lock_with, FIDO2ENROLL_UP) ? FIDO_OPT_TRUE : FIDO_OPT_FALSE); if (r != FIDO_OK) return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to turn off FIDO2 assertion user presence: %s", sym_fido_strerr(r)); + "Failed to %s FIDO2 user presence test: %s", + enable_disable(FLAGS_SET(lock_with, FIDO2ENROLL_UP)), + sym_fido_strerr(r)); + + if (FLAGS_SET(lock_with, FIDO2ENROLL_UP)) + log_notice("%s%sIn order to allow secret key generation, please confirm presence on security token.", + emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", + emoji_enabled() ? " " : ""); } - log_info("Generating secret key on FIDO2 security token."); - - r = sym_fido_dev_get_assert(d, a, used_pin); - if (r == FIDO_ERR_UP_REQUIRED) { - - if (!has_up) - log_warning("Weird, device asked for User Presence check, but does not advertise it as feature. Ignoring."); - - r = sym_fido_assert_set_up(a, FIDO_OPT_TRUE); + if (has_uv) { + r = sym_fido_assert_set_uv(a, FLAGS_SET(lock_with, FIDO2ENROLL_UV) ? FIDO_OPT_TRUE : FIDO_OPT_FALSE); if (r != FIDO_OK) return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to turn on FIDO2 assertion user presence: %s", sym_fido_strerr(r)); - - log_notice("%s%sIn order to allow secret key generation, please verify presence on security token.", - emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", - emoji_enabled() ? " " : ""); - - r = sym_fido_dev_get_assert(d, a, used_pin); + "Failed to %s FIDO user verification: %s", + enable_disable(FLAGS_SET(lock_with, FIDO2ENROLL_UV)), + sym_fido_strerr(r)); + + if (FLAGS_SET(lock_with, FIDO2ENROLL_UV)) + log_notice("%s%sIn order to allow secret key generation, please verify user on security token.", + emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", + emoji_enabled() ? " " : ""); } + + r = sym_fido_dev_get_assert(d, a, FLAGS_SET(lock_with, FIDO2ENROLL_PIN) ? used_pin : NULL); + if (r == FIDO_ERR_UP_REQUIRED && !FLAGS_SET(lock_with, FIDO2ENROLL_UP)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Locking without user presence test requested, but FIDO2 device %s requires it.", + device); if (r == FIDO_ERR_ACTION_TIMEOUT) return log_error_errno(SYNTHETIC_ERRNO(ENOSTR), "Token action timeout. (User didn't interact with token quickly enough.)"); diff --git a/src/shared/libfido2-util.h b/src/shared/libfido2-util.h index 3648ea44c7..1b31577e06 100644 --- a/src/shared/libfido2-util.h +++ b/src/shared/libfido2-util.h @@ -3,6 +3,14 @@ #include "macro.h" +typedef enum Fido2EnrollFlags { + FIDO2ENROLL_PIN = 1 << 0, + FIDO2ENROLL_UP = 1 << 1, /* User presence (ie: touching token) */ + FIDO2ENROLL_UV = 1 << 2, /* User verification (ie: fingerprint) */ + _FIDO2ENROLL_TYPE_MAX, + _FIDO2ENROLL_TYPE_INVALID = -EINVAL, +} Fido2EnrollFlags; + #if HAVE_LIBFIDO2 #include <fido.h> @@ -16,6 +24,7 @@ extern int (*sym_fido_assert_set_extensions)(fido_assert_t *, int); extern int (*sym_fido_assert_set_hmac_salt)(fido_assert_t *, const unsigned char *, size_t); extern int (*sym_fido_assert_set_rp)(fido_assert_t *, const char *); extern int (*sym_fido_assert_set_up)(fido_assert_t *, fido_opt_t); +extern int (*sym_fido_assert_set_uv)(fido_assert_t *, fido_opt_t); extern size_t (*sym_fido_cbor_info_extensions_len)(const fido_cbor_info_t *); extern char **(*sym_fido_cbor_info_extensions_ptr)(const fido_cbor_info_t *); extern void (*sym_fido_cbor_info_free)(fido_cbor_info_t **); @@ -80,7 +89,7 @@ int fido2_use_hmac_hash( const void *cid, size_t cid_size, char **pins, - bool up, /* user presence permitted */ + Fido2EnrollFlags required, void **ret_hmac, size_t *ret_hmac_size); @@ -93,6 +102,7 @@ int fido2_generate_hmac_hash( const char *user_display_name, const char *user_icon, const char *askpw_icon_name, + Fido2EnrollFlags lock_with, void **ret_cid, size_t *ret_cid_size, void **ret_salt, size_t *ret_salt_size, void **ret_secret, size_t *ret_secret_size, diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index aff45ed868..9fc577ca3c 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -184,6 +184,7 @@ int pkcs11_token_login( const char *key_name, const char *credential_name, usec_t until, + bool headless, char **ret_used_pin) { _cleanup_free_ char *token_uri_string = NULL, *token_uri_escaped = NULL, *id = NULL, *token_label = NULL; @@ -247,7 +248,9 @@ int pkcs11_token_login( string_erase(e); if (unsetenv("PIN") < 0) return log_error_errno(errno, "Failed to unset $PIN: %m"); - } else { + } else if (headless) + return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable."); + else { _cleanup_free_ char *text = NULL; if (FLAGS_SET(token_info->flags, CKF_USER_PIN_FINAL_TRY)) @@ -960,7 +963,7 @@ static int pkcs11_acquire_certificate_callback( /* Called for every token matching our URI */ - r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", "pkcs11-pin", UINT64_MAX, &pin_used); + r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", "pkcs11-pin", UINT64_MAX, false, &pin_used); if (r < 0) return r; diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h index c2c852f0eb..f7f32d34d7 100644 --- a/src/shared/pkcs11-util.h +++ b/src/shared/pkcs11-util.h @@ -30,7 +30,7 @@ char *pkcs11_token_label(const CK_TOKEN_INFO *token_info); char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO *token_info); char *pkcs11_token_model(const CK_TOKEN_INFO *token_info); -int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *key_name, const char *credential_name, usec_t until, char **ret_used_pin); +int pkcs11_token_login(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_TOKEN_INFO *token_info, const char *friendly_name, const char *icon_name, const char *key_name, const char *credential_name, usec_t until, bool headless, char **ret_used_pin); int pkcs11_token_find_x509_certificate(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, P11KitUri *search_uri, CK_OBJECT_HANDLE *ret_object); #if HAVE_OPENSSL |