summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndré Klitzing <aklitzing@gmail.com>2014-11-18 10:18:18 +0100
committerAndré Klitzing <aklitzing@gmail.com>2015-01-18 10:18:43 +0100
commit962ea5690cb9351822c30da534ecae7aeeba667d (patch)
treec3fef960ae04c61bd55426cc05c7a910b8b48f52
parenta6a865e24999bf878f6f80341b7fc14f2b67a05e (diff)
Add elliptic curve support to QSsl
Add possibility to get length and other information of EC based certificates. Also it is possible to parse those public/private keys from PEM and DER encoded files. Based on patch by Remco Bloemen [ChangeLog][QtNetwork][SSL/TLS support] It is now possible to parse elliptic curve certificates. Change-Id: I4b11f726296aecda89c3cbd195d7c817ae6fc47b Task-number: QTBUG-18972 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
-rw-r--r--src/network/ssl/qssl.cpp1
-rw-r--r--src/network/ssl/qssl.h3
-rw-r--r--src/network/ssl/qsslcertificate_openssl.cpp6
-rw-r--r--src/network/ssl/qsslcontext_openssl.cpp6
-rw-r--r--src/network/ssl/qsslkey_openssl.cpp60
-rw-r--r--src/network/ssl/qsslkey_p.cpp18
-rw-r--r--src/network/ssl/qsslkey_p.h6
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp52
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h24
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pri-224-secp224r1.derbin0 -> 106 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pri-224-secp224r1.pem5
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pri-256-prime256v1.derbin0 -> 121 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pri-256-prime256v1.pem5
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pri-384-secp384r1.derbin0 -> 167 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pri-384-secp384r1.pem6
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pub-224-secp224r1.derbin0 -> 80 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pub-224-secp224r1.pem4
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pub-256-prime256v1.derbin0 -> 91 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pub-256-prime256v1.pem4
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pub-384-secp384r1.derbin0 -> 120 bytes
-rw-r--r--tests/auto/network/ssl/qsslkey/keys/ec-pub-384-secp384r1.pem5
-rwxr-xr-xtests/auto/network/ssl/qsslkey/keys/genkeys.sh22
-rw-r--r--tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp8
23 files changed, 223 insertions, 12 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
index 98be348e19..f76674f500 100644
--- a/src/network/ssl/qssl.cpp
+++ b/src/network/ssl/qssl.cpp
@@ -65,6 +65,7 @@ Q_LOGGING_CATEGORY(lcSsl, "qt.network.ssl");
\value Rsa The RSA algorithm.
\value Dsa The DSA algorithm.
+ \value Ec The Elliptic Curve 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 b0a35075fc..b626b884dc 100644
--- a/src/network/ssl/qssl.h
+++ b/src/network/ssl/qssl.h
@@ -55,7 +55,8 @@ namespace QSsl {
enum KeyAlgorithm {
Opaque,
Rsa,
- Dsa
+ Dsa,
+ Ec
};
enum AlternativeNameEntryType {
diff --git a/src/network/ssl/qsslcertificate_openssl.cpp b/src/network/ssl/qsslcertificate_openssl.cpp
index 065f0bfd04..4cb2e525eb 100644
--- a/src/network/ssl/qsslcertificate_openssl.cpp
+++ b/src/network/ssl/qsslcertificate_openssl.cpp
@@ -249,6 +249,12 @@ QSslKey QSslCertificate::publicKey() const
key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
key.d->algorithm = QSsl::Dsa;
key.d->isNull = false;
+#ifndef OPENSSL_NO_EC
+ } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_EC) {
+ key.d->ec = q_EVP_PKEY_get1_EC_KEY(pkey);
+ key.d->algorithm = QSsl::Ec;
+ key.d->isNull = false;
+#endif
} else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DH) {
// DH unsupported
} else {
diff --git a/src/network/ssl/qsslcontext_openssl.cpp b/src/network/ssl/qsslcontext_openssl.cpp
index 0a687082b7..d5328901a7 100644
--- a/src/network/ssl/qsslcontext_openssl.cpp
+++ b/src/network/ssl/qsslcontext_openssl.cpp
@@ -269,8 +269,12 @@ init_context:
// take ownership of the RSA/DSA key instance because the QSslKey already has ownership.
if (configuration.d->privateKey.algorithm() == QSsl::Rsa)
q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle()));
- else
+ else if (configuration.d->privateKey.algorithm() == QSsl::Dsa)
q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle()));
+#ifndef OPENSSL_NO_EC
+ else if (configuration.d->privateKey.algorithm() == QSsl::Ec)
+ q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle()));
+#endif
}
if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, sslContext->pkey)) {
diff --git a/src/network/ssl/qsslkey_openssl.cpp b/src/network/ssl/qsslkey_openssl.cpp
index e4d30ff229..ee4e8efa7c 100644
--- a/src/network/ssl/qsslkey_openssl.cpp
+++ b/src/network/ssl/qsslkey_openssl.cpp
@@ -70,6 +70,13 @@ void QSslKeyPrivate::clear(bool deep)
q_DSA_free(dsa);
dsa = 0;
}
+#ifndef OPENSSL_NO_EC
+ if (ec) {
+ if (deep)
+ q_EC_KEY_free(ec);
+ ec = 0;
+ }
+#endif
if (opaque) {
if (deep)
q_EVP_PKEY_free(opaque);
@@ -99,6 +106,16 @@ bool QSslKeyPrivate::fromEVP_PKEY(EVP_PKEY *pkey)
return true;
}
+#ifndef OPENSSL_NO_EC
+ else if (pkey->type == EVP_PKEY_EC) {
+ isNull = false;
+ algorithm = QSsl::Ec;
+ type = QSsl::PrivateKey;
+ ec = q_EC_KEY_dup(q_EVP_PKEY_get1_EC_KEY(pkey));
+
+ return true;
+ }
+#endif
else {
// Unknown key type. This could be handled as opaque, but then
// we'd eventually leak memory since we wouldn't be able to free
@@ -138,12 +155,20 @@ void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhra
: q_PEM_read_bio_RSAPrivateKey(bio, &rsa, 0, phrase);
if (rsa && rsa == result)
isNull = false;
- } else {
+ } else if (algorithm == QSsl::Dsa) {
DSA *result = (type == QSsl::PublicKey)
? q_PEM_read_bio_DSA_PUBKEY(bio, &dsa, 0, phrase)
: q_PEM_read_bio_DSAPrivateKey(bio, &dsa, 0, phrase);
if (dsa && dsa == result)
isNull = false;
+#ifndef OPENSSL_NO_EC
+ } else if (algorithm == QSsl::Ec) {
+ EC_KEY *result = (type == QSsl::PublicKey)
+ ? q_PEM_read_bio_EC_PUBKEY(bio, &ec, 0, phrase)
+ : q_PEM_read_bio_ECPrivateKey(bio, &ec, 0, phrase);
+ if (ec && ec == result)
+ isNull = false;
+#endif
}
q_BIO_free(bio);
@@ -154,8 +179,14 @@ int QSslKeyPrivate::length() const
if (isNull || algorithm == QSsl::Opaque)
return -1;
- return (algorithm == QSsl::Rsa)
- ? q_BN_num_bits(rsa->n) : q_BN_num_bits(dsa->p);
+ switch (algorithm) {
+ case QSsl::Rsa: return q_BN_num_bits(rsa->n);
+ case QSsl::Dsa: return q_BN_num_bits(dsa->p);
+#ifndef OPENSSL_NO_EC
+ case QSsl::Ec: return q_EC_GROUP_get_degree(q_EC_KEY_get0_group(ec));
+#endif
+ default: return -1;
+ }
}
QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
@@ -182,7 +213,7 @@ QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
fail = true;
}
}
- } else {
+ } else if (algorithm == QSsl::Dsa) {
if (type == QSsl::PublicKey) {
if (!q_PEM_write_bio_DSA_PUBKEY(bio, dsa))
fail = true;
@@ -195,6 +226,23 @@ QByteArray QSslKeyPrivate::toPem(const QByteArray &passPhrase) const
fail = true;
}
}
+#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,
+ // ### the cipher should be selectable in the API:
+ passPhrase.isEmpty() ? (const EVP_CIPHER *)0 : q_EVP_des_ede3_cbc(),
+ (uchar *)passPhrase.data(), passPhrase.size(), 0, 0)) {
+ fail = true;
+ }
+ }
+#endif
+ } else {
+ fail = true;
}
QByteArray pem;
@@ -216,6 +264,10 @@ Qt::HANDLE QSslKeyPrivate::handle() const
return Qt::HANDLE(rsa);
case QSsl::Dsa:
return Qt::HANDLE(dsa);
+#ifndef OPENSSL_NO_EC
+ case QSsl::Ec:
+ return Qt::HANDLE(ec);
+#endif
default:
return Qt::HANDLE(NULL);
}
diff --git a/src/network/ssl/qsslkey_p.cpp b/src/network/ssl/qsslkey_p.cpp
index 6162034fd7..99d502e8f9 100644
--- a/src/network/ssl/qsslkey_p.cpp
+++ b/src/network/ssl/qsslkey_p.cpp
@@ -103,7 +103,13 @@ QByteArray QSslKeyPrivate::pemHeader() const
return QByteArrayLiteral("-----BEGIN PUBLIC KEY-----");
else if (algorithm == QSsl::Rsa)
return QByteArrayLiteral("-----BEGIN RSA PRIVATE KEY-----");
- return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----");
+ else if (algorithm == QSsl::Dsa)
+ return QByteArrayLiteral("-----BEGIN DSA PRIVATE KEY-----");
+ else if (algorithm == QSsl::Ec)
+ return QByteArrayLiteral("-----BEGIN EC PRIVATE KEY-----");
+
+ Q_UNREACHABLE();
+ return QByteArray();
}
/*!
@@ -115,7 +121,13 @@ QByteArray QSslKeyPrivate::pemFooter() const
return QByteArrayLiteral("-----END PUBLIC KEY-----");
else if (algorithm == QSsl::Rsa)
return QByteArrayLiteral("-----END RSA PRIVATE KEY-----");
- return QByteArrayLiteral("-----END DSA PRIVATE KEY-----");
+ else if (algorithm == QSsl::Dsa)
+ return QByteArrayLiteral("-----END DSA PRIVATE KEY-----");
+ else if (algorithm == QSsl::Ec)
+ return QByteArrayLiteral("-----END EC PRIVATE KEY-----");
+
+ Q_UNREACHABLE();
+ return QByteArray();
}
/*!
@@ -438,7 +450,7 @@ 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" : "DSA"))
+ (key.algorithm() == QSsl::Rsa ? "RSA" : ((key.algorithm() == QSsl::Dsa) ? "DSA" : "EC")))
<< ", " << key.length()
<< ')';
return debug;
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
index 1254b33dfb..9cea860867 100644
--- a/src/network/ssl/qsslkey_p.h
+++ b/src/network/ssl/qsslkey_p.h
@@ -65,6 +65,9 @@ public:
#ifndef QT_NO_OPENSSL
, rsa(0)
, dsa(0)
+#ifndef OPENSSL_NO_EC
+ , ec(0)
+#endif
#endif
{
clear();
@@ -97,6 +100,9 @@ public:
EVP_PKEY *opaque;
RSA *rsa;
DSA *dsa;
+#ifndef OPENSSL_NO_EC
+ EC_KEY *ec;
+#endif
#else
enum Cipher {
DesCbc,
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
index 91de3b2743..ef87e77a3e 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols.cpp
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -142,6 +142,10 @@ DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return)
DEFINEFUNC(BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return 0, return)
DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return)
DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC(const EC_GROUP*, EC_KEY_get0_group, const EC_KEY* k, k, return 0, return)
+DEFINEFUNC(int, EC_GROUP_get_degree, const EC_GROUP* g, g, return 0, return)
+#endif
DEFINEFUNC(int, CRYPTO_num_locks, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(void, CRYPTO_set_locking_callback, void (*a)(int, int, const char *, int), a, return, DUMMYARG)
DEFINEFUNC(void, CRYPTO_set_id_callback, unsigned long (*a)(), a, return, DUMMYARG)
@@ -160,9 +164,15 @@ DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return 0, r
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)
+#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 0, return)
DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return 0, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC(EC_KEY *, EVP_PKEY_get1_EC_KEY, EVP_PKEY *a, a, return 0, return)
+#endif
DEFINEFUNC(EVP_PKEY *, EVP_PKEY_new, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(int, EVP_PKEY_type, int a, a, return NID_undef, return)
DEFINEFUNC2(int, i2d_X509, X509 *a, a, unsigned char **b, b, return -1, return)
@@ -179,13 +189,25 @@ DEFINEFUNC6(void *, PEM_ASN1_write_bio, d2i_of_void *a, a, const char *b, b, BIO
#else
DEFINEFUNC4(DSA *, PEM_read_bio_DSAPrivateKey, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(RSA *, PEM_read_bio_RSAPrivateKey, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC4(EC_KEY *, PEM_read_bio_ECPrivateKey, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
+#endif
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)
+#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
#endif
DEFINEFUNC4(DSA *, PEM_read_bio_DSA_PUBKEY, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
DEFINEFUNC4(RSA *, PEM_read_bio_RSA_PUBKEY, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC4(EC_KEY *, PEM_read_bio_EC_PUBKEY, BIO *a, a, EC_KEY **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
+#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)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC2(int, PEM_write_bio_EC_PUBKEY, BIO *a, a, EC_KEY *b, b, return 0, return)
+#endif
DEFINEFUNC2(void, RAND_seed, const void *a, a, int b, b, return, DUMMYARG)
DEFINEFUNC(int, RAND_status, void, DUMMYARG, return -1, return)
DEFINEFUNC(RSA *, RSA_new, DUMMYARG, DUMMYARG, return 0, return)
@@ -343,8 +365,14 @@ DEFINEFUNC(X509_STORE_CTX *, X509_STORE_CTX_new, DUMMYARG, DUMMYARG, return 0, r
#ifdef SSLEAY_MACROS
DEFINEFUNC2(int, i2d_DSAPrivateKey, const DSA *a, a, unsigned char **b, b, return -1, return)
DEFINEFUNC2(int, i2d_RSAPrivateKey, const RSA *a, a, unsigned char **b, b, return -1, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC2(int, i2d_ECPrivateKey, const EC_KEY *a, a, unsigned char **b, b, return -1, return)
+#endif
DEFINEFUNC3(RSA *, d2i_RSAPrivateKey, RSA **a, a, unsigned char **b, b, long c, c, return 0, return)
DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c, c, return 0, return)
+#ifndef OPENSSL_NO_EC
+DEFINEFUNC3(EC_KEY *, d2i_ECPrivateKey, EC_KEY **a, a, unsigned char **b, b, long c, c, return 0, return)
+#endif
#endif
DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG)
DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG)
@@ -371,6 +399,7 @@ DEFINEFUNC(DH *, DH_new, DUMMYARG, DUMMYARG, return 0, return)
DEFINEFUNC(void, DH_free, DH *dh, dh, return, DUMMYARG)
DEFINEFUNC3(BIGNUM *, BN_bin2bn, const unsigned char *s, s, int len, len, BIGNUM *ret, ret, return 0, return)
#ifndef OPENSSL_NO_EC
+DEFINEFUNC(EC_KEY *, EC_KEY_dup, const EC_KEY *ec, ec, return 0, return)
DEFINEFUNC(EC_KEY *, EC_KEY_new_by_curve_name, int nid, nid, return 0, return)
DEFINEFUNC(void, EC_KEY_free, EC_KEY *ecdh, ecdh, return, DUMMYARG)
DEFINEFUNC2(size_t, EC_get_builtin_curves, EC_builtin_curve * r, r, size_t nitems, nitems, return 0, return)
@@ -713,6 +742,10 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(BIO_read)
RESOLVEFUNC(BIO_s_mem)
RESOLVEFUNC(BIO_write)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(EC_KEY_get0_group)
+ RESOLVEFUNC(EC_GROUP_get_degree)
+#endif
RESOLVEFUNC(BN_num_bits)
RESOLVEFUNC(CRYPTO_free)
RESOLVEFUNC(CRYPTO_num_locks)
@@ -727,9 +760,15 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(EVP_PKEY_assign)
RESOLVEFUNC(EVP_PKEY_set1_RSA)
RESOLVEFUNC(EVP_PKEY_set1_DSA)
+#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)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(EVP_PKEY_get1_EC_KEY)
+#endif
RESOLVEFUNC(EVP_PKEY_new)
RESOLVEFUNC(EVP_PKEY_type)
RESOLVEFUNC(OBJ_nid2sn)
@@ -743,13 +782,25 @@ bool q_resolveOpenSslSymbols()
#else
RESOLVEFUNC(PEM_read_bio_DSAPrivateKey)
RESOLVEFUNC(PEM_read_bio_RSAPrivateKey)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(PEM_read_bio_ECPrivateKey)
+#endif
RESOLVEFUNC(PEM_write_bio_DSAPrivateKey)
RESOLVEFUNC(PEM_write_bio_RSAPrivateKey)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(PEM_write_bio_ECPrivateKey)
+#endif
#endif
RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY)
RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(PEM_read_bio_EC_PUBKEY)
+#endif
RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY)
RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY)
+#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(PEM_write_bio_EC_PUBKEY)
+#endif
RESOLVEFUNC(RAND_seed)
RESOLVEFUNC(RAND_status)
RESOLVEFUNC(RSA_new)
@@ -883,6 +934,7 @@ bool q_resolveOpenSslSymbols()
RESOLVEFUNC(DH_free)
RESOLVEFUNC(BN_bin2bn)
#ifndef OPENSSL_NO_EC
+ RESOLVEFUNC(EC_KEY_dup)
RESOLVEFUNC(EC_KEY_new_by_curve_name)
RESOLVEFUNC(EC_KEY_free)
RESOLVEFUNC(EC_get_builtin_curves)
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
index ee19345e4a..04cfd83de5 100644
--- a/src/network/ssl/qsslsocket_openssl_symbols_p.h
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -221,6 +221,10 @@ int q_BIO_read(BIO *a, void *b, int c);
BIO_METHOD *q_BIO_s_mem();
int q_BIO_write(BIO *a, const void *b, int c);
int q_BN_num_bits(const BIGNUM *a);
+#ifndef OPENSSL_NO_EC
+const EC_GROUP* q_EC_KEY_get0_group(const EC_KEY* k);
+int q_EC_GROUP_get_degree(const EC_GROUP* g);
+#endif
int q_CRYPTO_num_locks();
void q_CRYPTO_set_locking_callback(void (*a)(int, int, const char *, int));
void q_CRYPTO_set_id_callback(unsigned long (*a)());
@@ -240,9 +244,15 @@ const EVP_CIPHER *q_EVP_des_ede3_cbc();
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);
+#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);
+#ifndef OPENSSL_NO_EC
+EC_KEY *q_EVP_PKEY_get1_EC_KEY(EVP_PKEY *a);
+#endif
int q_EVP_PKEY_type(int a);
Q_AUTOTEST_EXPORT EVP_PKEY *q_EVP_PKEY_new();
int q_i2d_X509(X509 *a, unsigned char **b);
@@ -260,15 +270,28 @@ void *q_PEM_ASN1_read_bio(d2i_of_void *a, const char *b, BIO *c, void **d, pem_p
#else
DSA *q_PEM_read_bio_DSAPrivateKey(BIO *a, DSA **b, pem_password_cb *c, void *d);
RSA *q_PEM_read_bio_RSAPrivateKey(BIO *a, RSA **b, pem_password_cb *c, void *d);
+#ifndef OPENSSL_NO_EC
+EC_KEY *q_PEM_read_bio_ECPrivateKey(BIO *a, EC_KEY **b, pem_password_cb *c, void *d);
+#endif
int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned char *d,
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);
+#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);
+#endif
#endif
DSA *q_PEM_read_bio_DSA_PUBKEY(BIO *a, DSA **b, pem_password_cb *c, void *d);
RSA *q_PEM_read_bio_RSA_PUBKEY(BIO *a, RSA **b, pem_password_cb *c, void *d);
+#ifndef OPENSSL_NO_EC
+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);
+#ifndef OPENSSL_NO_EC
+int q_PEM_write_bio_EC_PUBKEY(BIO *a, EC_KEY *b);
+#endif
void q_RAND_seed(const void *a, int b);
int q_RAND_status();
RSA *q_RSA_new();
@@ -433,6 +456,7 @@ BIGNUM *q_BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
#ifndef OPENSSL_NO_EC
// EC Diffie-Hellman support
+EC_KEY *q_EC_KEY_dup(const EC_KEY *src);
EC_KEY *q_EC_KEY_new_by_curve_name(int nid);
void q_EC_KEY_free(EC_KEY *ecdh);
#define q_SSL_CTX_set_tmp_ecdh(ctx, ecdh) q_SSL_CTX_ctrl((ctx), SSL_CTRL_SET_TMP_ECDH, 0, (char *)ecdh)
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pri-224-secp224r1.der b/tests/auto/network/ssl/qsslkey/keys/ec-pri-224-secp224r1.der
new file mode 100644
index 0000000000..96bd7e5802
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pri-224-secp224r1.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pri-224-secp224r1.pem b/tests/auto/network/ssl/qsslkey/keys/ec-pri-224-secp224r1.pem
new file mode 100644
index 0000000000..9719604a5b
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pri-224-secp224r1.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MGgCAQEEHO64tAcs1VO7jI5uxJWVZ4Vl2Ich+pv8ctBzuaigBwYFK4EEACGhPAM6
+AATCe752GB/gfLn631dS6JYBBL+YcYeSakOWm/LnAuzyvtNlMDXWxmGpJScDcqYT
+okUBHW8YZbhj2A==
+-----END EC PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pri-256-prime256v1.der b/tests/auto/network/ssl/qsslkey/keys/ec-pri-256-prime256v1.der
new file mode 100644
index 0000000000..410ad8e950
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pri-256-prime256v1.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pri-256-prime256v1.pem b/tests/auto/network/ssl/qsslkey/keys/ec-pri-256-prime256v1.pem
new file mode 100644
index 0000000000..6a8af58066
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pri-256-prime256v1.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIPgxX3TR74wCm/Ivz0uEtk0cumCVxmKbd5Vf0p+fV84toAoGCCqGSM49
+AwEHoUQDQgAEVtbEzyqqHhBSH7Dsx8YVaC0YcvhvBA06fcva1vHZV4hJj7GL6yaO
+qjSIot2QW79M4ZoVFCu9GmOW+w+mjwMqNQ==
+-----END EC PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pri-384-secp384r1.der b/tests/auto/network/ssl/qsslkey/keys/ec-pri-384-secp384r1.der
new file mode 100644
index 0000000000..f9663cbf43
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pri-384-secp384r1.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pri-384-secp384r1.pem b/tests/auto/network/ssl/qsslkey/keys/ec-pri-384-secp384r1.pem
new file mode 100644
index 0000000000..53be8dfb52
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pri-384-secp384r1.pem
@@ -0,0 +1,6 @@
+-----BEGIN EC PRIVATE KEY-----
+MIGkAgEBBDDRnUOmMxV2R44q5RoM4ldm9A+5T4Xxzp6hWdRWOdhkIozo5GtNnYX8
+ZI5P3zTywD+gBwYFK4EEACKhZANiAAS/u72YC+dGs8D8bH+zRnneVMNPfGKeQrdt
+avEiVfKO7nmGdPu7KK9HDQPiKbWc4Yxtn4n7tsKMKo4adnThakcjZxuCIVjmdHIP
+9Wy7ZWeOaHi32MLHWQqh0z2elC92SmM=
+-----END EC PRIVATE KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pub-224-secp224r1.der b/tests/auto/network/ssl/qsslkey/keys/ec-pub-224-secp224r1.der
new file mode 100644
index 0000000000..006a99437b
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pub-224-secp224r1.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pub-224-secp224r1.pem b/tests/auto/network/ssl/qsslkey/keys/ec-pub-224-secp224r1.pem
new file mode 100644
index 0000000000..901d69d424
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pub-224-secp224r1.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+ME4wEAYHKoZIzj0CAQYFK4EEACEDOgAEwnu+dhgf4Hy5+t9XUuiWAQS/mHGHkmpD
+lpvy5wLs8r7TZTA11sZhqSUnA3KmE6JFAR1vGGW4Y9g=
+-----END PUBLIC KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pub-256-prime256v1.der b/tests/auto/network/ssl/qsslkey/keys/ec-pub-256-prime256v1.der
new file mode 100644
index 0000000000..82d3d462d9
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pub-256-prime256v1.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pub-256-prime256v1.pem b/tests/auto/network/ssl/qsslkey/keys/ec-pub-256-prime256v1.pem
new file mode 100644
index 0000000000..76ec2d4b0a
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pub-256-prime256v1.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVtbEzyqqHhBSH7Dsx8YVaC0Ycvhv
+BA06fcva1vHZV4hJj7GL6yaOqjSIot2QW79M4ZoVFCu9GmOW+w+mjwMqNQ==
+-----END PUBLIC KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pub-384-secp384r1.der b/tests/auto/network/ssl/qsslkey/keys/ec-pub-384-secp384r1.der
new file mode 100644
index 0000000000..aee76614f2
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pub-384-secp384r1.der
Binary files differ
diff --git a/tests/auto/network/ssl/qsslkey/keys/ec-pub-384-secp384r1.pem b/tests/auto/network/ssl/qsslkey/keys/ec-pub-384-secp384r1.pem
new file mode 100644
index 0000000000..ec69ee21a6
--- /dev/null
+++ b/tests/auto/network/ssl/qsslkey/keys/ec-pub-384-secp384r1.pem
@@ -0,0 +1,5 @@
+-----BEGIN PUBLIC KEY-----
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEv7u9mAvnRrPA/Gx/s0Z53lTDT3xinkK3
+bWrxIlXyju55hnT7uyivRw0D4im1nOGMbZ+J+7bCjCqOGnZ04WpHI2cbgiFY5nRy
+D/Vsu2Vnjmh4t9jCx1kKodM9npQvdkpj
+-----END PUBLIC KEY-----
diff --git a/tests/auto/network/ssl/qsslkey/keys/genkeys.sh b/tests/auto/network/ssl/qsslkey/keys/genkeys.sh
index c9f2406cad..279e71e561 100755
--- a/tests/auto/network/ssl/qsslkey/keys/genkeys.sh
+++ b/tests/auto/network/ssl/qsslkey/keys/genkeys.sh
@@ -72,3 +72,25 @@ do
echo -e "\ngenerating DSA public key to DER file ..."
openssl dsa -in dsa-pri-$size.pem -pubout -out dsa-pub-$size.der -outform DER
done
+
+#--- EC ----------------------------------------------------------------------------
+# Note: EC will be generated with pre-defined curves. You can check supported curves
+# with openssl ecparam -list_curves.
+# If OpenSSL 1.0.2 is available brainpool should be added!
+# brainpoolP256r1 brainpoolP384r1 brainpoolP512r1
+for curve in secp224r1 prime256v1 secp384r1
+do
+ size=`tr -cd 0-9 <<< $curve`
+ size=${size::-1} # remove last number of curve name as we need bit size only
+ echo -e "\ngenerating EC private key to PEM file ..."
+ openssl ecparam -name $curve -genkey -noout -out ec-pri-$size-$curve.pem
+
+ echo -e "\ngenerating EC private key to DER file ..."
+ openssl ec -in ec-pri-$size-$curve.pem -out ec-pri-$size-$curve.der -outform DER
+
+ echo -e "\ngenerating EC public key to PEM file ..."
+ openssl ec -in ec-pri-$size-$curve.pem -pubout -out ec-pub-$size-$curve.pem
+
+ echo -e "\ngenerating EC public key to DER file ..."
+ openssl ec -in ec-pri-$size-$curve.pem -pubout -out ec-pub-$size-$curve.der -outform DER
+done
diff --git a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
index 8083662d40..ddd8cb64aa 100644
--- a/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
+++ b/tests/auto/network/ssl/qsslkey/tst_qsslkey.cpp
@@ -105,12 +105,13 @@ void tst_QSslKey::initTestCase()
QDir dir(testDataDir + "/keys");
QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::Readable);
- QRegExp rx(QLatin1String("^(rsa|dsa)-(pub|pri)-(\\d+)\\.(pem|der)$"));
+ QRegExp rx(QLatin1String("^(rsa|dsa|ec)-(pub|pri)-(\\d+)-?\\w*\\.(pem|der)$"));
foreach (QFileInfo fileInfo, fileInfoList) {
if (rx.indexIn(fileInfo.fileName()) >= 0)
keyInfoList << KeyInfo(
fileInfo,
- rx.cap(1) == QLatin1String("rsa") ? QSsl::Rsa : QSsl::Dsa,
+ rx.cap(1) == QLatin1String("rsa") ? QSsl::Rsa :
+ (rx.cap(1) == QLatin1String("dsa") ? QSsl::Dsa : QSsl::Ec),
rx.cap(2) == QLatin1String("pub") ? QSsl::PublicKey : QSsl::PrivateKey,
rx.cap(3).toInt(),
rx.cap(4) == QLatin1String("pem") ? QSsl::Pem : QSsl::Der);
@@ -279,7 +280,8 @@ void tst_QSslKey::toEncryptedPemOrDer_data()
foreach (KeyInfo keyInfo, keyInfoList) {
foreach (QString password, passwords) {
QString testName = QString("%1-%2-%3-%4-%5").arg(keyInfo.fileInfo.fileName())
- .arg(keyInfo.algorithm == QSsl::Rsa ? "RSA" : "DSA")
+ .arg(keyInfo.algorithm == QSsl::Rsa ? "RSA" :
+ (keyInfo.algorithm == QSsl::Dsa ? "DSA" : "EC"))
.arg(keyInfo.type == QSsl::PrivateKey ? "PrivateKey" : "PublicKey")
.arg(keyInfo.format == QSsl::Pem ? "PEM" : "DER")
.arg(password);