9#include <QtNetwork/private/qsslkey_p.h>
11#include <QtNetwork/qpassworddigestor.h>
13#include <QtCore/QMessageAuthenticationCode>
14#include <QtCore/qcryptographichash.h>
15#include <QtCore/qrandom.h>
17#include <QtCore/qdatastream.h>
18#include <QtCore/qbytearray.h>
19#include <QtCore/qdebug.h>
20#include <QtCore/qmap.h>
35const quint8 bits_table[256] = {
36 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,
37 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
38 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
39 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
40 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
41 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
42 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
43 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
44 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
45 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
46 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
47 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
48 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
49 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
50 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
51 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
54using OidLengthMap = QMap<QByteArray,
int>;
56OidLengthMap createOidMap()
59 oids.insert(oids.cend(), QByteArrayLiteral(
"1.2.840.10045.3.1.1"), 192);
60 oids.insert(oids.cend(), QByteArrayLiteral(
"1.2.840.10045.3.1.7"), 256);
61 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.1"), 193);
62 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.10"), 256);
63 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.16"), 283);
64 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.17"), 283);
65 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.26"), 233);
66 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.27"), 233);
67 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.3"), 239);
68 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.30"), 160);
69 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.31"), 192);
70 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.32"), 224);
71 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.33"), 224);
72 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.34"), 384);
73 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.35"), 521);
74 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.36"), 409);
75 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.37"), 409);
76 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.38"), 571);
77 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.39"), 571);
78 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.8"), 160);
79 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.132.0.9"), 160);
80 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.36.3.3.2.8.1.1.11"), 384);
81 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.36.3.3.2.8.1.1.13"), 512);
82 oids.insert(oids.cend(), QByteArrayLiteral(
"1.3.36.3.3.2.8.1.1.7"), 256);
93const QMap<QByteArray, QSslKeyPrivate::Cipher> oidCipherMap {
111 EncryptionData() =
default;
113 EncryptionData(QSslKeyPrivate::Cipher cipher, QByteArray key, QByteArray iv)
114 : initialized(
true), cipher(cipher), key(key), iv(iv)
117 bool initialized =
false;
118 QSslKeyPrivate::Cipher cipher;
123EncryptionData readPbes2(
const QList<QAsn1Element> &element,
const QByteArray &passPhrase)
127
128
129
130
131
132
133
134
135
136
137
138
140 static const QMap<QByteArray, QCryptographicHash::Algorithm> pbes2OidHashFunctionMap {
152 static const QMap<QSslKeyPrivate::Cipher,
int> cipherKeyLengthMap {
153 {QSslKeyPrivate::Cipher::DesCbc, 8},
154 {QSslKeyPrivate::Cipher::DesEde3Cbc, 24},
156 {QSslKeyPrivate::Cipher::Rc2Cbc, 4}
160 const QList<QAsn1Element> keyDerivationContainer = element[0].toList();
161 if (keyDerivationContainer.size() != 2
167 const QByteArray keyDerivationAlgorithm = keyDerivationContainer[0].toObjectId();
168 const auto keyDerivationParams = keyDerivationContainer[1].toList();
170 const auto encryptionAlgorithmContainer = element[1].toList();
171 if (encryptionAlgorithmContainer.size() != 2
176 auto iterator = oidCipherMap.constFind(encryptionAlgorithmContainer[0].toObjectId());
177 if (iterator == oidCipherMap.cend()) {
179 <<
"QSslKey: Unsupported encryption cipher OID:" << encryptionAlgorithmContainer[0].toObjectId()
180 <<
"\nFile a bug report to Qt (include the line above).";
184 QSslKeyPrivate::Cipher cipher = *iterator;
188 case QSslKeyPrivate::Cipher::DesCbc:
189 case QSslKeyPrivate::Cipher::DesEde3Cbc:
194
195
200 iv = encryptionAlgorithmContainer[1].value();
205 case QSslKeyPrivate::Cipher::Rc2Cbc: {
208
209
210
211
214 const auto rc2ParametersContainer = encryptionAlgorithmContainer[1].toList();
215 if ((rc2ParametersContainer.size() != 1 && rc2ParametersContainer.size() != 2)
219 iv = rc2ParametersContainer.back().value();
224 case QSslKeyPrivate::Cipher::Aes128Cbc:
225 case QSslKeyPrivate::Cipher::Aes192Cbc:
226 case QSslKeyPrivate::Cipher::Aes256Cbc:
234 salt = keyDerivationParams[0].value();
238
239
246 int iterationCount = keyDerivationParams[1].toInteger();
250 if (keyDerivationParams.size() > vectorPos
252 keyLength = keyDerivationParams[vectorPos].toInteger(
nullptr);
255 keyLength = cipherKeyLengthMap[cipher];
259 QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
260 if (keyDerivationParams.size() > vectorPos
262 const auto hashAlgorithmContainer = keyDerivationParams[vectorPos].toList();
263 hashAlgorithm = pbes2OidHashFunctionMap[hashAlgorithmContainer.front().toObjectId()];
267 Q_ASSERT(keyDerivationParams.size() == vectorPos);
269 key = QPasswordDigestor::deriveKeyPbkdf2(hashAlgorithm, passPhrase, salt, iterationCount, keyLength);
272 <<
"QSslKey: Unsupported key derivation algorithm OID:" << keyDerivationAlgorithm
273 <<
"\nFile a bugreport to Qt (include the line above).";
276 return {cipher, key, iv};
280const QMap<QByteArray, QCryptographicHash::Algorithm> pbes1OidHashFunctionMap {
299EncryptionData readPbes1(
const QList<QAsn1Element> &element,
const QByteArray &encryptionScheme,
300 const QByteArray &passPhrase)
305
306
307
308
310 if (element.size() != 2
315 QByteArray salt = element[0].value();
316 if (salt.size() != 8)
319 int iterationCount = element[1].toInteger();
320 if (iterationCount < 0)
324 auto iterator = pbes1OidHashFunctionMap.constFind(encryptionScheme);
325 if (iterator == pbes1OidHashFunctionMap.cend()) {
329 QCryptographicHash::Algorithm hashAlgorithm = *iterator;
330 QByteArray key = QPasswordDigestor::deriveKeyPbkdf1(hashAlgorithm, passPhrase, salt, iterationCount, 16);
331 if (key.size() != 16)
335 QByteArray iv = key.right(8);
338 QSslKeyPrivate::Cipher cipher = oidCipherMap[encryptionScheme];
340 return {cipher, key, iv};
343int curveBits(
const QByteArray &oid)
345 const int length = oidLengthMap->value(oid);
346 return length ? length : -1;
349int numberOfBits(
const QByteArray &modulus)
351 int bits = modulus.size() * 8;
352 for (
int i = 0; i < modulus.size(); ++i) {
353 quint8 b = modulus[i];
356 bits += bits_table[b];
363QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher,
const QByteArray &passPhrase,
364 const QByteArray &iv)
372 Q_ASSERT(iv.size() >= 8);
374 QCryptographicHash hash(QCryptographicHash::Md5);
376 QByteArray data(passPhrase);
377 data.append(iv.data(), 8);
381 if (cipher == Cipher::Aes128Cbc)
382 return hash.result();
384 QByteArray key(hash.result());
389 if (cipher == Cipher::Aes192Cbc)
390 return key.append(hash.resultView().first(8));
392 return key.append(hash.resultView());
395QByteArray deriveKey(QSslKeyPrivate::Cipher cipher,
const QByteArray &passPhrase,
396 const QByteArray &iv)
399 QCryptographicHash hash(QCryptographicHash::Md5);
400 hash.addData(passPhrase);
404 key = hash.result().left(8);
406 case Cipher::DesEde3Cbc:
410 hash.addData(passPhrase);
412 key += hash.result().left(8);
417 case Cipher::Aes128Cbc:
418 case Cipher::Aes192Cbc:
419 case Cipher::Aes256Cbc:
420 return deriveAesKey(cipher, passPhrase, iv);
425int extractPkcs8KeyLength(
const QList<QAsn1Element> &items, TlsKey *that)
427 Q_ASSERT(items.size() == 3);
432 auto getName = [](QSsl::KeyAlgorithm algorithm) {
434 case QSsl::Rsa:
return "RSA";
435 case QSsl::Dsa:
return "DSA";
436 case QSsl::Dh:
return "DH";
437 case QSsl::Ec:
return "EC";
438 default:
return "Opaque";
443 const auto pkcs8Info = items[1].toList();
446 const QByteArray value = pkcs8Info[0].toObjectId();
448 if (Q_UNLIKELY(that->algorithm() != QSsl::Rsa)) {
452 qWarning() <<
"QSslKey: Found RSA key when asked to use" << getName(that->algorithm())
453 <<
"\nLoading will fail.";
458 that->decodeDer(that->type(), that->algorithm(), items[2].value(), {},
true);
463 if (Q_UNLIKELY(that->algorithm() != QSsl::Ec)) {
465 qWarning() <<
"QSslKey: Found EC key when asked to use" << getName(that->algorithm())
466 <<
"\nLoading will fail.";
473 keyLength = curveBits(pkcs8Info[1].toObjectId());
475 if (Q_UNLIKELY(that->algorithm() != QSsl::Dsa)) {
477 qWarning() <<
"QSslKey: Found DSA when asked to use" << getName(that->algorithm())
478 <<
"\nLoading will fail.";
485 const auto dsaInfo = pkcs8Info[1].toList();
488 keyLength = numberOfBits(dsaInfo[0].value());
490 if (Q_UNLIKELY(that->algorithm() != QSsl::Dh)) {
492 qWarning() <<
"QSslKey: Found DH when asked to use" << getName(that->algorithm())
493 <<
"\nLoading will fail.";
500 const auto dhInfo = pkcs8Info[1].toList();
503 keyLength = numberOfBits(dhInfo[0].value());
506 qWarning() <<
"QSslKey: Unsupported PKCS#8 key algorithm:" << value
507 <<
"\nFile a bugreport to Qt (include the line above).";
682 QMap<QByteArray, QByteArray> headers;
684 if (type() == QSsl::PrivateKey && !passPhrase.isEmpty()) {
686 quint64 random = QRandomGenerator::system()->generate64();
687 QByteArray iv = QByteArray::fromRawData(
reinterpret_cast<
const char *>(&random),
sizeof(random));
689 auto cipher = Cipher::DesEde3Cbc;
690 const QByteArray key = deriveKey(cipher, passPhrase, iv);
691 data = encrypt(cipher, derData, key, iv);
693 headers.insert(
"Proc-Type",
"4,ENCRYPTED");
694 headers.insert(
"DEK-Info",
"DES-EDE3-CBC," + iv.toHex());
699 return pemFromDer(data, headers);
707 QByteArray header = pemHeader();
708 QByteArray footer = pemFooter();
712 int headerIndex = der.indexOf(header);
713 int footerIndex = der.indexOf(footer, headerIndex + header.length());
714 if (type() != QSsl::PublicKey) {
715 if (headerIndex == -1 || footerIndex == -1) {
716 header = pkcs8Header(
true);
717 footer = pkcs8Footer(
true);
718 headerIndex = der.indexOf(header);
719 footerIndex = der.indexOf(footer, headerIndex + header.length());
721 if (headerIndex == -1 || footerIndex == -1) {
722 header = pkcs8Header(
false);
723 footer = pkcs8Footer(
false);
724 headerIndex = der.indexOf(header);
725 footerIndex = der.indexOf(footer, headerIndex + header.length());
728 if (headerIndex == -1 || footerIndex == -1)
731 der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
733 if (der.contains(
"Proc-Type:")) {
736 while (i < der.length()) {
737 int j = der.indexOf(
':', i);
740 const QByteArray field = der.mid(i, j - i).trimmed();
745 i = der.indexOf(
'\n', j);
748 if (!value.isEmpty())
751 bool hasCR = (i && der[i-1] ==
'\r');
752 int length = i -(hasCR ? 1: 0) - j;
753 value += der.mid(j, length).trimmed();
755 }
while (i < der.length() && (der.at(i) ==
' ' || der.at(i) ==
'\t'));
759 headers->insert(field, value);
764 return QByteArray::fromBase64(der);
777 std::memset(derData.data(), 0, derData.size());
782QByteArray
TlsKeyGeneric::decryptPkcs8(
const QByteArray &encrypted,
const QByteArray &passPhrase)
786
787
788
789
790
791
796 const auto items = elem.toList();
797 if (items.size() != 2
803 const auto encryptionSchemeContainer = items[0].toList();
805 if (encryptionSchemeContainer.size() != 2
811 const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
812 const auto schemeParameterContainer = encryptionSchemeContainer[1].toList();
814 if (schemeParameterContainer.size() != 2
822 data = readPbes2(schemeParameterContainer, passPhrase);
823 }
else if (pbes1OidHashFunctionMap.contains(encryptionScheme)) {
824 data = readPbes1(schemeParameterContainer, encryptionScheme, passPhrase);
825 }
else if (encryptionScheme.startsWith(
PKCS12_OID)) {
830 <<
"QSslKey: Unsupported encryption scheme OID:" << encryptionScheme
831 <<
"\nFile a bugreport to Qt (include the line above).";
835 if (!data.initialized) {
840 QByteArray decryptedKey = decrypt(data.cipher, items[1].value(), data.key, data.iv);
843 return decryptedKeyElement.value();
QByteArray derFromPem(const QByteArray &pem, QMap< QByteArray, QByteArray > *headers) const override
QByteArray toPem(const QByteArray &passPhrase) const override
void clear(bool deep) override
Namespace containing onternal types that TLS backends implement.
Q_GLOBAL_STATIC_WITH_ARGS(OidLengthMap, oidLengthMap,(createOidMap())) namespace
#define PKCS5_MD5_DES_CBC_OID
#define EC_ENCRYPTION_OID
#define RC2_CBC_ENCRYPTION_OID
#define PKCS5_PBES2_ENCRYPTION_OID
#define HMAC_WITH_SHA512_256
#define DSA_ENCRYPTION_OID
#define RSA_ENCRYPTION_OID
#define PKCS5_PBKDF2_ENCRYPTION_OID
#define DH_ENCRYPTION_OID
#define PKCS5_SHA1_RC2_CBC_OID
#define DES_CBC_ENCRYPTION_OID
#define DES_EDE3_CBC_ENCRYPTION_OID
#define PKCS5_MD5_RC2_CBC_OID
#define HMAC_WITH_SHA512_224
#define PKCS5_SHA1_DES_CBC_OID