]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/openssl-util.c
Two follow-ups for recent PRs (#38062)
[thirdparty/systemd.git] / src / shared / openssl-util.c
CommitLineData
30e31503
ZJS
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
f2d5df8a 3#include "alloc-util.h"
eac5336c 4#include "ask-password-api.h"
a65a25be 5#include "fd-util.h"
eac5336c 6#include "fileio.h"
7e8facb3 7#include "hexdecoct.h"
93a1f792 8#include "log.h"
85686b37 9#include "memory-util.h"
6a2097dd 10#include "memstream-util.h"
a65a25be 11#include "openssl-util.h"
876206f2 12#include "random-util.h"
a65a25be 13#include "string-util.h"
eac5336c 14#include "strv.h"
f2d5df8a
LP
15
16#if HAVE_OPENSSL
81d61d6a 17# include <openssl/ec.h>
1cf40697 18# include <openssl/rsa.h>
81d61d6a
NL
19
20# if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
21# include <openssl/engine.h>
22DISABLE_WARNING_DEPRECATED_DECLARATIONS;
23DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ENGINE*, ENGINE_free, NULL);
24REENABLE_WARNING;
25# endif
26
d1d16c62 27#ifndef OPENSSL_NO_UI_CONSOLE
0bf70b19 28DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(UI_METHOD*, UI_destroy_method, NULL);
d1d16c62 29#endif
0bf70b19 30
3d05c058
VS
31/* For each error in the OpenSSL thread error queue, log the provided message and the OpenSSL error
32 * string. If there are no errors in the OpenSSL thread queue, this logs the message with "No OpenSSL
60696b22
DS
33 * errors." This logs at level debug. Returns -EIO (or -ENOMEM). */
34#define log_openssl_errors(fmt, ...) _log_openssl_errors(UNIQ, fmt, ##__VA_ARGS__)
35#define _log_openssl_errors(u, fmt, ...) \
36 ({ \
37 size_t UNIQ_T(MAX, u) = 512 /* arbitrary, but openssl doc states it must be >= 256 */; \
38 _cleanup_free_ char *UNIQ_T(BUF, u) = malloc(UNIQ_T(MAX, u)); \
39 !UNIQ_T(BUF, u) \
40 ? log_oom_debug() \
41 : __log_openssl_errors(u, UNIQ_T(BUF, u), UNIQ_T(MAX, u), fmt, ##__VA_ARGS__) \
968d232d 42 ?: log_debug_errno(SYNTHETIC_ERRNO(EIO), fmt ": No OpenSSL errors.", ##__VA_ARGS__); \
60696b22
DS
43 })
44#define __log_openssl_errors(u, buf, max, fmt, ...) \
45 ({ \
46 int UNIQ_T(R, u) = 0; \
47 for (;;) { \
48 unsigned long UNIQ_T(E, u) = ERR_get_error(); \
49 if (UNIQ_T(E, u) == 0) \
50 break; \
51 ERR_error_string_n(UNIQ_T(E, u), buf, max); \
52 UNIQ_T(R, u) = log_debug_errno(SYNTHETIC_ERRNO(EIO), fmt ": %s", ##__VA_ARGS__, buf); \
53 } \
54 UNIQ_T(R, u); \
55 })
56
6a2097dd 57int openssl_pubkey_from_pem(const void *pem, size_t pem_size, EVP_PKEY **ret) {
4af788c7
DS
58 assert(pem);
59 assert(ret);
60
6a2097dd
LP
61 if (pem_size == SIZE_MAX)
62 pem_size = strlen(pem);
63
4af788c7
DS
64 _cleanup_fclose_ FILE *f = NULL;
65 f = fmemopen((void*) pem, pem_size, "r");
66 if (!f)
67 return log_oom_debug();
68
6a2097dd 69 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = PEM_read_PUBKEY(f, /* x= */ NULL, /* pam_password_cb= */ NULL, /* userdata= */ NULL);
4af788c7 70 if (!pkey)
60696b22 71 return log_openssl_errors("Failed to parse PEM");
4af788c7
DS
72
73 *ret = TAKE_PTR(pkey);
4af788c7
DS
74 return 0;
75}
76
6a2097dd
LP
77int openssl_pubkey_to_pem(EVP_PKEY *pkey, char **ret) {
78 assert(pkey);
79 assert(ret);
80
81 _cleanup_(memstream_done) MemStream m = {};
82 FILE *f = memstream_init(&m);
83 if (!f)
84 return -ENOMEM;
85
86 if (PEM_write_PUBKEY(f, pkey) <= 0)
87 return -EIO;
88
89 return memstream_finalize(&m, ret, /* ret_size= */ NULL);
90}
91
c52a003d
DS
92/* Returns the number of bytes generated by the specified digest algorithm. This can be used only for
93 * fixed-size algorithms, e.g. md5, sha1, sha256, etc. Do not use this for variable-sized digest algorithms,
94 * e.g. shake128. Returns 0 on success, -EOPNOTSUPP if the algorithm is not supported, or < 0 for any other
95 * error. */
96int openssl_digest_size(const char *digest_alg, size_t *ret_digest_size) {
97 assert(digest_alg);
98 assert(ret_digest_size);
99
100#if OPENSSL_VERSION_MAJOR >= 3
101 _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
102#else
103 const EVP_MD *md = EVP_get_digestbyname(digest_alg);
104#endif
105 if (!md)
106 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
107 "Digest algorithm '%s' not supported.", digest_alg);
108
109 size_t digest_size;
110#if OPENSSL_VERSION_MAJOR >= 3
111 digest_size = EVP_MD_get_size(md);
112#else
113 digest_size = EVP_MD_size(md);
114#endif
115 if (digest_size == 0)
116 return log_openssl_errors("Failed to get Digest size");
117
118 *ret_digest_size = digest_size;
119
120 return 0;
121}
122
bed4831c
DS
123/* Calculate the digest hash value for the provided data, using the specified digest algorithm. Returns 0 on
124 * success, -EOPNOTSUPP if the digest algorithm is not supported, or < 0 for any other error. */
125int openssl_digest_many(
126 const char *digest_alg,
127 const struct iovec data[],
128 size_t n_data,
129 void **ret_digest,
130 size_t *ret_digest_size) {
131
132 int r;
133
134 assert(digest_alg);
135 assert(data || n_data == 0);
136 assert(ret_digest);
137 /* ret_digest_size is optional, as caller may already know the digest size */
138
139#if OPENSSL_VERSION_MAJOR >= 3
140 _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
141#else
142 const EVP_MD *md = EVP_get_digestbyname(digest_alg);
143#endif
144 if (!md)
145 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
146 "Digest algorithm '%s' not supported.", digest_alg);
147
148 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = EVP_MD_CTX_new();
149 if (!ctx)
150 return log_openssl_errors("Failed to create new EVP_MD_CTX");
151
152 if (!EVP_DigestInit_ex(ctx, md, NULL))
fcdd21ec 153 return log_openssl_errors("Failed to initialize EVP_MD_CTX");
bed4831c
DS
154
155 for (size_t i = 0; i < n_data; i++)
156 if (!EVP_DigestUpdate(ctx, data[i].iov_base, data[i].iov_len))
157 return log_openssl_errors("Failed to update Digest");
158
159 size_t digest_size;
160 r = openssl_digest_size(digest_alg, &digest_size);
161 if (r < 0)
162 return r;
163
164 _cleanup_free_ void *buf = malloc(digest_size);
165 if (!buf)
166 return log_oom_debug();
167
9ec7d7ae 168 unsigned size;
bed4831c
DS
169 if (!EVP_DigestFinal_ex(ctx, buf, &size))
170 return log_openssl_errors("Failed to finalize Digest");
171
172 assert(size == digest_size);
173
174 *ret_digest = TAKE_PTR(buf);
175 if (ret_digest_size)
176 *ret_digest_size = size;
177
178 return 0;
179}
180
a95e8fa2
DS
181/* Calculate the HMAC digest hash value for the provided data, using the provided key and specified digest
182 * algorithm. Returns 0 on success, -EOPNOTSUPP if the digest algorithm is not supported, or < 0 for any
183 * other error. */
184int openssl_hmac_many(
185 const char *digest_alg,
186 const void *key,
187 size_t key_size,
188 const struct iovec data[],
189 size_t n_data,
190 void **ret_digest,
191 size_t *ret_digest_size) {
192
193 assert(digest_alg);
194 assert(key);
195 assert(data || n_data == 0);
196 assert(ret_digest);
197 /* ret_digest_size is optional, as caller may already know the digest size */
198
199#if OPENSSL_VERSION_MAJOR >= 3
200 _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
201#else
202 const EVP_MD *md = EVP_get_digestbyname(digest_alg);
203#endif
204 if (!md)
205 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
206 "Digest algorithm '%s' not supported.", digest_alg);
207
208#if OPENSSL_VERSION_MAJOR >= 3
209 _cleanup_(EVP_MAC_freep) EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
210 if (!mac)
211 return log_openssl_errors("Failed to create new EVP_MAC");
212
213 _cleanup_(EVP_MAC_CTX_freep) EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac);
214 if (!ctx)
215 return log_openssl_errors("Failed to create new EVP_MAC_CTX");
216
217 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
218 if (!bld)
219 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
220
221 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_MAC_PARAM_DIGEST, (char*) digest_alg, 0))
222 return log_openssl_errors("Failed to set HMAC OSSL_MAC_PARAM_DIGEST");
223
224 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
225 if (!params)
226 return log_openssl_errors("Failed to build HMAC OSSL_PARAM");
227
228 if (!EVP_MAC_init(ctx, key, key_size, params))
fcdd21ec 229 return log_openssl_errors("Failed to initialize EVP_MAC_CTX");
a95e8fa2
DS
230#else
231 _cleanup_(HMAC_CTX_freep) HMAC_CTX *ctx = HMAC_CTX_new();
232 if (!ctx)
233 return log_openssl_errors("Failed to create new HMAC_CTX");
234
235 if (!HMAC_Init_ex(ctx, key, key_size, md, NULL))
236 return log_openssl_errors("Failed to initialize HMAC_CTX");
237#endif
238
239 for (size_t i = 0; i < n_data; i++)
240#if OPENSSL_VERSION_MAJOR >= 3
241 if (!EVP_MAC_update(ctx, data[i].iov_base, data[i].iov_len))
242#else
243 if (!HMAC_Update(ctx, data[i].iov_base, data[i].iov_len))
244#endif
245 return log_openssl_errors("Failed to update HMAC");
246
247 size_t digest_size;
248#if OPENSSL_VERSION_MAJOR >= 3
249 digest_size = EVP_MAC_CTX_get_mac_size(ctx);
250#else
251 digest_size = HMAC_size(ctx);
252#endif
253 if (digest_size == 0)
254 return log_openssl_errors("Failed to get HMAC digest size");
255
256 _cleanup_free_ void *buf = malloc(digest_size);
257 if (!buf)
258 return log_oom_debug();
259
260#if OPENSSL_VERSION_MAJOR >= 3
261 size_t size;
262 if (!EVP_MAC_final(ctx, buf, &size, digest_size))
263#else
9ec7d7ae 264 unsigned size;
a95e8fa2
DS
265 if (!HMAC_Final(ctx, buf, &size))
266#endif
267 return log_openssl_errors("Failed to finalize HMAC");
268
269 assert(size == digest_size);
270
271 *ret_digest = TAKE_PTR(buf);
272 if (ret_digest_size)
273 *ret_digest_size = size;
274
275 return 0;
276}
277
58f215a0
DS
278/* Symmetric Cipher encryption using the alg-bits-mode cipher, e.g. AES-128-CFB. The key is required and must
279 * be at least the minimum required key length for the cipher. The IV is optional but, if provided, it must
280 * be at least the minimum iv length for the cipher. If no IV is provided and the cipher requires one, a
281 * buffer of zeroes is used. Returns 0 on success, -EOPNOTSUPP if the cipher algorithm is not supported, or <
282 * 0 on any other error. */
283int openssl_cipher_many(
284 const char *alg,
285 size_t bits,
286 const char *mode,
287 const void *key,
288 size_t key_size,
289 const void *iv,
290 size_t iv_size,
291 const struct iovec data[],
292 size_t n_data,
293 void **ret,
294 size_t *ret_size) {
295
296 assert(alg);
297 assert(bits > 0);
298 assert(mode);
299 assert(key);
300 assert(iv || iv_size == 0);
301 assert(data || n_data == 0);
302 assert(ret);
303 assert(ret_size);
304
305 _cleanup_free_ char *cipher_alg = NULL;
306 if (asprintf(&cipher_alg, "%s-%zu-%s", alg, bits, mode) < 0)
307 return log_oom_debug();
308
309#if OPENSSL_VERSION_MAJOR >= 3
310 _cleanup_(EVP_CIPHER_freep) EVP_CIPHER *cipher = EVP_CIPHER_fetch(NULL, cipher_alg, NULL);
311#else
312 const EVP_CIPHER *cipher = EVP_get_cipherbyname(cipher_alg);
313#endif
314 if (!cipher)
315 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
316 "Cipher algorithm '%s' not supported.", cipher_alg);
317
318 _cleanup_(EVP_CIPHER_CTX_freep) EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
319 if (!ctx)
320 return log_openssl_errors("Failed to create new EVP_CIPHER_CTX");
321
322 /* Verify enough key data was provided. */
323 int cipher_key_length = EVP_CIPHER_key_length(cipher);
324 assert(cipher_key_length >= 0);
325 if ((size_t) cipher_key_length > key_size)
326 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
327 "Not enough key bytes provided, require %d", cipher_key_length);
328
329 /* Verify enough IV data was provided or, if no IV was provided, use a zeroed buffer for IV data. */
330 int cipher_iv_length = EVP_CIPHER_iv_length(cipher);
331 assert(cipher_iv_length >= 0);
332 _cleanup_free_ void *zero_iv = NULL;
333 if (iv_size == 0) {
334 zero_iv = malloc0(cipher_iv_length);
335 if (!zero_iv)
336 return log_oom_debug();
337
338 iv = zero_iv;
339 iv_size = (size_t) cipher_iv_length;
340 }
341 if ((size_t) cipher_iv_length > iv_size)
342 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
343 "Not enough IV bytes provided, require %d", cipher_iv_length);
344
345 if (!EVP_EncryptInit(ctx, cipher, key, iv))
346 return log_openssl_errors("Failed to initialize EVP_CIPHER_CTX.");
347
348 int cipher_block_size = EVP_CIPHER_CTX_block_size(ctx);
349 assert(cipher_block_size > 0);
350
351 _cleanup_free_ uint8_t *buf = NULL;
352 size_t size = 0;
353
354 for (size_t i = 0; i < n_data; i++) {
355 /* Cipher may produce (up to) input length + cipher block size of output. */
356 if (!GREEDY_REALLOC(buf, size + data[i].iov_len + cipher_block_size))
357 return log_oom_debug();
358
359 int update_size;
360 if (!EVP_EncryptUpdate(ctx, &buf[size], &update_size, data[i].iov_base, data[i].iov_len))
361 return log_openssl_errors("Failed to update Cipher.");
362
363 size += update_size;
364 }
365
366 if (!GREEDY_REALLOC(buf, size + cipher_block_size))
367 return log_oom_debug();
368
369 int final_size;
370 if (!EVP_EncryptFinal_ex(ctx, &buf[size], &final_size))
371 return log_openssl_errors("Failed to finalize Cipher.");
372
373 *ret = TAKE_PTR(buf);
374 *ret_size = size + final_size;
375
376 return 0;
377}
378
8c2205bb
DS
379/* Perform Single-Step (aka "Concat") KDF. Currently, this only supports using the digest for the auxiliary
380 * function. The derive_size parameter specifies how many bytes are derived.
381 *
382 * For more details see: https://www.openssl.org/docs/manmaster/man7/EVP_KDF-SS.html */
383int kdf_ss_derive(
384 const char *digest,
385 const void *key,
386 size_t key_size,
387 const void *salt,
388 size_t salt_size,
389 const void *info,
390 size_t info_size,
391 size_t derive_size,
392 void **ret) {
393
394#if OPENSSL_VERSION_MAJOR >= 3
395 assert(digest);
396 assert(key);
397 assert(derive_size > 0);
398 assert(ret);
399
400 _cleanup_(EVP_KDF_freep) EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
401 if (!kdf)
402 return log_openssl_errors("Failed to create new EVP_KDF");
403
404 _cleanup_(EVP_KDF_CTX_freep) EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
405 if (!ctx)
406 return log_openssl_errors("Failed to create new EVP_KDF_CTX");
407
408 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
409 if (!bld)
410 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
411
412 _cleanup_free_ void *buf = malloc(derive_size);
413 if (!buf)
414 return log_oom_debug();
415
416 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_DIGEST, (char*) digest, 0))
417 return log_openssl_errors("Failed to add KDF-SS OSSL_KDF_PARAM_DIGEST");
418
419 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_KEY, (char*) key, key_size))
420 return log_openssl_errors("Failed to add KDF-SS OSSL_KDF_PARAM_KEY");
421
422 if (salt)
423 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_SALT, (char*) salt, salt_size))
424 return log_openssl_errors("Failed to add KDF-SS OSSL_KDF_PARAM_SALT");
425
426 if (info)
427 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_INFO, (char*) info, info_size))
428 return log_openssl_errors("Failed to add KDF-SS OSSL_KDF_PARAM_INFO");
429
430 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
431 if (!params)
432 return log_openssl_errors("Failed to build KDF-SS OSSL_PARAM");
433
434 if (EVP_KDF_derive(ctx, buf, derive_size, params) <= 0)
968d232d 435 return log_openssl_errors("OpenSSL KDF-SS derive failed");
8c2205bb
DS
436
437 *ret = TAKE_PTR(buf);
438
439 return 0;
440#else
968d232d 441 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "KDF-SS requires OpenSSL >= 3.");
8c2205bb
DS
442#endif
443}
444
a65a25be 445/* Perform Key-Based HMAC KDF. The mode must be "COUNTER" or "FEEDBACK". The parameter naming is from the
968d232d 446 * OpenSSL api, and maps to SP800-108 naming as "...key, salt, info, and seed correspond to KI, Label,
a65a25be
DS
447 * Context, and IV (respectively)...". The derive_size parameter specifies how many bytes are derived.
448 *
449 * For more details see: https://www.openssl.org/docs/manmaster/man7/EVP_KDF-KB.html */
450int kdf_kb_hmac_derive(
451 const char *mode,
452 const char *digest,
453 const void *key,
454 size_t key_size,
455 const void *salt,
456 size_t salt_size,
457 const void *info,
458 size_t info_size,
459 const void *seed,
460 size_t seed_size,
461 size_t derive_size,
462 void **ret) {
463
464#if OPENSSL_VERSION_MAJOR >= 3
465 assert(mode);
466 assert(strcaseeq(mode, "COUNTER") || strcaseeq(mode, "FEEDBACK"));
467 assert(digest);
468 assert(key || key_size == 0);
469 assert(salt || salt_size == 0);
470 assert(info || info_size == 0);
471 assert(seed || seed_size == 0);
472 assert(derive_size > 0);
473 assert(ret);
474
475 _cleanup_(EVP_KDF_freep) EVP_KDF *kdf = EVP_KDF_fetch(NULL, "KBKDF", NULL);
476 if (!kdf)
477 return log_openssl_errors("Failed to create new EVP_KDF");
478
479 _cleanup_(EVP_KDF_CTX_freep) EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
480 if (!ctx)
481 return log_openssl_errors("Failed to create new EVP_KDF_CTX");
482
483 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
484 if (!bld)
485 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
486
487 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_MAC, (char*) "HMAC", 0))
488 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_MAC");
489
490 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_MODE, (char*) mode, 0))
491 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_MODE");
492
493 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_DIGEST, (char*) digest, 0))
494 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_DIGEST");
495
496 if (key)
497 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_KEY, (char*) key, key_size))
498 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_KEY");
499
500 if (salt)
501 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_SALT, (char*) salt, salt_size))
502 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_SALT");
503
504 if (info)
505 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_INFO, (char*) info, info_size))
506 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_INFO");
507
508 if (seed)
509 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_SEED, (char*) seed, seed_size))
510 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_SEED");
511
512 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
513 if (!params)
514 return log_openssl_errors("Failed to build KDF-KB OSSL_PARAM");
515
516 _cleanup_free_ void *buf = malloc(derive_size);
517 if (!buf)
518 return log_oom_debug();
519
520 if (EVP_KDF_derive(ctx, buf, derive_size, params) <= 0)
968d232d 521 return log_openssl_errors("OpenSSL KDF-KB derive failed");
a65a25be
DS
522
523 *ret = TAKE_PTR(buf);
524
525 return 0;
526#else
968d232d 527 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "KDF-KB requires OpenSSL >= 3.");
a65a25be
DS
528#endif
529}
530
f2d5df8a
LP
531int rsa_encrypt_bytes(
532 EVP_PKEY *pkey,
533 const void *decrypted_key,
534 size_t decrypted_key_size,
535 void **ret_encrypt_key,
536 size_t *ret_encrypt_key_size) {
537
538 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL;
539 _cleanup_free_ void *b = NULL;
540 size_t l;
541
542 ctx = EVP_PKEY_CTX_new(pkey, NULL);
543 if (!ctx)
60696b22 544 return log_openssl_errors("Failed to allocate public key context");
f2d5df8a
LP
545
546 if (EVP_PKEY_encrypt_init(ctx) <= 0)
60696b22 547 return log_openssl_errors("Failed to initialize public key context");
f2d5df8a
LP
548
549 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
60696b22 550 return log_openssl_errors("Failed to configure PKCS#1 padding");
f2d5df8a
LP
551
552 if (EVP_PKEY_encrypt(ctx, NULL, &l, decrypted_key, decrypted_key_size) <= 0)
60696b22 553 return log_openssl_errors("Failed to determine encrypted key size");
f2d5df8a
LP
554
555 b = malloc(l);
556 if (!b)
557 return -ENOMEM;
558
559 if (EVP_PKEY_encrypt(ctx, b, &l, decrypted_key, decrypted_key_size) <= 0)
60696b22 560 return log_openssl_errors("Failed to determine encrypted key size");
f2d5df8a
LP
561
562 *ret_encrypt_key = TAKE_PTR(b);
563 *ret_encrypt_key_size = l;
f2d5df8a
LP
564 return 0;
565}
d041e4fc 566
816b1dc4
DS
567/* Encrypt the key data using RSA-OAEP with the provided label and specified digest algorithm. Returns 0 on
568 * success, -EOPNOTSUPP if the digest algorithm is not supported, or < 0 for any other error. */
569int rsa_oaep_encrypt_bytes(
570 const EVP_PKEY *pkey,
571 const char *digest_alg,
572 const char *label,
573 const void *decrypted_key,
574 size_t decrypted_key_size,
575 void **ret_encrypt_key,
576 size_t *ret_encrypt_key_size) {
577
578 assert(pkey);
579 assert(digest_alg);
580 assert(label);
581 assert(decrypted_key);
582 assert(decrypted_key_size > 0);
583 assert(ret_encrypt_key);
584 assert(ret_encrypt_key_size);
585
586#if OPENSSL_VERSION_MAJOR >= 3
587 _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
588#else
589 const EVP_MD *md = EVP_get_digestbyname(digest_alg);
590#endif
591 if (!md)
592 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
593 "Digest algorithm '%s' not supported.", digest_alg);
594
595 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new((EVP_PKEY*) pkey, NULL);
596 if (!ctx)
597 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
598
599 if (EVP_PKEY_encrypt_init(ctx) <= 0)
600 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
601
602 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
603 return log_openssl_errors("Failed to configure RSA-OAEP padding");
604
605 if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0)
606 return log_openssl_errors("Failed to configure RSA-OAEP MD");
607
608 _cleanup_free_ char *duplabel = strdup(label);
609 if (!duplabel)
610 return log_oom_debug();
611
612 if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, duplabel, strlen(duplabel) + 1) <= 0)
613 return log_openssl_errors("Failed to configure RSA-OAEP label");
614 /* ctx owns this now, don't free */
615 TAKE_PTR(duplabel);
616
617 size_t size = 0;
618 if (EVP_PKEY_encrypt(ctx, NULL, &size, decrypted_key, decrypted_key_size) <= 0)
619 return log_openssl_errors("Failed to determine RSA-OAEP encrypted key size");
620
621 _cleanup_free_ void *buf = malloc(size);
622 if (!buf)
623 return log_oom_debug();
624
625 if (EVP_PKEY_encrypt(ctx, buf, &size, decrypted_key, decrypted_key_size) <= 0)
626 return log_openssl_errors("Failed to RSA-OAEP encrypt");
627
628 *ret_encrypt_key = TAKE_PTR(buf);
629 *ret_encrypt_key_size = size;
630
631 return 0;
632}
633
d041e4fc
LP
634int rsa_pkey_to_suitable_key_size(
635 EVP_PKEY *pkey,
636 size_t *ret_suitable_key_size) {
637
638 size_t suitable_key_size;
d041e4fc
LP
639 int bits;
640
2e64df07
YW
641 assert(pkey);
642 assert(ret_suitable_key_size);
d041e4fc
LP
643
644 /* Analyzes the specified public key and that it is RSA. If so, will return a suitable size for a
645 * disk encryption key to encrypt with RSA for use in PKCS#11 security token schemes. */
646
647 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA)
648 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "X.509 certificate does not refer to RSA key.");
649
7f12adc3 650 bits = EVP_PKEY_bits(pkey);
d041e4fc
LP
651 log_debug("Bits in RSA key: %i", bits);
652
653 /* We use PKCS#1 padding for the RSA cleartext, hence let's leave some extra space for it, hence only
654 * generate a random key half the size of the RSA length */
655 suitable_key_size = bits / 8 / 2;
656
657 if (suitable_key_size < 1)
658 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Uh, RSA key size too short?");
659
660 *ret_suitable_key_size = suitable_key_size;
661 return 0;
662}
7e8facb3 663
85686b37
VS
664/* Generate RSA public key from provided "n" and "e" values. Numbers "n" and "e" must be provided here
665 * in big-endian format, e.g. wrap it with htobe32() for uint32_t. */
dcec950c
DS
666int rsa_pkey_from_n_e(const void *n, size_t n_size, const void *e, size_t e_size, EVP_PKEY **ret) {
667 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
668
669 assert(n);
85686b37 670 assert(n_size != 0);
dcec950c 671 assert(e);
85686b37 672 assert(e_size != 0);
dcec950c
DS
673 assert(ret);
674
85686b37
VS
675#if OPENSSL_VERSION_MAJOR >= 3
676 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
dcec950c 677 if (!ctx)
60696b22 678 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
dcec950c 679
dcec950c 680 if (EVP_PKEY_fromdata_init(ctx) <= 0)
60696b22 681 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
dcec950c 682
85686b37 683 OSSL_PARAM params[3];
dcec950c 684
85686b37
VS
685#if __BYTE_ORDER == __BIG_ENDIAN
686 params[0] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_N, (void*)n, n_size);
687 params[1] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, (void*)e, e_size);
688#else
689 _cleanup_free_ void *native_n = memdup_reverse(n, n_size);
690 if (!native_n)
691 return log_oom_debug();
dcec950c 692
85686b37
VS
693 _cleanup_free_ void *native_e = memdup_reverse(e, e_size);
694 if (!native_e)
695 return log_oom_debug();
dcec950c 696
85686b37
VS
697 params[0] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_N, native_n, n_size);
698 params[1] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, native_e, e_size);
699#endif
700 params[2] = OSSL_PARAM_construct_end();
dcec950c
DS
701
702 if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
60696b22 703 return log_openssl_errors("Failed to create RSA EVP_PKEY");
dcec950c 704#else
85686b37
VS
705 _cleanup_(BN_freep) BIGNUM *bn_n = BN_bin2bn(n, n_size, NULL);
706 if (!bn_n)
707 return log_openssl_errors("Failed to create BIGNUM for RSA n");
708
709 _cleanup_(BN_freep) BIGNUM *bn_e = BN_bin2bn(e, e_size, NULL);
710 if (!bn_e)
711 return log_openssl_errors("Failed to create BIGNUM for RSA e");
712
dcec950c
DS
713 _cleanup_(RSA_freep) RSA *rsa_key = RSA_new();
714 if (!rsa_key)
60696b22 715 return log_openssl_errors("Failed to create new RSA");
dcec950c
DS
716
717 if (!RSA_set0_key(rsa_key, bn_n, bn_e, NULL))
60696b22 718 return log_openssl_errors("Failed to set RSA n/e");
dcec950c
DS
719 /* rsa_key owns these now, don't free */
720 TAKE_PTR(bn_n);
721 TAKE_PTR(bn_e);
722
723 pkey = EVP_PKEY_new();
724 if (!pkey)
60696b22 725 return log_openssl_errors("Failed to create new EVP_PKEY");
dcec950c
DS
726
727 if (!EVP_PKEY_assign_RSA(pkey, rsa_key))
60696b22 728 return log_openssl_errors("Failed to assign RSA key");
dcec950c
DS
729 /* pkey owns this now, don't free */
730 TAKE_PTR(rsa_key);
731#endif
732
733 *ret = TAKE_PTR(pkey);
734
735 return 0;
736}
737
738/* Get the "n" and "e" values from the pkey. The values are returned in "bin" format, i.e. BN_bn2bin(). */
739int rsa_pkey_to_n_e(
740 const EVP_PKEY *pkey,
741 void **ret_n,
742 size_t *ret_n_size,
743 void **ret_e,
744 size_t *ret_e_size) {
745
746 assert(pkey);
747 assert(ret_n);
748 assert(ret_n_size);
749 assert(ret_e);
750 assert(ret_e_size);
751
752#if OPENSSL_VERSION_MAJOR >= 3
753 _cleanup_(BN_freep) BIGNUM *bn_n = NULL;
754 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn_n))
60696b22 755 return log_openssl_errors("Failed to get RSA n");
dcec950c
DS
756
757 _cleanup_(BN_freep) BIGNUM *bn_e = NULL;
758 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn_e))
60696b22 759 return log_openssl_errors("Failed to get RSA e");
dcec950c
DS
760#else
761 const RSA *rsa = EVP_PKEY_get0_RSA((EVP_PKEY*) pkey);
762 if (!rsa)
60696b22 763 return log_openssl_errors("Failed to get RSA key from public key");
dcec950c
DS
764
765 const BIGNUM *bn_n = RSA_get0_n(rsa);
766 if (!bn_n)
60696b22 767 return log_openssl_errors("Failed to get RSA n");
dcec950c
DS
768
769 const BIGNUM *bn_e = RSA_get0_e(rsa);
770 if (!bn_e)
60696b22 771 return log_openssl_errors("Failed to get RSA e");
dcec950c
DS
772#endif
773
774 size_t n_size = BN_num_bytes(bn_n), e_size = BN_num_bytes(bn_e);
775 _cleanup_free_ void *n = malloc(n_size), *e = malloc(e_size);
776 if (!n || !e)
777 return log_oom_debug();
778
779 assert(BN_bn2bin(bn_n, n) == (int) n_size);
780 assert(BN_bn2bin(bn_e, e) == (int) e_size);
781
782 *ret_n = TAKE_PTR(n);
783 *ret_n_size = n_size;
784 *ret_e = TAKE_PTR(e);
785 *ret_e_size = e_size;
786
787 return 0;
788}
789
900e73f8
DS
790/* Generate ECC public key from provided curve ID and x/y points. */
791int ecc_pkey_from_curve_x_y(
792 int curve_id,
793 const void *x,
794 size_t x_size,
795 const void *y,
796 size_t y_size,
797 EVP_PKEY **ret) {
798
799 assert(x);
800 assert(y);
801 assert(ret);
802
803 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
804 if (!ctx)
60696b22 805 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
900e73f8 806
60696b22
DS
807 _cleanup_(BN_freep) BIGNUM *bn_x = BN_bin2bn(x, x_size, NULL);
808 if (!bn_x)
809 return log_openssl_errors("Failed to create BIGNUM x");
810
811 _cleanup_(BN_freep) BIGNUM *bn_y = BN_bin2bn(y, y_size, NULL);
812 if (!bn_y)
813 return log_openssl_errors("Failed to create BIGNUM y");
900e73f8
DS
814
815 _cleanup_(EC_GROUP_freep) EC_GROUP *group = EC_GROUP_new_by_curve_name(curve_id);
816 if (!group)
60696b22 817 return log_openssl_errors("ECC curve id %d not supported", curve_id);
900e73f8
DS
818
819 _cleanup_(EC_POINT_freep) EC_POINT *point = EC_POINT_new(group);
820 if (!point)
60696b22 821 return log_openssl_errors("Failed to create new EC_POINT");
900e73f8
DS
822
823 if (!EC_POINT_set_affine_coordinates(group, point, bn_x, bn_y, NULL))
60696b22 824 return log_openssl_errors("Failed to set ECC coordinates");
900e73f8
DS
825
826#if OPENSSL_VERSION_MAJOR >= 3
827 if (EVP_PKEY_fromdata_init(ctx) <= 0)
60696b22 828 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
900e73f8
DS
829
830 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
831 if (!bld)
60696b22 832 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
900e73f8
DS
833
834 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, (char*) OSSL_EC_curve_nid2name(curve_id), 0))
60696b22 835 return log_openssl_errors("Failed to add ECC OSSL_PKEY_PARAM_GROUP_NAME");
900e73f8
DS
836
837 _cleanup_(OPENSSL_freep) void *pbuf = NULL;
838 size_t pbuf_len = 0;
839 pbuf_len = EC_POINT_point2buf(group, point, POINT_CONVERSION_UNCOMPRESSED, (unsigned char**) &pbuf, NULL);
840 if (pbuf_len == 0)
60696b22 841 return log_openssl_errors("Failed to convert ECC point to buffer");
900e73f8
DS
842
843 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pbuf, pbuf_len))
60696b22 844 return log_openssl_errors("Failed to add ECC OSSL_PKEY_PARAM_PUB_KEY");
900e73f8
DS
845
846 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
847 if (!params)
60696b22 848 return log_openssl_errors("Failed to build ECC OSSL_PARAM");
900e73f8
DS
849
850 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
851 if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
60696b22 852 return log_openssl_errors("Failed to create ECC EVP_PKEY");
900e73f8
DS
853#else
854 _cleanup_(EC_KEY_freep) EC_KEY *eckey = EC_KEY_new();
855 if (!eckey)
60696b22 856 return log_openssl_errors("Failed to create new EC_KEY");
900e73f8
DS
857
858 if (!EC_KEY_set_group(eckey, group))
60696b22 859 return log_openssl_errors("Failed to set ECC group");
900e73f8
DS
860
861 if (!EC_KEY_set_public_key(eckey, point))
60696b22 862 return log_openssl_errors("Failed to set ECC point");
900e73f8
DS
863
864 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = EVP_PKEY_new();
865 if (!pkey)
60696b22 866 return log_openssl_errors("Failed to create new EVP_PKEY");
900e73f8
DS
867
868 if (!EVP_PKEY_assign_EC_KEY(pkey, eckey))
60696b22 869 return log_openssl_errors("Failed to assign ECC key");
900e73f8
DS
870 /* pkey owns this now, don't free */
871 TAKE_PTR(eckey);
872#endif
873
874 *ret = TAKE_PTR(pkey);
875
876 return 0;
877}
878
879int ecc_pkey_to_curve_x_y(
880 const EVP_PKEY *pkey,
881 int *ret_curve_id,
882 void **ret_x,
883 size_t *ret_x_size,
884 void **ret_y,
885 size_t *ret_y_size) {
886
887 _cleanup_(BN_freep) BIGNUM *bn_x = NULL, *bn_y = NULL;
888 int curve_id;
889
890 assert(pkey);
891
892#if OPENSSL_VERSION_MAJOR >= 3
893 size_t name_size;
894 if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0, &name_size))
60696b22 895 return log_openssl_errors("Failed to get ECC group name size");
900e73f8 896
b0307102 897 _cleanup_free_ char *name = new(char, name_size + 1);
900e73f8
DS
898 if (!name)
899 return log_oom_debug();
900
901 if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, name, name_size + 1, NULL))
60696b22 902 return log_openssl_errors("Failed to get ECC group name");
900e73f8
DS
903
904 curve_id = OBJ_sn2nid(name);
905 if (curve_id == NID_undef)
60696b22 906 return log_openssl_errors("Failed to get ECC curve id");
900e73f8
DS
907
908 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &bn_x))
60696b22 909 return log_openssl_errors("Failed to get ECC point x");
900e73f8
DS
910
911 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &bn_y))
60696b22 912 return log_openssl_errors("Failed to get ECC point y");
900e73f8
DS
913#else
914 const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY*) pkey);
915 if (!eckey)
60696b22 916 return log_openssl_errors("Failed to get EC_KEY");
900e73f8
DS
917
918 const EC_GROUP *group = EC_KEY_get0_group(eckey);
919 if (!group)
60696b22 920 return log_openssl_errors("Failed to get EC_GROUP");
900e73f8
DS
921
922 curve_id = EC_GROUP_get_curve_name(group);
923 if (curve_id == NID_undef)
60696b22 924 return log_openssl_errors("Failed to get ECC curve id");
900e73f8
DS
925
926 const EC_POINT *point = EC_KEY_get0_public_key(eckey);
927 if (!point)
60696b22 928 return log_openssl_errors("Failed to get EC_POINT");
900e73f8
DS
929
930 bn_x = BN_new();
931 bn_y = BN_new();
932 if (!bn_x || !bn_y)
60696b22 933 return log_openssl_errors("Failed to create new BIGNUM");
900e73f8
DS
934
935 if (!EC_POINT_get_affine_coordinates(group, point, bn_x, bn_y, NULL))
60696b22 936 return log_openssl_errors("Failed to get ECC x/y.");
900e73f8
DS
937#endif
938
939 size_t x_size = BN_num_bytes(bn_x), y_size = BN_num_bytes(bn_y);
940 _cleanup_free_ void *x = malloc(x_size), *y = malloc(y_size);
941 if (!x || !y)
942 return log_oom_debug();
943
944 assert(BN_bn2bin(bn_x, x) == (int) x_size);
945 assert(BN_bn2bin(bn_y, y) == (int) y_size);
946
947 if (ret_curve_id)
948 *ret_curve_id = curve_id;
949 if (ret_x)
950 *ret_x = TAKE_PTR(x);
951 if (ret_x_size)
952 *ret_x_size = x_size;
953 if (ret_y)
954 *ret_y = TAKE_PTR(y);
955 if (ret_y_size)
956 *ret_y_size = y_size;
957
958 return 0;
959}
960
961/* Generate a new ECC key for the specified ECC curve id. */
962int ecc_pkey_new(int curve_id, EVP_PKEY **ret) {
963 assert(ret);
964
965 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
966 if (!ctx)
60696b22 967 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
900e73f8
DS
968
969 if (EVP_PKEY_keygen_init(ctx) <= 0)
60696b22 970 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
900e73f8
DS
971
972 if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_id) <= 0)
60696b22 973 return log_openssl_errors("Failed to set ECC curve %d", curve_id);
900e73f8
DS
974
975 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
976 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
60696b22 977 return log_openssl_errors("Failed to generate ECC key");
900e73f8
DS
978
979 *ret = TAKE_PTR(pkey);
980
981 return 0;
982}
983
779b80d8
DS
984/* Perform ECDH to derive an ECC shared secret between the provided private key and public peer key. For two
985 * keys, this will result in the same shared secret in either direction; ECDH using Alice's private key and
986 * Bob's public (peer) key will result in the same shared secret as ECDH using Bob's private key and Alice's
987 * public (peer) key. On success, this returns 0 and provides the shared secret; otherwise this returns an
988 * error. */
989int ecc_ecdh(const EVP_PKEY *private_pkey,
990 const EVP_PKEY *peer_pkey,
991 void **ret_shared_secret,
992 size_t *ret_shared_secret_size) {
993
994 assert(private_pkey);
995 assert(peer_pkey);
996 assert(ret_shared_secret);
997 assert(ret_shared_secret_size);
998
999 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new((EVP_PKEY*) private_pkey, NULL);
1000 if (!ctx)
1001 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
1002
1003 if (EVP_PKEY_derive_init(ctx) <= 0)
1004 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
1005
1006 if (EVP_PKEY_derive_set_peer(ctx, (EVP_PKEY*) peer_pkey) <= 0)
1007 return log_openssl_errors("Failed to set ECC derive peer");
1008
1009 size_t shared_secret_size;
1010 if (EVP_PKEY_derive(ctx, NULL, &shared_secret_size) <= 0)
1011 return log_openssl_errors("Failed to get ECC shared secret size");
1012
3d05c058 1013 _cleanup_(erase_and_freep) void *shared_secret = malloc(shared_secret_size);
779b80d8
DS
1014 if (!shared_secret)
1015 return log_oom_debug();
1016
1017 if (EVP_PKEY_derive(ctx, (unsigned char*) shared_secret, &shared_secret_size) <= 0)
1018 return log_openssl_errors("Failed to derive ECC shared secret");
1019
1020 *ret_shared_secret = TAKE_PTR(shared_secret);
1021 *ret_shared_secret_size = shared_secret_size;
1022
1023 return 0;
1024}
1025
e8ccb5c7
LP
1026int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size) {
1027 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* m = NULL;
1028 _cleanup_free_ void *d = NULL, *h = NULL;
1029 int sz, lsz, msz;
1030 unsigned umsz;
1031 unsigned char *dd;
1032
1033 /* Calculates a message digest of the DER encoded public key */
1034
1035 assert(pk);
1036 assert(md);
1037 assert(ret);
1038 assert(ret_size);
1039
1040 sz = i2d_PublicKey(pk, NULL);
1041 if (sz < 0)
60696b22 1042 return log_openssl_errors("Unable to convert public key to DER format");
e8ccb5c7
LP
1043
1044 dd = d = malloc(sz);
1045 if (!d)
1046 return log_oom_debug();
1047
1048 lsz = i2d_PublicKey(pk, &dd);
1049 if (lsz < 0)
60696b22 1050 return log_openssl_errors("Unable to convert public key to DER format");
e8ccb5c7
LP
1051
1052 m = EVP_MD_CTX_new();
1053 if (!m)
60696b22 1054 return log_openssl_errors("Failed to create new EVP_MD_CTX");
e8ccb5c7
LP
1055
1056 if (EVP_DigestInit_ex(m, md, NULL) != 1)
60696b22 1057 return log_openssl_errors("Failed to initialize %s context", EVP_MD_name(md));
e8ccb5c7
LP
1058
1059 if (EVP_DigestUpdate(m, d, lsz) != 1)
60696b22 1060 return log_openssl_errors("Failed to run %s context", EVP_MD_name(md));
e8ccb5c7
LP
1061
1062 msz = EVP_MD_size(md);
2e64df07 1063 assert(msz > 0);
e8ccb5c7
LP
1064
1065 h = malloc(msz);
1066 if (!h)
1067 return log_oom_debug();
1068
1069 umsz = msz;
1070 if (EVP_DigestFinal_ex(m, h, &umsz) != 1)
60696b22 1071 return log_openssl_errors("Failed to finalize hash context");
e8ccb5c7 1072
2e64df07 1073 assert(umsz == (unsigned) msz);
e8ccb5c7
LP
1074
1075 *ret = TAKE_PTR(h);
1076 *ret_size = msz;
1077
1078 return 0;
1079}
1080
ef65c0f6
LP
1081int digest_and_sign(
1082 const EVP_MD *md,
1083 EVP_PKEY *privkey,
1084 const void *data, size_t size,
1085 void **ret, size_t *ret_size) {
1086
1144f07d
LP
1087 int r;
1088
ef65c0f6
LP
1089 assert(privkey);
1090 assert(ret);
1091 assert(ret_size);
1092
1093 if (size == 0)
1094 data = ""; /* make sure to pass a valid pointer to OpenSSL */
1095 else {
1096 assert(data);
1097
1098 if (size == SIZE_MAX) /* If SIZE_MAX input is a string whose size we determine automatically */
1099 size = strlen(data);
1100 }
1101
1102 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
1103 if (!mdctx)
1104 return log_openssl_errors("Failed to create new EVP_MD_CTX");
1105
1144f07d
LP
1106 if (EVP_DigestSignInit(mdctx, NULL, md, NULL, privkey) != 1) {
1107 /* Distro security policies often disable support for SHA-1. Let's return a recognizable
1108 * error for that case. */
1109 bool invalid_digest = ERR_GET_REASON(ERR_peek_last_error()) == EVP_R_INVALID_DIGEST;
1110 r = log_openssl_errors("Failed to initialize signature context");
1111 return invalid_digest ? -EADDRNOTAVAIL : r;
1112}
ef65c0f6
LP
1113
1114 /* Determine signature size */
1115 size_t ss;
1116 if (EVP_DigestSign(mdctx, NULL, &ss, data, size) != 1)
1117 return log_openssl_errors("Failed to determine size of signature");
1118
1119 _cleanup_free_ void *sig = malloc(ss);
1120 if (!sig)
1121 return log_oom_debug();
1122
1123 if (EVP_DigestSign(mdctx, sig, &ss, data, size) != 1)
1124 return log_openssl_errors("Failed to sign data");
1125
1126 *ret = TAKE_PTR(sig);
1127 *ret_size = ss;
1128 return 0;
1129}
1130
768a297c 1131int pkcs7_new(X509 *certificate, EVP_PKEY *private_key, const char *hash_algorithm, PKCS7 **ret_p7, PKCS7_SIGNER_INFO **ret_si) {
d46b16af
DDM
1132 assert(certificate);
1133 assert(ret_p7);
1134
1135 /* This function sets up a new PKCS7 signing context. If a private key is provided, the context is
1136 * set up for "in-band" signing with PKCS7_dataFinal(). If a private key is not provided, the context
1137 * is set up for "out-of-band" signing, meaning the signature has to be provided by the user and
768a297c
DS
1138 * copied into the signer info's "enc_digest" field. If the signing hash algorithm is not provided,
1139 * SHA-256 is used. */
d46b16af
DDM
1140
1141 _cleanup_(PKCS7_freep) PKCS7 *p7 = PKCS7_new();
1142 if (!p7)
1143 return log_oom();
1144
1145 if (PKCS7_set_type(p7, NID_pkcs7_signed) == 0)
1146 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 type: %s",
1147 ERR_error_string(ERR_get_error(), NULL));
1148
1149 if (PKCS7_content_new(p7, NID_pkcs7_data) == 0)
1150 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 content: %s",
1151 ERR_error_string(ERR_get_error(), NULL));
1152
1153 if (PKCS7_add_certificate(p7, certificate) == 0)
1154 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 certificate: %s",
1155 ERR_error_string(ERR_get_error(), NULL));
1156
768a297c
DS
1157 int x509_pknid = 0;
1158 if (X509_get_signature_info(certificate, NULL, &x509_pknid, NULL, NULL) == 0)
d46b16af
DDM
1159 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get X509 digest NID: %s",
1160 ERR_error_string(ERR_get_error(), NULL));
1161
768a297c 1162 const EVP_MD *md = EVP_get_digestbyname(hash_algorithm ?: "SHA256");
d46b16af 1163 if (!md)
768a297c
DS
1164 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to get digest algorithm '%s'",
1165 hash_algorithm ?: "SHA256");
d46b16af
DDM
1166
1167 _cleanup_(PKCS7_SIGNER_INFO_freep) PKCS7_SIGNER_INFO *si = PKCS7_SIGNER_INFO_new();
1168 if (!si)
1169 return log_oom();
1170
1171 if (private_key) {
768a297c 1172 if (PKCS7_SIGNER_INFO_set(si, certificate, private_key, md) <= 0)
d46b16af
DDM
1173 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to configure signer info: %s",
1174 ERR_error_string(ERR_get_error(), NULL));
1175 } else {
1176 if (ASN1_INTEGER_set(si->version, 1) == 0)
1177 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info version: %s",
1178 ERR_error_string(ERR_get_error(), NULL));
1179
1180 if (X509_NAME_set(&si->issuer_and_serial->issuer, X509_get_issuer_name(certificate)) == 0)
1181 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info issuer: %s",
1182 ERR_error_string(ERR_get_error(), NULL));
1183
1184 ASN1_INTEGER_free(si->issuer_and_serial->serial);
1185 si->issuer_and_serial->serial = ASN1_INTEGER_dup(X509_get0_serialNumber(certificate));
1186 if (!si->issuer_and_serial->serial)
1187 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info serial: %s",
1188 ERR_error_string(ERR_get_error(), NULL));
1189
768a297c 1190 if (X509_ALGOR_set0(si->digest_alg, OBJ_nid2obj(EVP_MD_type(md)), V_ASN1_NULL, NULL) == 0)
d46b16af
DDM
1191 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info digest algorithm: %s",
1192 ERR_error_string(ERR_get_error(), NULL));
1193
1194 if (X509_ALGOR_set0(si->digest_enc_alg, OBJ_nid2obj(x509_pknid), V_ASN1_NULL, NULL) == 0)
1195 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set signer info signing algorithm: %s",
1196 ERR_error_string(ERR_get_error(), NULL));
1197 }
1198
1199 if (PKCS7_add_signer(p7, si) == 0)
1200 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to set PKCS7 signer info: %s",
1201 ERR_error_string(ERR_get_error(), NULL));
1202
1203 *ret_p7 = TAKE_PTR(p7);
1204 if (ret_si)
1205 /* We do not pass ownership here, 'si' object remains owned by 'p7' object. */
1206 *ret_si = si;
1207
1208 TAKE_PTR(si);
1209
1210 return 0;
1211}
1212
7e8facb3
ZJS
1213int string_hashsum(
1214 const char *s,
1215 size_t len,
11f7bc5e 1216 const char *md_algorithm,
7e8facb3
ZJS
1217 char **ret) {
1218
11f7bc5e 1219 _cleanup_free_ void *hash = NULL;
7e8facb3 1220 size_t hash_size;
38e1035b 1221 _cleanup_free_ char *enc = NULL;
7e8facb3
ZJS
1222 int r;
1223
11f7bc5e
DS
1224 assert(s || len == 0);
1225 assert(md_algorithm);
1226 assert(ret);
7e8facb3 1227
11f7bc5e 1228 r = openssl_digest(md_algorithm, s, len, &hash, &hash_size);
7e8facb3
ZJS
1229 if (r < 0)
1230 return r;
1231
1232 enc = hexmem(hash, hash_size);
1233 if (!enc)
1234 return -ENOMEM;
1235
11f7bc5e 1236 *ret = TAKE_PTR(enc);
7e8facb3 1237 return 0;
7e8facb3 1238}
876206f2 1239
3d05c058
VS
1240static int ecc_pkey_generate_volume_keys(
1241 EVP_PKEY *pkey,
1242 void **ret_decrypted_key,
1243 size_t *ret_decrypted_key_size,
1244 void **ret_saved_key,
1245 size_t *ret_saved_key_size) {
1246
1247 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_new = NULL;
1248 _cleanup_(erase_and_freep) void *decrypted_key = NULL;
1249 _cleanup_free_ unsigned char *saved_key = NULL;
1250 size_t decrypted_key_size, saved_key_size;
1251 int nid = NID_undef;
1252 int r;
1253
1254#if OPENSSL_VERSION_MAJOR >= 3
1255 _cleanup_free_ char *curve_name = NULL;
1256 size_t len = 0;
1257
1258 if (EVP_PKEY_get_group_name(pkey, NULL, 0, &len) != 1 || len == 0)
1259 return log_openssl_errors("Failed to determine PKEY group name length");
1260
1261 len++;
1262 curve_name = new(char, len);
1263 if (!curve_name)
1264 return log_oom_debug();
1265
1266 if (EVP_PKEY_get_group_name(pkey, curve_name, len, &len) != 1)
1267 return log_openssl_errors("Failed to get PKEY group name");
1268
1269 nid = OBJ_sn2nid(curve_name);
1270#else
1271 EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
1272 if (!ec_key)
1273 return log_openssl_errors("PKEY doesn't have EC_KEY associated");
1274
1275 if (EC_KEY_check_key(ec_key) != 1)
1276 return log_openssl_errors("EC_KEY associated with PKEY is not valid");
1277
1278 nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
1279#endif
1280
1281 r = ecc_pkey_new(nid, &pkey_new);
1282 if (r < 0)
1283 return log_debug_errno(r, "Failed to generate a new EC keypair: %m");
1284
1285 r = ecc_ecdh(pkey_new, pkey, &decrypted_key, &decrypted_key_size);
1286 if (r < 0)
1287 return log_debug_errno(r, "Failed to derive shared secret: %m");
1288
1289#if OPENSSL_VERSION_MAJOR >= 3
1290 /* EVP_PKEY_get1_encoded_public_key() always returns uncompressed format of EC points.
1291 See https://github.com/openssl/openssl/discussions/22835 */
1292 saved_key_size = EVP_PKEY_get1_encoded_public_key(pkey_new, &saved_key);
1293 if (saved_key_size == 0)
1294 return log_openssl_errors("Failed to convert the generated public key to SEC1 format");
1295#else
1296 EC_KEY *ec_key_new = EVP_PKEY_get0_EC_KEY(pkey_new);
1297 if (!ec_key_new)
1298 return log_openssl_errors("The generated key doesn't have associated EC_KEY");
1299
1300 if (EC_KEY_check_key(ec_key_new) != 1)
1301 return log_openssl_errors("EC_KEY associated with the generated key is not valid");
1302
1303 saved_key_size = EC_POINT_point2oct(EC_KEY_get0_group(ec_key_new),
1304 EC_KEY_get0_public_key(ec_key_new),
1305 POINT_CONVERSION_UNCOMPRESSED,
1306 NULL, 0, NULL);
1307 if (saved_key_size == 0)
1308 return log_openssl_errors("Failed to determine size of the generated public key");
1309
1310 saved_key = malloc(saved_key_size);
1311 if (!saved_key)
1312 return log_oom_debug();
1313
1314 saved_key_size = EC_POINT_point2oct(EC_KEY_get0_group(ec_key_new),
1315 EC_KEY_get0_public_key(ec_key_new),
1316 POINT_CONVERSION_UNCOMPRESSED,
1317 saved_key, saved_key_size, NULL);
1318 if (saved_key_size == 0)
1319 return log_openssl_errors("Failed to convert the generated public key to SEC1 format");
1320#endif
1321
1322 *ret_decrypted_key = TAKE_PTR(decrypted_key);
1323 *ret_decrypted_key_size = decrypted_key_size;
1324 *ret_saved_key = TAKE_PTR(saved_key);
1325 *ret_saved_key_size = saved_key_size;
1326 return 0;
1327}
1328
876206f2
VS
1329static int rsa_pkey_generate_volume_keys(
1330 EVP_PKEY *pkey,
1331 void **ret_decrypted_key,
1332 size_t *ret_decrypted_key_size,
1333 void **ret_saved_key,
1334 size_t *ret_saved_key_size) {
1335
1336 _cleanup_(erase_and_freep) void *decrypted_key = NULL;
1337 _cleanup_free_ void *saved_key = NULL;
1338 size_t decrypted_key_size, saved_key_size;
1339 int r;
1340
1341 r = rsa_pkey_to_suitable_key_size(pkey, &decrypted_key_size);
1342 if (r < 0)
1343 return log_debug_errno(r, "Failed to determine RSA public key size.");
1344
1345 log_debug("Generating %zu bytes random key.", decrypted_key_size);
1346
1347 decrypted_key = malloc(decrypted_key_size);
1348 if (!decrypted_key)
1349 return log_oom_debug();
1350
1351 r = crypto_random_bytes(decrypted_key, decrypted_key_size);
1352 if (r < 0)
1353 return log_debug_errno(r, "Failed to generate random key: %m");
1354
1355 r = rsa_encrypt_bytes(pkey, decrypted_key, decrypted_key_size, &saved_key, &saved_key_size);
1356 if (r < 0)
1357 return log_debug_errno(r, "Failed to encrypt random key: %m");
1358
1359 *ret_decrypted_key = TAKE_PTR(decrypted_key);
1360 *ret_decrypted_key_size = decrypted_key_size;
1361 *ret_saved_key = TAKE_PTR(saved_key);
1362 *ret_saved_key_size = saved_key_size;
1363 return 0;
1364}
1365
85686b37
VS
1366int pkey_generate_volume_keys(
1367 EVP_PKEY *pkey,
876206f2
VS
1368 void **ret_decrypted_key,
1369 size_t *ret_decrypted_key_size,
1370 void **ret_saved_key,
1371 size_t *ret_saved_key_size) {
1372
85686b37 1373 assert(pkey);
876206f2
VS
1374 assert(ret_decrypted_key);
1375 assert(ret_decrypted_key_size);
1376 assert(ret_saved_key);
1377 assert(ret_saved_key_size);
1378
876206f2
VS
1379#if OPENSSL_VERSION_MAJOR >= 3
1380 int type = EVP_PKEY_get_base_id(pkey);
1381#else
1382 int type = EVP_PKEY_base_id(pkey);
1383#endif
1384 switch (type) {
1385
1386 case EVP_PKEY_RSA:
1387 return rsa_pkey_generate_volume_keys(pkey, ret_decrypted_key, ret_decrypted_key_size, ret_saved_key, ret_saved_key_size);
1388
3d05c058
VS
1389 case EVP_PKEY_EC:
1390 return ecc_pkey_generate_volume_keys(pkey, ret_decrypted_key, ret_decrypted_key_size, ret_saved_key, ret_saved_key_size);
1391
876206f2 1392 case NID_undef:
4e494e6a 1393 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine a type of public key.");
876206f2
VS
1394
1395 default:
1396 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unsupported public key type: %s", OBJ_nid2sn(type));
1397 }
1398}
dba0afa1 1399
eac5336c
DDM
1400static int load_key_from_provider(
1401 const char *provider,
1402 const char *private_key_uri,
eac5336c 1403 EVP_PKEY **ret) {
dba0afa1
LB
1404
1405 assert(provider);
1406 assert(private_key_uri);
1407 assert(ret);
1408
1409#if OPENSSL_VERSION_MAJOR >= 3
1410 /* Load the provider so that this can work without any custom written configuration in /etc/.
1411 * Also load the 'default' as that seems to be the recommendation. */
1412 if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, provider, /* retain_fallbacks= */ true))
1413 return log_openssl_errors("Failed to load OpenSSL provider '%s'", provider);
1414 if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, "default", /* retain_fallbacks= */ true))
1415 return log_openssl_errors("Failed to load OpenSSL provider 'default'");
1416
1417 _cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = OSSL_STORE_open(
1418 private_key_uri,
0bf70b19
DDM
1419 /*ui_method=*/ NULL,
1420 /*ui_method=*/ NULL,
dba0afa1
LB
1421 /* post_process= */ NULL,
1422 /* post_process_data= */ NULL);
1423 if (!store)
1424 return log_openssl_errors("Failed to open OpenSSL store via '%s'", private_key_uri);
1425
5619a618
DDM
1426 if (OSSL_STORE_expect(store, OSSL_STORE_INFO_PKEY) == 0)
1427 return log_openssl_errors("Failed to filter store by private keys");
1428
dba0afa1
LB
1429 _cleanup_(OSSL_STORE_INFO_freep) OSSL_STORE_INFO *info = OSSL_STORE_load(store);
1430 if (!info)
1431 return log_openssl_errors("Failed to load OpenSSL store via '%s'", private_key_uri);
1432
1433 _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = OSSL_STORE_INFO_get1_PKEY(info);
1434 if (!private_key)
1435 return log_openssl_errors("Failed to load private key via '%s'", private_key_uri);
1436
1437 *ret = TAKE_PTR(private_key);
1438
1439 return 0;
1440#else
1441 return -EOPNOTSUPP;
1442#endif
1443}
1444
0bf70b19 1445static int load_key_from_engine(const char *engine, const char *private_key_uri, EVP_PKEY **ret) {
dba0afa1
LB
1446 assert(engine);
1447 assert(private_key_uri);
1448 assert(ret);
1449
81d61d6a 1450#if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
dba0afa1
LB
1451 DISABLE_WARNING_DEPRECATED_DECLARATIONS;
1452 _cleanup_(ENGINE_freep) ENGINE *e = ENGINE_by_id(engine);
1453 if (!e)
1454 return log_openssl_errors("Failed to load signing engine '%s'", engine);
1455
1456 if (ENGINE_init(e) == 0)
1457 return log_openssl_errors("Failed to initialize signing engine '%s'", engine);
1458
0bf70b19 1459 _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = ENGINE_load_private_key(e, private_key_uri, /*ui_method=*/ NULL, /*callback_data=*/ NULL);
dba0afa1
LB
1460 if (!private_key)
1461 return log_openssl_errors("Failed to load private key from '%s'", private_key_uri);
1462 REENABLE_WARNING;
1463
1464 *ret = TAKE_PTR(private_key);
1465
1466 return 0;
81d61d6a
NL
1467#else
1468 return -EOPNOTSUPP;
1469#endif
dba0afa1
LB
1470}
1471
d1d16c62 1472#ifndef OPENSSL_NO_UI_CONSOLE
eac5336c
DDM
1473static int openssl_ask_password_ui_read(UI *ui, UI_STRING *uis) {
1474 int r;
1475
1476 switch(UI_get_string_type(uis)) {
1477 case UIT_PROMPT: {
1478 /* If no ask password request was configured use the default openssl UI. */
0bf70b19 1479 AskPasswordRequest *req = (AskPasswordRequest*) UI_method_get_ex_data(UI_get_method(ui), 0);
eac5336c
DDM
1480 if (!req)
1481 return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
1482
1483 req->message = UI_get0_output_string(uis);
1484
fe5a1afb 1485 _cleanup_strv_free_ char **l = NULL;
c4a02a52 1486 r = ask_password_auto(req, ASK_PASSWORD_ACCEPT_CACHED|ASK_PASSWORD_PUSH_CACHE, &l);
eac5336c
DDM
1487 if (r < 0) {
1488 log_error_errno(r, "Failed to query for PIN: %m");
1489 return 0;
1490 }
1491
1492 if (strv_length(l) != 1) {
1493 log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected only a single password/pin.");
1494 return 0;
1495 }
1496
1497 if (UI_set_result(ui, uis, *l) != 0) {
1498 log_openssl_errors("Failed to set user interface result");
1499 return 0;
1500 }
1501
1502 return 1;
1503 }
1504 default:
1505 return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
1506 }
1507}
d1d16c62 1508#endif
8939d335 1509
0bf70b19
DDM
1510static int openssl_load_private_key_from_file(const char *path, EVP_PKEY **ret) {
1511 _cleanup_(erase_and_freep) char *rawkey = NULL;
1512 _cleanup_(BIO_freep) BIO *kb = NULL;
1513 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pk = NULL;
1514 size_t rawkeysz;
1515 int r;
1516
1517 assert(path);
1518 assert(ret);
1519
1520 r = read_full_file_full(
1521 AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
1522 READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET,
1523 NULL,
1524 &rawkey, &rawkeysz);
1525 if (r < 0)
1526 return log_debug_errno(r, "Failed to read key file '%s': %m", path);
1527
1528 kb = BIO_new_mem_buf(rawkey, rawkeysz);
1529 if (!kb)
1530 return log_oom_debug();
1531
1532 pk = PEM_read_bio_PrivateKey(kb, NULL, NULL, NULL);
1533 if (!pk)
1534 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse PEM private key: %s",
1535 ERR_error_string(ERR_get_error(), NULL));
1536
1537 if (ret)
1538 *ret = TAKE_PTR(pk);
1539
1540 return 0;
1541}
1542
1543static int openssl_ask_password_ui_new(const AskPasswordRequest *request, OpenSSLAskPasswordUI **ret) {
eac5336c
DDM
1544 assert(ret);
1545
d1d16c62 1546#ifndef OPENSSL_NO_UI_CONSOLE
eac5336c
DDM
1547 _cleanup_(UI_destroy_methodp) UI_METHOD *method = UI_create_method("systemd-ask-password");
1548 if (!method)
1549 return log_openssl_errors("Failed to initialize openssl user interface");
1550
1551 if (UI_method_set_reader(method, openssl_ask_password_ui_read) != 0)
1552 return log_openssl_errors("Failed to set openssl user interface reader");
1553
1554 OpenSSLAskPasswordUI *ui = new(OpenSSLAskPasswordUI, 1);
1555 if (!ui)
1556 return log_oom_debug();
1557
1558 *ui = (OpenSSLAskPasswordUI) {
1559 .method = TAKE_PTR(method),
0bf70b19 1560 .request = *request,
eac5336c
DDM
1561 };
1562
0bf70b19
DDM
1563 UI_set_default_method(ui->method);
1564
1565 if (UI_method_set_ex_data(ui->method, 0, &ui->request) == 0)
1566 return log_openssl_errors("Failed to set extra data for UI method");
1567
eac5336c
DDM
1568 *ret = TAKE_PTR(ui);
1569 return 0;
d1d16c62
YW
1570#else
1571 return -EOPNOTSUPP;
1572#endif
0bf70b19 1573}
a1d46e30
DDM
1574
1575static int load_x509_certificate_from_file(const char *path, X509 **ret) {
1576 _cleanup_free_ char *rawcert = NULL;
1577 _cleanup_(X509_freep) X509 *cert = NULL;
1578 _cleanup_(BIO_freep) BIO *cb = NULL;
1579 size_t rawcertsz;
1580 int r;
1581
1582 assert(path);
1583 assert(ret);
1584
1585 r = read_full_file_full(
1586 AT_FDCWD, path, UINT64_MAX, SIZE_MAX,
1587 READ_FULL_FILE_CONNECT_SOCKET,
1588 NULL,
1589 &rawcert, &rawcertsz);
1590 if (r < 0)
1591 return log_debug_errno(r, "Failed to read certificate file '%s': %m", path);
1592
1593 cb = BIO_new_mem_buf(rawcert, rawcertsz);
1594 if (!cb)
1595 return log_oom_debug();
1596
1597 cert = PEM_read_bio_X509(cb, NULL, NULL, NULL);
1598 if (!cert)
1599 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse X.509 certificate: %s",
1600 ERR_error_string(ERR_get_error(), NULL));
1601
1602 if (ret)
1603 *ret = TAKE_PTR(cert);
1604
1605 return 0;
1606}
1607
1608static int load_x509_certificate_from_provider(const char *provider, const char *certificate_uri, X509 **ret) {
1609 assert(provider);
1610 assert(certificate_uri);
1611 assert(ret);
1612
1613#if OPENSSL_VERSION_MAJOR >= 3
1614 /* Load the provider so that this can work without any custom written configuration in /etc/.
1615 * Also load the 'default' as that seems to be the recommendation. */
1616 if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, provider, /* retain_fallbacks= */ true))
1617 return log_openssl_errors("Failed to load OpenSSL provider '%s'", provider);
1618 if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, "default", /* retain_fallbacks= */ true))
1619 return log_openssl_errors("Failed to load OpenSSL provider 'default'");
1620
1621 _cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = OSSL_STORE_open(
1622 certificate_uri,
1623 /*ui_method=*/ NULL,
1624 /*ui_method=*/ NULL,
1625 /* post_process= */ NULL,
1626 /* post_process_data= */ NULL);
1627 if (!store)
1628 return log_openssl_errors("Failed to open OpenSSL store via '%s'", certificate_uri);
1629
1630 if (OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) == 0)
1631 return log_openssl_errors("Failed to filter store by X.509 certificates");
1632
1633 _cleanup_(OSSL_STORE_INFO_freep) OSSL_STORE_INFO *info = OSSL_STORE_load(store);
1634 if (!info)
1635 return log_openssl_errors("Failed to load OpenSSL store via '%s'", certificate_uri);
1636
1637 _cleanup_(X509_freep) X509 *cert = OSSL_STORE_INFO_get1_CERT(info);
1638 if (!cert)
1639 return log_openssl_errors("Failed to load certificate via '%s'", certificate_uri);
1640
1641 *ret = TAKE_PTR(cert);
1642
1643 return 0;
1644#else
1645 return -EOPNOTSUPP;
1646#endif
1647}
0bf70b19
DDM
1648#endif
1649
1650OpenSSLAskPasswordUI* openssl_ask_password_ui_free(OpenSSLAskPasswordUI *ui) {
d1d16c62 1651#if HAVE_OPENSSL && !defined(OPENSSL_NO_UI_CONSOLE)
0bf70b19
DDM
1652 if (!ui)
1653 return NULL;
1654
1655 assert(UI_get_default_method() == ui->method);
1656 UI_set_default_method(UI_OpenSSL());
1657 UI_destroy_method(ui->method);
1658 return mfree(ui);
eac5336c 1659#else
0bf70b19
DDM
1660 assert(ui == NULL);
1661 return NULL;
eac5336c
DDM
1662#endif
1663}
1664
8939d335
DDM
1665int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
1666#if HAVE_OPENSSL
1667 _cleanup_free_ uint8_t *der = NULL;
1668 int dersz;
1669
1670 assert(cert);
1671
1672 dersz = i2d_X509(cert, &der);
1673 if (dersz < 0)
60696b22 1674 return log_openssl_errors("Unable to convert PEM certificate to DER format");
8939d335
DDM
1675
1676 sha256_direct(der, dersz, buffer);
1677 return 0;
1678#else
4e494e6a 1679 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot calculate X509 fingerprint.");
8939d335
DDM
1680#endif
1681}
a73144bb 1682
a1d46e30
DDM
1683int openssl_load_x509_certificate(
1684 CertificateSourceType certificate_source_type,
1685 const char *certificate_source,
1686 const char *certificate,
1687 X509 **ret) {
eac5336c 1688#if HAVE_OPENSSL
eac5336c
DDM
1689 int r;
1690
a1d46e30 1691 assert(certificate);
eac5336c 1692
a1d46e30 1693 switch (certificate_source_type) {
eac5336c 1694
a1d46e30
DDM
1695 case OPENSSL_CERTIFICATE_SOURCE_FILE:
1696 r = load_x509_certificate_from_file(certificate, ret);
1697 break;
1698 case OPENSSL_CERTIFICATE_SOURCE_PROVIDER:
1699 r = load_x509_certificate_from_provider(certificate_source, certificate, ret);
1700 break;
1701 default:
1702 assert_not_reached();
1703 }
1704 if (r < 0)
1705 return log_debug_errno(
1706 r,
1707 "Failed to load certificate '%s' from OpenSSL certificate source %s: %m",
1708 certificate,
1709 certificate_source);
eac5336c
DDM
1710
1711 return 0;
1712#else
1713 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot load X509 certificate.");
1714#endif
1715}
1716
eac5336c
DDM
1717int openssl_load_private_key(
1718 KeySourceType private_key_source_type,
1719 const char *private_key_source,
1720 const char *private_key,
1721 const AskPasswordRequest *request,
1722 EVP_PKEY **ret_private_key,
1723 OpenSSLAskPasswordUI **ret_user_interface) {
0bf70b19 1724#if HAVE_OPENSSL
eac5336c
DDM
1725 int r;
1726
1727 assert(private_key);
1728 assert(request);
1729
1730 if (private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
1731 r = openssl_load_private_key_from_file(private_key, ret_private_key);
1732 if (r < 0)
1733 return r;
1734
1735 *ret_user_interface = NULL;
1736 } else {
1737 _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
0bf70b19 1738 r = openssl_ask_password_ui_new(request, &ui);
eac5336c
DDM
1739 if (r < 0)
1740 return log_debug_errno(r, "Failed to allocate ask-password user interface: %m");
1741
0bf70b19 1742 switch (private_key_source_type) {
eac5336c 1743
0bf70b19
DDM
1744 case OPENSSL_KEY_SOURCE_ENGINE:
1745 r = load_key_from_engine(private_key_source, private_key, ret_private_key);
1746 break;
1747 case OPENSSL_KEY_SOURCE_PROVIDER:
1748 r = load_key_from_provider(private_key_source, private_key, ret_private_key);
1749 break;
1750 default:
1751 assert_not_reached();
1752 }
eac5336c
DDM
1753 if (r < 0)
1754 return log_debug_errno(
1755 r,
1756 "Failed to load key '%s' from OpenSSL private key source %s: %m",
1757 private_key,
1758 private_key_source);
1759
1760 *ret_user_interface = TAKE_PTR(ui);
1761 }
1762
1763 return 0;
0bf70b19
DDM
1764#else
1765 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot load private key.");
1766#endif
eac5336c
DDM
1767}
1768
a1d46e30
DDM
1769int parse_openssl_certificate_source_argument(
1770 const char *argument,
1771 char **certificate_source,
1772 CertificateSourceType *certificate_source_type) {
1773
1774 CertificateSourceType type;
1775 const char *e = NULL;
1776 int r;
1777
1778 assert(argument);
1779 assert(certificate_source);
1780 assert(certificate_source_type);
1781
1782 if (streq(argument, "file"))
1783 type = OPENSSL_CERTIFICATE_SOURCE_FILE;
1784 else if ((e = startswith(argument, "provider:")))
1785 type = OPENSSL_CERTIFICATE_SOURCE_PROVIDER;
1786 else
1787 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid certificate source '%s'", argument);
1788
1789 r = free_and_strdup_warn(certificate_source, e);
1790 if (r < 0)
1791 return r;
1792
1793 *certificate_source_type = type;
1794
1795 return 0;
1796}
1797
a73144bb
LB
1798int parse_openssl_key_source_argument(
1799 const char *argument,
1800 char **private_key_source,
1801 KeySourceType *private_key_source_type) {
1802
1803 KeySourceType type;
1804 const char *e = NULL;
1805 int r;
1806
1807 assert(argument);
1808 assert(private_key_source);
1809 assert(private_key_source_type);
1810
1811 if (streq(argument, "file"))
1812 type = OPENSSL_KEY_SOURCE_FILE;
1813 else if ((e = startswith(argument, "engine:")))
1814 type = OPENSSL_KEY_SOURCE_ENGINE;
1815 else if ((e = startswith(argument, "provider:")))
1816 type = OPENSSL_KEY_SOURCE_PROVIDER;
1817 else
1818 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid private key source '%s'", argument);
1819
1820 r = free_and_strdup_warn(private_key_source, e);
1821 if (r < 0)
1822 return r;
1823
1824 *private_key_source_type = type;
1825
1826 return 0;
1827}