Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPString.h"
25 : #include "SPLog.h"
26 : #include "SPCrypto.h"
27 : #include "SPValid.h"
28 :
29 : #if __CDT_PARSER__
30 : #define MODULE_STAPPLER_CRYPTO_OPENSSL 1
31 : #endif
32 :
33 : #if MODULE_STAPPLER_CRYPTO_OPENSSL
34 :
35 : #include <openssl/pem.h>
36 : #include <openssl/rsa.h>
37 : #include <openssl/evp.h>
38 : #include <openssl/err.h>
39 : #include <openssl/ssl.h>
40 : #include <openssl/engine.h>
41 :
42 : extern "C" {
43 :
44 : #include <gost-engine.h>
45 : #include <e_gost_err.h>
46 :
47 : int pack_sign_cp(ECDSA_SIG *s, int order, unsigned char *sig, size_t *siglen);
48 : int gost_ec_point_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *n,
49 : const EC_POINT *q, const BIGNUM *m, BN_CTX *ctx);
50 : }
51 :
52 : #define EVP_PKEY_CTRL_GOST_PARAMSET (EVP_PKEY_ALG_CTRL+1)
53 :
54 : namespace STAPPLER_VERSIONIZED stappler::crypto {
55 :
56 : static uint8_t * writeRSAKey(uint8_t *buf, BytesViewNetwork mod, BytesViewNetwork exp);
57 : static void fillCryptoBlockHeader(uint8_t *buf, const BlockKey256 &key, BytesView d);
58 :
59 : static const char *ossl_engine_gost_id = "stappler-gost-hook";
60 : static const char *ossl_engine_gost_name = "Hook for GOST engine sign functions";
61 :
62 : static EVP_PKEY_METHOD *s_ossl_GostR3410_2012_256_resign;
63 : static int (*s_ossl_GostR3410_2012_256_psign_init)(EVP_PKEY_CTX *ctx);
64 : static int (*s_ossl_GostR3410_2012_256_psign)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen);
65 :
66 : static EVP_PKEY_METHOD *s_ossl_GostR3410_2012_512_resign;
67 : static int (*s_ossl_GostR3410_2012_512_psign_init)(EVP_PKEY_CTX *ctx);
68 : static int (*s_ossl_GostR3410_2012_512_psign)(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbslen);
69 :
70 : static EVP_PKEY_METHOD *s_ossl_GostR3410_2012_meths[] = {
71 : nullptr,
72 : nullptr
73 : };
74 :
75 : static int s_ossl_GostR3410_2012_nids_array[] = {
76 : NID_id_GostR3410_2012_256,
77 : NID_id_GostR3410_2012_512
78 : };
79 :
80 : static ENGINE *s_ossl_Engine = nullptr;
81 :
82 : typedef enum bnrand_flag_e {
83 : NORMAL, TESTING, PRIVATE
84 : } BNRAND_FLAG;
85 :
86 4681 : static int hook_ossl_bnrand(BIGNUM *rnd, int bits, int top, int bottom, unsigned int strength, BytesView rndData) {
87 4681 : unsigned char *buf = NULL;
88 4681 : int ret = 0, bit, bytes, mask;
89 :
90 4681 : if (bits == 0) {
91 0 : if (top != BN_RAND_TOP_ANY || bottom != BN_RAND_BOTTOM_ANY)
92 0 : goto toosmall;
93 0 : BN_zero(rnd);
94 0 : return 1;
95 : }
96 4681 : if (bits < 0 || (bits == 1 && top > 0))
97 0 : goto toosmall;
98 :
99 4681 : bytes = (bits + 7) / 8;
100 4681 : bit = (bits - 1) % 8;
101 4681 : mask = 0xff << (bit + 1);
102 :
103 4681 : buf = static_cast<unsigned char *>(OPENSSL_malloc(bytes));
104 4681 : if (buf == NULL) {
105 0 : ERR_raise(ERR_LIB_BN, ERR_R_MALLOC_FAILURE);
106 0 : goto err;
107 : }
108 :
109 : /* make a random number and set the top and bottom bits */
110 4681 : if (size_t(bytes) > rndData.size()) {
111 0 : goto err;
112 : }
113 4681 : memcpy(buf, rndData.data(), bytes);
114 :
115 4681 : if (top >= 0) {
116 0 : if (top) {
117 0 : if (bit == 0) {
118 0 : buf[0] = 1;
119 0 : buf[1] |= 0x80;
120 : } else {
121 0 : buf[0] |= (3 << (bit - 1));
122 : }
123 : } else {
124 0 : buf[0] |= (1 << bit);
125 : }
126 : }
127 4681 : buf[0] &= ~mask;
128 4681 : if (bottom) /* set bottom bit if requested */
129 0 : buf[bytes - 1] |= 1;
130 4681 : if (!BN_bin2bn(buf, bytes, rnd))
131 0 : goto err;
132 4681 : ret = 1;
133 4681 : err:
134 4681 : OPENSSL_clear_free(buf, bytes);
135 4681 : return ret;
136 :
137 0 : toosmall:
138 0 : ERR_raise(ERR_LIB_BN, BN_R_BITS_TOO_SMALL);
139 0 : return 0;
140 : }
141 :
142 : /* random number r: 0 <= r < range */
143 325 : static int hook_ossl_bnrand_range(BIGNUM *r, const BIGNUM *range, unsigned int strength, BytesView rndData) {
144 : int n;
145 325 : int count = 100;
146 :
147 325 : if (r == NULL) {
148 0 : ERR_raise(ERR_LIB_BN, ERR_R_PASSED_NULL_PARAMETER);
149 0 : return 0;
150 : }
151 :
152 325 : if (BN_is_zero(range)) {
153 0 : ERR_raise(ERR_LIB_BN, BN_R_INVALID_RANGE);
154 0 : return 0;
155 : }
156 :
157 325 : n = BN_num_bits(range); /* n > 0 */
158 :
159 : /* BN_is_bit_set(range, n - 1) always holds */
160 :
161 325 : if (n == 1)
162 0 : BN_zero(r);
163 325 : else if (!BN_is_bit_set(range, n - 2) && !BN_is_bit_set(range, n - 3)) {
164 : /*
165 : * range = 100..._2, so 3*range (= 11..._2) is exactly one bit longer
166 : * than range
167 : */
168 : do {
169 4506 : if (!hook_ossl_bnrand(r, n + 1, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, strength, rndData))
170 0 : return 0;
171 :
172 : /*
173 : * If r < 3*range, use r := r MOD range (which is either r, r -
174 : * range, or r - 2*range). Otherwise, iterate once more. Since
175 : * 3*range = 11..._2, each iteration succeeds with probability >=
176 : * .75.
177 : */
178 4506 : if (BN_cmp(r, range) >= 0) {
179 4464 : if (!BN_sub(r, r, range))
180 0 : return 0;
181 4464 : if (BN_cmp(r, range) >= 0)
182 4434 : if (!BN_sub(r, r, range))
183 0 : return 0;
184 : }
185 :
186 4506 : if (!--count) {
187 44 : break;
188 : }
189 :
190 4462 : } while (BN_cmp(r, range) >= 0);
191 : } else {
192 : do {
193 : /* range = 11..._2 or range = 101..._2 */
194 175 : if (!hook_ossl_bnrand(r, n, BN_RAND_TOP_ANY, BN_RAND_BOTTOM_ANY, 0, rndData))
195 0 : return 0;
196 :
197 175 : if (!--count) {
198 0 : ERR_raise(ERR_LIB_BN, BN_R_TOO_MANY_ITERATIONS);
199 0 : return 0;
200 : }
201 175 : } while (BN_cmp(r, range) >= 0);
202 : }
203 :
204 325 : return 1;
205 : }
206 :
207 : #pragma GCC diagnostic push
208 : #pragma GCC diagnostic ignored "-Wwrite-strings"
209 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
210 :
211 325 : static ECDSA_SIG *hook_ossl_gost_ec_sign(const unsigned char *dgst, int dlen, EC_KEY *eckey, int nbytes) {
212 325 : ECDSA_SIG *newsig = NULL, *ret = NULL;
213 325 : BIGNUM *md = NULL;
214 325 : BIGNUM *order = NULL;
215 : const EC_GROUP *group;
216 : const BIGNUM *priv_key;
217 325 : BIGNUM *r = NULL, *s = NULL, *X = NULL, *tmp = NULL, *tmp2 = NULL, *k = NULL, *e = NULL;
218 :
219 325 : BIGNUM *new_r = NULL, *new_s = NULL;
220 :
221 325 : EC_POINT *C = NULL;
222 : BN_CTX *ctx;
223 :
224 325 : OPENSSL_assert(dgst != NULL && eckey != NULL);
225 :
226 325 : if (!(ctx = BN_CTX_secure_new())) {
227 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
228 0 : return NULL;
229 : }
230 :
231 325 : BN_CTX_start(ctx);
232 325 : OPENSSL_assert(dlen == 32 || dlen == 64);
233 325 : md = BN_lebin2bn(dgst, dlen, NULL);
234 325 : newsig = ECDSA_SIG_new();
235 325 : if (!newsig || !md) {
236 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
237 0 : goto err;
238 : }
239 325 : group = EC_KEY_get0_group(eckey);
240 325 : if (!group) {
241 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
242 0 : goto err;
243 : }
244 325 : order = BN_CTX_get(ctx);
245 325 : if (!order || !EC_GROUP_get_order(group, order, ctx)) {
246 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
247 0 : goto err;
248 : }
249 325 : priv_key = EC_KEY_get0_private_key(eckey);
250 :
251 325 : if (!priv_key) {
252 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
253 0 : goto err;
254 : }
255 325 : e = BN_CTX_get(ctx);
256 325 : if (!e || !BN_mod(e, md, order, ctx)) {
257 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
258 0 : goto err;
259 : }
260 : #ifdef DEBUG_SIGN
261 : fprintf(stderr, "digest as bignum=");
262 : BN_print_fp(stderr, md);
263 : fprintf(stderr, "\ndigest mod q=");
264 : BN_print_fp(stderr, e);
265 : fprintf(stderr, "\n");
266 : #endif
267 325 : if (BN_is_zero(e)) {
268 0 : BN_one(e);
269 : }
270 325 : k = BN_CTX_get(ctx);
271 325 : C = EC_POINT_new(group);
272 325 : if (!k || !C) {
273 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
274 0 : goto err;
275 : }
276 :
277 : do {
278 : do {
279 325 : auto hexPrivKey = BN_bn2hex(priv_key);
280 325 : auto privBytes = base16::decode<memory::StandartInterface>(StringView(hexPrivKey));
281 325 : std::reverse(privBytes.begin(), privBytes.end());
282 325 : OPENSSL_free(hexPrivKey);
283 :
284 325 : auto randSeed = Gost3411_512::hmac(privBytes, BytesView(dgst, dlen));
285 :
286 325 : if (!hook_ossl_bnrand_range(k, order, 0, randSeed)) {
287 0 : GOSTerr(GOST_F_GOST_EC_SIGN, GOST_R_RNG_ERROR);
288 0 : goto err;
289 : }
290 :
291 325 : if (!gost_ec_point_mul(group, C, k, NULL, NULL, ctx)) {
292 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_EC_LIB);
293 0 : goto err;
294 : }
295 325 : if (!X)
296 325 : X = BN_CTX_get(ctx);
297 325 : if (!r)
298 325 : r = BN_CTX_get(ctx);
299 325 : if (!X || !r) {
300 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
301 0 : goto err;
302 : }
303 325 : if (!EC_POINT_get_affine_coordinates(group, C, X, NULL, ctx)) {
304 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_EC_LIB);
305 0 : goto err;
306 : }
307 :
308 325 : if (!BN_nnmod(r, X, order, ctx)) {
309 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
310 0 : goto err;
311 : }
312 650 : } while (BN_is_zero(r));
313 : /* s = (r*priv_key+k*e) mod order */
314 325 : if (!tmp)
315 325 : tmp = BN_CTX_get(ctx);
316 325 : if (!tmp2)
317 325 : tmp2 = BN_CTX_get(ctx);
318 325 : if (!s)
319 325 : s = BN_CTX_get(ctx);
320 325 : if (!tmp || !tmp2 || !s) {
321 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
322 0 : goto err;
323 : }
324 :
325 325 : if (!BN_mod_mul(tmp, priv_key, r, order, ctx) || !BN_mod_mul(tmp2, k, e, order, ctx) || !BN_mod_add(s, tmp, tmp2, order, ctx)) {
326 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_INTERNAL_ERROR);
327 0 : goto err;
328 : }
329 325 : } while (BN_is_zero(s));
330 :
331 325 : new_s = BN_dup(s);
332 325 : new_r = BN_dup(r);
333 325 : if (!new_s || !new_r) {
334 0 : GOSTerr(GOST_F_GOST_EC_SIGN, ERR_R_MALLOC_FAILURE);
335 0 : goto err;
336 : }
337 325 : ECDSA_SIG_set0(newsig, new_r, new_s);
338 :
339 325 : ret = newsig;
340 325 : err:
341 325 : BN_CTX_end(ctx);
342 325 : BN_CTX_free(ctx);
343 325 : if (C)
344 325 : EC_POINT_free(C);
345 325 : if (md)
346 325 : BN_free(md);
347 325 : if (!ret && newsig) {
348 0 : ECDSA_SIG_free(newsig);
349 : }
350 325 : return ret;
351 : }
352 :
353 300 : static int s_ossl_GostR3410_2012_256_psign_resign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbs_len) {
354 300 : if (!sig) {
355 150 : return s_ossl_GostR3410_2012_256_psign(ctx, sig, siglen, tbs, tbs_len);
356 : } else {
357 : size_t order;
358 150 : s_ossl_GostR3410_2012_256_psign(ctx, nullptr, &order, tbs, tbs_len);
359 :
360 150 : EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
361 150 : auto unpacked_sig = hook_ossl_gost_ec_sign(tbs, tbs_len, (EC_KEY *)EVP_PKEY_get0(pkey), 32);
362 150 : if (!unpacked_sig) {
363 0 : return 0;
364 : }
365 150 : return pack_sign_cp(unpacked_sig, order / 2, sig, siglen);
366 : }
367 : }
368 :
369 350 : static int s_ossl_GostR3410_2012_512_psign_resign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, const unsigned char *tbs, size_t tbs_len) {
370 350 : if (!sig) {
371 175 : return s_ossl_GostR3410_2012_512_psign(ctx, sig, siglen, tbs, tbs_len);
372 : } else {
373 : size_t order;
374 175 : s_ossl_GostR3410_2012_512_psign(ctx, nullptr, &order, tbs, tbs_len);
375 :
376 175 : EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(ctx);
377 175 : auto unpacked_sig = hook_ossl_gost_ec_sign(tbs, tbs_len, (EC_KEY *)EVP_PKEY_get0(pkey), 64);
378 175 : if (!unpacked_sig) {
379 0 : return 0;
380 : }
381 175 : return pack_sign_cp(unpacked_sig, order / 2, sig, siglen);
382 : }
383 : }
384 :
385 : #pragma GCC diagnostic pop
386 :
387 25 : static int ossl_gost_meth_nids(const int **nids) {
388 25 : if (nids) {
389 25 : *nids = s_ossl_GostR3410_2012_nids_array;
390 : }
391 25 : return 2;
392 : }
393 :
394 775 : static int ossl_gost_pkey_meths(ENGINE *e, EVP_PKEY_METHOD **pmeth, const int **nids, int nid) {
395 775 : if (!pmeth)
396 25 : return ossl_gost_meth_nids(nids);
397 :
398 750 : size_t i = 0;
399 1200 : for (auto &it : s_ossl_GostR3410_2012_nids_array) {
400 1200 : if (nid == it) {
401 750 : *pmeth = s_ossl_GostR3410_2012_meths[i];
402 750 : return 1;
403 : }
404 450 : ++ i;
405 : }
406 :
407 0 : *pmeth = NULL;
408 0 : return 0;
409 : }
410 :
411 : // For interoperability with GnuTLS
412 : static constexpr int OPENSSL_PK_ENCRYPT_PADDING = RSA_PKCS1_PADDING;
413 :
414 : SP_COVERAGE_TRIVIAL
415 : static void logOpenSSLErrors() {
416 : BIO *bio = BIO_new(BIO_s_mem());
417 : ERR_print_errors(bio);
418 : char *buf;
419 : size_t len = BIO_get_mem_data(bio, &buf);
420 : log::error("OpenSSL", StringView(buf, len));
421 : BIO_free(bio);
422 : ERR_clear_error();
423 : }
424 :
425 1450 : static KeyType getOpenSSLKeyType(int id) {
426 1450 : if (id == EVP_PKEY_RSA) {
427 675 : return KeyType::RSA;
428 775 : } else if (id == EVP_PKEY_DSA) {
429 0 : return KeyType::DSA;
430 775 : } else if (id == EVP_PKEY_EC) {
431 50 : return KeyType::ECDSA;
432 725 : } else if (id == EVP_PKEY_ED448) {
433 50 : return KeyType::EDDSA_ED448;
434 675 : } else if (id == NID_id_GostR3410_2012_256) {
435 350 : return KeyType::GOST3410_2012_256;
436 325 : } else if (id == NID_id_GostR3410_2012_512) {
437 325 : return KeyType::GOST3410_2012_512;
438 : }
439 0 : return KeyType::Unknown;
440 : }
441 :
442 250 : static const EVP_CIPHER *getOpenSSLCipher(BlockCipher b) {
443 250 : switch (b) {
444 100 : case BlockCipher::AES_CBC:
445 100 : return EVP_aes_256_cbc();
446 : break;
447 0 : case BlockCipher::AES_CFB8:
448 0 : return EVP_aes_256_cfb8();
449 : break;
450 150 : case BlockCipher::Gost3412_2015_CTR_ACPKM:
451 150 : if (auto m = EVP_get_cipherbyname("kuznyechik-ctr-acpkm")) {
452 150 : return m;
453 : }
454 0 : break;
455 : }
456 0 : return EVP_aes_256_cbc();
457 : }
458 :
459 25 : static void OpenSSL_initGost() {
460 : static bool init = false;
461 25 : if (init) {
462 0 : return;
463 : }
464 :
465 25 : init = true;
466 :
467 : #pragma GCC diagnostic push
468 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
469 25 : ENGINE_load_gost();
470 :
471 25 : auto e = ENGINE_get_pkey_meth_engine(NID_id_GostR3410_2012_256);
472 25 : if (auto meth = ENGINE_get_pkey_meth(e, NID_id_GostR3410_2012_256)) {
473 25 : s_ossl_GostR3410_2012_256_resign = EVP_PKEY_meth_new(NID_id_GostR3410_2012_256, 0);
474 25 : EVP_PKEY_meth_copy(s_ossl_GostR3410_2012_256_resign, meth);
475 :
476 25 : EVP_PKEY_meth_get_sign(s_ossl_GostR3410_2012_256_resign,
477 : &s_ossl_GostR3410_2012_256_psign_init, &s_ossl_GostR3410_2012_256_psign);
478 25 : EVP_PKEY_meth_set_sign(s_ossl_GostR3410_2012_256_resign, s_ossl_GostR3410_2012_256_psign_init,
479 : &s_ossl_GostR3410_2012_256_psign_resign);
480 :
481 25 : s_ossl_GostR3410_2012_meths[0] = s_ossl_GostR3410_2012_256_resign;
482 25 : EVP_PKEY_meth_add0(s_ossl_GostR3410_2012_256_resign);
483 : }
484 25 : if (auto meth = ENGINE_get_pkey_meth(e, NID_id_GostR3410_2012_512)) {
485 25 : s_ossl_GostR3410_2012_512_resign = EVP_PKEY_meth_new(NID_id_GostR3410_2012_512, 0);
486 25 : EVP_PKEY_meth_copy(s_ossl_GostR3410_2012_512_resign, meth);
487 :
488 25 : EVP_PKEY_meth_get_sign(s_ossl_GostR3410_2012_512_resign,
489 : &s_ossl_GostR3410_2012_512_psign_init, &s_ossl_GostR3410_2012_512_psign);
490 25 : EVP_PKEY_meth_set_sign(s_ossl_GostR3410_2012_512_resign, s_ossl_GostR3410_2012_512_psign_init,
491 : &s_ossl_GostR3410_2012_512_psign_resign);
492 :
493 25 : s_ossl_GostR3410_2012_meths[1] = s_ossl_GostR3410_2012_512_resign;
494 25 : EVP_PKEY_meth_add0(s_ossl_GostR3410_2012_512_resign);
495 : }
496 25 : if (auto meth = ENGINE_get_pkey_asn1_meth(e, NID_id_GostR3410_2012_256)) {
497 25 : EVP_PKEY_asn1_add0(meth);
498 : }
499 25 : if (auto meth = ENGINE_get_pkey_asn1_meth(e, NID_id_GostR3410_2012_512)) {
500 25 : EVP_PKEY_asn1_add0(meth);
501 : }
502 :
503 25 : s_ossl_Engine = ENGINE_new();
504 25 : ENGINE_set_id(s_ossl_Engine, ossl_engine_gost_id);
505 25 : ENGINE_set_name(s_ossl_Engine, ossl_engine_gost_name);
506 25 : ENGINE_set_pkey_meths(s_ossl_Engine, ossl_gost_pkey_meths);
507 :
508 25 : ENGINE_register_pkey_meths(s_ossl_Engine);
509 :
510 25 : ENGINE_register_all_complete();
511 : #pragma GCC diagnostic pop
512 : }
513 :
514 : static BackendCtx s_openSSLCtx = {
515 : .name = Backend::OpenSSL,
516 : .title = StringView("OpenSSL"),
517 : .flags = BackendFlags::SupportsPKCS1 | BackendFlags::SupportsPKCS8 | BackendFlags::SupportsAes | BackendFlags::SecureLibrary
518 : | BackendFlags::SupportsGost3410_2012 | BackendFlags::SupportsGost3412_2015,
519 25 : .initialize = [] () {
520 25 : OpenSSL_initGost();
521 25 : OPENSSL_init_ssl(OPENSSL_INIT_SSL_DEFAULT, NULL);
522 25 : log::verbose("Crypto", "OpenSSL+gost backend loaded");
523 25 : },
524 25 : .finalize = [] () { },
525 75 : .encryptBlock = [] (const BlockKey256 &key, BytesView d, const Callback<void(BytesView)> &cb) -> bool {
526 75 : auto cipherBlockSize = getBlockSize(key.cipher);
527 75 : auto cipher = getOpenSSLCipher(key.cipher);
528 :
529 75 : uint64_t dataSize = d.size();
530 75 : auto blockSize = math::align<size_t>(dataSize, cipherBlockSize)
531 75 : + cipherBlockSize; // allocate space for possible padding
532 :
533 75 : uint8_t output[blockSize + sizeof(BlockCryptoHeader)];
534 :
535 75 : fillCryptoBlockHeader(output, key, d);
536 :
537 75 : uint8_t iv[16] = { 0 };
538 75 : EVP_CIPHER_CTX *en = nullptr;
539 :
540 75 : auto finalize = [&] (bool value) {
541 75 : if (en) {
542 75 : EVP_CIPHER_CTX_free(en);
543 75 : en = nullptr;
544 : }
545 75 : return value;
546 75 : };
547 :
548 75 : en = EVP_CIPHER_CTX_new();
549 75 : if (!en) {
550 0 : return finalize(false);
551 : }
552 :
553 75 : if (!EVP_EncryptInit_ex(en, cipher, NULL, key.data.data(), iv)) {
554 0 : return finalize(false);
555 : }
556 :
557 75 : auto perform = [] (EVP_CIPHER_CTX *en, const uint8_t *target, size_t targetSize, uint8_t *out) {
558 75 : int outSize = 0;
559 150 : while (targetSize > 0) {
560 75 : if (!EVP_EncryptUpdate(en, out, &outSize, target, targetSize)) {
561 0 : return false;
562 : }
563 :
564 75 : out += outSize;
565 75 : target += outSize;
566 75 : if (int(targetSize) >= outSize) {
567 75 : targetSize -= outSize;
568 : } else {
569 0 : targetSize = 0;
570 : }
571 : }
572 :
573 75 : if (!EVP_EncryptFinal(en, out, &outSize)) {
574 0 : return false;
575 : }
576 :
577 75 : return true;
578 : };
579 :
580 75 : fillCryptoBlockHeader(output, key, d);
581 :
582 : if constexpr (SafeBlockEncoding) {
583 75 : uint8_t tmp[blockSize];
584 75 : memset(tmp, 0, blockSize);
585 75 : memcpy(tmp, d.data(), d.size());
586 :
587 75 : if (!perform(en, tmp, blockSize - cipherBlockSize, output + sizeof(BlockCryptoHeader))) {
588 0 : return finalize(false);
589 : }
590 75 : } else {
591 : if (!perform(en, d.data(), d.size(), output + sizeof(BlockCryptoHeader))) {
592 : return finalize(false);
593 : }
594 : }
595 :
596 75 : cb(BytesView(output, blockSize + sizeof(BlockCryptoHeader) - cipherBlockSize));
597 75 : return finalize(true);
598 75 : },
599 175 : .decryptBlock = [] (const BlockKey256 &key, BytesView b, const Callback<void(BytesView)> &cb) -> bool {
600 175 : auto info = getBlockInfo(b);
601 175 : auto cipherBlockSize = getBlockSize(info.cipher);
602 175 : auto cipher = getOpenSSLCipher(info.cipher);
603 :
604 175 : auto blockSize = math::align<size_t>(info.dataSize, cipherBlockSize) + cipherBlockSize;
605 175 : b.offset(sizeof(BlockCryptoHeader));
606 :
607 175 : uint8_t output[blockSize];
608 :
609 175 : uint8_t iv[16] = { 0 };
610 175 : EVP_CIPHER_CTX *de = nullptr;
611 :
612 175 : auto finalize = [&] (bool value) {
613 175 : if (de) {
614 175 : EVP_CIPHER_CTX_free(de);
615 175 : de = nullptr;
616 : }
617 175 : return value;
618 175 : };
619 :
620 175 : de = EVP_CIPHER_CTX_new();
621 175 : if (!de) {
622 0 : return finalize(false);
623 : }
624 :
625 175 : if (!EVP_DecryptInit_ex(de, cipher, NULL, key.data.data(), iv)) {
626 0 : return finalize(false);
627 : }
628 :
629 175 : auto target = b.data();
630 175 : auto targetSize = b.size();
631 175 : auto out = output;
632 :
633 175 : int outSize = 0;
634 425 : while (targetSize > 0) {
635 250 : if (!EVP_DecryptUpdate(de, out, &outSize, target, targetSize)) {
636 0 : return finalize(false);
637 : }
638 :
639 250 : out += outSize;
640 250 : target += outSize;
641 250 : if (int(targetSize) > outSize) {
642 75 : targetSize -= outSize;
643 : } else {
644 175 : targetSize = 0;
645 : }
646 : }
647 :
648 175 : EVP_DecryptFinal(de, out, &outSize); // gives false-positive error
649 :
650 175 : cb(BytesView(output, info.dataSize));
651 175 : return finalize(true);
652 175 : },
653 275 : .hash256 = [] (Sha256::Buf &buf, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) -> bool {
654 275 : bool success = true;
655 275 : EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
656 275 : EVP_MD_CTX_init(mdctx);
657 :
658 275 : switch (func) {
659 175 : case HashFunction::SHA_2:
660 175 : if (EVP_DigestInit(mdctx, EVP_sha256()) == 0) {
661 0 : success = false;
662 : }
663 175 : break;
664 100 : case HashFunction::GOST_3411:
665 100 : if (auto md = EVP_get_digestbyname("md_gost12_256")) {
666 100 : if (EVP_DigestInit(mdctx, md) == 0) {
667 0 : success = false;
668 : }
669 : } else {
670 0 : success = false;
671 : }
672 100 : break;
673 : }
674 :
675 275 : if (success) {
676 275 : cb([&] (const CoderSource &data) {
677 275 : if (success && EVP_DigestUpdate(mdctx, data.data(), data.size()) == 0) {
678 0 : success = false;
679 0 : return false;
680 : }
681 275 : return true;
682 : });
683 :
684 275 : if (success && EVP_DigestFinal(mdctx, buf.data(), nullptr) == 0) {
685 0 : success = false;
686 : }
687 : }
688 :
689 275 : EVP_MD_CTX_free(mdctx);
690 275 : return success;
691 : },
692 125 : .hash512 = [] (Sha512::Buf &buf, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) -> bool {
693 125 : bool success = true;
694 125 : EVP_MD_CTX *mdctx = EVP_MD_CTX_new();
695 125 : EVP_MD_CTX_init(mdctx);
696 :
697 125 : switch (func) {
698 25 : case HashFunction::SHA_2:
699 25 : if (EVP_DigestInit(mdctx, EVP_sha512()) == 0) {
700 0 : success = false;
701 : }
702 25 : break;
703 100 : case HashFunction::GOST_3411:
704 100 : if (auto md = EVP_get_digestbyname("md_gost12_512")) {
705 100 : if (EVP_DigestInit(mdctx, md) == 0) {
706 0 : success = false;
707 : }
708 : } else {
709 0 : success = false;
710 : }
711 100 : break;
712 : }
713 :
714 125 : if (success) {
715 125 : cb([&] (const CoderSource &data) {
716 125 : if (success && EVP_DigestUpdate(mdctx, data.data(), data.size()) == 0) {
717 0 : success = false;
718 0 : return false;
719 : }
720 125 : return true;
721 : });
722 :
723 125 : if (success && EVP_DigestFinal(mdctx, buf.data(), nullptr) == 0) {
724 0 : success = false;
725 : }
726 : }
727 :
728 125 : EVP_MD_CTX_free(mdctx);
729 125 : return success;
730 : },
731 800 : .privInit = [] (KeyContext &ctx) -> bool {
732 800 : ctx.keyCtx = nullptr;
733 800 : return true;
734 : },
735 800 : .privFree = [] (KeyContext &ctx) {
736 800 : if (ctx.keyCtx) {
737 800 : EVP_PKEY_free( static_cast<EVP_PKEY *>(ctx.keyCtx) );
738 800 : ctx.keyCtx = nullptr;
739 : }
740 800 : },
741 375 : .privGen = [] (KeyContext &ctx, KeyBits bits, KeyType type) -> bool {
742 375 : EVP_PKEY_CTX *kctx = nullptr;
743 375 : auto finalize = [&] (bool value) {
744 375 : if (kctx) {
745 375 : EVP_PKEY_CTX_free(kctx);
746 375 : kctx = nullptr;
747 : }
748 375 : if (!value) {
749 0 : ctx.keyCtx = nullptr;
750 0 : logOpenSSLErrors();
751 : }
752 375 : return value;
753 375 : };
754 :
755 375 : if (type == KeyType::RSA) {
756 75 : kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
757 75 : if (!kctx) { return finalize(false); }
758 :
759 75 : if (!EVP_PKEY_keygen_init(kctx)) { return finalize(false); }
760 :
761 75 : switch (bits) {
762 25 : case KeyBits::_1024: if (!EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, 1024)) { return finalize(false); } break;
763 25 : case KeyBits::_2048: if (!EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, 2048)) { return finalize(false); } break;
764 25 : case KeyBits::_4096: if (!EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, 4096)) { return finalize(false); } break;
765 : }
766 300 : } else if (type == KeyType::GOST3410_2012_256) {
767 150 : kctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2012_256, NULL);
768 150 : if (!kctx) { return finalize(false); }
769 :
770 150 : EVP_PKEY_paramgen_init(kctx);
771 :
772 150 : EVP_PKEY_CTX_ctrl(kctx, NID_id_GostR3410_2012_256, EVP_PKEY_OP_PARAMGEN, EVP_PKEY_CTRL_GOST_PARAMSET,
773 : NID_id_tc26_gost_3410_2012_256_paramSetA, NULL);
774 :
775 150 : if (!EVP_PKEY_keygen_init(kctx)) { return finalize(false); }
776 :
777 150 : } else if (type == KeyType::GOST3410_2012_512) {
778 100 : kctx = EVP_PKEY_CTX_new_id(NID_id_GostR3410_2012_512, NULL);
779 100 : if (!kctx) { return finalize(false); }
780 :
781 100 : EVP_PKEY_paramgen_init(kctx);
782 :
783 100 : EVP_PKEY_CTX_ctrl(kctx, NID_id_GostR3410_2012_512, EVP_PKEY_OP_PARAMGEN, EVP_PKEY_CTRL_GOST_PARAMSET,
784 : NID_id_tc26_gost_3410_2012_512_paramSetA, NULL);
785 :
786 100 : if (!EVP_PKEY_keygen_init(kctx)) { return finalize(false); }
787 50 : } else if (type == KeyType::ECDSA) {
788 25 : kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
789 25 : if (!kctx) { return finalize(false); }
790 :
791 25 : if (!EVP_PKEY_keygen_init(kctx)) { return finalize(false); }
792 :
793 25 : if (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(kctx, NID_X9_62_prime256v1)) { return finalize(false); }
794 25 : } else if (type == KeyType::EDDSA_ED448) {
795 25 : kctx = EVP_PKEY_CTX_new_id(EVP_PKEY_ED448, NULL);
796 25 : if (!kctx) { return finalize(false); }
797 :
798 25 : if (!EVP_PKEY_keygen_init(kctx)) { return finalize(false); }
799 : } else {
800 0 : log::error("Crypto-openssl", "Unsupported key type for keygen");
801 0 : return finalize(false);
802 : }
803 :
804 375 : EVP_PKEY *ret = nullptr;
805 375 : if (EVP_PKEY_keygen(kctx, &ret)) {
806 375 : ctx.keyCtx = ret;
807 375 : ctx.type = getOpenSSLKeyType(EVP_PKEY_get_id(ret));
808 375 : return finalize(true);
809 : }
810 0 : return finalize(false);
811 : },
812 425 : .privImport = [] (KeyContext &ctx, BytesView data, const CoderSource &passwd) {
813 425 : BIO *bioData = nullptr;
814 :
815 425 : auto finalize = [&] (bool value) {
816 425 : if (bioData) {
817 425 : BIO_free(bioData);
818 425 : bioData = nullptr;
819 : }
820 425 : if (!value) {
821 850 : ctx.keyCtx = nullptr;
822 0 : logOpenSSLErrors();
823 : } else {
824 425 : ctx.type = getOpenSSLKeyType(EVP_PKEY_get_id(static_cast<EVP_PKEY *>(ctx.keyCtx)));
825 : }
826 425 : return value;
827 425 : };
828 :
829 425 : bioData = BIO_new_mem_buf(data.data(), data.size());
830 425 : if (!bioData) {
831 0 : return finalize(false);
832 : }
833 :
834 425 : if (isPemKey(data)) {
835 275 : ctx.keyCtx = PEM_read_bio_PrivateKey(bioData, NULL, [] (char *buf, int size, int rwflag, void *userdata) -> int {
836 75 : auto passwd = static_cast<const CoderSource *>(userdata);
837 75 : int i = passwd->size();
838 75 : i = (i > size) ? size : i;
839 75 : memcpy(buf, passwd->data(), i);
840 75 : return i;
841 : }, const_cast<CoderSource *>(&passwd));
842 :
843 275 : if (ctx.keyCtx) {
844 275 : return finalize(true);
845 : }
846 : } else {
847 150 : if (!passwd.empty()) {
848 75 : ctx.keyCtx = d2i_PKCS8PrivateKey_bio(bioData, NULL, [] (char *buf, int size, int rwflag, void *userdata) -> int {
849 75 : auto passwd = static_cast<const CoderSource *>(userdata);
850 75 : int i = passwd->size();
851 75 : i = (i > size) ? size : i;
852 75 : memcpy(buf, passwd->data(), i);
853 75 : return i;
854 : }, const_cast<CoderSource *>(&passwd));
855 : } else {
856 75 : ctx.keyCtx = d2i_PrivateKey_bio(bioData, NULL);
857 : }
858 :
859 150 : if (ctx.keyCtx) {
860 150 : return finalize(true);
861 : }
862 : }
863 0 : return finalize(false);
864 : },
865 400 : .privExportPem = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) {
866 400 : BIO *bp = nullptr;
867 400 : auto key = static_cast<const EVP_PKEY *>(ctx.keyCtx);
868 :
869 400 : auto finalize = [&] (bool value) {
870 400 : if (bp) {
871 400 : BIO_free(bp);
872 400 : bp = nullptr;
873 : }
874 400 : return value;
875 400 : };
876 :
877 400 : bp = BIO_new(BIO_s_mem());
878 400 : if (!bp) {
879 0 : return finalize(false);
880 : }
881 :
882 400 : switch (fmt) {
883 50 : case KeyFormat::RSA:
884 50 : if (passPhrase.empty()) {
885 50 : if (!PEM_write_bio_PrivateKey_traditional(bp, key, NULL, nullptr, 0, 0, NULL)) {
886 0 : return finalize(false);
887 : }
888 : } else {
889 0 : if (!PEM_write_bio_PrivateKey_traditional(bp, key, EVP_des_ede3_cbc(), const_cast<unsigned char *>(passPhrase.data()), int(passPhrase.size()), 0, NULL)) {
890 0 : return finalize(false);
891 : }
892 : }
893 50 : break;
894 350 : case KeyFormat::PKCS8:
895 350 : if (passPhrase.empty()) {
896 200 : if (!PEM_write_bio_PKCS8PrivateKey(bp, key, NULL, NULL, 0, 0, NULL)) {
897 0 : return finalize(false);
898 : }
899 : } else {
900 150 : if (!PEM_write_bio_PKCS8PrivateKey(bp, key, EVP_des_ede3_cbc(), reinterpret_cast<const char *>(passPhrase.data()), int(passPhrase.size()), 0, NULL)) {
901 0 : return finalize(false);
902 : }
903 : }
904 350 : break;
905 : }
906 :
907 400 : char *buf = nullptr;
908 400 : size_t len = BIO_get_mem_data(bp, &buf);
909 400 : if (len > 0) {
910 400 : cb(BytesView(reinterpret_cast<uint8_t *>(buf), len));
911 400 : return finalize(true);
912 : }
913 :
914 0 : return finalize(false);
915 : },
916 425 : .privExportDer = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) {
917 425 : BIO *bp = nullptr;
918 425 : auto key = static_cast<const EVP_PKEY *>(ctx.keyCtx);
919 :
920 425 : auto finalize = [&] (bool value) {
921 425 : if (bp) {
922 425 : BIO_free(bp);
923 425 : bp = nullptr;
924 : }
925 425 : return value;
926 425 : };
927 :
928 425 : bp = BIO_new(BIO_s_mem());
929 425 : if (!bp) {
930 0 : return finalize(false);
931 : }
932 :
933 425 : switch (fmt) {
934 50 : case KeyFormat::RSA:
935 50 : if (passPhrase.empty()) {
936 50 : if (!i2d_PrivateKey_bio(bp, key)) {
937 0 : return finalize(false);
938 : }
939 : } else {
940 0 : log::error("PrivateKey", "exportDer: passPhrase is not supported for KeyFormat::RSA");
941 0 : return finalize(false);
942 : }
943 50 : break;
944 375 : case KeyFormat::PKCS8:
945 375 : if (passPhrase.empty()) {
946 225 : if (!i2d_PKCS8PrivateKey_bio(bp, key, NULL, NULL, 0, 0, NULL)) {
947 0 : return finalize(false);
948 : }
949 : } else {
950 150 : if (!i2d_PKCS8PrivateKey_bio(bp, key, EVP_des_ede3_cbc(), reinterpret_cast<const char *>(passPhrase.data()), int(passPhrase.size()), 0, NULL)) {
951 0 : return finalize(false);
952 : }
953 : }
954 375 : break;
955 : }
956 :
957 425 : char *buf = nullptr;
958 425 : size_t len = BIO_get_mem_data(bp, &buf);
959 425 : if (len > 0) {
960 425 : cb(BytesView(reinterpret_cast<uint8_t *>(buf), len));
961 425 : return finalize(true);
962 : }
963 :
964 0 : return finalize(false);
965 : },
966 250 : .privExportPublic = [] (KeyContext &target, const KeyContext &privKey) {
967 250 : auto bp = BIO_new(BIO_s_mem());
968 250 : if (!bp) {
969 0 : return false;
970 : }
971 :
972 250 : auto size = i2d_PUBKEY_bio(bp, static_cast<const EVP_PKEY *>(privKey.keyCtx));
973 250 : if (size > 0) {
974 250 : target.keyCtx = d2i_PUBKEY_bio(bp, NULL);
975 250 : target.type = getOpenSSLKeyType(EVP_PKEY_get_id(static_cast<EVP_PKEY *>(target.keyCtx)));
976 : }
977 :
978 250 : BIO_free(bp);
979 250 : return target.keyCtx != nullptr;
980 : },
981 825 : .privSign = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data, SignAlgorithm algo) {
982 825 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
983 825 : EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
984 825 : EVP_PKEY_CTX *pctx = nullptr;
985 825 : unsigned char *sigdata = nullptr;
986 825 : size_t siglen = 0;
987 :
988 825 : auto cleanup = [&] (bool value) {
989 825 : if (mdctx) {
990 825 : EVP_MD_CTX_destroy(mdctx);
991 825 : mdctx = nullptr;
992 : }
993 825 : if (sigdata) {
994 825 : OPENSSL_free(sigdata);
995 825 : sigdata = nullptr;
996 : }
997 825 : return value;
998 825 : };
999 :
1000 825 : if (!mdctx) {
1001 0 : return cleanup(false);
1002 : }
1003 :
1004 825 : switch (algo) {
1005 50 : case SignAlgorithm::RSA_SHA256:
1006 : case SignAlgorithm::ECDSA_SHA256:
1007 50 : if (1 != EVP_DigestSignInit(mdctx, &pctx, (ctx.type == KeyType::EDDSA_ED448) ? nullptr : EVP_sha256(), NULL, key)) {
1008 0 : return cleanup(false);
1009 : }
1010 50 : break;
1011 200 : case SignAlgorithm::RSA_SHA512:
1012 : case SignAlgorithm::ECDSA_SHA512:
1013 200 : if (1 != EVP_DigestSignInit(mdctx, &pctx, (ctx.type == KeyType::EDDSA_ED448) ? nullptr : EVP_sha512(), NULL, key)) {
1014 0 : return cleanup(false);
1015 : }
1016 200 : break;
1017 300 : case SignAlgorithm::GOST_256:
1018 300 : if (auto md = EVP_get_digestbyname("md_gost12_256")) {
1019 300 : if (1 != EVP_DigestSignInit(mdctx, &pctx, md, NULL, key)) {
1020 0 : return cleanup(false);
1021 : }
1022 : } else {
1023 0 : return cleanup(false);
1024 : }
1025 300 : break;
1026 275 : case SignAlgorithm::GOST_512:
1027 275 : if (auto md = EVP_get_digestbyname("md_gost12_512")) {
1028 275 : if (1 != EVP_DigestSignInit(mdctx, &pctx, md, NULL, key)) {
1029 0 : return cleanup(false);
1030 : }
1031 : } else {
1032 0 : return cleanup(false);
1033 : }
1034 275 : break;
1035 : }
1036 825 : if (algo == SignAlgorithm::GOST_256 || algo == SignAlgorithm::GOST_512) {
1037 575 : if (1 != EVP_DigestSignUpdate(mdctx, data.data(), data.size())) {
1038 0 : return cleanup(false);
1039 : }
1040 :
1041 575 : if (1 == EVP_DigestSignFinal(mdctx, NULL, &siglen)) {
1042 575 : sigdata = static_cast<unsigned char *>(OPENSSL_zalloc(sizeof(unsigned char) * siglen));
1043 575 : if (sigdata) {
1044 575 : if (1 == EVP_DigestSignFinal(mdctx, sigdata, &siglen)) {
1045 575 : cb(BytesView(sigdata, siglen));
1046 575 : return cleanup(true);
1047 : } else {
1048 0 : return cleanup(false);
1049 : }
1050 : } else {
1051 0 : return cleanup(false);
1052 : }
1053 : } else {
1054 0 : return cleanup(false);
1055 : }
1056 : } else {
1057 250 : if (1 != EVP_DigestSign(mdctx, NULL, &siglen, data.data(), data.size())) {
1058 0 : return cleanup(false);
1059 : }
1060 :
1061 250 : sigdata = static_cast<unsigned char *>(OPENSSL_malloc(sizeof(unsigned char) * siglen));
1062 250 : if (1 == EVP_DigestSign(mdctx, sigdata, &siglen, data.data(), data.size())) {
1063 250 : cb(BytesView(sigdata, siglen));
1064 250 : return cleanup(true);
1065 : }
1066 : }
1067 0 : return cleanup(false);
1068 : },
1069 175 : .privVerify = [] (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) {
1070 175 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
1071 175 : EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
1072 :
1073 175 : auto cleanup = [&] (bool value) {
1074 175 : if (mdctx) {
1075 175 : EVP_MD_CTX_destroy(mdctx);
1076 175 : mdctx = nullptr;
1077 : }
1078 175 : return value;
1079 175 : };
1080 :
1081 175 : if (!mdctx) {
1082 0 : return cleanup(false);
1083 : }
1084 :
1085 175 : switch (algo) {
1086 25 : case SignAlgorithm::RSA_SHA256:
1087 : case SignAlgorithm::ECDSA_SHA256:
1088 25 : if (!EVP_DigestVerifyInit(mdctx, NULL, (ctx.type == KeyType::EDDSA_ED448) ? nullptr : EVP_sha256(), NULL, key)) {
1089 0 : return cleanup(false);
1090 : }
1091 25 : break;
1092 50 : case SignAlgorithm::RSA_SHA512:
1093 : case SignAlgorithm::ECDSA_SHA512:
1094 50 : if (!EVP_DigestVerifyInit(mdctx, NULL, (ctx.type == KeyType::EDDSA_ED448) ? nullptr : EVP_sha512(), NULL, key)) {
1095 0 : return cleanup(false);
1096 : }
1097 50 : break;
1098 50 : case SignAlgorithm::GOST_256:
1099 50 : if (auto md = EVP_get_digestbyname("md_gost12_256")) {
1100 50 : if (1 != EVP_DigestVerifyInit(mdctx, NULL, md, NULL, key)) {
1101 0 : return cleanup(false);
1102 : }
1103 : } else {
1104 0 : return cleanup(false);
1105 : }
1106 50 : break;
1107 50 : case SignAlgorithm::GOST_512:
1108 50 : if (auto md = EVP_get_digestbyname("md_gost12_512")) {
1109 50 : if (1 != EVP_DigestVerifyInit(mdctx, NULL, md, NULL, key)) {
1110 0 : return cleanup(false);
1111 : }
1112 : } else {
1113 0 : return cleanup(false);
1114 : }
1115 50 : break;
1116 : }
1117 :
1118 : /* Initialize `key` with a public key */
1119 175 : if (!EVP_DigestVerifyUpdate(mdctx, data.data(), data.size())) {
1120 0 : return cleanup(false);
1121 : }
1122 :
1123 175 : if (EVP_DigestVerifyFinal(mdctx, signature.data(), signature.size())) {
1124 175 : return cleanup(true);
1125 : }
1126 :
1127 0 : return cleanup(false);
1128 : },
1129 100 : .privEncrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
1130 100 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
1131 100 : auto pctx = EVP_PKEY_CTX_new(key, nullptr);
1132 :
1133 100 : void *out = nullptr;
1134 :
1135 100 : auto cleanup = [&] (bool value) {
1136 100 : if (out) {
1137 100 : OPENSSL_free(out);
1138 100 : out = nullptr;
1139 : }
1140 100 : if (pctx) {
1141 100 : EVP_PKEY_CTX_free(pctx);
1142 100 : pctx = nullptr;
1143 : }
1144 100 : return value;
1145 100 : };
1146 :
1147 100 : if (EVP_PKEY_encrypt_init(pctx) <= 0) {
1148 0 : return cleanup(false);
1149 : }
1150 :
1151 100 : switch (ctx.type) {
1152 50 : case KeyType::RSA:
1153 50 : if (EVP_PKEY_CTX_set_rsa_padding(pctx, OPENSSL_PK_ENCRYPT_PADDING) <= 0) {
1154 0 : return cleanup(false);
1155 : }
1156 50 : break;
1157 50 : default:
1158 50 : break;
1159 : }
1160 :
1161 : /* Determine buffer length */
1162 : size_t outlen;
1163 100 : if (EVP_PKEY_encrypt(pctx, NULL, &outlen, data.data(), data.size()) <= 0) {
1164 0 : return cleanup(false);
1165 : }
1166 :
1167 100 : out = OPENSSL_malloc(outlen);
1168 :
1169 100 : if (!out) {
1170 0 : return cleanup(false);
1171 : }
1172 :
1173 100 : if (EVP_PKEY_encrypt(pctx, static_cast<uint8_t *>(out), &outlen, data.data(), data.size()) <= 0) {
1174 0 : return cleanup(false);
1175 : }
1176 :
1177 100 : cb(BytesView(static_cast<uint8_t *>(out), outlen));
1178 :
1179 100 : return cleanup(true);
1180 : },
1181 50 : .privDecrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
1182 50 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
1183 50 : auto pctx = EVP_PKEY_CTX_new(key, nullptr);
1184 :
1185 50 : void *out = nullptr;
1186 :
1187 50 : auto cleanup = [&] (bool value) {
1188 50 : if (out) {
1189 50 : OPENSSL_free(out);
1190 50 : out = nullptr;
1191 : }
1192 50 : if (pctx) {
1193 50 : EVP_PKEY_CTX_free(pctx);
1194 50 : pctx = nullptr;
1195 : }
1196 50 : return value;
1197 50 : };
1198 :
1199 50 : if (EVP_PKEY_decrypt_init(pctx) <= 0) {
1200 0 : return cleanup(false);
1201 : }
1202 :
1203 50 : switch (ctx.type) {
1204 50 : case KeyType::RSA:
1205 50 : if (EVP_PKEY_CTX_set_rsa_padding(pctx, OPENSSL_PK_ENCRYPT_PADDING) <= 0) {
1206 0 : return cleanup(false);
1207 : }
1208 50 : break;
1209 0 : default:
1210 0 : break;
1211 : }
1212 :
1213 : /* Determine buffer length */
1214 : size_t outlen;
1215 50 : if (EVP_PKEY_decrypt(pctx, NULL, &outlen, data.data(), data.size()) <= 0) {
1216 0 : return cleanup(false);
1217 : }
1218 :
1219 50 : out = OPENSSL_malloc(outlen);
1220 :
1221 50 : if (!out) {
1222 0 : return cleanup(false);
1223 : }
1224 :
1225 50 : if (EVP_PKEY_decrypt(pctx, static_cast<uint8_t *>(out), &outlen, data.data(), data.size()) <= 0) {
1226 0 : return cleanup(false);
1227 : }
1228 :
1229 50 : cb(BytesView(static_cast<uint8_t *>(out), outlen));
1230 :
1231 50 : return cleanup(true);
1232 : },
1233 375 : .privFingerprint = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
1234 375 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
1235 375 : bool success = false;
1236 375 : switch (ctx.type) {
1237 50 : case KeyType::RSA:
1238 : case KeyType::DSA:
1239 50 : return s_openSSLCtx.privSign(ctx, cb, data, SignAlgorithm::RSA_SHA512);
1240 : break;
1241 0 : case KeyType::ECDSA:
1242 : case KeyType::EDDSA_ED448:
1243 0 : return s_openSSLCtx.privSign(ctx, cb, data, SignAlgorithm::RSA_SHA512);
1244 : break;
1245 150 : case KeyType::GOST3410_2012_256:
1246 : #pragma GCC diagnostic push
1247 : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1248 150 : EVP_PKEY_set1_engine(key, s_ossl_Engine);
1249 150 : success = s_openSSLCtx.privSign(ctx, cb, data, SignAlgorithm::GOST_256);
1250 150 : EVP_PKEY_set1_engine(key, nullptr);
1251 150 : break;
1252 175 : case KeyType::GOST3410_2012_512:
1253 175 : EVP_PKEY_set1_engine(key, s_ossl_Engine);
1254 175 : success = s_openSSLCtx.privSign(ctx, cb, data, SignAlgorithm::GOST_512);
1255 175 : EVP_PKEY_set1_engine(key, nullptr);
1256 : #pragma GCC diagnostic pop
1257 175 : break;
1258 0 : default:
1259 0 : break;
1260 : }
1261 325 : return success;
1262 : },
1263 400 : .pubInit = [] (KeyContext &ctx) -> bool {
1264 400 : ctx.keyCtx = nullptr;
1265 400 : return true;
1266 : },
1267 650 : .pubFree = [] (KeyContext &ctx) {
1268 650 : if (ctx.keyCtx) {
1269 650 : EVP_PKEY_free( static_cast<EVP_PKEY *>(ctx.keyCtx) );
1270 650 : ctx.keyCtx = nullptr;
1271 : }
1272 650 : },
1273 350 : .pubImport = [] (KeyContext &ctx, BytesView data) {
1274 350 : BIO *bioData = nullptr;
1275 :
1276 350 : auto finalize = [&] (bool value) {
1277 350 : if (bioData) {
1278 350 : BIO_free(bioData);
1279 350 : bioData = nullptr;
1280 : }
1281 350 : if (!value) {
1282 0 : ctx.keyCtx = nullptr;
1283 : } else {
1284 350 : ctx.type = getOpenSSLKeyType(EVP_PKEY_get_id(static_cast<EVP_PKEY *>(ctx.keyCtx)));
1285 : }
1286 350 : return value;
1287 350 : };
1288 :
1289 350 : bioData = BIO_new_mem_buf((void*)data.data(), data.size());
1290 350 : if (isPemKey(data)) {
1291 75 : ctx.keyCtx = PEM_read_bio_PUBKEY(bioData, NULL, NULL, NULL);
1292 75 : if (ctx.keyCtx) {
1293 75 : return finalize(true);
1294 : }
1295 : } else {
1296 275 : ctx.keyCtx = d2i_PUBKEY_bio(bioData, NULL);
1297 275 : if (ctx.keyCtx) {
1298 275 : return finalize(true);
1299 : }
1300 : }
1301 0 : return finalize(false);
1302 : },
1303 50 : .pubImportOpenSSH = [] (KeyContext &ctx, StringView r) {
1304 50 : auto origKeyType = r.readUntil<StringView::CharGroup<CharGroupId::WhiteSpace>>();
1305 50 : r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
1306 50 : auto dataBlock = r.readUntil<StringView::CharGroup<CharGroupId::WhiteSpace>>();
1307 50 : dataBlock = dataBlock.readChars<StringView::CharGroup<CharGroupId::Base64>>();
1308 50 : if (valid::validateBase64(dataBlock)) {
1309 50 : uint8_t bytes[base64::decodeSize(dataBlock.size())];
1310 50 : uint8_t *target = bytes;
1311 50 : base64::decode([&] (uint8_t c) {
1312 20350 : *target++ = c;
1313 20350 : }, dataBlock);
1314 50 : BytesViewNetwork dataView(bytes, target - bytes);
1315 50 : auto len = dataView.readUnsigned32();
1316 50 : auto keyType = dataView.readString(len);
1317 :
1318 50 : if (origKeyType != keyType || keyType != "ssh-rsa") {
1319 0 : return false;
1320 : }
1321 :
1322 50 : auto elen = dataView.readUnsigned32();
1323 50 : auto exp = dataView.readBytes(elen);
1324 :
1325 50 : auto mlen = dataView.readUnsigned32();
1326 50 : auto modulus = dataView.readBytes(mlen);
1327 :
1328 : uint8_t out[12_KiB];
1329 50 : uint8_t *buf = out;
1330 50 : buf = writeRSAKey(buf, modulus, exp);
1331 :
1332 50 : std::stringstream stream;
1333 50 : stream << "-----BEGIN RSA PUBLIC KEY-----\n";
1334 50 : base64::encode([&] (char c) {
1335 26600 : stream << c;
1336 50 : }, CoderSource(out, buf - out));
1337 50 : stream << "\n-----END RSA PUBLIC KEY-----\n";
1338 :
1339 50 : BIO *bioData = nullptr;
1340 :
1341 50 : auto finalize = [&] (bool value) {
1342 50 : if (bioData) {
1343 50 : BIO_free(bioData);
1344 50 : bioData = nullptr;
1345 : }
1346 50 : if (!value) {
1347 0 : ctx.keyCtx = nullptr;
1348 : } else {
1349 50 : ctx.type = getOpenSSLKeyType(EVP_PKEY_get_id(static_cast<EVP_PKEY *>(ctx.keyCtx)));
1350 : }
1351 50 : return value;
1352 50 : };
1353 :
1354 50 : std::string tmp = stream.str();
1355 :
1356 50 : bioData = BIO_new_mem_buf(tmp.data(), tmp.size());
1357 50 : ctx.keyCtx = PEM_read_bio_PUBKEY(bioData, NULL, NULL, NULL);
1358 50 : if (ctx.keyCtx) {
1359 50 : return finalize(true);
1360 : }
1361 0 : return finalize(false);
1362 100 : }
1363 0 : return false;
1364 : },
1365 175 : .pubExportPem = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb) {
1366 175 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
1367 175 : BIO *bp = nullptr;
1368 :
1369 175 : auto finalize = [&] (bool value) {
1370 175 : if (bp) {
1371 175 : BIO_free(bp);
1372 175 : bp = nullptr;
1373 : }
1374 175 : return value;
1375 175 : };
1376 :
1377 175 : bp = BIO_new(BIO_s_mem());
1378 175 : if (!bp) {
1379 0 : return finalize(false);
1380 : }
1381 :
1382 175 : if (!PEM_write_bio_PUBKEY(bp, key)) {
1383 0 : return finalize(false);
1384 : }
1385 :
1386 175 : auto len = BIO_pending(bp);
1387 175 : if (len > 0) {
1388 175 : uint8_t buf[len];
1389 :
1390 175 : if (BIO_read(bp, buf, len)) {
1391 175 : cb(BytesView(buf, len));
1392 175 : return finalize(true);
1393 : }
1394 175 : }
1395 0 : return finalize(false);
1396 : },
1397 250 : .pubExportDer = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb) {
1398 250 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
1399 250 : BIO *bp = nullptr;
1400 :
1401 250 : auto finalize = [&] (bool value) {
1402 250 : if (bp) {
1403 250 : BIO_free(bp);
1404 250 : bp = nullptr;
1405 : }
1406 250 : return value;
1407 250 : };
1408 :
1409 :
1410 250 : bp = BIO_new(BIO_s_mem());
1411 250 : if (!bp) {
1412 0 : return finalize(false);
1413 : }
1414 :
1415 250 : if (!i2d_PUBKEY_bio(bp, key)) {
1416 0 : return finalize(false);
1417 : }
1418 :
1419 250 : auto len = BIO_pending(bp);
1420 250 : if (len > 0) {
1421 250 : uint8_t buf[len];
1422 :
1423 250 : if (BIO_read(bp, buf, len)) {
1424 250 : cb(BytesView(buf, len));
1425 250 : return finalize(true);
1426 : }
1427 250 : }
1428 0 : return finalize(false);
1429 : },
1430 325 : .pubVerify = [] (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) {
1431 325 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
1432 325 : EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
1433 :
1434 325 : auto cleanup = [&] (bool value) {
1435 325 : if (mdctx) {
1436 325 : EVP_MD_CTX_destroy(mdctx);
1437 325 : mdctx = nullptr;
1438 : }
1439 325 : return value;
1440 325 : };
1441 :
1442 325 : if (!mdctx) {
1443 0 : return cleanup(false);
1444 : }
1445 :
1446 325 : switch (algo) {
1447 50 : case SignAlgorithm::RSA_SHA256:
1448 : case SignAlgorithm::ECDSA_SHA256:
1449 50 : if (!EVP_DigestVerifyInit(mdctx, NULL, (ctx.type == KeyType::EDDSA_ED448) ? nullptr : EVP_sha256(), NULL, key)) {
1450 0 : return cleanup(false);
1451 : }
1452 50 : break;
1453 75 : case SignAlgorithm::RSA_SHA512:
1454 : case SignAlgorithm::ECDSA_SHA512:
1455 75 : if (!EVP_DigestVerifyInit(mdctx, NULL, (ctx.type == KeyType::EDDSA_ED448) ? nullptr : EVP_sha512(), NULL, key)) {
1456 0 : return cleanup(false);
1457 : }
1458 75 : break;
1459 100 : case SignAlgorithm::GOST_256:
1460 100 : if (auto md = EVP_get_digestbyname("md_gost12_256")) {
1461 100 : if (1 != EVP_DigestVerifyInit(mdctx, NULL, md, NULL, key)) {
1462 0 : return cleanup(false);
1463 : }
1464 : } else {
1465 0 : return cleanup(false);
1466 : }
1467 100 : break;
1468 100 : case SignAlgorithm::GOST_512:
1469 100 : if (auto md = EVP_get_digestbyname("md_gost12_512")) {
1470 100 : if (1 != EVP_DigestVerifyInit(mdctx, NULL, md, NULL, key)) {
1471 0 : return cleanup(false);
1472 : }
1473 : } else {
1474 0 : return cleanup(false);
1475 : }
1476 100 : break;
1477 : }
1478 :
1479 325 : if (EVP_DigestVerify(mdctx, signature.data(), signature.size(), data.data(), data.size()) == 1) {
1480 325 : return cleanup(true);
1481 : }
1482 :
1483 0 : return cleanup(false);
1484 : },
1485 150 : .pubEncrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
1486 150 : auto key = static_cast<EVP_PKEY *>(ctx.keyCtx);
1487 150 : auto pctx = EVP_PKEY_CTX_new(key, nullptr);
1488 :
1489 150 : void *out = nullptr;
1490 :
1491 150 : auto cleanup = [&] (bool value) {
1492 150 : if (out) {
1493 150 : OPENSSL_free(out);
1494 150 : out = nullptr;
1495 : }
1496 150 : if (pctx) {
1497 150 : EVP_PKEY_CTX_free(pctx);
1498 150 : pctx = nullptr;
1499 : }
1500 150 : return value;
1501 150 : };
1502 :
1503 150 : if (EVP_PKEY_encrypt_init(pctx) <= 0) {
1504 0 : return cleanup(false);
1505 : }
1506 :
1507 150 : switch (ctx.type) {
1508 100 : case KeyType::RSA:
1509 100 : if (EVP_PKEY_CTX_set_rsa_padding(pctx, OPENSSL_PK_ENCRYPT_PADDING) <= 0) {
1510 0 : return cleanup(false);
1511 : }
1512 100 : break;
1513 50 : default:
1514 50 : break;
1515 : }
1516 :
1517 : /* Determine buffer length */
1518 : size_t outlen;
1519 150 : if (EVP_PKEY_encrypt(pctx, NULL, &outlen, data.data(), data.size()) <= 0) {
1520 0 : return cleanup(false);
1521 : }
1522 :
1523 150 : out = OPENSSL_malloc(outlen);
1524 :
1525 150 : if (!out) {
1526 0 : return cleanup(false);
1527 : }
1528 :
1529 150 : if (EVP_PKEY_encrypt(pctx, static_cast<uint8_t *>(out), &outlen, data.data(), data.size()) <= 0) {
1530 0 : return cleanup(false);
1531 : }
1532 :
1533 150 : cb(BytesView(static_cast<uint8_t *>(out), outlen));
1534 :
1535 150 : return cleanup(true);
1536 : }
1537 : };
1538 :
1539 : BackendCtxRef s_openSSLRef(&s_openSSLCtx);
1540 :
1541 : }
1542 :
1543 : #endif
|