Line data Source code
1 : /**
2 : Copyright (c) 2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 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 "SPCrypto.h"
25 : #include "SPString.h"
26 : #include "SPValid.h"
27 : #include "SPMemory.h"
28 :
29 : namespace STAPPLER_VERSIONIZED stappler::crypto {
30 :
31 : struct BackendCtx {
32 : static BackendCtx *get(Backend);
33 :
34 : Backend name;
35 : StringView title;
36 : BackendFlags flags;
37 :
38 : void (*initialize) () = nullptr;
39 : void (*finalize) () = nullptr;
40 :
41 : bool (*encryptBlock) (const BlockKey256 &key, BytesView d, const Callback<void(BytesView)> &cb) = nullptr;
42 : bool (*decryptBlock) (const BlockKey256 &key, BytesView d, const Callback<void(BytesView)> &cb) = nullptr;
43 :
44 : bool (*hash256) (Sha256::Buf &, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func);
45 : bool (*hash512) (Sha512::Buf &, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func);
46 :
47 : bool (*privInit) (KeyContext &ctx) = nullptr;
48 : void (*privFree) (KeyContext &ctx) = nullptr;
49 :
50 : bool (*privGen) (KeyContext &ctx, KeyBits, KeyType) = nullptr;
51 : bool (*privImport) (KeyContext &ctx, BytesView data, const CoderSource &passwd) = nullptr;
52 : bool (*privExportPem) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) = nullptr;
53 : bool (*privExportDer) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) = nullptr;
54 : bool (*privExportPublic) (KeyContext &target, const KeyContext &privKey) = nullptr;
55 : bool (*privSign) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data, SignAlgorithm algo) = nullptr;
56 : bool (*privVerify) (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) = nullptr;
57 : bool (*privEncrypt) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) = nullptr;
58 : bool (*privDecrypt) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) = nullptr;
59 : bool (*privFingerprint) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) = nullptr;
60 :
61 : bool (*pubInit) (KeyContext &ctx) = nullptr;
62 : void (*pubFree) (KeyContext &ctx) = nullptr;
63 :
64 : bool (*pubImport) (KeyContext &ctx, BytesView data) = nullptr;
65 : bool (*pubImportOpenSSH) (KeyContext &ctx, StringView data) = nullptr;
66 : bool (*pubExportPem) (const KeyContext &ctx, const Callback<void(BytesView)> &cb) = nullptr;
67 : bool (*pubExportDer) (const KeyContext &ctx, const Callback<void(BytesView)> &cb) = nullptr;
68 : bool (*pubVerify) (const KeyContext &ctx, const CoderSource &data, BytesView signature, SignAlgorithm algo) = nullptr;
69 : bool (*pubEncrypt) (const KeyContext &ctx, const Callback<void(BytesView)> &cb, const CoderSource &data) = nullptr;
70 : };
71 :
72 : struct BackendCtxRef {
73 : static mem_std::HashMap<Backend, BackendCtx *> s_backends;
74 :
75 : BackendCtxRef(BackendCtx *);
76 : ~BackendCtxRef();
77 :
78 : BackendCtx *backend;
79 : };
80 :
81 : mem_std::HashMap<Backend, BackendCtx *> BackendCtxRef::s_backends;
82 :
83 8625 : BackendCtx *BackendCtx::get(Backend b) {
84 8625 : auto it = BackendCtxRef::s_backends.find(b);
85 8625 : if (it != BackendCtxRef::s_backends.end()) {
86 6575 : return it->second;
87 : }
88 :
89 2050 : if (b == Backend::Default) {
90 1800 : BackendCtx *ret = nullptr;
91 : #if MODULE_STAPPLER_CRYPTO_GNUTLS
92 1800 : if (!ret) {
93 1800 : ret = get(Backend::GnuTLS);
94 : }
95 : #endif
96 : #if MODULE_STAPPLER_CRYPTO_OPENSSL
97 1800 : if (!ret) {
98 0 : ret = get(Backend::OpenSSL);
99 : }
100 : #endif
101 : #if MODULE_STAPPLER_CRYPTO_MBEDTLS
102 1800 : if (!ret) {
103 0 : ret = get(Backend::MbedTLS);
104 : }
105 : #endif
106 1800 : if (!ret) {
107 0 : ret = get(Backend::Embedded);
108 : }
109 1800 : return ret;
110 : }
111 :
112 250 : return nullptr;
113 : }
114 :
115 75 : BackendCtxRef::BackendCtxRef(BackendCtx *ctx) {
116 75 : s_backends.emplace(ctx->name, ctx);
117 75 : backend = ctx;
118 75 : if (backend->initialize) {
119 75 : backend->initialize();
120 : }
121 75 : }
122 :
123 75 : BackendCtxRef::~BackendCtxRef() {
124 75 : s_backends.erase(backend->name);
125 75 : if (backend->finalize) {
126 75 : backend->finalize();
127 : }
128 75 : }
129 :
130 25 : void listBackends(const Callback<void(Backend, StringView, BackendFlags)> &cb) {
131 100 : for (auto &it : BackendCtxRef::s_backends) {
132 75 : cb(it.first, it.second->title, it.second->flags);
133 : }
134 25 : }
135 :
136 2475 : bool isPemKey(BytesView data) {
137 2475 : StringView str(reinterpret_cast<const char *>(data.data()), data.size());
138 2475 : str.skipUntilString("-----");
139 2475 : if (str.is("-----")) {
140 1100 : return true;
141 : }
142 1375 : return false;
143 : }
144 :
145 400 : static bool isBackendValidForBlock(BackendCtx *b, BlockCipher c) {
146 400 : switch (c) {
147 200 : case BlockCipher::AES_CBC:
148 : case BlockCipher::AES_CFB8:
149 200 : if ((b->flags & BackendFlags::SupportsAes) != BackendFlags::None && b->encryptBlock && b->decryptBlock) {
150 200 : return true;
151 : }
152 0 : break;
153 200 : case BlockCipher::Gost3412_2015_CTR_ACPKM:
154 200 : if ((b->flags & BackendFlags::SupportsGost3412_2015) != BackendFlags::None && b->encryptBlock && b->decryptBlock) {
155 200 : return true;
156 : }
157 0 : break;
158 : }
159 0 : return false;
160 : }
161 :
162 400 : static BackendCtx *findBackendForBlock(BlockCipher c) {
163 : // check default
164 :
165 400 : auto check = [&] (BackendCtx *b, bool secure) -> BackendCtx * {
166 400 : if (b && (b->flags & BackendFlags::SecureLibrary) == (secure ? BackendFlags::SecureLibrary : BackendFlags::None)) {
167 400 : if (isBackendValidForBlock(b, c)) {
168 400 : return b;
169 : }
170 : }
171 0 : return nullptr;
172 400 : };
173 :
174 400 : auto b = check(BackendCtx::get(Backend::Default), true);
175 400 : if (b) {
176 400 : return b;
177 : }
178 :
179 : // check secure libs first
180 0 : for (auto &it : BackendCtxRef::s_backends) {
181 0 : if (check(it.second, true)) { return it.second; }
182 : }
183 :
184 0 : for (auto &it : BackendCtxRef::s_backends) {
185 0 : if (check(it.second, false)) { return it.second; }
186 : }
187 0 : return nullptr;
188 : }
189 :
190 525 : static void fillCryptoBlockHeader(uint8_t *buf, const BlockKey256 &key, BytesView d) {
191 525 : uint64_t dataSize = d.size();
192 :
193 : BlockCryptoHeader header;
194 525 : header.size = byteorder::HostToLittle(dataSize);
195 525 : header.version = byteorder::HostToLittle(key.version);
196 525 : header.cipher = byteorder::HostToLittle(toInt(key.cipher));
197 525 : header.padding = 0;
198 :
199 525 : memcpy(buf, &header, sizeof(BlockCryptoHeader));
200 525 : }
201 :
202 650 : static SignAlgorithm getSignForBlockCipher(const PrivateKey &key) {
203 650 : switch (key.getType()) {
204 50 : case KeyType::GOST3410_2012_256:
205 50 : return SignAlgorithm::GOST_256;
206 : break;
207 50 : case KeyType::GOST3410_2012_512:
208 50 : return SignAlgorithm::GOST_512;
209 : break;
210 550 : default:
211 550 : break;
212 : }
213 550 : return SignAlgorithm::RSA_SHA512;
214 : }
215 :
216 275 : bool encryptBlock(const BlockKey256 &key, BytesView data, const Callback<void(BytesView)> &cb) {
217 275 : auto b = findBackendForBlock(key.cipher);
218 275 : return b->encryptBlock(key, data, cb);
219 : }
220 :
221 175 : bool encryptBlock(Backend b, const BlockKey256 &key, BytesView data, const Callback<void(BytesView)> &cb) {
222 175 : auto backend = BackendCtx::get(b);
223 175 : if (!backend || !backend->encryptBlock) {
224 0 : return false;
225 : }
226 175 : return backend->encryptBlock(key, data, cb);
227 : }
228 :
229 125 : bool decryptBlock(const BlockKey256 &key, BytesView data, const Callback<void(BytesView)> &cb) {
230 125 : auto b = findBackendForBlock(key.cipher);
231 125 : return b->decryptBlock(key, data, cb);
232 : }
233 :
234 400 : bool decryptBlock(Backend b, const BlockKey256 &key, BytesView data, const Callback<void(BytesView)> &cb) {
235 400 : auto backend = BackendCtx::get(b);
236 400 : if (!backend || !backend->decryptBlock) {
237 0 : return false;
238 : }
239 400 : return backend->decryptBlock(key, data, cb);
240 : }
241 :
242 225 : BlockKey256 makeBlockKey(Backend b, BytesView pkey, BytesView hash, BlockCipher c, uint32_t version) {
243 225 : crypto::PrivateKey pk(b, pkey);
244 225 : if (pk && version > 0) {
245 75 : auto ret = makeBlockKey(pk, hash, c, version);
246 75 : if (ret.version == 0) {
247 0 : ret.data = string::Sha256().update(hash).update(pkey).final();
248 : }
249 75 : ret.cipher = c;
250 75 : return ret;
251 : } else {
252 300 : return BlockKey256 { 0, c, string::Sha256().update(hash).update(pkey).final() };
253 : }
254 225 : }
255 :
256 225 : BlockKey256 makeBlockKey(BytesView pkey, BytesView hash, BlockCipher b, uint32_t version) {
257 225 : return makeBlockKey(Backend::Default, pkey, hash, b, version);
258 : }
259 :
260 525 : BlockKey256 makeBlockKey(const PrivateKey &pkey, BytesView hash, uint32_t version) {
261 525 : switch (pkey.getType()) {
262 200 : case KeyType::GOST3410_2012_256:
263 : case KeyType::GOST3410_2012_512:
264 200 : return makeBlockKey(pkey, hash, BlockCipher::Gost3412_2015_CTR_ACPKM, version);
265 : break;
266 325 : default:
267 325 : break;
268 : }
269 325 : return makeBlockKey(pkey, hash, BlockCipher::AES_CBC, version);
270 : }
271 :
272 1050 : BlockKey256 makeBlockKey(const PrivateKey &pkey, BytesView hash, BlockCipher b, uint32_t version) {
273 1050 : BlockKey256 ret;
274 1050 : ret.cipher = b;
275 1050 : if (version == 2) {
276 875 : ret.version = 0;
277 875 : switch (b) {
278 475 : case BlockCipher::AES_CBC:
279 : case BlockCipher::AES_CFB8:
280 475 : pkey.sign([&] (BytesView data) {
281 950 : ret.version = version;
282 475 : ret.data = hash256(pkey.getBackend(), CoderSource(data), HashFunction::SHA_2);
283 475 : }, hash, getSignForBlockCipher(pkey));
284 475 : break;
285 400 : case BlockCipher::Gost3412_2015_CTR_ACPKM:
286 400 : pkey.fingerprint([&] (BytesView data) {
287 800 : ret.version = version;
288 400 : ret.data = Gost3411_256::hmac(hash, data);
289 400 : }, hash);
290 400 : break;
291 : }
292 175 : } else if (version == 1) {
293 175 : if (!pkey.sign([&] (BytesView data) {
294 175 : auto s = std::min(data.size(), size_t(256));
295 175 : ret.data = hash256(pkey.getBackend(), CoderSource(BytesView(data, s)), HashFunction::SHA_2);
296 175 : ret.version = version;
297 175 : }, hash, getSignForBlockCipher(pkey))) {
298 0 : ret.version = 0;
299 : }
300 : } else {
301 0 : ret.version = 0;
302 : }
303 1050 : return ret;
304 : }
305 :
306 650 : BlockInfo getBlockInfo(BytesView val) {
307 650 : BlockInfo ret;
308 650 : BytesViewTemplate<Endian::Little> b(val);
309 650 : ret.dataSize = b.readUnsigned64();
310 650 : ret.version = b.readUnsigned16();
311 650 : ret.cipher = BlockCipher(b.readUnsigned16());
312 650 : return ret;
313 : }
314 :
315 1250 : Sha256::Buf hash256(Backend b, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) {
316 125 : auto embedded = [&] {
317 125 : switch (func) {
318 25 : case HashFunction::SHA_2: {
319 25 : Sha256 ctx;
320 25 : cb([&] (const CoderSource &data) {
321 25 : ctx.update(data);
322 25 : return true;
323 : });
324 25 : return ctx.final();
325 : break;
326 : }
327 100 : case HashFunction::GOST_3411:
328 100 : Gost3411_256 ctx;
329 100 : cb([&] (const CoderSource &data) {
330 100 : ctx.update(data);
331 100 : return true;
332 : });
333 100 : return ctx.final();
334 : break;
335 : }
336 0 : return Sha256::Buf();
337 1250 : };
338 :
339 1250 : auto bctx = BackendCtx::get(b);
340 1250 : if (!bctx) {
341 125 : return embedded();
342 : } else {
343 : Sha256::Buf ctx;
344 1125 : if (!bctx->hash256 || !bctx->hash256(ctx, cb, func)) {
345 0 : return embedded();
346 : }
347 1125 : return ctx;
348 : }
349 : }
350 :
351 1150 : Sha256::Buf hash256(Backend b, const CoderSource &data, HashFunction func) {
352 2300 : return hash256(b, Callback<void( const HashCoderCallback &upd )>([&] (const HashCoderCallback &upd) {
353 1150 : upd(data);
354 2300 : }), func);
355 : }
356 :
357 900 : Sha512::Buf hash512(Backend b, const Callback<void( const HashCoderCallback &upd )> &cb, HashFunction func) {
358 125 : auto embedded = [&] {
359 125 : switch (func) {
360 25 : case HashFunction::SHA_2: {
361 25 : Sha512 ctx;
362 25 : cb([&] (const CoderSource &data) {
363 25 : ctx.update(data);
364 25 : return true;
365 : });
366 25 : return ctx.final();
367 : break;
368 : }
369 100 : case HashFunction::GOST_3411:
370 100 : Gost3411_512 ctx;
371 100 : cb([&] (const CoderSource &data) {
372 100 : ctx.update(data);
373 100 : return true;
374 : });
375 100 : return ctx.final();
376 : break;
377 : }
378 0 : return Sha512::Buf();
379 900 : };
380 :
381 900 : auto bctx = BackendCtx::get(b);
382 900 : if (!bctx) {
383 125 : return embedded();
384 : } else {
385 : Sha512::Buf ctx;
386 775 : if (!bctx->hash512 || !bctx->hash512(ctx, cb, func)) {
387 0 : return embedded();
388 : }
389 775 : return ctx;
390 : }
391 : }
392 :
393 500 : Sha512::Buf hash512(Backend b, const CoderSource &data, HashFunction func) {
394 1000 : return hash512(b, Callback<void( const HashCoderCallback &upd )>([&] (const HashCoderCallback &upd) {
395 500 : upd(data);
396 1000 : }), func);
397 : }
398 :
399 100 : Sha256::Buf hash256(const Callback<void( const Callback<bool(const CoderSource &)> &upd )> &cb, HashFunction func) {
400 100 : return hash256(Backend::Default, cb, func);
401 : }
402 100 : Sha256::Buf hash256(const CoderSource &data, HashFunction func) {
403 100 : return hash256(Backend::Default, data, func);
404 : }
405 :
406 400 : Sha512::Buf hash512(const Callback<void( const Callback<bool(const CoderSource &)> &upd )> &cb, HashFunction func) {
407 400 : return hash512(Backend::Default, cb, func);
408 : }
409 100 : Sha512::Buf hash512(const CoderSource &data, HashFunction func) {
410 100 : return hash512(Backend::Default, data, func);
411 : }
412 :
413 2425 : PrivateKey::PrivateKey(Backend b) : _valid(true), _key() {
414 2425 : auto backend = BackendCtx::get(b);
415 2425 : if (!backend) {
416 0 : _valid = false;
417 0 : return;
418 : }
419 :
420 2425 : if (!backend->privInit || !backend->privInit(_key)) {
421 0 : _valid = false;
422 : }
423 :
424 2425 : _key.backendCtx = backend;
425 : }
426 :
427 1200 : PrivateKey::PrivateKey(Backend b, BytesView data, const CoderSource &str) : PrivateKey(b) {
428 1200 : this->import(data, str);
429 1200 : }
430 :
431 200 : PrivateKey::PrivateKey(BytesView data, const CoderSource &str) : PrivateKey(Backend::Default) {
432 200 : this->import(data, str);
433 200 : }
434 :
435 2450 : PrivateKey::~PrivateKey() {
436 2450 : if (_valid) {
437 2350 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
438 2350 : if (backend && backend->privFree) {
439 2350 : backend->privFree(_key);
440 2350 : _valid = false;
441 : }
442 : }
443 2450 : }
444 :
445 50 : PrivateKey::PrivateKey(PrivateKey &&other) {
446 50 : _key = other._key;
447 50 : _valid = other._valid;
448 50 : _loaded = other._loaded;
449 :
450 50 : other._valid = false;
451 50 : other._loaded = false;
452 50 : other._key.cryptoCtx = nullptr;
453 50 : other._key.keyCtx = nullptr;
454 50 : other._key.backendCtx = nullptr;
455 50 : }
456 :
457 50 : PrivateKey& PrivateKey::operator=(PrivateKey &&other) {
458 50 : if (_valid) {
459 50 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
460 50 : if (backend && backend->privFree) {
461 50 : backend->privFree(_key);
462 50 : _valid = false;
463 : }
464 : }
465 :
466 50 : _key = other._key;
467 50 : _valid = other._valid;
468 50 : _loaded = other._loaded;
469 :
470 50 : other._valid = false;
471 50 : other._loaded = false;
472 50 : other._key.cryptoCtx = nullptr;
473 50 : other._key.keyCtx = nullptr;
474 50 : other._key.backendCtx = nullptr;
475 50 : return *this;
476 : }
477 :
478 200 : bool PrivateKey::generate(KeyType type) {
479 200 : return generate(KeyBits::_4096, type);
480 : }
481 :
482 725 : bool PrivateKey::generate(KeyBits bits, KeyType type) {
483 725 : if (!_valid) {
484 0 : return false;
485 : }
486 :
487 725 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
488 725 : if (backend && backend->privGen && backend->privGen(_key, bits, type)) {
489 725 : _loaded = true;
490 725 : return true;
491 : }
492 :
493 0 : return false;
494 : }
495 :
496 1475 : bool PrivateKey::import(BytesView data, const CoderSource &passwd) {
497 1475 : if (_loaded || !_valid || data.empty()) {
498 0 : return false;
499 : }
500 :
501 1475 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
502 1475 : if (backend && backend->privImport && backend->privImport(_key, data, passwd)) {
503 1300 : _loaded = true;
504 1300 : return true;
505 : }
506 :
507 175 : return false;
508 : }
509 :
510 300 : PublicKey PrivateKey::exportPublic() const {
511 300 : return PublicKey(*this);
512 : }
513 :
514 650 : Backend PrivateKey::getBackend() const {
515 650 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
516 650 : return backend->name;
517 : }
518 :
519 850 : bool PrivateKey::exportPem(const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) const {
520 850 : if (!_loaded || !_valid) {
521 0 : return false;
522 : }
523 :
524 850 : if (fmt == KeyFormat::RSA && getType() != KeyType::RSA) {
525 0 : log::error("Crypto", "Unable to export non-RSA key in PKCS#1 format");
526 0 : return false;
527 : }
528 :
529 850 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
530 850 : if (backend && backend->privExportPem && backend->privExportPem(_key, cb, fmt, passPhrase)) {
531 850 : return true;
532 : }
533 :
534 0 : return false;
535 : }
536 :
537 150 : bool PrivateKey::exportPem(const Callback<void(BytesView)> &cb, const CoderSource &passPhrase) const {
538 150 : return exportPem(cb, KeyFormat::PKCS8, passPhrase);
539 : }
540 :
541 900 : bool PrivateKey::exportDer(const Callback<void(BytesView)> &cb, KeyFormat fmt, const CoderSource &passPhrase) const {
542 900 : if (!_loaded || !_valid) {
543 0 : return false;
544 : }
545 :
546 900 : if (fmt == KeyFormat::RSA && getType() != KeyType::RSA) {
547 0 : log::error("Crypto", "Unable to export non-RSA key in PKCS#1 format");
548 0 : return false;
549 : }
550 :
551 900 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
552 900 : if (backend && backend->privExportDer && backend->privExportDer(_key, cb, fmt, passPhrase)) {
553 900 : return true;
554 : }
555 :
556 0 : return false;
557 : }
558 :
559 150 : bool PrivateKey::exportDer(const Callback<void(BytesView)> &cb, const CoderSource &passPhrase) const {
560 150 : return exportDer(cb, KeyFormat::PKCS8, passPhrase);
561 : }
562 :
563 1175 : bool PrivateKey::sign(const Callback<void(BytesView)> &cb, const CoderSource &data, SignAlgorithm algo) const {
564 1175 : if (!_loaded || !_valid) {
565 0 : return false;
566 : }
567 :
568 1175 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
569 1175 : if (backend && backend->privSign && backend->privSign(_key, cb, data, algo)) {
570 1175 : return true;
571 : }
572 :
573 0 : return false;
574 : }
575 :
576 425 : bool PrivateKey::verify(const CoderSource &data, BytesView signature, SignAlgorithm algo) const {
577 425 : if (!_loaded || !_valid) {
578 0 : return false;
579 : }
580 :
581 425 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
582 425 : if (backend && backend->privVerify && backend->privVerify(_key, data, signature, algo)) {
583 425 : return true;
584 : }
585 :
586 0 : return false;
587 : }
588 :
589 575 : bool PrivateKey::fingerprint(const Callback<void(BytesView)> &cb, const CoderSource &data) const {
590 575 : if (!_loaded || !_valid) {
591 0 : return false;
592 : }
593 :
594 575 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
595 575 : if (backend && backend->privFingerprint && backend->privFingerprint(_key, cb, data)) {
596 575 : return true;
597 : }
598 :
599 0 : return false;
600 : }
601 :
602 225 : bool PrivateKey::isGenerateSupported(KeyType type) const {
603 225 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
604 225 : switch (type) {
605 75 : case KeyType::RSA:
606 75 : return (backend->flags & BackendFlags::SecureLibrary) != BackendFlags::None;
607 : break;
608 150 : case KeyType::GOST3410_2012_256:
609 : case KeyType::GOST3410_2012_512:
610 150 : return (backend->flags & BackendFlags::SupportsGost3410_2012) != BackendFlags::None;
611 : break;
612 :
613 0 : case KeyType::Unknown:
614 : case KeyType::DSA:
615 : case KeyType::ECDSA:
616 : case KeyType::EDDSA_ED448:
617 0 : return false;
618 : break;
619 : }
620 0 : return false;
621 : }
622 :
623 550 : bool PrivateKey::isSupported(KeyFormat fmt) const {
624 550 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
625 550 : switch (fmt) {
626 225 : case KeyFormat::PKCS1: return (backend->flags & BackendFlags::SupportsPKCS1) != BackendFlags::None; break;
627 325 : case KeyFormat::PKCS8: return (backend->flags & BackendFlags::SupportsPKCS8) != BackendFlags::None; break;
628 : }
629 0 : return false;
630 : }
631 :
632 275 : bool PrivateKey::encrypt(const Callback<void(BytesView)> &cb, const CoderSource &data) {
633 275 : if (!_loaded || !_valid) {
634 0 : return false;
635 : }
636 :
637 275 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
638 275 : if (backend && backend->privEncrypt) {
639 275 : return backend->privEncrypt(_key, cb, data);
640 : }
641 :
642 0 : return false;
643 : }
644 :
645 150 : bool PrivateKey::decrypt(const Callback<void(BytesView)> &cb, const CoderSource &data) {
646 150 : if (!_loaded || !_valid) {
647 0 : return false;
648 : }
649 :
650 150 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
651 150 : if (backend && backend->privDecrypt) {
652 150 : return backend->privDecrypt(_key, cb, data);
653 : }
654 :
655 0 : return false;
656 : }
657 :
658 1275 : PublicKey::PublicKey(Backend b) : _valid(true), _key() {
659 1275 : auto backend = BackendCtx::get(b);
660 1275 : if (!backend) {
661 0 : _valid = false;
662 0 : return;
663 : }
664 :
665 1275 : if (!backend->pubInit || !backend->pubInit(_key)) {
666 0 : _valid = false;
667 : }
668 1275 : _key.backendCtx = backend;
669 : }
670 :
671 1000 : PublicKey::PublicKey(Backend b, BytesView data) : PublicKey(b) {
672 1000 : if (data.starts_with(reinterpret_cast<const uint8_t *>("ssh-rsa"), "ssh-rsa"_len)) {
673 75 : importOpenSSH(StringView(reinterpret_cast<const char *>(data.data()), data.size()));
674 : } else {
675 925 : this->import(data);
676 : }
677 1000 : }
678 :
679 100 : PublicKey::PublicKey(BytesView data) : PublicKey(Backend::Default) {
680 100 : if (data.starts_with(reinterpret_cast<const uint8_t *>("ssh-rsa"), "ssh-rsa"_len)) {
681 25 : importOpenSSH(StringView(reinterpret_cast<const char *>(data.data()), data.size()));
682 : } else {
683 75 : this->import(data);
684 : }
685 100 : }
686 :
687 475 : PublicKey::PublicKey(const PrivateKey &priv) : _valid(false) {
688 475 : auto backend = static_cast<BackendCtx *>(priv.getKey().backendCtx);
689 475 : if (backend && backend->privExportPublic && backend->privExportPublic(_key, priv.getKey())) {
690 475 : _valid = true;
691 475 : _loaded = true;
692 475 : _key.backendCtx = priv.getKey().backendCtx;
693 : }
694 475 : }
695 :
696 1800 : PublicKey::~PublicKey() {
697 1800 : if (_valid) {
698 1650 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
699 1650 : if (backend && backend->pubFree) {
700 1650 : backend->pubFree(_key);
701 1650 : _valid = false;
702 : }
703 : }
704 1800 : }
705 :
706 75 : PublicKey::PublicKey(PublicKey &&other) {
707 75 : _key = other._key;
708 75 : _valid = other._valid;
709 75 : _loaded = other._loaded;
710 :
711 75 : other._valid = false;
712 75 : other._loaded = false;
713 75 : other._key.cryptoCtx = nullptr;
714 75 : other._key.keyCtx = nullptr;
715 75 : other._key.backendCtx = nullptr;
716 75 : }
717 :
718 75 : PublicKey& PublicKey::operator=(PublicKey &&other) {
719 75 : if (_valid) {
720 75 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
721 75 : if (backend && backend->pubFree) {
722 75 : backend->pubFree(_key);
723 75 : _valid = false;
724 : }
725 : }
726 :
727 75 : _key = other._key;
728 75 : _valid = other._valid;
729 75 : _loaded = other._loaded;
730 :
731 75 : other._valid = false;
732 75 : other._loaded = false;
733 75 : other._key.cryptoCtx = nullptr;
734 75 : other._key.keyCtx = nullptr;
735 75 : other._key.backendCtx = nullptr;
736 75 : return *this;
737 : }
738 :
739 1000 : bool PublicKey::import(BytesView data) {
740 1000 : if (_loaded || !_valid || data.empty()) {
741 0 : return false;
742 : }
743 :
744 1000 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
745 1000 : if (backend && backend->pubImport && backend->pubImport(_key, data)) {
746 1000 : _loaded = true;
747 1000 : return true;
748 : }
749 :
750 0 : return false;
751 : }
752 :
753 175 : bool PublicKey::importOpenSSH(StringView r) {
754 175 : if (!_valid || _loaded) {
755 0 : return false;
756 : }
757 :
758 175 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
759 175 : if (backend && backend->pubImportOpenSSH && backend->pubImportOpenSSH(_key, r)) {
760 175 : _loaded = true;
761 175 : return true;
762 : }
763 :
764 0 : return false;
765 : }
766 :
767 75 : Backend PublicKey::getBackend() const {
768 75 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
769 75 : return backend->name;
770 : }
771 :
772 550 : bool PublicKey::exportPem(const Callback<void(BytesView)> &cb) const {
773 550 : if (!_loaded || !_valid) {
774 0 : return false;
775 : }
776 :
777 550 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
778 550 : if (backend && backend->pubExportPem && backend->pubExportPem(_key, cb)) {
779 550 : return true;
780 : }
781 :
782 0 : return false;
783 : }
784 :
785 650 : bool PublicKey::exportDer(const Callback<void(BytesView)> &cb) const {
786 650 : if (!_loaded || !_valid) {
787 0 : return false;
788 : }
789 :
790 650 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
791 650 : if (backend && backend->pubExportDer && backend->pubExportDer(_key, cb)) {
792 650 : return true;
793 : }
794 :
795 0 : return false;
796 : }
797 :
798 625 : bool PublicKey::verify(const CoderSource &data, BytesView signature, SignAlgorithm algo) const {
799 625 : if (!_loaded || !_valid) {
800 0 : return false;
801 : }
802 :
803 625 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
804 625 : if (backend && backend->pubVerify && backend->pubVerify(_key, data, signature, algo)) {
805 625 : return true;
806 : }
807 :
808 0 : return false;
809 : }
810 :
811 375 : bool PublicKey::encrypt(const Callback<void(BytesView)> &cb, const CoderSource &data) {
812 375 : if (!_loaded || !_valid) {
813 0 : return false;
814 : }
815 :
816 375 : auto backend = static_cast<BackendCtx *>(_key.backendCtx);
817 375 : if (backend && backend->pubEncrypt) {
818 375 : return backend->pubEncrypt(_key, cb, data);
819 : }
820 :
821 0 : return false;
822 : }
823 :
824 100 : static uint8_t * writeRSAKey(uint8_t *buf, BytesViewNetwork mod, BytesViewNetwork exp) {
825 100 : size_t modSize = 1;
826 100 : size_t expSize = 1;
827 :
828 200 : auto readSize = [&] (size_t s) {
829 200 : if (s < 128) {
830 100 : return 1;
831 100 : } else if (s < 256) {
832 0 : return 2;
833 : } else {
834 100 : return 3;
835 : }
836 : };
837 :
838 300 : auto writeSize = [&] (size_t s) {
839 300 : if (s < 128) {
840 100 : *buf = uint8_t(s); ++ buf;
841 200 : } else if (s < 256) {
842 0 : *buf = uint8_t(0x81); ++ buf;
843 0 : *buf = uint8_t(s); ++ buf;
844 : } else {
845 200 : *buf = uint8_t(0x82); ++ buf;
846 200 : *buf = uint8_t((s >> 8) & 0xFF); ++ buf;
847 200 : *buf = uint8_t(s & 0xFF); ++ buf;
848 : }
849 400 : };
850 :
851 100 : modSize += readSize(mod.size()) + mod.size();
852 100 : expSize += readSize(exp.size()) + exp.size();
853 :
854 100 : *buf = uint8_t(0x30); ++ buf;
855 100 : writeSize(modSize + expSize);
856 :
857 100 : *buf = uint8_t(0x02); ++ buf;
858 100 : writeSize(mod.size());
859 38600 : for (size_t i = 0; i < mod.size(); ++ i) {
860 38500 : *buf = mod.at(i); ++ buf;
861 : }
862 :
863 100 : *buf = uint8_t(0x02); ++ buf;
864 100 : writeSize(exp.size());
865 400 : for (size_t i = 0; i < exp.size(); ++ i) {
866 300 : *buf = exp.at(i); ++ buf;
867 : }
868 :
869 100 : return buf;
870 : }
871 :
872 : }
873 :
874 : #ifdef __LCC__
875 : #pragma diag_suppress 2464
876 : #pragma diag_suppress 1444
877 : #endif
878 :
879 : #include "SPCrypto-openssl.cc"
880 : #include "SPCrypto-mbedtls.cc"
881 : #include "SPCrypto-gnutls.cc"
882 :
883 : #ifdef __LCC__
884 : #pragma diag_default 2464
885 : #pragma diag_default 1444
886 : #endif
|