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