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, ¶mset, 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
|