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