diff options
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/ssl/qssl.h | 1 | ||||
-rw-r--r-- | src/network/ssl/qsslcertificate.cpp | 23 | ||||
-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 | 42 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_symbols_p.h | 4 |
7 files changed, 83 insertions, 36 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/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index bbc60f674c..fa97ccb78c 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -892,23 +892,24 @@ QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteAr // These certificates are known to be fraudulent and were created during the comodo // compromise. See http://www.comodo.com/Comodo-Fraud-Incident-2011-03-23.html static const char *certificate_blacklist[] = { - "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e", - "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06", - "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3", - "39:2a:43:4f:0e:07:df:1f:8a:a3:05:de:34:e0:c2:29", - "3e:75:ce:d4:6b:69:30:21:21:88:30:ae:86:a8:2a:71", - "e9:02:8b:95:78:e4:15:dc:1a:71:0a:2b:88:15:44:47", - "92:39:d5:34:8f:40:d1:69:5a:74:54:70:e1:f2:3f:43", - "b0:b7:13:3e:d0:96:f9:b5:6f:ae:91:c8:74:bd:3a:c0", - "d8:f3:5f:4e:b7:87:2b:2d:ab:06:92:e3:15:38:2f:b0", - "05:e2:e6:a4:cd:09:ea:54:d6:65:b0:75:fe:22:a2:56", + "04:7e:cb:e9:fc:a5:5f:7b:d0:9e:ae:36:e1:0c:ae:1e", "mail.google.com", // Comodo + "f5:c8:6a:f3:61:62:f1:3a:64:f5:4f:6d:c9:58:7c:06", "www.google.com", // Comodo + "d7:55:8f:da:f5:f1:10:5b:b2:13:28:2b:70:77:29:a3", "login.yahoo.com", // Comodo + "39:2a:43:4f:0e:07:df:1f:8a:a3:05:de:34:e0:c2:29", "login.yahoo.com", // Comodo + "3e:75:ce:d4:6b:69:30:21:21:88:30:ae:86:a8:2a:71", "login.yahoo.com", // Comodo + "e9:02:8b:95:78:e4:15:dc:1a:71:0a:2b:88:15:44:47", "login.skype.com", // Comodo + "92:39:d5:34:8f:40:d1:69:5a:74:54:70:e1:f2:3f:43", "addons.mozilla.org", // Comodo + "b0:b7:13:3e:d0:96:f9:b5:6f:ae:91:c8:74:bd:3a:c0", "login.live.com", // Comodo + "d8:f3:5f:4e:b7:87:2b:2d:ab:06:92:e3:15:38:2f:b0", "global trustee", // Comodo + "05:e2:e6:a4:cd:09:ea:54:d6:65:b0:75:fe:22:a2:56", "*.google.com", // DigiNotar 0 }; bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate) { for (int a = 0; certificate_blacklist[a] != 0; a++) { - if (certificate.serialNumber() == certificate_blacklist[a]) + if (certificate.serialNumber() == certificate_blacklist[a++] && + certificate.subjectInfo(QSslCertificate::CommonName).contains(QString::fromUtf8(certificate_blacklist[a]))) return true; } return false; 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..0ff17910f3 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -322,7 +322,7 @@ init_context: if (! caCertificate.isValid()) { expiredCerts.append(caCertificate); } else { - q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle()); + q_X509_STORE_add_cert(ctx->cert_store, reinterpret_cast<X509 *>(caCertificate.handle())); } } @@ -335,7 +335,7 @@ init_context: // now add the expired certs if (addExpiredCerts) { foreach (const QSslCertificate &caCertificate, expiredCerts) { - q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle()); + q_X509_STORE_add_cert(ctx->cert_store, reinterpret_cast<X509 *>(caCertificate.handle())); } } @@ -358,26 +358,33 @@ init_context: } // Load certificate - if (!q_SSL_CTX_use_certificate(ctx, (X509 *)configuration.localCertificate.handle())) { + if (!q_SSL_CTX_use_certificate(ctx, reinterpret_cast<X509 *>(configuration.localCertificate.handle()))) { q->setErrorString(QSslSocket::tr("Error loading local certificate, %1").arg(getErrorsFromOpenSsl())); emit q->error(QAbstractSocket::UnknownSocketError); 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, reinterpret_cast<RSA *>(configuration.privateKey.handle())); + else + q_EVP_PKEY_set1_DSA(pkey, reinterpret_cast<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 @@ -1508,7 +1514,7 @@ QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certifi if (!caCertificate.isValid()) { expiredCerts.append(caCertificate); } else { - q_X509_STORE_add_cert(certStore, (X509 *)caCertificate.handle()); + q_X509_STORE_add_cert(certStore, reinterpret_cast<X509 *>(caCertificate.handle())); } } @@ -1521,7 +1527,7 @@ QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certifi // now add the expired certs if (addExpiredCerts) { foreach (const QSslCertificate &caCertificate, expiredCerts) { - q_X509_STORE_add_cert(certStore, (X509 *)caCertificate.handle()); + q_X509_STORE_add_cert(certStore, reinterpret_cast<X509 *>(caCertificate.handle())); } } @@ -1548,9 +1554,9 @@ QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certifi continue; } #if OPENSSL_VERSION_NUMBER >= 0x10000000L - q_sk_push( (_STACK *)intermediates, (X509 *)cert.handle()); + q_sk_push( (_STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle())); #else - q_sk_push( (STACK *)intermediates, (X509 *)cert.handle()); + q_sk_push( (STACK *)intermediates, reinterpret_cast<X509 *>(cert.handle())); #endif } } @@ -1562,7 +1568,7 @@ QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certifi return errors; } - if (!q_X509_STORE_CTX_init(storeContext, certStore, (X509 *)certificateChain[0].handle(), intermediates)) { + if (!q_X509_STORE_CTX_init(storeContext, certStore, reinterpret_cast<X509 *>(certificateChain[0].handle()), intermediates)) { q_X509_STORE_CTX_free(storeContext); q_X509_STORE_free(certStore); errors << QSslError(QSslError::UnspecifiedError); diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h index a1db6d9320..d1705b3680 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols_p.h +++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h @@ -228,13 +228,13 @@ char *q_ERR_error_string(unsigned long a, char *b); unsigned long q_ERR_get_error(); const EVP_CIPHER *q_EVP_des_ede3_cbc(); int q_EVP_PKEY_assign(EVP_PKEY *a, int b, char *c); -int q_EVP_PKEY_set1_RSA(EVP_PKEY *a, RSA *b); +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); 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); int q_EVP_PKEY_type(int a); -EVP_PKEY *q_EVP_PKEY_new(); +Q_AUTOTEST_EXPORT EVP_PKEY *q_EVP_PKEY_new(); int q_i2d_X509(X509 *a, unsigned char **b); const char *q_OBJ_nid2sn(int a); const char *q_OBJ_nid2ln(int a); |