summaryrefslogtreecommitdiffstats
path: root/src/network/ssl/qsslkey_p.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/ssl/qsslkey_p.cpp')
-rw-r--r--src/network/ssl/qsslkey_p.cpp348
1 files changed, 79 insertions, 269 deletions
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index ce12f49989..55cb2b0436 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtNetwork module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
/*!
@@ -54,14 +18,12 @@
\sa QSslSocket, QSslCertificate, QSslCipher
*/
+#include "qssl_p.h"
#include "qsslkey.h"
#include "qsslkey_p.h"
-#ifndef QT_NO_OPENSSL
-#include "qsslsocket_openssl_symbols_p.h"
-#endif
#include "qsslsocket.h"
#include "qsslsocket_p.h"
-#include "qasn1element_p.h"
+#include "qtlsbackend_p.h"
#include <QtCore/qatomic.h>
#include <QtCore/qbytearray.h>
@@ -73,11 +35,6 @@
QT_BEGIN_NAMESPACE
/*!
- \fn void QSslKeyPrivate::clear(bool deep)
- \internal
- */
-
-/*!
\fn void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
bool deepClear)
\internal
@@ -94,210 +51,57 @@ QT_BEGIN_NAMESPACE
*/
/*!
- Constructs a null key.
-
- \sa isNull()
-*/
-QSslKey::QSslKey()
- : d(new QSslKeyPrivate)
-{
-}
-
-/*!
\internal
*/
-QByteArray QSslKeyPrivate::pemHeader() const
+QSslKeyPrivate::QSslKeyPrivate()
{
- if (type == QSsl::PublicKey)
- return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----");
- else if (algorithm == QSsl::Rsa)
- return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Dsa)
- return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Ec)
- return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----");
- else if (algorithm == QSsl::Dh)
- return QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
-
- Q_UNREACHABLE();
- return QByteArray();
-}
-
-static QByteArray pkcs8Header(bool encrypted)
-{
- return encrypted
- ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----")
- : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
+ const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse();
+ if (!tlsBackend)
+ return;
+ backend.reset(tlsBackend->createKey());
+ if (backend.get())
+ backend->clear(false /*not deep clear*/);
+ else
+ qCWarning(lcSsl, "Active TLS backend does not support key creation");
}
/*!
\internal
*/
-QByteArray QSslKeyPrivate::pemFooter() const
+QSslKeyPrivate::~QSslKeyPrivate()
{
- if (type == QSsl::PublicKey)
- return QByteArrayLiteral("-----END PUBLIC KEY-----");
- else if (algorithm == QSsl::Rsa)
- return QByteArrayLiteral("-----END RSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Dsa)
- return QByteArrayLiteral("-----END DSA PRIVATE KEY-----");
- else if (algorithm == QSsl::Ec)
- return QByteArrayLiteral("-----END EC PRIVATE KEY-----");
- else if (algorithm == QSsl::Dh)
- return QByteArrayLiteral("-----END PRIVATE KEY-----");
-
- Q_UNREACHABLE();
- return QByteArray();
+ if (backend.get())
+ backend->clear(true /*deep clear*/);
}
-static QByteArray pkcs8Footer(bool encrypted)
+QByteArray QSslKeyPrivate::decrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
{
- return encrypted
- ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----")
- : QByteArrayLiteral("-----END PRIVATE KEY-----");
-}
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) {
+ const std::unique_ptr<QTlsPrivate::TlsKey> cryptor(tlsBackend->createKey());
+ return cryptor->decrypt(cipher, data, key, iv);
+ }
-/*!
- \internal
+ return {};
+}
- Returns a DER key formatted as PEM.
-*/
-QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const
+QByteArray QSslKeyPrivate::encrypt(Cipher cipher, const QByteArray &data, const QByteArray &key, const QByteArray &iv)
{
- QByteArray pem(der.toBase64());
-
- const int lineWidth = 64; // RFC 1421
- const int newLines = pem.size() / lineWidth;
- const bool rem = pem.size() % lineWidth;
-
- // ### optimize
- for (int i = 0; i < newLines; ++i)
- pem.insert((i + 1) * lineWidth + i, '\n');
- if (rem)
- pem.append('\n'); // ###
-
- QByteArray extra;
- if (!headers.isEmpty()) {
- QMap<QByteArray, QByteArray>::const_iterator it = headers.constEnd();
- do {
- --it;
- extra += it.key() + ": " + it.value() + '\n';
- } while (it != headers.constBegin());
- extra += '\n';
+ if (const auto *tlsBackend = QSslSocketPrivate::tlsBackendInUse()) {
+ const std::unique_ptr<QTlsPrivate::TlsKey> cryptor(tlsBackend->createKey());
+ return cryptor->encrypt(cipher, data, key, iv);
}
- if (isEncryptedPkcs8(der)) {
- pem.prepend(pkcs8Header(true) + '\n' + extra);
- pem.append(pkcs8Footer(true) + '\n');
-#if !QT_CONFIG(openssl)
- } else if (isPkcs8) {
- pem.prepend(pkcs8Header(false) + '\n' + extra);
- pem.append(pkcs8Footer(false) + '\n');
-#endif
- } else {
- pem.prepend(pemHeader() + '\n' + extra);
- pem.append(pemFooter() + '\n');
- }
-
- return pem;
+ return {};
}
/*!
- \internal
+ Constructs a null key.
- Returns a PEM key formatted as DER.
+ \sa isNull()
*/
-QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
-{
- QByteArray header = pemHeader();
- QByteArray footer = pemFooter();
-
- QByteArray der(pem);
-
- int headerIndex = der.indexOf(header);
- int footerIndex = der.indexOf(footer, headerIndex + header.length());
- if (type != QSsl::PublicKey) {
- if (headerIndex == -1 || footerIndex == -1) {
- header = pkcs8Header(true);
- footer = pkcs8Footer(true);
- headerIndex = der.indexOf(header);
- footerIndex = der.indexOf(footer, headerIndex + header.length());
- }
- if (headerIndex == -1 || footerIndex == -1) {
- header = pkcs8Header(false);
- footer = pkcs8Footer(false);
- headerIndex = der.indexOf(header);
- footerIndex = der.indexOf(footer, headerIndex + header.length());
- }
- }
- if (headerIndex == -1 || footerIndex == -1)
- return QByteArray();
-
- der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
-
- if (der.contains("Proc-Type:")) {
- // taken from QHttpNetworkReplyPrivate::parseHeader
- int i = 0;
- while (i < der.count()) {
- int j = der.indexOf(':', i); // field-name
- if (j == -1)
- break;
- const QByteArray field = der.mid(i, j - i).trimmed();
- j++;
- // any number of LWS is allowed before and after the value
- QByteArray value;
- do {
- i = der.indexOf('\n', j);
- if (i == -1)
- break;
- if (!value.isEmpty())
- value += ' ';
- // check if we have CRLF or only LF
- bool hasCR = (i && der[i-1] == '\r');
- int length = i -(hasCR ? 1: 0) - j;
- value += der.mid(j, length).trimmed();
- j = ++i;
- } while (i < der.count() && (der.at(i) == ' ' || der.at(i) == '\t'));
- if (i == -1)
- break; // something is wrong
-
- headers->insert(field, value);
- }
- der = der.mid(i);
- }
-
- return QByteArray::fromBase64(der); // ignores newlines
-}
-
-bool QSslKeyPrivate::isEncryptedPkcs8(const QByteArray &der) const
+QSslKey::QSslKey()
+ : d(new QSslKeyPrivate)
{
- static const QList<QByteArray> pbes1OIds {
- // PKCS5
- { PKCS5_MD2_DES_CBC_OID }, { PKCS5_MD2_RC2_CBC_OID }, { PKCS5_MD5_DES_CBC_OID },
- { PKCS5_MD5_RC2_CBC_OID }, { PKCS5_SHA1_DES_CBC_OID }, { PKCS5_SHA1_RC2_CBC_OID },
- };
- QAsn1Element elem;
- if (!elem.read(der) || elem.type() != QAsn1Element::SequenceType)
- return false;
-
- const auto items = elem.toList();
- if (items.size() != 2
- || items[0].type() != QAsn1Element::SequenceType
- || items[1].type() != QAsn1Element::OctetStringType) {
- return false;
- }
-
- const auto encryptionSchemeContainer = items[0].toList();
- if (encryptionSchemeContainer.size() != 2
- || encryptionSchemeContainer[0].type() != QAsn1Element::ObjectIdentifierType
- || encryptionSchemeContainer[1].type() != QAsn1Element::SequenceType) {
- return false;
- }
-
- const QByteArray encryptionScheme = encryptionSchemeContainer[0].toObjectId();
- return encryptionScheme == PKCS5_PBES2_ENCRYPTION_OID
- || pbes1OIds.contains(encryptionScheme)
- || encryptionScheme.startsWith(PKCS12_OID);
}
/*!
@@ -314,12 +118,12 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
QSsl::EncodingFormat encoding, QSsl::KeyType type, const QByteArray &passPhrase)
: d(new QSslKeyPrivate)
{
- d->type = type;
- d->algorithm = algorithm;
- if (encoding == QSsl::Der)
- d->decodeDer(encoded, passPhrase);
- else
- d->decodePem(encoded, passPhrase);
+ if (auto *tlsKey = d->backend.get()) {
+ if (encoding == QSsl::Der)
+ tlsKey->decodeDer(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ else
+ tlsKey->decodePem(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ }
}
/*!
@@ -339,12 +143,13 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
QByteArray encoded;
if (device)
encoded = device->readAll();
- d->type = type;
- d->algorithm = algorithm;
- if (encoding == QSsl::Der)
- d->decodeDer(encoded, passPhrase);
- else
- d->decodePem(encoded, passPhrase);
+
+ if (auto *tlsKey = d->backend.get()) {
+ if (encoding == QSsl::Der)
+ tlsKey->decodeDer(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ else
+ tlsKey->decodePem(type, algorithm, encoded, passPhrase, true /*deep clear*/);
+ }
}
/*!
@@ -358,20 +163,8 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
QSslKey::QSslKey(Qt::HANDLE handle, QSsl::KeyType type)
: d(new QSslKeyPrivate)
{
-#ifndef QT_NO_OPENSSL
- EVP_PKEY *evpKey = reinterpret_cast<EVP_PKEY *>(handle);
- if (!evpKey || !d->fromEVP_PKEY(evpKey)) {
- d->opaque = evpKey;
- d->algorithm = QSsl::Opaque;
- } else {
- q_EVP_PKEY_free(evpKey);
- }
-#else
- d->opaque = handle;
- d->algorithm = QSsl::Opaque;
-#endif
- d->type = type;
- d->isNull = !d->opaque;
+ if (auto *tlsKey = d->backend.get())
+ tlsKey->fromHandle(handle, type);
}
/*!
@@ -433,7 +226,10 @@ QSslKey &QSslKey::operator=(const QSslKey &other)
*/
bool QSslKey::isNull() const
{
- return d->isNull;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->isNull();
+
+ return true;
}
/*!
@@ -451,7 +247,10 @@ void QSslKey::clear()
*/
int QSslKey::length() const
{
- return d->length();
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->length();
+
+ return -1;
}
/*!
@@ -459,7 +258,10 @@ int QSslKey::length() const
*/
QSsl::KeyType QSslKey::type() const
{
- return d->type;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->type();
+
+ return QSsl::PublicKey;
}
/*!
@@ -467,7 +269,10 @@ QSsl::KeyType QSslKey::type() const
*/
QSsl::KeyAlgorithm QSslKey::algorithm() const
{
- return d->algorithm;
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->algorithm();
+
+ return QSsl::Opaque;
}
/*!
@@ -478,19 +283,18 @@ QSsl::KeyAlgorithm QSslKey::algorithm() const
*/
QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
{
- if (d->isNull || d->algorithm == QSsl::Opaque)
- return QByteArray();
+ if (isNull() || algorithm() == QSsl::Opaque)
+ return {};
// Encrypted DER is nonsense, see QTBUG-41038.
- if (d->type == QSsl::PrivateKey && !passPhrase.isEmpty())
- return QByteArray();
+ if (type() == QSsl::PrivateKey && !passPhrase.isEmpty())
+ return {};
-#ifndef QT_NO_OPENSSL
QMap<QByteArray, QByteArray> headers;
- return d->derFromPem(toPem(passPhrase), &headers);
-#else
- return d->derData;
-#endif
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->derFromPem(toPem(passPhrase), &headers);
+
+ return {};
}
/*!
@@ -500,7 +304,10 @@ QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
*/
QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
{
- return d->toPem(passPhrase);
+ if (const auto *tlsKey = d->backend.get())
+ return tlsKey->toPem(passPhrase);
+
+ return {};
}
/*!
@@ -516,7 +323,10 @@ QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
*/
Qt::HANDLE QSslKey::handle() const
{
- return d->handle();
+ if (d->backend.get())
+ return d->backend->handle();
+
+ return nullptr;
}
/*!