summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Schmertmann <Lars.Schmertmann@governikus.de>2016-07-13 08:42:33 +0200
committerAndré Klitzing <aklitzing@gmail.com>2018-11-23 22:58:05 +0000
commitde83447830b0941216f922a37b6cd36e703197d4 (patch)
treeb2c58b8fb086cc7a6b45252b56f2014732a9f9ba
parent14144079709201929c97b9a5f0db406c27275baf (diff)
Add support for Diffie-Hellman keys to QSslKey
This is necessary to provide details for the key too, when the server is using DHE-RSA-AESxxx-SHAxxx. Amends 7f77dc84fb434f33ffe96f6633792706b80fb0a3. Change-Id: I8ab15b6987c17c857f54bc368df3c6c1818f428c Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Timur Pocheptsov <timur.pocheptsov@qt.io>
-rw-r--r--src/network/ssl/qasn1element_p.h1
-rw-r--r--src/network/ssl/qssl.cpp3
-rw-r--r--src/network/ssl/qssl.h3
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp46
-rw-r--r--src/network/ssl/qsslkey_p.cpp8
-rw-r--r--src/network/ssl/qsslkey_p.h1
-rw-r--r--src/network/ssl/qsslkey_qt.cpp32
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp8
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h5
-rw-r--r--src/network/ssl/qsslsocket_opensslpre11_symbols_p.h1
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pri-1024.derbin0 -> 293 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pri-1024.pem9
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pri-2048.derbin0 -> 554 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pri-2048.pem14
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pri-512.derbin0 -> 159 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pri-512.pem6
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pub-1024.derbin0 -> 291 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pub-1024.pem9
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pub-2048.derbin0 -> 552 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pub-2048.pem14
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pub-512.derbin0 -> 157 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/dh-pub-512.pem6
-rwxr-xr-xtests/auto/network/ssl/qsslkey/keys/genkeys.sh21
-rw-r--r--tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp5
24 files changed, 182 insertions, 10 deletions
diff --git a/src/network/ssl/qasn1element_p.h b/src/network/ssl/qasn1element_p.h
index 2068254a95..59d1f58482 100644
--- a/src/network/ssl/qasn1element_p.h
+++ b/src/network/ssl/qasn1element_p.h
@@ -64,6 +64,7 @@ QT_BEGIN_NAMESPACE
#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")
+#define DH_ENCRYPTION_OID QByteArrayLiteral(RSADSI_OID "1.3.1")
// These are mostly from the RFC for PKCS#5
// PKCS#5: https://tools.ietf.org/html/rfc8018#appendix-B
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index 19d99bc489..ea2b73bad5 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -71,7 +71,8 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\value Rsa The RSA algorithm.
\value Dsa The DSA algorithm.
- \value Ec The Elliptic Curve algorithm
+ \value Ec The Elliptic Curve algorithm.
+ \value Dh The Diffie-Hellman algorithm.
\value Opaque A key that should be treated as a 'black box' by QSslKey.
The opaque key facility allows applications to add support for facilities
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
index 60362cb410..5c25e4e105 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -62,7 +62,8 @@ namespace QSsl {
Opaque,
Rsa,
Dsa,
- Ec
+ Ec,
+ Dh,
};
enum AlternativeNameEntryType {
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
index 9a43e67772..99c1a39c73 100644
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ b/src/network/ssl/qsslkey_openssl.cpp
@@ -69,6 +69,11 @@ void QSslKeyPrivate::clear(bool deep)
q_DSA_free(dsa);
dsa = nullptr;
}
+ if (algorithm == QSsl::Dh && dh) {
+ if (deep)
+ q_DH_free(dh);
+ dh = nullptr;
+ }
#ifndef OPENSSL_NO_EC
if (algorithm == QSsl::Ec && ec) {
if (deep)
@@ -105,6 +110,12 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
type = QSsl::PrivateKey;
dsa = q_EVP_PKEY_get1_DSA(pkey);
return true;
+ } else if (keyType == EVP_PKEY_DH) {
+ isNull = false;
+ algorithm = QSsl::Dh;
+ type = QSsl::PrivateKey;
+ dh = q_EVP_PKEY_get1_DH(pkey);
+ return true;
}
#ifndef OPENSSL_NO_EC
else if (keyType == EVP_PKEY_EC) {
@@ -160,6 +171,15 @@ void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhra
: q_PEM_read_bio_DSAPrivateKey(bio, &dsa, nullptr, phrase);
if (dsa && dsa == result)
isNull = false;
+ } else if (algorithm == QSsl::Dh) {
+ EVP_PKEY *result = (type == QSsl::PublicKey)
+ ? q_PEM_read_bio_PUBKEY(bio, nullptr, nullptr, phrase)
+ : q_PEM_read_bio_PrivateKey(bio, nullptr, nullptr, phrase);
+ if (result)
+ dh = q_EVP_PKEY_get1_DH(result);
+ if (dh)
+ isNull = false;
+ q_EVP_PKEY_free(result);
#ifndef OPENSSL_NO_EC
} else if (algorithm == QSsl::Ec) {
EC_KEY *result = (type == QSsl::PublicKey)
@@ -181,6 +201,7 @@ int QSslKeyPrivate::length() const
switch (algorithm) {
case QSsl::Rsa: return q_RSA_bits(rsa);
case QSsl::Dsa: return q_DSA_bits(dsa);
+ case QSsl::Dh: return q_DH_bits(dh);
#ifndef OPENSSL_NO_EC
case QSsl::Ec: return q_EC_GROUP_get_degree(q_EC_KEY_get0_group(ec));
#endif
@@ -215,7 +236,7 @@ QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
fail = true;
} else {
if (!q_PEM_write_bio_RSAPrivateKey(
- bio, rsa, cipher, const_cast<uchar *>((const uchar *)passPhrase.data()),
+ bio, rsa, cipher, (uchar *)passPhrase.data(),
passPhrase.size(), nullptr, nullptr)) {
fail = true;
}
@@ -226,20 +247,33 @@ QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
fail = true;
} else {
if (!q_PEM_write_bio_DSAPrivateKey(
- bio, dsa, cipher, const_cast<uchar *>((const uchar *)passPhrase.data()),
+ bio, dsa, cipher, (uchar *)passPhrase.data(),
passPhrase.size(), nullptr, nullptr)) {
fail = true;
}
}
+ } else if (algorithm == QSsl::Dh) {
+ EVP_PKEY *result = q_EVP_PKEY_new();
+ if (!result || !q_EVP_PKEY_set1_DH(result, dh)) {
+ fail = true;
+ } else if (type == QSsl::PublicKey) {
+ if (!q_PEM_write_bio_PUBKEY(bio, result))
+ fail = true;
+ } else if (!q_PEM_write_bio_PrivateKey(
+ bio, result, cipher, (uchar *)passPhrase.data(),
+ passPhrase.size(), nullptr, nullptr)) {
+ fail = true;
+ }
+ q_EVP_PKEY_free(result);
#ifndef OPENSSL_NO_EC
} else if (algorithm == QSsl::Ec) {
if (type == QSsl::PublicKey) {
if (!q_PEM_write_bio_EC_PUBKEY(bio, ec))
fail = true;
} else {
- if (!q_PEM_write_bio_ECPrivateKey(bio, ec, cipher,
- const_cast<uchar *>((const uchar *)passPhrase.data()),
- passPhrase.size(), nullptr, nullptr)) {
+ if (!q_PEM_write_bio_ECPrivateKey(
+ bio, ec, cipher, (uchar *)passPhrase.data(),
+ passPhrase.size(), nullptr, nullptr)) {
fail = true;
}
}
@@ -267,6 +301,8 @@ Qt::HANDLE QSslKeyPrivate::handle() const
return Qt::HANDLE(rsa);
case QSsl::Dsa:
return Qt::HANDLE(dsa);
+ case QSsl::Dh:
+ return Qt::HANDLE(dh);
#ifndef OPENSSL_NO_EC
case QSsl::Ec:
return Qt::HANDLE(ec);
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index 28e3e2efd8..b29b38beab 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -116,6 +116,8 @@ QByteArray QSslKeyPrivate::pemHeader() const
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();
@@ -141,6 +143,8 @@ QByteArray QSslKeyPrivate::pemFooter() const
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();
@@ -535,7 +539,9 @@ QDebug operator<<(QDebug debug, const QSslKey &key)
debug << "QSslKey("
<< (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey")
<< ", " << (key.algorithm() == QSsl::Opaque ? "OPAQUE" :
- (key.algorithm() == QSsl::Rsa ? "RSA" : ((key.algorithm() == QSsl::Dsa) ? "DSA" : "EC")))
+ (key.algorithm() == QSsl::Rsa ? "RSA" :
+ (key.algorithm() == QSsl::Dsa ? "DSA" :
+ (key.algorithm() == QSsl::Dh ? "DH" : "EC"))))
<< ", " << key.length()
<< ')';
return debug;
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index 7ae2cc740b..310553cab2 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -116,6 +116,7 @@ public:
EVP_PKEY *opaque;
RSA *rsa;
DSA *dsa;
+ DH *dh;
#ifndef OPENSSL_NO_EC
EC_KEY *ec;
#endif
diff --git a/src/network/ssl/qsslkey_qt.cpp b/src/network/ssl/qsslkey_qt.cpp
index a13275f3bb..5ebd8ac3bd 100644
--- a/src/network/ssl/qsslkey_qt.cpp
+++ b/src/network/ssl/qsslkey_qt.cpp
@@ -165,6 +165,7 @@ static int extractPkcs8KeyLength(const QVector<QAsn1Element> &items, QSslKeyPriv
switch (algorithm){
case QSsl::Rsa: return "RSA";
case QSsl::Dsa: return "DSA";
+ case QSsl::Dh: return "DH";
case QSsl::Ec: return "EC";
case QSsl::Opaque: return "Opaque";
}
@@ -217,6 +218,21 @@ static int extractPkcs8KeyLength(const QVector<QAsn1Element> &items, QSslKeyPriv
if (dsaInfo.size() != 3 || dsaInfo[0].type() != QAsn1Element::IntegerType)
return -1;
keyLength = numberOfBits(dsaInfo[0].value());
+ } else if (value == DH_ENCRYPTION_OID) {
+ if (Q_UNLIKELY(that->algorithm != QSsl::Dh)) {
+ // As above for RSA.
+ qWarning() << "QSslKey: Found DH when asked to use" << getName(that->algorithm)
+ << "\nLoading will fail.";
+ return -1;
+ }
+ // DH's structure is documented here:
+ // https://www.cryptsoft.com/pkcs11doc/STANDARD/v201-95.pdf in section 11.9.
+ if (pkcs8Info[1].type() != QAsn1Element::SequenceType)
+ return -1;
+ const QVector<QAsn1Element> dhInfo = pkcs8Info[1].toVector();
+ if (dhInfo.size() < 2 || dhInfo.size() > 3 || dhInfo[0].type() != QAsn1Element::IntegerType)
+ return -1;
+ keyLength = numberOfBits(dhInfo[0].value());
} else {
// in case of unexpected formats:
qWarning() << "QSslKey: Unsupported PKCS#8 key algorithm:" << value
@@ -268,6 +284,16 @@ void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhra
if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
return;
keyLength = numberOfBits(params[0].value());
+ } else if (algorithm == QSsl::Dh) {
+ if (infoItems[0].toObjectId() != DH_ENCRYPTION_OID)
+ return;
+ if (infoItems[1].type() != QAsn1Element::SequenceType)
+ return;
+ // key params
+ const QVector<QAsn1Element> params = infoItems[1].toVector();
+ if (params.isEmpty() || params[0].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(params[0].value());
} else if (algorithm == QSsl::Ec) {
if (infoItems[0].toObjectId() != EC_ENCRYPTION_OID)
return;
@@ -307,6 +333,12 @@ void QSslKeyPrivate::decodeDer(const QByteArray &der, const QByteArray &passPhra
if (items.size() != 6 || items[1].type() != QAsn1Element::IntegerType)
return;
keyLength = numberOfBits(items[1].value());
+ } else if (algorithm == QSsl::Dh) {
+ if (versionHex != "00")
+ return;
+ if (items.size() < 5 || items.size() > 6 || items[1].type() != QAsn1Element::IntegerType)
+ return;
+ keyLength = numberOfBits(items[1].value());
} else if (algorithm == QSsl::Ec) {
if (versionHex != "01")
return;
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 781b3d6640..5ba2c40636 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -366,12 +366,14 @@ DEFINEFUNC(const EVP_MD *, EVP_sha1, DUMMYARG, DUMMYARG, return nullptr, return)
DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, char *c, c, return -1, return)
DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_DH, EVP_PKEY *a, a, DH *b, b, return -1, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, EVP_PKEY_set1_EC_KEY, EVP_PKEY *a, a, EC_KEY *b, b, return -1, return)
#endif
DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return nullptr, return)
DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return nullptr, return)
+DEFINEFUNC(DH *, EVP_PKEY_get1_DH, EVP_PKEY *a, a, return nullptr, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return nullptr, return)
#endif
@@ -397,6 +399,7 @@ DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_p
DEFINEFUNC4(DH *, PEM_read_bio_DHparams, BIO *a, a, DH **b, b, pem_password_cb *c, c, void *d, d, return nullptr, return)
DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_PrivateKey, BIO *a, a, EVP_PKEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC7(int, PEM_write_bio_ECPrivateKey, BIO *a, a, EC_KEY *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
#endif
@@ -409,6 +412,7 @@ DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_pass
#endif
DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return)
DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return)
+DEFINEFUNC2(int, PEM_write_bio_PUBKEY, BIO *a, a, EVP_PKEY *b, b, return 0, return)
#ifndef OPENSSL_NO_EC
DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
#endif
@@ -1168,12 +1172,14 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(EVP_PKEY_assign)
RESOLVEFUNC(EVP_PKEY_set1_RSA)
RESOLVEFUNC(EVP_PKEY_set1_DSA)
+ RESOLVEFUNC(EVP_PKEY_set1_DH)
#ifndef OPENSSL_NO_EC
RESOLVEFUNC(EVP_PKEY_set1_EC_KEY)
#endif
RESOLVEFUNC(EVP_PKEY_free)
RESOLVEFUNC(EVP_PKEY_get1_DSA)
RESOLVEFUNC(EVP_PKEY_get1_RSA)
+ RESOLVEFUNC(EVP_PKEY_get1_DH)
#ifndef OPENSSL_NO_EC
RESOLVEFUNC(EVP_PKEY_get1_EC_KEY)
#endif
@@ -1197,6 +1203,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(PEM_read_bio_DHparams)
RESOLVEFUNC(PEM_write_bio_DSAPrivateKey)
RESOLVEFUNC(PEM_write_bio_RSAPrivateKey)
+ RESOLVEFUNC(PEM_write_bio_PrivateKey)
#ifndef OPENSSL_NO_EC
RESOLVEFUNC(PEM_write_bio_ECPrivateKey)
#endif
@@ -1210,6 +1217,7 @@ bool q_resolveOpenSslSymbols()
#endif
RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY)
RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY)
+ RESOLVEFUNC(PEM_write_bio_PUBKEY)
#ifndef OPENSSL_NO_EC
RESOLVEFUNC(PEM_write_bio_EC_PUBKEY)
#endif
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index bfdfbf0efc..7e759d3825 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -278,12 +278,14 @@ const EVP_MD *q_EVP_sha1();
int q_EVP_PKEY_assign(EVP_PKEY *a, int b, char *c);
Q_AUTOTEST_EXPORT int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b);
int q_EVP_PKEY_set1_DSA(EVP_PKEY *a, DSA *b);
+int q_EVP_PKEY_set1_DH(EVP_PKEY *a, DH *b);
#ifndef OPENSSL_NO_EC
int q_EVP_PKEY_set1_EC_KEY(EVP_PKEY *a, EC_KEY *b);
#endif
void q_EVP_PKEY_free(EVP_PKEY *a);
RSA *q_EVP_PKEY_get1_RSA(EVP_PKEY *a);
DSA *q_EVP_PKEY_get1_DSA(EVP_PKEY *a);
+DH *q_EVP_PKEY_get1_DH(EVP_PKEY *a);
#ifndef OPENSSL_NO_EC
EC_KEY *q_EVP_PKEY_get1_EC_KEY(EVP_PKEY *a);
#endif
@@ -314,6 +316,8 @@ int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned
int e, pem_password_cb *f, void *g);
int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned char *d,
int e, pem_password_cb *f, void *g);
+int q_PEM_write_bio_PrivateKey(BIO *a, EVP_PKEY *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
#ifndef OPENSSL_NO_EC
int q_PEM_write_bio_ECPrivateKey(BIO *a, EC_KEY *b, const EVP_CIPHER *c, unsigned char *d,
int e, pem_password_cb *f, void *g);
@@ -327,6 +331,7 @@ EC_KEY *q_PEM_read_bio_EC_PUBKEY(BIO *a, EC_KEY **b, pem_password_cb *c, void *d
#endif
int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b);
int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b);
+int q_PEM_write_bio_PUBKEY(BIO *a, EVP_PKEY *b);
#ifndef OPENSSL_NO_EC
int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b);
#endif
diff --git a/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h b/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h
index b7bac5d2a2..daf46f485c 100644
--- a/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h
+++ b/src/network/ssl/qsslsocket_opensslpre11_symbols_p.h
@@ -218,6 +218,7 @@ DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
#define q_SSL_SESSION_get_ticket_lifetime_hint(s) ((s)->tlsext_tick_lifetime_hint)
#define q_RSA_bits(rsa) q_BN_num_bits((rsa)->n)
#define q_DSA_bits(dsa) q_BN_num_bits((dsa)->p)
+#define q_DH_bits(dsa) q_BN_num_bits((dh)->p)
#define q_X509_STORE_set_verify_cb(s,c) X509_STORE_set_verify_cb_func((s),(c))
char *q_CONF_get1_default_config_file();
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pri-1024.der b/tests/auto/network/ssl/qsslkey/keys/dh-pri-1024.der
new file mode 100644
index 0000000000..687009e087
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pri-1024.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pri-1024.pem b/tests/auto/network/ssl/qsslkey/keys/dh-pri-1024.pem
new file mode 100644
index 0000000000..233e0dfb37
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pri-1024.pem
@@ -0,0 +1,9 @@
+-----BEGIN PRIVATE KEY-----
+MIIBIQIBADCBlQYJKoZIhvcNAQMBMIGHAoGBAIlk2YX0TJzfQ18ZzZroQoE5Nyjt
+bWxWRxBriG/c+JWhBwttVDb6lzLN+GVJxXVPfc6JJmDORVRxdxAlMqu++2Vqpsnl
+/H8xIXsxjuTcTjq8sXagGRa0LfeggkUD64tEhO4iZ8Q2TIdb3OHkAF0Sn+06b/0e
+iIz323Kywq0CsspTAgECBIGDAoGAQCo39UHP4s2ZVH4nOmWgNlb4JsHPX4EzqDBr
+ig46hvMLAFrILYnsCbqqD/+GNAUl1PV/nfEQoAk/HvtACqLFLG5/3jK2w6dVHGEo
+JnVOGz9vZpWUx+SCslHJRFaeE+6AAbbvrTr0lci29Ta4IesHlamRsj+ZaUrVX6k/
+/9OTGAo=
+-----END PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pri-2048.der b/tests/auto/network/ssl/qsslkey/keys/dh-pri-2048.der
new file mode 100644
index 0000000000..e193f25f07
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pri-2048.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pri-2048.pem b/tests/auto/network/ssl/qsslkey/keys/dh-pri-2048.pem
new file mode 100644
index 0000000000..32299b2b6c
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pri-2048.pem
@@ -0,0 +1,14 @@
+-----BEGIN PRIVATE KEY-----
+MIICJgIBADCCARcGCSqGSIb3DQEDATCCAQgCggEBAJsiReJxBjkC7Hy99AJATusq
+YsNQHhjoeTLPeHhsBuLtJK18Krk736V09efX6qeAEmvgMQbvbHqtrOaY3q6dut6C
+UTGVW+oVg3d/Y8qakkanvEnIlliaTIyWIz0JMjO2prC6AuU/QEzZcQVUS6bxyn3D
+iYFxCE6+7cJJpEH9HVbcrl+J6Ch6ax5rQGUyxpSMkmItLJx92upRxOnaxJMHR+ZF
+OSdDPfrkINpEzahnhteLszddyLasnE0or6ZnXYLvKsT1Uu6QwDc4EO1FJHScoeep
+zsK/VRcXzMpj/1Rl+F9E/AikCqHRrnvISt25wrK0Mwy854P2T7dJlBNewc6vE6MC
+AQIEggEEAoIBAGIctO30MoZ9DiuKbOBpqM9rl2bNH/I46GGcfEiSsO/zOw2V9WFC
+MxkjF0I1ilDfPY+Ag3bLB2n89DPcfXliYH9MFolehPTc1fWplhX3+ImdC6y95uXO
+FV5xtcEQCbPktnUtkUdcAT5831p9lu1QJo+DzMPrQa7axMLj8heBAi4VqAi+8Q31
+dpGKuhCUlgs+pLENx1o0QY2kui6Z5uR0YhmA547lwBWA4XEv5OV9ExmxytiatvOv
+PZKT1ID76LrL9bnnZvOEGczWLQvJ9VaaZSpoP+2QisRANWW4w57d+PIR1WR/FTSH
+F6xocElUoTzuiSPzRz60aw/KkisImBBKERQ=
+-----END PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pri-512.der b/tests/auto/network/ssl/qsslkey/keys/dh-pri-512.der
new file mode 100644
index 0000000000..42ddbaaae2
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pri-512.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pri-512.pem b/tests/auto/network/ssl/qsslkey/keys/dh-pri-512.pem
new file mode 100644
index 0000000000..d2c3170b16
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pri-512.pem
@@ -0,0 +1,6 @@
+-----BEGIN PRIVATE KEY-----
+MIGcAgEAMFMGCSqGSIb3DQEDATBGAkEAvXx0QxJvIGA2ig8Je55R2rmeO4Ta2Esj
+ANLuyVIFRbtuLFsdhU+amUc8bs9RUQmkUNzS92jkpAfqtCv+mQ06EwIBAgRCAkBJ
+rDM0BTevOPIHpJzMtSQhw3e7Dr38HUfTn8zF3uYi1RCxjkTUukmzRLPTf0aqPgpd
+8dSldjG/11aZORl8/mXO
+-----END PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pub-1024.der b/tests/auto/network/ssl/qsslkey/keys/dh-pub-1024.der
new file mode 100644
index 0000000000..2805a67633
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pub-1024.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pub-1024.pem b/tests/auto/network/ssl/qsslkey/keys/dh-pub-1024.pem
new file mode 100644
index 0000000000..da4e327ac9
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pub-1024.pem
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBHzCBlQYJKoZIhvcNAQMBMIGHAoGBAIlk2YX0TJzfQ18ZzZroQoE5NyjtbWxW
+RxBriG/c+JWhBwttVDb6lzLN+GVJxXVPfc6JJmDORVRxdxAlMqu++2Vqpsnl/H8x
+IXsxjuTcTjq8sXagGRa0LfeggkUD64tEhO4iZ8Q2TIdb3OHkAF0Sn+06b/0eiIz3
+23Kywq0CsspTAgECA4GEAAKBgA8pxU1sMDvRWKpvJKNs3jNhZPQWFf4Tszu/cMcb
+1qAQ/q0DRb41VvsUoMaCfef/plZleV4MG26owb574AJeC86wX5MbRDTPS4CzAn+I
+an92AZl3vlYRQ2sSo3ktkyhw6LV1iewi08Ky7J4rqvG0Oo335QGEZlK1OgwBsyh0
+FKLe
+-----END PUBLIC KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pub-2048.der b/tests/auto/network/ssl/qsslkey/keys/dh-pub-2048.der
new file mode 100644
index 0000000000..9e749d8a41
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pub-2048.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pub-2048.pem b/tests/auto/network/ssl/qsslkey/keys/dh-pub-2048.pem
new file mode 100644
index 0000000000..f751157c87
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pub-2048.pem
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICJDCCARcGCSqGSIb3DQEDATCCAQgCggEBAJsiReJxBjkC7Hy99AJATusqYsNQ
+HhjoeTLPeHhsBuLtJK18Krk736V09efX6qeAEmvgMQbvbHqtrOaY3q6dut6CUTGV
+W+oVg3d/Y8qakkanvEnIlliaTIyWIz0JMjO2prC6AuU/QEzZcQVUS6bxyn3DiYFx
+CE6+7cJJpEH9HVbcrl+J6Ch6ax5rQGUyxpSMkmItLJx92upRxOnaxJMHR+ZFOSdD
+PfrkINpEzahnhteLszddyLasnE0or6ZnXYLvKsT1Uu6QwDc4EO1FJHScoeepzsK/
+VRcXzMpj/1Rl+F9E/AikCqHRrnvISt25wrK0Mwy854P2T7dJlBNewc6vE6MCAQID
+ggEFAAKCAQAUeWRuqjl7F84USogxJOM1M4y8yKtBYY2KLs5iIVhzV4UZ+9+cMNZA
+otLXJ/e8BH0diR0yk7tjxD6hjjqd+nyafIkJGPElDMnTbRPHg5zZYMmI5L/efdSm
+OPbM7QsodrYH5aoF4c7hjMb/cttYVG2Yupsy4tfORuDbwL70upqOo6rkVq55eOGS
+6pseEume/SD+7e3xIPJTkrMMzBFHG6H7bVHikT4O7yWV1iVzElj919yi+4Zy6TK8
+0hG6l31D5bsJpOduhHYZtN1yQpw+sGT6Yiepkjgt+1YkGFiiRs5vDl4DHeYHyAhL
+oH9uKcm3q4lhaOeT5ml765g87qQD6+vr
+-----END PUBLIC KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pub-512.der b/tests/auto/network/ssl/qsslkey/keys/dh-pub-512.der
new file mode 100644
index 0000000000..8a75babb6d
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pub-512.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/dh-pub-512.pem b/tests/auto/network/ssl/qsslkey/keys/dh-pub-512.pem
new file mode 100644
index 0000000000..1f4e5c9a47
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/dh-pub-512.pem
@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGaMFMGCSqGSIb3DQEDATBGAkEAvXx0QxJvIGA2ig8Je55R2rmeO4Ta2EsjANLu
+yVIFRbtuLFsdhU+amUc8bs9RUQmkUNzS92jkpAfqtCv+mQ06EwIBAgNDAAJARGBh
+9FmRRZZAxBtXZmS8wIgDwWvjB63GQ+E1pDLtZPztvPQ2eqUjTgSuGKV5cDankAV1
+Pkj/IA0Xl+SuFhLLew==
+-----END PUBLIC KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/genkeys.sh b/tests/auto/network/ssl/qsslkey/keys/genkeys.sh
index 6210b42ab4..0106953bff 100755
--- a/tests/auto/network/ssl/qsslkey/keys/genkeys.sh
+++ b/tests/auto/network/ssl/qsslkey/keys/genkeys.sh
@@ -88,6 +88,27 @@ do
openssl ec -in ec-pri-$size-$curve.pem -pubout -out ec-pub-$size-$curve.der -outform DER
done
+#--- DH ----------------------------------------------------------------------------
+for size in 512 1024 2048
+do
+ echo -e "\ngenerating DH parameters to PEM file ..."
+ openssl dhparam -out dhpar-$size.pem $size
+
+ echo -e "\ngenerating DH private key to PEM file ..."
+ openssl genpkey -paramfile dhpar-$size.pem -out dh-pri-$size.pem
+
+ /bin/rm dhpar-$size.pem
+
+ echo -e "\ngenerating DH private key to DER file ..."
+ openssl pkey -in dh-pri-$size.pem -out dh-pri-$size.der -outform DER
+
+ echo -e "\ngenerating DH public key to PEM file ..."
+ openssl pkey -in dh-pri-$size.pem -pubout -out dh-pub-$size.pem
+
+ echo -e "\ngenerating DH public key to DER file ..."
+ openssl pkey -in dh-pri-$size.pem -pubout -out dh-pub-$size.der -outform DER
+done
+
#--- PKCS#8 ------------------------------------------------------------------------
# Note: We'll just grab some of the keys generated earlier and convert those
# https://www.openssl.org/docs/manmaster/man1/pkcs8.html#PKCS-5-v1.5-and-PKCS-12-algorithms
diff --git a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
index ddfe52c5e4..a257becfd2 100644
--- a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
+++ b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
@@ -111,13 +111,14 @@ void tst_QSslKey::initTestCase()
QDir dir(testDataDir + "keys");
const QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::Readable);
- QRegExp rx(QLatin1String("^(rsa|dsa|ec)-(pub|pri)-(\\d+)-?[\\w-]*\\.(pem|der)$"));
+ QRegExp rx(QLatin1String("^(rsa|dsa|dh|ec)-(pub|pri)-(\\d+)-?[\\w-]*\\.(pem|der)$"));
for (const QFileInfo &fileInfo : fileInfoList) {
if (rx.indexIn(fileInfo.fileName()) >= 0) {
keyInfoList << KeyInfo(
fileInfo,
rx.cap(1) == QLatin1String("rsa") ? QSsl::Rsa :
- (rx.cap(1) == QLatin1String("dsa") ? QSsl::Dsa : QSsl::Ec),
+ rx.cap(1) == QLatin1String("dsa") ? QSsl::Dsa :
+ rx.cap(1) == QLatin1String("dh") ? QSsl::Dh : QSsl::Ec,
rx.cap(2) == QLatin1String("pub") ? QSsl::PublicKey : QSsl::PrivateKey,
rx.cap(3).toInt(),
rx.cap(4) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);