LCOV - code coverage report
Current view: top level - core/crypto - SPCrypto-openssl.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 737 917 80.4 %
Date: 2024-05-12 00:16:13 Functions: 59 59 100.0 %

          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

Generated by: LCOV version 1.14