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_generic.cpp
Go to the documentation of this file.
1// Copyright (C) 2014 Jeremy Lainé <jeremy.laine@m4x.org>
2// Copyright (C) 2021 The Qt Company Ltd.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:critical reason:data-parser
5
8
9#include <QtNetwork/private/qsslkey_p.h>
10
11#include <QtNetwork/qpassworddigestor.h>
12
13#include <QtCore/QMessageAuthenticationCode>
14#include <QtCore/qcryptographichash.h>
15#include <QtCore/qrandom.h>
16
17#include <QtCore/qdatastream.h>
18#include <QtCore/qbytearray.h>
19#include <QtCore/qdebug.h>
20#include <QtCore/qmap.h>
21
22#include <cstring>
23
24QT_BEGIN_NAMESPACE
25
26// The code here is essentially what we had in qsslkey_qt.cpp before, with
27// minimal changes/restructure.
28
29namespace QTlsPrivate {
30
31// OIDs of named curves allowed in TLS as per RFCs 4492 and 7027,
32// see also https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
33namespace {
34
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,
52};
53
54using OidLengthMap = QMap<QByteArray, int>;
55
56OidLengthMap createOidMap()
57{
58 OidLengthMap oids;
59 oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.10045.3.1.1"), 192); // secp192r1 a.k.a prime192v1
60 oids.insert(oids.cend(), QByteArrayLiteral("1.2.840.10045.3.1.7"), 256); // secp256r1 a.k.a prime256v1
61 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.1"), 193); // sect193r2
62 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.10"), 256); // secp256k1
63 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.16"), 283); // sect283k1
64 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.17"), 283); // sect283r1
65 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.26"), 233); // sect233k1
66 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.27"), 233); // sect233r1
67 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.3"), 239); // sect239k1
68 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.30"), 160); // secp160r2
69 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.31"), 192); // secp192k1
70 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.32"), 224); // secp224k1
71 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.33"), 224); // secp224r1
72 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.34"), 384); // secp384r1
73 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.35"), 521); // secp521r1
74 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.36"), 409); // sect409k1
75 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.37"), 409); // sect409r1
76 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.38"), 571); // sect571k1
77 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.39"), 571); // sect571r1
78 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.8"), 160); // secp160r1
79 oids.insert(oids.cend(), QByteArrayLiteral("1.3.132.0.9"), 160); // secp160k1
80 oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.11"), 384); // brainpoolP384r1
81 oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.13"), 512); // brainpoolP512r1
82 oids.insert(oids.cend(), QByteArrayLiteral("1.3.36.3.3.2.8.1.1.7"), 256); // brainpoolP256r1
83 return oids;
84}
85
86} // Unnamed namespace.
87
89
90namespace {
91
92// Maps OIDs to the encryption cipher they specify
93const QMap<QByteArray, QSslKeyPrivate::Cipher> oidCipherMap {
94 {DES_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::DesCbc},
95 {DES_EDE3_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::DesEde3Cbc},
96 // {PKCS5_MD2_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc}, // No MD2
97 {PKCS5_MD5_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc},
98 {PKCS5_SHA1_DES_CBC_OID, QSslKeyPrivate::Cipher::DesCbc},
99 // {PKCS5_MD2_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc}, // No MD2
100 {PKCS5_MD5_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc},
101 {PKCS5_SHA1_RC2_CBC_OID, QSslKeyPrivate::Cipher::Rc2Cbc},
102 {RC2_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Rc2Cbc}
103 // {RC5_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Rc5Cbc}, // No RC5
104 // {AES128_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes128}, // no AES
105 // {AES192_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes192},
106 // {AES256_CBC_ENCRYPTION_OID, QSslKeyPrivate::Cipher::Aes256}
107};
108
109struct EncryptionData
110{
111 EncryptionData() = default;
112
113 EncryptionData(QSslKeyPrivate::Cipher cipher, QByteArray key, QByteArray iv)
114 : initialized(true), cipher(cipher), key(key), iv(iv)
115 {
116 }
117 bool initialized = false;
118 QSslKeyPrivate::Cipher cipher;
119 QByteArray key;
120 QByteArray iv;
121};
122
123EncryptionData readPbes2(const QList<QAsn1Element> &element, const QByteArray &passPhrase)
124{
125 // RFC 8018: https://tools.ietf.org/html/rfc8018#section-6.2
126 /*** Scheme: ***
127 * Sequence (scheme-specific info..)
128 * Sequence (key derivation info)
129 * Object Identifier (Key derivation algorithm (e.g. PBKDF2))
130 * Sequence (salt)
131 * CHOICE (this entry can be either of the types it contains)
132 * Octet string (actual salt)
133 * Object identifier (Anything using this is deferred to a later version of PKCS #5)
134 * Integer (iteration count)
135 * Sequence (encryption algorithm info)
136 * Object identifier (identifier for the algorithm)
137 * Algorithm dependent, is covered in the switch further down
138 */
139
140 static const QMap<QByteArray, QCryptographicHash::Algorithm> pbes2OidHashFunctionMap {
141 // PBES2/PBKDF2
142 {HMAC_WITH_SHA1, QCryptographicHash::Sha1},
143 {HMAC_WITH_SHA224, QCryptographicHash::Sha224},
144 {HMAC_WITH_SHA256, QCryptographicHash::Sha256},
145 {HMAC_WITH_SHA512, QCryptographicHash::Sha512},
146 {HMAC_WITH_SHA512_224, QCryptographicHash::Sha512},
147 {HMAC_WITH_SHA512_256, QCryptographicHash::Sha512},
148 {HMAC_WITH_SHA384, QCryptographicHash::Sha384}
149 };
150
151 // Values from their respective sections here: https://tools.ietf.org/html/rfc8018#appendix-B.2
152 static const QMap<QSslKeyPrivate::Cipher, int> cipherKeyLengthMap {
153 {QSslKeyPrivate::Cipher::DesCbc, 8},
154 {QSslKeyPrivate::Cipher::DesEde3Cbc, 24},
155 // @note: variable key-length (https://tools.ietf.org/html/rfc8018#appendix-B.2.3)
156 {QSslKeyPrivate::Cipher::Rc2Cbc, 4}
157 // @todo: AES(, rc5?)
158 };
159
160 const QList<QAsn1Element> keyDerivationContainer = element[0].toList();
161 if (keyDerivationContainer.size() != 2
162 || keyDerivationContainer[0].type() != QAsn1Element::ObjectIdentifierType
163 || keyDerivationContainer[1].type() != QAsn1Element::SequenceType) {
164 return {};
165 }
166
167 const QByteArray keyDerivationAlgorithm = keyDerivationContainer[0].toObjectId();
168 const auto keyDerivationParams = keyDerivationContainer[1].toList();
169
170 const auto encryptionAlgorithmContainer = element[1].toList();
171 if (encryptionAlgorithmContainer.size() != 2
172 || encryptionAlgorithmContainer[0].type() != QAsn1Element::ObjectIdentifierType) {
173 return {};
174 }
175
176 auto iterator = oidCipherMap.constFind(encryptionAlgorithmContainer[0].toObjectId());
177 if (iterator == oidCipherMap.cend()) {
178 qWarning()
179 << "QSslKey: Unsupported encryption cipher OID:" << encryptionAlgorithmContainer[0].toObjectId()
180 << "\nFile a bug report to Qt (include the line above).";
181 return {};
182 }
183
184 QSslKeyPrivate::Cipher cipher = *iterator;
185 QByteArray key;
186 QByteArray iv;
187 switch (cipher) {
188 case QSslKeyPrivate::Cipher::DesCbc:
189 case QSslKeyPrivate::Cipher::DesEde3Cbc:
190 // https://tools.ietf.org/html/rfc8018#appendix-B.2.1 (DES-CBC-PAD)
191 // https://tools.ietf.org/html/rfc8018#appendix-B.2.2 (DES-EDE3-CBC-PAD)
192 // @todo https://tools.ietf.org/html/rfc8018#appendix-B.2.5 (AES-CBC-PAD)
193 /*** Scheme: ***
194 * Octet string (IV)
195 */
196 if (encryptionAlgorithmContainer[1].type() != QAsn1Element::OctetStringType)
197 return {};
198
199 // @note: All AES identifiers should be able to use this branch!!
200 iv = encryptionAlgorithmContainer[1].value();
201
202 if (iv.size() != 8) // @note: AES needs 16 bytes
203 return {};
204 break;
205 case QSslKeyPrivate::Cipher::Rc2Cbc: {
206 // https://tools.ietf.org/html/rfc8018#appendix-B.2.3
207 /*** Scheme: ***
208 * Sequence (rc2 parameters)
209 * Integer (rc2 parameter version)
210 * Octet string (IV)
211 */
212 if (encryptionAlgorithmContainer[1].type() != QAsn1Element::SequenceType)
213 return {};
214 const auto rc2ParametersContainer = encryptionAlgorithmContainer[1].toList();
215 if ((rc2ParametersContainer.size() != 1 && rc2ParametersContainer.size() != 2)
216 || rc2ParametersContainer.back().type() != QAsn1Element::OctetStringType) {
217 return {};
218 }
219 iv = rc2ParametersContainer.back().value();
220 if (iv.size() != 8)
221 return {};
222 break;
223 } // @todo(?): case (RC5 , AES)
224 case QSslKeyPrivate::Cipher::Aes128Cbc:
225 case QSslKeyPrivate::Cipher::Aes192Cbc:
226 case QSslKeyPrivate::Cipher::Aes256Cbc:
227 Q_UNREACHABLE();
228 }
229
230 if (Q_LIKELY(keyDerivationAlgorithm == PKCS5_PBKDF2_ENCRYPTION_OID)) {
231 // Definition: https://tools.ietf.org/html/rfc8018#appendix-A.2
232 QByteArray salt;
233 if (keyDerivationParams[0].type() == QAsn1Element::OctetStringType) {
234 salt = keyDerivationParams[0].value();
235 } else if (keyDerivationParams[0].type() == QAsn1Element::ObjectIdentifierType) {
236 Q_UNIMPLEMENTED();
237 /* See paragraph from https://tools.ietf.org/html/rfc8018#appendix-A.2
238 which ends with: "such facilities are deferred to a future version of PKCS #5"
239 */
240 return {};
241 } else {
242 return {};
243 }
244
245 // Iterations needed to derive the key
246 int iterationCount = keyDerivationParams[1].toInteger();
247 // Optional integer
248 int keyLength = -1;
249 int vectorPos = 2;
250 if (keyDerivationParams.size() > vectorPos
251 && keyDerivationParams[vectorPos].type() == QAsn1Element::IntegerType) {
252 keyLength = keyDerivationParams[vectorPos].toInteger(nullptr);
253 ++vectorPos;
254 } else {
255 keyLength = cipherKeyLengthMap[cipher];
256 }
257
258 // Optional algorithm identifier (default: HMAC-SHA-1)
259 QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha1;
260 if (keyDerivationParams.size() > vectorPos
261 && keyDerivationParams[vectorPos].type() == QAsn1Element::SequenceType) {
262 const auto hashAlgorithmContainer = keyDerivationParams[vectorPos].toList();
263 hashAlgorithm = pbes2OidHashFunctionMap[hashAlgorithmContainer.front().toObjectId()];
264 Q_ASSERT(hashAlgorithmContainer[1].type() == QAsn1Element::NullType);
265 ++vectorPos;
266 }
267 Q_ASSERT(keyDerivationParams.size() == vectorPos);
268
269 key = QPasswordDigestor::deriveKeyPbkdf2(hashAlgorithm, passPhrase, salt, iterationCount, keyLength);
270 } else {
271 qWarning()
272 << "QSslKey: Unsupported key derivation algorithm OID:" << keyDerivationAlgorithm
273 << "\nFile a bugreport to Qt (include the line above).";
274 return {};
275 }
276 return {cipher, key, iv};
277}
278
279// Maps OIDs to the hash function it specifies
280const QMap<QByteArray, QCryptographicHash::Algorithm> pbes1OidHashFunctionMap {
281 // PKCS5
282 //{PKCS5_MD2_DES_CBC_OID, QCryptographicHash::Md2}, No MD2
283 //{PKCS5_MD2_RC2_CBC_OID, QCryptographicHash::Md2},
284 {PKCS5_MD5_DES_CBC_OID, QCryptographicHash::Md5},
285 {PKCS5_MD5_RC2_CBC_OID, QCryptographicHash::Md5},
286 {PKCS5_SHA1_DES_CBC_OID, QCryptographicHash::Sha1},
287 {PKCS5_SHA1_RC2_CBC_OID, QCryptographicHash::Sha1},
288 // PKCS12 (unimplemented)
289 // {PKCS12_SHA1_RC4_128_OID, QCryptographicHash::Sha1}, // No RC4
290 // {PKCS12_SHA1_RC4_40_OID, QCryptographicHash::Sha1},
291 // @todo: lacking support. @note: there might be code to do this inside qsslsocket_mac...
292 // further note that more work may be required for the 3DES variations listed to be available.
293 // {PKCS12_SHA1_3KEY_3DES_CBC_OID, QCryptographicHash::Sha1},
294 // {PKCS12_SHA1_2KEY_3DES_CBC_OID, QCryptographicHash::Sha1},
295 // {PKCS12_SHA1_RC2_128_CBC_OID, QCryptographicHash::Sha1},
296 // {PKCS12_SHA1_RC2_40_CBC_OID, QCryptographicHash::Sha1}
297};
298
299EncryptionData readPbes1(const QList<QAsn1Element> &element, const QByteArray &encryptionScheme,
300 const QByteArray &passPhrase)
301{
302 // RFC 8018: https://tools.ietf.org/html/rfc8018#section-6.1
303 // Steps refer to this section: https://tools.ietf.org/html/rfc8018#section-6.1.2
304 /*** Scheme: ***
305 * Sequence (PBE Parameter)
306 * Octet string (salt)
307 * Integer (iteration counter)
308 */
309 // Step 1
310 if (element.size() != 2
311 || element[0].type() != QAsn1Element::ElementType::OctetStringType
312 || element[1].type() != QAsn1Element::ElementType::IntegerType) {
313 return {};
314 }
315 QByteArray salt = element[0].value();
316 if (salt.size() != 8)
317 return {};
318
319 int iterationCount = element[1].toInteger();
320 if (iterationCount < 0)
321 return {};
322
323 // Step 2
324 auto iterator = pbes1OidHashFunctionMap.constFind(encryptionScheme);
325 if (iterator == pbes1OidHashFunctionMap.cend()) {
326 // Qt was compiled with ONLY_SHA1 (or it's MD2)
327 return {};
328 }
329 QCryptographicHash::Algorithm hashAlgorithm = *iterator;
330 QByteArray key = QPasswordDigestor::deriveKeyPbkdf1(hashAlgorithm, passPhrase, salt, iterationCount, 16);
331 if (key.size() != 16)
332 return {};
333
334 // Step 3
335 QByteArray iv = key.right(8); // last 8 bytes are used as IV
336 key.truncate(8); // first 8 bytes are used for the key
337
338 QSslKeyPrivate::Cipher cipher = oidCipherMap[encryptionScheme];
339 // Steps 4-6 are done after returning
340 return {cipher, key, iv};
341}
342
343int curveBits(const QByteArray &oid)
344{
345 const int length = oidLengthMap->value(oid);
346 return length ? length : -1;
347}
348
349int numberOfBits(const QByteArray &modulus)
350{
351 int bits = modulus.size() * 8;
352 for (int i = 0; i < modulus.size(); ++i) {
353 quint8 b = modulus[i];
354 bits -= 8;
355 if (b != 0) {
356 bits += bits_table[b];
357 break;
358 }
359 }
360 return bits;
361}
362
363QByteArray deriveAesKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase,
364 const QByteArray &iv)
365{
366 // This is somewhat simplified and shortened version of what OpenSSL does.
367 // See, for example, EVP_BytesToKey for the "algorithm" itself and elsewhere
368 // in their code for what they pass as arguments to EVP_BytesToKey when
369 // deriving encryption keys (when reading/writing pems files with encrypted
370 // keys).
371
372 Q_ASSERT(iv.size() >= 8);
373
374 QCryptographicHash hash(QCryptographicHash::Md5);
375
376 QByteArray data(passPhrase);
377 data.append(iv.data(), 8); // AKA PKCS5_SALT_LEN in OpenSSL.
378
379 hash.addData(data);
380
381 if (cipher == Cipher::Aes128Cbc)
382 return hash.result();
383
384 QByteArray key(hash.result());
385 hash.reset();
386 hash.addData(key);
387 hash.addData(data);
388
389 if (cipher == Cipher::Aes192Cbc)
390 return key.append(hash.resultView().first(8));
391
392 return key.append(hash.resultView());
393}
394
395QByteArray deriveKey(QSslKeyPrivate::Cipher cipher, const QByteArray &passPhrase,
396 const QByteArray &iv)
397{
398 QByteArray key;
399 QCryptographicHash hash(QCryptographicHash::Md5);
400 hash.addData(passPhrase);
401 hash.addData(iv);
402 switch (cipher) {
403 case Cipher::DesCbc:
404 key = hash.result().left(8);
405 break;
406 case Cipher::DesEde3Cbc:
407 key = hash.result();
408 hash.reset();
409 hash.addData(key);
410 hash.addData(passPhrase);
411 hash.addData(iv);
412 key += hash.result().left(8);
413 break;
414 case Cipher::Rc2Cbc:
415 key = hash.result();
416 break;
417 case Cipher::Aes128Cbc:
418 case Cipher::Aes192Cbc:
419 case Cipher::Aes256Cbc:
420 return deriveAesKey(cipher, passPhrase, iv);
421 }
422 return key;
423}
424
425int extractPkcs8KeyLength(const QList<QAsn1Element> &items, TlsKey *that)
426{
427 Q_ASSERT(items.size() == 3);
428 Q_ASSERT(that);
429
430 int keyLength = -1;
431
432 auto getName = [](QSsl::KeyAlgorithm algorithm) {
433 switch (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";
439 }
440 Q_UNREACHABLE();
441 };
442
443 const auto pkcs8Info = items[1].toList();
444 if (pkcs8Info.size() != 2 || pkcs8Info[0].type() != QAsn1Element::ObjectIdentifierType)
445 return -1;
446 const QByteArray value = pkcs8Info[0].toObjectId();
447 if (value == RSA_ENCRYPTION_OID) {
448 if (Q_UNLIKELY(that->algorithm() != QSsl::Rsa)) {
449 // We could change the 'algorithm' of QSslKey here and continue loading, but
450 // this is not supported in the openssl back-end, so we'll fail here and give
451 // the user some feedback.
452 qWarning() << "QSslKey: Found RSA key when asked to use" << getName(that->algorithm())
453 << "\nLoading will fail.";
454 return -1;
455 }
456 // Luckily it contains the 'normal' RSA-key format inside, so we can just recurse
457 // and read the key's info.
458 that->decodeDer(that->type(), that->algorithm(), items[2].value(), {}, true);
459 // The real info has been filled out in the call above, so return as if it was invalid
460 // to avoid overwriting the data.
461 return -1;
462 } else if (value == EC_ENCRYPTION_OID) {
463 if (Q_UNLIKELY(that->algorithm() != QSsl::Ec)) {
464 // As above for RSA.
465 qWarning() << "QSslKey: Found EC key when asked to use" << getName(that->algorithm())
466 << "\nLoading will fail.";
467 return -1;
468 }
469 // I don't know where this is documented, but the elliptic-curve identifier has been
470 // moved into the "pkcs#8 wrapper", which is what we're interested in.
471 if (pkcs8Info[1].type() != QAsn1Element::ObjectIdentifierType)
472 return -1;
473 keyLength = curveBits(pkcs8Info[1].toObjectId());
474 } else if (value == DSA_ENCRYPTION_OID) {
475 if (Q_UNLIKELY(that->algorithm() != QSsl::Dsa)) {
476 // As above for RSA.
477 qWarning() << "QSslKey: Found DSA when asked to use" << getName(that->algorithm())
478 << "\nLoading will fail.";
479 return -1;
480 }
481 // DSA's structure is documented here:
482 // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
483 if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
484 return -1;
485 const auto dsaInfo = pkcs8Info[1].toList();
486 if (dsaInfo.size() != 3 || dsaInfo[0].type() != QAsn1Element::IntegerType)
487 return -1;
488 keyLength = numberOfBits(dsaInfo[0].value());
489 } else if (value == DH_ENCRYPTION_OID) {
490 if (Q_UNLIKELY(that->algorithm() != QSsl::Dh)) {
491 // As above for RSA.
492 qWarning() << "QSslKey: Found DH when asked to use" << getName(that->algorithm())
493 << "\nLoading will fail.";
494 return -1;
495 }
496 // DH's structure is documented here:
497 // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
498 if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
499 return -1;
500 const auto dhInfo = pkcs8Info[1].toList();
501 if (dhInfo.size() < 2 || dhInfo.size() > 3 || dhInfo[0].type() != QAsn1Element::IntegerType)
502 return -1;
503 keyLength = numberOfBits(dhInfo[0].value());
504 } else {
505 // in case of unexpected formats:
506 qWarning() << "QSslKey: Unsupported PKCS#8 key algorithm:" << value
507 << "\nFile a bugreport to Qt (include the line above).";
508 return -1;
509 }
510
511 return keyLength;
512}
513
514} // Unnamed namespace
515
517 const QByteArray &passPhrase, bool deepClear)
518{
519 keyType = type;
521
523
524 if (der.isEmpty())
525 return;
526 // decryptPkcs8 decrypts if necessary or returns 'der' unaltered
528
531 return;
532
533 if (type == QSsl::PublicKey) {
534 // key info
537 return;
538 const auto infoItems = elem.toList();
540 return;
541 if (algorithm == QSsl::Rsa) {
543 return;
544 // key data
546 return;
548 return;
550 return;
552 } else if (algorithm == QSsl::Dsa) {
554 return;
556 return;
557 // key params
558 const auto params = infoItems[1].toList();
560 return;
562 } else if (algorithm == QSsl::Dh) {
564 return;
566 return;
567 // key params
568 const auto params = infoItems[1].toList();
570 return;
572 } else if (algorithm == QSsl::Ec) {
574 return;
576 return;
578 }
579
580 } else {
581 const auto items = elem.toList();
582 if (items.isEmpty())
583 return;
584
585 // version
586 if (items[0].type() != QAsn1Element::IntegerType)
587 return;
588 const QByteArray versionHex = items[0].value().toHex();
589
590 if (items.size() == 3 && items[1].type() == QAsn1Element::SequenceType
592 if (versionHex != "00" && versionHex != "01")
593 return;
595 if (pkcs8KeyLength == -1)
596 return;
597 pkcs8 = true;
599 } else if (algorithm == QSsl::Rsa) {
600 if (versionHex != "00")
601 return;
602 if (items.size() != 9 || items[1].type() != QAsn1Element::IntegerType)
603 return;
605 } else if (algorithm == QSsl::Dsa) {
606 if (versionHex != "00")
607 return;
608 if (items.size() != 6 || items[1].type() != QAsn1Element::IntegerType)
609 return;
611 } else if (algorithm == QSsl::Dh) {
612 if (versionHex != "00")
613 return;
614 if (items.size() < 5 || items.size() > 6 || items[1].type() != QAsn1Element::IntegerType)
615 return;
617 } else if (algorithm == QSsl::Ec) {
618 if (versionHex != "01")
619 return;
620 if (items.size() != 4
624 return;
626 if (!oidElem.read(items[2].value())
628 return;
630 }
631 }
632
634 keyIsNull = false;
635}
636
638 const QByteArray &passPhrase, bool deepClear)
639{
640 keyType = type;
642
645
646 if (headers.value("Proc-Type") == "4,ENCRYPTED") {
647 const QList<QByteArray> dekInfo = headers.value("DEK-Info").split(',');
648 if (dekInfo.size() != 2) {
650 return;
651 }
652
654 if (dekInfo.first() == "DES-CBC") {
656 } else if (dekInfo.first() == "DES-EDE3-CBC") {
658 } else if (dekInfo.first() == "RC2-CBC") {
660 } else if (dekInfo.first() == "AES-128-CBC") {
662 } else if (dekInfo.first() == "AES-192-CBC") {
664 } else if (dekInfo.first() == "AES-256-CBC") {
666 } else {
668 return;
669 }
670
674 }
675
677}
678
679QByteArray TlsKeyGeneric::toPem(const QByteArray &passPhrase) const
680{
681 QByteArray data;
682 QMap<QByteArray, QByteArray> headers;
683
684 if (type() == QSsl::PrivateKey && !passPhrase.isEmpty()) {
685 // ### use a cryptographically secure random number generator
686 quint64 random = QRandomGenerator::system()->generate64();
687 QByteArray iv = QByteArray::fromRawData(reinterpret_cast<const char *>(&random), sizeof(random));
688
689 auto cipher = Cipher::DesEde3Cbc;
690 const QByteArray key = deriveKey(cipher, passPhrase, iv);
691 data = encrypt(cipher, derData, key, iv);
692
693 headers.insert("Proc-Type", "4,ENCRYPTED");
694 headers.insert("DEK-Info", "DES-EDE3-CBC," + iv.toHex());
695 } else {
696 data = derData;
697 }
698
699 return pemFromDer(data, headers);
700}
701
702QByteArray TlsKeyGeneric::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
703{
704 if (derData.size())
705 return derData;
706
707 QByteArray header = pemHeader();
708 QByteArray footer = pemFooter();
709
710 QByteArray der(pem);
711
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());
720 }
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());
726 }
727 }
728 if (headerIndex == -1 || footerIndex == -1)
729 return QByteArray();
730
731 der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
732
733 if (der.contains("Proc-Type:")) {
734 // taken from QHttpNetworkReplyPrivate::parseHeader
735 int i = 0;
736 while (i < der.length()) {
737 int j = der.indexOf(':', i); // field-name
738 if (j == -1)
739 break;
740 const QByteArray field = der.mid(i, j - i).trimmed();
741 j++;
742 // any number of LWS is allowed before and after the value
743 QByteArray value;
744 do {
745 i = der.indexOf('\n', j);
746 if (i == -1)
747 break;
748 if (!value.isEmpty())
749 value += ' ';
750 // check if we have CRLF or only LF
751 bool hasCR = (i && der[i-1] == '\r');
752 int length = i -(hasCR ? 1: 0) - j;
753 value += der.mid(j, length).trimmed();
754 j = ++i;
755 } while (i < der.length() && (der.at(i) == ' ' || der.at(i) == '\t'));
756 if (i == -1)
757 break; // something is wrong
758
759 headers->insert(field, value);
760 }
761 der = der.mid(i);
762 }
763
764 return QByteArray::fromBase64(der); // ignores newlines
765}
766
768{
769 opaque = handle;
771}
772
773void TlsKeyGeneric::clear(bool deep)
774{
775 keyIsNull = true;
776 if (deep)
777 std::memset(derData.data(), 0, derData.size());
778 derData.clear();
779 keyLength = -1;
780}
781
782QByteArray TlsKeyGeneric::decryptPkcs8(const QByteArray &encrypted, const QByteArray &passPhrase)
783{
784 // RFC 5958: https://tools.ietf.org/html/rfc5958
785 /*** Scheme: ***
786 * Sequence
787 * Sequence
788 * Object Identifier (encryption scheme (currently PBES2, PBES1, @todo PKCS12))
789 * Sequence (scheme parameters)
790 * Octet String (the encrypted data)
791 */
792 QAsn1Element elem;
793 if (!elem.read(encrypted) || elem.type() != QAsn1Element::SequenceType)
794 return encrypted;
795
796 const auto items = elem.toList();
797 if (items.size() != 2
798 || items[0].type() != QAsn1Element::SequenceType
799 || items[1].type() != QAsn1Element::OctetStringType) {
800 return encrypted;
801 }
802
803 const auto encryptionSchemeContainer = items[0].toList();
804
805 if (encryptionSchemeContainer.size() != 2
806 || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
807 || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
808 return encrypted;
809 }
810
811 const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
812 const auto schemeParameterContainer = encryptionSchemeContainer[1].toList();
813
814 if (schemeParameterContainer.size() != 2
815 && schemeParameterContainer[0].type() != QAsn1Element::SequenceType
816 && schemeParameterContainer[1].type() != QAsn1Element::SequenceType) {
817 return encrypted;
818 }
819
820 EncryptionData data;
821 if (encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID) {
822 data = readPbes2(schemeParameterContainer, passPhrase);
823 } else if (pbes1OidHashFunctionMap.contains(encryptionScheme)) {
824 data = readPbes1(schemeParameterContainer, encryptionScheme, passPhrase);
825 } else if (encryptionScheme.startsWith(PKCS12_OID)) {
826 Q_UNIMPLEMENTED(); // this isn't some 'unknown', I know these aren't implemented
827 return encrypted;
828 } else {
829 qWarning()
830 << "QSslKey: Unsupported encryption scheme OID:" << encryptionScheme
831 << "\nFile a bugreport to Qt (include the line above).";
832 return encrypted;
833 }
834
835 if (!data.initialized) {
836 // something went wrong, return
837 return encrypted;
838 }
839
840 QByteArray decryptedKey = decrypt(data.cipher, items[1].value(), data.key, data.iv);
841 // The data is still wrapped in a octet string, so let's unwrap it
842 QAsn1Element decryptedKeyElement(QAsn1Element::ElementType::OctetStringType, decryptedKey);
843 return decryptedKeyElement.value();
844}
845
846} // namespace QTlsPrivate
847
848QT_END_NAMESPACE
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 HMAC_WITH_SHA224
#define HMAC_WITH_SHA512
#define PKCS5_MD5_DES_CBC_OID
#define EC_ENCRYPTION_OID
#define PKCS12_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 HMAC_WITH_SHA256
#define DES_CBC_ENCRYPTION_OID
#define DES_EDE3_CBC_ENCRYPTION_OID
#define HMAC_WITH_SHA384
#define PKCS5_MD5_RC2_CBC_OID
#define HMAC_WITH_SHA512_224
#define HMAC_WITH_SHA1
#define PKCS5_SHA1_DES_CBC_OID