LCOV - code coverage report
Current view: top level - core/crypto - SPCrypto-gnutls.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 429 498 86.1 %
Date: 2024-05-12 00:16:13 Functions: 41 41 100.0 %

          Line data    Source code
       1             : /**
       2             : Copyright (c) 2021 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 "SPValid.h"
      27             : #include "SPCrypto.h"
      28             : 
      29             : #if __CDT_PARSER__
      30             : #define MODULE_STAPPLER_CRYPTO_GNUTLS 1
      31             : #endif
      32             : 
      33             : #if MODULE_STAPPLER_CRYPTO_GNUTLS
      34             : 
      35             : #include "SPCryptoAsn1.h"
      36             : 
      37             : #include <gnutls/abstract.h>
      38             : #include <gnutls/crypto.h>
      39             : #include <gnutls/gnutls.h>
      40             : #include <nettle/bignum.h>
      41             : #include <nettle/gostdsa.h>
      42             : #include <nettle/ecc.h>
      43             : #include <nettle/ecc-curve.h>
      44             : #include <gmp.h>
      45             : 
      46             : namespace STAPPLER_VERSIONIZED stappler::crypto {
      47             : 
      48             : struct Hook_GnuTLS_RandomData {
      49             :         const Gost3411_512::Buf *buf;
      50             :         size_t offset;
      51             : };
      52             : 
      53         125 : static void hook_gnutls_random_func(void *ctx, size_t length, uint8_t *dst) {
      54         125 :         Hook_GnuTLS_RandomData *data = static_cast<Hook_GnuTLS_RandomData *>(ctx);
      55         125 :         memcpy(dst, data->buf->data() + data->offset, length);
      56         125 :         data->offset += length;
      57         125 : }
      58             : 
      59         500 : static void hook_gnutls_mpi_print(const mpz_t *p, void *buffer, size_t *nbytes) {
      60         500 :         unsigned int size = nettle_mpz_sizeinbase_256_u(*p);
      61         500 :         if (buffer) {
      62         250 :                 nettle_mpz_get_str_256(size, static_cast<uint8_t *>(buffer), *p);
      63             :         }
      64         500 :         *nbytes = size;
      65         500 : }
      66             : 
      67         250 : static void hook_gnutls_mpi_bprint_size(const mpz_t *a, uint8_t *buf, size_t size) {
      68         250 :         size_t bytes = 0;
      69         250 :         hook_gnutls_mpi_print(a, NULL, &bytes);
      70             : 
      71         250 :         if (bytes <= size) {
      72             :                 unsigned i;
      73         250 :                 size_t diff = size - bytes;
      74             : 
      75         250 :                 for (i = 0; i < diff; i++) {
      76           0 :                         buf[i] = 0;
      77             :                 }
      78         250 :                 hook_gnutls_mpi_print(a, &buf[diff], &bytes);
      79             :         } else {
      80           0 :                 hook_gnutls_mpi_print(a, buf, &bytes);
      81             :         }
      82         250 : }
      83             : 
      84         125 : static bool hook_gnutls_sign_gost(gnutls_privkey_t key, BytesView hash, const Callback<void(BytesView)> &cb) {
      85             :         gnutls_ecc_curve_t c;
      86             :         gnutls_digest_algorithm_t digest;
      87             :         gnutls_gost_paramset_t paramset;
      88             :         gnutls_datum_t k;
      89         125 :         gnutls_privkey_export_gost_raw2(key, &c, &digest, &paramset, nullptr, nullptr, &k, 0);
      90             : 
      91             :         struct ecc_scalar priv;
      92             :         struct dsa_signature sig;
      93             :         const struct ecc_curve *curve;
      94             : 
      95         125 :         switch (c) {
      96          50 :         case GNUTLS_ECC_CURVE_GOST256CPA:
      97             :         case GNUTLS_ECC_CURVE_GOST256CPXA:
      98             :         case GNUTLS_ECC_CURVE_GOST256B:
      99          50 :                 curve = nettle_get_gost_gc256b();
     100          50 :                 break;
     101          75 :         case GNUTLS_ECC_CURVE_GOST512A:
     102          75 :                 curve = nettle_get_gost_gc512a();
     103          75 :                 break;
     104           0 :         default:
     105           0 :                 break;
     106             :         }
     107             : 
     108         125 :         if (!curve) {
     109           0 :                 gnutls_free(k.data);
     110           0 :                 return false;
     111             :         }
     112             : 
     113             :         mpz_t privKeyK;
     114         125 :         mpz_init(privKeyK);
     115         125 :         mpz_import(privKeyK, k.size, -1, 1, 0, 0, k.data);
     116             : 
     117         125 :         ecc_scalar_init(&priv, curve);
     118         125 :         if (ecc_scalar_set(&priv, privKeyK) == 0) {
     119           0 :                 ecc_scalar_clear(&priv);
     120             :         }
     121             : 
     122         125 :         dsa_signature_init(&sig);
     123             : 
     124         125 :         auto randSeed = Gost3411_512::hmac(BytesView(k.data, k.size), hash);
     125             : 
     126         125 :         Hook_GnuTLS_RandomData randomData { &randSeed, 0 };
     127             : 
     128         125 :         gostdsa_sign(&priv, &randomData, hook_gnutls_random_func, hash.size(), hash.data(), &sig);
     129             : 
     130         125 :         auto intsize = (ecc_bit_size(curve) + 7) / 8;
     131         125 :         uint8_t data[intsize * 2];
     132             : 
     133         125 :         hook_gnutls_mpi_bprint_size(&sig.s, data, intsize);
     134         125 :         hook_gnutls_mpi_bprint_size(&sig.r, data + intsize, intsize);
     135             : 
     136         125 :         cb(BytesView(data, intsize * 2));
     137             : 
     138         125 :         dsa_signature_clear(&sig);
     139         125 :         ecc_scalar_clear(&priv);
     140         125 :         mpz_clear(privKeyK);
     141             : 
     142         125 :         gnutls_free(k.data);
     143             : 
     144         125 :         return true;
     145             : }
     146             : 
     147        1025 : static gnutls_sign_algorithm_t getGnuTLSAlgo(SignAlgorithm a) {
     148        1025 :         switch (a) {
     149         125 :         case SignAlgorithm::RSA_SHA256: return GNUTLS_SIGN_RSA_SHA256; break;
     150         600 :         case SignAlgorithm::RSA_SHA512: return GNUTLS_SIGN_RSA_SHA512; break;
     151           0 :         case SignAlgorithm::ECDSA_SHA256: return GNUTLS_SIGN_ECDSA_SHA256; break;
     152           0 :         case SignAlgorithm::ECDSA_SHA512: return GNUTLS_SIGN_ECDSA_SHA512; break;
     153         150 :         case SignAlgorithm::GOST_256: return GNUTLS_SIGN_GOST_256; break;
     154         150 :         case SignAlgorithm::GOST_512: return GNUTLS_SIGN_GOST_512; break;
     155             :         }
     156           0 :         return GNUTLS_SIGN_UNKNOWN;
     157             : }
     158             : 
     159         625 : static gnutls_cipher_algorithm_t getGnuTLSAlgo(BlockCipher b) {
     160         625 :         switch (b) {
     161         275 :         case BlockCipher::AES_CBC:
     162         275 :                 return GNUTLS_CIPHER_AES_256_CBC;
     163             :                 break;
     164           0 :         case BlockCipher::AES_CFB8:
     165           0 :                 return GNUTLS_CIPHER_AES_256_CFB8;
     166             :                 break;
     167         350 :         case BlockCipher::Gost3412_2015_CTR_ACPKM:
     168         350 :                 return GNUTLS_CIPHER_KUZNYECHIK_CTR_ACPKM;
     169             :                 break;
     170             :         }
     171           0 :         return GNUTLS_CIPHER_AES_256_CBC;
     172             : }
     173             : 
     174        1625 : static KeyType getGnuTLSKeyType(int a) {
     175        1625 :         switch (a) {
     176        1050 :         case GNUTLS_PK_RSA: return KeyType::RSA; break;
     177           0 :         case GNUTLS_PK_DSA: return KeyType::DSA; break;
     178           0 :         case GNUTLS_PK_DH: break;
     179           0 :         case GNUTLS_PK_ECDSA: return KeyType::ECDSA; break;
     180           0 :         case GNUTLS_PK_RSA_PSS: break;
     181           0 :         case GNUTLS_PK_EDDSA_ED25519: break;
     182           0 :         case GNUTLS_PK_GOST_01: break;
     183         300 :         case GNUTLS_PK_GOST_12_256: return KeyType::GOST3410_2012_256; break;
     184         275 :         case GNUTLS_PK_GOST_12_512: return KeyType::GOST3410_2012_512; break;
     185           0 :         case GNUTLS_PK_EDDSA_ED448: return KeyType::EDDSA_ED448; break;
     186           0 :         default:
     187           0 :                 break;
     188             :         }
     189           0 :         return KeyType::Unknown;
     190             : }
     191             : 
     192             : struct Pkcs1RsaPubKeyReader {
     193             :         using Decoder = Asn1Decoder<memory::StandartInterface, Pkcs1RsaPubKeyReader>;
     194             : 
     195             :         enum State {
     196             :                 Init,
     197             :                 Seq,
     198             :                 Exp,
     199             :                 Mod,
     200             :                 Fin,
     201             :                 Invalid
     202             :         };
     203             : 
     204          25 :         Pkcs1RsaPubKeyReader(const BytesViewNetwork &source) {
     205             :                 Decoder dec;
     206          25 :                 dec.decode(*this, source);
     207          25 :         }
     208             : 
     209          25 :         void onBeginSequence(Decoder &) {
     210          25 :                 if (state == Init) {
     211          25 :                         state = Seq;
     212             :                 } else {
     213           0 :                         state = Invalid;
     214             :                 }
     215          25 :         }
     216          25 :         void onEndSequence(Decoder &) {
     217          25 :                 if (state == Exp) {
     218          25 :                         state = Fin;
     219             :                 } else {
     220           0 :                         state = Invalid;
     221             :                 }
     222          25 :         }
     223             : 
     224          50 :         void onBigInteger(Decoder &, const BytesViewNetwork &val) {
     225          50 :                 switch (state) {
     226          25 :                 case Seq:
     227          25 :                         mod = val;
     228          25 :                         state = Mod;
     229          25 :                         break;
     230          25 :                 case Mod:
     231          25 :                         exp = val;
     232          25 :                         state = Exp;
     233          25 :                         break;
     234           0 :                 default:
     235           0 :                         state = Invalid;
     236           0 :                         break;
     237             :                 }
     238          50 :         }
     239             : 
     240             :         SP_COVERAGE_TRIVIAL
     241             :         void onCustom(Decoder &, uint8_t, const BytesViewNetwork &val) {
     242             :                 state = Invalid;
     243             :         }
     244             : 
     245             :         State state = State::Init;
     246             :         BytesViewNetwork exp;
     247             :         BytesViewNetwork mod;
     248             : };
     249             : 
     250             : static BackendCtx s_gnuTLSCtx = {
     251             :         .name = Backend::GnuTLS,
     252             :         .title = StringView("GnuTLS"),
     253             :         .flags = BackendFlags::SupportsPKCS1 | BackendFlags::SupportsPKCS8 | BackendFlags::SupportsAes | BackendFlags::SecureLibrary
     254             :                 | BackendFlags::SupportsGost3410_2012 | BackendFlags::SupportsGost3412_2015,
     255          25 :         .initialize = [] () {
     256          25 :                 log::verbose("Crypto", "GnuTLS backend loaded: ", gnutls_check_version("3.0.0"));
     257             :                 /*gnutls_global_set_log_level(9);
     258             :                 gnutls_global_set_log_function([] (int l, const char *data) {
     259             :                         log::verbose("GnuTLS", l, ": ", data);
     260             :                 })*/;
     261          25 :                 gnutls_global_init();
     262          25 :         },
     263          25 :         .finalize = [] () {
     264          25 :                 gnutls_global_deinit();
     265          25 :         },
     266         350 :         .encryptBlock = [] (const BlockKey256 &key, BytesView d, const Callback<void(BytesView)> &cb) -> bool {
     267         350 :                 auto cipherBlockSize = getBlockSize(key.cipher);
     268         350 :                 auto algo = getGnuTLSAlgo(key.cipher);
     269             : 
     270         350 :                 uint64_t dataSize = d.size();
     271         350 :                 auto blockSize = math::align<size_t>(dataSize, cipherBlockSize)
     272         350 :                                 + cipherBlockSize; // allocate space for possible padding
     273             : 
     274         350 :                 uint8_t output[blockSize + sizeof(BlockCryptoHeader)];
     275             : 
     276         350 :                 uint8_t iv[16] = { 0 };
     277         350 :                 gnutls_datum_t ivData = {
     278             :                         .data = static_cast<unsigned char *>(iv),
     279             :                         .size = static_cast<unsigned int>(16)
     280         350 :                 };
     281             : 
     282             :                 gnutls_datum_t keyData = {
     283         350 :                         .data = const_cast<unsigned char *>(static_cast<const unsigned char *>(key.data.data())),
     284         350 :                         .size = static_cast<unsigned int>(key.data.size())
     285         350 :                 };
     286             : 
     287             :                 gnutls_cipher_hd_t aes;
     288         350 :                 auto err = gnutls_cipher_init(&aes, algo, &keyData, &ivData);
     289         350 :                 if (err != 0) {
     290           0 :                         log::error("Crypto", "gnutls_cipher_init() = [", err, "] ", gnutls_strerror(err));
     291           0 :                         return false;
     292             :                 }
     293             : 
     294         350 :                 size_t outSize = blockSize - sizeof(BlockCryptoHeader);
     295         350 :                 fillCryptoBlockHeader(output, key, d);
     296             : 
     297             :                 if constexpr (SafeBlockEncoding) {
     298         350 :                         memcpy(output + sizeof(BlockCryptoHeader), d.data(), d.size());
     299         350 :                         memset(output + sizeof(BlockCryptoHeader) + d.size(), 0, blockSize - d.size());
     300         350 :                         err = gnutls_cipher_encrypt(aes, output + sizeof(BlockCryptoHeader), outSize);
     301             :                 } else {
     302             :                         err = gnutls_cipher_encrypt2(aes, d.data(), math::align<size_t>(dataSize, cipherBlockSize), output + sizeof(BlockCryptoHeader), outSize);
     303             :                 }
     304             : 
     305         350 :                 if (err != 0) {
     306           0 :                         gnutls_cipher_deinit(aes);
     307           0 :                         log::error("Crypto", "gnutls_cipher_encrypt() = [", err, "] ", gnutls_strerror(err));
     308           0 :                         return false;
     309             :                 }
     310             : 
     311         350 :                 gnutls_cipher_deinit(aes);
     312         350 :                 cb(BytesView(output, blockSize + sizeof(BlockCryptoHeader) - cipherBlockSize));
     313         350 :                 return true;
     314         350 :         },
     315         275 :         .decryptBlock = [] (const BlockKey256 &key, BytesView b, const Callback<void(BytesView)> &cb) -> bool {
     316         275 :                 auto info = getBlockInfo(b);
     317         275 :                 auto cipherBlockSize = getBlockSize(info.cipher);
     318         275 :                 auto algo = getGnuTLSAlgo(info.cipher);
     319             : 
     320         275 :                 auto blockSize = math::align<size_t>(info.dataSize, cipherBlockSize) + cipherBlockSize;
     321         275 :                 b.offset(sizeof(BlockCryptoHeader));
     322             : 
     323         275 :                 uint8_t output[blockSize];
     324             : 
     325         275 :                 uint8_t iv[16] = { 0 };
     326         275 :                 gnutls_datum_t ivData = {
     327             :                         .data = static_cast<unsigned char *>(iv),
     328             :                         .size = static_cast<unsigned int>(16)
     329         275 :                 };
     330             : 
     331             :                 gnutls_datum_t keyData = {
     332         275 :                         .data = const_cast<unsigned char *>(static_cast<const unsigned char *>(key.data.data())),
     333         275 :                         .size = static_cast<unsigned int>(key.data.size())
     334         275 :                 };
     335             : 
     336             :                 gnutls_cipher_hd_t aes;
     337         275 :                 auto err = gnutls_cipher_init(&aes, algo, &keyData, &ivData);
     338         275 :                 if (err != 0) {
     339           0 :                         log::error("Crypto", "gnutls_cipher_init() = [", err, "] ", gnutls_strerror(err));
     340           0 :                         return false;
     341             :                 }
     342             : 
     343         275 :                 err = gnutls_cipher_decrypt2(aes, b.data(), b.size(), output, blockSize);
     344         275 :                 if (err != 0) {
     345           0 :                         gnutls_cipher_deinit(aes);
     346           0 :                         log::error("Crypto", "gnutls_cipher_decrypt2() = [", err, "] ", gnutls_strerror(err));
     347           0 :                         return false;
     348             :                 }
     349             : 
     350         275 :                 gnutls_cipher_deinit(aes);
     351         275 :                 cb(BytesView(output, info.dataSize));
     352         275 :                 return true;
     353         275 :         },
     354         725 :         .hash256 = [] (Sha256::Buf &buf, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) -> bool {
     355             :                 gnutls_hash_hd_t hash;
     356         725 :                 switch (func) {
     357         425 :                 case HashFunction::SHA_2:
     358         425 :                         if (gnutls_hash_init(&hash, GNUTLS_DIG_SHA256) != GNUTLS_E_SUCCESS) {
     359           0 :                                 return false;
     360             :                         }
     361         425 :                         break;
     362         300 :                 case HashFunction::GOST_3411:
     363         300 :                         if (gnutls_hash_init(&hash, GNUTLS_DIG_STREEBOG_256) != GNUTLS_E_SUCCESS) {
     364           0 :                                 return false;
     365             :                         }
     366         300 :                         break;
     367             :                 }
     368             : 
     369         725 :                 bool success = true;
     370         725 :                 cb([&] (const CoderSource &data) {
     371         725 :                         if (success && gnutls_hash(hash, data.data(), data.size()) != GNUTLS_E_SUCCESS) {
     372           0 :                                 success = false;
     373           0 :                                 return false;
     374             :                         }
     375         725 :                         return true;
     376             :                 });
     377         725 :                 gnutls_hash_deinit(hash, buf.data());
     378         725 :                 return success;
     379             :         },
     380         625 :         .hash512 = [] (Sha512::Buf &buf, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) -> bool {
     381             :                 gnutls_hash_hd_t hash;
     382         625 :                 switch (func) {
     383          50 :                 case HashFunction::SHA_2:
     384          50 :                         if (gnutls_hash_init(&hash, GNUTLS_DIG_SHA512) != GNUTLS_E_SUCCESS) {
     385           0 :                                 return false;
     386             :                         }
     387          50 :                         break;
     388         575 :                 case HashFunction::GOST_3411:
     389         575 :                         if (gnutls_hash_init(&hash, GNUTLS_DIG_STREEBOG_512) != GNUTLS_E_SUCCESS) {
     390           0 :                                 return false;
     391             :                         }
     392         575 :                         break;
     393             :                 }
     394             : 
     395         625 :                 bool success = true;
     396         625 :                 cb([&] (const CoderSource &data) {
     397        2550 :                         if (success && gnutls_hash(hash, data.data(), data.size()) != GNUTLS_E_SUCCESS) {
     398           0 :                                 success = false;
     399           0 :                                 return false;
     400             :                         }
     401        2550 :                         return true;
     402             :                 });
     403         625 :                 gnutls_hash_deinit(hash, buf.data());
     404         625 :                 return success;
     405             :         },
     406        1225 :         .privInit = [] (KeyContext &ctx) -> bool {
     407        1225 :                 auto err = gnutls_privkey_init( reinterpret_cast<gnutls_privkey_t *>(&ctx.keyCtx) );
     408        1225 :                 if (err == GNUTLS_E_SUCCESS) {
     409        1225 :                         return true;
     410             :                 }
     411           0 :                 return false;
     412             :         },
     413        1200 :         .privFree = [] (KeyContext &ctx) {
     414        1200 :                 gnutls_privkey_deinit( static_cast<gnutls_privkey_t>(ctx.keyCtx) );
     415        1200 :         },
     416         275 :         .privGen = [] (KeyContext &ctx, KeyBits bits, KeyType type) -> bool {
     417         275 :                 auto key = static_cast<gnutls_privkey_t>(ctx.keyCtx);
     418             : 
     419         275 :                 int err = 0;
     420             : 
     421         275 :                 switch (type) {
     422           0 :                 case KeyType::Unknown:
     423             :                 case KeyType::DSA:
     424             :                 case KeyType::ECDSA:
     425             :                 case KeyType::EDDSA_ED448:
     426           0 :                         log::error("Crypto-gnutls", "Unsupported key type for keygen");
     427           0 :                         return false;
     428             :                         break;
     429         125 :                 case KeyType::GOST3410_2012_256:
     430         125 :                         err = gnutls_privkey_generate(key, GNUTLS_PK_GOST_12_256, 512, 0);
     431         125 :                         break;
     432          75 :                 case KeyType::GOST3410_2012_512:
     433          75 :                         err = gnutls_privkey_generate(key, GNUTLS_PK_GOST_12_512, 512, 0);
     434          75 :                         break;
     435          75 :                 case KeyType::RSA:
     436             :                         switch (bits) {
     437          25 :                         case KeyBits::_1024: err = gnutls_privkey_generate(key, GNUTLS_PK_RSA, 1024, 0); break;
     438          25 :                         case KeyBits::_2048: err = gnutls_privkey_generate(key, GNUTLS_PK_RSA, 2048, 0); break;
     439          25 :                         case KeyBits::_4096: err = gnutls_privkey_generate(key, GNUTLS_PK_RSA, 4096, 0); break;
     440             :                         }
     441          75 :                         break;
     442             :                 }
     443             : 
     444         275 :                 if (err == GNUTLS_E_SUCCESS) {
     445         275 :                         ctx.type = getGnuTLSKeyType(gnutls_privkey_get_pk_algorithm(key, nullptr));
     446         275 :                         return true;
     447             :                 }
     448             : 
     449           0 :                 return false;
     450             :         },
     451         875 :         .privImport = [] (KeyContext &ctx, BytesView data, const CoderSource &passwd) {
     452             :                 gnutls_datum_t keyData;
     453         875 :                 keyData.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(data.data()));
     454         875 :                 keyData.size = static_cast<unsigned int>(data.size());
     455             : 
     456         875 :                 auto key = static_cast<gnutls_privkey_t>(ctx.keyCtx);
     457         875 :                 if (isPemKey(data)) {
     458         500 :                         if (gnutls_privkey_import_x509_raw(key, &keyData, GNUTLS_X509_FMT_PEM,
     459         925 :                                         reinterpret_cast<const char *>(passwd._data.empty() ? nullptr : passwd._data.data()), 0) == GNUTLS_E_SUCCESS) {
     460         425 :                                 ctx.type = getGnuTLSKeyType(gnutls_privkey_get_pk_algorithm(key, nullptr));
     461         425 :                                 return true;
     462             :                         }
     463             :                 } else {
     464         525 :                         if (gnutls_privkey_import_x509_raw(key, &keyData, GNUTLS_X509_FMT_DER,
     465         975 :                                         reinterpret_cast<const char *>(passwd._data.empty() ? nullptr : passwd._data.data()), 0) == GNUTLS_E_SUCCESS) {
     466         275 :                                 ctx.type = getGnuTLSKeyType(gnutls_privkey_get_pk_algorithm(key, nullptr));
     467         275 :                                 return true;
     468             :                         }
     469             :                 }
     470         175 :                 return false;
     471             :         },
     472         400 :         .privExportPem = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) {
     473         400 :                 auto key = static_cast<gnutls_privkey_t>(ctx.keyCtx);
     474         400 :                 bool success = false;
     475             :                 gnutls_datum_t out;
     476             :                 gnutls_x509_privkey_t pk;
     477         400 :                 if (gnutls_privkey_export_x509(key, &pk) == GNUTLS_E_SUCCESS) {
     478         400 :                         switch (fmt) {
     479          50 :                         case KeyFormat::PKCS1:
     480          50 :                                 if (!passPhrase.empty()) {
     481           0 :                                         log::error("Crypto", "Password-encoding is not supported for PKCS1");
     482             :                                 }
     483          50 :                                 if (gnutls_x509_privkey_export2(pk, GNUTLS_X509_FMT_PEM, &out) == GNUTLS_E_SUCCESS) {
     484          50 :                                         cb(BytesView(out.data, out.size));
     485          50 :                                         gnutls_free(out.data);
     486          50 :                                         success = true;
     487             :                                 }
     488          50 :                                 break;
     489         350 :                         case KeyFormat::PKCS8:
     490         350 :                                 if (!passPhrase.empty()) {
     491         300 :                                         char buf[passPhrase.size() + 1];
     492         150 :                                         memcpy(buf, passPhrase.data(), passPhrase.size());
     493         150 :                                         buf[passPhrase.size()] = 0;
     494         150 :                                         if (gnutls_x509_privkey_export2_pkcs8(pk, GNUTLS_X509_FMT_PEM, buf, 0, &out) == GNUTLS_E_SUCCESS) {
     495         150 :                                                 cb(BytesView(out.data, out.size));
     496         150 :                                                 gnutls_free(out.data);
     497         150 :                                                 success = true;
     498             :                                         }
     499         150 :                                 } else {
     500         200 :                                         if (gnutls_x509_privkey_export2_pkcs8(pk, GNUTLS_X509_FMT_PEM, nullptr, 0, &out) == GNUTLS_E_SUCCESS) {
     501         200 :                                                 cb(BytesView(out.data, out.size));
     502         200 :                                                 gnutls_free(out.data);
     503         200 :                                                 success = true;
     504             :                                         }
     505             :                                 }
     506         350 :                                 break;
     507             :                         }
     508         400 :                         gnutls_x509_privkey_deinit(pk);
     509             :                 }
     510         400 :                 return success;
     511             :         },
     512         425 :         .privExportDer = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) {
     513         425 :                 auto key = static_cast<gnutls_privkey_t>(ctx.keyCtx);
     514         425 :                 bool success = false;
     515             :                 gnutls_datum_t out;
     516             :                 gnutls_x509_privkey_t pk;
     517         425 :                 if (gnutls_privkey_export_x509(key, &pk) == GNUTLS_E_SUCCESS) {
     518         425 :                         switch (fmt) {
     519          50 :                         case KeyFormat::PKCS1:
     520          50 :                                 if (!passPhrase.empty()) {
     521           0 :                                         log::error("Crypto", "Password-encoding is not supported for PKCS1");
     522             :                                 }
     523          50 :                                 if (gnutls_x509_privkey_export2(pk, GNUTLS_X509_FMT_DER, &out) == GNUTLS_E_SUCCESS) {
     524          50 :                                         cb(BytesView(out.data, out.size));
     525          50 :                                         gnutls_free(out.data);
     526          50 :                                         success = true;
     527             :                                 }
     528          50 :                                 break;
     529         375 :                         case KeyFormat::PKCS8:
     530         375 :                                 if (!passPhrase.empty()) {
     531         300 :                                         char buf[passPhrase.size() + 1];
     532         150 :                                         memcpy(buf, passPhrase.data(), passPhrase.size());
     533         150 :                                         buf[passPhrase.size()] = 0;
     534         150 :                                         if (gnutls_x509_privkey_export2_pkcs8(pk, GNUTLS_X509_FMT_DER, buf, 0, &out) == GNUTLS_E_SUCCESS) {
     535         150 :                                                 cb(BytesView(out.data, out.size));
     536         150 :                                                 gnutls_free(out.data);
     537         150 :                                                 success = true;
     538             :                                         }
     539         150 :                                 } else {
     540         225 :                                         if (gnutls_x509_privkey_export2_pkcs8(pk, GNUTLS_X509_FMT_DER, nullptr, 0, &out) == GNUTLS_E_SUCCESS) {
     541         225 :                                                 cb(BytesView(out.data, out.size));
     542         225 :                                                 gnutls_free(out.data);
     543         225 :                                                 success = true;
     544             :                                         }
     545             :                                 }
     546         375 :                                 break;
     547             :                         }
     548         425 :                         gnutls_x509_privkey_deinit(pk);
     549             :                 }
     550         425 :                 return success;
     551             :         },
     552         150 :         .privExportPublic = [] (KeyContext &target, const KeyContext &privKey) {
     553         150 :                 auto err = gnutls_pubkey_init( reinterpret_cast<gnutls_pubkey_t *>(&target.keyCtx) );
     554         150 :                 if (err == GNUTLS_E_SUCCESS) {
     555         300 :                         if (gnutls_pubkey_import_privkey(static_cast<gnutls_pubkey_t>(target.keyCtx),
     556         150 :                                         static_cast<gnutls_privkey_t>(privKey.keyCtx), 0, 0) != GNUTLS_E_SUCCESS) {
     557           0 :                                 gnutls_pubkey_deinit( static_cast<gnutls_pubkey_t>(target.keyCtx) );
     558             :                         } else {
     559         150 :                                 target.type = getGnuTLSKeyType(gnutls_pubkey_get_pk_algorithm(static_cast<gnutls_pubkey_t>(target.keyCtx), nullptr));
     560         150 :                                 return true;
     561             :                         }
     562             :                 } else {
     563           0 :                         log::error("Crypto", "gnutls_pubkey_init() = [", err, "] ", gnutls_strerror(err));
     564             :                 }
     565           0 :                 return false;
     566             :         },
     567         625 :         .privSign = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data, SignAlgorithm algo) {
     568         625 :                 auto key = static_cast<gnutls_privkey_t>(ctx.keyCtx);
     569             : 
     570             :                 gnutls_datum_t dataToSign;
     571         625 :                 dataToSign.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(data.data()));
     572         625 :                 dataToSign.size = static_cast<unsigned int>(data.size());
     573             : 
     574             :                 gnutls_datum_t signature;
     575             : 
     576         625 :                 if (gnutls_privkey_sign_data2(key, getGnuTLSAlgo(algo), 0, &dataToSign, &signature) == GNUTLS_E_SUCCESS) {
     577         625 :                         cb(BytesView(signature.data, signature.size));
     578         625 :                         gnutls_free(signature.data);
     579         625 :                         return true;
     580             :                 }
     581           0 :                 return false;
     582             :         },
     583         175 :         .privVerify = [] (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) {
     584         175 :                 auto key = static_cast<gnutls_privkey_t>(ctx.keyCtx);
     585         175 :                 bool success = false;
     586             : 
     587             :                 gnutls_pubkey_t pubkey;
     588         175 :                 auto err = gnutls_pubkey_init( &pubkey );
     589         175 :                 if (err == GNUTLS_E_SUCCESS) {
     590         175 :                         if (gnutls_pubkey_import_privkey(pubkey, key, 0, 0) == GNUTLS_E_SUCCESS) {
     591             :                                 gnutls_datum_t inputData;
     592         175 :                                 inputData.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(data.data()));
     593         175 :                                 inputData.size = static_cast<unsigned int>(data.size());
     594             : 
     595             :                                 gnutls_datum_t signatureData;
     596         175 :                                 signatureData.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(signature.data()));
     597         175 :                                 signatureData.size = static_cast<unsigned int>(signature.size());
     598             : 
     599         175 :                                 success = gnutls_pubkey_verify_data2(pubkey, getGnuTLSAlgo(algo), 0, &inputData, &signatureData) >= 0;
     600             :                         }
     601         175 :                         gnutls_pubkey_deinit(pubkey);
     602             :                 } else {
     603           0 :                         log::error("Crypto", "gnutls_pubkey_init() = [", err, "] ", gnutls_strerror(err));
     604             :                 }
     605         175 :                 return success;
     606             :         },
     607         125 :         .privEncrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
     608         125 :                 auto key = static_cast<gnutls_privkey_t>(ctx.keyCtx);
     609         125 :                 bool success = false;
     610             : 
     611             :                 gnutls_pubkey_t pubkey;
     612         125 :                 auto err = gnutls_pubkey_init( &pubkey );
     613         125 :                 if (err == GNUTLS_E_SUCCESS) {
     614         125 :                         auto err = gnutls_pubkey_import_privkey(pubkey, key, 0, 0);
     615         125 :                         if (err == GNUTLS_E_SUCCESS) {
     616             :                                 gnutls_datum_t dataToEncrypt;
     617         125 :                                 dataToEncrypt.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(data.data()));
     618         125 :                                 dataToEncrypt.size = static_cast<unsigned int>(data.size());
     619             : 
     620             :                                 gnutls_datum_t output;
     621             : 
     622         125 :                                 err = gnutls_pubkey_encrypt_data(pubkey, 0, &dataToEncrypt, &output);
     623         125 :                                 if (err == GNUTLS_E_SUCCESS) {
     624          75 :                                         cb(BytesView(output.data, output.size));
     625          75 :                                         gnutls_free(output.data);
     626          75 :                                         success = true;
     627             :                                 }
     628             :                         }
     629         125 :                         gnutls_pubkey_deinit(pubkey);
     630             :                 } else {
     631           0 :                         log::error("Crypto", "gnutls_pubkey_init() = [", err, "] ", gnutls_strerror(err));
     632             :                 }
     633         125 :                 return success;
     634             :         },
     635          50 :         .privDecrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
     636          50 :                 auto key = static_cast<gnutls_privkey_t>(ctx.keyCtx);
     637             : 
     638             :                 gnutls_datum_t dataToDecrypt;
     639          50 :                 dataToDecrypt.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(data.data()));
     640          50 :                 dataToDecrypt.size = static_cast<unsigned int>(data.size());
     641             : 
     642             :                 gnutls_datum_t output;
     643             : 
     644          50 :                 auto err = gnutls_privkey_decrypt_data(key, 0, &dataToDecrypt, &output);
     645          50 :                 if (err == GNUTLS_E_SUCCESS) {
     646          50 :                         cb(BytesView(output.data, output.size));
     647          50 :                         gnutls_free(output.data);
     648          50 :                         return true;
     649             :                 }
     650           0 :                 return false;
     651             :         },
     652         175 :         .privFingerprint = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
     653         175 :                 switch (ctx.type) {
     654          50 :                 case KeyType::RSA:
     655             :                 case KeyType::DSA:
     656          50 :                         return s_gnuTLSCtx.privSign(ctx, cb, data, SignAlgorithm::RSA_SHA512);
     657             :                         break;
     658           0 :                 case KeyType::ECDSA:
     659             :                 case KeyType::EDDSA_ED448:
     660           0 :                         return s_gnuTLSCtx.privSign(ctx, cb, data, SignAlgorithm::ECDSA_SHA512);
     661             :                         break;
     662          50 :                 case KeyType::GOST3410_2012_256:
     663          50 :                         return  hook_gnutls_sign_gost(static_cast<gnutls_privkey_t>(ctx.keyCtx), Gost3411_256().update(data).final(), cb);
     664             :                         break;
     665          75 :                 case KeyType::GOST3410_2012_512:
     666          75 :                         return  hook_gnutls_sign_gost(static_cast<gnutls_privkey_t>(ctx.keyCtx), Gost3411_512().update(data).final(), cb);
     667             :                         break;
     668           0 :                 default:
     669           0 :                         break;
     670             :                 }
     671           0 :                 return false;
     672             :         },
     673         600 :         .pubInit = [] (KeyContext &ctx) -> bool {
     674         600 :                 return gnutls_pubkey_init( reinterpret_cast<gnutls_pubkey_t *>(&ctx.keyCtx) ) == GNUTLS_E_SUCCESS;
     675             :         },
     676         725 :         .pubFree = [] (KeyContext &ctx) {
     677         725 :                 gnutls_pubkey_deinit( static_cast<gnutls_pubkey_t>(ctx.keyCtx) );
     678         725 :         },
     679         425 :         .pubImport = [] (KeyContext &ctx, BytesView data) {
     680         425 :                 auto key = static_cast<gnutls_pubkey_t>(ctx.keyCtx);
     681             : 
     682             :                 gnutls_datum_t keyData;
     683         425 :                 keyData.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(data.data()));
     684         425 :                 keyData.size = static_cast<unsigned int>(data.size());
     685             : 
     686         425 :                 int err = 0;
     687         425 :                 if (isPemKey(data)) {
     688         150 :                         err = gnutls_pubkey_import(key, &keyData, GNUTLS_X509_FMT_PEM);
     689         150 :                         if (err == GNUTLS_E_SUCCESS) {
     690         125 :                                 ctx.type = getGnuTLSKeyType(gnutls_pubkey_get_pk_algorithm(key, nullptr));
     691         150 :                                 return true;
     692             :                         }
     693             : 
     694          25 :                         StringView str(reinterpret_cast<const char *>(data.data()), data.size());
     695          25 :                         str.skipUntilString("-----");
     696          25 :                         if (str.is("-----BEGIN RSA PUBLIC KEY-----\n")) {
     697          25 :                                 str += "-----BEGIN RSA PUBLIC KEY-----\n"_len;
     698             : 
     699          25 :                                 auto data = str.readUntilString("\n-----END RSA PUBLIC KEY-----");
     700          25 :                                 auto tmp = data;
     701          25 :                                 tmp.skipChars<StringView::Base64, StringView::WhiteSpace>();
     702          25 :                                 if (tmp.empty()) {
     703          25 :                                         size_t len = 0;
     704          25 :                                         uint8_t buf[base64::decodeSize(data.size())];
     705          50 :                                         base64::decode([&] (uint8_t b) {
     706          25 :                                                 buf[len ++] = b;
     707        9950 :                                         }, data);
     708             : 
     709          25 :                                         BytesViewNetwork asn1(buf, len);
     710          25 :                                         Pkcs1RsaPubKeyReader r(asn1);
     711          25 :                                         if (r.state == Pkcs1RsaPubKeyReader::Fin) {
     712             :                                                 gnutls_datum_t mData;
     713          25 :                                                 mData.data = const_cast<unsigned char *>(r.mod.data());
     714          25 :                                                 mData.size = static_cast<unsigned int>(r.mod.size());
     715             : 
     716             :                                                 gnutls_datum_t eData;
     717          25 :                                                 eData.data = const_cast<unsigned char *>(r.exp.data());
     718          25 :                                                 eData.size = static_cast<unsigned int>(r.exp.size());
     719             : 
     720          25 :                                                 auto key = static_cast<gnutls_pubkey_t>(ctx.keyCtx);
     721          25 :                                                 auto err = gnutls_pubkey_import_rsa_raw(key, &mData, &eData);
     722          25 :                                                 if (err == GNUTLS_E_SUCCESS) {
     723          25 :                                                         ctx.type = getGnuTLSKeyType(gnutls_pubkey_get_pk_algorithm(key, nullptr));
     724          25 :                                                         return true;
     725             :                                                 }
     726             :                                         }
     727          25 :                                 }
     728             :                         }
     729             :                 } else {
     730         275 :                         err = gnutls_pubkey_import(key, &keyData, GNUTLS_X509_FMT_DER);
     731         275 :                         if (err == GNUTLS_E_SUCCESS) {
     732         275 :                                 ctx.type = getGnuTLSKeyType(gnutls_pubkey_get_pk_algorithm(key, nullptr));
     733         275 :                                 return true;
     734             :                         }
     735             :                 }
     736           0 :                 return false;
     737             :         },
     738          75 :         .pubImportOpenSSH = [] (KeyContext &ctx, StringView r) {
     739          75 :                 auto origKeyType = r.readUntil<StringView::CharGroup<CharGroupId::WhiteSpace>>();
     740          75 :                 r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
     741          75 :                 auto dataBlock = r.readUntil<StringView::CharGroup<CharGroupId::WhiteSpace>>();
     742          75 :                 auto valid = valid::validateBase64(dataBlock);
     743          75 :                 if (valid) {
     744          75 :                         uint8_t bytes[base64::decodeSize(dataBlock.size())];
     745          75 :                         uint8_t *target = bytes;
     746          75 :                         base64::decode([&] (uint8_t c) {
     747       27325 :                                 *target++ = c;
     748       27325 :                         }, dataBlock);
     749             : 
     750          75 :                         BytesViewNetwork dataView(bytes, target - bytes);
     751          75 :                         auto len = dataView.readUnsigned32();
     752          75 :                         auto keyType = dataView.readString(len);
     753             : 
     754          75 :                         if (origKeyType != keyType || keyType != "ssh-rsa") {
     755          75 :                                 return false;
     756             :                         }
     757             : 
     758          75 :                         auto elen = dataView.readUnsigned32();
     759          75 :                         auto exp = dataView.readBytes(elen);
     760             : 
     761          75 :                         auto mlen = dataView.readUnsigned32();
     762          75 :                         auto modulus = dataView.readBytes(mlen);
     763             : 
     764             :                         gnutls_datum_t mData;
     765          75 :                         mData.data = const_cast<unsigned char *>(modulus.data());
     766          75 :                         mData.size = static_cast<unsigned int>(mlen);
     767             : 
     768             :                         gnutls_datum_t eData;
     769          75 :                         eData.data = const_cast<unsigned char *>(exp.data());
     770          75 :                         eData.size = static_cast<unsigned int>(elen);
     771             : 
     772          75 :                         auto key = static_cast<gnutls_pubkey_t>(ctx.keyCtx);
     773          75 :                         auto err = gnutls_pubkey_import_rsa_raw(key, &mData, &eData);
     774          75 :                         if (err == GNUTLS_E_SUCCESS) {
     775          75 :                                 ctx.type = getGnuTLSKeyType(gnutls_pubkey_get_pk_algorithm(key, nullptr));
     776          75 :                                 return true;
     777             :                         }
     778          75 :                 }
     779           0 :                 return false;
     780             :         },
     781         250 :         .pubExportPem = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb) {
     782         250 :                 auto key = static_cast<gnutls_pubkey_t>(ctx.keyCtx);
     783             : 
     784             :                 gnutls_datum_t out;
     785         250 :                 if (gnutls_pubkey_export2(key, GNUTLS_X509_FMT_PEM, &out) == GNUTLS_E_SUCCESS) {
     786         250 :                         cb(BytesView(out.data, out.size));
     787         250 :                         gnutls_free(out.data);
     788         250 :                         return true;
     789             :                 }
     790           0 :                 return false;
     791             :         },
     792         250 :         .pubExportDer = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb) {
     793         250 :                 auto key = static_cast<gnutls_pubkey_t>(ctx.keyCtx);
     794             : 
     795             :                 gnutls_datum_t out;
     796         250 :                 if (gnutls_pubkey_export2(key, GNUTLS_X509_FMT_DER, &out) == GNUTLS_E_SUCCESS) {
     797         250 :                         cb(BytesView(out.data, out.size));
     798         250 :                         gnutls_free(out.data);
     799         250 :                         return true;
     800             :                 }
     801           0 :                 return false;
     802             :         },
     803         225 :         .pubVerify = [] (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) {
     804         225 :                 auto key = static_cast<gnutls_pubkey_t>(ctx.keyCtx);
     805             :                 gnutls_datum_t inputData;
     806         225 :                 inputData.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(data.data()));
     807         225 :                 inputData.size = static_cast<unsigned int>(data.size());
     808             : 
     809             :                 gnutls_datum_t signatureData;
     810         225 :                 signatureData.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(signature.data()));
     811         225 :                 signatureData.size = static_cast<unsigned int>(signature.size());
     812             : 
     813         225 :                 return gnutls_pubkey_verify_data2(key, getGnuTLSAlgo(algo), 0, &inputData, &signatureData) >= 0;
     814             :         },
     815         125 :         .pubEncrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
     816         125 :                 auto key = static_cast<gnutls_pubkey_t>(ctx.keyCtx);
     817             : 
     818             :                 gnutls_datum_t dataToEncrypt;
     819         125 :                 dataToEncrypt.data = const_cast<unsigned char *>(static_cast<const unsigned char *>(data.data()));
     820         125 :                 dataToEncrypt.size = static_cast<unsigned int>(data.size());
     821             : 
     822             :                 gnutls_datum_t output;
     823             : 
     824         125 :                 auto err = gnutls_pubkey_encrypt_data(key, 0, &dataToEncrypt, &output);
     825         125 :                 if (err == GNUTLS_E_SUCCESS) {
     826          75 :                         cb(BytesView(output.data, output.size));
     827          75 :                         gnutls_free(output.data);
     828          75 :                         return true;
     829             :                 }
     830          50 :                 return false;
     831             :         },
     832             : };
     833             : 
     834             : BackendCtxRef s_gnuTlsRef(&s_gnuTLSCtx);
     835             : 
     836             : }
     837             : 
     838             : #endif

Generated by: LCOV version 1.14