/src/cryptsetup/lib/volumekey.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | /* |
3 | | * cryptsetup volume key implementation |
4 | | * |
5 | | * Copyright (C) 2004-2006 Clemens Fruhwirth <clemens@endorphin.org> |
6 | | * Copyright (C) 2010-2025 Red Hat, Inc. All rights reserved. |
7 | | */ |
8 | | |
9 | | #include <string.h> |
10 | | #include <stdint.h> |
11 | | #include <stdlib.h> |
12 | | #include <errno.h> |
13 | | |
14 | | #include "internal.h" |
15 | | |
16 | | struct volume_key { |
17 | | int id; |
18 | | size_t keylength; /* length in bytes */ |
19 | | const char *key_description; /* keyring key name/description */ |
20 | | key_type_t keyring_key_type; /* kernel keyring key type */ |
21 | | key_serial_t key_id; /* kernel key id of volume key representation linked in thread keyring */ |
22 | | struct volume_key *next; |
23 | | char *key; |
24 | | }; |
25 | | |
26 | | struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key) |
27 | 1.74k | { |
28 | 1.74k | struct volume_key *vk; |
29 | | |
30 | 1.74k | if (keylength > (SIZE_MAX - sizeof(*vk))) |
31 | 0 | return NULL; |
32 | | |
33 | 1.74k | vk = crypt_zalloc(sizeof(*vk)); |
34 | 1.74k | if (!vk) |
35 | 0 | return NULL; |
36 | | |
37 | 1.74k | vk->keyring_key_type = INVALID_KEY; |
38 | 1.74k | vk->key_id = -1; |
39 | 1.74k | vk->keylength = keylength; |
40 | 1.74k | vk->id = KEY_NOT_VERIFIED; |
41 | | |
42 | | /* keylength 0 is valid => no key */ |
43 | 1.74k | if (vk->keylength && key) { |
44 | 741 | vk->key = crypt_safe_alloc(keylength); |
45 | 741 | if (!vk->key) { |
46 | 0 | free(vk); |
47 | 0 | return NULL; |
48 | 0 | } |
49 | 741 | crypt_safe_memcpy(vk->key, key, keylength); |
50 | 741 | } |
51 | | |
52 | 1.74k | return vk; |
53 | 1.74k | } |
54 | | |
55 | | struct volume_key *crypt_alloc_volume_key_by_safe_alloc(void **safe_alloc) |
56 | 151 | { |
57 | 151 | size_t keylength; |
58 | 151 | struct volume_key *vk; |
59 | | |
60 | 151 | if (!safe_alloc) |
61 | 0 | return NULL; |
62 | | |
63 | 151 | keylength = crypt_safe_alloc_size(*safe_alloc); |
64 | 151 | if (!keylength) |
65 | 0 | return NULL; |
66 | | |
67 | 151 | vk = crypt_alloc_volume_key(keylength, NULL); |
68 | 151 | if (!vk) |
69 | 0 | return NULL; |
70 | | |
71 | 151 | vk->key = *safe_alloc; |
72 | 151 | *safe_alloc = NULL; |
73 | | |
74 | 151 | return vk; |
75 | 151 | } |
76 | | |
77 | | void crypt_volume_key_pass_safe_alloc(struct volume_key *vk, void **safe_alloc) |
78 | 0 | { |
79 | 0 | assert(vk); |
80 | 0 | assert(vk->keylength); |
81 | 0 | assert(safe_alloc); |
82 | 0 | assert(crypt_safe_alloc_size(*safe_alloc) == vk->keylength); |
83 | | |
84 | 0 | crypt_safe_free(vk->key); |
85 | 0 | vk->key = *safe_alloc; |
86 | 0 | *safe_alloc = NULL; |
87 | 0 | } |
88 | | |
89 | | const char *crypt_volume_key_get_key(const struct volume_key *vk) |
90 | 29 | { |
91 | 29 | assert(vk && vk->key); |
92 | | |
93 | 29 | return vk->key; |
94 | 29 | } |
95 | | |
96 | | size_t crypt_volume_key_length(const struct volume_key *vk) |
97 | 0 | { |
98 | 0 | assert(vk); |
99 | | |
100 | 0 | return vk->keylength; |
101 | 0 | } |
102 | | |
103 | | int crypt_volume_key_set_description(struct volume_key *vk, |
104 | | const char *key_description, key_type_t keyring_key_type) |
105 | 0 | { |
106 | 0 | if (!vk) |
107 | 0 | return -EINVAL; |
108 | | |
109 | 0 | free(CONST_CAST(void*)vk->key_description); |
110 | 0 | vk->key_description = NULL; |
111 | 0 | vk->keyring_key_type = keyring_key_type; |
112 | 0 | if (key_description && !(vk->key_description = strdup(key_description))) |
113 | 0 | return -ENOMEM; |
114 | | |
115 | 0 | return 0; |
116 | 0 | } |
117 | | |
118 | | int crypt_volume_key_set_description_by_name(struct volume_key *vk, const char *key_name) |
119 | 0 | { |
120 | 0 | const char *key_description = NULL; |
121 | 0 | key_type_t keyring_key_type = keyring_type_and_name(key_name, &key_description); |
122 | |
|
123 | 0 | if (keyring_key_type == INVALID_KEY) |
124 | 0 | return -EINVAL; |
125 | | |
126 | 0 | return crypt_volume_key_set_description(vk, key_description, keyring_key_type); |
127 | 0 | } |
128 | | |
129 | | const char *crypt_volume_key_description(const struct volume_key *vk) |
130 | 0 | { |
131 | 0 | assert(vk); |
132 | | |
133 | 0 | return vk->key_description; |
134 | 0 | } |
135 | | |
136 | | |
137 | | key_type_t crypt_volume_key_kernel_key_type(const struct volume_key *vk) |
138 | 0 | { |
139 | 0 | assert(vk); |
140 | | |
141 | 0 | return vk->keyring_key_type; |
142 | 0 | } |
143 | | |
144 | | void crypt_volume_key_set_id(struct volume_key *vk, int id) |
145 | 0 | { |
146 | 0 | if (vk && id >= 0) |
147 | 0 | vk->id = id; |
148 | 0 | } |
149 | | |
150 | | int crypt_volume_key_get_id(const struct volume_key *vk) |
151 | 0 | { |
152 | 0 | return vk ? vk->id : -1; |
153 | 0 | } |
154 | | |
155 | | struct volume_key *crypt_volume_key_by_id(struct volume_key *vks, int id) |
156 | 0 | { |
157 | 0 | struct volume_key *vk = vks; |
158 | |
|
159 | 0 | if (id < 0) |
160 | 0 | return NULL; |
161 | | |
162 | 0 | while (vk && vk->id != id) |
163 | 0 | vk = vk->next; |
164 | |
|
165 | 0 | return vk; |
166 | 0 | } |
167 | | |
168 | | void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk) |
169 | 1.53k | { |
170 | 1.53k | struct volume_key *tmp; |
171 | | |
172 | 1.53k | if (!vks) |
173 | 0 | return; |
174 | | |
175 | 1.53k | if (!*vks) { |
176 | 471 | *vks = vk; |
177 | 471 | return; |
178 | 471 | } |
179 | | |
180 | 1.06k | tmp = *vks; |
181 | | |
182 | 52.4k | while (tmp->next) |
183 | 51.3k | tmp = tmp->next; |
184 | | |
185 | 1.06k | tmp->next = vk; |
186 | 1.06k | } |
187 | | |
188 | | struct volume_key *crypt_volume_key_next(struct volume_key *vk) |
189 | 0 | { |
190 | 0 | return vk ? vk->next : NULL; |
191 | 0 | } |
192 | | |
193 | | void crypt_free_volume_key(struct volume_key *vk) |
194 | 8.36k | { |
195 | 8.36k | struct volume_key *vk_next; |
196 | | |
197 | 10.1k | while (vk) { |
198 | 1.74k | free(CONST_CAST(void*)vk->key_description); |
199 | 1.74k | crypt_safe_free(vk->key); |
200 | 1.74k | vk_next = vk->next; |
201 | 1.74k | free(vk); |
202 | 1.74k | vk = vk_next; |
203 | 1.74k | } |
204 | 8.36k | } |
205 | | |
206 | | struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength, |
207 | | key_quality_info quality) |
208 | 0 | { |
209 | 0 | int r; |
210 | 0 | void *key; |
211 | 0 | struct volume_key *vk = NULL; |
212 | |
|
213 | 0 | key = crypt_safe_alloc(keylength); |
214 | 0 | if (!key) |
215 | 0 | return NULL; |
216 | | |
217 | 0 | switch (quality) { |
218 | 0 | case KEY_QUALITY_KEY: |
219 | 0 | r = crypt_random_get(cd, key, keylength, CRYPT_RND_KEY); |
220 | 0 | break; |
221 | 0 | case KEY_QUALITY_NORMAL: |
222 | 0 | r = crypt_random_get(cd, key, keylength, CRYPT_RND_NORMAL); |
223 | 0 | break; |
224 | 0 | case KEY_QUALITY_EMPTY: |
225 | 0 | r = 0; |
226 | 0 | break; |
227 | 0 | default: |
228 | 0 | abort(); |
229 | 0 | } |
230 | | |
231 | 0 | if (!r) |
232 | 0 | vk = crypt_alloc_volume_key(keylength, NULL); |
233 | 0 | if (vk) |
234 | 0 | vk->key = key; |
235 | 0 | else |
236 | 0 | crypt_safe_free(key); |
237 | |
|
238 | 0 | return vk; |
239 | 0 | } |
240 | | |
241 | | bool crypt_volume_key_is_set(const struct volume_key *vk) |
242 | 0 | { |
243 | 0 | return vk && vk->key; |
244 | 0 | } |
245 | | |
246 | | bool crypt_volume_key_upload_kernel_key(struct volume_key *vk) |
247 | 0 | { |
248 | 0 | key_serial_t kid; |
249 | |
|
250 | 0 | assert(vk && vk->key && vk->key_description && vk->keyring_key_type != INVALID_KEY); |
251 | | |
252 | 0 | kid = keyring_add_key_in_thread_keyring(vk->keyring_key_type, vk->key_description, |
253 | 0 | vk->key, vk->keylength); |
254 | 0 | if (kid >= 0) { |
255 | 0 | vk->key_id = kid; |
256 | 0 | return true; |
257 | 0 | } |
258 | | |
259 | 0 | return false; |
260 | 0 | } |
261 | | |
262 | | void crypt_volume_key_drop_kernel_key(struct crypt_device *cd, struct volume_key *vk) |
263 | 0 | { |
264 | 0 | assert(vk); |
265 | 0 | assert(vk->key_description || vk->keyring_key_type == INVALID_KEY); |
266 | 0 | assert(!vk->key_description || vk->keyring_key_type != INVALID_KEY); |
267 | | |
268 | 0 | crypt_unlink_key_by_description_from_thread_keyring(cd, |
269 | 0 | vk->key_description, |
270 | 0 | vk->keyring_key_type); |
271 | 0 | } |
272 | | |
273 | | void crypt_volume_key_drop_uploaded_kernel_key(struct crypt_device *cd, struct volume_key *vk) |
274 | 0 | { |
275 | 0 | assert(vk); |
276 | | |
277 | 0 | if (vk->key_id < 0) |
278 | 0 | return; |
279 | | |
280 | 0 | crypt_unlink_key_from_thread_keyring(cd, vk->key_id); |
281 | 0 | vk->key_id = -1; |
282 | 0 | } |