]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptenroll/cryptenroll-fido2.c
FIDO2: support pin-less LUKS enroll/unlock
[thirdparty/systemd.git] / src / cryptenroll / cryptenroll-fido2.c
CommitLineData
8710a681
LP
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "cryptenroll-fido2.h"
4#include "hexdecoct.h"
5#include "json.h"
6#include "libfido2-util.h"
7#include "memory-util.h"
8#include "random-util.h"
9
10int enroll_fido2(
11 struct crypt_device *cd,
12 const void *volume_key,
13 size_t volume_key_size,
cde2f860
LB
14 const char *device,
15 Fido2EnrollFlags lock_with) {
8710a681
LP
16
17 _cleanup_(erase_and_freep) void *salt = NULL, *secret = NULL;
18 _cleanup_(erase_and_freep) char *base64_encoded = NULL;
19 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
20 _cleanup_free_ char *keyslot_as_string = NULL;
21 size_t cid_size, salt_size, secret_size;
22 _cleanup_free_ void *cid = NULL;
23 const char *node, *un;
24 int r, keyslot;
25
26 assert_se(cd);
27 assert_se(volume_key);
28 assert_se(volume_key_size > 0);
29 assert_se(device);
30
31 assert_se(node = crypt_get_device_name(cd));
32
33 un = strempty(crypt_get_uuid(cd));
34
35 r = fido2_generate_hmac_hash(
36 device,
37 /* rp_id= */ "io.systemd.cryptsetup",
38 /* rp_name= */ "Encrypted Volume",
39 /* user_id= */ un, strlen(un), /* We pass the user ID and name as the same: the disk's UUID if we have it */
40 /* user_name= */ un,
41 /* user_display_name= */ node,
42 /* user_icon_name= */ NULL,
43 /* askpw_icon_name= */ "drive-harddisk",
cde2f860 44 lock_with,
8710a681
LP
45 &cid, &cid_size,
46 &salt, &salt_size,
47 &secret, &secret_size,
48 NULL);
49 if (r < 0)
50 return r;
51
52 /* Before we use the secret, we base64 encode it, for compat with homed, and to make it easier to type in manually */
53 r = base64mem(secret, secret_size, &base64_encoded);
54 if (r < 0)
55 return log_error_errno(r, "Failed to base64 encode secret key: %m");
56
57 r = cryptsetup_set_minimal_pbkdf(cd);
58 if (r < 0)
59 return log_error_errno(r, "Failed to set minimal PBKDF: %m");
60
61 keyslot = crypt_keyslot_add_by_volume_key(
62 cd,
63 CRYPT_ANY_SLOT,
64 volume_key,
65 volume_key_size,
66 base64_encoded,
67 strlen(base64_encoded));
68 if (keyslot < 0)
69 return log_error_errno(keyslot, "Failed to add new PKCS#11 key to %s: %m", node);
70
71 if (asprintf(&keyslot_as_string, "%i", keyslot) < 0)
72 return log_oom();
73
74 r = json_build(&v,
75 JSON_BUILD_OBJECT(
76 JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-fido2")),
77 JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))),
78 JSON_BUILD_PAIR("fido2-credential", JSON_BUILD_BASE64(cid, cid_size)),
79 JSON_BUILD_PAIR("fido2-salt", JSON_BUILD_BASE64(salt, salt_size)),
cde2f860
LB
80 JSON_BUILD_PAIR("fido2-rp", JSON_BUILD_STRING("io.systemd.cryptsetup")),
81 JSON_BUILD_PAIR("fido2-clientPin-required", JSON_BUILD_BOOLEAN(FLAGS_SET(lock_with, FIDO2ENROLL_PIN)))));
8710a681
LP
82 if (r < 0)
83 return log_error_errno(r, "Failed to prepare PKCS#11 JSON token object: %m");
84
85 r = cryptsetup_add_token_json(cd, v);
86 if (r < 0)
87 return log_error_errno(r, "Failed to add FIDO2 JSON token to LUKS2 header: %m");
88
89 log_info("New FIDO2 token enrolled as key slot %i.", keyslot);
90 return keyslot;
91}