diff options
author | Corentin Chary <corentin.chary@gmail.com> | 2011-08-31 19:35:35 +0200 |
---|---|---|
committer | Qt by Nokia <qt-info@nokia.com> | 2011-08-31 21:06:53 +0200 |
commit | a4878db8df3fbaf9d222ec1206813b16dcdd90c7 (patch) | |
tree | 83271767995af278a8fe57ad0ac2e9a316deb9a4 /src/network/ssl | |
parent | a3e8f1ab0cc38c0d2e631d3e7f9e6379982204b7 (diff) |
qssl: add support for QSsl::Opaque key
This allow to use directly EVP_PKEY * with QSslKey (for
example comming from a PKCS#11 dongle).
Change-Id: Icb1ba5081506a831ec3d8cfffe13ce70939608ea
Merge-request: 48
Reviewed-by: Peter Hartmann <peter.hartmann@nokia.com>
Reviewed-on: http://codereview.qt.nokia.com/4010
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Diffstat (limited to 'src/network/ssl')
-rw-r--r-- | src/network/ssl/qssl.h | 1 | ||||
-rw-r--r-- | src/network/ssl/qsslkey.cpp | 46 | ||||
-rw-r--r-- | src/network/ssl/qsslkey.h | 1 | ||||
-rw-r--r-- | src/network/ssl/qsslkey_p.h | 2 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 26 |
5 files changed, 61 insertions, 15 deletions
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h index 7b76b64b4c..c8af346800 100644 --- a/src/network/ssl/qssl.h +++ b/src/network/ssl/qssl.h @@ -63,6 +63,7 @@ namespace QSsl { }; enum KeyAlgorithm { + Opaque, Rsa, Dsa }; diff --git a/src/network/ssl/qsslkey.cpp b/src/network/ssl/qsslkey.cpp index 29cfd0a77d..580b71bca9 100644 --- a/src/network/ssl/qsslkey.cpp +++ b/src/network/ssl/qsslkey.cpp @@ -89,6 +89,11 @@ void QSslKeyPrivate::clear(bool deep) q_DSA_free(dsa); dsa = 0; } + if (opaque) { + if (deep) + q_EVP_PKEY_free(opaque); + opaque = 0; + } } /*! @@ -265,6 +270,23 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding } /*! + Constructs a QSslKey from a valid native key \a handle. + \a type specifies whether the key is public or private. + + QSslKey will take ownership for this key and you must not + free the key using the native library. The algorithm used + when creating a key from a handle will always be QSsl::Opaque. +*/ +QSslKey::QSslKey(Qt::HANDLE handle, QSsl::KeyType type) + : d(new QSslKeyPrivate) +{ + d->opaque = reinterpret_cast<EVP_PKEY *>(handle); + d->algorithm = QSsl::Opaque; + d->type = type; + d->isNull = !d->opaque; +} + +/*! Constructs an identical copy of \a other. */ QSslKey::QSslKey(const QSslKey &other) : d(other.d) @@ -315,8 +337,9 @@ void QSslKey::clear() */ int QSslKey::length() const { - if (d->isNull) + if (d->isNull || d->algorithm == QSsl::Opaque) return -1; + return (d->algorithm == QSsl::Rsa) ? q_BN_num_bits(d->rsa->n) : q_BN_num_bits(d->dsa->p); } @@ -345,8 +368,9 @@ QSsl::KeyAlgorithm QSslKey::algorithm() const // ### autotest failure for non-empty passPhrase and private key QByteArray QSslKey::toDer(const QByteArray &passPhrase) const { - if (d->isNull) + if (d->isNull || d->algorithm == QSsl::Opaque) return QByteArray(); + return d->derFromPem(toPem(passPhrase)); } @@ -357,7 +381,7 @@ QByteArray QSslKey::toDer(const QByteArray &passPhrase) const */ QByteArray QSslKey::toPem(const QByteArray &passPhrase) const { - if (!QSslSocket::supportsSsl() || d->isNull) + if (!QSslSocket::supportsSsl() || d->isNull || d->algorithm == QSsl::Opaque) return QByteArray(); BIO *bio = q_BIO_new(q_BIO_s_mem()); @@ -417,7 +441,16 @@ QByteArray QSslKey::toPem(const QByteArray &passPhrase) const */ Qt::HANDLE QSslKey::handle() const { - return (d->algorithm == QSsl::Rsa) ? Qt::HANDLE(d->rsa) : Qt::HANDLE(d->dsa); + switch (d->algorithm) { + case QSsl::Opaque: + return Qt::HANDLE(d->opaque); + case QSsl::Rsa: + return Qt::HANDLE(d->rsa); + case QSsl::Dsa: + return Qt::HANDLE(d->dsa); + default: + return Qt::HANDLE(NULL); + } } /*! @@ -435,6 +468,8 @@ bool QSslKey::operator==(const QSslKey &other) const return false; if (length() != other.length()) return false; + if (algorithm() == QSsl::Opaque) + return handle() == other.handle(); return toDer() == other.toDer(); } @@ -450,7 +485,8 @@ QDebug operator<<(QDebug debug, const QSslKey &key) { debug << "QSslKey(" << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey") - << ", " << (key.algorithm() == QSsl::Rsa ? "RSA" : "DSA") + << ", " << (key.algorithm() == QSsl::Opaque ? "OPAQUE" : + (key.algorithm() == QSsl::Rsa ? "RSA" : "DSA")) << ", " << key.length() << ')'; return debug; diff --git a/src/network/ssl/qsslkey.h b/src/network/ssl/qsslkey.h index 5ee1b4ad2f..7064d22eb4 100644 --- a/src/network/ssl/qsslkey.h +++ b/src/network/ssl/qsslkey.h @@ -73,6 +73,7 @@ public: QSsl::EncodingFormat format = QSsl::Pem, QSsl::KeyType type = QSsl::PrivateKey, const QByteArray &passPhrase = QByteArray()); + explicit QSslKey(Qt::HANDLE handle, QSsl::KeyType type = QSsl::PrivateKey); QSslKey(const QSslKey &other); ~QSslKey(); QSslKey &operator=(const QSslKey &other); diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h index f4a77b3c3f..14075ecad0 100644 --- a/src/network/ssl/qsslkey_p.h +++ b/src/network/ssl/qsslkey_p.h @@ -67,6 +67,7 @@ public: inline QSslKeyPrivate() : rsa(0) , dsa(0) + , opaque(0) { clear(); } @@ -88,6 +89,7 @@ public: QSsl::KeyAlgorithm algorithm; RSA *rsa; DSA *dsa; + EVP_PKEY *opaque; QAtomicInt ref; diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 300a5c84d5..2fae2ccdce 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -364,20 +364,27 @@ init_context: return false; } - // Load private key - pkey = q_EVP_PKEY_new(); - // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free. - // this lead to a memory leak. Now we use the *_set1_* functions which do not - // take ownership of the RSA/DSA key instance because the QSslKey already has ownership. - if (configuration.privateKey.algorithm() == QSsl::Rsa) - q_EVP_PKEY_set1_RSA(pkey, (RSA *)configuration.privateKey.handle()); - else - q_EVP_PKEY_set1_DSA(pkey, (DSA *)configuration.privateKey.handle()); + if (configuration.privateKey.algorithm() == QSsl::Opaque) { + pkey = reinterpret_cast<EVP_PKEY *>(configuration.privateKey.handle()); + } else { + // Load private key + pkey = q_EVP_PKEY_new(); + // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free. + // this lead to a memory leak. Now we use the *_set1_* functions which do not + // take ownership of the RSA/DSA key instance because the QSslKey already has ownership. + if (configuration.privateKey.algorithm() == QSsl::Rsa) + q_EVP_PKEY_set1_RSA(pkey, (RSA *)configuration.privateKey.handle()); + else + q_EVP_PKEY_set1_DSA(pkey, (DSA *)configuration.privateKey.handle()); + } + if (!q_SSL_CTX_use_PrivateKey(ctx, pkey)) { q->setErrorString(QSslSocket::tr("Error loading private key, %1").arg(getErrorsFromOpenSsl())); emit q->error(QAbstractSocket::UnknownSocketError); return false; } + if (configuration.privateKey.algorithm() == QSsl::Opaque) + pkey = 0; // Don't free the private key, it belongs to QSslKey // Check if the certificate matches the private key. if (!q_SSL_CTX_check_private_key(ctx)) { @@ -1383,7 +1390,6 @@ void QSslSocketBackendPrivate::disconnected() q_EVP_PKEY_free(pkey); pkey = 0; } - } QSslCipher QSslSocketBackendPrivate::sessionCipher() const |