]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/openssl-util.c
openssl: use new(char, size) instead of malloc(size)
[thirdparty/systemd.git] / src / shared / openssl-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "fd-util.h"
4 #include "openssl-util.h"
5 #include "alloc-util.h"
6 #include "hexdecoct.h"
7
8 #if HAVE_OPENSSL
9 /* For each error in the the Openssl thread error queue, log the provided message and the Openssl error
10 * string. If there are no errors in the Openssl thread queue, this logs the message with "No openssl
11 * errors." This logs at level debug. Returns -EIO (or -ENOMEM). */
12 #define log_openssl_errors(fmt, ...) _log_openssl_errors(UNIQ, fmt, ##__VA_ARGS__)
13 #define _log_openssl_errors(u, fmt, ...) \
14 ({ \
15 size_t UNIQ_T(MAX, u) = 512 /* arbitrary, but openssl doc states it must be >= 256 */; \
16 _cleanup_free_ char *UNIQ_T(BUF, u) = malloc(UNIQ_T(MAX, u)); \
17 !UNIQ_T(BUF, u) \
18 ? log_oom_debug() \
19 : __log_openssl_errors(u, UNIQ_T(BUF, u), UNIQ_T(MAX, u), fmt, ##__VA_ARGS__) \
20 ?: log_debug_errno(SYNTHETIC_ERRNO(EIO), fmt ": No openssl errors.", ##__VA_ARGS__); \
21 })
22 #define __log_openssl_errors(u, buf, max, fmt, ...) \
23 ({ \
24 int UNIQ_T(R, u) = 0; \
25 for (;;) { \
26 unsigned long UNIQ_T(E, u) = ERR_get_error(); \
27 if (UNIQ_T(E, u) == 0) \
28 break; \
29 ERR_error_string_n(UNIQ_T(E, u), buf, max); \
30 UNIQ_T(R, u) = log_debug_errno(SYNTHETIC_ERRNO(EIO), fmt ": %s", ##__VA_ARGS__, buf); \
31 } \
32 UNIQ_T(R, u); \
33 })
34
35 int openssl_pkey_from_pem(const void *pem, size_t pem_size, EVP_PKEY **ret) {
36 assert(pem);
37 assert(ret);
38
39 _cleanup_fclose_ FILE *f = NULL;
40 f = fmemopen((void*) pem, pem_size, "r");
41 if (!f)
42 return log_oom_debug();
43
44 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = PEM_read_PUBKEY(f, NULL, NULL, NULL);
45 if (!pkey)
46 return log_openssl_errors("Failed to parse PEM");
47
48 *ret = TAKE_PTR(pkey);
49
50 return 0;
51 }
52
53 int openssl_hash(const EVP_MD *alg,
54 const void *msg,
55 size_t msg_len,
56 uint8_t *ret_hash,
57 size_t *ret_hash_len) {
58
59 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = NULL;
60 unsigned len;
61 int r;
62
63 ctx = EVP_MD_CTX_new();
64 if (!ctx)
65 /* This function just calls OPENSSL_zalloc, so failure
66 * here is almost certainly a failed allocation. */
67 return -ENOMEM;
68
69 /* The documentation claims EVP_DigestInit behaves just like
70 * EVP_DigestInit_ex if passed NULL, except it also calls
71 * EVP_MD_CTX_reset, which deinitializes the context. */
72 r = EVP_DigestInit_ex(ctx, alg, NULL);
73 if (r == 0)
74 return -EIO;
75
76 r = EVP_DigestUpdate(ctx, msg, msg_len);
77 if (r == 0)
78 return -EIO;
79
80 r = EVP_DigestFinal_ex(ctx, ret_hash, &len);
81 if (r == 0)
82 return -EIO;
83
84 if (ret_hash_len)
85 *ret_hash_len = len;
86
87 return 0;
88 }
89
90 int rsa_encrypt_bytes(
91 EVP_PKEY *pkey,
92 const void *decrypted_key,
93 size_t decrypted_key_size,
94 void **ret_encrypt_key,
95 size_t *ret_encrypt_key_size) {
96
97 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL;
98 _cleanup_free_ void *b = NULL;
99 size_t l;
100
101 ctx = EVP_PKEY_CTX_new(pkey, NULL);
102 if (!ctx)
103 return log_openssl_errors("Failed to allocate public key context");
104
105 if (EVP_PKEY_encrypt_init(ctx) <= 0)
106 return log_openssl_errors("Failed to initialize public key context");
107
108 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
109 return log_openssl_errors("Failed to configure PKCS#1 padding");
110
111 if (EVP_PKEY_encrypt(ctx, NULL, &l, decrypted_key, decrypted_key_size) <= 0)
112 return log_openssl_errors("Failed to determine encrypted key size");
113
114 b = malloc(l);
115 if (!b)
116 return -ENOMEM;
117
118 if (EVP_PKEY_encrypt(ctx, b, &l, decrypted_key, decrypted_key_size) <= 0)
119 return log_openssl_errors("Failed to determine encrypted key size");
120
121 *ret_encrypt_key = TAKE_PTR(b);
122 *ret_encrypt_key_size = l;
123
124 return 0;
125 }
126
127 int rsa_pkey_to_suitable_key_size(
128 EVP_PKEY *pkey,
129 size_t *ret_suitable_key_size) {
130
131 size_t suitable_key_size;
132 int bits;
133
134 assert(pkey);
135 assert(ret_suitable_key_size);
136
137 /* Analyzes the specified public key and that it is RSA. If so, will return a suitable size for a
138 * disk encryption key to encrypt with RSA for use in PKCS#11 security token schemes. */
139
140 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA)
141 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "X.509 certificate does not refer to RSA key.");
142
143 bits = EVP_PKEY_bits(pkey);
144 log_debug("Bits in RSA key: %i", bits);
145
146 /* We use PKCS#1 padding for the RSA cleartext, hence let's leave some extra space for it, hence only
147 * generate a random key half the size of the RSA length */
148 suitable_key_size = bits / 8 / 2;
149
150 if (suitable_key_size < 1)
151 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Uh, RSA key size too short?");
152
153 *ret_suitable_key_size = suitable_key_size;
154 return 0;
155 }
156
157 /* Generate RSA public key from provided "n" and "e" values. Note that if "e" is a number (e.g. uint32_t), it
158 * must be provided here big-endian, e.g. wrap it with htobe32(). */
159 int rsa_pkey_from_n_e(const void *n, size_t n_size, const void *e, size_t e_size, EVP_PKEY **ret) {
160 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
161
162 assert(n);
163 assert(e);
164 assert(ret);
165
166 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
167 if (!ctx)
168 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
169
170 _cleanup_(BN_freep) BIGNUM *bn_n = BN_bin2bn(n, n_size, NULL);
171 if (!bn_n)
172 return log_openssl_errors("Failed to create BIGNUM for RSA n");
173
174 _cleanup_(BN_freep) BIGNUM *bn_e = BN_bin2bn(e, e_size, NULL);
175 if (!bn_e)
176 return log_openssl_errors("Failed to create BIGNUM for RSA e");
177
178 #if OPENSSL_VERSION_MAJOR >= 3
179 if (EVP_PKEY_fromdata_init(ctx) <= 0)
180 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
181
182 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
183 if (!bld)
184 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
185
186 if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, bn_n))
187 return log_openssl_errors("Failed to set RSA OSSL_PKEY_PARAM_RSA_N");
188
189 if (!OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, bn_e))
190 return log_openssl_errors("Failed to set RSA OSSL_PKEY_PARAM_RSA_E");
191
192 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
193 if (!params)
194 return log_openssl_errors("Failed to build RSA OSSL_PARAM");
195
196 if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
197 return log_openssl_errors("Failed to create RSA EVP_PKEY");
198 #else
199 _cleanup_(RSA_freep) RSA *rsa_key = RSA_new();
200 if (!rsa_key)
201 return log_openssl_errors("Failed to create new RSA");
202
203 if (!RSA_set0_key(rsa_key, bn_n, bn_e, NULL))
204 return log_openssl_errors("Failed to set RSA n/e");
205 /* rsa_key owns these now, don't free */
206 TAKE_PTR(bn_n);
207 TAKE_PTR(bn_e);
208
209 pkey = EVP_PKEY_new();
210 if (!pkey)
211 return log_openssl_errors("Failed to create new EVP_PKEY");
212
213 if (!EVP_PKEY_assign_RSA(pkey, rsa_key))
214 return log_openssl_errors("Failed to assign RSA key");
215 /* pkey owns this now, don't free */
216 TAKE_PTR(rsa_key);
217 #endif
218
219 *ret = TAKE_PTR(pkey);
220
221 return 0;
222 }
223
224 /* Get the "n" and "e" values from the pkey. The values are returned in "bin" format, i.e. BN_bn2bin(). */
225 int rsa_pkey_to_n_e(
226 const EVP_PKEY *pkey,
227 void **ret_n,
228 size_t *ret_n_size,
229 void **ret_e,
230 size_t *ret_e_size) {
231
232 assert(pkey);
233 assert(ret_n);
234 assert(ret_n_size);
235 assert(ret_e);
236 assert(ret_e_size);
237
238 #if OPENSSL_VERSION_MAJOR >= 3
239 _cleanup_(BN_freep) BIGNUM *bn_n = NULL;
240 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &bn_n))
241 return log_openssl_errors("Failed to get RSA n");
242
243 _cleanup_(BN_freep) BIGNUM *bn_e = NULL;
244 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &bn_e))
245 return log_openssl_errors("Failed to get RSA e");
246 #else
247 const RSA *rsa = EVP_PKEY_get0_RSA((EVP_PKEY*) pkey);
248 if (!rsa)
249 return log_openssl_errors("Failed to get RSA key from public key");
250
251 const BIGNUM *bn_n = RSA_get0_n(rsa);
252 if (!bn_n)
253 return log_openssl_errors("Failed to get RSA n");
254
255 const BIGNUM *bn_e = RSA_get0_e(rsa);
256 if (!bn_e)
257 return log_openssl_errors("Failed to get RSA e");
258 #endif
259
260 size_t n_size = BN_num_bytes(bn_n), e_size = BN_num_bytes(bn_e);
261 _cleanup_free_ void *n = malloc(n_size), *e = malloc(e_size);
262 if (!n || !e)
263 return log_oom_debug();
264
265 assert(BN_bn2bin(bn_n, n) == (int) n_size);
266 assert(BN_bn2bin(bn_e, e) == (int) e_size);
267
268 *ret_n = TAKE_PTR(n);
269 *ret_n_size = n_size;
270 *ret_e = TAKE_PTR(e);
271 *ret_e_size = e_size;
272
273 return 0;
274 }
275
276 /* Generate a new RSA key with the specified number of bits. */
277 int rsa_pkey_new(size_t bits, EVP_PKEY **ret) {
278 assert(ret);
279
280 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
281 if (!ctx)
282 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
283
284 if (EVP_PKEY_keygen_init(ctx) <= 0)
285 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
286
287 if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, (int) bits) <= 0)
288 return log_openssl_errors("Failed to set RSA bits to %zu", bits);
289
290 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
291 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
292 return log_openssl_errors("Failed to generate ECC key");
293
294 *ret = TAKE_PTR(pkey);
295
296 return 0;
297 }
298
299 /* Generate ECC public key from provided curve ID and x/y points. */
300 int ecc_pkey_from_curve_x_y(
301 int curve_id,
302 const void *x,
303 size_t x_size,
304 const void *y,
305 size_t y_size,
306 EVP_PKEY **ret) {
307
308 assert(x);
309 assert(y);
310 assert(ret);
311
312 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
313 if (!ctx)
314 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
315
316 _cleanup_(BN_freep) BIGNUM *bn_x = BN_bin2bn(x, x_size, NULL);
317 if (!bn_x)
318 return log_openssl_errors("Failed to create BIGNUM x");
319
320 _cleanup_(BN_freep) BIGNUM *bn_y = BN_bin2bn(y, y_size, NULL);
321 if (!bn_y)
322 return log_openssl_errors("Failed to create BIGNUM y");
323
324 _cleanup_(EC_GROUP_freep) EC_GROUP *group = EC_GROUP_new_by_curve_name(curve_id);
325 if (!group)
326 return log_openssl_errors("ECC curve id %d not supported", curve_id);
327
328 _cleanup_(EC_POINT_freep) EC_POINT *point = EC_POINT_new(group);
329 if (!point)
330 return log_openssl_errors("Failed to create new EC_POINT");
331
332 if (!EC_POINT_set_affine_coordinates(group, point, bn_x, bn_y, NULL))
333 return log_openssl_errors("Failed to set ECC coordinates");
334
335 #if OPENSSL_VERSION_MAJOR >= 3
336 if (EVP_PKEY_fromdata_init(ctx) <= 0)
337 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
338
339 _cleanup_(OSSL_PARAM_BLD_freep) OSSL_PARAM_BLD *bld = OSSL_PARAM_BLD_new();
340 if (!bld)
341 return log_openssl_errors("Failed to create new OSSL_PARAM_BLD");
342
343 if (!OSSL_PARAM_BLD_push_utf8_string(bld, OSSL_PKEY_PARAM_GROUP_NAME, (char*) OSSL_EC_curve_nid2name(curve_id), 0))
344 return log_openssl_errors("Failed to add ECC OSSL_PKEY_PARAM_GROUP_NAME");
345
346 _cleanup_(OPENSSL_freep) void *pbuf = NULL;
347 size_t pbuf_len = 0;
348 pbuf_len = EC_POINT_point2buf(group, point, POINT_CONVERSION_UNCOMPRESSED, (unsigned char**) &pbuf, NULL);
349 if (pbuf_len == 0)
350 return log_openssl_errors("Failed to convert ECC point to buffer");
351
352 if (!OSSL_PARAM_BLD_push_octet_string(bld, OSSL_PKEY_PARAM_PUB_KEY, pbuf, pbuf_len))
353 return log_openssl_errors("Failed to add ECC OSSL_PKEY_PARAM_PUB_KEY");
354
355 _cleanup_(OSSL_PARAM_freep) OSSL_PARAM *params = OSSL_PARAM_BLD_to_param(bld);
356 if (!params)
357 return log_openssl_errors("Failed to build ECC OSSL_PARAM");
358
359 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
360 if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0)
361 return log_openssl_errors("Failed to create ECC EVP_PKEY");
362 #else
363 _cleanup_(EC_KEY_freep) EC_KEY *eckey = EC_KEY_new();
364 if (!eckey)
365 return log_openssl_errors("Failed to create new EC_KEY");
366
367 if (!EC_KEY_set_group(eckey, group))
368 return log_openssl_errors("Failed to set ECC group");
369
370 if (!EC_KEY_set_public_key(eckey, point))
371 return log_openssl_errors("Failed to set ECC point");
372
373 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = EVP_PKEY_new();
374 if (!pkey)
375 return log_openssl_errors("Failed to create new EVP_PKEY");
376
377 if (!EVP_PKEY_assign_EC_KEY(pkey, eckey))
378 return log_openssl_errors("Failed to assign ECC key");
379 /* pkey owns this now, don't free */
380 TAKE_PTR(eckey);
381 #endif
382
383 *ret = TAKE_PTR(pkey);
384
385 return 0;
386 }
387
388 int ecc_pkey_to_curve_x_y(
389 const EVP_PKEY *pkey,
390 int *ret_curve_id,
391 void **ret_x,
392 size_t *ret_x_size,
393 void **ret_y,
394 size_t *ret_y_size) {
395
396 _cleanup_(BN_freep) BIGNUM *bn_x = NULL, *bn_y = NULL;
397 int curve_id;
398
399 assert(pkey);
400
401 #if OPENSSL_VERSION_MAJOR >= 3
402 size_t name_size;
403 if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0, &name_size))
404 return log_openssl_errors("Failed to get ECC group name size");
405
406 _cleanup_free_ char *name = new(char, name_size + 1);
407 if (!name)
408 return log_oom_debug();
409
410 if (!EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, name, name_size + 1, NULL))
411 return log_openssl_errors("Failed to get ECC group name");
412
413 curve_id = OBJ_sn2nid(name);
414 if (curve_id == NID_undef)
415 return log_openssl_errors("Failed to get ECC curve id");
416
417 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_X, &bn_x))
418 return log_openssl_errors("Failed to get ECC point x");
419
420 if (!EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_EC_PUB_Y, &bn_y))
421 return log_openssl_errors("Failed to get ECC point y");
422 #else
423 const EC_KEY *eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY*) pkey);
424 if (!eckey)
425 return log_openssl_errors("Failed to get EC_KEY");
426
427 const EC_GROUP *group = EC_KEY_get0_group(eckey);
428 if (!group)
429 return log_openssl_errors("Failed to get EC_GROUP");
430
431 curve_id = EC_GROUP_get_curve_name(group);
432 if (curve_id == NID_undef)
433 return log_openssl_errors("Failed to get ECC curve id");
434
435 const EC_POINT *point = EC_KEY_get0_public_key(eckey);
436 if (!point)
437 return log_openssl_errors("Failed to get EC_POINT");
438
439 bn_x = BN_new();
440 bn_y = BN_new();
441 if (!bn_x || !bn_y)
442 return log_openssl_errors("Failed to create new BIGNUM");
443
444 if (!EC_POINT_get_affine_coordinates(group, point, bn_x, bn_y, NULL))
445 return log_openssl_errors("Failed to get ECC x/y.");
446 #endif
447
448 size_t x_size = BN_num_bytes(bn_x), y_size = BN_num_bytes(bn_y);
449 _cleanup_free_ void *x = malloc(x_size), *y = malloc(y_size);
450 if (!x || !y)
451 return log_oom_debug();
452
453 assert(BN_bn2bin(bn_x, x) == (int) x_size);
454 assert(BN_bn2bin(bn_y, y) == (int) y_size);
455
456 if (ret_curve_id)
457 *ret_curve_id = curve_id;
458 if (ret_x)
459 *ret_x = TAKE_PTR(x);
460 if (ret_x_size)
461 *ret_x_size = x_size;
462 if (ret_y)
463 *ret_y = TAKE_PTR(y);
464 if (ret_y_size)
465 *ret_y_size = y_size;
466
467 return 0;
468 }
469
470 /* Generate a new ECC key for the specified ECC curve id. */
471 int ecc_pkey_new(int curve_id, EVP_PKEY **ret) {
472 assert(ret);
473
474 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
475 if (!ctx)
476 return log_openssl_errors("Failed to create new EVP_PKEY_CTX");
477
478 if (EVP_PKEY_keygen_init(ctx) <= 0)
479 return log_openssl_errors("Failed to initialize EVP_PKEY_CTX");
480
481 if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve_id) <= 0)
482 return log_openssl_errors("Failed to set ECC curve %d", curve_id);
483
484 _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL;
485 if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
486 return log_openssl_errors("Failed to generate ECC key");
487
488 *ret = TAKE_PTR(pkey);
489
490 return 0;
491 }
492
493 int pubkey_fingerprint(EVP_PKEY *pk, const EVP_MD *md, void **ret, size_t *ret_size) {
494 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX* m = NULL;
495 _cleanup_free_ void *d = NULL, *h = NULL;
496 int sz, lsz, msz;
497 unsigned umsz;
498 unsigned char *dd;
499
500 /* Calculates a message digest of the DER encoded public key */
501
502 assert(pk);
503 assert(md);
504 assert(ret);
505 assert(ret_size);
506
507 sz = i2d_PublicKey(pk, NULL);
508 if (sz < 0)
509 return log_openssl_errors("Unable to convert public key to DER format");
510
511 dd = d = malloc(sz);
512 if (!d)
513 return log_oom_debug();
514
515 lsz = i2d_PublicKey(pk, &dd);
516 if (lsz < 0)
517 return log_openssl_errors("Unable to convert public key to DER format");
518
519 m = EVP_MD_CTX_new();
520 if (!m)
521 return log_openssl_errors("Failed to create new EVP_MD_CTX");
522
523 if (EVP_DigestInit_ex(m, md, NULL) != 1)
524 return log_openssl_errors("Failed to initialize %s context", EVP_MD_name(md));
525
526 if (EVP_DigestUpdate(m, d, lsz) != 1)
527 return log_openssl_errors("Failed to run %s context", EVP_MD_name(md));
528
529 msz = EVP_MD_size(md);
530 assert(msz > 0);
531
532 h = malloc(msz);
533 if (!h)
534 return log_oom_debug();
535
536 umsz = msz;
537 if (EVP_DigestFinal_ex(m, h, &umsz) != 1)
538 return log_openssl_errors("Failed to finalize hash context");
539
540 assert(umsz == (unsigned) msz);
541
542 *ret = TAKE_PTR(h);
543 *ret_size = msz;
544
545 return 0;
546 }
547
548 # if PREFER_OPENSSL
549 int string_hashsum(
550 const char *s,
551 size_t len,
552 const EVP_MD *md_algorithm,
553 char **ret) {
554
555 uint8_t hash[EVP_MAX_MD_SIZE];
556 size_t hash_size;
557 char *enc;
558 int r;
559
560 hash_size = EVP_MD_size(md_algorithm);
561 assert(hash_size > 0);
562
563 r = openssl_hash(md_algorithm, s, len, hash, NULL);
564 if (r < 0)
565 return r;
566
567 enc = hexmem(hash, hash_size);
568 if (!enc)
569 return -ENOMEM;
570
571 *ret = enc;
572 return 0;
573
574 }
575 # endif
576 #endif
577
578 int x509_fingerprint(X509 *cert, uint8_t buffer[static SHA256_DIGEST_SIZE]) {
579 #if HAVE_OPENSSL
580 _cleanup_free_ uint8_t *der = NULL;
581 int dersz;
582
583 assert(cert);
584
585 dersz = i2d_X509(cert, &der);
586 if (dersz < 0)
587 return log_openssl_errors("Unable to convert PEM certificate to DER format");
588
589 sha256_direct(der, dersz, buffer);
590 return 0;
591 #else
592 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "openssl is not supported, cannot calculate X509 fingerprint: %m");
593 #endif
594 }