1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "openssl-util.h"
4 #include "alloc-util.h"
5 #include "hexdecoct.h"
6
7 #if HAVE_OPENSSL
openssl_hash(const EVP_MD * alg,const void * msg,size_t msg_len,uint8_t * ret_hash,size_t * ret_hash_len)8 int openssl_hash(const EVP_MD *alg,
9 const void *msg,
10 size_t msg_len,
11 uint8_t *ret_hash,
12 size_t *ret_hash_len) {
13
14 _cleanup_(EVP_MD_CTX_freep) EVP_MD_CTX *ctx = NULL;
15 unsigned len;
16 int r;
17
18 ctx = EVP_MD_CTX_new();
19 if (!ctx)
20 /* This function just calls OPENSSL_zalloc, so failure
21 * here is almost certainly a failed allocation. */
22 return -ENOMEM;
23
24 /* The documentation claims EVP_DigestInit behaves just like
25 * EVP_DigestInit_ex if passed NULL, except it also calls
26 * EVP_MD_CTX_reset, which deinitializes the context. */
27 r = EVP_DigestInit_ex(ctx, alg, NULL);
28 if (r == 0)
29 return -EIO;
30
31 r = EVP_DigestUpdate(ctx, msg, msg_len);
32 if (r == 0)
33 return -EIO;
34
35 r = EVP_DigestFinal_ex(ctx, ret_hash, &len);
36 if (r == 0)
37 return -EIO;
38
39 if (ret_hash_len)
40 *ret_hash_len = len;
41
42 return 0;
43 }
44
rsa_encrypt_bytes(EVP_PKEY * pkey,const void * decrypted_key,size_t decrypted_key_size,void ** ret_encrypt_key,size_t * ret_encrypt_key_size)45 int rsa_encrypt_bytes(
46 EVP_PKEY *pkey,
47 const void *decrypted_key,
48 size_t decrypted_key_size,
49 void **ret_encrypt_key,
50 size_t *ret_encrypt_key_size) {
51
52 _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL;
53 _cleanup_free_ void *b = NULL;
54 size_t l;
55
56 ctx = EVP_PKEY_CTX_new(pkey, NULL);
57 if (!ctx)
58 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to allocate public key context");
59
60 if (EVP_PKEY_encrypt_init(ctx) <= 0)
61 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize public key context");
62
63 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
64 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to configure PKCS#1 padding");
65
66 if (EVP_PKEY_encrypt(ctx, NULL, &l, decrypted_key, decrypted_key_size) <= 0)
67 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to determine encrypted key size");
68
69 b = malloc(l);
70 if (!b)
71 return -ENOMEM;
72
73 if (EVP_PKEY_encrypt(ctx, b, &l, decrypted_key, decrypted_key_size) <= 0)
74 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to determine encrypted key size");
75
76 *ret_encrypt_key = TAKE_PTR(b);
77 *ret_encrypt_key_size = l;
78
79 return 0;
80 }
81
rsa_pkey_to_suitable_key_size(EVP_PKEY * pkey,size_t * ret_suitable_key_size)82 int rsa_pkey_to_suitable_key_size(
83 EVP_PKEY *pkey,
84 size_t *ret_suitable_key_size) {
85
86 size_t suitable_key_size;
87 int bits;
88
89 assert_se(pkey);
90 assert_se(ret_suitable_key_size);
91
92 /* Analyzes the specified public key and that it is RSA. If so, will return a suitable size for a
93 * disk encryption key to encrypt with RSA for use in PKCS#11 security token schemes. */
94
95 if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA)
96 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "X.509 certificate does not refer to RSA key.");
97
98 bits = EVP_PKEY_bits(pkey);
99 log_debug("Bits in RSA key: %i", bits);
100
101 /* We use PKCS#1 padding for the RSA cleartext, hence let's leave some extra space for it, hence only
102 * generate a random key half the size of the RSA length */
103 suitable_key_size = bits / 8 / 2;
104
105 if (suitable_key_size < 1)
106 return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Uh, RSA key size too short?");
107
108 *ret_suitable_key_size = suitable_key_size;
109 return 0;
110 }
111
112 # if PREFER_OPENSSL
string_hashsum(const char * s,size_t len,const EVP_MD * md_algorithm,char ** ret)113 int string_hashsum(
114 const char *s,
115 size_t len,
116 const EVP_MD *md_algorithm,
117 char **ret) {
118
119 uint8_t hash[EVP_MAX_MD_SIZE];
120 size_t hash_size;
121 char *enc;
122 int r;
123
124 hash_size = EVP_MD_size(md_algorithm);
125 assert(hash_size > 0);
126
127 r = openssl_hash(md_algorithm, s, len, hash, NULL);
128 if (r < 0)
129 return r;
130
131 enc = hexmem(hash, hash_size);
132 if (!enc)
133 return -ENOMEM;
134
135 *ret = enc;
136 return 0;
137
138 }
139 # endif
140 #endif
141