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
|