summaryrefslogtreecommitdiffstats
path: root/src/network/ssl
diff options
context:
space:
mode:
authorCorentin Chary <corentin.chary@gmail.com>2011-08-31 19:35:35 +0200
committerQt by Nokia <qt-info@nokia.com>2011-08-31 21:06:53 +0200
commita4878db8df3fbaf9d222ec1206813b16dcdd90c7 (patch)
tree83271767995af278a8fe57ad0ac2e9a316deb9a4 /src/network/ssl
parenta3e8f1ab0cc38c0d2e631d3e7f9e6379982204b7 (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.h1
-rw-r--r--src/network/ssl/qsslkey.cpp46
-rw-r--r--src/network/ssl/qsslkey.h1
-rw-r--r--src/network/ssl/qsslkey_p.h2
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp26
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