summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/network/ssl/qasn1element_p.h25
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp4
-rw-r--r--src/network/ssl/qsslkey_p.cpp92
-rw-r--r--src/network/ssl/qsslkey_p.h7
-rw-r--r--src/network/ssl/qsslkey_qt.cpp5
5 files changed, 113 insertions, 20 deletions
diff --git a/src/network/ssl/qasn1element_p.h b/src/network/ssl/qasn1element_p.h
index 2c5019b4f7..c706c1f321 100644
--- a/src/network/ssl/qasn1element_p.h
+++ b/src/network/ssl/qasn1element_p.h
@@ -58,10 +58,33 @@
QT_BEGIN_NAMESPACE
-#define RSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.113549.1.1.1")
+// General
+#define RSADSI_OID "1.2.840.113549."
+
+#define RSA_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.1.1")
#define DSA_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10040.4.1")
#define EC_ENCRYPTION_OID QByteArrayLiteral("1.2.840.10045.2.1")
+// These are mostly from the RFC for PKCS#5
+// PKCS#5: https://tools.ietf.org/html/rfc8018#appendix-B
+#define PKCS5_OID RSADSI_OID "1.5."
+// PKCS#12: https://tools.ietf.org/html/rfc7292#appendix-D)
+#define PKCS12_OID RSADSI_OID "1.12."
+
+// -PBES1
+#define PKCS5_MD2_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "1")
+#define PKCS5_MD2_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "4")
+#define PKCS5_MD5_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "3")
+#define PKCS5_MD5_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "6")
+#define PKCS5_SHA1_DES_CBC_OID QByteArrayLiteral(PKCS5_OID "10")
+#define PKCS5_SHA1_RC2_CBC_OID QByteArrayLiteral(PKCS5_OID "11")
+
+// -PBKDF2
+#define PKCS5_PBKDF2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "12")
+
+// -PBES2
+#define PKCS5_PBES2_ENCRYPTION_OID QByteArrayLiteral(PKCS5_OID "13")
+
class Q_AUTOTEST_EXPORT QAsn1Element
{
public:
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
index aa81b735b9..7c77f5a910 100644
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ b/src/network/ssl/qsslkey_openssl.cpp
@@ -125,10 +125,10 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
return false;
}
-void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
+void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
{
QMap<QByteArray, QByteArray> headers;
- decodePem(pemFromDer(der, headers), QByteArray(), deepClear);
+ decodePem(pemFromDer(der, headers), passPhrase, deepClear);
}
void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index e66ec953a0..2957633348 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -61,6 +61,7 @@
#endif
#include "qsslsocket.h"
#include "qsslsocket_p.h"
+#include "qasn1element_p.h"
#include <QtCore/qatomic.h>
#include <QtCore/qbytearray.h>
@@ -120,6 +121,13 @@ QByteArray QSslKeyPrivate::pemHeader() const
return QByteArray();
}
+static QByteArray pkcs8Header(bool encrypted)
+{
+ return encrypted
+ ? QByteArrayLiteral("-----BEGIN ENCRYPTED PRIVATE KEY-----")
+ : QByteArrayLiteral("-----BEGIN PRIVATE KEY-----");
+}
+
/*!
\internal
*/
@@ -138,6 +146,13 @@ QByteArray QSslKeyPrivate::pemFooter() const
return QByteArray();
}
+static QByteArray pkcs8Footer(bool encrypted)
+{
+ return encrypted
+ ? QByteArrayLiteral("-----END ENCRYPTED PRIVATE KEY-----")
+ : QByteArrayLiteral("-----END PRIVATE KEY-----");
+}
+
/*!
\internal
@@ -166,8 +181,14 @@ QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArr
} while (it != headers.constBegin());
extra += '\n';
}
- pem.prepend(pemHeader() + '\n' + extra);
- pem.append(pemFooter() + '\n');
+
+ if (isEncryptedPkcs8(der)) {
+ pem.prepend(pkcs8Header(true) + '\n' + extra);
+ pem.append(pkcs8Footer(true) + '\n');
+ } else {
+ pem.prepend(pemHeader() + '\n' + extra);
+ pem.append(pemFooter() + '\n');
+ }
return pem;
}
@@ -179,13 +200,27 @@ QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der, const QMap<QByteArr
*/
QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem, QMap<QByteArray, QByteArray> *headers) const
{
- const QByteArray header = pemHeader();
- const QByteArray footer = pemFooter();
+ QByteArray header = pemHeader();
+ QByteArray footer = pemFooter();
QByteArray der(pem);
- const int headerIndex = der.indexOf(header);
- const int footerIndex = der.indexOf(footer);
+ 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();
@@ -225,13 +260,47 @@ QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem, QMap<QByteArray, QB
return QByteArray::fromBase64(der); // ignores newlines
}
+bool QSslKeyPrivate::isEncryptedPkcs8(const QByteArray &der) const
+{
+ static const QVector<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 QVector<QAsn1Element> items = elem.toVector();
+ if (items.size() != 2
+ || items[0].type() != QAsn1Element::SequenceType
+ || items[1].type() != QAsn1Element::OctetStringType) {
+ return false;
+ }
+
+ const QVector<QAsn1Element> encryptionSchemeContainer = items[0].toVector();
+ 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);
+}
+
/*!
Constructs a QSslKey by decoding the string in the byte array
\a encoded using a specified \a algorithm and \a encoding format.
\a type specifies whether the key is public or private.
- If the key is encoded as PEM and encrypted, \a passPhrase is used
- to decrypt it.
+ If the key is encrypted then \a passPhrase is used to decrypt it.
After construction, use isNull() to check if \a encoded contained
a valid key.
@@ -243,7 +312,7 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
d->type = type;
d->algorithm = algorithm;
if (encoding == QSsl::Der)
- d->decodeDer(encoded);
+ d->decodeDer(encoded, passPhrase);
else
d->decodePem(encoded, passPhrase);
}
@@ -253,8 +322,7 @@ QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
\a device using a specified \a algorithm and \a encoding format.
\a type specifies whether the key is public or private.
- If the key is encoded as PEM and encrypted, \a passPhrase is used
- to decrypt it.
+ If the key is encrypted then \a passPhrase is used to decrypt it.
After construction, use isNull() to check if \a device provided
a valid key.
@@ -269,7 +337,7 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
d->type = type;
d->algorithm = algorithm;
if (encoding == QSsl::Der)
- d->decodeDer(encoded);
+ d->decodeDer(encoded, passPhrase);
else
d->decodePem(encoded, passPhrase);
}
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index c93941c198..d6c5af9d47 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -81,9 +81,8 @@ public:
#ifndef QT_NO_OPENSSL
bool fromEVP_PKEY(EVP_PKEY *pkey);
#endif
- void decodeDer(const QByteArray &der, bool deepClear = true);
- void decodePem(const QByteArray &pem, const QByteArray &passPhrase,
- bool deepClear = true);
+ void decodeDer(const QByteArray &der, const QByteArray &passPhrase = {}, bool deepClear = true);
+ void decodePem(const QByteArray &pem, const QByteArray &passPhrase, bool deepClear = true);
QByteArray pemHeader() const;
QByteArray pemFooter() const;
QByteArray pemFromDer(const QByteArray &der, const QMap<QByteArray, QByteArray> &headers) const;
@@ -93,6 +92,8 @@ public:
QByteArray toPem(const QByteArray &passPhrase) const;
Qt::HANDLE handle() const;
+ bool isEncryptedPkcs8(const QByteArray &der) const;
+
bool isNull;
QSsl::KeyType type;
QSsl::KeyAlgorithm algorithm;
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
index a85fed21ed..0e7702bbeb 100644
--- a/src/network/ssl/qsslkey_qt.cpp
+++ b/src/network/ssl/qsslkey_qt.cpp
@@ -154,8 +154,9 @@ void QSslKeyPrivate::clear(bool deep)
keyLength = -1;
}
-void QSslKeyPrivate::decodeDer(const QByteArray &der, bool deepClear)
+void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhrase, bool deepClear)
{
+ Q_UNUSED(passPhrase);
clear(deepClear);
if (der.isEmpty())
@@ -272,7 +273,7 @@ void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhra
const QByteArray key = deriveKey(cipher, passPhrase, iv);
data = decrypt(cipher, data, key, iv);
}
- decodeDer(data, deepClear);
+ decodeDer(data, passPhrase, deepClear);
}
int QSslKeyPrivate::length() const