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>
This commit is contained in:
parent
a3e8f1ab0c
commit
a4878db8df
@ -63,6 +63,7 @@ namespace QSsl {
|
||||
};
|
||||
|
||||
enum KeyAlgorithm {
|
||||
Opaque,
|
||||
Rsa,
|
||||
Dsa
|
||||
};
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -264,6 +269,23 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding
|
||||
passPhrase);
|
||||
}
|
||||
|
||||
/*!
|
||||
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.
|
||||
*/
|
||||
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user