`fido2HmacSalt` → An array of objects, implementing authentication support with
FIDO2 devices that implement the `hmac-secret` extension. Each element of the
array should be an object consisting of three string fields: `credential`,
-`salt`, `hashedPassword`. The first two shall contain Base64-encoded binary
+`salt`, `hashedPassword`, and three boolean fields: `up`, `uv` and
+`clientPin`. The first two string fields shall contain Base64-encoded binary
data: the FIDO2 credential ID and the salt value to pass to the FIDO2
device. During authentication this salt along with the credential ID is sent to
the FIDO2 token, which will HMAC hash the salt with its internal secret key and
return the result. This resulting binary key should then be Base64-encoded and
used as string password for the further layers of the stack. The
`hashedPassword` field of the `fido2HmacSalt` field shall be a UNIX password
-hash to test this derived secret key against for authentication. It is
-generally recommended that for each entry in `fido2HmacSalt` there's also a
-matching one in `fido2HmacCredential`, and vice versa, with the same credential
-ID, appearing in the same order, but this should not be required by
-applications processing user records.
+hash to test this derived secret key against for authentication. The `up`, `uv`
+and `clientPin` booleans map to the FIDO2 concepts of the same name and encode
+whether the `uv`/`up` options are enabled during the authentication, and
+whether a PIN shall be required. It is generally recommended that for each
+entry in `fido2HmacSalt` there's also a matching one in `fido2HmacCredential`,
+and vice versa, with the same credential ID, appearing in the same order, but
+this should not be required by applications processing user records.
`recoveryKey`→ An array of objects, each defining a recovery key. The object
has two mandatory fields: `type` indicates the type of recovery key. The only
`fido2UserPresencePermitted` → a boolean. If set to true allows the receiver to
use the FIDO2 "user presence" flag. This is similar to the concept of
-`pkcs11ProtectedAuthenticationPathPermitted`, but exposes the FIDO2 concept
-behind it. If false or unset authentication this way shall not be attempted.
+`pkcs11ProtectedAuthenticationPathPermitted`, but exposes the FIDO2 "up"
+concept behind it. If false or unset authentication this way shall not be
+attempted.
+
+`fido2UserVerificationPermitted` → a boolean. If set to true allows the
+receiver to use the FIDO2 "user verification" flag. This is similar to the
+concept of `pkcs11ProtectedAuthenticationPathPermitted`, but exposes the FIDO2
+"uv" concept behind it. If false or unset authentication this way shall not be
+attempted.
## Mapping to `struct passwd` and `struct spwd`
discussion see above.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--fido2-with-client-pin=</option><replaceable>BOOL</replaceable></term>
+
+ <listitem><para>When enrolling a FIDO2 security token, controls whether to require the user to enter
+ a PIN when unlocking the account (the FIDO2 <literal>clientPin</literal> feature). Defaults to
+ <literal>yes</literal>. (Note: this setting is without effect if the security token does not support
+ the <literal>clientPin</literal> feature at all, or does not allow enabling or disabling
+ it.)</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--fido2-with-user-presence=</option><replaceable>BOOL</replaceable></term>
+
+ <listitem><para>When enrolling a FIDO2 security token, controls whether to require the user to
+ verify presence (tap the token, the FIDO2 <literal>up</literal> feature) when unlocking the account.
+ Defaults to <literal>yes</literal>. (Note: this setting is without effect if the security token does not support
+ the <literal>up</literal> feature at all, or does not allow enabling or disabling it.)
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--fido2-with-user-verification=</option><replaceable>BOOL</replaceable></term>
+
+ <listitem><para>When enrolling a FIDO2 security token, controls whether to require user verification
+ when unlocking the account (the FIDO2 <literal>uv</literal> feature). Defaults to
+ <literal>no</literal>. (Note: this setting is without effect if the security token does not support
+ the <literal>uv</literal> feature at all, or does not allow enabling or disabling it.)</para></listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--recovery-key=</option><replaceable>BOOL</replaceable></term>
include_directories : includes,
link_with : [libshared],
dependencies : [threads,
- libcryptsetup,
libblkid,
libcrypt,
libopenssl,
if (r <= 0)
return r;
+ cryptsetup_enable_logging(NULL);
+
if (arg_enroll_type < 0)
r = prepare_luks(&cd, NULL, NULL); /* No need to unlock device if we don't need the volume key because we don't need to enroll anything */
else
log_setup();
- cryptsetup_enable_logging(cd);
+ cryptsetup_enable_logging(NULL);
umask(0022);
const void *fido2_salt,
size_t fido2_salt_size,
const void *secret,
- size_t secret_size) {
+ size_t secret_size,
+ Fido2EnrollFlags lock_with) {
_cleanup_(json_variant_unrefp) JsonVariant *l = NULL, *w = NULL, *e = NULL;
_cleanup_(erase_and_freep) char *base64_encoded = NULL, *hashed = NULL;
r = json_build(&e, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("credential", JSON_BUILD_BASE64(cid, cid_size)),
JSON_BUILD_PAIR("salt", JSON_BUILD_BASE64(fido2_salt, fido2_salt_size)),
- JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(hashed))));
+ JSON_BUILD_PAIR("hashedPassword", JSON_BUILD_STRING(hashed)),
+ JSON_BUILD_PAIR("up", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_UP))),
+ JSON_BUILD_PAIR("uv", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_UV))),
+ JSON_BUILD_PAIR("clientPin", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_PIN)))));
+
if (r < 0)
return log_error_errno(r, "Failed to build FIDO2 salt JSON key object: %m");
int identity_add_fido2_parameters(
JsonVariant **v,
- const char *device) {
+ const char *device,
+ Fido2EnrollFlags lock_with) {
#if HAVE_LIBFIDO2
JsonVariant *un, *realm, *rn;
/* user_display_name= */ rn ? json_variant_string(rn) : NULL,
/* user_icon_name= */ NULL,
/* askpw_icon_name= */ "user-home",
- FIDO2ENROLL_PIN | FIDO2ENROLL_UP, // FIXME: add a --lock-with-pin/up parameter like cryptenroll
+ lock_with,
&cid, &cid_size,
&salt, &salt_size,
&secret, &secret_size,
&used_pin,
- NULL);
+ &lock_with);
if (r < 0)
return r;
salt,
salt_size,
secret,
- secret_size);
+ secret_size,
+ lock_with);
if (r < 0)
return r;
#pragma once
#include "json.h"
+#include "libfido2-util.h"
-int identity_add_fido2_parameters(JsonVariant **v, const char *device);
+int identity_add_fido2_parameters(JsonVariant **v, const char *device, Fido2EnrollFlags lock_with);
static uint64_t arg_disk_size_relative = UINT64_MAX;
static char **arg_pkcs11_token_uri = NULL;
static char **arg_fido2_device = NULL;
+static Fido2EnrollFlags arg_fido2_lock_with = FIDO2ENROLL_PIN | FIDO2ENROLL_UP;
static bool arg_recovery_key = false;
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
static bool arg_and_resize = false;
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED)) {
- log_notice("%s%sAuthentication requires presence verification on security token.",
+ log_notice("%s%sPlease confirm presence on security token.",
emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "",
emoji_enabled() ? " " : "");
if (r < 0)
return log_error_errno(r, "Failed to set FIDO2 user presence permitted flag: %m");
+ } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED)) {
+
+ log_notice("%s%sPlease verify user on security token.",
+ emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "",
+ emoji_enabled() ? " " : "");
+
+ r = user_record_set_fido2_user_verification_permitted(hr, true);
+ if (r < 0)
+ return log_error_errno(r, "Failed to set FIDO2 user verification permitted flag: %m");
+
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_LOCKED))
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)");
_cleanup_(user_record_unrefp) UserRecord *stripped = NULL;
if (arg_export_format == EXPORT_FORMAT_STRIPPED)
- r = user_record_clone(hr, USER_RECORD_EXTRACT_EMBEDDED, &stripped);
+ r = user_record_clone(hr, USER_RECORD_EXTRACT_EMBEDDED|USER_RECORD_PERMISSIVE, &stripped);
else if (arg_export_format == EXPORT_FORMAT_MINIMAL)
- r = user_record_clone(hr, USER_RECORD_EXTRACT_SIGNABLE, &stripped);
+ r = user_record_clone(hr, USER_RECORD_EXTRACT_SIGNABLE|USER_RECORD_PERMISSIVE, &stripped);
else
r = 0;
if (r < 0)
if (!hr)
return log_oom();
- r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG);
+ r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0) {
if (ret == 0)
ret = r;
}
STRV_FOREACH(i, arg_fido2_device) {
- r = identity_add_fido2_parameters(&v, *i);
+ r = identity_add_fido2_parameters(&v, *i, arg_fido2_lock_with);
if (r < 0)
return r;
}
if (!hr)
return log_oom();
- r = user_record_load(hr, v, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_LOG);
+ r = user_record_load(hr, v, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
}
STRV_FOREACH(i, arg_fido2_device) {
- r = identity_add_fido2_parameters(&json, *i);
+ r = identity_add_fido2_parameters(&json, *i, arg_fido2_lock_with);
if (r < 0)
return r;
}
if (!hr)
return log_oom();
- r = user_record_load(hr, json, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_LOG);
+ r = user_record_load(hr, json, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
if (r < 0)
return log_error_errno(r, "Failed to reset FIDO2 user presence permission flag: %m");
+ r = user_record_set_fido2_user_verification_permitted(hr, -1);
+ if (r < 0)
+ return log_error_errno(r, "Failed to reset FIDO2 user verification permission flag: %m");
+
return 0;
}
" private key and matching X.509 certificate\n"
" --fido2-device=PATH Path to FIDO2 hidraw device with hmac-secret\n"
" extension\n"
+ " --fido2-with-client-pin=BOOL\n"
+ " Whether to require entering a PIN to unlock the\n"
+ " account\n"
+ " --fido2-with-user-presence=BOOL\n"
+ " Whether to require user presence to unlock the\n"
+ " account\n"
+ " --fido2-with-user-verification=BOOL\n"
+ " Whether to require user verification to unlock the\n"
+ " account\n"
" --recovery-key=BOOL Add a recovery key\n"
"\n%4$sAccount Management User Record Properties:%5$s\n"
" --locked=BOOL Set locked account state\n"
ARG_AUTO_LOGIN,
ARG_PKCS11_TOKEN_URI,
ARG_FIDO2_DEVICE,
+ ARG_FIDO2_WITH_PIN,
+ ARG_FIDO2_WITH_UP,
+ ARG_FIDO2_WITH_UV,
ARG_RECOVERY_KEY,
ARG_AND_RESIZE,
ARG_AND_CHANGE_PASSWORD,
{ "export-format", required_argument, NULL, ARG_EXPORT_FORMAT },
{ "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 },
+ { "fido2-with-user-verification",required_argument, NULL, ARG_FIDO2_WITH_UV },
{ "recovery-key", required_argument, NULL, ARG_RECOVERY_KEY },
{ "and-resize", required_argument, NULL, ARG_AND_RESIZE },
{ "and-change-password", required_argument, NULL, ARG_AND_CHANGE_PASSWORD },
r = strv_consume(&arg_fido2_device, TAKE_PTR(found));
} else
r = strv_extend(&arg_fido2_device, optarg);
-
if (r < 0)
return r;
break;
}
+ case ARG_FIDO2_WITH_PIN: {
+ bool lock_with_pin;
+
+ r = parse_boolean_argument("--fido2-with-client-pin=", optarg, &lock_with_pin);
+ if (r < 0)
+ return r;
+
+ SET_FLAG(arg_fido2_lock_with, FIDO2ENROLL_PIN, lock_with_pin);
+ 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_FIDO2_WITH_UV: {
+ bool lock_with_uv;
+
+ r = parse_boolean_argument("--fido2-with-user-verification=", optarg, &lock_with_uv);
+ if (r < 0)
+ return r;
+
+ SET_FLAG(arg_fido2_lock_with, FIDO2ENROLL_UV, lock_with_uv);
+ break;
+ }
+
case ARG_RECOVERY_KEY: {
const char *p;
if (!hr)
return -ENOMEM;
- r = user_record_load(hr, full, USER_RECORD_REQUIRE_SECRET);
+ r = user_record_load(hr, full, USER_RECORD_REQUIRE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
trusted = false;
}
- flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE;
+ flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
if (trusted)
flags |= USER_RECORD_ALLOW_PRIVILEGED;
else
assert(message);
assert(h);
- r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_REQUIRE_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE, &hr, error);
+ r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_REQUIRE_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE, &hr, error);
if (r < 0)
return r;
return r;
}
- r = user_record_clone(hr, USER_RECORD_LOAD_MASK_SECRET, &home->record);
+ r = user_record_clone(hr, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &home->record);
if (r < 0)
return r;
if (!new_hr)
return -ENOMEM;
- r = user_record_load(new_hr, v, USER_RECORD_LOAD_REFUSE_SECRET);
+ r = user_record_load(new_hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
if (!hr)
return log_oom();
- r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET);
+ r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0)
return log_error_errno(r, "Failed to load home record identity: %m");
case -ERFKILL:
return sd_bus_error_set(error, BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, "Security token requires protected authentication path.");
case -EMEDIUMTYPE:
- return sd_bus_error_set(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, "Security token requires user presence.");
+ return sd_bus_error_set(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, "Security token requires presence confirmation.");
+ case -ENOCSI:
+ return sd_bus_error_set(error, BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED, "Security token requires user verification.");
case -ENOSTR:
return sd_bus_error_set(error, BUS_ERROR_TOKEN_ACTION_TIMEOUT, "Token action timeout. (User was supposed to verify presence or similar, by interacting with the token, and didn't do that in time.)");
case -EOWNERDEAD:
return sd_bus_error_set(error, BUS_ERROR_HOME_RECORD_DOWNGRADE, "Refusing to update to older home record.");
if (!secret && FLAGS_SET(hr->mask, USER_RECORD_SECRET)) {
- r = user_record_clone(hr, USER_RECORD_EXTRACT_SECRET, &saved_secret);
+ r = user_record_clone(hr, USER_RECORD_EXTRACT_SECRET|USER_RECORD_PERMISSIVE, &saved_secret);
if (r < 0)
return r;
return r;
}
- r = user_record_extend_with_binding(hr, h->record, USER_RECORD_LOAD_MASK_SECRET, &new_hr);
+ r = user_record_extend_with_binding(hr, h->record, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_hr);
if (r < 0)
return r;
if (h->signed_locally <= 0) /* Don't allow changing of records not signed only by us */
return sd_bus_error_setf(error, BUS_ERROR_HOME_RECORD_SIGNED, "Home %s is signed and cannot be modified locally.", h->user_name);
- r = user_record_clone(h->record, USER_RECORD_LOAD_REFUSE_SECRET, &c);
+ r = user_record_clone(h->record, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE, &c);
if (r < 0)
return r;
if (r < 0)
return r;
- r = user_record_clone(h->record, USER_RECORD_LOAD_REFUSE_SECRET, &c);
+ r = user_record_clone(h->record, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE, &c);
if (r < 0)
return r;
assert(message);
assert(m);
- r = bus_message_read_home_record(message, USER_RECORD_LOAD_EMBEDDED, &hr, error);
+ r = bus_message_read_home_record(message, USER_RECORD_LOAD_EMBEDDED|USER_RECORD_PERMISSIVE, &hr, error);
if (r < 0)
return r;
assert(message);
assert(m);
- r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE, &hr, error);
+ r = bus_message_read_home_record(message, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_SECRET|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE, &hr, error);
if (r < 0)
return r;
if (!hr)
return log_oom();
- r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG);
+ r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
assert(h);
assert(ret);
- flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE;
+ flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
if (trusted)
flags |= USER_RECORD_ALLOW_PRIVILEGED;
else
if (r < 0)
return r;
- r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET, &new_home);
+ r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_home);
if (r < 0)
return log_error_errno(r, "Failed to clone record: %m");
if (r < 0)
return r;
- r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET, &new_home);
+ r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_home);
if (r < 0)
return log_error_errno(r, "Failed to clone record: %m");
#include "homework-fido2.h"
#include "libfido2-util.h"
#include "memory-util.h"
+#include "strv.h"
int fido2_use_token(
UserRecord *h,
_cleanup_(erase_and_freep) void *hmac = NULL;
size_t hmac_size;
+ Fido2EnrollFlags flags = 0;
int r;
assert(h);
assert(salt);
assert(ret);
+ /* If we know the up/uv/clientPin settings used during enrollment, let's pass this on for
+ * authentication, or generate errors immediately if interactivity of the specified kind is not
+ * allowed. */
+
+ if (salt->up > 0) {
+ if (h->fido2_user_presence_permitted <= 0)
+ return -EMEDIUMTYPE;
+
+ flags |= FIDO2ENROLL_UP;
+ } else if (salt->up < 0) /* unset? */
+ flags |= FIDO2ENROLL_UP_IF_NEEDED; /* compat with pre-248 */
+
+ if (salt->uv > 0) {
+ if (h->fido2_user_verification_permitted <= 0)
+ return -ENOCSI;
+
+ flags |= FIDO2ENROLL_UV;
+ } else if (salt->uv < 0)
+ flags |= FIDO2ENROLL_UV_OMIT; /* compat with pre-248 */
+
+ if (salt->client_pin > 0) {
+
+ if (strv_isempty(secret->token_pin))
+ return -ENOANO;
+
+ flags |= FIDO2ENROLL_PIN;
+ } else if (salt->client_pin < 0)
+ flags |= FIDO2ENROLL_PIN_IF_NEEDED; /* compat with pre-248 */
+
r = fido2_use_hmac_hash(
NULL,
"io.systemd.home",
salt->salt, salt->salt_size,
salt->credential.id, salt->credential.size,
secret->token_pin,
- FIDO2ENROLL_PIN | (h->fido2_user_presence_permitted > 0 ? FIDO2ENROLL_UP : 0), // FIXME: add a --lock-with-pin parameter like cryptenroll
+ flags,
&hmac,
&hmac_size);
if (r < 0)
if (r < 0)
return r;
- r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET, &new_home);
+ r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, &new_home);
if (r < 0)
return log_error_errno(r, "Failed to clone record: %m");
STRV_FOREACH(pp, passwords) {
size_t vks = *volume_key_size;
- r = crypt_volume_key_get(
+ r = sym_crypt_volume_key_get(
cd,
CRYPT_ANY_SLOT,
volume_key,
void **ret_volume_key,
size_t *ret_volume_key_size) {
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *vk = NULL;
sd_id128_t p;
size_t vks;
assert(dm_name);
assert(ret);
- r = crypt_init(&cd, node);
+ r = sym_crypt_init(&cd, node);
if (r < 0)
return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
cryptsetup_enable_logging(cd);
- r = crypt_load(cd, CRYPT_LUKS2, NULL);
+ r = sym_crypt_load(cd, CRYPT_LUKS2, NULL);
if (r < 0)
return log_error_errno(r, "Failed to load LUKS superblock: %m");
- r = crypt_get_volume_key_size(cd);
+ r = sym_crypt_get_volume_key_size(cd);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size");
vks = (size_t) r;
if (!sd_id128_is_null(uuid) || ret_found_uuid) {
const char *s;
- s = crypt_get_uuid(cd);
+ s = sym_crypt_get_uuid(cd);
if (!s)
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has no UUID.");
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has wrong UUID.");
}
- if (cipher && !streq_ptr(cipher, crypt_get_cipher(cd)))
+ if (cipher && !streq_ptr(cipher, sym_crypt_get_cipher(cd)))
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock declares wrong cipher.");
- if (cipher_mode && !streq_ptr(cipher_mode, crypt_get_cipher_mode(cd)))
+ if (cipher_mode && !streq_ptr(cipher_mode, sym_crypt_get_cipher_mode(cd)))
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock declares wrong cipher mode.");
if (volume_key_size != UINT64_MAX && vks != volume_key_size)
if (r < 0)
return log_error_errno(r, "Failed to unlocks LUKS superblock: %m");
- r = crypt_activate_by_volume_key(
+ r = sym_crypt_activate_by_volume_key(
cd,
dm_name,
vk, vks,
void **ret_volume_key,
size_t *ret_volume_key_size) {
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *vk = NULL;
sd_id128_t p;
char **list;
/* Opens a LUKS device that is already set up. Re-validates the password while doing so (which also
* provides us with the volume key, which we want). */
- r = crypt_init_by_name(&cd, dm_name);
+ r = sym_crypt_init_by_name(&cd, dm_name);
if (r < 0)
return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
cryptsetup_enable_logging(cd);
- r = crypt_load(cd, CRYPT_LUKS2, NULL);
+ r = sym_crypt_load(cd, CRYPT_LUKS2, NULL);
if (r < 0)
return log_error_errno(r, "Failed to load LUKS superblock: %m");
- r = crypt_get_volume_key_size(cd);
+ r = sym_crypt_get_volume_key_size(cd);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size");
vks = (size_t) r;
if (ret_found_uuid) {
const char *s;
- s = crypt_get_uuid(cd);
+ s = sym_crypt_get_uuid(cd);
if (!s)
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "LUKS superblock has no UUID.");
/* This is needed so that crypt_resize() can operate correctly for pre-existing LUKS devices. We need
* to tell libcryptsetup the volume key explicitly, so that it is in the kernel keyring. */
- r = crypt_activate_by_volume_key(cd, NULL, vk, vks, CRYPT_ACTIVATE_KEYRING_KEY);
+ r = sym_crypt_activate_by_volume_key(cd, NULL, vk, vks, CRYPT_ACTIVATE_KEYRING_KEY);
if (r < 0)
return log_error_errno(r, "Failed to upload volume key again: %m");
/* Let's find the right OpenSSL EVP_CIPHER object that matches the encryption settings of the LUKS
* device */
- cipher = crypt_get_cipher(cd);
+ cipher = sym_crypt_get_cipher(cd);
if (!cipher)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot get cipher from LUKS device.");
- cipher_mode = crypt_get_cipher_mode(cd);
+ cipher_mode = sym_crypt_get_cipher_mode(cd);
if (!cipher_mode)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot get cipher mode from LUKS device.");
if (e)
cipher_mode = strndupa(cipher_mode, e - cipher_mode);
- r = crypt_get_volume_key_size(cd);
+ r = sym_crypt_get_volume_key_size(cd);
if (r <= 0)
return log_error_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), "Cannot get volume key size from LUKS device.");
unsigned line, column;
const EVP_CIPHER *cc;
- state = crypt_token_status(cd, token, &type);
+ state = sym_crypt_token_status(cd, token, &type);
if (state == CRYPT_TOKEN_INACTIVE) /* First unconfigured token, give up */
break;
if (IN_SET(state, CRYPT_TOKEN_INTERNAL, CRYPT_TOKEN_INTERNAL_UNKNOWN, CRYPT_TOKEN_EXTERNAL))
if (!streq(type, "systemd-homed"))
continue;
- r = crypt_token_json_get(cd, token, &text);
+ r = sym_crypt_token_json_get(cd, token, &text);
if (r < 0)
return log_error_errno(r, "Failed to read LUKS token %i: %m", token);
if (!lhr)
return log_oom();
- r = user_record_load(lhr, rr, USER_RECORD_LOAD_EMBEDDED);
+ r = user_record_load(lhr, rr, USER_RECORD_LOAD_EMBEDDED|USER_RECORD_PERMISSIVE);
if (r < 0)
return log_error_errno(r, "Failed to parse user record: %m");
* the file system, so that we can validate it first, and only then mount the file system. To keep
* things simple we use the same encryption settings for this record as for the file system itself. */
- r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED, &header_home);
+ r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED|USER_RECORD_PERMISSIVE, &header_home);
if (r < 0)
return log_error_errno(r, "Failed to determine new header record: %m");
crypt_token_info state;
const char *type;
- state = crypt_token_status(setup->crypt_device, token, &type);
+ state = sym_crypt_token_status(setup->crypt_device, token, &type);
if (state == CRYPT_TOKEN_INACTIVE) /* First unconfigured token, we are done */
break;
if (IN_SET(state, CRYPT_TOKEN_INTERNAL, CRYPT_TOKEN_INTERNAL_UNKNOWN, CRYPT_TOKEN_EXTERNAL))
if (!streq(type, "systemd-homed"))
continue;
- r = crypt_token_json_set(setup->crypt_device, token, text);
+ r = sym_crypt_token_json_set(setup->crypt_device, token, text);
if (r < 0)
return log_error_errno(r, "Failed to set JSON token for slot %i: %m", token);
sd_id128_t found_partition_uuid, found_luks_uuid, found_fs_uuid;
_cleanup_(user_record_unrefp) UserRecord *luks_home = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *volume_key = NULL;
_cleanup_close_ int root_fd = -1, image_fd = -1;
bool dm_activated = false, mounted = false;
assert(user_record_storage(h) == USER_LUKS);
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
if (already_activated) {
struct loop_info64 info;
const char *n;
if (r < 0)
return r;
- n = crypt_get_device_name(cd);
+ n = sym_crypt_get_device_name(cd);
if (!n)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine backing device for DM %s.", setup->dm_name);
(void) umount_verbose(LOG_ERR, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
if (dm_activated)
- (void) crypt_deactivate(cd, setup->dm_name);
+ (void) sym_crypt_deactivate_by_name(cd, setup->dm_name, 0);
if (image_fd >= 0 && marked_dirty)
(void) run_mark_dirty(image_fd, false);
assert(user_record_storage(h) == USER_LUKS);
assert(ret_home);
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
assert_se(hdo = user_record_home_directory(h));
hd = strdupa(hdo); /* copy the string out, since it might change later in the home record object */
loop_device_relinquish(setup.loop);
- r = crypt_deactivate_by_name(NULL, setup.dm_name, CRYPT_DEACTIVATE_DEFERRED);
+ r = sym_crypt_deactivate_by_name(NULL, setup.dm_name, CRYPT_DEACTIVATE_DEFERRED);
if (r < 0)
log_warning_errno(r, "Failed to relinquish DM device, ignoring: %m");
}
int home_deactivate_luks(UserRecord *h) {
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
bool we_detached;
int r;
* don't bother about the loopback device because unlike the DM device it doesn't have a fixed
* name. */
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
r = make_dm_names(h->user_name, &dm_name, &dm_node);
if (r < 0)
return r;
- r = crypt_init_by_name(&cd, dm_name);
+ r = sym_crypt_init_by_name(&cd, dm_name);
if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
log_debug_errno(r, "LUKS device %s has already been detached.", dm_name);
we_detached = false;
cryptsetup_enable_logging(cd);
- r = crypt_deactivate(cd, dm_name);
+ r = sym_crypt_deactivate_by_name(cd, dm_name, 0);
if (IN_SET(r, -ENODEV, -EINVAL, -ENOENT)) {
log_debug_errno(r, "LUKS device %s is already detached.", dm_node);
we_detached = false;
struct crypt_device **ret) {
_cleanup_(user_record_unrefp) UserRecord *reduced = NULL;
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_(erase_and_freep) void *volume_key = NULL;
struct crypt_pbkdf_type good_pbkdf, minimal_pbkdf;
char suuid[ID128_UUID_STRING_MAX], **pp;
assert(hr);
assert(ret);
- r = crypt_init(&cd, node);
+ r = sym_crypt_init(&cd, node);
if (r < 0)
return log_error_errno(r, "Failed to allocate libcryptsetup context: %m");
#if HAVE_CRYPT_SET_METADATA_SIZE
/* Increase the metadata space to 4M, the largest LUKS2 supports */
- r = crypt_set_metadata_size(cd, 4096U*1024U, 0);
+ r = sym_crypt_set_metadata_size(cd, 4096U*1024U, 0);
if (r < 0)
return log_error_errno(r, "Failed to change LUKS2 metadata size: %m");
#endif
build_good_pbkdf(&good_pbkdf, hr);
build_minimal_pbkdf(&minimal_pbkdf, hr);
- r = crypt_format(cd,
+ r = sym_crypt_format(cd,
CRYPT_LUKS2,
user_record_luks_cipher(hr),
user_record_luks_cipher_mode(hr),
if (strv_contains(cache->pkcs11_passwords, *pp) ||
strv_contains(cache->fido2_passwords, *pp)) {
log_debug("Using minimal PBKDF for slot %i", slot);
- r = crypt_set_pbkdf_type(cd, &minimal_pbkdf);
+ r = sym_crypt_set_pbkdf_type(cd, &minimal_pbkdf);
} else {
log_debug("Using good PBKDF for slot %i", slot);
- r = crypt_set_pbkdf_type(cd, &good_pbkdf);
+ r = sym_crypt_set_pbkdf_type(cd, &good_pbkdf);
}
if (r < 0)
return log_error_errno(r, "Failed to tweak PBKDF for slot %i: %m", slot);
- r = crypt_keyslot_add_by_volume_key(
+ r = sym_crypt_keyslot_add_by_volume_key(
cd,
slot,
volume_key,
slot++;
}
- r = crypt_activate_by_volume_key(
+ r = sym_crypt_activate_by_volume_key(
cd,
dm_name,
volume_key,
log_info("LUKS activation by volume key succeeded.");
- r = user_record_clone(hr, USER_RECORD_EXTRACT_EMBEDDED, &reduced);
+ r = user_record_clone(hr, USER_RECORD_EXTRACT_EMBEDDED|USER_RECORD_PERMISSIVE, &reduced);
if (r < 0)
return log_error_errno(r, "Failed to prepare home record for LUKS: %m");
if (r < 0)
return r;
- r = crypt_token_json_set(cd, CRYPT_ANY_TOKEN, text);
+ r = sym_crypt_token_json_set(cd, CRYPT_ANY_TOKEN, text);
if (r < 0)
return log_error_errno(r, "Failed to set LUKS JSON token: %m");
_cleanup_(user_record_unrefp) UserRecord *new_home = NULL;
sd_id128_t partition_uuid, fs_uuid, luks_uuid, disk_uuid;
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_close_ int image_fd = -1, root_fd = -1;
const char *fstype, *ip;
struct statfs sfs;
assert(h->storage < 0 || h->storage == USER_LUKS);
assert(ret_home);
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
assert_se(ip = user_record_image_path(h));
fstype = user_record_file_system_type(h);
if (r < 0)
goto fail;
- r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_LOG, &new_home);
+ r = user_record_clone(h, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE, &new_home);
if (r < 0) {
log_error_errno(r, "Failed to clone record: %m");
goto fail;
partition_uuid,
luks_uuid,
fs_uuid,
- crypt_get_cipher(cd),
- crypt_get_cipher_mode(cd),
+ sym_crypt_get_cipher(cd),
+ sym_crypt_get_cipher_mode(cd),
luks_volume_key_size_convert(cd),
fstype,
NULL,
mounted = false;
- r = crypt_deactivate(cd, dm_name);
+ r = sym_crypt_deactivate_by_name(cd, dm_name, 0);
if (r < 0) {
log_error_errno(r, "Failed to deactivate LUKS device: %m");
goto fail;
}
- crypt_free(cd);
+ sym_crypt_free(cd);
cd = NULL;
dm_activated = false;
(void) umount_verbose(LOG_WARNING, "/run/systemd/user-home-mount", UMOUNT_NOFOLLOW);
if (dm_activated)
- (void) crypt_deactivate(cd, dm_name);
+ (void) sym_crypt_deactivate_by_name(cd, dm_name, 0);
loop = loop_device_unref(loop);
assert(setup);
assert(ret_home);
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
assert_se(ipo = user_record_image_path(h));
ip = strdupa(ipo); /* copy out since original might change later in home record object */
setup->partition_offset + new_partition_size > new_image_size)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "New partition doesn't fit into backing storage, refusing.");
- crypto_offset = crypt_get_data_offset(setup->crypt_device);
+ crypto_offset = sym_crypt_get_data_offset(setup->crypt_device);
if (setup->partition_size / 512U <= crypto_offset)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Weird, old crypto payload offset doesn't actually fit in partition size?");
if (new_partition_size / 512U <= crypto_offset)
log_debug_errno(errno, "BLKRRPART failed on block device, ignoring: %m");
/* Tell LUKS about the new bigger size too */
- r = crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512U);
+ r = sym_crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512U);
if (r < 0)
return log_error_errno(r, "Failed to grow LUKS device: %m");
if (new_fs_size < old_fs_size) {
/* Shrink the LUKS device now, matching the new file system size */
- r = crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512);
+ r = sym_crypt_resize(setup->crypt_device, setup->dm_name, new_fs_size / 512);
if (r < 0)
return log_error_errno(r, "Failed to shrink LUKS device: %m");
assert(user_record_storage(h) == USER_LUKS);
assert(setup);
- type = crypt_get_type(setup->crypt_device);
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
+ type = sym_crypt_get_type(setup->crypt_device);
if (!type)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine crypto device type.");
- r = crypt_keyslot_max(type);
+ r = sym_crypt_keyslot_max(type);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine number of key slots.");
max_key_slots = r;
- r = crypt_get_volume_key_size(setup->crypt_device);
+ r = sym_crypt_get_volume_key_size(setup->crypt_device);
if (r <= 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine volume key size.");
volume_key_size = (size_t) r;
build_minimal_pbkdf(&minimal_pbkdf, h);
for (size_t i = 0; i < max_key_slots; i++) {
- r = crypt_keyslot_destroy(setup->crypt_device, i);
+ r = sym_crypt_keyslot_destroy(setup->crypt_device, i);
if (r < 0 && !IN_SET(r, -ENOENT, -EINVAL)) /* Returns EINVAL or ENOENT if there's no key in this slot already */
return log_error_errno(r, "Failed to destroy LUKS password: %m");
if (strv_contains(cache->pkcs11_passwords, effective_passwords[i]) ||
strv_contains(cache->fido2_passwords, effective_passwords[i])) {
log_debug("Using minimal PBKDF for slot %zu", i);
- r = crypt_set_pbkdf_type(setup->crypt_device, &minimal_pbkdf);
+ r = sym_crypt_set_pbkdf_type(setup->crypt_device, &minimal_pbkdf);
} else {
log_debug("Using good PBKDF for slot %zu", i);
- r = crypt_set_pbkdf_type(setup->crypt_device, &good_pbkdf);
+ r = sym_crypt_set_pbkdf_type(setup->crypt_device, &good_pbkdf);
}
if (r < 0)
return log_error_errno(r, "Failed to tweak PBKDF for slot %zu: %m", i);
- r = crypt_keyslot_add_by_volume_key(
+ r = sym_crypt_keyslot_add_by_volume_key(
setup->crypt_device,
i,
volume_key,
}
int home_lock_luks(UserRecord *h) {
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
_cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
_cleanup_close_ int root_fd = -1;
const char *p;
if (r < 0)
return r;
- r = crypt_init_by_name(&cd, dm_name);
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
+ r = sym_crypt_init_by_name(&cd, dm_name);
if (r < 0)
return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
/* Note that we don't invoke FIFREEZE here, it appears libcryptsetup/device-mapper already does that on its own for us */
- r = crypt_suspend(cd, dm_name);
+ r = sym_crypt_suspend(cd, dm_name);
if (r < 0)
return log_error_errno(r, "Failed to suspend cryptsetup device: %s: %m", dm_node);
assert(dm_name);
STRV_FOREACH(pp, password) {
- r = crypt_resume_by_passphrase(
+ r = sym_crypt_resume_by_passphrase(
cd,
dm_name,
CRYPT_ANY_SLOT,
int home_unlock_luks(UserRecord *h, PasswordCache *cache) {
_cleanup_free_ char *dm_name = NULL, *dm_node = NULL;
- _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
+ _cleanup_(sym_crypt_freep) struct crypt_device *cd = NULL;
char **list;
int r;
if (r < 0)
return r;
- r = crypt_init_by_name(&cd, dm_name);
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ return r;
+
+ r = sym_crypt_init_by_name(&cd, dm_name);
if (r < 0)
return log_error_errno(r, "Failed to initialize cryptsetup context for %s: %m", dm_name);
/* Convert the "int" to uint64_t, which we usually use for byte sizes stored on disk. */
- k = crypt_get_volume_key_size(cd);
+ k = sym_crypt_get_volume_key_size(cd);
if (k <= 0)
return UINT64_MAX;
PasswordCache *cache,
bool strict_verify) {
- bool need_password = false, need_recovery_key = false, need_token = false, need_pin = false, need_protected_authentication_path_permitted = false, need_user_presence_permitted = false,
- pin_locked = false, pin_incorrect = false, pin_incorrect_few_tries_left = false, pin_incorrect_one_try_left = false, token_action_timeout = false;
+ bool need_password = false, need_recovery_key = false, need_token = false, need_pin = false,
+ need_protected_authentication_path_permitted = false, need_user_presence_permitted = false,
+ need_user_verification_permitted = false, pin_locked = false, pin_incorrect = false,
+ pin_incorrect_few_tries_left = false, pin_incorrect_one_try_left = false, token_action_timeout = false;
int r;
assert(h);
return log_error_errno(r, "Failed to check supplied FIDO2 password: %m");
if (r > 0) {
log_info("Previously acquired FIDO2 password unlocks user record.");
- return 0;
+ return 1;
}
}
}
if (r < 0)
return log_oom();
- return 0;
+ return 1;
}
#else
need_token = true;
case -EMEDIUMTYPE:
need_user_presence_permitted = true;
break;
+ case -ENOCSI:
+ need_user_verification_permitted = true;
+ break;
case -ENOSTR:
token_action_timeout = true;
break;
return -ERFKILL;
if (need_user_presence_permitted)
return -EMEDIUMTYPE;
+ if (need_user_verification_permitted)
+ return -ENOCSI;
if (need_pin)
return -ENOANO;
if (need_token)
}
if (setup->undo_dm && setup->crypt_device && setup->dm_name) {
- q = crypt_deactivate(setup->crypt_device, setup->dm_name);
+ q = sym_crypt_deactivate_by_name(setup->crypt_device, setup->dm_name, 0);
if (q < 0)
r = q;
}
setup->dm_node = mfree(setup->dm_node);
setup->loop = loop_device_unref(setup->loop);
- crypt_free(setup->crypt_device);
- setup->crypt_device = NULL;
+ if (setup->crypt_device) {
+ sym_crypt_free(setup->crypt_device);
+ setup->crypt_device = NULL;
+ }
explicit_bzero_safe(setup->volume_key, setup->volume_key_size);
setup->volume_key = mfree(setup->volume_key);
if (!embedded_home)
return log_oom();
- r = user_record_load(embedded_home, v, USER_RECORD_LOAD_EMBEDDED);
+ r = user_record_load(embedded_home, v, USER_RECORD_LOAD_EMBEDDED|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
assert(root_fd >= 0);
assert(uid_is_valid(uid));
- r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED, &embedded);
+ r = user_record_clone(h, USER_RECORD_EXTRACT_EMBEDDED|USER_RECORD_PERMISSIVE, &embedded);
if (r < 0)
return log_error_errno(r, "Failed to determine new embedded record: %m");
setup->found_partition_uuid,
setup->found_luks_uuid,
setup->found_fs_uuid,
- setup->crypt_device ? crypt_get_cipher(setup->crypt_device) : NULL,
- setup->crypt_device ? crypt_get_cipher_mode(setup->crypt_device) : NULL,
+ setup->crypt_device ? sym_crypt_get_cipher(setup->crypt_device) : NULL,
+ setup->crypt_device ? sym_crypt_get_cipher_mode(setup->crypt_device) : NULL,
setup->crypt_device ? luks_volume_key_size_convert(setup->crypt_device) : UINT64_MAX,
file_system_type_fd(setup->root_fd),
user_record_home_directory(used),
return log_error_errno(r, "Failed to determine whether we are in a container: %m");
if (r == 0) {
r = path_is_encrypted("/home");
- if (r < 0)
- log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m");
- if (r <= 0) {
- log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS));
- *ret = USER_LUKS;
- return 0;
- }
+ if (r > 0)
+ log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS));
+ else {
+ if (r < 0)
+ log_warning_errno(r, "Failed to determine if /home is encrypted, ignoring: %m");
- log_info("/home is encrypted, not using '%s' storage, in order to avoid double encryption.", user_storage_to_string(USER_LUKS));
+ r = dlopen_cryptsetup();
+ if (r < 0)
+ log_info("Not using '%s' storage, since libcryptsetup could not be loaded.", user_storage_to_string(USER_LUKS));
+ else {
+ log_info("Using automatic default storage of '%s'.", user_storage_to_string(USER_LUKS));
+ *ret = USER_LUKS;
+ return 0;
+ }
+ }
} else
log_info("Running in container, not using '%s' storage.", user_storage_to_string(USER_LUKS));
if (!home)
return log_oom();
- r = user_record_load(home, v, USER_RECORD_LOAD_FULL|USER_RECORD_LOG);
+ r = user_record_load(home, v, USER_RECORD_LOAD_FULL|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
* ENOANO → suitable PKCS#11/FIDO2 device found, but PIN is missing to unlock it
* ERFKILL → suitable PKCS#11 device found, but OK to ask for on-device interactive authentication not given
* EMEDIUMTYPE → suitable FIDO2 device found, but OK to ask for user presence not given
+ * ENOCSI → suitable FIDO2 device found, but OK to ask for user verification not given
* ENOSTR → suitable FIDO2 device found, but user didn't react to action request on token quickly enough
* EOWNERDEAD → suitable PKCS#11/FIDO2 device found, but its PIN is locked
* ENOLCK → suitable PKCS#11/FIDO2 device found, but PIN incorrect
if (!ur)
return pam_log_oom(handle);
- r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET);
+ r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to load user record: %s", strerror_safe(r));
return PAM_SERVICE_ERR;
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED)) {
- (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please verify presence on security token of user %s.", user_name);
+ (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please confirm presence on security token of user %s.", user_name);
r = user_record_set_fido2_user_presence_permitted(secret, true);
if (r < 0) {
return PAM_SERVICE_ERR;
}
+ } else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED)) {
+
+ (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Please verify user on security token of user %s.", user_name);
+
+ r = user_record_set_fido2_user_verification_permitted(secret, true);
+ if (r < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to set FIDO2 user verification permitted flag: %s", strerror_safe(r));
+ return PAM_SERVICE_ERR;
+ }
+
} else if (sd_bus_error_has_name(error, BUS_ERROR_TOKEN_PIN_LOCKED)) {
(void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Security token PIN is locked, please unlock it first. (Hint: Removal and re-insertion might suffice.)");
assert(ur);
assert(ret);
- r = user_record_clone(ur, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_STRIP_SECRET|USER_RECORD_STRIP_BINDING|USER_RECORD_STRIP_STATUS|USER_RECORD_STRIP_SIGNATURE, &reduced);
+ r = user_record_clone(ur, USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PRIVILEGED|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_STRIP_SECRET|USER_RECORD_STRIP_BINDING|USER_RECORD_STRIP_STATUS|USER_RECORD_STRIP_SIGNATURE|USER_RECORD_PERMISSIVE, &reduced);
if (r < 0)
return r;
if (!signed_ur)
return log_oom();
- r = user_record_load(signed_ur, v, USER_RECORD_LOAD_FULL);
+ r = user_record_load(signed_ur, v, USER_RECORD_LOAD_FULL|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
if (!merged)
return -ENOMEM;
- r = user_record_load(merged, extended, USER_RECORD_LOAD_MASK_SECRET);
+ r = user_record_load(merged, extended, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
}
/* Strip out secrets */
- r = user_record_clone(host, USER_RECORD_LOAD_MASK_SECRET, ret);
+ r = user_record_clone(host, USER_RECORD_LOAD_MASK_SECRET|USER_RECORD_PERMISSIVE, ret);
if (r < 0)
return r;
return 0;
}
+int user_record_set_fido2_user_verification_permitted(UserRecord *h, int b) {
+ _cleanup_(json_variant_unrefp) JsonVariant *w = NULL;
+ int r;
+
+ assert(h);
+
+ w = json_variant_ref(json_variant_by_key(h->json, "secret"));
+
+ if (b < 0)
+ r = json_variant_filter(&w, STRV_MAKE("fido2UserVerificationPermitted"));
+ else
+ r = json_variant_set_field_boolean(&w, "fido2UserVerificationPermitted", b);
+ if (r < 0)
+ return r;
+
+ if (json_variant_is_blank_object(w))
+ r = json_variant_filter(&h->json, STRV_MAKE("secret"));
+ else
+ r = json_variant_set_field(&h->json, "secret", w);
+ if (r < 0)
+ return r;
+
+ h->fido2_user_verification_permitted = b;
+
+ SET_FLAG(h->mask, USER_RECORD_SECRET, !json_variant_is_blank_object(w));
+ return 0;
+}
+
static bool per_machine_entry_empty(JsonVariant *v) {
const char *k;
_unused_ JsonVariant *e;
return r;
}
+ if (secret->fido2_user_verification_permitted >= 0) {
+ r = user_record_set_fido2_user_verification_permitted(
+ h,
+ secret->fido2_user_verification_permitted);
+ if (r < 0)
+ return r;
+ }
+
return 0;
}
int user_record_set_token_pin(UserRecord *h, char **pin, bool prepend);
int user_record_set_pkcs11_protected_authentication_path_permitted(UserRecord *h, int b);
int user_record_set_fido2_user_presence_permitted(UserRecord *h, int b);
+int user_record_set_fido2_user_verification_permitted(UserRecord *h, int b);
int user_record_set_password_change_now(UserRecord *h, int b);
int user_record_merge_secret(UserRecord *h, UserRecord *secret);
int user_record_good_authentication(UserRecord *h);
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PIN_NEEDED, ENOANO),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED, ERFKILL),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED, EMEDIUMTYPE),
+ SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED, ENOCSI),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_ACTION_TIMEOUT, ENOSTR),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_PIN_LOCKED, EOWNERDEAD),
SD_BUS_ERROR_MAP(BUS_ERROR_TOKEN_BAD_PIN, ENOLCK),
#define BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED \
"org.freedesktop.home1.TokenProtectedAuthenticationPathNeeded"
#define BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED "org.freedesktop.home1.TokenUserPresenceNeeded"
+#define BUS_ERROR_TOKEN_USER_VERIFICATION_NEEDED \
+ "org.freedesktop.home1.TokenUserVerificationNeeded"
#define BUS_ERROR_TOKEN_ACTION_TIMEOUT "org.freedesktop.home1.TokenActionTimeout"
#define BUS_ERROR_TOKEN_PIN_LOCKED "org.freedesktop.home1.TokenPinLocked"
#define BUS_ERROR_TOKEN_BAD_PIN "org.freedesktop.home1.BadPin"
if (!ur)
return pam_log_oom(handle);
- r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET);
+ r = user_record_load(ur, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_PERMISSIVE);
if (r < 0) {
pam_syslog(handle, LOG_ERR, "Failed to load user record: %s", strerror_safe(r));
return PAM_SERVICE_ERR;
USER_RECORD_STRIP_PRIVILEGED|
USER_RECORD_ALLOW_PER_MACHINE|
USER_RECORD_ALLOW_BINDING|
- USER_RECORD_ALLOW_SIGNATURE;
+ USER_RECORD_ALLOW_SIGNATURE|
+ USER_RECORD_PERMISSIVE;
static const UserRecordLoadFlags shadow_flags = /* Extracts privileged info */
USER_RECORD_STRIP_REGULAR|
USER_RECORD_ALLOW_PRIVILEGED|
USER_RECORD_STRIP_PER_MACHINE|
USER_RECORD_STRIP_BINDING|
USER_RECORD_STRIP_SIGNATURE|
- USER_RECORD_EMPTY_OK;
+ USER_RECORD_EMPTY_OK|
+ USER_RECORD_PERMISSIVE;
int r;
assert(root);
int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags);
int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params);
void (*sym_crypt_free)(struct crypt_device *cd);
+const char *(*sym_crypt_get_cipher)(struct crypt_device *cd);
+const char *(*sym_crypt_get_cipher_mode)(struct crypt_device *cd);
+uint64_t (*sym_crypt_get_data_offset)(struct crypt_device *cd);
+const char *(*sym_crypt_get_device_name)(struct crypt_device *cd);
const char *(*sym_crypt_get_dir)(void);
+const char *(*sym_crypt_get_type)(struct crypt_device *cd);
+const char *(*sym_crypt_get_uuid)(struct crypt_device *cd);
int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp);
+int (*sym_crypt_get_volume_key_size)(struct crypt_device *cd);
int (*sym_crypt_init)(struct crypt_device **cd, const char *device);
int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name);
int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size);
+int (*sym_crypt_keyslot_destroy)(struct crypt_device *cd, int keyslot);
+int (*sym_crypt_keyslot_max)(const char *type);
int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params);
int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size);
+int (*sym_crypt_resume_by_passphrase)(struct crypt_device *cd, const char *name, int keyslot, const char *passphrase, size_t passphrase_size);
int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device);
void (*sym_crypt_set_debug_level)(int level);
void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr);
-int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf) = NULL;
-int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json) = NULL;
-int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json) = NULL;
-int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
+#if HAVE_CRYPT_SET_METADATA_SIZE
+int (*sym_crypt_set_metadata_size)(struct crypt_device *cd, uint64_t metadata_size, uint64_t keyslots_size);
+#endif
+int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf);
+int (*sym_crypt_suspend)(struct crypt_device *cd, const char *name);
+int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json);
+int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json);
#if HAVE_CRYPT_TOKEN_MAX
int (*sym_crypt_token_max)(const char *type);
#endif
+crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, const char **type);
+int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
int dlopen_cryptsetup(void) {
_cleanup_(dlclosep) void *dl = NULL;
DLSYM_ARG(crypt_deactivate_by_name),
DLSYM_ARG(crypt_format),
DLSYM_ARG(crypt_free),
+ DLSYM_ARG(crypt_get_cipher),
+ DLSYM_ARG(crypt_get_cipher_mode),
+ DLSYM_ARG(crypt_get_data_offset),
+ DLSYM_ARG(crypt_get_device_name),
DLSYM_ARG(crypt_get_dir),
+ DLSYM_ARG(crypt_get_type),
+ DLSYM_ARG(crypt_get_uuid),
DLSYM_ARG(crypt_get_verity_info),
+ DLSYM_ARG(crypt_get_volume_key_size),
DLSYM_ARG(crypt_init),
DLSYM_ARG(crypt_init_by_name),
DLSYM_ARG(crypt_keyslot_add_by_volume_key),
+ DLSYM_ARG(crypt_keyslot_destroy),
+ DLSYM_ARG(crypt_keyslot_max),
DLSYM_ARG(crypt_load),
DLSYM_ARG(crypt_resize),
+ DLSYM_ARG(crypt_resume_by_passphrase),
DLSYM_ARG(crypt_set_data_device),
DLSYM_ARG(crypt_set_debug_level),
DLSYM_ARG(crypt_set_log_callback),
+#if HAVE_CRYPT_SET_METADATA_SIZE
+ DLSYM_ARG(crypt_set_metadata_size),
+#endif
DLSYM_ARG(crypt_set_pbkdf_type),
+ DLSYM_ARG(crypt_suspend),
DLSYM_ARG(crypt_token_json_get),
DLSYM_ARG(crypt_token_json_set),
- DLSYM_ARG(crypt_volume_key_get),
#if HAVE_CRYPT_TOKEN_MAX
DLSYM_ARG(crypt_token_max),
#endif
+ DLSYM_ARG(crypt_token_status),
+ DLSYM_ARG(crypt_volume_key_get),
NULL);
if (r < 0)
return r;
/* Note that we never release the reference here, because there's no real reason to, after all this
* was traditionally a regular shared library dependency which lives forever too. */
cryptsetup_dl = TAKE_PTR(dl);
+
+ /* Redirect the default logging calls of libcryptsetup to our own logging infra. (Note that
+ * libcryptsetup also maintains per-"struct crypt_device" log functions, which we'll also set
+ * whenever allocating a "struct crypt_device" context. Why set both? To be defensive: maybe some
+ * other code loaded into this process also changes the global log functions of libcryptsetup, who
+ * knows? And if so, we still want our own objects to log via our own infra, at the very least.) */
+ cryptsetup_enable_logging(NULL);
return 1;
}
}
void cryptsetup_enable_logging(struct crypt_device *cd) {
- if (!cd)
- return;
-
- if (dlopen_cryptsetup() < 0) /* If this fails, let's gracefully ignore the issue, this is just debug
- * logging after all, and if this failed we already generated a debug
- * log message that should help to track things down. */
- return;
+ /* It's OK to call this with a NULL parameter, in which case libcryptsetup will set the defaut log
+ * function.
+ *
+ * Note that this is also called from dlopen_cryptsetup(), which we call here too. Sounds like an
+ * endless loop, but isn't because we break it via the check for 'cryptsetup_dl' early in
+ * dlopen_cryptsetup(). */
+
+ if (dlopen_cryptsetup() < 0)
+ return; /* If this fails, let's gracefully ignore the issue, this is just debug logging after
+ * all, and if this failed we already generated a debug log message that should help
+ * to track things down. */
sym_crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
sym_crypt_set_debug_level(DEBUG_LOGGING ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE);
extern int (*sym_crypt_deactivate_by_name)(struct crypt_device *cd, const char *name, uint32_t flags);
extern int (*sym_crypt_format)(struct crypt_device *cd, const char *type, const char *cipher, const char *cipher_mode, const char *uuid, const char *volume_key, size_t volume_key_size, void *params);
extern void (*sym_crypt_free)(struct crypt_device *cd);
+extern const char *(*sym_crypt_get_cipher)(struct crypt_device *cd);
+extern const char *(*sym_crypt_get_cipher_mode)(struct crypt_device *cd);
+extern uint64_t (*sym_crypt_get_data_offset)(struct crypt_device *cd);
+extern const char *(*sym_crypt_get_device_name)(struct crypt_device *cd);
extern const char *(*sym_crypt_get_dir)(void);
+extern const char *(*sym_crypt_get_type)(struct crypt_device *cd);
+extern const char *(*sym_crypt_get_uuid)(struct crypt_device *cd);
extern int (*sym_crypt_get_verity_info)(struct crypt_device *cd, struct crypt_params_verity *vp);
+extern int (*sym_crypt_get_volume_key_size)(struct crypt_device *cd);
extern int (*sym_crypt_init)(struct crypt_device **cd, const char *device);
extern int (*sym_crypt_init_by_name)(struct crypt_device **cd, const char *name);
extern int (*sym_crypt_keyslot_add_by_volume_key)(struct crypt_device *cd, int keyslot, const char *volume_key, size_t volume_key_size, const char *passphrase, size_t passphrase_size);
+extern int (*sym_crypt_keyslot_destroy)(struct crypt_device *cd, int keyslot);
+extern int (*sym_crypt_keyslot_max)(const char *type);
extern int (*sym_crypt_load)(struct crypt_device *cd, const char *requested_type, void *params);
extern int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_size);
+extern int (*sym_crypt_resume_by_passphrase)(struct crypt_device *cd, const char *name, int keyslot, const char *passphrase, size_t passphrase_size);
extern int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device);
extern void (*sym_crypt_set_debug_level)(int level);
extern void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr);
+#if HAVE_CRYPT_SET_METADATA_SIZE
+extern int (*sym_crypt_set_metadata_size)(struct crypt_device *cd, uint64_t metadata_size, uint64_t keyslots_size);
+#endif
extern int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf);
+extern int (*sym_crypt_suspend)(struct crypt_device *cd, const char *name);
extern int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json);
extern int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json);
-extern int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
#if HAVE_CRYPT_TOKEN_MAX
extern int (*sym_crypt_token_max)(const char *type);
#else
return 32;
}
#endif
+extern crypt_token_info (*sym_crypt_token_status)(struct crypt_device *cd, int token, const char **type);
+extern int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size);
int dlopen_cryptsetup(void);
if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_init_by_name failed: %m");
+ cryptsetup_enable_logging(cd);
+
r = sym_crypt_get_verity_info(cd, &crypt_params);
if (r < 0)
return log_debug_errno(r, "Error opening verity device, crypt_get_verity_info failed: %m");
.password_change_now = -1,
.pkcs11_protected_authentication_path_permitted = -1,
.fido2_user_presence_permitted = -1,
+ .fido2_user_verification_permitted = -1,
};
return h;
{ "pkcs11Pin", /* legacy alias */ _JSON_VARIANT_TYPE_INVALID, json_dispatch_strv, offsetof(UserRecord, token_pin), 0 },
{ "pkcs11ProtectedAuthenticationPathPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, pkcs11_protected_authentication_path_permitted), 0 },
{ "fido2UserPresencePermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, fido2_user_presence_permitted), 0 },
+ { "fido2UserVerificationPermitted", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, fido2_user_verification_permitted), 0 },
{},
};
Fido2HmacSalt *array, *k;
static const JsonDispatch fido2_hmac_salt_dispatch_table[] = {
- { "credential", JSON_VARIANT_STRING, dispatch_fido2_hmac_credential, offsetof(Fido2HmacSalt, credential), JSON_MANDATORY },
- { "salt", JSON_VARIANT_STRING, dispatch_fido2_hmac_salt_value, 0, JSON_MANDATORY },
- { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Fido2HmacSalt, hashed_password), JSON_MANDATORY },
+ { "credential", JSON_VARIANT_STRING, dispatch_fido2_hmac_credential, offsetof(Fido2HmacSalt, credential), JSON_MANDATORY },
+ { "salt", JSON_VARIANT_STRING, dispatch_fido2_hmac_salt_value, 0, JSON_MANDATORY },
+ { "hashedPassword", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Fido2HmacSalt, hashed_password), JSON_MANDATORY },
+ { "up", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, up), 0 },
+ { "uv", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, uv), 0 },
+ { "clientPin", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(Fido2HmacSalt, client_pin), 0 },
{},
};
h->fido2_hmac_salt = array;
k = h->fido2_hmac_salt + h->n_fido2_hmac_salt;
- *k = (Fido2HmacSalt) {};
+ *k = (Fido2HmacSalt) {
+ .uv = -1,
+ .up = -1,
+ .client_pin = -1,
+ };
r = json_dispatch(e, fido2_hmac_salt_dispatch_table, NULL, flags, k);
if (r < 0) {
/* Compares the two records, but ignores anything not listed in the specified mask */
if ((a->mask & ~mask) != 0) {
- r = user_record_clone(a, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &x);
+ r = user_record_clone(a, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX) | USER_RECORD_PERMISSIVE, &x);
if (r < 0)
return r;
}
if ((b->mask & ~mask) != 0) {
- r = user_record_clone(b, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX), &y);
+ r = user_record_clone(b, USER_RECORD_ALLOW(mask) | USER_RECORD_STRIP(~mask & _USER_RECORD_MASK_MAX) | USER_RECORD_PERMISSIVE, &y);
if (r < 0)
return r;
/* What to test the hashed salt value against, usually UNIX password hash here. */
char *hashed_password;
+
+ /* Whether the 'up', 'uv', 'clientPin' features are enabled. */
+ int uv, up, client_pin;
} Fido2HmacSalt;
typedef struct RecoveryKey {
Fido2HmacSalt *fido2_hmac_salt;
size_t n_fido2_hmac_salt;
int fido2_user_presence_permitted;
+ int fido2_user_verification_permitted;
char **recovery_key_type;
RecoveryKey *recovery_key;
USER_RECORD_ALLOW_PER_MACHINE|
USER_RECORD_ALLOW_BINDING|
USER_RECORD_ALLOW_SIGNATURE|
- (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0));
+ (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0)|
+ USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
USER_RECORD_ALLOW_PER_MACHINE|
USER_RECORD_ALLOW_BINDING|
USER_RECORD_ALLOW_SIGNATURE|
- (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0));
+ (have_privileged ? USER_RECORD_ALLOW_PRIVILEGED : 0)|
+ USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
} else
trusted = peer_uid == 0 || peer_uid == ur->uid;
- flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE;
+ flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
if (trusted)
flags |= USER_RECORD_ALLOW_PRIVILEGED;
else
} else
trusted = peer_uid == 0;
- flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE;
+ flags = USER_RECORD_REQUIRE_REGULAR|USER_RECORD_ALLOW_PER_MACHINE|USER_RECORD_ALLOW_BINDING|USER_RECORD_STRIP_SECRET|USER_RECORD_ALLOW_STATUS|USER_RECORD_ALLOW_SIGNATURE|USER_RECORD_PERMISSIVE;
if (trusted)
flags |= USER_RECORD_ALLOW_PRIVILEGED;
else
log_setup();
+ cryptsetup_enable_logging(NULL);
+
umask(0022);
if (streq(argv[1], "attach")) {