LCOV - code coverage report
Current view: top level - core/crypto - SPCrypto-mbedtls.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 314 408 77.0 %
Date: 2024-05-12 00:16:13 Functions: 37 37 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 "SPValid.h"
      27             : #include "SPCrypto.h"
      28             : 
      29             : #if __CDT_PARSER__
      30             : #define MODULE_STAPPLER_CRYPTO_MBEDTLS 1
      31             : #endif
      32             : 
      33             : #if MODULE_STAPPLER_CRYPTO_MBEDTLS
      34             : 
      35             : #include "mbedtls/mbedtls_config.h"
      36             : #include "mbedtls/pk.h"
      37             : #include "mbedtls/md.h"
      38             : #include "mbedtls/error.h"
      39             : #include "mbedtls/pem.h"
      40             : #include "mbedtls/entropy.h"
      41             : #include "mbedtls/ctr_drbg.h"
      42             : 
      43             : namespace STAPPLER_VERSIONIZED stappler::crypto {
      44             : 
      45             : static constexpr size_t MBEDTLS_KEY_BUFFER_SIZE = 12_KiB; // Должен вмещать ключ в формате DER и PEM максимального размера
      46             : 
      47             : static constexpr auto PERSONALIZATION_STRING = "SP_PERSONALIZATION_STRING";
      48             : static constexpr int PUBLIC_EXPONENT = 65537;
      49             : 
      50         600 : static KeyType getMbedTLSKeyType(mbedtls_pk_type_t a) {
      51         600 :         switch (a) {
      52         600 :         case MBEDTLS_PK_RSA: return KeyType::RSA; break;
      53           0 :         case MBEDTLS_PK_ECDSA: return KeyType::ECDSA; break;
      54           0 :         default: break;
      55             :         }
      56           0 :         return KeyType::Unknown;
      57             : }
      58             : 
      59             : struct EntropyContext {
      60             :         bool valid = false;
      61             :         mbedtls_entropy_context entropy;
      62             :         mbedtls_ctr_drbg_context ctr_drbg;
      63             : 
      64         625 :         EntropyContext() {
      65         625 :                 mbedtls_ctr_drbg_init(&ctr_drbg);
      66         625 :                 mbedtls_entropy_init(&entropy);
      67             : 
      68         625 :                 if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
      69         625 :                                 reinterpret_cast<const unsigned char*>(PERSONALIZATION_STRING), strlen(PERSONALIZATION_STRING)) == 0) {
      70         625 :                         valid = true;
      71             :                 }
      72         625 :         }
      73             : 
      74         625 :         ~EntropyContext() {
      75         625 :                 mbedtls_ctr_drbg_free(&ctr_drbg);
      76         625 :                 mbedtls_entropy_free(&entropy);
      77         625 :         }
      78             : 
      79         450 :         explicit operator bool() const {
      80         450 :                 return valid;
      81             :         }
      82             : };
      83             : 
      84             : static BackendCtx s_mbedTLSCtx = {
      85             :         .name = Backend::MbedTLS,
      86             :         .title = StringView("MbedTLS"),
      87             :         .flags = BackendFlags::SupportsPKCS1 | BackendFlags::SupportsAes | BackendFlags::SecureLibrary,
      88          25 :         .initialize = [] () {
      89          25 :                 log::verbose("Crypto", "MbedTLS backend loaded");
      90          25 :         },
      91          25 :         .finalize = [] () { },
      92          25 :         .encryptBlock = [] (const BlockKey256 &key, BytesView d, const Callback<void(BytesView)> &cb) -> bool {
      93          25 :                 auto cipherBlockSize = getBlockSize(key.cipher);
      94             : 
      95          25 :                 uint64_t dataSize = d.size();
      96          25 :                 auto blockSize = math::align<size_t>(dataSize, cipherBlockSize)
      97          25 :                                 + cipherBlockSize; // allocate space for possible padding
      98             : 
      99          25 :                 uint8_t output[blockSize + sizeof(BlockCryptoHeader)];
     100             : 
     101          25 :                 fillCryptoBlockHeader(output, key, d);
     102             : 
     103          75 :                 auto perform = [&key] (const uint8_t *source, size_t size, uint8_t *out) {
     104          25 :                         bool success = false;
     105             :                         mbedtls_aes_context aes;
     106          25 :                         unsigned char iv[16] = { 0 };
     107             : 
     108          25 :                         mbedtls_aes_init( &aes );
     109          25 :                         if (mbedtls_aes_setkey_enc( &aes, key.data.data(), 256 ) == 0) {
     110          25 :                                 switch (key.cipher) {
     111          25 :                                 case BlockCipher::AES_CBC:
     112          25 :                                         if (mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_ENCRYPT, size, iv, source, out ) == 0) {
     113          25 :                                                 success = true;
     114             :                                         }
     115          25 :                                         break;
     116           0 :                                 case BlockCipher::AES_CFB8:
     117           0 :                                         if (mbedtls_aes_crypt_cfb8( &aes, MBEDTLS_AES_ENCRYPT, size, iv, source, out ) == 0) {
     118           0 :                                                 success = true;
     119             :                                         }
     120           0 :                                         break;
     121           0 :                                 default:
     122           0 :                                         break;
     123             :                                 }
     124             :                         }
     125          25 :                         mbedtls_aes_free( &aes );
     126          25 :                         return success;
     127          25 :                 };
     128             : 
     129             :                 if constexpr (SafeBlockEncoding) {
     130          25 :                         uint8_t tmp[blockSize];
     131          25 :                         memset(tmp, 0, blockSize);
     132          25 :                         memcpy(tmp, d.data(), d.size());
     133             : 
     134          25 :                         if (!perform(tmp, blockSize - cipherBlockSize, output + sizeof(BlockCryptoHeader))) {
     135           0 :                                 return false;
     136             :                         }
     137          25 :                 } else {
     138             :                         if (!perform(d.data(), blockSize - cipherBlockSize, output + sizeof(BlockCryptoHeader))) {
     139             :                                 return false;
     140             :                         }
     141             :                 }
     142             : 
     143          25 :                 cb(BytesView(output, blockSize + sizeof(BlockCryptoHeader) - cipherBlockSize));
     144          25 :                 return true;
     145          25 :         },
     146          75 :         .decryptBlock = [] (const BlockKey256 &key, BytesView b, const Callback<void(BytesView)> &cb) -> bool {
     147          75 :                 bool success = false;
     148          75 :                 auto info = getBlockInfo(b);
     149          75 :                 auto cipherBlockSize = getBlockSize(info.cipher);
     150             : 
     151          75 :                 auto blockSize = math::align<size_t>(info.dataSize, cipherBlockSize) + cipherBlockSize;
     152          75 :                 b.offset(sizeof(BlockCryptoHeader));
     153             : 
     154          75 :                 uint8_t output[blockSize];
     155             : 
     156             :                 mbedtls_aes_context aes;
     157          75 :                 unsigned char iv[16] = { 0 };
     158             : 
     159          75 :                 mbedtls_aes_init( &aes );
     160          75 :                 if (mbedtls_aes_setkey_dec( &aes, key.data.data(), 256 ) == 0) {
     161          75 :                         switch (info.cipher) {
     162          75 :                         case BlockCipher::AES_CBC:
     163          75 :                                 if (mbedtls_aes_crypt_cbc( &aes, MBEDTLS_AES_DECRYPT, blockSize, iv, b.data(), output ) == 0) {
     164          75 :                                         success = true;
     165             :                                 }
     166          75 :                                 break;
     167           0 :                         case BlockCipher::AES_CFB8:
     168           0 :                                 if (mbedtls_aes_crypt_cfb8( &aes, MBEDTLS_AES_DECRYPT, blockSize, iv, b.data(), output ) == 0) {
     169           0 :                                         success = true;
     170             :                                 }
     171           0 :                                 break;
     172           0 :                         default:
     173           0 :                                 break;
     174             :                         }
     175             :                 }
     176          75 :                 mbedtls_aes_free( &aes );
     177          75 :                 if (success) {
     178          75 :                         cb(BytesView(output, info.dataSize));
     179             :                 }
     180          75 :                 return success;
     181          75 :         },
     182         125 :         .hash256 = [] (Sha256::Buf &buf, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) -> bool {
     183         125 :                 bool success = true;
     184             :                 mbedtls_md_context_t ctx;
     185         125 :                 switch (func) {
     186         125 :                 case HashFunction::SHA_2:
     187         125 :                         mbedtls_md_init(&ctx);
     188         125 :                         if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(mbedtls_md_type_t(MBEDTLS_MD_SHA256)), 0) == 0
     189         125 :                                         && mbedtls_md_starts(&ctx) == 0) {
     190         125 :                                 cb([&] (const CoderSource &data) {
     191         125 :                                         if (success && mbedtls_md_update(&ctx, data.data(), data.size()) != 0) {
     192           0 :                                                 success = false;
     193           0 :                                                 return false;
     194             :                                         }
     195         125 :                                         return true;
     196             :                                 });
     197         125 :                                 if (success && mbedtls_md_finish(&ctx, buf.data()) != 0) {
     198           0 :                                         success = false;
     199             :                                 }
     200             :                         } else {
     201           0 :                                 success = false;
     202             :                         }
     203         125 :                         mbedtls_md_free(&ctx);
     204         125 :                         break;
     205           0 :                 case HashFunction::GOST_3411:
     206           0 :                         return false;
     207             :                         break;
     208             :                 }
     209         125 :                 return success;
     210             :         },
     211          25 :         .hash512 = [] (Sha512::Buf &buf, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) -> bool {
     212          25 :                 bool success = true;
     213             :                 mbedtls_md_context_t ctx;
     214          25 :                 switch (func) {
     215          25 :                 case HashFunction::SHA_2:
     216          25 :                         mbedtls_md_init(&ctx);
     217          25 :                         if (mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(mbedtls_md_type_t(MBEDTLS_MD_SHA512)), 0) == 0
     218          25 :                                         && mbedtls_md_starts(&ctx) == 0) {
     219          25 :                                 cb([&] (const CoderSource &data) {
     220          25 :                                         if (success && mbedtls_md_update(&ctx, data.data(), data.size()) != 0) {
     221           0 :                                                 success = false;
     222           0 :                                                 return false;
     223             :                                         }
     224          25 :                                         return true;
     225             :                                 });
     226          25 :                                 if (success && mbedtls_md_finish(&ctx, buf.data()) != 0) {
     227           0 :                                         success = false;
     228             :                                 }
     229             :                         } else {
     230           0 :                                 success = false;
     231             :                         }
     232          25 :                         mbedtls_md_free(&ctx);
     233          25 :                         break;
     234           0 :                 case HashFunction::GOST_3411:
     235           0 :                         return false;
     236             :                         break;
     237             :                 }
     238          25 :                 return success;
     239             :         },
     240         400 :         .privInit = [] (KeyContext &ctx) -> bool {
     241         400 :                 mbedtls_pk_init(reinterpret_cast<mbedtls_pk_context *>(&ctx));
     242         400 :                 return true;
     243             :         },
     244         400 :         .privFree = [] (KeyContext &ctx) {
     245         400 :                 mbedtls_pk_free(reinterpret_cast<mbedtls_pk_context *>(&ctx));
     246         400 :         },
     247          75 :         .privGen = [] (KeyContext &ctx, KeyBits bits, KeyType type) -> bool {
     248          75 :                 if (type != KeyType::RSA) {
     249           0 :                         log::error("Crypto-mbedtls", "Unsupported key type for keygen");
     250           0 :                         return false;
     251             :                 }
     252             : 
     253          75 :                 int nbits = 0;
     254             : 
     255          75 :                 switch (bits) {
     256          25 :                 case KeyBits::_1024: nbits = 1024; break;
     257          25 :                 case KeyBits::_2048: nbits = 2048; break;
     258          25 :                 case KeyBits::_4096: nbits = 4096; break;
     259             :                 }
     260             : 
     261          75 :                 if (nbits == 0) {
     262           0 :                         return false;
     263             :                 }
     264             : 
     265         150 :                 EntropyContext entropy;
     266          75 :                 if (!entropy) {
     267           0 :                         return false;
     268             :                 }
     269             : 
     270          75 :                 auto finalize = [&] (bool value) {
     271          75 :                         if (!value) {
     272           0 :                                 mbedtls_pk_free( reinterpret_cast<mbedtls_pk_context *>(&ctx) );
     273             :                         }
     274          75 :                         return value;
     275          75 :                 };
     276             : 
     277          75 :                 auto key = reinterpret_cast<mbedtls_pk_context *>(&ctx);
     278             : 
     279          75 :                 int ret = -1;
     280          75 :                 if ((ret = mbedtls_pk_setup(key, mbedtls_pk_info_from_type(mbedtls_pk_type_t(MBEDTLS_PK_RSA)))) != 0) {
     281           0 :                         return finalize(false);
     282             :                 }
     283             : 
     284          75 :                 if ((ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(*key), mbedtls_ctr_drbg_random, &entropy.ctr_drbg, nbits, PUBLIC_EXPONENT)) != 0) {
     285           0 :                         return finalize(false);
     286             :                 }
     287             : 
     288          75 :                 if (mbedtls_rsa_check_pubkey(mbedtls_pk_rsa(*key)) != 0) {
     289           0 :                         return finalize(false);
     290             :                 }
     291             : 
     292          75 :                 if (mbedtls_rsa_check_privkey(mbedtls_pk_rsa(*key)) != 0) {
     293           0 :                         return finalize(false);
     294             :                 }
     295             : 
     296          75 :                 ctx.type = getMbedTLSKeyType(mbedtls_pk_get_type(key));
     297          75 :                 return finalize(true);
     298             :         },
     299         175 :         .privImport = [] (KeyContext &ctx, BytesView data, const CoderSource &passwd) {
     300         175 :                 EntropyContext entropy;
     301             : 
     302         175 :                 auto loadKey = [&] (BytesView input) {
     303         350 :                         auto key = reinterpret_cast<mbedtls_pk_context *>(&ctx);
     304         175 :                         auto err = mbedtls_pk_parse_key(key, input.data(), input.size(),
     305         175 :                                         passwd.data(), passwd.size(), mbedtls_ctr_drbg_random, &entropy.ctr_drbg);
     306         175 :                         if (err != 0) {
     307           0 :                                 mbedtls_pk_free( key );
     308           0 :                                 return false;
     309             :                         }
     310             : 
     311         175 :                         ctx.type = getMbedTLSKeyType(mbedtls_pk_get_type(key));
     312         175 :                         return true;
     313         175 :                 };
     314             : 
     315         175 :                 if (!isPemKey(data) || data.data()[data.size() - 1] == 0) {
     316          50 :                         return loadKey(data);
     317             :                 } else {
     318         125 :                         if (data.data()[data.size()] == 0) {
     319         125 :                                 return loadKey(BytesView(data.data(), data.size() + 1));
     320             :                         } else {
     321           0 :                                 uint8_t buf[data.size() + 1];
     322           0 :                                 memcpy(buf, data.data(), data.size());
     323           0 :                                 buf[data.size()] = 0;
     324             : 
     325           0 :                                 return loadKey(BytesView(buf, data.size() + 1));
     326           0 :                         }
     327             :                 }
     328             :                 return false;
     329         175 :         },
     330          50 :         .privExportPem = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) {
     331             :                 uint8_t buf[MBEDTLS_KEY_BUFFER_SIZE];
     332          50 :                 int ret = -1;
     333             : 
     334          50 :                 auto key = reinterpret_cast<const mbedtls_pk_context *>(&ctx);
     335             : 
     336          50 :                 if (fmt == KeyFormat::PKCS8) { log::error("Crypto", "KeyFormat::PKCS8 is not supported by mbedtls backend, Fallback to PKCS1"); }
     337             : 
     338          50 :                 if (!passPhrase.empty()) {
     339           0 :                         log::error("Crypto", "Password-encoding is not supported for PKCS1");
     340             :                 }
     341          50 :                 ret = mbedtls_pk_write_key_pem(key, buf, MBEDTLS_KEY_BUFFER_SIZE);
     342          50 :                 if (ret > 0) {
     343           0 :                         cb(BytesView(buf + MBEDTLS_KEY_BUFFER_SIZE - ret, ret));
     344           0 :                         return true;
     345          50 :                 } else if (ret == 0) {
     346          50 :                         auto len = strlen(reinterpret_cast<char *>(buf));
     347          50 :                         if (len < MBEDTLS_KEY_BUFFER_SIZE) {
     348          50 :                                 cb(BytesView(buf, len));
     349          50 :                                 return true;
     350             :                         }
     351             :                 }
     352             : 
     353           0 :                 return false;
     354             :         },
     355          50 :         .privExportDer = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) {
     356             :                 uint8_t buf[MBEDTLS_KEY_BUFFER_SIZE];
     357          50 :                 int ret = -1;
     358             : 
     359          50 :                 auto key = reinterpret_cast<const mbedtls_pk_context *>(&ctx);
     360             : 
     361          50 :                 if (fmt == KeyFormat::PKCS8) { log::error("Crypto", "KeyFormat::PKCS8 is not supported by mbedtls backend, Fallback to PKCS1"); }
     362             : 
     363          50 :                 if (!passPhrase.empty()) {
     364           0 :                         log::error("Crypto", "Password-encoding is not supported for PKCS1");
     365             :                 }
     366          50 :                 ret = mbedtls_pk_write_key_der(key, buf, MBEDTLS_KEY_BUFFER_SIZE);
     367          50 :                 if (ret > 0) {
     368          50 :                         cb(BytesView(buf + MBEDTLS_KEY_BUFFER_SIZE - ret, ret));
     369          50 :                         return true;
     370             :                 }
     371             : 
     372           0 :                 return false;
     373             :         },
     374          75 :         .privExportPublic = [] (KeyContext &target, const KeyContext &privKey) {
     375             :                 uint8_t buf[MBEDTLS_KEY_BUFFER_SIZE];
     376          75 :                 int ret = -1;
     377             : 
     378          75 :                 auto sourceKey = reinterpret_cast<const mbedtls_pk_context *>(&privKey);
     379          75 :                 auto targetKey = reinterpret_cast<mbedtls_pk_context *>(&target);
     380             : 
     381          75 :                 ret = mbedtls_pk_write_pubkey_der(sourceKey, buf, MBEDTLS_KEY_BUFFER_SIZE);
     382          75 :                 if (ret > 0) {
     383          75 :                         auto data = BytesView(buf + MBEDTLS_KEY_BUFFER_SIZE - ret, ret);
     384             : 
     385          75 :                         mbedtls_pk_init(targetKey);
     386             : 
     387          75 :                         auto err = mbedtls_pk_parse_public_key(targetKey, data.data(), data.size());
     388          75 :                         if (err != 0) {
     389           0 :                                 mbedtls_pk_free(targetKey);
     390           0 :                                 return false;
     391             :                         }
     392          75 :                         target.type = getMbedTLSKeyType(mbedtls_pk_get_type(targetKey));
     393          75 :                         return true;
     394             :                 }
     395           0 :                 return false;
     396             :         },
     397         175 :         .privSign = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data, SignAlgorithm algo) {
     398         175 :                 EntropyContext entropy;
     399         175 :                 if (!entropy) {
     400           0 :                         return false;
     401             :                 }
     402             : 
     403         175 :                 size_t writeSize = 0;
     404             :                 uint8_t buf[MBEDTLS_PK_SIGNATURE_MAX_SIZE];
     405             : 
     406         175 :                 auto key = const_cast<mbedtls_pk_context *>(reinterpret_cast<const mbedtls_pk_context *>(&ctx));
     407             : 
     408         175 :                 switch (algo) {
     409          25 :                 case SignAlgorithm::ECDSA_SHA256:
     410             :                 case SignAlgorithm::RSA_SHA256: {
     411          25 :                         auto hash = Sha256().update(data).final();
     412             : 
     413          25 :                         if (mbedtls_pk_sign(key, mbedtls_md_type_t(MBEDTLS_MD_SHA256), hash.data(), hash.size(),
     414          25 :                                         buf, MBEDTLS_PK_SIGNATURE_MAX_SIZE, &writeSize, mbedtls_ctr_drbg_random, &entropy.ctr_drbg) == 0) {
     415          25 :                                 cb(BytesView(buf, writeSize));
     416          25 :                                 return true;
     417             :                         }
     418             : 
     419           0 :                         break;
     420             :                 }
     421         150 :                 case SignAlgorithm::ECDSA_SHA512:
     422             :                 case SignAlgorithm::RSA_SHA512: {
     423         150 :                         auto hash = Sha512().update(data).final();
     424             : 
     425         150 :                         if (mbedtls_pk_sign(key, mbedtls_md_type_t(MBEDTLS_MD_SHA512), hash.data(), hash.size(),
     426         150 :                                         buf, MBEDTLS_PK_SIGNATURE_MAX_SIZE, &writeSize, mbedtls_ctr_drbg_random, &entropy.ctr_drbg) == 0) {
     427         150 :                                 cb(BytesView(buf, writeSize));
     428         150 :                                 return true;
     429             :                         }
     430             : 
     431           0 :                         break;
     432             :                 }
     433           0 :                 case SignAlgorithm::GOST_256:
     434             :                 case SignAlgorithm::GOST_512:
     435           0 :                         return false;
     436             :                 }
     437             : 
     438           0 :                 return false;
     439         175 :         },
     440          75 :         .privVerify = [] (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) {
     441          75 :                 auto key = const_cast<mbedtls_pk_context *>(reinterpret_cast<const mbedtls_pk_context *>(&ctx));
     442          75 :                 switch (algo) {
     443          25 :                 case SignAlgorithm::ECDSA_SHA256:
     444             :                 case SignAlgorithm::RSA_SHA256: {
     445          25 :                         auto hash = string::Sha256().update(data).final();
     446          25 :                         if (mbedtls_pk_verify(key, mbedtls_md_type_t(MBEDTLS_MD_SHA256), hash.data(), hash.size(),
     447          25 :                                         signature.data(), signature.size()) == 0) {
     448          25 :                                 return true;
     449             :                         }
     450           0 :                         break;
     451             :                 }
     452          50 :                 case SignAlgorithm::ECDSA_SHA512:
     453             :                 case SignAlgorithm::RSA_SHA512: {
     454          50 :                         auto hash = string::Sha512().update(data).final();
     455          50 :                         if (mbedtls_pk_verify(key, mbedtls_md_type_t(MBEDTLS_MD_SHA512), hash.data(), hash.size(),
     456          50 :                                         signature.data(), signature.size()) == 0) {
     457          50 :                                 return true;
     458             :                         }
     459           0 :                         break;
     460             :                 }
     461           0 :                 case SignAlgorithm::GOST_256:
     462             :                 case SignAlgorithm::GOST_512:
     463           0 :                         return false;
     464             :                 }
     465           0 :                 return false;
     466             :         },
     467          50 :         .privEncrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
     468          50 :                 EntropyContext entropy;
     469          50 :                 if (!entropy) {
     470           0 :                         return false;
     471             :                 }
     472             : 
     473          50 :                 size_t bufSize = math::align<size_t>(data.size(), 1_KiB) + MBEDTLS_PK_SIGNATURE_MAX_SIZE;
     474          50 :                 size_t writeSize = 0;
     475          50 :                 uint8_t buf[bufSize];
     476             : 
     477          50 :                 auto key = const_cast<mbedtls_pk_context *>(reinterpret_cast<const mbedtls_pk_context *>(&ctx));
     478             : 
     479          50 :                 if (mbedtls_pk_encrypt(key, data.data(), data.size(), buf, &writeSize, bufSize, mbedtls_ctr_drbg_random, &entropy.ctr_drbg) == 0) {
     480          50 :                         cb(BytesView(buf, writeSize));
     481          50 :                         return true;
     482             :                 }
     483             : 
     484           0 :                 return false;
     485         100 :         },
     486          50 :         .privDecrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
     487          50 :                 EntropyContext entropy;
     488          50 :                 if (!entropy) {
     489           0 :                         return false;
     490             :                 }
     491             : 
     492          50 :                 size_t bufSize = math::align<size_t>(data.size(), 1_KiB) + MBEDTLS_PK_SIGNATURE_MAX_SIZE;
     493          50 :                 size_t writeSize = 0;
     494          50 :                 uint8_t buf[bufSize];
     495             : 
     496          50 :                 auto key = const_cast<mbedtls_pk_context *>(reinterpret_cast<const mbedtls_pk_context *>(&ctx));
     497             : 
     498          50 :                 if (mbedtls_pk_decrypt(key, data.data(), data.size(), buf, &writeSize, bufSize, mbedtls_ctr_drbg_random, &entropy.ctr_drbg) == 0) {
     499          50 :                         cb(BytesView(buf, writeSize));
     500          50 :                         return true;
     501             :                 }
     502             : 
     503           0 :                 return false;
     504         100 :         },
     505          25 :         .privFingerprint = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
     506          25 :                 switch (ctx.type) {
     507          25 :                 case KeyType::RSA:
     508             :                 case KeyType::DSA:
     509          25 :                         return s_mbedTLSCtx.privSign(ctx, cb, data, SignAlgorithm::RSA_SHA512);
     510             :                         break;
     511           0 :                 case KeyType::ECDSA:
     512             :                 case KeyType::EDDSA_ED448:
     513           0 :                         return s_mbedTLSCtx.privSign(ctx, cb, data, SignAlgorithm::ECDSA_SHA512);
     514             :                         break;
     515           0 :                 default:
     516           0 :                         break;
     517             :                 }
     518           0 :                 return false;
     519             :         },
     520         275 :         .pubInit = [] (KeyContext &ctx) -> bool {
     521         275 :                 mbedtls_pk_init(reinterpret_cast<mbedtls_pk_context *>(&ctx));
     522         275 :                 return true;
     523             :         },
     524         350 :         .pubFree = [] (KeyContext &ctx) {
     525         350 :                 mbedtls_pk_free(reinterpret_cast<mbedtls_pk_context *>(&ctx));
     526         350 :         },
     527         225 :         .pubImport = [] (KeyContext &ctx, BytesView data) {
     528         225 :                 auto loadKey = [&] (BytesView input) {
     529         450 :                         auto key = reinterpret_cast<mbedtls_pk_context *>(&ctx);
     530         225 :                         auto err = mbedtls_pk_parse_public_key(key, input.data(), input.size());
     531         225 :                         if (err != 0) {
     532           0 :                                 mbedtls_pk_free( key );
     533           0 :                                 return false;
     534             :                         }
     535             : 
     536         225 :                         ctx.type = getMbedTLSKeyType(mbedtls_pk_get_type(key));
     537         225 :                         return true;
     538         225 :                 };
     539             : 
     540         225 :                 if (!isPemKey(data) || data.data()[data.size() - 1] == 0) {
     541         175 :                         return loadKey(data);
     542             :                 } else {
     543          50 :                         if (data.data()[data.size()] == 0) {
     544          50 :                                 return loadKey(BytesView(data.data(), data.size() + 1));
     545             :                         } else {
     546           0 :                                 uint8_t buf[data.size() + 1];
     547           0 :                                 memcpy(buf, data.data(), data.size());
     548           0 :                                 buf[data.size()] = 0;
     549             : 
     550           0 :                                 return loadKey(BytesView(buf, data.size() + 1));
     551           0 :                         }
     552             :                 }
     553             :                 return false;
     554             :         },
     555          50 :         .pubImportOpenSSH = [] (KeyContext &ctx, StringView r) {
     556             :                 uint8_t out[MBEDTLS_KEY_BUFFER_SIZE];
     557          50 :                 uint8_t *buf = out;
     558             : 
     559          50 :                 auto origKeyType = r.readUntil<StringView::CharGroup<CharGroupId::WhiteSpace>>();
     560          50 :                 r.skipChars<StringView::CharGroup<CharGroupId::WhiteSpace>>();
     561          50 :                 auto dataBlock = r.readUntil<StringView::CharGroup<CharGroupId::WhiteSpace>>();
     562          50 :                 if (valid::validateBase64(dataBlock)) {
     563          50 :                         uint8_t bytes[base64::decodeSize(dataBlock.size())];
     564          50 :                         uint8_t *target = bytes;
     565          50 :                         base64::decode([&] (uint8_t c) {
     566       20350 :                                 *target++ = c;
     567       20350 :                         }, dataBlock);
     568             : 
     569          50 :                         BytesViewNetwork dataView(bytes, target - bytes);
     570          50 :                         auto len = dataView.readUnsigned32();
     571          50 :                         auto keyType = dataView.readString(len);
     572             : 
     573          50 :                         if (origKeyType != keyType || keyType != "ssh-rsa") {
     574           0 :                                 return false;
     575             :                         }
     576             : 
     577          50 :                         auto elen = dataView.readUnsigned32();
     578          50 :                         auto exp = dataView.readBytes(elen);
     579             : 
     580          50 :                         auto mlen = dataView.readUnsigned32();
     581          50 :                         auto modulus = dataView.readBytes(mlen);
     582             : 
     583          50 :                         buf = writeRSAKey(buf, modulus, exp);
     584             : 
     585          50 :                         auto key = reinterpret_cast<mbedtls_pk_context *>(&ctx);
     586          50 :                         if (mbedtls_pk_parse_public_key(key, out, buf - out) != 0) {
     587           0 :                                 return false;
     588             :                         }
     589             : 
     590          50 :                         ctx.type = getMbedTLSKeyType(mbedtls_pk_get_type(key));
     591          50 :                         return true;
     592          50 :                 }
     593             : 
     594           0 :                 return false;
     595             :         },
     596         125 :         .pubExportPem = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb) {
     597         125 :                 auto key = const_cast<mbedtls_pk_context *>(reinterpret_cast<const mbedtls_pk_context *>(&ctx));
     598             : 
     599             :                 uint8_t buf[MBEDTLS_KEY_BUFFER_SIZE];
     600         125 :                 int ret = -1;
     601             : 
     602         125 :                 ret = mbedtls_pk_write_pubkey_pem(key, buf, MBEDTLS_KEY_BUFFER_SIZE);
     603         125 :                 if (ret > 0) {
     604           0 :                         cb(BytesView(buf + MBEDTLS_KEY_BUFFER_SIZE - ret, ret));
     605           0 :                         return true;
     606         125 :                 } else if (ret == 0) {
     607         125 :                         auto len = strlen(reinterpret_cast<char *>(buf));
     608         125 :                         if (len < MBEDTLS_KEY_BUFFER_SIZE) {
     609         125 :                                 cb(BytesView(buf, len));
     610         125 :                                 return true;
     611             :                         }
     612             :                 }
     613             : 
     614           0 :                 return false;
     615             :         },
     616         150 :         .pubExportDer = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb) {
     617         150 :                 auto key = reinterpret_cast<const mbedtls_pk_context *>(&ctx);
     618             : 
     619             :                 uint8_t buf[MBEDTLS_KEY_BUFFER_SIZE];
     620         150 :                 int ret = -1;
     621             : 
     622         150 :                 ret = mbedtls_pk_write_pubkey_der(key, buf, MBEDTLS_KEY_BUFFER_SIZE);
     623         150 :                 if (ret > 0) {
     624         150 :                         cb(BytesView(buf + MBEDTLS_KEY_BUFFER_SIZE - ret, ret));
     625         150 :                         return true;
     626             :                 }
     627             : 
     628           0 :                 return false;
     629             :         },
     630          75 :         .pubVerify = [] (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) {
     631          75 :                 auto key = const_cast<mbedtls_pk_context *>(reinterpret_cast<const mbedtls_pk_context *>(&ctx));
     632             : 
     633          75 :                 switch (algo) {
     634          25 :                 case SignAlgorithm::ECDSA_SHA256:
     635             :                 case SignAlgorithm::RSA_SHA256: {
     636          25 :                         auto hash = string::Sha256().update(data).final();
     637          25 :                         if (mbedtls_pk_verify(key, mbedtls_md_type_t(MBEDTLS_MD_SHA256), hash.data(), hash.size(),
     638          25 :                                         signature.data(), signature.size()) == 0) {
     639          25 :                                 return true;
     640             :                         }
     641           0 :                         break;
     642             :                 }
     643          50 :                 case SignAlgorithm::ECDSA_SHA512:
     644             :                 case SignAlgorithm::RSA_SHA512: {
     645          50 :                         auto hash = string::Sha512().update(data).final();
     646          50 :                         if (mbedtls_pk_verify(key, mbedtls_md_type_t(MBEDTLS_MD_SHA512), hash.data(), hash.size(),
     647          50 :                                         signature.data(), signature.size()) == 0) {
     648          50 :                                 return true;
     649             :                         }
     650           0 :                         break;
     651             :                 }
     652           0 :                 case SignAlgorithm::GOST_256:
     653             :                 case SignAlgorithm::GOST_512:
     654           0 :                         return false;
     655             :                 }
     656           0 :                 return false;
     657             :         },
     658         100 :         .pubEncrypt = [] (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) {
     659         100 :                 EntropyContext entropy;
     660         100 :                 if (!entropy) {
     661           0 :                         return false;
     662             :                 }
     663             : 
     664         100 :                 size_t bufSize = math::align<size_t>(data.size(), 1_KiB) + MBEDTLS_PK_SIGNATURE_MAX_SIZE;
     665         100 :                 size_t writeSize = 0;
     666         100 :                 uint8_t buf[bufSize];
     667             : 
     668         100 :                 auto key = const_cast<mbedtls_pk_context *>(reinterpret_cast<const mbedtls_pk_context *>(&ctx));
     669             : 
     670         100 :                 if (mbedtls_pk_encrypt(key, data.data(), data.size(), buf, &writeSize, bufSize, mbedtls_ctr_drbg_random, &entropy.ctr_drbg) == 0) {
     671         100 :                         cb(BytesView(buf, writeSize));
     672         100 :                         return true;
     673             :                 }
     674             : 
     675           0 :                 return false;
     676         200 :         }
     677             : };
     678             : 
     679             : BackendCtxRef s_mbedTlsRef(&s_mbedTLSCtx);
     680             : 
     681             : }
     682             : 
     683             : #endif

Generated by: LCOV version 1.14