1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
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 
41 /*!
42     \class QSslKey
43     \brief The QSslKey class provides an interface for private and public keys.
44     \since 4.3
45 
46     \reentrant
47     \ingroup network
48     \ingroup ssl
49     \ingroup shared
50     \inmodule QtNetwork
51 
52     QSslKey provides a simple API for managing keys.
53 
54     \sa QSslSocket, QSslCertificate, QSslCipher
55 */
56 
57 #include "qsslkey.h"
58 #include "qsslkey_p.h"
59 #ifndef QT_NO_OPENSSL
60 #include "qsslsocket_openssl_symbols_p.h"
61 #endif
62 #include "qsslsocket.h"
63 #include "qsslsocket_p.h"
64 #include "qasn1element_p.h"
65 
66 #include <QtCore/qatomic.h>
67 #include <QtCore/qbytearray.h>
68 #include <QtCore/qiodevice.h>
69 #ifndef QT_NO_DEBUG_STREAM
70 #include <QtCore/qdebug.h>
71 #endif
72 
73 QT_BEGIN_NAMESPACE
74 
75 /*!
76     \fn void QSslKeyPrivate::clear(bool deep)
77     \internal
78  */
79 
80 /*!
81     \fn void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
82                                bool deepClear)
83     \internal
84 
85     Allocates a new rsa or dsa struct and decodes \a pem into it
86     according to the current algorithm and type.
87 
88     If \a deepClear is true, the rsa/dsa struct is freed if it is was
89     already allocated, otherwise we "leak" memory (which is exactly
90     what we want for copy construction).
91 
92     If \a passPhrase is non-empty, it will be used for decrypting
93     \a pem.
94 */
95 
96 /*!
97     Constructs a null key.
98 
99     \sa isNull()
100 */
QSslKey()101 QSslKey::QSslKey()
102     : d(new QSslKeyPrivate)
103 {
104 }
105 
106 /*!
107     \internal
108 */
pemHeader() const109 QByteArray QSslKeyPrivate::pemHeader() const
110 {
111     if (type == QSsl::PublicKey)
112         return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----");
113     else if (algorithm == QSsl::Rsa)
114         return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----");
115     else if (algorithm == QSsl::Dsa)
116         return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----");
117     else if (algorithm == QSsl::Ec)
118         return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----");
119     else if (algorithm == QSsl::Dh)
120         return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
121 
122     Q_UNREACHABLE();
123     return QByteArray();
124 }
125 
pkcs8Header(bool encrypted)126 static QByteArray pkcs8Header(bool encrypted)
127 {
128     return encrypted
129         ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----")
130         : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
131 }
132 
133 /*!
134     \internal
135 */
pemFooter() const136 QByteArray QSslKeyPrivate::pemFooter() const
137 {
138     if (type == QSsl::PublicKey)
139         return QByteArrayLiteral("-----END PUBLIC KEY-----");
140     else if (algorithm == QSsl::Rsa)
141         return QByteArrayLiteral("-----END RSA PRIVATE KEY-----");
142     else if (algorithm == QSsl::Dsa)
143         return QByteArrayLiteral("-----END DSA PRIVATE KEY-----");
144     else if (algorithm == QSsl::Ec)
145         return QByteArrayLiteral("-----END EC PRIVATE KEY-----");
146     else if (algorithm == QSsl::Dh)
147         return QByteArrayLiteral("-----END PRIVATE KEY-----");
148 
149     Q_UNREACHABLE();
150     return QByteArray();
151 }
152 
pkcs8Footer(bool encrypted)153 static QByteArray pkcs8Footer(bool encrypted)
154 {
155     return encrypted
156         ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----")
157         : QByteArrayLiteral("-----END PRIVATE KEY-----");
158 }
159 
160 /*!
161     \internal
162 
163     Returns a DER key formatted as PEM.
164 */
pemFromDer(const QByteArray & der,const QMap<QByteArray,QByteArray> & headers) const165 QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
166 {
167     QByteArray pem(der.toBase64());
168 
169     const int lineWidth = 64; // RFC 1421
170     const int newLines = pem.size() / lineWidth;
171     const bool rem = pem.size() % lineWidth;
172 
173     // ### optimize
174     for (int i = 0; i < newLines; ++i)
175         pem.insert((i + 1) * lineWidth + i, '\n');
176     if (rem)
177         pem.append('\n'); // ###
178 
179     QByteArray extra;
180     if (!headers.isEmpty()) {
181         QMap<QByteArray, QByteArray>::const_iterator it = headers.constEnd();
182         do {
183             --it;
184             extra += it.key() + ": " + it.value() + '\n';
185         } while (it != headers.constBegin());
186         extra += '\n';
187     }
188 
189     if (isEncryptedPkcs8(der)) {
190         pem.prepend(pkcs8Header(true) + '\n' + extra);
191         pem.append(pkcs8Footer(true) + '\n');
192 #if !QT_CONFIG(openssl)
193     } else if (isPkcs8) {
194         pem.prepend(pkcs8Header(false) + '\n' + extra);
195         pem.append(pkcs8Footer(false) + '\n');
196 #endif
197     } else {
198         pem.prepend(pemHeader() + '\n' + extra);
199         pem.append(pemFooter() + '\n');
200     }
201 
202     return pem;
203 }
204 
205 /*!
206     \internal
207 
208     Returns a PEM key formatted as DER.
209 */
derFromPem(const QByteArray & pem,QMap<QByteArray,QByteArray> * headers) const210 QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
211 {
212     QByteArray header = pemHeader();
213     QByteArray footer = pemFooter();
214 
215     QByteArray der(pem);
216 
217     int headerIndex = der.indexOf(header);
218     int footerIndex = der.indexOf(footer, headerIndex + header.length());
219     if (type != QSsl::PublicKey) {
220         if (headerIndex == -1 || footerIndex == -1) {
221             header = pkcs8Header(true);
222             footer = pkcs8Footer(true);
223             headerIndex = der.indexOf(header);
224             footerIndex = der.indexOf(footer, headerIndex + header.length());
225         }
226         if (headerIndex == -1 || footerIndex == -1) {
227             header = pkcs8Header(false);
228             footer = pkcs8Footer(false);
229             headerIndex = der.indexOf(header);
230             footerIndex = der.indexOf(footer, headerIndex + header.length());
231         }
232     }
233     if (headerIndex == -1 || footerIndex == -1)
234         return QByteArray();
235 
236     der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
237 
238     if (der.contains("Proc-Type:")) {
239         // taken from QHttpNetworkReplyPrivate::parseHeader
240         int i = 0;
241         while (i < der.count()) {
242             int j = der.indexOf(':', i); // field-name
243             if (j == -1)
244                 break;
245             const QByteArray field = der.mid(i, j - i).trimmed();
246             j++;
247             // any number of LWS is allowed before and after the value
248             QByteArray value;
249             do {
250                 i = der.indexOf('\n', j);
251                 if (i == -1)
252                     break;
253                 if (!value.isEmpty())
254                     value += ' ';
255                 // check if we have CRLF or only LF
256                 bool hasCR = (i && der[i-1] == '\r');
257                 int length = i -(hasCR ? 1: 0) - j;
258                 value += der.mid(j, length).trimmed();
259                 j = ++i;
260             } while (i < der.count() && (der.at(i) == ' ' || der.at(i) == '\t'));
261             if (i == -1)
262                 break; // something is wrong
263 
264             headers->insert(field, value);
265         }
266         der = der.mid(i);
267     }
268 
269     return QByteArray::fromBase64(der); // ignores newlines
270 }
271 
isEncryptedPkcs8(const QByteArray & der) const272 bool QSslKeyPrivate::isEncryptedPkcs8(const QByteArray &der) const
273 {
274     static const QVector<QByteArray> pbes1OIds {
275         // PKCS5
276         {PKCS5_MD2_DES_CBC_OID},
277         {PKCS5_MD2_RC2_CBC_OID},
278         {PKCS5_MD5_DES_CBC_OID},
279         {PKCS5_MD5_RC2_CBC_OID},
280         {PKCS5_SHA1_DES_CBC_OID},
281         {PKCS5_SHA1_RC2_CBC_OID},
282     };
283     QAsn1Element elem;
284     if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType)
285         return false;
286 
287     const QVector<QAsn1Element> items = elem.toVector();
288     if (items.size() != 2
289         || items[0].type() != QAsn1Element::SequenceType
290         || items[1].type() != QAsn1Element::OctetStringType) {
291         return false;
292     }
293 
294     const QVector<QAsn1Element> encryptionSchemeContainer = items[0].toVector();
295     if (encryptionSchemeContainer.size() != 2
296         || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
297         || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
298         return false;
299     }
300 
301     const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
302     return encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID
303             || pbes1OIds.contains(encryptionScheme)
304             || encryptionScheme.startsWith(PKCS12_OID);
305 }
306 
307 /*!
308     Constructs a QSslKey by decoding the string in the byte array
309     \a encoded using a specified \a algorithm and \a encoding format.
310     \a type specifies whether the key is public or private.
311 
312     If the key is encrypted then \a passPhrase is used to decrypt it.
313 
314     After construction, use isNull() to check if \a encoded contained
315     a valid key.
316 */
QSslKey(const QByteArray & encoded,QSsl::KeyAlgorithm algorithm,QSsl::EncodingFormat encoding,QSsl::KeyType type,const QByteArray & passPhrase)317 QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
318                  QSsl::EncodingFormat encoding, QSsl::KeyType type, const QByteArray &passPhrase)
319     : d(new QSslKeyPrivate)
320 {
321     d->type = type;
322     d->algorithm = algorithm;
323     if (encoding == QSsl::Der)
324         d->decodeDer(encoded, passPhrase);
325     else
326         d->decodePem(encoded, passPhrase);
327 }
328 
329 /*!
330     Constructs a QSslKey by reading and decoding data from a
331     \a device using a specified \a algorithm and \a encoding format.
332     \a type specifies whether the key is public or private.
333 
334     If the key is encrypted then \a passPhrase is used to decrypt it.
335 
336     After construction, use isNull() to check if \a device provided
337     a valid key.
338 */
QSslKey(QIODevice * device,QSsl::KeyAlgorithm algorithm,QSsl::EncodingFormat encoding,QSsl::KeyType type,const QByteArray & passPhrase)339 QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::EncodingFormat encoding,
340                  QSsl::KeyType type, const QByteArray &passPhrase)
341     : d(new QSslKeyPrivate)
342 {
343     QByteArray encoded;
344     if (device)
345         encoded = device->readAll();
346     d->type = type;
347     d->algorithm = algorithm;
348     if (encoding == QSsl::Der)
349         d->decodeDer(encoded, passPhrase);
350     else
351         d->decodePem(encoded, passPhrase);
352 }
353 
354 /*!
355     \since 5.0
356     Constructs a QSslKey from a valid native key \a handle.
357     \a type specifies whether the key is public or private.
358 
359     QSslKey will take ownership for this key and you must not
360     free the key using the native library.
361 */
QSslKey(Qt::HANDLE handle,QSsl::KeyType type)362 QSslKey::QSslKey(Qt::HANDLE handle, QSsl::KeyType type)
363     : d(new QSslKeyPrivate)
364 {
365 #ifndef QT_NO_OPENSSL
366     EVP_PKEY *evpKey = reinterpret_cast<EVP_PKEY *>(handle);
367     if (!evpKey || !d->fromEVP_PKEY(evpKey)) {
368         d->opaque = evpKey;
369         d->algorithm = QSsl::Opaque;
370     } else {
371         q_EVP_PKEY_free(evpKey);
372     }
373 #else
374     d->opaque = handle;
375     d->algorithm = QSsl::Opaque;
376 #endif
377     d->type = type;
378     d->isNull = !d->opaque;
379 }
380 
381 /*!
382     Constructs an identical copy of \a other.
383 */
QSslKey(const QSslKey & other)384 QSslKey::QSslKey(const QSslKey &other) : d(other.d)
385 {
386 }
387 
QSslKey(QSslKey && other)388 QSslKey::QSslKey(QSslKey &&other) noexcept
389     : d(nullptr)
390 {
391     qSwap(d, other.d);
392 }
393 
operator =(QSslKey && other)394 QSslKey &QSslKey::operator=(QSslKey &&other) noexcept
395 {
396     if (this == &other)
397         return *this;
398 
399     // If no one else is referencing the key data we want to make sure
400     // before we swap the d-ptr that it is not left in memory.
401     d.reset();
402     qSwap(d, other.d);
403     return *this;
404 }
405 
406 /*!
407     Destroys the QSslKey object.
408 */
~QSslKey()409 QSslKey::~QSslKey()
410 {
411 }
412 
413 /*!
414     Copies the contents of \a other into this key, making the two keys
415     identical.
416 
417     Returns a reference to this QSslKey.
418 */
operator =(const QSslKey & other)419 QSslKey &QSslKey::operator=(const QSslKey &other)
420 {
421     d = other.d;
422     return *this;
423 }
424 
425 /*!
426     \fn void QSslKey::swap(QSslKey &other)
427     \since 5.0
428 
429     Swaps this ssl key with \a other. This function is very fast and
430     never fails.
431 */
432 
433 /*!
434     Returns \c true if this is a null key; otherwise false.
435 
436     \sa clear()
437 */
isNull() const438 bool QSslKey::isNull() const
439 {
440     return d->isNull;
441 }
442 
443 /*!
444     Clears the contents of this key, making it a null key.
445 
446     \sa isNull()
447 */
clear()448 void QSslKey::clear()
449 {
450     d = new QSslKeyPrivate;
451 }
452 
453 /*!
454     Returns the length of the key in bits, or -1 if the key is null.
455 */
length() const456 int QSslKey::length() const
457 {
458     return d->length();
459 }
460 
461 /*!
462     Returns the type of the key (i.e., PublicKey or PrivateKey).
463 */
type() const464 QSsl::KeyType QSslKey::type() const
465 {
466     return d->type;
467 }
468 
469 /*!
470     Returns the key algorithm.
471 */
algorithm() const472 QSsl::KeyAlgorithm QSslKey::algorithm() const
473 {
474     return d->algorithm;
475 }
476 
477 /*!
478   Returns the key in DER encoding.
479 
480   The \a passPhrase argument should be omitted as DER cannot be
481   encrypted. It will be removed in a future version of Qt.
482 */
toDer(const QByteArray & passPhrase) const483 QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
484 {
485     if (d->isNull || d->algorithm == QSsl::Opaque)
486         return QByteArray();
487 
488     // Encrypted DER is nonsense, see QTBUG-41038.
489     if (d->type == QSsl::PrivateKey && !passPhrase.isEmpty())
490         return QByteArray();
491 
492 #ifndef QT_NO_OPENSSL
493     QMap<QByteArray, QByteArray> headers;
494     return d->derFromPem(toPem(passPhrase), &headers);
495 #else
496     return d->derData;
497 #endif
498 }
499 
500 /*!
501   Returns the key in PEM encoding. The result is encrypted with
502   \a passPhrase if the key is a private key and \a passPhrase is
503   non-empty.
504 */
toPem(const QByteArray & passPhrase) const505 QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
506 {
507     return d->toPem(passPhrase);
508 }
509 
510 /*!
511     Returns a pointer to the native key handle, if there is
512     one, else \nullptr.
513 
514     You can use this handle together with the native API to access
515     extended information about the key.
516 
517     \warning Use of this function has a high probability of being
518     non-portable, and its return value may vary across platforms, and
519     between minor Qt releases.
520 */
handle() const521 Qt::HANDLE QSslKey::handle() const
522 {
523     return d->handle();
524 }
525 
526 /*!
527     Returns \c true if this key is equal to \a other; otherwise returns \c false.
528 */
operator ==(const QSslKey & other) const529 bool QSslKey::operator==(const QSslKey &other) const
530 {
531     if (isNull())
532         return other.isNull();
533     if (other.isNull())
534         return isNull();
535     if (algorithm() != other.algorithm())
536         return false;
537     if (type() != other.type())
538         return false;
539     if (length() != other.length())
540         return false;
541     if (algorithm() == QSsl::Opaque)
542         return handle() == other.handle();
543     return toDer() == other.toDer();
544 }
545 
546 /*! \fn bool QSslKey::operator!=(const QSslKey &other) const
547 
548   Returns \c true if this key is not equal to key \a other; otherwise
549   returns \c false.
550 */
551 
552 #ifndef QT_NO_DEBUG_STREAM
operator <<(QDebug debug,const QSslKey & key)553 QDebug operator<<(QDebug debug, const QSslKey &key)
554 {
555     QDebugStateSaver saver(debug);
556     debug.resetFormat().nospace();
557     debug << "QSslKey("
558           << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey")
559           << ", " << (key.algorithm() == QSsl::Opaque ? "OPAQUE" :
560                      (key.algorithm() == QSsl::Rsa ? "RSA" :
561                      (key.algorithm() == QSsl::Dsa ? "DSA" :
562                      (key.algorithm() == QSsl::Dh ? "DH" : "EC"))))
563           << ", " << key.length()
564           << ')';
565     return debug;
566 }
567 #endif
568 
569 QT_END_NAMESPACE
570