]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/cryptsetup/cryptsetup-pkcs11.c
hexdecoct: make unbase64mem and unhexmem always use SIZE_MAX
[thirdparty/systemd.git] / src / cryptsetup / cryptsetup-pkcs11.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
08669709
LP
2
3#include <fcntl.h>
4#include <unistd.h>
5#include <sys/stat.h>
6
7#include <p11-kit/p11-kit.h>
8#include <p11-kit/uri.h>
9
10#include "alloc-util.h"
11#include "ask-password-api.h"
12#include "cryptsetup-pkcs11.h"
13#include "escape.h"
14#include "fd-util.h"
4d1bb8f3 15#include "fileio.h"
12f69587 16#include "format-util.h"
b997d111
LP
17#include "hexdecoct.h"
18#include "json.h"
08669709
LP
19#include "macro.h"
20#include "memory-util.h"
b997d111 21#include "parse-util.h"
08669709 22#include "pkcs11-util.h"
4d1bb8f3 23#include "random-util.h"
08669709
LP
24#include "stat-util.h"
25#include "strv.h"
26
08669709 27int decrypt_pkcs11_key(
4d1bb8f3 28 const char *volume_name,
08669709
LP
29 const char *friendly_name,
30 const char *pkcs11_uri,
7407f689 31 const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */
08669709
LP
32 size_t key_file_size,
33 uint64_t key_file_offset,
7407f689
LP
34 const void *key_data, /* … or key_data and key_data_size (for literal keys) */
35 size_t key_data_size,
08669709 36 usec_t until,
cd5f57bd 37 bool headless,
08669709
LP
38 void **ret_decrypted_key,
39 size_t *ret_decrypted_key_size) {
40
ed3d3af1 41 _cleanup_(pkcs11_crypt_device_callback_data_release) pkcs11_crypt_device_callback_data data = {
08669709
LP
42 .friendly_name = friendly_name,
43 .until = until,
cd5f57bd 44 .headless = headless,
08669709
LP
45 };
46 int r;
47
48 assert(friendly_name);
49 assert(pkcs11_uri);
7407f689 50 assert(key_file || key_data);
08669709
LP
51 assert(ret_decrypted_key);
52 assert(ret_decrypted_key_size);
53
54 /* The functions called here log about all errors, except for EAGAIN which means "token not found right now" */
55
7407f689
LP
56 if (key_data) {
57 data.encrypted_key = (void*) key_data;
58 data.encrypted_key_size = key_data_size;
59
60 data.free_encrypted_key = false;
61 } else {
4d1bb8f3
LP
62 _cleanup_free_ char *bindname = NULL;
63
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)
66 return log_oom();
67
68 r = read_full_file_full(
69 AT_FDCWD, key_file,
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,
73 bindname,
74 (char**) &data.encrypted_key, &data.encrypted_key_size);
7407f689
LP
75 if (r < 0)
76 return r;
77
78 data.free_encrypted_key = true;
79 }
08669709 80
ed3d3af1 81 r = pkcs11_find_token(pkcs11_uri, pkcs11_crypt_device_callback, &data);
08669709
LP
82 if (r < 0)
83 return r;
84
85 *ret_decrypted_key = TAKE_PTR(data.decrypted_key);
86 *ret_decrypted_key_size = data.decrypted_key_size;
87
88 return 0;
89}
b997d111
LP
90
91int find_pkcs11_auto_data(
92 struct crypt_device *cd,
93 char **ret_uri,
94 void **ret_encrypted_key,
95 size_t *ret_encrypted_key_size,
96 int *ret_keyslot) {
97
98 _cleanup_free_ char *uri = NULL;
99 _cleanup_free_ void *key = NULL;
100 int r, keyslot = -1;
101 size_t key_size = 0;
102
103 assert(cd);
104 assert(ret_uri);
105 assert(ret_encrypted_key);
106 assert(ret_encrypted_key_size);
107 assert(ret_keyslot);
108
109 /* Loads PKCS#11 metadata from LUKS2 JSON token headers. */
110
3c2c8e62 111 for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) {
b997d111
LP
112 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
113 JsonVariant *w;
1641c2b1 114 int ks;
b997d111
LP
115
116 r = cryptsetup_get_token_as_json(cd, token, "systemd-pkcs11", &v);
117 if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE))
118 continue;
119 if (r < 0)
120 return log_error_errno(r, "Failed to read JSON token data off disk: %m");
121
1641c2b1
LP
122 ks = cryptsetup_get_keyslot_from_token(v);
123 if (ks < 0) {
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);
127 continue;
128 }
129
b997d111
LP
130 if (uri)
131 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
132 "Multiple PKCS#11 tokens enrolled, cannot automatically determine token.");
133
1641c2b1
LP
134 assert(keyslot < 0);
135 keyslot = ks;
136
b997d111
LP
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.");
141
142 uri = strdup(json_variant_string(w));
143 if (!uri)
144 return log_oom();
145
146 if (!pkcs11_uri_valid(uri))
147 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
148 "PKCS#11 token data contains invalid PKCS#11 URI.");
149
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.");
154
155 assert(!key);
156 assert(key_size == 0);
bdd2036e 157 r = unbase64mem(json_variant_string(w), &key, &key_size);
b997d111
LP
158 if (r < 0)
159 return log_error_errno(r, "Failed to decode base64 encoded key.");
b997d111
LP
160 }
161
162 if (!uri)
163 return log_error_errno(SYNTHETIC_ERRNO(ENXIO),
164 "No valid PKCS#11 token data found.");
165
166 log_info("Automatically discovered security PKCS#11 token '%s' unlocks volume.", uri);
167
168 *ret_uri = TAKE_PTR(uri);
169 *ret_encrypted_key = TAKE_PTR(key);
170 *ret_encrypted_key_size = key_size;
171 *ret_keyslot = keyslot;
172 return 0;
173}