]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/openssl-util.c
mkosi: update arch commit reference
[thirdparty/systemd.git] / src / shared / openssl-util.c
CommitLineData
30e31503
ZJS
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
85686b37
VS
3#include <endian.h>
4
f2d5df8a 5#include "alloc-util.h"
a65a25be 6#include "fd-util.h"
7e8facb3 7#include "hexdecoct.h"
85686b37 8#include "memory-util.h"
a65a25be 9#include "openssl-util.h"
876206f2 10#include "random-util.h"
a65a25be 11#include "string-util.h"
f2d5df8a
LP
12
13#if HAVE_OPENSSL
81d61d6a
NL
14# include <openssl/rsa.h>
15# include <openssl/ec.h>
16
17# if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
18# include <openssl/engine.h>
19DISABLE_WARNING_DEPRECATED_DECLARATIONS;
20DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ENGINE*, ENGINE_free, NULL);
21REENABLE_WARNING;
22# endif
23
3d05c058
VS
24/* For each error in the OpenSSL thread error queue, log the provided message and the OpenSSL error
25 * string. If there are no errors in the OpenSSL thread queue, this logs the message with "No OpenSSL
60696b22
DS
26 * errors." This logs at level debug. Returns -EIO (or -ENOMEM). */
27#define log_openssl_errors(fmt, ...) _log_openssl_errors(UNIQ, fmt, ##__VA_ARGS__)
28#define _log_openssl_errors(u, fmt, ...) \
29 ({ \
30 size_t UNIQ_T(MAX, u) = 512 /* arbitrary, but openssl doc states it must be >= 256 */; \
31 _cleanup_free_ char *UNIQ_T(BUF, u) = malloc(UNIQ_T(MAX, u)); \
32 !UNIQ_T(BUF, u) \
33 ? log_oom_debug() \
34 : __log_openssl_errors(u, UNIQ_T(BUF, u), UNIQ_T(MAX, u), fmt, ##__VA_ARGS__) \
968d232d 35 ?: log_debug_errno(SYNTHETIC_ERRNO(EIO), fmt ": No OpenSSL errors.", ##__VA_ARGS__); \
60696b22
DS
36 })
37#define __log_openssl_errors(u, buf, max, fmt, ...) \
38 ({ \
39 int UNIQ_T(R, u) = 0; \
40 for (;;) { \
41 unsigned long UNIQ_T(E, u) = ERR_get_error(); \
42 if (UNIQ_T(E, u) == 0) \
43 break; \
44 ERR_error_string_n(UNIQ_T(E, u), buf, max); \
45 UNIQ_T(R, u) = log_debug_errno(SYNTHETIC_ERRNO(EIO), fmt ": %s", ##__VA_ARGS__, buf); \
46 } \
47 UNIQ_T(R, u); \
48 })
49
4af788c7
DS
50int openssl_pkey_from_pem(const void *pem, size_t pem_size, EVP_PKEY **ret) {
51 assert(pem);
52 assert(ret);
53
54 _cleanup_fclose_ FILE *f = NULL;
55 f = fmemopen((void*) pem, pem_size, "r");
56 if (!f)
57 return log_oom_debug();
58
59 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
60 if (!pkey)
60696b22 61 return log_openssl_errors("Failed to parse PEM");
4af788c7
DS
62
63 *ret = TAKE_PTR(pkey);
64
65 return 0;
66}
67
c52a003d
DS
68/* Returns the number of bytes generated by the specified digest algorithm. This can be used only for
69 * fixed-size algorithms, e.g. md5, sha1, sha256, etc. Do not use this for variable-sized digest algorithms,
70 * e.g. shake128. Returns 0 on success, -EOPNOTSUPP if the algorithm is not supported, or < 0 for any other
71 * error. */
72int openssl_digest_size(const char *digest_alg, size_t *ret_digest_size) {
73 assert(digest_alg);
74 assert(ret_digest_size);
75
76#if OPENSSL_VERSION_MAJOR >= 3
77 _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
78#else
79 const EVP_MD *md = EVP_get_digestbyname(digest_alg);
80#endif
81 if (!md)
82 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
83 "Digest algorithm '%s' not supported.", digest_alg);
84
85 size_t digest_size;
86#if OPENSSL_VERSION_MAJOR >= 3
87 digest_size = EVP_MD_get_size(md);
88#else
89 digest_size = EVP_MD_size(md);
90#endif
91 if (digest_size == 0)
92 return log_openssl_errors("Failed to get Digest size");
93
94 *ret_digest_size = digest_size;
95
96 return 0;
97}
98
bed4831c
DS
99/* Calculate the digest hash value for the provided data, using the specified digest algorithm. Returns 0 on
100 * success, -EOPNOTSUPP if the digest algorithm is not supported, or < 0 for any other error. */
101int openssl_digest_many(
102 const char *digest_alg,
103 const struct iovec data[],
104 size_t n_data,
105 void **ret_digest,
106 size_t *ret_digest_size) {
107
108 int r;
109
110 assert(digest_alg);
111 assert(data || n_data == 0);
112 assert(ret_digest);
113 /* ret_digest_size is optional, as caller may already know the digest size */
114
115#if OPENSSL_VERSION_MAJOR >= 3
116 _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
117#else
118 const EVP_MD *md = EVP_get_digestbyname(digest_alg);
119#endif
120 if (!md)
121 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
122 "Digest algorithm '%s' not supported.", digest_alg);
123
124 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = EVP_MD_CTX_new();
125 if (!ctx)
126 return log_openssl_errors("Failed to create new EVP_MD_CTX");
127
128 if (!EVP_DigestInit_ex(ctx, md, NULL))
fcdd21ec 129 return log_openssl_errors("Failed to initialize EVP_MD_CTX");
bed4831c
DS
130
131 for (size_t i = 0; i < n_data; i++)
132 if (!EVP_DigestUpdate(ctx, data[i].iov_base, data[i].iov_len))
133 return log_openssl_errors("Failed to update Digest");
134
135 size_t digest_size;
136 r = openssl_digest_size(digest_alg, &digest_size);
137 if (r < 0)
138 return r;
139
140 _cleanup_free_ void *buf = malloc(digest_size);
141 if (!buf)
142 return log_oom_debug();
143
144 unsigned int size;
145 if (!EVP_DigestFinal_ex(ctx, buf, &size))
146 return log_openssl_errors("Failed to finalize Digest");
147
148 assert(size == digest_size);
149
150 *ret_digest = TAKE_PTR(buf);
151 if (ret_digest_size)
152 *ret_digest_size = size;
153
154 return 0;
155}
156
a95e8fa2
DS
157/* Calculate the HMAC digest hash value for the provided data, using the provided key and specified digest
158 * algorithm. Returns 0 on success, -EOPNOTSUPP if the digest algorithm is not supported, or < 0 for any
159 * other error. */
160int openssl_hmac_many(
161 const char *digest_alg,
162 const void *key,
163 size_t key_size,
164 const struct iovec data[],
165 size_t n_data,
166 void **ret_digest,
167 size_t *ret_digest_size) {
168
169 assert(digest_alg);
170 assert(key);
171 assert(data || n_data == 0);
172 assert(ret_digest);
173 /* ret_digest_size is optional, as caller may already know the digest size */
174
175#if OPENSSL_VERSION_MAJOR >= 3
176 _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
177#else
178 const EVP_MD *md = EVP_get_digestbyname(digest_alg);
179#endif
180 if (!md)
181 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
182 "Digest algorithm '%s' not supported.", digest_alg);
183
184#if OPENSSL_VERSION_MAJOR >= 3
185 _cleanup_(EVP_MAC_freep) EVP_MAC *mac = EVP_MAC_fetch(NULL, "HMAC", NULL);
186 if (!mac)
187 return log_openssl_errors("Failed to create new EVP_MAC");
188
189 _cleanup_(EVP_MAC_CTX_freep) EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac);
190 if (!ctx)
191 return log_openssl_errors("Failed to create new EVP_MAC_CTX");
192
193 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
194 if (!bld)
195 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
196
197 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_MAC_PARAM_DIGEST, (char*) digest_alg, 0))
198 return log_openssl_errors("Failed to set HMAC OSSL_MAC_PARAM_DIGEST");
199
200 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
201 if (!params)
202 return log_openssl_errors("Failed to build HMAC OSSL_PARAM");
203
204 if (!EVP_MAC_init(ctx, key, key_size, params))
fcdd21ec 205 return log_openssl_errors("Failed to initialize EVP_MAC_CTX");
a95e8fa2
DS
206#else
207 _cleanup_(HMAC_CTX_freep) HMAC_CTX *ctx = HMAC_CTX_new();
208 if (!ctx)
209 return log_openssl_errors("Failed to create new HMAC_CTX");
210
211 if (!HMAC_Init_ex(ctx, key, key_size, md, NULL))
212 return log_openssl_errors("Failed to initialize HMAC_CTX");
213#endif
214
215 for (size_t i = 0; i < n_data; i++)
216#if OPENSSL_VERSION_MAJOR >= 3
217 if (!EVP_MAC_update(ctx, data[i].iov_base, data[i].iov_len))
218#else
219 if (!HMAC_Update(ctx, data[i].iov_base, data[i].iov_len))
220#endif
221 return log_openssl_errors("Failed to update HMAC");
222
223 size_t digest_size;
224#if OPENSSL_VERSION_MAJOR >= 3
225 digest_size = EVP_MAC_CTX_get_mac_size(ctx);
226#else
227 digest_size = HMAC_size(ctx);
228#endif
229 if (digest_size == 0)
230 return log_openssl_errors("Failed to get HMAC digest size");
231
232 _cleanup_free_ void *buf = malloc(digest_size);
233 if (!buf)
234 return log_oom_debug();
235
236#if OPENSSL_VERSION_MAJOR >= 3
237 size_t size;
238 if (!EVP_MAC_final(ctx, buf, &size, digest_size))
239#else
240 unsigned int size;
241 if (!HMAC_Final(ctx, buf, &size))
242#endif
243 return log_openssl_errors("Failed to finalize HMAC");
244
245 assert(size == digest_size);
246
247 *ret_digest = TAKE_PTR(buf);
248 if (ret_digest_size)
249 *ret_digest_size = size;
250
251 return 0;
252}
253
58f215a0
DS
254/* Symmetric Cipher encryption using the alg-bits-mode cipher, e.g. AES-128-CFB. The key is required and must
255 * be at least the minimum required key length for the cipher. The IV is optional but, if provided, it must
256 * be at least the minimum iv length for the cipher. If no IV is provided and the cipher requires one, a
257 * buffer of zeroes is used. Returns 0 on success, -EOPNOTSUPP if the cipher algorithm is not supported, or <
258 * 0 on any other error. */
259int openssl_cipher_many(
260 const char *alg,
261 size_t bits,
262 const char *mode,
263 const void *key,
264 size_t key_size,
265 const void *iv,
266 size_t iv_size,
267 const struct iovec data[],
268 size_t n_data,
269 void **ret,
270 size_t *ret_size) {
271
272 assert(alg);
273 assert(bits > 0);
274 assert(mode);
275 assert(key);
276 assert(iv || iv_size == 0);
277 assert(data || n_data == 0);
278 assert(ret);
279 assert(ret_size);
280
281 _cleanup_free_ char *cipher_alg = NULL;
282 if (asprintf(&cipher_alg, "%s-%zu-%s", alg, bits, mode) < 0)
283 return log_oom_debug();
284
285#if OPENSSL_VERSION_MAJOR >= 3
286 _cleanup_(EVP_CIPHER_freep) EVP_CIPHER *cipher = EVP_CIPHER_fetch(NULL, cipher_alg, NULL);
287#else
288 const EVP_CIPHER *cipher = EVP_get_cipherbyname(cipher_alg);
289#endif
290 if (!cipher)
291 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
292 "Cipher algorithm '%s' not supported.", cipher_alg);
293
294 _cleanup_(EVP_CIPHER_CTX_freep) EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
295 if (!ctx)
296 return log_openssl_errors("Failed to create new EVP_CIPHER_CTX");
297
298 /* Verify enough key data was provided. */
299 int cipher_key_length = EVP_CIPHER_key_length(cipher);
300 assert(cipher_key_length >= 0);
301 if ((size_t) cipher_key_length > key_size)
302 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
303 "Not enough key bytes provided, require %d", cipher_key_length);
304
305 /* Verify enough IV data was provided or, if no IV was provided, use a zeroed buffer for IV data. */
306 int cipher_iv_length = EVP_CIPHER_iv_length(cipher);
307 assert(cipher_iv_length >= 0);
308 _cleanup_free_ void *zero_iv = NULL;
309 if (iv_size == 0) {
310 zero_iv = malloc0(cipher_iv_length);
311 if (!zero_iv)
312 return log_oom_debug();
313
314 iv = zero_iv;
315 iv_size = (size_t) cipher_iv_length;
316 }
317 if ((size_t) cipher_iv_length > iv_size)
318 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
319 "Not enough IV bytes provided, require %d", cipher_iv_length);
320
321 if (!EVP_EncryptInit(ctx, cipher, key, iv))
322 return log_openssl_errors("Failed to initialize EVP_CIPHER_CTX.");
323
324 int cipher_block_size = EVP_CIPHER_CTX_block_size(ctx);
325 assert(cipher_block_size > 0);
326
327 _cleanup_free_ uint8_t *buf = NULL;
328 size_t size = 0;
329
330 for (size_t i = 0; i < n_data; i++) {
331 /* Cipher may produce (up to) input length + cipher block size of output. */
332 if (!GREEDY_REALLOC(buf, size + data[i].iov_len + cipher_block_size))
333 return log_oom_debug();
334
335 int update_size;
336 if (!EVP_EncryptUpdate(ctx, &buf[size], &update_size, data[i].iov_base, data[i].iov_len))
337 return log_openssl_errors("Failed to update Cipher.");
338
339 size += update_size;
340 }
341
342 if (!GREEDY_REALLOC(buf, size + cipher_block_size))
343 return log_oom_debug();
344
345 int final_size;
346 if (!EVP_EncryptFinal_ex(ctx, &buf[size], &final_size))
347 return log_openssl_errors("Failed to finalize Cipher.");
348
349 *ret = TAKE_PTR(buf);
350 *ret_size = size + final_size;
351
352 return 0;
353}
354
8c2205bb
DS
355/* Perform Single-Step (aka "Concat") KDF. Currently, this only supports using the digest for the auxiliary
356 * function. The derive_size parameter specifies how many bytes are derived.
357 *
358 * For more details see: https://www.openssl.org/docs/manmaster/man7/EVP_KDF-SS.html */
359int kdf_ss_derive(
360 const char *digest,
361 const void *key,
362 size_t key_size,
363 const void *salt,
364 size_t salt_size,
365 const void *info,
366 size_t info_size,
367 size_t derive_size,
368 void **ret) {
369
370#if OPENSSL_VERSION_MAJOR >= 3
371 assert(digest);
372 assert(key);
373 assert(derive_size > 0);
374 assert(ret);
375
376 _cleanup_(EVP_KDF_freep) EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSKDF", NULL);
377 if (!kdf)
378 return log_openssl_errors("Failed to create new EVP_KDF");
379
380 _cleanup_(EVP_KDF_CTX_freep) EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
381 if (!ctx)
382 return log_openssl_errors("Failed to create new EVP_KDF_CTX");
383
384 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
385 if (!bld)
386 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
387
388 _cleanup_free_ void *buf = malloc(derive_size);
389 if (!buf)
390 return log_oom_debug();
391
392 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_DIGEST, (char*) digest, 0))
393 return log_openssl_errors("Failed to add KDF-SS OSSL_KDF_PARAM_DIGEST");
394
395 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_KEY, (char*) key, key_size))
396 return log_openssl_errors("Failed to add KDF-SS OSSL_KDF_PARAM_KEY");
397
398 if (salt)
399 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_SALT, (char*) salt, salt_size))
400 return log_openssl_errors("Failed to add KDF-SS OSSL_KDF_PARAM_SALT");
401
402 if (info)
403 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_INFO, (char*) info, info_size))
404 return log_openssl_errors("Failed to add KDF-SS OSSL_KDF_PARAM_INFO");
405
406 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
407 if (!params)
408 return log_openssl_errors("Failed to build KDF-SS OSSL_PARAM");
409
410 if (EVP_KDF_derive(ctx, buf, derive_size, params) <= 0)
968d232d 411 return log_openssl_errors("OpenSSL KDF-SS derive failed");
8c2205bb
DS
412
413 *ret = TAKE_PTR(buf);
414
415 return 0;
416#else
968d232d 417 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "KDF-SS requires OpenSSL >= 3.");
8c2205bb
DS
418#endif
419}
420
a65a25be 421/* Perform Key-Based HMAC KDF. The mode must be "COUNTER" or "FEEDBACK". The parameter naming is from the
968d232d 422 * OpenSSL api, and maps to SP800-108 naming as "...key, salt, info, and seed correspond to KI, Label,
a65a25be
DS
423 * Context, and IV (respectively)...". The derive_size parameter specifies how many bytes are derived.
424 *
425 * For more details see: https://www.openssl.org/docs/manmaster/man7/EVP_KDF-KB.html */
426int kdf_kb_hmac_derive(
427 const char *mode,
428 const char *digest,
429 const void *key,
430 size_t key_size,
431 const void *salt,
432 size_t salt_size,
433 const void *info,
434 size_t info_size,
435 const void *seed,
436 size_t seed_size,
437 size_t derive_size,
438 void **ret) {
439
440#if OPENSSL_VERSION_MAJOR >= 3
441 assert(mode);
442 assert(strcaseeq(mode, "COUNTER") || strcaseeq(mode, "FEEDBACK"));
443 assert(digest);
444 assert(key || key_size == 0);
445 assert(salt || salt_size == 0);
446 assert(info || info_size == 0);
447 assert(seed || seed_size == 0);
448 assert(derive_size > 0);
449 assert(ret);
450
451 _cleanup_(EVP_KDF_freep) EVP_KDF *kdf = EVP_KDF_fetch(NULL, "KBKDF", NULL);
452 if (!kdf)
453 return log_openssl_errors("Failed to create new EVP_KDF");
454
455 _cleanup_(EVP_KDF_CTX_freep) EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf);
456 if (!ctx)
457 return log_openssl_errors("Failed to create new EVP_KDF_CTX");
458
459 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
460 if (!bld)
461 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
462
463 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_MAC, (char*) "HMAC", 0))
464 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_MAC");
465
466 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_MODE, (char*) mode, 0))
467 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_MODE");
468
469 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_KDF_PARAM_DIGEST, (char*) digest, 0))
470 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_DIGEST");
471
472 if (key)
473 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_KEY, (char*) key, key_size))
474 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_KEY");
475
476 if (salt)
477 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_SALT, (char*) salt, salt_size))
478 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_SALT");
479
480 if (info)
481 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_INFO, (char*) info, info_size))
482 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_INFO");
483
484 if (seed)
485 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_KDF_PARAM_SEED, (char*) seed, seed_size))
486 return log_openssl_errors("Failed to add KDF-KB OSSL_KDF_PARAM_SEED");
487
488 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
489 if (!params)
490 return log_openssl_errors("Failed to build KDF-KB OSSL_PARAM");
491
492 _cleanup_free_ void *buf = malloc(derive_size);
493 if (!buf)
494 return log_oom_debug();
495
496 if (EVP_KDF_derive(ctx, buf, derive_size, params) <= 0)
968d232d 497 return log_openssl_errors("OpenSSL KDF-KB derive failed");
a65a25be
DS
498
499 *ret = TAKE_PTR(buf);
500
501 return 0;
502#else
968d232d 503 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "KDF-KB requires OpenSSL >= 3.");
a65a25be
DS
504#endif
505}
506
f2d5df8a
LP
507int rsa_encrypt_bytes(
508 EVP_PKEY *pkey,
509 const void *decrypted_key,
510 size_t decrypted_key_size,
511 void **ret_encrypt_key,
512 size_t *ret_encrypt_key_size) {
513
514 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL;
515 _cleanup_free_ void *b = NULL;
516 size_t l;
517
518 ctx = EVP_PKEY_CTX_new(pkey, NULL);
519 if (!ctx)
60696b22 520 return log_openssl_errors("Failed to allocate public key context");
f2d5df8a
LP
521
522 if (EVP_PKEY_encrypt_init(ctx) <= 0)
60696b22 523 return log_openssl_errors("Failed to initialize public key context");
f2d5df8a
LP
524
525 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
60696b22 526 return log_openssl_errors("Failed to configure PKCS#1 padding");
f2d5df8a
LP
527
528 if (EVP_PKEY_encrypt(ctx, NULL, &l, decrypted_key, decrypted_key_size) <= 0)
60696b22 529 return log_openssl_errors("Failed to determine encrypted key size");
f2d5df8a
LP
530
531 b = malloc(l);
532 if (!b)
533 return -ENOMEM;
534
535 if (EVP_PKEY_encrypt(ctx, b, &l, decrypted_key, decrypted_key_size) <= 0)
60696b22 536 return log_openssl_errors("Failed to determine encrypted key size");
f2d5df8a
LP
537
538 *ret_encrypt_key = TAKE_PTR(b);
539 *ret_encrypt_key_size = l;
f2d5df8a
LP
540 return 0;
541}
d041e4fc 542
816b1dc4
DS
543/* Encrypt the key data using RSA-OAEP with the provided label and specified digest algorithm. Returns 0 on
544 * success, -EOPNOTSUPP if the digest algorithm is not supported, or < 0 for any other error. */
545int rsa_oaep_encrypt_bytes(
546 const EVP_PKEY *pkey,
547 const char *digest_alg,
548 const char *label,
549 const void *decrypted_key,
550 size_t decrypted_key_size,
551 void **ret_encrypt_key,
552 size_t *ret_encrypt_key_size) {
553
554 assert(pkey);
555 assert(digest_alg);
556 assert(label);
557 assert(decrypted_key);
558 assert(decrypted_key_size > 0);
559 assert(ret_encrypt_key);
560 assert(ret_encrypt_key_size);
561
562#if OPENSSL_VERSION_MAJOR >= 3
563 _cleanup_(EVP_MD_freep) EVP_MD *md = EVP_MD_fetch(NULL, digest_alg, NULL);
564#else
565 const EVP_MD *md = EVP_get_digestbyname(digest_alg);
566#endif
567 if (!md)
568 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
569 "Digest algorithm '%s' not supported.", digest_alg);
570
571 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new((EVP_PKEY*) pkey, NULL);
572 if (!ctx)
573 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
574
575 if (EVP_PKEY_encrypt_init(ctx) <= 0)
576 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
577
578 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
579 return log_openssl_errors("Failed to configure RSA-OAEP padding");
580
581 if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0)
582 return log_openssl_errors("Failed to configure RSA-OAEP MD");
583
584 _cleanup_free_ char *duplabel = strdup(label);
585 if (!duplabel)
586 return log_oom_debug();
587
588 if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, duplabel, strlen(duplabel) + 1) <= 0)
589 return log_openssl_errors("Failed to configure RSA-OAEP label");
590 /* ctx owns this now, don't free */
591 TAKE_PTR(duplabel);
592
593 size_t size = 0;
594 if (EVP_PKEY_encrypt(ctx, NULL, &size, decrypted_key, decrypted_key_size) <= 0)
595 return log_openssl_errors("Failed to determine RSA-OAEP encrypted key size");
596
597 _cleanup_free_ void *buf = malloc(size);
598 if (!buf)
599 return log_oom_debug();
600
601 if (EVP_PKEY_encrypt(ctx, buf, &size, decrypted_key, decrypted_key_size) <= 0)
602 return log_openssl_errors("Failed to RSA-OAEP encrypt");
603
604 *ret_encrypt_key = TAKE_PTR(buf);
605 *ret_encrypt_key_size = size;
606
607 return 0;
608}
609
d041e4fc
LP
610int rsa_pkey_to_suitable_key_size(
611 EVP_PKEY *pkey,
612 size_t *ret_suitable_key_size) {
613
614 size_t suitable_key_size;
d041e4fc
LP
615 int bits;
616
2e64df07
YW
617 assert(pkey);
618 assert(ret_suitable_key_size);
d041e4fc
LP
619
620 /* Analyzes the specified public key and that it is RSA. If so, will return a suitable size for a
621 * disk encryption key to encrypt with RSA for use in PKCS#11 security token schemes. */
622
623 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA)
624 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "X.509 certificate does not refer to RSA key.");
625
7f12adc3 626 bits = EVP_PKEY_bits(pkey);
d041e4fc
LP
627 log_debug("Bits in RSA key: %i", bits);
628
629 /* We use PKCS#1 padding for the RSA cleartext, hence let's leave some extra space for it, hence only
630 * generate a random key half the size of the RSA length */
631 suitable_key_size = bits / 8 / 2;
632
633 if (suitable_key_size < 1)
634 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Uh, RSA key size too short?");
635
636 *ret_suitable_key_size = suitable_key_size;
637 return 0;
638}
7e8facb3 639
85686b37
VS
640/* Generate RSA public key from provided "n" and "e" values. Numbers "n" and "e" must be provided here
641 * in big-endian format, e.g. wrap it with htobe32() for uint32_t. */
dcec950c
DS
642int rsa_pkey_from_n_e(const void *n, size_t n_size, const void *e, size_t e_size, EVP_PKEY **ret) {
643 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
644
645 assert(n);
85686b37 646 assert(n_size != 0);
dcec950c 647 assert(e);
85686b37 648 assert(e_size != 0);
dcec950c
DS
649 assert(ret);
650
85686b37
VS
651#if OPENSSL_VERSION_MAJOR >= 3
652 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
dcec950c 653 if (!ctx)
60696b22 654 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
dcec950c 655
dcec950c 656 if (EVP_PKEY_fromdata_init(ctx) <= 0)
60696b22 657 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
dcec950c 658
85686b37 659 OSSL_PARAM params[3];
dcec950c 660
85686b37
VS
661#if __BYTE_ORDER == __BIG_ENDIAN
662 params[0] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_N, (void*)n, n_size);
663 params[1] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, (void*)e, e_size);
664#else
665 _cleanup_free_ void *native_n = memdup_reverse(n, n_size);
666 if (!native_n)
667 return log_oom_debug();
dcec950c 668
85686b37
VS
669 _cleanup_free_ void *native_e = memdup_reverse(e, e_size);
670 if (!native_e)
671 return log_oom_debug();
dcec950c 672
85686b37
VS
673 params[0] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_N, native_n, n_size);
674 params[1] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, native_e, e_size);
675#endif
676 params[2] = OSSL_PARAM_construct_end();
dcec950c
DS
677
678 if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
60696b22 679 return log_openssl_errors("Failed to create RSA EVP_PKEY");
dcec950c 680#else
85686b37
VS
681 _cleanup_(BN_freep) BIGNUM *bn_n = BN_bin2bn(n, n_size, NULL);
682 if (!bn_n)
683 return log_openssl_errors("Failed to create BIGNUM for RSA n");
684
685 _cleanup_(BN_freep) BIGNUM *bn_e = BN_bin2bn(e, e_size, NULL);
686 if (!bn_e)
687 return log_openssl_errors("Failed to create BIGNUM for RSA e");
688
dcec950c
DS
689 _cleanup_(RSA_freep) RSA *rsa_key = RSA_new();
690 if (!rsa_key)
60696b22 691 return log_openssl_errors("Failed to create new RSA");
dcec950c
DS
692
693 if (!RSA_set0_key(rsa_key, bn_n, bn_e, NULL))
60696b22 694 return log_openssl_errors("Failed to set RSA n/e");
dcec950c
DS
695 /* rsa_key owns these now, don't free */
696 TAKE_PTR(bn_n);
697 TAKE_PTR(bn_e);
698
699 pkey = EVP_PKEY_new();
700 if (!pkey)
60696b22 701 return log_openssl_errors("Failed to create new EVP_PKEY");
dcec950c
DS
702
703 if (!EVP_PKEY_assign_RSA(pkey, rsa_key))
60696b22 704 return log_openssl_errors("Failed to assign RSA key");
dcec950c
DS
705 /* pkey owns this now, don't free */
706 TAKE_PTR(rsa_key);
707#endif
708
709 *ret = TAKE_PTR(pkey);
710
711 return 0;
712}
713
714/* Get the "n" and "e" values from the pkey. The values are returned in "bin" format, i.e. BN_bn2bin(). */
715int rsa_pkey_to_n_e(
716 const EVP_PKEY *pkey,
717 void **ret_n,
718 size_t *ret_n_size,
719 void **ret_e,
720 size_t *ret_e_size) {
721
722 assert(pkey);
723 assert(ret_n);
724 assert(ret_n_size);
725 assert(ret_e);
726 assert(ret_e_size);
727
728#if OPENSSL_VERSION_MAJOR >= 3
729 _cleanup_(BN_freep) BIGNUM *bn_n = NULL;
730 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn_n))
60696b22 731 return log_openssl_errors("Failed to get RSA n");
dcec950c
DS
732
733 _cleanup_(BN_freep) BIGNUM *bn_e = NULL;
734 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn_e))
60696b22 735 return log_openssl_errors("Failed to get RSA e");
dcec950c
DS
736#else
737 const RSA *rsa = EVP_PKEY_get0_RSA((EVP_PKEY*) pkey);
738 if (!rsa)
60696b22 739 return log_openssl_errors("Failed to get RSA key from public key");
dcec950c
DS
740
741 const BIGNUM *bn_n = RSA_get0_n(rsa);
742 if (!bn_n)
60696b22 743 return log_openssl_errors("Failed to get RSA n");
dcec950c
DS
744
745 const BIGNUM *bn_e = RSA_get0_e(rsa);
746 if (!bn_e)
60696b22 747 return log_openssl_errors("Failed to get RSA e");
dcec950c
DS
748#endif
749
750 size_t n_size = BN_num_bytes(bn_n), e_size = BN_num_bytes(bn_e);
751 _cleanup_free_ void *n = malloc(n_size), *e = malloc(e_size);
752 if (!n || !e)
753 return log_oom_debug();
754
755 assert(BN_bn2bin(bn_n, n) == (int) n_size);
756 assert(BN_bn2bin(bn_e, e) == (int) e_size);
757
758 *ret_n = TAKE_PTR(n);
759 *ret_n_size = n_size;
760 *ret_e = TAKE_PTR(e);
761 *ret_e_size = e_size;
762
763 return 0;
764}
765
766/* Generate a new RSA key with the specified number of bits. */
767int rsa_pkey_new(size_t bits, EVP_PKEY **ret) {
768 assert(ret);
769
770 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
771 if (!ctx)
60696b22 772 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
dcec950c
DS
773
774 if (EVP_PKEY_keygen_init(ctx) <= 0)
60696b22 775 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
dcec950c
DS
776
777 if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int) bits) <= 0)
60696b22 778 return log_openssl_errors("Failed to set RSA bits to %zu", bits);
dcec950c
DS
779
780 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
781 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
60696b22 782 return log_openssl_errors("Failed to generate ECC key");
dcec950c
DS
783
784 *ret = TAKE_PTR(pkey);
785
786 return 0;
787}
788
900e73f8
DS
789/* Generate ECC public key from provided curve ID and x/y points. */
790int ecc_pkey_from_curve_x_y(
791 int curve_id,
792 const void *x,
793 size_t x_size,
794 const void *y,
795 size_t y_size,
796 EVP_PKEY **ret) {
797
798 assert(x);
799 assert(y);
800 assert(ret);
801
802 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
803 if (!ctx)
60696b22 804 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
900e73f8 805
60696b22
DS
806 _cleanup_(BN_freep) BIGNUM *bn_x = BN_bin2bn(x, x_size, NULL);
807 if (!bn_x)
808 return log_openssl_errors("Failed to create BIGNUM x");
809
810 _cleanup_(BN_freep) BIGNUM *bn_y = BN_bin2bn(y, y_size, NULL);
811 if (!bn_y)
812 return log_openssl_errors("Failed to create BIGNUM y");
900e73f8
DS
813
814 _cleanup_(EC_GROUP_freep) EC_GROUP *group = EC_GROUP_new_by_curve_name(curve_id);
815 if (!group)
60696b22 816 return log_openssl_errors("ECC curve id %d not supported", curve_id);
900e73f8
DS
817
818 _cleanup_(EC_POINT_freep) EC_POINT *point = EC_POINT_new(group);
819 if (!point)
60696b22 820 return log_openssl_errors("Failed to create new EC_POINT");
900e73f8
DS
821
822 if (!EC_POINT_set_affine_coordinates(group, point, bn_x, bn_y, NULL))
60696b22 823 return log_openssl_errors("Failed to set ECC coordinates");
900e73f8
DS
824
825#if OPENSSL_VERSION_MAJOR >= 3
826 if (EVP_PKEY_fromdata_init(ctx) <= 0)
60696b22 827 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
900e73f8
DS
828
829 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
830 if (!bld)
60696b22 831 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
900e73f8
DS
832
833 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, (char*) OSSL_EC_curve_nid2name(curve_id), 0))
60696b22 834 return log_openssl_errors("Failed to add ECC OSSL_PKEY_PARAM_GROUP_NAME");
900e73f8
DS
835
836 _cleanup_(OPENSSL_freep) void *pbuf = NULL;
837 size_t pbuf_len = 0;
838 pbuf_len = EC_POINT_point2buf(group, point, POINT_CONVERSION_UNCOMPRESSED, (unsigned char**) &pbuf, NULL);
839 if (pbuf_len == 0)
60696b22 840 return log_openssl_errors("Failed to convert ECC point to buffer");
900e73f8
DS
841
842 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pbuf, pbuf_len))
60696b22 843 return log_openssl_errors("Failed to add ECC OSSL_PKEY_PARAM_PUB_KEY");
900e73f8
DS
844
845 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
846 if (!params)
60696b22 847 return log_openssl_errors("Failed to build ECC OSSL_PARAM");
900e73f8
DS
848
849 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
850 if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
60696b22 851 return log_openssl_errors("Failed to create ECC EVP_PKEY");
900e73f8
DS
852#else
853 _cleanup_(EC_KEY_freep) EC_KEY *eckey = EC_KEY_new();
854 if (!eckey)
60696b22 855 return log_openssl_errors("Failed to create new EC_KEY");
900e73f8
DS
856
857 if (!EC_KEY_set_group(eckey, group))
60696b22 858 return log_openssl_errors("Failed to set ECC group");
900e73f8
DS
859
860 if (!EC_KEY_set_public_key(eckey, point))
60696b22 861 return log_openssl_errors("Failed to set ECC point");
900e73f8
DS
862
863 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = EVP_PKEY_new();
864 if (!pkey)
60696b22 865 return log_openssl_errors("Failed to create new EVP_PKEY");
900e73f8
DS
866
867 if (!EVP_PKEY_assign_EC_KEY(pkey, eckey))
60696b22 868 return log_openssl_errors("Failed to assign ECC key");
900e73f8
DS
869 /* pkey owns this now, don't free */
870 TAKE_PTR(eckey);
871#endif
872
873 *ret = TAKE_PTR(pkey);
874
875 return 0;
876}
877
878int ecc_pkey_to_curve_x_y(
879 const EVP_PKEY *pkey,
880 int *ret_curve_id,
881 void **ret_x,
882 size_t *ret_x_size,
883 void **ret_y,
884 size_t *ret_y_size) {
885
886 _cleanup_(BN_freep) BIGNUM *bn_x = NULL, *bn_y = NULL;
887 int curve_id;
888
889 assert(pkey);
890
891#if OPENSSL_VERSION_MAJOR >= 3
892 size_t name_size;
893 if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0, &name_size))
60696b22 894 return log_openssl_errors("Failed to get ECC group name size");
900e73f8 895
b0307102 896 _cleanup_free_ char *name = new(char, name_size + 1);
900e73f8
DS
897 if (!name)
898 return log_oom_debug();
899
900 if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, name, name_size + 1, NULL))
60696b22 901 return log_openssl_errors("Failed to get ECC group name");
900e73f8
DS
902
903 curve_id = OBJ_sn2nid(name);
904 if (curve_id == NID_undef)
60696b22 905 return log_openssl_errors("Failed to get ECC curve id");
900e73f8
DS
906
907 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &bn_x))
60696b22 908 return log_openssl_errors("Failed to get ECC point x");
900e73f8
DS
909
910 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &bn_y))
60696b22 911 return log_openssl_errors("Failed to get ECC point y");
900e73f8
DS
912#else
913 const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY*) pkey);
914 if (!eckey)
60696b22 915 return log_openssl_errors("Failed to get EC_KEY");
900e73f8
DS
916
917 const EC_GROUP *group = EC_KEY_get0_group(eckey);
918 if (!group)
60696b22 919 return log_openssl_errors("Failed to get EC_GROUP");
900e73f8
DS
920
921 curve_id = EC_GROUP_get_curve_name(group);
922 if (curve_id == NID_undef)
60696b22 923 return log_openssl_errors("Failed to get ECC curve id");
900e73f8
DS
924
925 const EC_POINT *point = EC_KEY_get0_public_key(eckey);
926 if (!point)
60696b22 927 return log_openssl_errors("Failed to get EC_POINT");
900e73f8
DS
928
929 bn_x = BN_new();
930 bn_y = BN_new();
931 if (!bn_x || !bn_y)
60696b22 932 return log_openssl_errors("Failed to create new BIGNUM");
900e73f8
DS
933
934 if (!EC_POINT_get_affine_coordinates(group, point, bn_x, bn_y, NULL))
60696b22 935 return log_openssl_errors("Failed to get ECC x/y.");
900e73f8
DS
936#endif
937
938 size_t x_size = BN_num_bytes(bn_x), y_size = BN_num_bytes(bn_y);
939 _cleanup_free_ void *x = malloc(x_size), *y = malloc(y_size);
940 if (!x || !y)
941 return log_oom_debug();
942
943 assert(BN_bn2bin(bn_x, x) == (int) x_size);
944 assert(BN_bn2bin(bn_y, y) == (int) y_size);
945
946 if (ret_curve_id)
947 *ret_curve_id = curve_id;
948 if (ret_x)
949 *ret_x = TAKE_PTR(x);
950 if (ret_x_size)
951 *ret_x_size = x_size;
952 if (ret_y)
953 *ret_y = TAKE_PTR(y);
954 if (ret_y_size)
955 *ret_y_size = y_size;
956
957 return 0;
958}
959
960/* Generate a new ECC key for the specified ECC curve id. */
961int ecc_pkey_new(int curve_id, EVP_PKEY **ret) {
962 assert(ret);
963
964 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
965 if (!ctx)
60696b22 966 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
900e73f8
DS
967
968 if (EVP_PKEY_keygen_init(ctx) <= 0)
60696b22 969 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
900e73f8
DS
970
971 if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_id) <= 0)
60696b22 972 return log_openssl_errors("Failed to set ECC curve %d", curve_id);
900e73f8
DS
973
974 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
975 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
60696b22 976 return log_openssl_errors("Failed to generate ECC key");
900e73f8
DS
977
978 *ret = TAKE_PTR(pkey);
979
980 return 0;
981}
982
779b80d8
DS
983/* Perform ECDH to derive an ECC shared secret between the provided private key and public peer key. For two
984 * keys, this will result in the same shared secret in either direction; ECDH using Alice's private key and
985 * Bob's public (peer) key will result in the same shared secret as ECDH using Bob's private key and Alice's
986 * public (peer) key. On success, this returns 0 and provides the shared secret; otherwise this returns an
987 * error. */
988int ecc_ecdh(const EVP_PKEY *private_pkey,
989 const EVP_PKEY *peer_pkey,
990 void **ret_shared_secret,
991 size_t *ret_shared_secret_size) {
992
993 assert(private_pkey);
994 assert(peer_pkey);
995 assert(ret_shared_secret);
996 assert(ret_shared_secret_size);
997
998 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new((EVP_PKEY*) private_pkey, NULL);
999 if (!ctx)
1000 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
1001
1002 if (EVP_PKEY_derive_init(ctx) <= 0)
1003 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
1004
1005 if (EVP_PKEY_derive_set_peer(ctx, (EVP_PKEY*) peer_pkey) <= 0)
1006 return log_openssl_errors("Failed to set ECC derive peer");
1007
1008 size_t shared_secret_size;
1009 if (EVP_PKEY_derive(ctx, NULL, &shared_secret_size) <= 0)
1010 return log_openssl_errors("Failed to get ECC shared secret size");
1011
3d05c058 1012 _cleanup_(erase_and_freep) void *shared_secret = malloc(shared_secret_size);
779b80d8
DS
1013 if (!shared_secret)
1014 return log_oom_debug();
1015
1016 if (EVP_PKEY_derive(ctx, (unsigned char*) shared_secret, &shared_secret_size) <= 0)
1017 return log_openssl_errors("Failed to derive ECC shared secret");
1018
1019 *ret_shared_secret = TAKE_PTR(shared_secret);
1020 *ret_shared_secret_size = shared_secret_size;
1021
1022 return 0;
1023}
1024
e8ccb5c7
LP
1025int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size) {
1026 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* m = NULL;
1027 _cleanup_free_ void *d = NULL, *h = NULL;
1028 int sz, lsz, msz;
1029 unsigned umsz;
1030 unsigned char *dd;
1031
1032 /* Calculates a message digest of the DER encoded public key */
1033
1034 assert(pk);
1035 assert(md);
1036 assert(ret);
1037 assert(ret_size);
1038
1039 sz = i2d_PublicKey(pk, NULL);
1040 if (sz < 0)
60696b22 1041 return log_openssl_errors("Unable to convert public key to DER format");
e8ccb5c7
LP
1042
1043 dd = d = malloc(sz);
1044 if (!d)
1045 return log_oom_debug();
1046
1047 lsz = i2d_PublicKey(pk, &dd);
1048 if (lsz < 0)
60696b22 1049 return log_openssl_errors("Unable to convert public key to DER format");
e8ccb5c7
LP
1050
1051 m = EVP_MD_CTX_new();
1052 if (!m)
60696b22 1053 return log_openssl_errors("Failed to create new EVP_MD_CTX");
e8ccb5c7
LP
1054
1055 if (EVP_DigestInit_ex(m, md, NULL) != 1)
60696b22 1056 return log_openssl_errors("Failed to initialize %s context", EVP_MD_name(md));
e8ccb5c7
LP
1057
1058 if (EVP_DigestUpdate(m, d, lsz) != 1)
60696b22 1059 return log_openssl_errors("Failed to run %s context", EVP_MD_name(md));
e8ccb5c7
LP
1060
1061 msz = EVP_MD_size(md);
2e64df07 1062 assert(msz > 0);
e8ccb5c7
LP
1063
1064 h = malloc(msz);
1065 if (!h)
1066 return log_oom_debug();
1067
1068 umsz = msz;
1069 if (EVP_DigestFinal_ex(m, h, &umsz) != 1)
60696b22 1070 return log_openssl_errors("Failed to finalize hash context");
e8ccb5c7 1071
2e64df07 1072 assert(umsz == (unsigned) msz);
e8ccb5c7
LP
1073
1074 *ret = TAKE_PTR(h);
1075 *ret_size = msz;
1076
1077 return 0;
1078}
1079
ef65c0f6
LP
1080int digest_and_sign(
1081 const EVP_MD *md,
1082 EVP_PKEY *privkey,
1083 const void *data, size_t size,
1084 void **ret, size_t *ret_size) {
1085
1086 assert(privkey);
1087 assert(ret);
1088 assert(ret_size);
1089
1090 if (size == 0)
1091 data = ""; /* make sure to pass a valid pointer to OpenSSL */
1092 else {
1093 assert(data);
1094
1095 if (size == SIZE_MAX) /* If SIZE_MAX input is a string whose size we determine automatically */
1096 size = strlen(data);
1097 }
1098
1099 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
1100 if (!mdctx)
1101 return log_openssl_errors("Failed to create new EVP_MD_CTX");
1102
1103 if (EVP_DigestSignInit(mdctx, NULL, md, NULL, privkey) != 1)
1104 return log_openssl_errors("Failed to initialize signature context");
1105
1106 /* Determine signature size */
1107 size_t ss;
1108 if (EVP_DigestSign(mdctx, NULL, &ss, data, size) != 1)
1109 return log_openssl_errors("Failed to determine size of signature");
1110
1111 _cleanup_free_ void *sig = malloc(ss);
1112 if (!sig)
1113 return log_oom_debug();
1114
1115 if (EVP_DigestSign(mdctx, sig, &ss, data, size) != 1)
1116 return log_openssl_errors("Failed to sign data");
1117
1118 *ret = TAKE_PTR(sig);
1119 *ret_size = ss;
1120 return 0;
1121}
1122
7e8facb3
ZJS
1123# if PREFER_OPENSSL
1124int string_hashsum(
1125 const char *s,
1126 size_t len,
11f7bc5e 1127 const char *md_algorithm,
7e8facb3
ZJS
1128 char **ret) {
1129
11f7bc5e 1130 _cleanup_free_ void *hash = NULL;
7e8facb3 1131 size_t hash_size;
38e1035b 1132 _cleanup_free_ char *enc = NULL;
7e8facb3
ZJS
1133 int r;
1134
11f7bc5e
DS
1135 assert(s || len == 0);
1136 assert(md_algorithm);
1137 assert(ret);
7e8facb3 1138
11f7bc5e 1139 r = openssl_digest(md_algorithm, s, len, &hash, &hash_size);
7e8facb3
ZJS
1140 if (r < 0)
1141 return r;
1142
1143 enc = hexmem(hash, hash_size);
1144 if (!enc)
1145 return -ENOMEM;
1146
11f7bc5e 1147 *ret = TAKE_PTR(enc);
7e8facb3 1148 return 0;
7e8facb3
ZJS
1149}
1150# endif
876206f2 1151
3d05c058
VS
1152static int ecc_pkey_generate_volume_keys(
1153 EVP_PKEY *pkey,
1154 void **ret_decrypted_key,
1155 size_t *ret_decrypted_key_size,
1156 void **ret_saved_key,
1157 size_t *ret_saved_key_size) {
1158
1159 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_new = NULL;
1160 _cleanup_(erase_and_freep) void *decrypted_key = NULL;
1161 _cleanup_free_ unsigned char *saved_key = NULL;
1162 size_t decrypted_key_size, saved_key_size;
1163 int nid = NID_undef;
1164 int r;
1165
1166#if OPENSSL_VERSION_MAJOR >= 3
1167 _cleanup_free_ char *curve_name = NULL;
1168 size_t len = 0;
1169
1170 if (EVP_PKEY_get_group_name(pkey, NULL, 0, &len) != 1 || len == 0)
1171 return log_openssl_errors("Failed to determine PKEY group name length");
1172
1173 len++;
1174 curve_name = new(char, len);
1175 if (!curve_name)
1176 return log_oom_debug();
1177
1178 if (EVP_PKEY_get_group_name(pkey, curve_name, len, &len) != 1)
1179 return log_openssl_errors("Failed to get PKEY group name");
1180
1181 nid = OBJ_sn2nid(curve_name);
1182#else
1183 EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
1184 if (!ec_key)
1185 return log_openssl_errors("PKEY doesn't have EC_KEY associated");
1186
1187 if (EC_KEY_check_key(ec_key) != 1)
1188 return log_openssl_errors("EC_KEY associated with PKEY is not valid");
1189
1190 nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
1191#endif
1192
1193 r = ecc_pkey_new(nid, &pkey_new);
1194 if (r < 0)
1195 return log_debug_errno(r, "Failed to generate a new EC keypair: %m");
1196
1197 r = ecc_ecdh(pkey_new, pkey, &decrypted_key, &decrypted_key_size);
1198 if (r < 0)
1199 return log_debug_errno(r, "Failed to derive shared secret: %m");
1200
1201#if OPENSSL_VERSION_MAJOR >= 3
1202 /* EVP_PKEY_get1_encoded_public_key() always returns uncompressed format of EC points.
1203 See https://github.com/openssl/openssl/discussions/22835 */
1204 saved_key_size = EVP_PKEY_get1_encoded_public_key(pkey_new, &saved_key);
1205 if (saved_key_size == 0)
1206 return log_openssl_errors("Failed to convert the generated public key to SEC1 format");
1207#else
1208 EC_KEY *ec_key_new = EVP_PKEY_get0_EC_KEY(pkey_new);
1209 if (!ec_key_new)
1210 return log_openssl_errors("The generated key doesn't have associated EC_KEY");
1211
1212 if (EC_KEY_check_key(ec_key_new) != 1)
1213 return log_openssl_errors("EC_KEY associated with the generated key is not valid");
1214
1215 saved_key_size = EC_POINT_point2oct(EC_KEY_get0_group(ec_key_new),
1216 EC_KEY_get0_public_key(ec_key_new),
1217 POINT_CONVERSION_UNCOMPRESSED,
1218 NULL, 0, NULL);
1219 if (saved_key_size == 0)
1220 return log_openssl_errors("Failed to determine size of the generated public key");
1221
1222 saved_key = malloc(saved_key_size);
1223 if (!saved_key)
1224 return log_oom_debug();
1225
1226 saved_key_size = EC_POINT_point2oct(EC_KEY_get0_group(ec_key_new),
1227 EC_KEY_get0_public_key(ec_key_new),
1228 POINT_CONVERSION_UNCOMPRESSED,
1229 saved_key, saved_key_size, NULL);
1230 if (saved_key_size == 0)
1231 return log_openssl_errors("Failed to convert the generated public key to SEC1 format");
1232#endif
1233
1234 *ret_decrypted_key = TAKE_PTR(decrypted_key);
1235 *ret_decrypted_key_size = decrypted_key_size;
1236 *ret_saved_key = TAKE_PTR(saved_key);
1237 *ret_saved_key_size = saved_key_size;
1238 return 0;
1239}
1240
876206f2
VS
1241static int rsa_pkey_generate_volume_keys(
1242 EVP_PKEY *pkey,
1243 void **ret_decrypted_key,
1244 size_t *ret_decrypted_key_size,
1245 void **ret_saved_key,
1246 size_t *ret_saved_key_size) {
1247
1248 _cleanup_(erase_and_freep) void *decrypted_key = NULL;
1249 _cleanup_free_ void *saved_key = NULL;
1250 size_t decrypted_key_size, saved_key_size;
1251 int r;
1252
1253 r = rsa_pkey_to_suitable_key_size(pkey, &decrypted_key_size);
1254 if (r < 0)
1255 return log_debug_errno(r, "Failed to determine RSA public key size.");
1256
1257 log_debug("Generating %zu bytes random key.", decrypted_key_size);
1258
1259 decrypted_key = malloc(decrypted_key_size);
1260 if (!decrypted_key)
1261 return log_oom_debug();
1262
1263 r = crypto_random_bytes(decrypted_key, decrypted_key_size);
1264 if (r < 0)
1265 return log_debug_errno(r, "Failed to generate random key: %m");
1266
1267 r = rsa_encrypt_bytes(pkey, decrypted_key, decrypted_key_size, &saved_key, &saved_key_size);
1268 if (r < 0)
1269 return log_debug_errno(r, "Failed to encrypt random key: %m");
1270
1271 *ret_decrypted_key = TAKE_PTR(decrypted_key);
1272 *ret_decrypted_key_size = decrypted_key_size;
1273 *ret_saved_key = TAKE_PTR(saved_key);
1274 *ret_saved_key_size = saved_key_size;
1275 return 0;
1276}
1277
85686b37
VS
1278int pkey_generate_volume_keys(
1279 EVP_PKEY *pkey,
876206f2
VS
1280 void **ret_decrypted_key,
1281 size_t *ret_decrypted_key_size,
1282 void **ret_saved_key,
1283 size_t *ret_saved_key_size) {
1284
85686b37 1285 assert(pkey);
876206f2
VS
1286 assert(ret_decrypted_key);
1287 assert(ret_decrypted_key_size);
1288 assert(ret_saved_key);
1289 assert(ret_saved_key_size);
1290
876206f2
VS
1291#if OPENSSL_VERSION_MAJOR >= 3
1292 int type = EVP_PKEY_get_base_id(pkey);
1293#else
1294 int type = EVP_PKEY_base_id(pkey);
1295#endif
1296 switch (type) {
1297
1298 case EVP_PKEY_RSA:
1299 return rsa_pkey_generate_volume_keys(pkey, ret_decrypted_key, ret_decrypted_key_size, ret_saved_key, ret_saved_key_size);
1300
3d05c058
VS
1301 case EVP_PKEY_EC:
1302 return ecc_pkey_generate_volume_keys(pkey, ret_decrypted_key, ret_decrypted_key_size, ret_saved_key, ret_saved_key_size);
1303
876206f2 1304 case NID_undef:
4e494e6a 1305 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine a type of public key.");
876206f2
VS
1306
1307 default:
1308 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unsupported public key type: %s", OBJ_nid2sn(type));
1309 }
1310}
dba0afa1
LB
1311
1312static int load_key_from_provider(const char *provider, const char *private_key_uri, EVP_PKEY **ret) {
1313
1314 assert(provider);
1315 assert(private_key_uri);
1316 assert(ret);
1317
1318#if OPENSSL_VERSION_MAJOR >= 3
1319 /* Load the provider so that this can work without any custom written configuration in /etc/.
1320 * Also load the 'default' as that seems to be the recommendation. */
1321 if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, provider, /* retain_fallbacks= */ true))
1322 return log_openssl_errors("Failed to load OpenSSL provider '%s'", provider);
1323 if (!OSSL_PROVIDER_try_load(/* ctx= */ NULL, "default", /* retain_fallbacks= */ true))
1324 return log_openssl_errors("Failed to load OpenSSL provider 'default'");
1325
1326 _cleanup_(OSSL_STORE_closep) OSSL_STORE_CTX *store = OSSL_STORE_open(
1327 private_key_uri,
1328 /* ui_method= */ NULL,
1329 /* ui_data= */ NULL,
1330 /* post_process= */ NULL,
1331 /* post_process_data= */ NULL);
1332 if (!store)
1333 return log_openssl_errors("Failed to open OpenSSL store via '%s'", private_key_uri);
1334
1335 _cleanup_(OSSL_STORE_INFO_freep) OSSL_STORE_INFO *info = OSSL_STORE_load(store);
1336 if (!info)
1337 return log_openssl_errors("Failed to load OpenSSL store via '%s'", private_key_uri);
1338
1339 _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = OSSL_STORE_INFO_get1_PKEY(info);
1340 if (!private_key)
1341 return log_openssl_errors("Failed to load private key via '%s'", private_key_uri);
1342
1343 *ret = TAKE_PTR(private_key);
1344
1345 return 0;
1346#else
1347 return -EOPNOTSUPP;
1348#endif
1349}
1350
1351static int load_key_from_engine(const char *engine, const char *private_key_uri, EVP_PKEY **ret) {
1352
1353 assert(engine);
1354 assert(private_key_uri);
1355 assert(ret);
1356
81d61d6a 1357#if !defined(OPENSSL_NO_ENGINE) && !defined(OPENSSL_NO_DEPRECATED_3_0)
dba0afa1
LB
1358 DISABLE_WARNING_DEPRECATED_DECLARATIONS;
1359 _cleanup_(ENGINE_freep) ENGINE *e = ENGINE_by_id(engine);
1360 if (!e)
1361 return log_openssl_errors("Failed to load signing engine '%s'", engine);
1362
1363 if (ENGINE_init(e) == 0)
1364 return log_openssl_errors("Failed to initialize signing engine '%s'", engine);
1365
1366 _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = ENGINE_load_private_key(
1367 e,
1368 private_key_uri,
1369 /* ui_method= */ NULL,
1370 /* callback_data= */ NULL);
1371 if (!private_key)
1372 return log_openssl_errors("Failed to load private key from '%s'", private_key_uri);
1373 REENABLE_WARNING;
1374
1375 *ret = TAKE_PTR(private_key);
1376
1377 return 0;
81d61d6a
NL
1378#else
1379 return -EOPNOTSUPP;
1380#endif
dba0afa1
LB
1381}
1382
a73144bb
LB
1383int openssl_load_key_from_token(
1384 KeySourceType private_key_source_type,
1385 const char *private_key_source,
1386 const char *private_key,
1387 EVP_PKEY **ret) {
dba0afa1 1388
a73144bb
LB
1389 assert(IN_SET(private_key_source_type, OPENSSL_KEY_SOURCE_ENGINE, OPENSSL_KEY_SOURCE_PROVIDER));
1390 assert(private_key_source);
1391 assert(private_key);
dba0afa1 1392
a73144bb 1393 switch (private_key_source_type) {
dba0afa1 1394
a73144bb
LB
1395 case OPENSSL_KEY_SOURCE_ENGINE:
1396 return load_key_from_engine(private_key_source, private_key, ret);
1397 case OPENSSL_KEY_SOURCE_PROVIDER:
1398 return load_key_from_provider(private_key_source, private_key, ret);
1399 default:
1400 assert_not_reached();
dba0afa1 1401 }
dba0afa1 1402}
f2d5df8a 1403#endif
8939d335
DDM
1404
1405int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
1406#if HAVE_OPENSSL
1407 _cleanup_free_ uint8_t *der = NULL;
1408 int dersz;
1409
1410 assert(cert);
1411
1412 dersz = i2d_X509(cert, &der);
1413 if (dersz < 0)
60696b22 1414 return log_openssl_errors("Unable to convert PEM certificate to DER format");
8939d335
DDM
1415
1416 sha256_direct(der, dersz, buffer);
1417 return 0;
1418#else
4e494e6a 1419 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "OpenSSL is not supported, cannot calculate X509 fingerprint.");
8939d335
DDM
1420#endif
1421}
a73144bb
LB
1422
1423int parse_openssl_key_source_argument(
1424 const char *argument,
1425 char **private_key_source,
1426 KeySourceType *private_key_source_type) {
1427
1428 KeySourceType type;
1429 const char *e = NULL;
1430 int r;
1431
1432 assert(argument);
1433 assert(private_key_source);
1434 assert(private_key_source_type);
1435
1436 if (streq(argument, "file"))
1437 type = OPENSSL_KEY_SOURCE_FILE;
1438 else if ((e = startswith(argument, "engine:")))
1439 type = OPENSSL_KEY_SOURCE_ENGINE;
1440 else if ((e = startswith(argument, "provider:")))
1441 type = OPENSSL_KEY_SOURCE_PROVIDER;
1442 else
1443 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid private key source '%s'", argument);
1444
1445 r = free_and_strdup_warn(private_key_source, e);
1446 if (r < 0)
1447 return r;
1448
1449 *private_key_source_type = type;
1450
1451 return 0;
1452}