1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
7 #include <p11-kit/p11-kit.h>
8 #include <p11-kit/uri.h>
10 #include "alloc-util.h"
11 #include "ask-password-api.h"
12 #include "cryptsetup-pkcs11.h"
16 #include "format-util.h"
17 #include "hexdecoct.h"
20 #include "memory-util.h"
21 #include "parse-util.h"
22 #include "pkcs11-util.h"
23 #include "random-util.h"
24 #include "stat-util.h"
27 int decrypt_pkcs11_key(
28 const char *volume_name
,
29 const char *friendly_name
,
30 const char *pkcs11_uri
,
31 const char *key_file
, /* We either expect key_file and associated parameters to be set (for file keys) … */
33 uint64_t key_file_offset
,
34 const void *key_data
, /* … or key_data and key_data_size (for literal keys) */
38 void **ret_decrypted_key
,
39 size_t *ret_decrypted_key_size
) {
41 _cleanup_(pkcs11_crypt_device_callback_data_release
) pkcs11_crypt_device_callback_data data
= {
42 .friendly_name
= friendly_name
,
48 assert(friendly_name
);
50 assert(key_file
|| key_data
);
51 assert(ret_decrypted_key
);
52 assert(ret_decrypted_key_size
);
54 /* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
57 data
.encrypted_key
= (void*) key_data
;
58 data
.encrypted_key_size
= key_data_size
;
60 data
.free_encrypted_key
= false;
62 _cleanup_free_
char *bindname
= NULL
;
64 /* If we read the key via AF_UNIX, make this client recognizable */
65 if (asprintf(&bindname
, "@%" PRIx64
"/cryptsetup-pkcs11/%s", random_u64(), volume_name
) < 0)
68 r
= read_full_file_full(
70 key_file_offset
== 0 ? UINT64_MAX
: key_file_offset
,
71 key_file_size
== 0 ? SIZE_MAX
: key_file_size
,
72 READ_FULL_FILE_CONNECT_SOCKET
,
74 (char**) &data
.encrypted_key
, &data
.encrypted_key_size
);
78 data
.free_encrypted_key
= true;
81 r
= pkcs11_find_token(pkcs11_uri
, pkcs11_crypt_device_callback
, &data
);
85 *ret_decrypted_key
= TAKE_PTR(data
.decrypted_key
);
86 *ret_decrypted_key_size
= data
.decrypted_key_size
;
91 int find_pkcs11_auto_data(
92 struct crypt_device
*cd
,
94 void **ret_encrypted_key
,
95 size_t *ret_encrypted_key_size
,
98 _cleanup_free_
char *uri
= NULL
;
99 _cleanup_free_
void *key
= NULL
;
105 assert(ret_encrypted_key
);
106 assert(ret_encrypted_key_size
);
109 /* Loads PKCS#11 metadata from LUKS2 JSON token headers. */
111 for (int token
= 0; token
< sym_crypt_token_max(CRYPT_LUKS2
); token
++) {
112 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
116 r
= cryptsetup_get_token_as_json(cd
, token
, "systemd-pkcs11", &v
);
117 if (IN_SET(r
, -ENOENT
, -EINVAL
, -EMEDIUMTYPE
))
120 return log_error_errno(r
, "Failed to read JSON token data off disk: %m");
122 ks
= cryptsetup_get_keyslot_from_token(v
);
124 /* Handle parsing errors of the keyslots field gracefully, since it's not 'owned' by
125 * us, but by the LUKS2 spec */
126 log_warning_errno(ks
, "Failed to extract keyslot index from PKCS#11 JSON data token %i, skipping: %m", token
);
131 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
132 "Multiple PKCS#11 tokens enrolled, cannot automatically determine token.");
137 w
= json_variant_by_key(v
, "pkcs11-uri");
138 if (!w
|| !json_variant_is_string(w
))
139 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
140 "PKCS#11 token data lacks 'pkcs11-uri' field.");
142 uri
= strdup(json_variant_string(w
));
146 if (!pkcs11_uri_valid(uri
))
147 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
148 "PKCS#11 token data contains invalid PKCS#11 URI.");
150 w
= json_variant_by_key(v
, "pkcs11-key");
151 if (!w
|| !json_variant_is_string(w
))
152 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
153 "PKCS#11 token data lacks 'pkcs11-key' field.");
156 assert(key_size
== 0);
157 r
= unbase64mem(json_variant_string(w
), &key
, &key_size
);
159 return log_error_errno(r
, "Failed to decode base64 encoded key.");
163 return log_error_errno(SYNTHETIC_ERRNO(ENXIO
),
164 "No valid PKCS#11 token data found.");
166 log_info("Automatically discovered security PKCS#11 token '%s' unlocks volume.", uri
);
168 *ret_uri
= TAKE_PTR(uri
);
169 *ret_encrypted_key
= TAKE_PTR(key
);
170 *ret_encrypted_key_size
= key_size
;
171 *ret_keyslot
= keyslot
;