]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptsetup/cryptsetup-tokens/luks2-pkcs11.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup-tokens / luks2-pkcs11.c
CommitLineData
8186022c
OK
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <p11-kit/p11-kit.h>
4#include <p11-kit/uri.h>
5
6#include "cryptsetup-token-util.h"
7#include "escape.h"
8#include "hexdecoct.h"
9#include "json.h"
10#include "luks2-pkcs11.h"
11#include "memory-util.h"
12#include "pkcs11-util.h"
13#include "time-util.h"
14
15struct luks2_pkcs11_callback_data {
16 struct crypt_device *cd;
17 const char *pin;
18 size_t pin_size;
19 void *encrypted_key;
20 size_t encrypted_key_size;
21 void *decrypted_key;
22 size_t decrypted_key_size;
23};
24
25static int luks2_pkcs11_callback(
26 CK_FUNCTION_LIST *m,
27 CK_SESSION_HANDLE session,
28 CK_SLOT_ID slot_id,
29 const CK_SLOT_INFO *slot_info,
30 const CK_TOKEN_INFO *token_info,
31 P11KitUri *uri,
32 void *userdata) {
33
34 CK_OBJECT_HANDLE object;
35 CK_RV rv;
36 CK_TOKEN_INFO updated_token_info;
37 int r;
38 _cleanup_free_ char *token_label = NULL;
99534007 39 struct luks2_pkcs11_callback_data *data = ASSERT_PTR(userdata);
8186022c
OK
40
41 assert(m);
42 assert(slot_info);
43 assert(token_info);
44 assert(uri);
8186022c
OK
45
46 token_label = pkcs11_token_label(token_info);
47 if (!token_label)
48 return -ENOMEM;
49
50 /* Called for every token matching our URI */
51 r = pkcs11_token_login_by_pin(m, session, token_info, token_label, data->pin, data->pin_size);
52 if (r == -ENOLCK) {
53 /* Referesh the token info, so that we can prompt knowing the new flags if they changed. */
54 rv = m->C_GetTokenInfo(slot_id, &updated_token_info);
55 if (rv != CKR_OK) {
56 crypt_log_error(data->cd,
57 "Failed to acquire updated security token information for slot %lu: %s",
58 slot_id, p11_kit_strerror(rv));
59 return -EIO;
60 }
61 token_info = &updated_token_info;
62 r = -ENOANO;
63 }
64
65 if (r == -ENOANO) {
66 if (FLAGS_SET(token_info->flags, CKF_USER_PIN_FINAL_TRY))
67 crypt_log_error(data->cd, "Please enter correct PIN for security token "
68 "'%s' in order to unlock it (final try).", token_label);
69 else if (FLAGS_SET(token_info->flags, CKF_USER_PIN_COUNT_LOW))
70 crypt_log_error(data->cd, "PIN has been entered incorrectly previously, "
71 "please enter correct PIN for security token '%s' in order to unlock it.",
72 token_label);
73 }
74
75 if (r == -EPERM) /* pin is locked, but map it to -ENOANO anyway */
76 r = -ENOANO;
77
78 if (r < 0)
79 return r;
80
81 r = pkcs11_token_find_private_key(m, session, uri, &object);
82 if (r < 0)
83 return r;
84
85 r = pkcs11_token_decrypt_data(
86 m,
87 session,
88 object,
89 data->encrypted_key,
90 data->encrypted_key_size,
91 &data->decrypted_key,
92 &data->decrypted_key_size);
93 if (r < 0)
94 return r;
95
96 return 0;
97}
98
99static void luks2_pkcs11_callback_data_release(struct luks2_pkcs11_callback_data *data) {
100 erase_and_free(data->decrypted_key);
101}
102
103static int acquire_luks2_key_by_pin(
104 struct crypt_device *cd,
105 const char *pkcs11_uri,
106 const void *pin,
107 size_t pin_size,
108 void *encrypted_key,
109 size_t encrypted_key_size,
110 void **ret_decrypted_key,
111 size_t *ret_decrypted_key_size) {
112
113 int r;
114 _cleanup_(luks2_pkcs11_callback_data_release) struct luks2_pkcs11_callback_data data = {
115 .cd = cd,
116 .pin = pin,
117 .pin_size = pin_size,
118 .encrypted_key = encrypted_key,
119 .encrypted_key_size = encrypted_key_size,
120 };
121
122 assert(pkcs11_uri);
123 assert(encrypted_key);
124 assert(ret_decrypted_key);
125 assert(ret_decrypted_key_size);
126
127 r = pkcs11_find_token(pkcs11_uri, luks2_pkcs11_callback, &data);
128 if (r < 0)
129 return r;
130
131 *ret_decrypted_key = TAKE_PTR(data.decrypted_key);
132 *ret_decrypted_key_size = data.decrypted_key_size;
133
134 return 0;
135}
136
137/* called from within systemd utilities */
138static int acquire_luks2_key_systemd(
139 const char *pkcs11_uri,
140 systemd_pkcs11_plugin_params *params,
141 void *encrypted_key,
142 size_t encrypted_key_size,
143 void **ret_decrypted_key,
144 size_t *ret_decrypted_key_size) {
145
146 int r;
147 _cleanup_(pkcs11_crypt_device_callback_data_release) pkcs11_crypt_device_callback_data data = {
148 .encrypted_key = encrypted_key,
149 .encrypted_key_size = encrypted_key_size,
150 .free_encrypted_key = false
151 };
152
153 assert(pkcs11_uri);
154 assert(encrypted_key);
155 assert(ret_decrypted_key);
156 assert(ret_decrypted_key_size);
157 assert(params);
158
159 data.friendly_name = params->friendly_name;
160 data.headless = params->headless;
161 data.until = params->until;
162
163 /* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
164 r = pkcs11_find_token(pkcs11_uri, pkcs11_crypt_device_callback, &data);
165 if (r < 0)
166 return r;
167
168 *ret_decrypted_key = TAKE_PTR(data.decrypted_key);
169 *ret_decrypted_key_size = data.decrypted_key_size;
170
171 return 0;
172}
173
174int acquire_luks2_key(
175 struct crypt_device *cd,
176 const char *json,
177 void *userdata,
178 const void *pin,
179 size_t pin_size,
180 char **ret_password,
181 size_t *ret_password_size) {
182
183 int r;
184 size_t decrypted_key_size, encrypted_key_size;
185 _cleanup_(erase_and_freep) void *decrypted_key = NULL;
186 _cleanup_(erase_and_freep) char *base64_encoded = NULL;
187 _cleanup_free_ char *pkcs11_uri = NULL;
188 _cleanup_free_ void *encrypted_key = NULL;
189 systemd_pkcs11_plugin_params *pkcs11_params = userdata;
190
191 assert(json);
192 assert(ret_password);
193 assert(ret_password_size);
194
195 r = parse_luks2_pkcs11_data(cd, json, &pkcs11_uri, &encrypted_key, &encrypted_key_size);
196 if (r < 0)
197 return r;
198
199 if (pkcs11_params && pin)
200 crypt_log_verbose(cd, "PIN parameter ignored in interactive mode.");
201
202 if (pkcs11_params) /* systemd based activation with interactive pin query callbacks */
203 r = acquire_luks2_key_systemd(
204 pkcs11_uri,
205 pkcs11_params,
206 encrypted_key, encrypted_key_size,
207 &decrypted_key, &decrypted_key_size);
208 else /* default activation that provides single PIN if needed */
209 r = acquire_luks2_key_by_pin(
210 cd, pkcs11_uri, pin, pin_size,
211 encrypted_key, encrypted_key_size,
212 &decrypted_key, &decrypted_key_size);
213 if (r < 0)
214 return r;
215
216 r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded);
217 if (r < 0)
218 return crypt_log_error_errno(cd, r, "Can not base64 encode key: %m");
219
220 *ret_password = TAKE_PTR(base64_encoded);
221 *ret_password_size = strlen(*ret_password);
222
223 return 0;
224}
225
226int parse_luks2_pkcs11_data(
227 struct crypt_device *cd,
228 const char *json,
229 char **ret_uri,
230 void **ret_encrypted_key,
231 size_t *ret_encrypted_key_size) {
232
233 int r;
234 size_t key_size;
235 _cleanup_free_ char *uri = NULL;
236 _cleanup_free_ void *key = NULL;
237 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
238 JsonVariant *w;
239
240 assert(json);
241 assert(ret_uri);
242 assert(ret_encrypted_key);
243 assert(ret_encrypted_key_size);
244
245 r = json_parse(json, 0, &v, NULL, NULL);
246 if (r < 0)
247 return r;
248
249 w = json_variant_by_key(v, "pkcs11-uri");
250 if (!w)
251 return -EINVAL;
252
253 uri = strdup(json_variant_string(w));
254 if (!uri)
255 return -ENOMEM;
256
257 w = json_variant_by_key(v, "pkcs11-key");
258 if (!w)
259 return -EINVAL;
260
261 r = unbase64mem(json_variant_string(w), SIZE_MAX, &key, &key_size);
262 if (r < 0)
263 return crypt_log_debug_errno(cd, r, "Failed to decode base64 encoded key: %m.");
264
265 *ret_uri = TAKE_PTR(uri);
266 *ret_encrypted_key = TAKE_PTR(key);
267 *ret_encrypted_key_size = key_size;
268
269 return 0;
270}