Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtlskey_openssl.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:cryptography
4
8
9#include <QtNetwork/private/qsslkey_p.h>
10
11#include <QtNetwork/qsslsocket.h>
12
13#include <QtCore/qscopeguard.h>
14
16
17namespace QTlsPrivate {
18
19void TlsKeyOpenSSL::decodeDer(QSsl::KeyType type, QSsl::KeyAlgorithm algorithm, const QByteArray &der,
20 const QByteArray &passPhrase, bool deepClear)
21{
22 if (der.isEmpty())
23 return;
24
25 keyType = type;
27
29 const auto pem = pemFromDer(der, headers);
30
32}
33
34void TlsKeyOpenSSL::readGenericKey(BIO *bio, void *phrase, QSsl::KeyType keyType)
35{
36 if (keyType == QSsl::PublicKey)
37 genericKey = q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase);
38 else
39 genericKey = q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase);
40 keyIsNull = !genericKey;
41 if (keyIsNull)
42 QTlsBackendOpenSSL::logAndClearErrorQueue();
43}
44
45void TlsKeyOpenSSL::decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem,
46 const QByteArray &passPhrase, bool deepClear)
47{
48 if (pem.isEmpty())
49 return;
50
51 keyType = type;
52 keyAlgorithm = algorithm;
53
54 clear(deepClear);
55
56 BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
57 if (!bio)
58 return;
59
60 const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
61
62 void *phrase = const_cast<char *>(passPhrase.data());
63
64#ifdef OPENSSL_NO_DEPRECATED_3_0
65 readGenericKey(bio, phrase, keyType);
66#else
67
68 if (algorithm == QSsl::Rsa) {
69 RSA *result = (type == QSsl::PublicKey)
70 ? q_PEM_read_bio_RSA_PUBKEY(bio, &rsa, nullptr, phrase)
71 : q_PEM_read_bio_RSAPrivateKey(bio, &rsa, nullptr, phrase);
72 if (rsa && rsa == result)
73 keyIsNull = false;
74 } else if (algorithm == QSsl::Dsa) {
75 DSA *result = (type == QSsl::PublicKey)
76 ? q_PEM_read_bio_DSA_PUBKEY(bio, &dsa, nullptr, phrase)
77 : q_PEM_read_bio_DSAPrivateKey(bio, &dsa, nullptr, phrase);
78 if (dsa && dsa == result)
79 keyIsNull = false;
80 } else if (algorithm == QSsl::Dh) {
81 EVP_PKEY *result = (type == QSsl::PublicKey)
82 ? q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase)
83 : q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase);
84 if (result)
85 dh = q_EVP_PKEY_get1_DH(result);
86 if (dh)
87 keyIsNull = false;
89#ifndef OPENSSL_NO_EC
90 } else if (algorithm == QSsl::Ec) {
91 EC_KEY *result = (type == QSsl::PublicKey)
92 ? q_PEM_read_bio_EC_PUBKEY(bio, &ec, nullptr, phrase)
93 : q_PEM_read_bio_ECPrivateKey(bio, &ec, nullptr, phrase);
94 if (ec && ec == result)
95 keyIsNull = false;
96#endif // OPENSSL_NO_EC
97 } else if (algorithm == QSsl::MlDsa) {
98 readGenericKey(bio, phrase, keyType);
99 }
100
101#endif // OPENSSL_NO_DEPRECATED_3_0
102}
103
104QByteArray TlsKeyOpenSSL::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
105{
106 QByteArray header = pemHeader();
107 QByteArray footer = pemFooter();
108
109 QByteArray der(pem);
110
111 int headerIndex = der.indexOf(header);
112 int footerIndex = der.indexOf(footer, headerIndex + header.size());
113 if (type() != QSsl::PublicKey) {
114 if (headerIndex == -1 || footerIndex == -1) {
115 header = pkcs8Header(true);
116 footer = pkcs8Footer(true);
117 headerIndex = der.indexOf(header);
118 footerIndex = der.indexOf(footer, headerIndex + header.size());
119 }
120 if (headerIndex == -1 || footerIndex == -1) {
121 header = pkcs8Header(false);
122 footer = pkcs8Footer(false);
123 headerIndex = der.indexOf(header);
124 footerIndex = der.indexOf(footer, headerIndex + header.size());
125 }
126 }
127 if (headerIndex == -1 || footerIndex == -1)
128 return QByteArray();
129
130 der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
131
132 if (der.contains("Proc-Type:")) {
133 // taken from QHttpNetworkReplyPrivate::parseHeader
134 int i = 0;
135 while (i < der.size()) {
136 int j = der.indexOf(':', i); // field-name
137 if (j == -1)
138 break;
139 const QByteArray field = der.mid(i, j - i).trimmed();
140 j++;
141 // any number of LWS is allowed before and after the value
142 QByteArray value;
143 do {
144 i = der.indexOf('\n', j);
145 if (i == -1)
146 break;
147 if (!value.isEmpty())
148 value += ' ';
149 // check if we have CRLF or only LF
150 bool hasCR = (i && der[i-1] == '\r');
151 int length = i -(hasCR ? 1: 0) - j;
152 value += der.mid(j, length).trimmed();
153 j = ++i;
154 } while (i < der.size() && (der.at(i) == ' ' || der.at(i) == '\t'));
155 if (i == -1)
156 break; // something is wrong
157
158 headers->insert(field, value);
159 }
160 der = der.mid(i);
161 }
162
163 return QByteArray::fromBase64(der); // ignores newlines
164}
165
166void TlsKeyOpenSSL::clear(bool deep)
167{
168 keyIsNull = true;
169
170#ifndef OPENSSL_NO_DEPRECATED_3_0
171 if (algorithm() == QSsl::Rsa && rsa) {
172 if (deep)
173 q_RSA_free(rsa);
174 rsa = nullptr;
175 }
176 if (algorithm() == QSsl::Dsa && dsa) {
177 if (deep)
178 q_DSA_free(dsa);
179 dsa = nullptr;
180 }
181 if (algorithm() == QSsl::Dh && dh) {
182 if (deep)
183 q_DH_free(dh);
184 dh = nullptr;
185 }
186#ifndef OPENSSL_NO_EC
187 if (algorithm() == QSsl::Ec && ec) {
188 if (deep)
190 ec = nullptr;
191 }
192#endif
193#endif // OPENSSL_NO_DEPRECATED_3_0
194
195 if (algorithm() == QSsl::Opaque && opaque) {
196 if (deep)
197 q_EVP_PKEY_free(opaque);
198 opaque = nullptr;
199 }
200
201 if (genericKey) {
202 // None of the above cleared it. genericKey is either
203 // initialised by PEM read operation, or from X509, and
204 // we are the owners and not sharing. So we free it.
205 q_EVP_PKEY_free(genericKey);
206 genericKey = nullptr;
207 }
208}
209
210Qt::HANDLE TlsKeyOpenSSL::handle() const
211{
212 if (keyAlgorithm == QSsl::Opaque)
213 return Qt::HANDLE(opaque);
214
215#ifndef OPENSSL_NO_DEPRECATED_3_0
216 switch (keyAlgorithm) {
217 case QSsl::Rsa:
218 return Qt::HANDLE(rsa);
219 case QSsl::Dsa:
220 return Qt::HANDLE(dsa);
221 case QSsl::Dh:
222 return Qt::HANDLE(dh);
223#ifndef OPENSSL_NO_EC
224 case QSsl::Ec:
225 return Qt::HANDLE(ec);
226#endif
227 default:
228 return Qt::HANDLE(nullptr);
229 }
230#else
231 qCWarning(lcTlsBackend,
232 "This version of OpenSSL disabled direct manipulation with RSA/DSA/DH/EC_KEY structures, consider using QSsl::Opaque instead.");
233 return Qt::HANDLE(genericKey);
234#endif
235}
236
237int TlsKeyOpenSSL::length() const
238{
239 if (isNull() || algorithm() == QSsl::Opaque)
240 return -1;
241
242#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
243 if (algorithm() == QSsl::MlDsa) {
244 Q_ASSERT(genericKey);
245 return q_EVP_PKEY_get_security_bits(genericKey);
246 }
247#endif
248
249#ifndef OPENSSL_NO_DEPRECATED_3_0
250 switch (algorithm()) {
251 case QSsl::Rsa:
252 return q_RSA_bits(rsa);
253 case QSsl::Dsa:
254 return q_DSA_bits(dsa);
255 case QSsl::Dh:
256 return q_DH_bits(dh);
257#ifndef OPENSSL_NO_EC
258 case QSsl::Ec:
260#endif
261 default:
262 return -1;
263 }
264#else // OPENSSL_NO_DEPRECATED_3_0
265 Q_ASSERT(genericKey);
266 return q_EVP_PKEY_get_bits(genericKey);
267#endif // OPENSSL_NO_DEPRECATED_3_0
268}
269
270QByteArray TlsKeyOpenSSL::toPem(const QByteArray &passPhrase) const
271{
272 if (!QSslSocket::supportsSsl() || isNull() || algorithm() == QSsl::Opaque)
273 return {};
274
275 const EVP_CIPHER *cipher = nullptr;
276 if (type() == QSsl::PrivateKey && !passPhrase.isEmpty()) {
277#ifndef OPENSSL_NO_DES
278 cipher = q_EVP_des_ede3_cbc();
279#else
280 return {};
281#endif
282 }
283
284 BIO *bio = q_BIO_new(q_BIO_s_mem());
285 if (!bio)
286 return {};
287
288 const auto bioRaii = qScopeGuard([bio]{q_BIO_free(bio);});
289
290#ifndef OPENSSL_NO_DEPRECATED_3_0
291
292#define write_pubkey(alg, key) q_PEM_write_bio_##alg##_PUBKEY(bio, key)
293#define write_privatekey(alg, key)
294 q_PEM_write_bio_##alg##PrivateKey(bio, key, cipher, (uchar *)passPhrase.data(),
295 passPhrase.size(), nullptr, nullptr)
296
297#else
298
299#define write_pubkey(alg, key) q_PEM_write_bio_PUBKEY(bio, genericKey)
300#define write_privatekey(alg, key)
301 q_PEM_write_bio_PrivateKey_traditional(bio, genericKey, cipher, (uchar *)passPhrase.data(), passPhrase.size(), nullptr, nullptr)
302
303#endif // OPENSSL_NO_DEPRECATED_3_0
304
305 bool fail = false;
306 if (algorithm() == QSsl::Rsa) {
307 if (type() == QSsl::PublicKey) {
308 if (!write_pubkey(RSA, rsa))
309 fail = true;
310 } else if (!write_privatekey(RSA, rsa)) {
311 fail = true;
312 }
313 } else if (algorithm() == QSsl::Dsa) {
314 if (type() == QSsl::PublicKey) {
315 if (!write_pubkey(DSA, dsa))
316 fail = true;
317 } else if (!write_privatekey(DSA, dsa)) {
318 fail = true;
319 }
320 } else if (algorithm() == QSsl::Dh) {
321#ifdef OPENSSL_NO_DEPRECATED_3_0
322 EVP_PKEY *result = genericKey;
323#else
324 EVP_PKEY *result = q_EVP_PKEY_new();
325 const auto guard = qScopeGuard([result]{if (result) q_EVP_PKEY_free(result);});
326 if (!result || !q_EVP_PKEY_set1_DH(result, dh)) {
327 fail = true;
328 } else
329#endif
330 if (type() == QSsl::PublicKey) {
331 if (!q_PEM_write_bio_PUBKEY(bio, result))
332 fail = true;
333 } else if (!q_PEM_write_bio_PrivateKey(bio, result, cipher, (uchar *)passPhrase.data(),
334 passPhrase.size(), nullptr, nullptr)) {
335 fail = true;
336 }
337#ifndef OPENSSL_NO_EC
338 } else if (algorithm() == QSsl::Ec) {
339 if (type() == QSsl::PublicKey) {
340 if (!write_pubkey(EC, ec))
341 fail = true;
342 } else {
343 if (!write_privatekey(EC, ec))
344 fail = true;
345 }
346#endif
347 } else if (algorithm() == QSsl::MlDsa) {
348 if (type() == QSsl::PublicKey) {
349 if (!q_PEM_write_bio_PUBKEY(bio, genericKey))
350 fail = true;
351 } else {
352 if (!q_PEM_write_bio_PrivateKey(bio, genericKey, cipher, (uchar *)passPhrase.data(),
353 passPhrase.size(), nullptr, nullptr))
354 fail = true;
355 }
356 } else {
357 fail = true;
358 }
359
360 QByteArray pem;
361 if (!fail) {
362 char *data = nullptr;
363 const long size = q_BIO_get_mem_data(bio, &data);
364 if (size > 0 && data)
365 pem = QByteArray(data, size);
366 } else {
367 QTlsBackendOpenSSL::logAndClearErrorQueue();
368 }
369
370 return pem;
371}
372
373void TlsKeyOpenSSL::fromHandle(Qt::HANDLE handle, QSsl::KeyType expectedType)
374{
375 EVP_PKEY *evpKey = reinterpret_cast<EVP_PKEY *>(handle);
376 if (!evpKey || !fromEVP_PKEY(evpKey)) {
377 opaque = evpKey;
379 } else {
381 }
382
384 keyIsNull = !opaque;
385}
386
387bool TlsKeyOpenSSL::fromEVP_PKEY(EVP_PKEY *pkey)
388{
389 if (!pkey)
390 return false;
391
392#ifndef OPENSSL_NO_DEPRECATED_3_0
393#define get_key(key, alg) key = q_EVP_PKEY_get1_##alg(pkey)
394#else
395#define get_key(key, alg) q_EVP_PKEY_up_ref(pkey); genericKey = pkey;
396#endif
397
398#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
399 // ML-DSA don't have NIDs
400 const auto keyTypeName = QLatin1StringView(q_EVP_PKEY_type_name(pkey));
401 if (keyTypeName.contains(QLatin1String("ML-DSA")) ||
402 keyTypeName.contains(QLatin1String("mldsa"))) {
403 keyAlgorithm = QSsl::MlDsa;
404 keyIsNull = false;
405 keyType = QSsl::PrivateKey;
407 genericKey = pkey;
408 return true;
409 }
410#endif
411
412 switch (q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey))) {
413 case EVP_PKEY_RSA:
414 keyIsNull = false;
415 keyAlgorithm = QSsl::Rsa;
416 keyType = QSsl::PrivateKey;
417 get_key(rsa, RSA);
418 return true;
419 case EVP_PKEY_DSA:
420 keyIsNull = false;
421 keyAlgorithm = QSsl::Dsa;
422 keyType = QSsl::PrivateKey;
423 get_key(dsa, DSA);
424 return true;
425 case EVP_PKEY_DH:
426 keyIsNull = false;
427 keyAlgorithm = QSsl::Dh;
428 keyType = QSsl::PrivateKey;
429 get_key(dh, DH);
430 return true;
431#ifndef OPENSSL_NO_EC
432 case EVP_PKEY_EC:
433 keyIsNull = false;
434 keyAlgorithm = QSsl::Ec;
435 keyType = QSsl::PrivateKey;
436 get_key(ec, EC_KEY);
437 return true;
438#endif
439 default:;
440 // Unknown key type. This could be handled as opaque, but then
441 // we'd eventually leak memory since we wouldn't be able to free
442 // the underlying EVP_PKEY structure. For now, we won't support
443 // this.
444 }
445
446 return false;
447}
448
449QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data,
450 const QByteArray &key, const QByteArray &iv, bool enc)
451{
452 const EVP_CIPHER *type = nullptr;
453 int i = 0, len = 0;
454
455 switch (cipher) {
456 case Cipher::DesCbc:
457#ifndef OPENSSL_NO_DES
458 type = q_EVP_des_cbc();
459#endif
460 break;
461 case Cipher::DesEde3Cbc:
462#ifndef OPENSSL_NO_DES
464#endif
465 break;
466 case Cipher::Rc2Cbc:
467#ifndef OPENSSL_NO_RC2
468 type = q_EVP_rc2_cbc();
469#endif
470 break;
471 case Cipher::Aes128Cbc:
472 type = q_EVP_aes_128_cbc();
473 break;
474 case Cipher::Aes192Cbc:
475 type = q_EVP_aes_192_cbc();
476 break;
477 case Cipher::Aes256Cbc:
478 type = q_EVP_aes_256_cbc();
479 break;
480 }
481
482 if (type == nullptr)
483 return {};
484
485 QByteArray output;
486 output.resize(data.size() + EVP_MAX_BLOCK_LENGTH);
487
488 EVP_CIPHER_CTX *ctx = q_EVP_CIPHER_CTX_new();
490 if (q_EVP_CipherInit(ctx, type, nullptr, nullptr, enc) != 1) {
492 QTlsBackendOpenSSL::logAndClearErrorQueue();
493 return {};
494 }
495
496 q_EVP_CIPHER_CTX_set_key_length(ctx, key.size());
497 if (cipher == Cipher::Rc2Cbc)
498 q_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_SET_RC2_KEY_BITS, 8 * key.size(), nullptr);
499
500 q_EVP_CipherInit_ex(ctx, nullptr, nullptr,
501 reinterpret_cast<const unsigned char *>(key.constData()),
502 reinterpret_cast<const unsigned char *>(iv.constData()),
503 enc);
504 q_EVP_CipherUpdate(ctx,
505 reinterpret_cast<unsigned char *>(output.data()), &len,
506 reinterpret_cast<const unsigned char *>(data.constData()), data.size());
508 reinterpret_cast<unsigned char *>(output.data()) + len, &i);
509 len += i;
510
513
514 return output.left(len);
515}
516
517QByteArray TlsKeyOpenSSL::decrypt(Cipher cipher, const QByteArray &data,
518 const QByteArray &key, const QByteArray &iv) const
519{
520 return doCrypt(cipher, data, key, iv, false);
521}
522
523QByteArray TlsKeyOpenSSL::encrypt(Cipher cipher, const QByteArray &data,
524 const QByteArray &key, const QByteArray &iv) const
525{
526 return doCrypt(cipher, data, key, iv, true);
527}
528
529TlsKeyOpenSSL *TlsKeyOpenSSL::publicKeyFromX509(X509 *x)
530{
531 TlsKeyOpenSSL *tlsKey = new TlsKeyOpenSSL;
532 std::unique_ptr<TlsKeyOpenSSL> keyRaii(tlsKey);
533
534 tlsKey->keyType = QSsl::PublicKey;
535
536#ifndef OPENSSL_NO_DEPRECATED_3_0
537
538#define get_pubkey(keyName, alg) tlsKey->keyName = q_EVP_PKEY_get1_##alg(pkey)
539
540#else
541
542#define get_pubkey(a, b) tlsKey->genericKey = pkey
543
544#endif
545
546 EVP_PKEY *pkey = q_X509_get_pubkey(x);
547 Q_ASSERT(pkey);
548 const int keyType = q_EVP_PKEY_type(q_EVP_PKEY_base_id(pkey));
549
550#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
551 // ML-DSA don't have NIDs
552 const auto keyTypeName = QLatin1StringView(q_EVP_PKEY_type_name(pkey));
553#endif
554
555 if (keyType == EVP_PKEY_RSA) {
557 tlsKey->keyAlgorithm = QSsl::Rsa;
558 tlsKey->keyIsNull = false;
559 } else if (keyType == EVP_PKEY_DSA) {
561 tlsKey->keyAlgorithm = QSsl::Dsa;
562 tlsKey->keyIsNull = false;
563#ifndef OPENSSL_NO_EC
564 } else if (keyType == EVP_PKEY_EC) {
566 tlsKey->keyAlgorithm = QSsl::Ec;
567 tlsKey->keyIsNull = false;
568#endif
569 } else if (keyType == EVP_PKEY_DH) {
570 // DH unsupported (key is null)
571#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
572 } else if (keyTypeName.contains(QLatin1String("ML-DSA")) ||
573 keyTypeName.contains(QLatin1String("mldsa"))) {
574 tlsKey->genericKey = pkey;
575 tlsKey->keyAlgorithm = QSsl::MlDsa;
576 tlsKey->keyIsNull = false;
577#endif
578 } else {
579 // error? (key is null)
580 }
581
582#ifndef OPENSSL_NO_DEPRECATED_3_0
584#endif
585
586 return keyRaii.release();
587}
588
589} // namespace QTlsPrivate
590
591QT_END_NAMESPACE
static void logAndClearErrorQueue()
void decodePem(KeyType type, KeyAlgorithm algorithm, const QByteArray &pem, const QByteArray &passPhrase, bool deepClear) override
void clear(bool deep) override
bool fromEVP_PKEY(EVP_PKEY *pkey)
QByteArray derFromPem(const QByteArray &pem, QMap< QByteArray, QByteArray > *headers) const override
QByteArray decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv) const override
QByteArray toPem(const QByteArray &passPhrase) const override
int length() const override
Qt::HANDLE handle() const override
QByteArray encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv) const override
static TlsKeyOpenSSL * publicKeyFromX509(X509 *x)
Namespace containing onternal types that TLS backends implement.
QByteArray doCrypt(QSslKeyPrivate::Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv, bool enc)
int q_EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *c)
const EVP_CIPHER * q_EVP_des_cbc()
const EVP_CIPHER * q_EVP_aes_192_cbc()
const EVP_CIPHER * q_EVP_aes_256_cbc()
int q_EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, const unsigned char *key, const unsigned char *iv, int enc)
void q_DH_free(DH *dh)
const EVP_CIPHER * q_EVP_rc2_cbc()
int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b)
void q_DSA_free(DSA *a)
int q_DSA_bits(DSA *a)
#define q_BIO_get_mem_data(b, pp)
void q_EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *a)
RSA * q_EVP_PKEY_get1_RSA(EVP_PKEY *a)
int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b)
int q_DH_bits(DH *dh)
EVP_PKEY * q_PEM_read_bio_PrivateKey(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d)
EVP_PKEY * q_EVP_PKEY_new()
void q_EVP_PKEY_free(EVP_PKEY *a)
void q_EC_KEY_free(EC_KEY *ecdh)
BIO * q_BIO_new(const BIO_METHOD *a)
const EVP_CIPHER * q_EVP_des_ede3_cbc()
EVP_PKEY * q_PEM_read_bio_PUBKEY(BIO *a, EVP_PKEY **b, pem_password_cb *c, void *d)
int q_EVP_PKEY_up_ref(EVP_PKEY *a)
EVP_PKEY * q_X509_get_pubkey(X509 *a)
EC_KEY * q_EVP_PKEY_get1_EC_KEY(EVP_PKEY *a)
int q_EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl)
int q_EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc)
const BIO_METHOD * q_BIO_s_mem()
int q_PEM_write_bio_PUBKEY(BIO *a, EVP_PKEY *b)
int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b)
int q_EC_GROUP_get_degree(const EC_GROUP *g)
int q_RSA_bits(RSA *a)
DH * q_EVP_PKEY_get1_DH(EVP_PKEY *a)
DSA * q_EVP_PKEY_get1_DSA(EVP_PKEY *a)
const EVP_CIPHER * q_EVP_aes_128_cbc()
int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b)
EVP_CIPHER_CTX * q_EVP_CIPHER_CTX_new()
int q_EVP_PKEY_type(int a)
const EC_GROUP * q_EC_KEY_get0_group(const EC_KEY *k)
int q_BIO_free(BIO *a)
void q_RSA_free(RSA *a)
#define write_pubkey(alg, key)
#define write_privatekey(alg, key)
#define get_key(key, alg)
#define get_pubkey(keyName, alg)