diff options
Diffstat (limited to 'src/network/ssl')
-rw-r--r-- | src/network/ssl/qssl.cpp | 3 | ||||
-rw-r--r-- | src/network/ssl/qsslcertificate.cpp | 55 | ||||
-rw-r--r-- | src/network/ssl/qsslcertificate.h | 3 | ||||
-rw-r--r-- | src/network/ssl/qsslcertificate_p.h | 1 | ||||
-rw-r--r-- | src/network/ssl/qsslcipher.cpp | 9 | ||||
-rw-r--r-- | src/network/ssl/qsslcipher.h | 3 | ||||
-rw-r--r-- | src/network/ssl/qsslconfiguration.cpp | 2 | ||||
-rw-r--r-- | src/network/ssl/qsslerror.cpp | 24 | ||||
-rw-r--r-- | src/network/ssl/qsslerror.h | 10 | ||||
-rw-r--r-- | src/network/ssl/qsslkey.cpp | 14 | ||||
-rw-r--r-- | src/network/ssl/qsslkey.h | 5 | ||||
-rw-r--r-- | src/network/ssl/qsslkey_p.h | 4 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket.cpp | 88 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket.h | 2 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 38 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_p.h | 6 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_openssl_symbols.cpp | 145 | ||||
-rw-r--r-- | src/network/ssl/qsslsocket_p.h | 7 | ||||
-rw-r--r-- | src/network/ssl/ssl.pri | 10 |
19 files changed, 344 insertions, 85 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp index c4f792e..1913b49 100644 --- a/src/network/ssl/qssl.cpp +++ b/src/network/ssl/qssl.cpp @@ -49,7 +49,8 @@ QT_BEGIN_NAMESPACE \brief The QSsl namespace declares enums common to all SSL classes in QtNetwork. \since 4.3 - \ingroup io + \ingroup network + \ingroup ssl \inmodule QtNetwork */ diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp index d62c911..8d855b1 100644 --- a/src/network/ssl/qsslcertificate.cpp +++ b/src/network/ssl/qsslcertificate.cpp @@ -46,7 +46,7 @@ \since 4.3 \reentrant - \ingroup io + \ingroup network \ingroup ssl \inmodule QtNetwork @@ -71,9 +71,10 @@ After loading a certificate, you can find information about the certificate, its subject, and its issuer, by calling one of the many accessor functions, including version(), serialNumber(), - issuerInfo() and subjectInfo(). You can call notValidBefore() and - notValidAfter() to check when the certificate was issued, and when - it expires. The publicKey() function returns the certificate + issuerInfo() and subjectInfo(). You can call effectiveDate() and + expiryDate() to check when the certificate starts being + effective and when it expires. + The publicKey() function returns the certificate subject's public key as a QSslKey. You can call issuerInfo() or subjectInfo() to get detailed information about the certificate issuer and its subject. @@ -125,6 +126,9 @@ QT_BEGIN_NAMESPACE +// forward declaration +static QMap<QString, QString> _q_mapFromOnelineName(char *name); + /*! Constructs a QSslCertificate by reading \a format encoded data from \a device and using the first certificate found. You can @@ -157,7 +161,6 @@ QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat fo */ QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d) { - d->ref.ref(); } /*! @@ -165,8 +168,6 @@ QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d) */ QSslCertificate::~QSslCertificate() { - if (!d->ref.deref()) - delete d; } /*! @@ -175,7 +176,7 @@ QSslCertificate::~QSslCertificate() */ QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other) { - qAtomicAssign(d, other.d); + d = other.d; return *this; } @@ -241,11 +242,6 @@ void QSslCertificate::clear() { if (isNull()) return; - if (d->ref == 1) - delete d; - else - d->ref.deref(); - d = new QSslCertificatePrivate; } @@ -300,6 +296,10 @@ static QString _q_SubjectInfoToString(QSslCertificate::SubjectInfo info) */ QString QSslCertificate::issuerInfo(SubjectInfo info) const { + if (d->issuerInfo.isEmpty() && d->x509) + d->issuerInfo = + _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_issuer_name(d->x509), 0, 0)); + return d->issuerInfo.value(_q_SubjectInfoToString(info)); } @@ -327,6 +327,10 @@ QString QSslCertificate::issuerInfo(const QByteArray &tag) const */ QString QSslCertificate::subjectInfo(SubjectInfo info) const { + if (d->subjectInfo.isEmpty() && d->x509) + d->subjectInfo = + _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_subject_name(d->x509), 0, 0)); + return d->subjectInfo.value(_q_SubjectInfoToString(info)); } @@ -377,7 +381,7 @@ QMultiMap<QSsl::AlternateNameEntryType, QString> QSslCertificate::alternateSubje } const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(genName->d.ia5)); - const QString altName = QLatin1String(QByteArray(altNameStr, len)); + const QString altName = QString::fromLatin1(altNameStr, len); if (genName->type == GEN_DNS) result.insert(QSsl::DnsEntry, altName); else if (genName->type == GEN_EMAIL) @@ -662,11 +666,6 @@ QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509) if (!x509 || !QSslSocket::supportsSsl()) return certificate; - certificate.d->issuerInfo = - _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_issuer_name(x509), 0, 0)); - certificate.d->subjectInfo = - _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_subject_name(x509), 0, 0)); - ASN1_TIME *nbef = q_X509_get_notBefore(x509); ASN1_TIME *naft = q_X509_get_notAfter(x509); certificate.d->notValidBefore = q_getTimeFromASN1(nbef); @@ -686,7 +685,7 @@ static bool matchLineFeed(const QByteArray &pem, int *offset) ch = pem.at(++*offset); if (ch == '\n') { - *offset++; + *offset += 1; return true; } if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') { @@ -766,16 +765,16 @@ QDebug operator<<(QDebug debug, const QSslCertificate &certificate) { debug << "QSslCertificate(" << certificate.version() - << "," << certificate.serialNumber() - << "," << certificate.digest().toBase64() - << "," << certificate.issuerInfo(QSslCertificate::Organization) - << "," << certificate.subjectInfo(QSslCertificate::Organization) - << "," << certificate.alternateSubjectNames() + << ',' << certificate.serialNumber() + << ',' << certificate.digest().toBase64() + << ',' << certificate.issuerInfo(QSslCertificate::Organization) + << ',' << certificate.subjectInfo(QSslCertificate::Organization) + << ',' << certificate.alternateSubjectNames() #ifndef QT_NO_TEXTSTREAM - << "," << certificate.effectiveDate() - << "," << certificate.expiryDate() + << ',' << certificate.effectiveDate() + << ',' << certificate.expiryDate() #endif - << ")"; + << ')'; return debug; } QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info) diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h index 9525550..d664434 100644 --- a/src/network/ssl/qsslcertificate.h +++ b/src/network/ssl/qsslcertificate.h @@ -47,6 +47,7 @@ #include <QtCore/qbytearray.h> #include <QtCore/qcryptographichash.h> #include <QtCore/qregexp.h> +#include <QtCore/qsharedpointer.h> #include <QtNetwork/qssl.h> typedef struct x509_st X509; // ### check if this works @@ -118,7 +119,7 @@ public: Qt::HANDLE handle() const; private: - QSslCertificatePrivate *d; + QExplicitlySharedDataPointer<QSslCertificatePrivate> d; friend class QSslCertificatePrivate; friend class QSslSocketBackendPrivate; }; diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h index bae5ad8..0a5bc54 100644 --- a/src/network/ssl/qsslcertificate_p.h +++ b/src/network/ssl/qsslcertificate_p.h @@ -71,7 +71,6 @@ public: : null(true), x509(0) { QSslSocketPrivate::ensureInitialized(); - ref = 1; } ~QSslCertificatePrivate() diff --git a/src/network/ssl/qsslcipher.cpp b/src/network/ssl/qsslcipher.cpp index 8ca2a70..b44fde2 100644 --- a/src/network/ssl/qsslcipher.cpp +++ b/src/network/ssl/qsslcipher.cpp @@ -46,7 +46,7 @@ \since 4.3 \reentrant - \ingroup io + \ingroup network \ingroup ssl \inmodule QtNetwork @@ -103,7 +103,7 @@ QSslCipher::QSslCipher(const QString &name, QSsl::SslProtocol protocol) QSslCipher::QSslCipher(const QSslCipher &other) : d(new QSslCipherPrivate) { - *d = *other.d; + *d.data() = *other.d.data(); } /*! @@ -111,7 +111,6 @@ QSslCipher::QSslCipher(const QSslCipher &other) */ QSslCipher::~QSslCipher() { - delete d; } /*! @@ -120,7 +119,7 @@ QSslCipher::~QSslCipher() */ QSslCipher &QSslCipher::operator=(const QSslCipher &other) { - *d = *other.d; + *d.data() = *other.d.data(); return *this; } @@ -231,7 +230,7 @@ QDebug operator<<(QDebug debug, const QSslCipher &cipher) debug << "QSslCipher(name=" << qPrintable(cipher.name()) << ", bits=" << cipher.usedBits() << ", proto=" << qPrintable(cipher.protocolString()) - << ")"; + << ')'; return debug; } #endif diff --git a/src/network/ssl/qsslcipher.h b/src/network/ssl/qsslcipher.h index a000575..dbea864 100644 --- a/src/network/ssl/qsslcipher.h +++ b/src/network/ssl/qsslcipher.h @@ -44,6 +44,7 @@ #define QSSLCIPHER_H #include <QtCore/qstring.h> +#include <QtCore/qscopedpointer.h> #include <QtNetwork/qssl.h> QT_BEGIN_HEADER @@ -78,7 +79,7 @@ public: QSsl::SslProtocol protocol() const; private: - QSslCipherPrivate *d; + QScopedPointer<QSslCipherPrivate> d; friend class QSslSocketBackendPrivate; }; diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index f207e99..87db324 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -66,7 +66,7 @@ template<> void QSharedDataPointer<QSslConfigurationPrivate>::detach() \reentrant \inmodule QtNetwork - \ingroup io + \ingroup network \ingroup ssl QSslConfiguration is used by Qt networking classes to relay diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp index 3536bc4..d8c2c7a 100644 --- a/src/network/ssl/qsslerror.cpp +++ b/src/network/ssl/qsslerror.cpp @@ -46,7 +46,7 @@ \since 4.3 \reentrant - \ingroup io + \ingroup network \ingroup ssl \inmodule QtNetwork @@ -110,6 +110,23 @@ public: \sa QSslCertificate */ + +// RVCT compiler in debug build does not like about default values in const- +// So as an workaround we define all constructor overloads here explicitly +QSslError::QSslError() + : d(new QSslErrorPrivate) +{ + d->error = QSslError::NoError; + d->certificate = QSslCertificate(); +} + +QSslError::QSslError(SslError error) + : d(new QSslErrorPrivate) +{ + d->error = error; + d->certificate = QSslCertificate(); +} + QSslError::QSslError(SslError error, const QSslCertificate &certificate) : d(new QSslErrorPrivate) { @@ -123,7 +140,7 @@ QSslError::QSslError(SslError error, const QSslCertificate &certificate) QSslError::QSslError(const QSslError &other) : d(new QSslErrorPrivate) { - *d = *other.d; + *d.data() = *other.d.data(); } /*! @@ -131,7 +148,6 @@ QSslError::QSslError(const QSslError &other) */ QSslError::~QSslError() { - delete d; } /*! @@ -141,7 +157,7 @@ QSslError::~QSslError() */ QSslError &QSslError::operator=(const QSslError &other) { - *d = *other.d; + *d.data() = *other.d.data(); return *this; } diff --git a/src/network/ssl/qsslerror.h b/src/network/ssl/qsslerror.h index 1531505..265082b 100644 --- a/src/network/ssl/qsslerror.h +++ b/src/network/ssl/qsslerror.h @@ -86,8 +86,14 @@ public: UnspecifiedError = -1 }; - QSslError(SslError error = NoError, const QSslCertificate &certificate = QSslCertificate()); + // RVCT compiler in debug build does not like about default values in const- + // So as an workaround we define all constructor overloads here explicitly + QSslError(); + QSslError(SslError error); + QSslError(SslError error, const QSslCertificate &certificate); + QSslError(const QSslError &other); + ~QSslError(); QSslError &operator=(const QSslError &other); bool operator==(const QSslError &other) const; @@ -99,7 +105,7 @@ public: QSslCertificate certificate() const; private: - QSslErrorPrivate *d; + QScopedPointer<QSslErrorPrivate> d; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/src/network/ssl/qsslkey.cpp b/src/network/ssl/qsslkey.cpp index ce6bdfb..fceeb84 100644 --- a/src/network/ssl/qsslkey.cpp +++ b/src/network/ssl/qsslkey.cpp @@ -46,7 +46,7 @@ \since 4.3 \reentrant - \ingroup io + \ingroup network \ingroup ssl \inmodule QtNetwork @@ -271,7 +271,6 @@ QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::Encoding */ QSslKey::QSslKey(const QSslKey &other) : d(other.d) { - d->ref.ref(); } /*! @@ -279,8 +278,6 @@ QSslKey::QSslKey(const QSslKey &other) : d(other.d) */ QSslKey::~QSslKey() { - if (!d->ref.deref()) - delete d; } /*! @@ -291,7 +288,7 @@ QSslKey::~QSslKey() */ QSslKey &QSslKey::operator=(const QSslKey &other) { - qAtomicAssign(d, other.d); + d = other.d; return *this; } @@ -312,10 +309,7 @@ bool QSslKey::isNull() const */ void QSslKey::clear() { - if (!d->ref.deref()) { - delete d; - d = new QSslKeyPrivate; - } + d = new QSslKeyPrivate; } /*! @@ -460,7 +454,7 @@ QDebug operator<<(QDebug debug, const QSslKey &key) << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey") << ", " << (key.algorithm() == QSsl::Rsa ? "RSA" : "DSA") << ", " << key.length() - << ")"; + << ')'; return debug; } #endif diff --git a/src/network/ssl/qsslkey.h b/src/network/ssl/qsslkey.h index e9059f9..d5a85b3 100644 --- a/src/network/ssl/qsslkey.h +++ b/src/network/ssl/qsslkey.h @@ -45,6 +45,7 @@ #include <QtCore/qnamespace.h> #include <QtCore/qbytearray.h> +#include <QtCore/qsharedpointer.h> #include <QtNetwork/qssl.h> QT_BEGIN_HEADER @@ -58,7 +59,7 @@ QT_MODULE(Network) template <typename A, typename B> struct QPair; class QIODevice; - + class QSslKeyPrivate; class Q_NETWORK_EXPORT QSslKey { @@ -92,7 +93,7 @@ public: inline bool operator!=(const QSslKey &key) const { return !operator==(key); } private: - QSslKeyPrivate *d; + QExplicitlySharedDataPointer<QSslKeyPrivate> d; friend class QSslCertificate; }; diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h index fe7f198..df5d7b2 100644 --- a/src/network/ssl/qsslkey_p.h +++ b/src/network/ssl/qsslkey_p.h @@ -69,7 +69,6 @@ public: , dsa(0) { clear(); - ref = 1; } inline ~QSslKeyPrivate() @@ -91,6 +90,9 @@ public: DSA *dsa; QAtomicInt ref; + +private: + Q_DISABLE_COPY(QSslKeyPrivate) }; QT_END_NAMESPACE diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 1acd88b..e9f62b6 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -49,7 +49,7 @@ \since 4.3 \reentrant - \ingroup io + \ingroup network \ingroup ssl \inmodule QtNetwork @@ -113,8 +113,8 @@ readLine(), or getChar() to read decrypted data from QSslSocket's internal buffer, and you can call write() or putChar() to write data back to the peer. QSslSocket will automatically encrypt the - written data for you, and emit bytesWritten() once the data has - been written to the peer. + written data for you, and emit encryptedBytesWritten() once + the data has been written to the peer. As a convenience, QSslSocket supports QTcpSocket's blocking functions waitForConnected(), waitForReadyRead(), @@ -356,7 +356,7 @@ QSslSocket::~QSslSocket() want to ignore the errors and continue connecting, you must call ignoreSslErrors(), either from inside a slot function connected to the sslErrors() signal, or prior to entering encrypted mode. If - ignoreSslErrors is not called, the connection is dropped, signal + ignoreSslErrors() is not called, the connection is dropped, signal disconnected() is emitted, and QSslSocket returns to the UnconnectedState. @@ -397,6 +397,36 @@ void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, O } /*! + \since 4.6 + \overload + + In addition to the original behaviour of connectToHostEncrypted, + this overloaded method enables the usage of a different hostname + (\a sslPeerName) for the certificate validation instead of + the one used for the TCP connection (\a hostName). + + \sa connectToHostEncrypted() +*/ +void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, + const QString &sslPeerName, OpenMode mode) +{ + Q_D(QSslSocket); + if (d->state == ConnectedState || d->state == ConnectingState) { + qWarning("QSslSocket::connectToHostEncrypted() called when already connecting/connected"); + return; + } + + d->init(); + d->autoStartHandshake = true; + d->initialized = true; + d->verificationPeerName = sslPeerName; + + // Note: When connecting to localhost, some platforms (e.g., HP-UX and some BSDs) + // establish the connection immediately (i.e., first attempt). + connectToHost(hostName, port, mode); +} + +/*! Initializes QSslSocket with the native socket descriptor \a socketDescriptor. Returns true if \a socketDescriptor is accepted as a valid socket descriptor; otherwise returns false. @@ -412,8 +442,8 @@ bool QSslSocket::setSocketDescriptor(int socketDescriptor, SocketState state, Op { Q_D(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::setSocketDescriptor(" << socketDescriptor << "," - << state << "," << openMode << ")"; + qDebug() << "QSslSocket::setSocketDescriptor(" << socketDescriptor << ',' + << state << ',' << openMode << ')'; #endif if (!d->plainSocket) d->createPlainSocket(openMode); @@ -1571,7 +1601,33 @@ void QSslSocket::startServerEncryption() void QSslSocket::ignoreSslErrors() { Q_D(QSslSocket); - d->ignoreSslErrors = true; + d->ignoreAllSslErrors = true; +} + +/*! + \overload + \since 4.6 + + This method tells QSslSocket to ignore only the errors given in \a + errors. + + Note that you can set the expected certificate in the SSL error: + If, for instance, you want to connect to a server that uses + a self-signed certificate, consider the following snippet: + + \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 6 + + Multiple calls to this function will replace the list of errors that + were passed in previous calls. + You can clear the list of errors you want to ignore by calling this + function with an empty list. + + \sa sslErrors() +*/ +void QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) +{ + Q_D(QSslSocket); + d->ignoreErrorsList = errors; } /*! @@ -1587,7 +1643,7 @@ void QSslSocket::connectToHostImplementation(const QString &hostName, quint16 po #ifdef QSSLSOCKET_DEBUG qDebug() << "QSslSocket::connectToHostImplementation(" - << hostName << "," << port << "," << openMode << ")"; + << hostName << ',' << port << ',' << openMode << ')'; #endif if (!d->plainSocket) { #ifdef QSSLSOCKET_DEBUG @@ -1661,7 +1717,7 @@ qint64 QSslSocket::readData(char *data, qint64 maxlen) } while (!d->readBuffer.isEmpty() && readBytes < maxlen); } #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::readData(" << (void *)data << "," << maxlen << ") ==" << readBytes; + qDebug() << "QSslSocket::readData(" << (void *)data << ',' << maxlen << ") ==" << readBytes; #endif return readBytes; } @@ -1673,7 +1729,7 @@ qint64 QSslSocket::writeData(const char *data, qint64 len) { Q_D(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::writeData(" << (void *)data << "," << len << ")"; + qDebug() << "QSslSocket::writeData(" << (void *)data << ',' << len << ')'; #endif if (d->mode == UnencryptedMode && !d->autoStartHandshake) return d->plainSocket->write(data, len); @@ -1711,7 +1767,11 @@ void QSslSocketPrivate::init() mode = QSslSocket::UnencryptedMode; autoStartHandshake = false; connectionEncrypted = false; - ignoreSslErrors = false; + ignoreAllSslErrors = false; + + // we don't want to clear the ignoreErrorsList, so + // that it is possible setting it before connecting +// ignoreErrorsList.clear(); readBuffer.clear(); writeBuffer.clear(); @@ -1978,7 +2038,7 @@ void QSslSocketPrivate::_q_stateChangedSlot(QAbstractSocket::SocketState state) { Q_Q(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::_q_stateChangedSlot(" << state << ")"; + qDebug() << "QSslSocket::_q_stateChangedSlot(" << state << ')'; #endif q->setSocketState(state); emit q->stateChanged(state); @@ -1991,7 +2051,7 @@ void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error) { Q_Q(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::_q_errorSlot(" << error << ")"; + qDebug() << "QSslSocket::_q_errorSlot(" << error << ')'; qDebug() << "\tstate =" << q->state(); qDebug() << "\terrorString =" << q->errorString(); #endif @@ -2026,7 +2086,7 @@ void QSslSocketPrivate::_q_bytesWrittenSlot(qint64 written) { Q_Q(QSslSocket); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocket::_q_bytesWrittenSlot(" << written << ")"; + qDebug() << "QSslSocket::_q_bytesWrittenSlot(" << written << ')'; #endif if (mode == QSslSocket::UnencryptedMode) diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h index 8098a5e..0657932 100644 --- a/src/network/ssl/qsslsocket.h +++ b/src/network/ssl/qsslsocket.h @@ -86,6 +86,7 @@ public: // Autostarting the SSL client handshake. void connectToHostEncrypted(const QString &hostName, quint16 port, OpenMode mode = ReadWrite); + void connectToHostEncrypted(const QString &hostName, quint16 port, const QString &sslPeerName, OpenMode mode = ReadWrite); bool setSocketDescriptor(int socketDescriptor, SocketState state = ConnectedState, OpenMode openMode = ReadWrite); @@ -168,6 +169,7 @@ public: QList<QSslError> sslErrors() const; static bool supportsSsl(); + void ignoreSslErrors(const QList<QSslError> &errors); public Q_SLOTS: void startClientEncryption(); diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 903b100..a5a3400 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -276,7 +276,7 @@ init_context: if (first) first = false; else - cipherString.append(":"); + cipherString.append(':'); cipherString.append(cipher.name().toLatin1()); } @@ -500,7 +500,7 @@ void QSslSocketBackendPrivate::startClientEncryption() // Start connecting. This will place outgoing data in the BIO, so we // follow up with calling transmit(). - testConnection(); + startHandshake(); transmit(); } @@ -513,7 +513,7 @@ void QSslSocketBackendPrivate::startServerEncryption() // Start connecting. This will place outgoing data in the BIO, so we // follow up with calling transmit(). - testConnection(); + startHandshake(); transmit(); } @@ -601,7 +601,7 @@ void QSslSocketBackendPrivate::transmit() #ifdef QSSLSOCKET_DEBUG qDebug() << "QSslSocketBackendPrivate::transmit: testing encryption"; #endif - if (testConnection()) { + if (startHandshake()) { #ifdef QSSLSOCKET_DEBUG qDebug() << "QSslSocketBackendPrivate::transmit: encryption established"; #endif @@ -620,7 +620,7 @@ void QSslSocketBackendPrivate::transmit() } // If the request is small and the remote host closes the transmission - // after sending, there's a chance that testConnection() will already + // after sending, there's a chance that startHandshake() will already // have triggered a shutdown. if (!ssl) continue; @@ -720,7 +720,7 @@ static QSslError _q_OpenSSL_to_QSslError(int errorCode, const QSslCertificate &c return error; } -bool QSslSocketBackendPrivate::testConnection() +bool QSslSocketBackendPrivate::startHandshake() { Q_Q(QSslSocket); @@ -761,7 +761,7 @@ bool QSslSocketBackendPrivate::testConnection() q->setErrorString(QSslSocket::tr("Error during SSL handshake: %1").arg(SSL_ERRORSTR())); q->setSocketError(QAbstractSocket::SslHandshakeFailedError); #ifdef QSSLSOCKET_DEBUG - qDebug() << "QSslSocketBackendPrivate::testConnection: error!" << q->errorString(); + qDebug() << "QSslSocketBackendPrivate::startHandshake: error!" << q->errorString(); #endif emit q->error(QAbstractSocket::SslHandshakeFailedError); q->abort(); @@ -792,7 +792,7 @@ bool QSslSocketBackendPrivate::testConnection() // but only if we're a client connecting to a server // if we're the server, don't check CN if (mode == QSslSocket::SslClientMode) { - QString peerName = q->peerName(); + QString peerName = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName); QString commonName = configuration.peerCertificate.subjectInfo(QSslCertificate::CommonName); QRegExp regexp(commonName, Qt::CaseInsensitive, QRegExp::Wildcard); @@ -839,7 +839,27 @@ bool QSslSocketBackendPrivate::testConnection() if (!errors.isEmpty()) { sslErrors = errors; emit q->sslErrors(errors); - if (doVerifyPeer && !ignoreSslErrors) { + + bool doEmitSslError; + if (!ignoreErrorsList.empty()) { + // check whether the errors we got are all in the list of expected errors + // (applies only if the method QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) + // was called) + doEmitSslError = false; + for (int a = 0; a < errors.count(); a++) { + if (!ignoreErrorsList.contains(errors.at(a))) { + doEmitSslError = true; + break; + } + } + } else { + // if QSslSocket::ignoreSslErrors(const QList<QSslError> &errors) was not called and + // we get an SSL error, emit a signal unless we ignored all errors (by calling + // QSslSocket::ignoreSslErrors() ) + doEmitSslError = !ignoreAllSslErrors; + } + // check whether we need to emit an SSL handshake error + if (doVerifyPeer && doEmitSslError) { q->setErrorString(sslErrors.first().errorString()); q->setSocketError(QAbstractSocket::SslHandshakeFailedError); emit q->error(QAbstractSocket::SslHandshakeFailedError); diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h index 0114aca..b4bc567 100644 --- a/src/network/ssl/qsslsocket_openssl_p.h +++ b/src/network/ssl/qsslsocket_openssl_p.h @@ -57,7 +57,7 @@ #include "qsslsocket_p.h" #ifdef Q_OS_WIN -#include <windows.h> +#include <qt_windows.h> #if defined(OCSP_RESPONSE) #undef OCSP_RESPONSE #endif @@ -77,6 +77,8 @@ #include <openssl/x509.h> #include <openssl/x509v3.h> #include <openssl/x509_vfy.h> +#include <openssl/dsa.h> +#include <openssl/rsa.h> #if OPENSSL_VERSION_NUMBER >= 0x10000000L typedef _STACK STACK; @@ -106,7 +108,7 @@ public: void startClientEncryption(); void startServerEncryption(); void transmit(); - bool testConnection(); + bool startHandshake(); void disconnectFromHost(); void disconnected(); QSslCipher sessionCipher() const; diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp index e843235..be5c93c 100644 --- a/src/network/ssl/qsslsocket_openssl_symbols.cpp +++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp @@ -254,10 +254,16 @@ DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c, DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG) DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG) +#ifdef Q_OS_SYMBIAN +#define RESOLVEFUNC(func, ordinal, lib) \ + if (!(_q_##func = _q_PTR_##func(lib->resolve(#ordinal)))) \ + qWarning("QSslSocket: cannot resolve "#func); +#else #define RESOLVEFUNC(func) \ if (!(_q_##func = _q_PTR_##func(libs.first->resolve(#func))) \ && !(_q_##func = _q_PTR_##func(libs.second->resolve(#func)))) \ qWarning("QSslSocket: cannot resolve "#func); +#endif #if !defined QT_LINKED_OPENSSL @@ -358,7 +364,24 @@ static QPair<QLibrary*, QLibrary*> loadOpenSsl() pair.first = ssleay32; pair.second = libeay32; return pair; +# elif defined(Q_OS_SYMBIAN) + QLibrary *libssl = new QLibrary(QLatin1String("libssl")); + if (!libssl->load()) { + // Cannot find ssleay32.dll + delete libssl; + return pair; + } + QLibrary *libcrypto = new QLibrary(QLatin1String("libcrypto")); + if (!libcrypto->load()) { + delete libcrypto; + delete libssl; + return pair; + } + + pair.first = libssl; + pair.second = libcrypto; + return pair; # elif defined(Q_OS_UNIX) QLibrary *&libssl = pair.first; QLibrary *&libcrypto = pair.second; @@ -460,6 +483,127 @@ bool q_resolveOpenSslSymbols() // failed to load them return false; +#ifdef Q_OS_SYMBIAN +#ifdef SSLEAY_MACROS + RESOLVEFUNC(ASN1_dup, 125, libs.second ) +#endif + RESOLVEFUNC(ASN1_STRING_data, 71, libs.second ) + RESOLVEFUNC(ASN1_STRING_length, 76, libs.second ) + RESOLVEFUNC(BIO_ctrl, 184, libs.second ) + RESOLVEFUNC(BIO_free, 209, libs.second ) + RESOLVEFUNC(BIO_new, 222, libs.second ) + RESOLVEFUNC(BIO_new_mem_buf, 230, libs.second ) + RESOLVEFUNC(BIO_read, 244, libs.second ) + RESOLVEFUNC(BIO_s_mem, 251, libs.second ) + RESOLVEFUNC(BIO_write, 269, libs.second ) + RESOLVEFUNC(BN_num_bits, 387, libs.second ) + RESOLVEFUNC(CRYPTO_free, 469, libs.second ) + RESOLVEFUNC(CRYPTO_num_locks, 500, libs.second ) + RESOLVEFUNC(CRYPTO_set_id_callback, 513, libs.second ) + RESOLVEFUNC(CRYPTO_set_locking_callback, 516, libs.second ) + RESOLVEFUNC(DSA_free, 594, libs.second ) + RESOLVEFUNC(ERR_error_string, 744, libs.second ) + RESOLVEFUNC(ERR_get_error, 749, libs.second ) + RESOLVEFUNC(EVP_des_ede3_cbc, 919, libs.second ) + RESOLVEFUNC(EVP_PKEY_assign, 859, libs.second ) + RESOLVEFUNC(EVP_PKEY_free, 867, libs.second ) + RESOLVEFUNC(EVP_PKEY_get1_DSA, 869, libs.second ) + RESOLVEFUNC(EVP_PKEY_get1_RSA, 870, libs.second ) + RESOLVEFUNC(EVP_PKEY_new, 876, libs.second ) + RESOLVEFUNC(EVP_PKEY_type, 882, libs.second ) + RESOLVEFUNC(OBJ_nid2sn, 1036, libs.second ) + RESOLVEFUNC(OBJ_obj2nid, 1037, libs.second ) +#ifdef SSLEAY_MACROS // ### verify + RESOLVEFUNC(PEM_ASN1_read_bio, 1180, libs.second ) +#else + RESOLVEFUNC(PEM_read_bio_DSAPrivateKey, 1219, libs.second ) + RESOLVEFUNC(PEM_read_bio_RSAPrivateKey, 1228, libs.second ) + RESOLVEFUNC(PEM_write_bio_DSAPrivateKey, 1260, libs.second ) + RESOLVEFUNC(PEM_write_bio_RSAPrivateKey, 1271, libs.second ) +#endif + RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY, 1220, libs.second ) + RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY, 1230, libs.second ) + RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY, 1261, libs.second ) + RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY, 1273, libs.second ) + RESOLVEFUNC(RAND_seed, 1426, libs.second ) + RESOLVEFUNC(RAND_status, 1429, libs.second ) + RESOLVEFUNC(RSA_free, 1450, libs.second ) + RESOLVEFUNC(sk_free, 2571, libs.second ) + RESOLVEFUNC(sk_num, 2576, libs.second ) + RESOLVEFUNC(sk_value, 2585, libs.second ) + RESOLVEFUNC(SSL_CIPHER_description, 11, libs.first ) + RESOLVEFUNC(SSL_CTX_check_private_key, 21, libs.first ) + RESOLVEFUNC(SSL_CTX_ctrl, 22, libs.first ) + RESOLVEFUNC(SSL_CTX_free, 24, libs.first ) + RESOLVEFUNC(SSL_CTX_new, 35, libs.first ) + RESOLVEFUNC(SSL_CTX_set_cipher_list, 40, libs.first ) + RESOLVEFUNC(SSL_CTX_set_default_verify_paths, 44, libs.first ) + RESOLVEFUNC(SSL_CTX_set_verify, 56, libs.first ) + RESOLVEFUNC(SSL_CTX_set_verify_depth, 57, libs.first ) + RESOLVEFUNC(SSL_CTX_use_certificate, 64, libs.first ) + RESOLVEFUNC(SSL_CTX_use_certificate_file, 67, libs.first ) + RESOLVEFUNC(SSL_CTX_use_PrivateKey, 58, libs.first ) + RESOLVEFUNC(SSL_CTX_use_RSAPrivateKey, 61, libs.first ) + RESOLVEFUNC(SSL_CTX_use_PrivateKey_file, 60, libs.first ) + RESOLVEFUNC(SSL_accept, 82, libs.first ) + RESOLVEFUNC(SSL_clear, 92, libs.first ) + RESOLVEFUNC(SSL_connect, 93, libs.first ) + RESOLVEFUNC(SSL_free, 99, libs.first ) + RESOLVEFUNC(SSL_get_ciphers, 104, libs.first ) + RESOLVEFUNC(SSL_get_current_cipher, 106, libs.first ) + RESOLVEFUNC(SSL_get_error, 110, libs.first ) + RESOLVEFUNC(SSL_get_peer_cert_chain, 117, libs.first ) + RESOLVEFUNC(SSL_get_peer_certificate, 118, libs.first ) + RESOLVEFUNC(SSL_get_verify_result, 132, libs.first ) + RESOLVEFUNC(SSL_library_init, 137, libs.first ) + RESOLVEFUNC(SSL_load_error_strings, 139, libs.first ) + RESOLVEFUNC(SSL_new, 140, libs.first ) + RESOLVEFUNC(SSL_read, 143, libs.first ) + RESOLVEFUNC(SSL_set_accept_state, 148, libs.first ) + RESOLVEFUNC(SSL_set_bio, 149, libs.first ) + RESOLVEFUNC(SSL_set_connect_state, 152, libs.first ) + RESOLVEFUNC(SSL_shutdown, 173, libs.first ) + RESOLVEFUNC(SSL_write, 188, libs.first ) + RESOLVEFUNC(SSLv2_client_method, 192, libs.first ) + RESOLVEFUNC(SSLv3_client_method, 195, libs.first ) + RESOLVEFUNC(SSLv23_client_method, 189, libs.first ) + RESOLVEFUNC(TLSv1_client_method, 198, libs.first ) + RESOLVEFUNC(SSLv2_server_method, 194, libs.first ) + RESOLVEFUNC(SSLv3_server_method, 197, libs.first ) + RESOLVEFUNC(SSLv23_server_method, 191, libs.first ) + RESOLVEFUNC(TLSv1_server_method, 200, libs.first ) + RESOLVEFUNC(X509_NAME_oneline, 1830, libs.second ) + RESOLVEFUNC(X509_PUBKEY_get, 1844, libs.second ) + RESOLVEFUNC(X509_STORE_free, 1939, libs.second ) + RESOLVEFUNC(X509_STORE_new, 1942, libs.second ) + RESOLVEFUNC(X509_STORE_add_cert, 1936, libs.second ) + RESOLVEFUNC(X509_STORE_CTX_free, 1907, libs.second ) + RESOLVEFUNC(X509_STORE_CTX_init, 1919, libs.second ) + RESOLVEFUNC(X509_STORE_CTX_new, 1920, libs.second ) + RESOLVEFUNC(X509_STORE_CTX_set_purpose, 1931, libs.second ) + RESOLVEFUNC(X509_cmp, 1992, libs.second ) +#ifndef SSLEAY_MACROS + RESOLVEFUNC(X509_dup, 1997, libs.second ) +#endif + RESOLVEFUNC(X509_EXTENSION_get_object, 1785, libs.second ) + RESOLVEFUNC(X509_free, 2001, libs.second ) + RESOLVEFUNC(X509_get_ext, 2012, libs.second ) + RESOLVEFUNC(X509_get_ext_count, 2016, libs.second ) + RESOLVEFUNC(X509_get_ext_d2i, 2017, libs.second ) + RESOLVEFUNC(X509_get_issuer_name, 2018, libs.second ) + RESOLVEFUNC(X509_get_subject_name, 2022, libs.second ) + RESOLVEFUNC(X509_verify_cert, 2069, libs.second ) + RESOLVEFUNC(d2i_X509, 2309, libs.second ) + RESOLVEFUNC(i2d_X509, 2489, libs.second ) +#ifdef SSLEAY_MACROS + RESOLVEFUNC(i2d_DSAPrivateKey, 2395, libs.second ) + RESOLVEFUNC(i2d_RSAPrivateKey, 2476, libs.second ) + RESOLVEFUNC(d2i_DSAPrivateKey, 2220, libs.second ) + RESOLVEFUNC(d2i_RSAPrivateKey, 2296, libs.second ) +#endif + RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf, 1153, libs.second ) + RESOLVEFUNC(OPENSSL_add_all_algorithms_conf, 1152, libs.second ) +#else // Q_OS_SYMBIAN #ifdef SSLEAY_MACROS RESOLVEFUNC(ASN1_dup) #endif @@ -579,6 +723,7 @@ bool q_resolveOpenSslSymbols() #endif RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf) RESOLVEFUNC(OPENSSL_add_all_algorithms_conf) +#endif // Q_OS_SYMBIAN symbolsResolved = true; delete libs.first; delete libs.second; diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 1218547..a602c85 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -79,7 +79,8 @@ public: QSslSocket::SslMode mode; bool autoStartHandshake; bool connectionEncrypted; - bool ignoreSslErrors; + bool ignoreAllSslErrors; + QList<QSslError> ignoreErrorsList; bool* readyReadEmittedPointer; QRingBuffer readBuffer; @@ -88,6 +89,10 @@ public: QSslConfigurationPrivate configuration; QList<QSslError> sslErrors; + // if set, this hostname is used for certificate validation instead of the hostname + // that was used for connecting to. + QString verificationPeerName; + static bool ensureInitialized(); static void deinitialize(); static QList<QSslCipher> defaultCiphers(); diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri index 196e19d..72ea80f 100644 --- a/src/network/ssl/ssl.pri +++ b/src/network/ssl/ssl.pri @@ -1,6 +1,12 @@ # OpenSSL support; compile in QSslSocket. contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { - include($$QT_SOURCE_TREE/config.tests/unix/openssl/openssl.pri) + + +symbian { + INCLUDEPATH *= $$OS_LAYER_SSL_SYSTEMINCLUDE +} else { + include($$QT_SOURCE_TREE/config.tests/unix/openssl/openssl.pri) +} HEADERS += ssl/qssl.h \ ssl/qsslcertificate.h \ @@ -29,5 +35,5 @@ contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) { RESOURCES += network.qrc # Add optional SSL libs - LIBS += $$OPENSSL_LIBS + LIBS_PRIVATE += $$OPENSSL_LIBS } |