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 {
|
enum KeyAlgorithm {
|
||||||
|
Opaque,
|
||||||
Rsa,
|
Rsa,
|
||||||
Dsa
|
Dsa
|
||||||
};
|
};
|
||||||
|
@ -89,6 +89,11 @@ void QSslKeyPrivate::clear(bool deep)
|
|||||||
q_DSA_free(dsa);
|
q_DSA_free(dsa);
|
||||||
dsa = 0;
|
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);
|
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.
|
Constructs an identical copy of \a other.
|
||||||
*/
|
*/
|
||||||
@ -315,8 +337,9 @@ void QSslKey::clear()
|
|||||||
*/
|
*/
|
||||||
int QSslKey::length() const
|
int QSslKey::length() const
|
||||||
{
|
{
|
||||||
if (d->isNull)
|
if (d->isNull || d->algorithm == QSsl::Opaque)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return (d->algorithm == QSsl::Rsa)
|
return (d->algorithm == QSsl::Rsa)
|
||||||
? q_BN_num_bits(d->rsa->n) : q_BN_num_bits(d->dsa->p);
|
? 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
|
// ### autotest failure for non-empty passPhrase and private key
|
||||||
QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
|
QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
|
||||||
{
|
{
|
||||||
if (d->isNull)
|
if (d->isNull || d->algorithm == QSsl::Opaque)
|
||||||
return QByteArray();
|
return QByteArray();
|
||||||
|
|
||||||
return d->derFromPem(toPem(passPhrase));
|
return d->derFromPem(toPem(passPhrase));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +381,7 @@ QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
|
|||||||
*/
|
*/
|
||||||
QByteArray QSslKey::toPem(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();
|
return QByteArray();
|
||||||
|
|
||||||
BIO *bio = q_BIO_new(q_BIO_s_mem());
|
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
|
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;
|
return false;
|
||||||
if (length() != other.length())
|
if (length() != other.length())
|
||||||
return false;
|
return false;
|
||||||
|
if (algorithm() == QSsl::Opaque)
|
||||||
|
return handle() == other.handle();
|
||||||
return toDer() == other.toDer();
|
return toDer() == other.toDer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -450,7 +485,8 @@ QDebug operator<<(QDebug debug, const QSslKey &key)
|
|||||||
{
|
{
|
||||||
debug << "QSslKey("
|
debug << "QSslKey("
|
||||||
<< (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey")
|
<< (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()
|
<< ", " << key.length()
|
||||||
<< ')';
|
<< ')';
|
||||||
return debug;
|
return debug;
|
||||||
|
@ -73,6 +73,7 @@ public:
|
|||||||
QSsl::EncodingFormat format = QSsl::Pem,
|
QSsl::EncodingFormat format = QSsl::Pem,
|
||||||
QSsl::KeyType type = QSsl::PrivateKey,
|
QSsl::KeyType type = QSsl::PrivateKey,
|
||||||
const QByteArray &passPhrase = QByteArray());
|
const QByteArray &passPhrase = QByteArray());
|
||||||
|
explicit QSslKey(Qt::HANDLE handle, QSsl::KeyType type = QSsl::PrivateKey);
|
||||||
QSslKey(const QSslKey &other);
|
QSslKey(const QSslKey &other);
|
||||||
~QSslKey();
|
~QSslKey();
|
||||||
QSslKey &operator=(const QSslKey &other);
|
QSslKey &operator=(const QSslKey &other);
|
||||||
|
@ -67,6 +67,7 @@ public:
|
|||||||
inline QSslKeyPrivate()
|
inline QSslKeyPrivate()
|
||||||
: rsa(0)
|
: rsa(0)
|
||||||
, dsa(0)
|
, dsa(0)
|
||||||
|
, opaque(0)
|
||||||
{
|
{
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
@ -88,6 +89,7 @@ public:
|
|||||||
QSsl::KeyAlgorithm algorithm;
|
QSsl::KeyAlgorithm algorithm;
|
||||||
RSA *rsa;
|
RSA *rsa;
|
||||||
DSA *dsa;
|
DSA *dsa;
|
||||||
|
EVP_PKEY *opaque;
|
||||||
|
|
||||||
QAtomicInt ref;
|
QAtomicInt ref;
|
||||||
|
|
||||||
|
@ -364,6 +364,9 @@ init_context:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configuration.privateKey.algorithm() == QSsl::Opaque) {
|
||||||
|
pkey = reinterpret_cast<EVP_PKEY *>(configuration.privateKey.handle());
|
||||||
|
} else {
|
||||||
// Load private key
|
// Load private key
|
||||||
pkey = q_EVP_PKEY_new();
|
pkey = q_EVP_PKEY_new();
|
||||||
// before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
|
// before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free.
|
||||||
@ -373,11 +376,15 @@ init_context:
|
|||||||
q_EVP_PKEY_set1_RSA(pkey, (RSA *)configuration.privateKey.handle());
|
q_EVP_PKEY_set1_RSA(pkey, (RSA *)configuration.privateKey.handle());
|
||||||
else
|
else
|
||||||
q_EVP_PKEY_set1_DSA(pkey, (DSA *)configuration.privateKey.handle());
|
q_EVP_PKEY_set1_DSA(pkey, (DSA *)configuration.privateKey.handle());
|
||||||
|
}
|
||||||
|
|
||||||
if (!q_SSL_CTX_use_PrivateKey(ctx, pkey)) {
|
if (!q_SSL_CTX_use_PrivateKey(ctx, pkey)) {
|
||||||
q->setErrorString(QSslSocket::tr("Error loading private key, %1").arg(getErrorsFromOpenSsl()));
|
q->setErrorString(QSslSocket::tr("Error loading private key, %1").arg(getErrorsFromOpenSsl()));
|
||||||
emit q->error(QAbstractSocket::UnknownSocketError);
|
emit q->error(QAbstractSocket::UnknownSocketError);
|
||||||
return false;
|
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.
|
// Check if the certificate matches the private key.
|
||||||
if (!q_SSL_CTX_check_private_key(ctx)) {
|
if (!q_SSL_CTX_check_private_key(ctx)) {
|
||||||
@ -1383,7 +1390,6 @@ void QSslSocketBackendPrivate::disconnected()
|
|||||||
q_EVP_PKEY_free(pkey);
|
q_EVP_PKEY_free(pkey);
|
||||||
pkey = 0;
|
pkey = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QSslCipher QSslSocketBackendPrivate::sessionCipher() const
|
QSslCipher QSslSocketBackendPrivate::sessionCipher() const
|
||||||
|
Loading…
x
Reference in New Issue
Block a user