]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
93295a25 LP |
2 | |
3 | #include "errno-util.h" | |
0eb3be46 | 4 | #include "format-table.h" |
93295a25 LP |
5 | #include "hexdecoct.h" |
6 | #include "homectl-pkcs11.h" | |
7 | #include "libcrypt-util.h" | |
8 | #include "memory-util.h" | |
9 | #include "openssl-util.h" | |
10 | #include "pkcs11-util.h" | |
93295a25 LP |
11 | #include "strv.h" |
12 | ||
309a747f LP |
13 | int identity_add_token_pin(sd_json_variant **v, const char *pin) { |
14 | _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL, *l = NULL; | |
85686b37 | 15 | _cleanup_strv_free_erase_ char **pins = NULL; |
93295a25 LP |
16 | int r; |
17 | ||
18 | assert(v); | |
93295a25 | 19 | |
85686b37 VS |
20 | if (isempty(pin)) |
21 | return 0; | |
93295a25 | 22 | |
309a747f LP |
23 | w = sd_json_variant_ref(sd_json_variant_by_key(*v, "secret")); |
24 | l = sd_json_variant_ref(sd_json_variant_by_key(w, "tokenPin")); | |
85686b37 | 25 | |
309a747f | 26 | r = sd_json_variant_strv(l, &pins); |
0e98d17e | 27 | if (r < 0) |
85686b37 | 28 | return log_error_errno(r, "Failed to convert PIN array: %m"); |
93295a25 | 29 | |
85686b37 VS |
30 | if (strv_contains(pins, pin)) |
31 | return 0; | |
32 | ||
33 | r = strv_extend(&pins, pin); | |
93295a25 | 34 | if (r < 0) |
85686b37 | 35 | return log_oom(); |
93295a25 | 36 | |
85686b37 | 37 | strv_uniq(pins); |
93295a25 | 38 | |
309a747f | 39 | l = sd_json_variant_unref(l); |
85686b37 | 40 | |
309a747f | 41 | r = sd_json_variant_new_array_strv(&l, pins); |
93295a25 | 42 | if (r < 0) |
85686b37 | 43 | return log_error_errno(r, "Failed to allocate new PIN array JSON: %m"); |
93295a25 | 44 | |
309a747f | 45 | sd_json_variant_sensitive(l); |
85686b37 | 46 | |
309a747f | 47 | r = sd_json_variant_set_field(&w, "tokenPin", l); |
93295a25 | 48 | if (r < 0) |
85686b37 | 49 | return log_error_errno(r, "Failed to update PIN field: %m"); |
93295a25 | 50 | |
309a747f | 51 | r = sd_json_variant_set_field(v, "secret", w); |
93295a25 | 52 | if (r < 0) |
85686b37 | 53 | return log_error_errno(r, "Failed to update secret object: %m"); |
93295a25 | 54 | |
85686b37 | 55 | return 1; |
93295a25 LP |
56 | } |
57 | ||
85686b37 VS |
58 | #if HAVE_P11KIT |
59 | ||
309a747f LP |
60 | static int add_pkcs11_token_uri(sd_json_variant **v, const char *uri) { |
61 | _cleanup_(sd_json_variant_unrefp) sd_json_variant *w = NULL; | |
93295a25 LP |
62 | _cleanup_strv_free_ char **l = NULL; |
63 | int r; | |
64 | ||
65 | assert(v); | |
66 | assert(uri); | |
67 | ||
309a747f | 68 | w = sd_json_variant_ref(sd_json_variant_by_key(*v, "pkcs11TokenUri")); |
93295a25 | 69 | if (w) { |
309a747f | 70 | r = sd_json_variant_strv(w, &l); |
93295a25 LP |
71 | if (r < 0) |
72 | return log_error_errno(r, "Failed to parse PKCS#11 token list: %m"); | |
73 | ||
74 | if (strv_contains(l, uri)) | |
75 | return 0; | |
76 | } | |
77 | ||
78 | r = strv_extend(&l, uri); | |
79 | if (r < 0) | |
80 | return log_oom(); | |
81 | ||
309a747f LP |
82 | w = sd_json_variant_unref(w); |
83 | r = sd_json_variant_new_array_strv(&w, l); | |
93295a25 LP |
84 | if (r < 0) |
85 | return log_error_errno(r, "Failed to create PKCS#11 token URI JSON: %m"); | |
86 | ||
309a747f | 87 | r = sd_json_variant_set_field(v, "pkcs11TokenUri", w); |
93295a25 LP |
88 | if (r < 0) |
89 | return log_error_errno(r, "Failed to update PKCS#11 token URI list: %m"); | |
90 | ||
91 | return 0; | |
92 | } | |
93 | ||
85686b37 | 94 | static int add_pkcs11_encrypted_key( |
309a747f | 95 | sd_json_variant **v, |
85686b37 VS |
96 | const char *uri, |
97 | const void *encrypted_key, size_t encrypted_key_size, | |
98 | const void *decrypted_key, size_t decrypted_key_size) { | |
99 | ||
309a747f | 100 | _cleanup_(sd_json_variant_unrefp) sd_json_variant *l = NULL, *w = NULL, *e = NULL; |
85686b37 VS |
101 | _cleanup_(erase_and_freep) char *base64_encoded = NULL, *hashed = NULL; |
102 | ssize_t base64_encoded_size; | |
93295a25 LP |
103 | int r; |
104 | ||
105 | assert(v); | |
85686b37 VS |
106 | assert(uri); |
107 | assert(encrypted_key); | |
108 | assert(encrypted_key_size > 0); | |
109 | assert(decrypted_key); | |
110 | assert(decrypted_key_size > 0); | |
93295a25 | 111 | |
85686b37 VS |
112 | /* Before using UNIX hashing on the supplied key we base64 encode it, since crypt_r() and friends |
113 | * expect a NUL terminated string, and we use a binary key */ | |
114 | base64_encoded_size = base64mem(decrypted_key, decrypted_key_size, &base64_encoded); | |
115 | if (base64_encoded_size < 0) | |
116 | return log_error_errno(base64_encoded_size, "Failed to base64 encode secret key: %m"); | |
93295a25 | 117 | |
85686b37 | 118 | r = hash_password(base64_encoded, &hashed); |
93295a25 | 119 | if (r < 0) |
85686b37 | 120 | return log_error_errno(errno_or_else(EINVAL), "Failed to UNIX hash secret key: %m"); |
93295a25 | 121 | |
309a747f LP |
122 | r = sd_json_build(&e, SD_JSON_BUILD_OBJECT( |
123 | SD_JSON_BUILD_PAIR("uri", SD_JSON_BUILD_STRING(uri)), | |
124 | SD_JSON_BUILD_PAIR("data", SD_JSON_BUILD_BASE64(encrypted_key, encrypted_key_size)), | |
125 | SD_JSON_BUILD_PAIR("hashedPassword", SD_JSON_BUILD_STRING(hashed)))); | |
93295a25 | 126 | if (r < 0) |
85686b37 | 127 | return log_error_errno(r, "Failed to build encrypted JSON key object: %m"); |
93295a25 | 128 | |
309a747f LP |
129 | w = sd_json_variant_ref(sd_json_variant_by_key(*v, "privileged")); |
130 | l = sd_json_variant_ref(sd_json_variant_by_key(w, "pkcs11EncryptedKey")); | |
93295a25 | 131 | |
309a747f | 132 | r = sd_json_variant_append_array(&l, e); |
93295a25 | 133 | if (r < 0) |
85686b37 | 134 | return log_error_errno(r, "Failed append PKCS#11 encrypted key: %m"); |
93295a25 | 135 | |
309a747f | 136 | r = sd_json_variant_set_field(&w, "pkcs11EncryptedKey", l); |
93295a25 | 137 | if (r < 0) |
85686b37 | 138 | return log_error_errno(r, "Failed to set PKCS#11 encrypted key: %m"); |
93295a25 | 139 | |
309a747f | 140 | r = sd_json_variant_set_field(v, "privileged", w); |
93295a25 | 141 | if (r < 0) |
85686b37 | 142 | return log_error_errno(r, "Failed to update privileged field: %m"); |
93295a25 | 143 | |
85686b37 | 144 | return 0; |
bf108eb9 FW |
145 | } |
146 | ||
309a747f | 147 | int identity_add_pkcs11_key_data(sd_json_variant **v, const char *uri) { |
876206f2 | 148 | _cleanup_(erase_and_freep) void *decrypted_key = NULL, *saved_key = NULL; |
93295a25 | 149 | _cleanup_(erase_and_freep) char *pin = NULL; |
876206f2 | 150 | size_t decrypted_key_size, saved_key_size; |
85686b37 | 151 | _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL; |
d041e4fc | 152 | int r; |
93295a25 LP |
153 | |
154 | assert(v); | |
155 | ||
b2ac9280 LP |
156 | r = pkcs11_acquire_public_key( |
157 | uri, | |
158 | "home directory operation", | |
159 | "user-home", | |
160 | "home.token-pin", | |
161 | /* askpw_flags= */ 0, | |
162 | &pkey, | |
163 | &pin); | |
93295a25 LP |
164 | if (r < 0) |
165 | return r; | |
166 | ||
85686b37 | 167 | r = pkey_generate_volume_keys(pkey, &decrypted_key, &decrypted_key_size, &saved_key, &saved_key_size); |
93295a25 | 168 | if (r < 0) |
876206f2 | 169 | return log_error_errno(r, "Failed to generate volume keys: %m"); |
93295a25 LP |
170 | |
171 | /* Add the token URI to the public part of the record. */ | |
172 | r = add_pkcs11_token_uri(v, uri); | |
173 | if (r < 0) | |
174 | return r; | |
175 | ||
176 | /* Include the encrypted version of the random key we just generated in the privileged part of the record */ | |
177 | r = add_pkcs11_encrypted_key( | |
178 | v, | |
179 | uri, | |
876206f2 | 180 | saved_key, saved_key_size, |
93295a25 LP |
181 | decrypted_key, decrypted_key_size); |
182 | if (r < 0) | |
183 | return r; | |
184 | ||
185 | /* If we acquired the PIN also include it in the secret section of the record, so that systemd-homed | |
186 | * can use it if it needs to, given that it likely needs to decrypt the key again to pass to LUKS or | |
187 | * fscrypt. */ | |
188 | r = identity_add_token_pin(v, pin); | |
189 | if (r < 0) | |
190 | return r; | |
191 | ||
192 | return 0; | |
193 | } | |
85686b37 VS |
194 | |
195 | #endif |