summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLuca Boccassi <luca.boccassi@microsoft.com>2021-04-12 22:48:05 +0100
committerLuca Boccassi <bluca@debian.org>2021-05-07 21:36:27 +0100
commit06f087192d27d6bbb237f8966c2fa2d6b790f7f2 (patch)
tree8daf3fe42fdf69acc142c0fe2669e179e7b29bc4 /src
parentcde2f8605e0c3842f9a87785dd758f955f2d04ba (diff)
downloadsystemd-06f087192d27d6bbb237f8966c2fa2d6b790f7f2.tar.gz
FIDO2: ask and record whether user presence was used to lock the volume
In some cases user presence might not be required to get _a_ secret out of a FIDO2 device, but it might be required to the get actual secret that was used to lock the volume. Record whether we used it in the LUKS header JSON metadata. Let the cryptenroll user ask for the feature, but bail out if it is required by the token and the user disabled it. Enabled by default.
Diffstat (limited to 'src')
-rw-r--r--src/cryptenroll/cryptenroll-fido2.c3
-rw-r--r--src/cryptenroll/cryptenroll.c18
-rw-r--r--src/cryptsetup/cryptsetup-fido2.c15
-rw-r--r--src/cryptsetup/cryptsetup.c4
-rw-r--r--src/home/homectl-fido2.c2
-rw-r--r--src/home/homework-fido2.c3
-rw-r--r--src/shared/libfido2-util.c84
-rw-r--r--src/shared/libfido2-util.h2
8 files changed, 76 insertions, 55 deletions
diff --git a/src/cryptenroll/cryptenroll-fido2.c b/src/cryptenroll/cryptenroll-fido2.c
index 213b7795b6..eab8f220e4 100644
--- a/src/cryptenroll/cryptenroll-fido2.c
+++ b/src/cryptenroll/cryptenroll-fido2.c
@@ -78,7 +78,8 @@ int enroll_fido2(
JSON_BUILD_PAIR("fido2-credential", JSON_BUILD_BASE64(cid, cid_size)),
JSON_BUILD_PAIR("fido2-salt", JSON_BUILD_BASE64(salt, salt_size)),
JSON_BUILD_PAIR("fido2-rp", JSON_BUILD_STRING("io.systemd.cryptsetup")),
- JSON_BUILD_PAIR("fido2-clientPin-required", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_PIN)))));
+ JSON_BUILD_PAIR("fido2-clientPin-required", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_PIN))),
+ JSON_BUILD_PAIR("fido2-up-required", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_UP)))));
if (r < 0)
return log_error_errno(r, "Failed to prepare PKCS#11 JSON token object: %m");
diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c
index ef6031cb1f..5eca69f851 100644
--- a/src/cryptenroll/cryptenroll.c
+++ b/src/cryptenroll/cryptenroll.c
@@ -36,7 +36,7 @@ static int *arg_wipe_slots = NULL;
static size_t arg_n_wipe_slots = 0;
static WipeScope arg_wipe_slots_scope = WIPE_EXPLICIT;
static unsigned arg_wipe_slots_mask = 0; /* Bitmask of (1U << EnrollType), for wiping all slots of specific types */
-static Fido2EnrollFlags arg_fido2_lock_with = FIDO2ENROLL_PIN;
+static Fido2EnrollFlags arg_fido2_lock_with = FIDO2ENROLL_PIN | FIDO2ENROLL_UP;
assert_cc(sizeof(arg_wipe_slots_mask) * 8 >= _ENROLL_TYPE_MAX);
@@ -91,6 +91,8 @@ static int help(void) {
" Enroll a FIDO2-HMAC security token\n"
" --fido2-with-client-pin=BOOL\n"
" Whether to require entering a PIN to unlock the volume\n"
+ " --fido2-with-user-presence=BOOL\n"
+ " Whether to require user presence to unlock the volume\n"
" --tpm2-device=PATH\n"
" Enroll a TPM2 device\n"
" --tpm2-pcrs=PCR1,PCR2,PCR3,…\n"
@@ -118,6 +120,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_TPM2_PCRS,
ARG_WIPE_SLOT,
ARG_FIDO2_WITH_PIN,
+ ARG_FIDO2_WITH_UP,
};
static const struct option options[] = {
@@ -128,6 +131,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "pkcs11-token-uri", required_argument, NULL, ARG_PKCS11_TOKEN_URI },
{ "fido2-device", required_argument, NULL, ARG_FIDO2_DEVICE },
{ "fido2-with-client-pin", required_argument, NULL, ARG_FIDO2_WITH_PIN },
+ { "fido2-with-user-presence", required_argument, NULL, ARG_FIDO2_WITH_UP },
{ "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE },
{ "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS },
{ "wipe-slot", required_argument, NULL, ARG_WIPE_SLOT },
@@ -161,6 +165,18 @@ static int parse_argv(int argc, char *argv[]) {
break;
}
+ case ARG_FIDO2_WITH_UP: {
+ bool lock_with_up;
+
+ r = parse_boolean_argument("--fido2-with-user-presence=", optarg, &lock_with_up);
+ if (r < 0)
+ return r;
+
+ SET_FLAG(arg_fido2_lock_with, FIDO2ENROLL_UP, lock_with_up);
+
+ break;
+ }
+
case ARG_PASSWORD:
if (arg_enroll_type >= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
diff --git a/src/cryptsetup/cryptsetup-fido2.c b/src/cryptsetup/cryptsetup-fido2.c
index 339e245575..9a3af2d8ff 100644
--- a/src/cryptsetup/cryptsetup-fido2.c
+++ b/src/cryptsetup/cryptsetup-fido2.c
@@ -81,7 +81,6 @@ int acquire_fido2_key(
salt, salt_size,
cid, cid_size,
pins,
- /* up= */ true,
required,
ret_decrypted_key,
ret_decrypted_key_size);
@@ -118,7 +117,8 @@ int find_fido2_auto_data(
size_t cid_size = 0, salt_size = 0;
_cleanup_free_ char *rp = NULL;
int r, keyslot = -1;
- Fido2EnrollFlags required = FIDO2ENROLL_PIN; /* For backward compatibility, require pin by default */
+ /* For backward compatibility, require pin and presence by default */
+ Fido2EnrollFlags required = FIDO2ENROLL_PIN | FIDO2ENROLL_UP;
assert(cd);
assert(ret_salt);
@@ -194,6 +194,17 @@ int find_fido2_auto_data(
SET_FLAG(required, FIDO2ENROLL_PIN, json_variant_boolean(w));
}
+
+ w = json_variant_by_key(v, "fido2-up-required");
+ if (w) {
+ /* The "fido2-up-required" field is optional. */
+
+ if (!json_variant_is_boolean(w))
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+ "FIDO2 token data's 'fido2-up-required' field is not a boolean.");
+
+ SET_FLAG(required, FIDO2ENROLL_UP, json_variant_boolean(w));
+ }
}
if (!cid)
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index 9ab42eacb9..d47e758cd7 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -769,9 +769,9 @@ static int attach_luks_or_plain_or_bitlk_by_fido2(
if (r < 0)
return r;
- if (FLAGS_SET(required, FIDO2ENROLL_PIN) && arg_headless)
+ if (FLAGS_SET(required, FIDO2ENROLL_PIN | FIDO2ENROLL_UP) && arg_headless)
return log_error_errno(SYNTHETIC_ERRNO(ENOPKG),
- "A PIN is required to unlock this volume, but the 'headless' parameter was set.");
+ "Local verification is required to unlock this volume, but the 'headless' parameter was set.");
rp_id = discovered_rp_id;
key_data = discovered_salt;
diff --git a/src/home/homectl-fido2.c b/src/home/homectl-fido2.c
index 76775ee6bd..a2054fcf73 100644
--- a/src/home/homectl-fido2.c
+++ b/src/home/homectl-fido2.c
@@ -158,7 +158,7 @@ int identity_add_fido2_parameters(
/* user_display_name= */ rn ? json_variant_string(rn) : NULL,
/* user_icon_name= */ NULL,
/* askpw_icon_name= */ "user-home",
- FIDO2ENROLL_PIN, // FIXME: add a --lock-with-pin parameter like cryptenroll
+ FIDO2ENROLL_PIN | FIDO2ENROLL_UP, // FIXME: add a --lock-with-pin/up parameter like cryptenroll
&cid, &cid_size,
&salt, &salt_size,
&secret, &secret_size,
diff --git a/src/home/homework-fido2.c b/src/home/homework-fido2.c
index 818f2a5d16..8811c00550 100644
--- a/src/home/homework-fido2.c
+++ b/src/home/homework-fido2.c
@@ -28,8 +28,7 @@ int fido2_use_token(
salt->salt, salt->salt_size,
salt->credential.id, salt->credential.size,
secret->token_pin,
- h->fido2_user_presence_permitted > 0,
- FIDO2ENROLL_PIN, // FIXME: add a --lock-with-pin parameter like cryptenroll
+ FIDO2ENROLL_PIN | (h->fido2_user_presence_permitted > 0 ? FIDO2ENROLL_UP : 0), // FIXME: add a --lock-with-pin parameter like cryptenroll
&hmac,
&hmac_size);
if (r < 0)
diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c
index 66a312bfb6..50e1efb2dc 100644
--- a/src/shared/libfido2-util.c
+++ b/src/shared/libfido2-util.c
@@ -218,8 +218,7 @@ 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 required */
+ Fido2EnrollFlags required, /* client pin/user presence required */
void **ret_hmac,
size_t *ret_hmac_size) {
@@ -256,6 +255,11 @@ static int fido2_use_hmac_hash_specific_token(
"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);
+
a = sym_fido_assert_new();
if (!a)
return log_oom();
@@ -285,30 +289,20 @@ 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));
- if (has_up) {
- r = sym_fido_assert_set_up(a, 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.");
- 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.");
-
- r = sym_fido_assert_set_up(a, FIDO_OPT_TRUE);
+ if (has_up) {
+ 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("Security token requires user presence.");
+ "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 but with up now */
+ if (FLAGS_SET(required, FIDO2ENROLL_UP))
+ log_info("User presence required to unlock.");
}
+
if (FLAGS_SET(required, FIDO2ENROLL_PIN)) {
char **i;
@@ -321,7 +315,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:
@@ -372,8 +367,7 @@ int fido2_use_hmac_hash(
const void *cid,
size_t cid_size,
char **pins,
- bool up, /* user presence permitted */
- Fido2EnrollFlags required, /* client pin required */
+ Fido2EnrollFlags required, /* client pin/user presence required */
void **ret_hmac,
size_t *ret_hmac_size) {
@@ -386,7 +380,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, required, 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)
@@ -421,7 +415,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, required, 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 */))
@@ -516,6 +510,11 @@ int fido2_generate_hmac_hash(
"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);
+
c = sym_fido_cred_new();
if (!c)
return log_oom();
@@ -652,32 +651,27 @@ 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, FLAGS_SET(lock_with, FIDO2ENROLL_PIN) ? used_pin : NULL);
- 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 (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, 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 c22deebfcc..9eddf5ca78 100644
--- a/src/shared/libfido2-util.h
+++ b/src/shared/libfido2-util.h
@@ -5,6 +5,7 @@
typedef enum Fido2EnrollFlags {
FIDO2ENROLL_PIN = 1 << 0,
+ FIDO2ENROLL_UP = 1 << 1, /* User presence (ie: touching token) */
_FIDO2ENROLL_TYPE_MAX,
_FIDO2ENROLL_TYPE_INVALID = -EINVAL,
} Fido2EnrollFlags;
@@ -86,7 +87,6 @@ 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);