]>
Commit | Line | Data |
---|---|---|
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 | ||
10 | int 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 | } |