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