summaryrefslogtreecommitdiffstats
path: root/src/network/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/ssl')
-rw-r--r--src/network/ssl/qssl.cpp123
-rw-r--r--src/network/ssl/qssl.h90
-rw-r--r--src/network/ssl/qsslcertificate.cpp858
-rw-r--r--src/network/ssl/qsslcertificate.h139
-rw-r--r--src/network/ssl/qsslcertificate_p.h108
-rw-r--r--src/network/ssl/qsslcipher.cpp238
-rw-r--r--src/network/ssl/qsslcipher.h98
-rw-r--r--src/network/ssl/qsslcipher_p.h78
-rw-r--r--src/network/ssl/qsslconfiguration.cpp542
-rw-r--r--src/network/ssl/qsslconfiguration.h137
-rw-r--r--src/network/ssl/qsslconfiguration_p.h115
-rw-r--r--src/network/ssl/qsslerror.cpp321
-rw-r--r--src/network/ssl/qsslerror.h124
-rw-r--r--src/network/ssl/qsslkey.cpp460
-rw-r--r--src/network/ssl/qsslkey.h111
-rw-r--r--src/network/ssl/qsslkey_p.h100
-rw-r--r--src/network/ssl/qsslsocket.cpp2260
-rw-r--r--src/network/ssl/qsslsocket.h227
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp1459
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h184
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp888
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h427
-rw-r--r--src/network/ssl/qsslsocket_p.h181
-rw-r--r--src/network/ssl/ssl.pri36
24 files changed, 9304 insertions, 0 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
new file mode 100644
index 0000000000..55942969e4
--- /dev/null
+++ b/src/network/ssl/qssl.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsslkey.h"
+
+QT_BEGIN_NAMESPACE
+
+/*! \namespace QSsl
+
+ \brief The QSsl namespace declares enums common to all SSL classes in QtNetwork.
+ \since 4.3
+
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+*/
+
+/*!
+ \enum QSsl::KeyType
+
+ Describes the two types of keys QSslKey supports.
+
+ \value PrivateKey A private key.
+ \value PublicKey A public key.
+*/
+
+/*!
+ \enum QSsl::KeyAlgorithm
+
+ Describes the different key algorithms supported by QSslKey.
+
+ \value Rsa The RSA algorithm.
+ \value Dsa The DSA algorithm.
+*/
+
+/*!
+ \enum QSsl::EncodingFormat
+
+ Describes supported encoding formats for certificates and keys.
+
+ \value Pem The PEM format.
+ \value Der The DER format.
+*/
+
+/*!
+ \enum QSsl::AlternateNameEntryType
+
+ Describes the key types for alternate name entries in QSslCertificate.
+
+ \value EmailEntry An email entry; the entry contains an email address that
+ the certificate is valid for.
+
+ \value DnsEntry A DNS host name entry; the entry contains a host name
+ entry that the certificate is valid for. The entry may contain wildcards.
+
+ \sa QSslCertificate::alternateSubjectNames()
+
+*/
+
+/*!
+ \enum QSsl::SslProtocol
+
+ Describes the protocol of the cipher.
+
+ \value SslV3 SSLv3
+ \value SslV2 SSLv2
+ \value TlsV1 TLSv1
+ \value UnknownProtocol The cipher's protocol cannot be determined.
+ \value AnyProtocol The socket understands SSLv2, SSLv3, and TLSv1. This
+ value is used by QSslSocket only.
+ \value TlsV1SslV3 On the client side, this will send
+ a TLS 1.0 Client Hello, enabling TLSv1 and SSLv3 connections.
+ On the server side, this will enable both SSLv3 and TLSv1 connections.
+ \value SecureProtocols The default option, using protocols known to be secure;
+ currently behaves like TlsV1SslV3.
+
+ Note: most servers using SSL understand both versions (2 and 3),
+ but it is recommended to use the latest version only for security
+ reasons. However, SSL and TLS are not compatible with each other:
+ if you get unexpected handshake failures, verify that you chose
+ the correct setting for your protocol.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qssl.h b/src/network/ssl/qssl.h
new file mode 100644
index 0000000000..24dbb09747
--- /dev/null
+++ b/src/network/ssl/qssl.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSL_H
+#define QSSL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+namespace QSsl {
+ enum KeyType {
+ PrivateKey,
+ PublicKey
+ };
+
+ enum EncodingFormat {
+ Pem,
+ Der
+ };
+
+ enum KeyAlgorithm {
+ Rsa,
+ Dsa
+ };
+
+ enum AlternateNameEntryType {
+ EmailEntry,
+ DnsEntry
+ };
+
+ enum SslProtocol {
+ SslV3,
+ SslV2,
+ TlsV1, // ### Qt 5: rename to TlsV1_0 or so
+ AnyProtocol,
+ TlsV1SslV3,
+ SecureProtocols,
+ UnknownProtocol = -1
+ };
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSSL_H
diff --git a/src/network/ssl/qsslcertificate.cpp b/src/network/ssl/qsslcertificate.cpp
new file mode 100644
index 0000000000..a5cdf011aa
--- /dev/null
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -0,0 +1,858 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QSslCertificate
+ \brief The QSslCertificate class provides a convenient API for an X509 certificate.
+ \since 4.3
+
+ \reentrant
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ QSslCertificate stores an X509 certificate, and is commonly used
+ to verify the identity and store information about the local host,
+ a remotely connected peer, or a trusted third party Certificate
+ Authority.
+
+ There are many ways to construct a QSslCertificate. The most
+ common way is to call QSslSocket::peerCertificate(), which returns
+ a QSslCertificate object, or QSslSocket::peerCertificateChain(),
+ which returns a list of them. You can also load certificates from
+ a DER (binary) or PEM (Base64) encoded bundle, typically stored as
+ one or more local files, or in a Qt Resource.
+
+ You can call isNull() to check if your certificate is null. By
+ default, QSslCertificate constructs a null certificate. To check
+ if the certificate is valid, call isValid(). A null certificate is
+ invalid, but an invalid certificate is not necessarily null. If
+ you want to reset all contents in a certificate, call clear().
+
+ 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 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.
+
+ Internally, QSslCertificate is stored as an X509 structure. You
+ can access this handle by calling handle(), but the results are
+ likely to not be portable.
+
+ \sa QSslSocket, QSslKey, QSslCipher, QSslError
+*/
+
+/*!
+ \enum QSslCertificate::SubjectInfo
+
+ Describes keys that you can pass to QSslCertificate::issuerInfo() or
+ QSslCertificate::subjectInfo() to get information about the certificate
+ issuer or subject.
+
+ \value Organization "O" The name of the organization.
+
+ \value CommonName "CN" The common name; most often this is used to store
+ the host name.
+
+ \value LocalityName "L" The locality.
+
+ \value OrganizationalUnitName "OU" The organizational unit name.
+
+ \value CountryName "C" The country.
+
+ \value StateOrProvinceName "ST" The state or province.
+*/
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qsslcertificate.h"
+#include "qsslcertificate_p.h"
+#include "qsslkey.h"
+#include "qsslkey_p.h"
+
+#include <QtCore/qatomic.h>
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qmap.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+
+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
+ later call isNull() to see if \a device contained a certificate,
+ and if this certificate was loaded successfully.
+*/
+QSslCertificate::QSslCertificate(QIODevice *device, QSsl::EncodingFormat format)
+ : d(new QSslCertificatePrivate)
+{
+ QSslSocketPrivate::ensureInitialized();
+ if (device)
+ d->init(device->readAll(), format);
+}
+
+/*!
+ Constructs a QSslCertificate by parsing the \a format encoded
+ \a data and using the first available certificate found. You can
+ later call isNull() to see if \a data contained a certificate,
+ and if this certificate was loaded successfully.
+*/
+QSslCertificate::QSslCertificate(const QByteArray &data, QSsl::EncodingFormat format)
+ : d(new QSslCertificatePrivate)
+{
+ QSslSocketPrivate::ensureInitialized();
+ d->init(data, format);
+}
+
+/*!
+ Constructs an identical copy of \a other.
+*/
+QSslCertificate::QSslCertificate(const QSslCertificate &other) : d(other.d)
+{
+}
+
+/*!
+ Destroys the QSslCertificate.
+*/
+QSslCertificate::~QSslCertificate()
+{
+}
+
+/*!
+ Copies the contents of \a other into this certificate, making the two
+ certificates identical.
+*/
+QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if this certificate is the same as \a other; otherwise
+ returns false.
+*/
+bool QSslCertificate::operator==(const QSslCertificate &other) const
+{
+ if (d == other.d)
+ return true;
+ if (d->null && other.d->null)
+ return true;
+ if (d->x509 && other.d->x509)
+ return q_X509_cmp(d->x509, other.d->x509) == 0;
+ return false;
+}
+
+/*!
+ \fn bool QSslCertificate::operator!=(const QSslCertificate &other) const
+
+ Returns true if this certificate is not the same as \a other; otherwise
+ returns false.
+*/
+
+/*!
+ Returns true if this is a null certificate (i.e., a certificate
+ with no contents); otherwise returns false.
+
+ By default, QSslCertificate constructs a null certificate.
+
+ \sa isValid(), clear()
+*/
+bool QSslCertificate::isNull() const
+{
+ return d->null;
+}
+
+/*!
+ Returns true if this certificate is valid; otherwise returns
+ false.
+
+ Note: Currently, this function checks that the current
+ data-time is within the date-time range during which the
+ certificate is considered valid, and checks that the
+ certificate is not in a blacklist of fraudulent certificates.
+
+ \sa isNull()
+*/
+bool QSslCertificate::isValid() const
+{
+ const QDateTime currentTime = QDateTime::currentDateTime();
+ return currentTime >= d->notValidBefore &&
+ currentTime <= d->notValidAfter &&
+ ! QSslCertificatePrivate::isBlacklisted(*this);
+}
+
+/*!
+ Clears the contents of this certificate, making it a null
+ certificate.
+
+ \sa isNull()
+*/
+void QSslCertificate::clear()
+{
+ if (isNull())
+ return;
+ d = new QSslCertificatePrivate;
+}
+
+/*!
+ Returns the certificate's version string.
+*/
+QByteArray QSslCertificate::version() const
+{
+ if (d->versionString.isEmpty() && d->x509)
+ d->versionString =
+ QByteArray::number(qlonglong(q_ASN1_INTEGER_get(d->x509->cert_info->version)) + 1);
+
+ return d->versionString;
+}
+
+/*!
+ Returns the certificate's serial number string in decimal format.
+ In case the serial number cannot be converted to decimal format
+ (i.e. if it is bigger than 4294967295, which means it does not fit into 4 bytes),
+ its hexadecimal version is returned.
+*/
+QByteArray QSslCertificate::serialNumber() const
+{
+ if (d->serialNumberString.isEmpty() && d->x509) {
+ ASN1_INTEGER *serialNumber = d->x509->cert_info->serialNumber;
+ // if we cannot convert to a long, just output the hexadecimal number
+ if (serialNumber->length > 4) {
+ QByteArray hexString;
+ hexString.reserve(serialNumber->length * 3);
+ for (int a = 0; a < serialNumber->length; ++a) {
+ hexString += QByteArray::number(serialNumber->data[a], 16).rightJustified(2, '0');
+ hexString += ':';
+ }
+ hexString.chop(1);
+ d->serialNumberString = hexString;
+ } else {
+ d->serialNumberString = QByteArray::number(qlonglong(q_ASN1_INTEGER_get(serialNumber)));
+ }
+ }
+ return d->serialNumberString;
+}
+
+/*!
+ Returns a cryptographic digest of this certificate. By default,
+ an MD5 digest will be generated, but you can also specify a
+ custom \a algorithm.
+*/
+QByteArray QSslCertificate::digest(QCryptographicHash::Algorithm algorithm) const
+{
+ return QCryptographicHash::hash(toDer(), algorithm);
+}
+
+static QString _q_SubjectInfoToString(QSslCertificate::SubjectInfo info)
+{
+ QString str;
+ switch (info) {
+ case QSslCertificate::Organization: str = QLatin1String("O"); break;
+ case QSslCertificate::CommonName: str = QLatin1String("CN"); break;
+ case QSslCertificate::LocalityName: str = QLatin1String("L"); break;
+ case QSslCertificate::OrganizationalUnitName: str = QLatin1String("OU"); break;
+ case QSslCertificate::CountryName: str = QLatin1String("C"); break;
+ case QSslCertificate::StateOrProvinceName: str = QLatin1String("ST"); break;
+ }
+ return str;
+}
+
+/*!
+ \fn QString QSslCertificate::issuerInfo(SubjectInfo subject) const
+
+ Returns the issuer information for the \a subject from the
+ certificate, or an empty string if there is no information for
+ \a subject in the certificate.
+
+ \sa subjectInfo()
+*/
+QString QSslCertificate::issuerInfo(SubjectInfo info) const
+{
+ // lazy init
+ 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));
+}
+
+/*!
+ Returns the issuer information for \a tag from the certificate,
+ or an empty string if there is no information for \a tag in the
+ certificate.
+
+ \sa subjectInfo()
+*/
+QString QSslCertificate::issuerInfo(const QByteArray &tag) const
+{
+ // lazy init
+ 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(QString::fromLatin1(tag));
+}
+
+/*!
+
+ \fn QString QSslCertificate::subjectInfo(SubjectInfo subject) const
+
+ Returns the information for the \a subject, or an empty string if
+ there is no information for \a subject in the certificate.
+
+ \sa issuerInfo()
+*/
+QString QSslCertificate::subjectInfo(SubjectInfo info) const
+{
+ // lazy init
+ 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));
+}
+
+/*!
+ Returns the subject information for \a tag, or an empty string if
+ there is no information for \a tag in the certificate.
+
+ \sa issuerInfo()
+*/
+QString QSslCertificate::subjectInfo(const QByteArray &tag) const
+{
+ // lazy init
+ 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(QString::fromLatin1(tag));
+}
+
+/*!
+ Returns the list of alternative subject names for this
+ certificate. The alternate subject names typically contain host
+ names, optionally with wildcards, that are valid for this
+ certificate.
+
+ These names are tested against the connected peer's host name, if
+ either the subject information for \l CommonName doesn't define a
+ valid host name, or the subject info name doesn't match the peer's
+ host name.
+
+ \sa subjectInfo()
+*/
+QMultiMap<QSsl::AlternateNameEntryType, QString> QSslCertificate::alternateSubjectNames() const
+{
+ QMultiMap<QSsl::AlternateNameEntryType, QString> result;
+
+ if (!d->x509)
+ return result;
+
+ STACK_OF(GENERAL_NAME) *altNames = (STACK_OF(GENERAL_NAME)*)q_X509_get_ext_d2i(d->x509, NID_subject_alt_name, 0, 0);
+
+ if (altNames) {
+ for (int i = 0; i < q_sk_GENERAL_NAME_num(altNames); ++i) {
+ const GENERAL_NAME *genName = q_sk_GENERAL_NAME_value(altNames, i);
+ if (genName->type != GEN_DNS && genName->type != GEN_EMAIL)
+ continue;
+
+ int len = q_ASN1_STRING_length(genName->d.ia5);
+ if (len < 0 || len >= 8192) {
+ // broken name
+ continue;
+ }
+
+ const char *altNameStr = reinterpret_cast<const char *>(q_ASN1_STRING_data(genName->d.ia5));
+ const QString altName = QString::fromLatin1(altNameStr, len);
+ if (genName->type == GEN_DNS)
+ result.insert(QSsl::DnsEntry, altName);
+ else if (genName->type == GEN_EMAIL)
+ result.insert(QSsl::EmailEntry, altName);
+ }
+ q_sk_pop_free((STACK*)altNames, reinterpret_cast<void(*)(void*)>(q_sk_free));
+ }
+
+ return result;
+}
+
+/*!
+ Returns the date-time that the certificate becomes valid, or an
+ empty QDateTime if this is a null certificate.
+
+ \sa expiryDate()
+*/
+QDateTime QSslCertificate::effectiveDate() const
+{
+ return d->notValidBefore;
+}
+
+/*!
+ Returns the date-time that the certificate expires, or an empty
+ QDateTime if this is a null certificate.
+
+ \sa effectiveDate()
+*/
+QDateTime QSslCertificate::expiryDate() const
+{
+ return d->notValidAfter;
+}
+
+/*!
+ Returns a pointer to the native certificate handle, if there is
+ one, or a null pointer otherwise.
+
+ You can use this handle, together with the native API, to access
+ extended information about the certificate.
+
+ \warning Use of this function has a high probability of being
+ non-portable, and its return value may vary from platform to
+ platform or change from minor release to minor release.
+*/
+Qt::HANDLE QSslCertificate::handle() const
+{
+ return Qt::HANDLE(d->x509);
+}
+
+/*!
+ Returns the certificate subject's public key.
+*/
+QSslKey QSslCertificate::publicKey() const
+{
+ if (!d->x509)
+ return QSslKey();
+
+ QSslKey key;
+
+ key.d->type = QSsl::PublicKey;
+ X509_PUBKEY *xkey = d->x509->cert_info->key;
+ EVP_PKEY *pkey = q_X509_PUBKEY_get(xkey);
+ Q_ASSERT(pkey);
+
+ if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA) {
+ key.d->rsa = q_EVP_PKEY_get1_RSA(pkey);
+ key.d->algorithm = QSsl::Rsa;
+ key.d->isNull = false;
+ } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
+ key.d->dsa = q_EVP_PKEY_get1_DSA(pkey);
+ key.d->algorithm = QSsl::Dsa;
+ key.d->isNull = false;
+ } else if (q_EVP_PKEY_type(pkey->type) == EVP_PKEY_DH) {
+ // DH unsupported
+ } else {
+ // error?
+ }
+
+ q_EVP_PKEY_free(pkey);
+ return key;
+}
+
+/*!
+ Returns this certificate converted to a PEM (Base64) encoded
+ representation.
+*/
+QByteArray QSslCertificate::toPem() const
+{
+ if (!d->x509)
+ return QByteArray();
+ return d->QByteArray_from_X509(d->x509, QSsl::Pem);
+}
+
+/*!
+ Returns this certificate converted to a DER (binary) encoded
+ representation.
+*/
+QByteArray QSslCertificate::toDer() const
+{
+ if (!d->x509)
+ return QByteArray();
+ return d->QByteArray_from_X509(d->x509, QSsl::Der);
+}
+
+/*!
+ Searches all files in the \a path for certificates encoded in the
+ specified \a format and returns them in a list. \e must be a file or a
+ pattern matching one or more files, as specified by \a syntax.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslcertificate.cpp 0
+
+ \sa fromData()
+*/
+QList<QSslCertificate> QSslCertificate::fromPath(const QString &path,
+ QSsl::EncodingFormat format,
+ QRegExp::PatternSyntax syntax)
+{
+ // $, (,), *, +, ., ?, [, ,], ^, {, | and }.
+ int pos = -1;
+ if (syntax == QRegExp::Wildcard)
+ pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\*\\?\\[\\]]")));
+ else if (syntax != QRegExp::FixedString)
+ pos = path.indexOf(QRegExp(QLatin1String("[^\\][\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\}\\|]")));
+ QString pathPrefix = path.left(pos); // == path if pos < 0
+ if (pos != -1)
+ pathPrefix = pathPrefix.left(pathPrefix.lastIndexOf(QLatin1Char('/')));
+
+ // Special case - if the prefix ends up being nothing, use "." instead and
+ // chop off the first two characters from the glob'ed paths.
+ int startIndex = 0;
+ if (pathPrefix.trimmed().isEmpty()) {
+ if(path.startsWith(QLatin1Char('/'))) {
+ pathPrefix = path.left(path.indexOf(QRegExp(QLatin1String("[\\*\\?\\[]"))));
+ pathPrefix = path.left(path.lastIndexOf(QLatin1Char('/')));
+ } else {
+ startIndex = 2;
+ pathPrefix = QLatin1String(".");
+ }
+ }
+
+ // The path is a file.
+ if (pos == -1 && QFileInfo(pathPrefix).isFile()) {
+ QFile file(pathPrefix);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text))
+ return QSslCertificate::fromData(file.readAll(),format);
+ return QList<QSslCertificate>();
+ }
+
+ // The path can be a file or directory.
+ QList<QSslCertificate> certs;
+ QRegExp pattern(path, Qt::CaseSensitive, syntax);
+ QDirIterator it(pathPrefix, QDir::Files, QDirIterator::FollowSymlinks | QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ QString filePath = startIndex == 0 ? it.next() : it.next().mid(startIndex);
+ if (!pattern.exactMatch(filePath))
+ continue;
+
+ QFile file(filePath);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text))
+ certs += QSslCertificate::fromData(file.readAll(),format);
+ }
+ return certs;
+}
+
+/*!
+ Searches for and parses all certificates in \a device that are
+ encoded in the specified \a format and returns them in a list of
+ certificates.
+
+ \sa fromData()
+*/
+QList<QSslCertificate> QSslCertificate::fromDevice(QIODevice *device, QSsl::EncodingFormat format)
+{
+ if (!device) {
+ qWarning("QSslCertificate::fromDevice: cannot read from a null device");
+ return QList<QSslCertificate>();
+ }
+ return fromData(device->readAll(), format);
+}
+
+/*!
+ Searches for and parses all certificates in \a data that are
+ encoded in the specified \a format and returns them in a list of
+ certificates.
+
+ \sa fromDevice()
+*/
+QList<QSslCertificate> QSslCertificate::fromData(const QByteArray &data, QSsl::EncodingFormat format)
+{
+ return (format == QSsl::Pem)
+ ? QSslCertificatePrivate::certificatesFromPem(data)
+ : QSslCertificatePrivate::certificatesFromDer(data);
+}
+
+void QSslCertificatePrivate::init(const QByteArray &data, QSsl::EncodingFormat format)
+{
+ if (!data.isEmpty()) {
+ QList<QSslCertificate> certs = (format == QSsl::Pem)
+ ? certificatesFromPem(data, 1)
+ : certificatesFromDer(data, 1);
+ if (!certs.isEmpty()) {
+ *this = *certs.first().d;
+ if (x509)
+ x509 = q_X509_dup(x509);
+ }
+ }
+}
+
+#define BEGINCERTSTRING "-----BEGIN CERTIFICATE-----"
+#define ENDCERTSTRING "-----END CERTIFICATE-----"
+
+// ### refactor against QSsl::pemFromDer() etc. (to avoid redundant implementations)
+QByteArray QSslCertificatePrivate::QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format)
+{
+ if (!x509) {
+ qWarning("QSslSocketBackendPrivate::X509_to_QByteArray: null X509");
+ return QByteArray();
+ }
+
+ // Use i2d_X509 to convert the X509 to an array.
+ int length = q_i2d_X509(x509, 0);
+ QByteArray array;
+ array.resize(length);
+ char *data = array.data();
+ char **dataP = &data;
+ unsigned char **dataPu = (unsigned char **)dataP;
+ if (q_i2d_X509(x509, dataPu) < 0)
+ return QByteArray();
+
+ if (format == QSsl::Der)
+ return array;
+
+ // Convert to Base64 - wrap at 64 characters.
+ array = array.toBase64();
+ QByteArray tmp;
+ for (int i = 0; i <= array.size() - 64; i += 64) {
+ tmp += QByteArray::fromRawData(array.data() + i, 64);
+ tmp += '\n';
+ }
+ if (int remainder = array.size() % 64) {
+ tmp += QByteArray::fromRawData(array.data() + array.size() - remainder, remainder);
+ tmp += '\n';
+ }
+
+ return BEGINCERTSTRING "\n" + tmp + ENDCERTSTRING "\n";
+}
+
+static QMap<QString, QString> _q_mapFromOnelineName(char *name)
+{
+ QMap<QString, QString> info;
+ QString infoStr = QString::fromLocal8Bit(name);
+ q_CRYPTO_free(name);
+
+ // ### The right-hand encoding seems to allow hex (Regulierungsbeh\xC8orde)
+ //entry.replace(QLatin1String("\\x"), QLatin1String("%"));
+ //entry = QUrl::fromPercentEncoding(entry.toLatin1());
+ // ### See RFC-4630 for more details!
+
+ QRegExp rx(QLatin1String("/([A-Za-z]+)=(.+)"));
+
+ int pos = 0;
+ while ((pos = rx.indexIn(infoStr, pos)) != -1) {
+ const QString name = rx.cap(1);
+
+ QString value = rx.cap(2);
+ const int valuePos = rx.pos(2);
+
+ const int next = rx.indexIn(value);
+ if (next == -1) {
+ info.insert(name, value);
+ break;
+ }
+
+ value = value.left(next);
+ info.insert(name, value);
+ pos = valuePos + value.length();
+ }
+
+ return info;
+}
+
+QSslCertificate QSslCertificatePrivate::QSslCertificate_from_X509(X509 *x509)
+{
+ QSslCertificate certificate;
+ if (!x509 || !QSslSocket::supportsSsl())
+ return certificate;
+
+ ASN1_TIME *nbef = q_X509_get_notBefore(x509);
+ ASN1_TIME *naft = q_X509_get_notAfter(x509);
+ certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
+ certificate.d->notValidAfter = q_getTimeFromASN1(naft);
+ certificate.d->null = false;
+ certificate.d->x509 = q_X509_dup(x509);
+
+ return certificate;
+}
+
+static bool matchLineFeed(const QByteArray &pem, int *offset)
+{
+ char ch = 0;
+
+ // ignore extra whitespace at the end of the line
+ while (*offset < pem.size() && (ch = pem.at(*offset)) == ' ')
+ ++*offset;
+
+ if (ch == '\n') {
+ *offset += 1;
+ return true;
+ }
+ if (ch == '\r' && pem.size() > (*offset + 1) && pem.at(*offset + 1) == '\n') {
+ *offset += 2;
+ return true;
+ }
+ return false;
+}
+
+QList<QSslCertificate> QSslCertificatePrivate::certificatesFromPem(const QByteArray &pem, int count)
+{
+ QList<QSslCertificate> certificates;
+ QSslSocketPrivate::ensureInitialized();
+
+ int offset = 0;
+ while (count == -1 || certificates.size() < count) {
+ int startPos = pem.indexOf(BEGINCERTSTRING, offset);
+ if (startPos == -1)
+ break;
+ startPos += sizeof(BEGINCERTSTRING) - 1;
+ if (!matchLineFeed(pem, &startPos))
+ break;
+
+ int endPos = pem.indexOf(ENDCERTSTRING, startPos);
+ if (endPos == -1)
+ break;
+
+ offset = endPos + sizeof(ENDCERTSTRING) - 1;
+ if (offset < pem.size() && !matchLineFeed(pem, &offset))
+ break;
+
+ QByteArray decoded = QByteArray::fromBase64(
+ QByteArray::fromRawData(pem.data() + startPos, endPos - startPos));
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+ const unsigned char *data = (const unsigned char *)decoded.data();
+#else
+ unsigned char *data = (unsigned char *)decoded.data();
+#endif
+
+ if (X509 *x509 = q_d2i_X509(0, &data, decoded.size())) {
+ certificates << QSslCertificate_from_X509(x509);
+ q_X509_free(x509);
+ }
+ }
+
+ return certificates;
+}
+
+QList<QSslCertificate> QSslCertificatePrivate::certificatesFromDer(const QByteArray &der, int count)
+{
+ QList<QSslCertificate> certificates;
+ QSslSocketPrivate::ensureInitialized();
+
+
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+ const unsigned char *data = (const unsigned char *)der.data();
+#else
+ unsigned char *data = (unsigned char *)der.data();
+#endif
+ int size = der.size();
+
+ while (count == -1 || certificates.size() < count) {
+ if (X509 *x509 = q_d2i_X509(0, &data, size)) {
+ certificates << QSslCertificate_from_X509(x509);
+ q_X509_free(x509);
+ } else {
+ break;
+ }
+ size -= ((char *)data - der.data());
+ }
+
+ return certificates;
+}
+
+// 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",
+ 0
+};
+
+bool QSslCertificatePrivate::isBlacklisted(const QSslCertificate &certificate)
+{
+ for (int a = 0; certificate_blacklist[a] != 0; a++) {
+ if (certificate.serialNumber() == certificate_blacklist[a])
+ return true;
+ }
+ return false;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+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()
+#ifndef QT_NO_TEXTSTREAM
+ << ',' << certificate.effectiveDate()
+ << ',' << certificate.expiryDate()
+#endif
+ << ')';
+ return debug;
+}
+QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info)
+{
+ switch (info) {
+ case QSslCertificate::Organization: debug << "Organization"; break;
+ case QSslCertificate::CommonName: debug << "CommonName"; break;
+ case QSslCertificate::CountryName: debug << "CountryName"; break;
+ case QSslCertificate::LocalityName: debug << "LocalityName"; break;
+ case QSslCertificate::OrganizationalUnitName: debug << "OrganizationalUnitName"; break;
+ case QSslCertificate::StateOrProvinceName: debug << "StateOrProvinceName"; break;
+ }
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcertificate.h b/src/network/ssl/qsslcertificate.h
new file mode 100644
index 0000000000..e972ee7239
--- /dev/null
+++ b/src/network/ssl/qsslcertificate.h
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLCERTIFICATE_H
+#define QSSLCERTIFICATE_H
+
+#include <QtCore/qnamespace.h>
+#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
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_OPENSSL
+
+class QDateTime;
+class QIODevice;
+class QSslKey;
+class QStringList;
+template <typename T, typename U> class QMultiMap;
+
+class QSslCertificatePrivate;
+class Q_NETWORK_EXPORT QSslCertificate
+{
+public:
+ enum SubjectInfo {
+ Organization,
+ CommonName,
+ LocalityName,
+ OrganizationalUnitName,
+ CountryName,
+ StateOrProvinceName
+ };
+
+ QSslCertificate(QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
+ QSslCertificate( // ### s/encoded/data (to be consistent with signature in .cpp file) ?
+ const QByteArray &encoded = QByteArray(), QSsl::EncodingFormat format = QSsl::Pem);
+ QSslCertificate(const QSslCertificate &other);
+ ~QSslCertificate();
+ QSslCertificate &operator=(const QSslCertificate &other);
+ bool operator==(const QSslCertificate &other) const;
+ inline bool operator!=(const QSslCertificate &other) const { return !operator==(other); }
+
+ bool isNull() const;
+ bool isValid() const;
+ void clear();
+
+ // Certificate info
+ QByteArray version() const;
+ QByteArray serialNumber() const;
+ QByteArray digest(QCryptographicHash::Algorithm algorithm = QCryptographicHash::Md5) const;
+ QString issuerInfo(SubjectInfo info) const;
+ QString issuerInfo(const QByteArray &tag) const;
+ QString subjectInfo(SubjectInfo info) const;
+ QString subjectInfo(const QByteArray &tag) const;
+ QMultiMap<QSsl::AlternateNameEntryType, QString> alternateSubjectNames() const;
+ QDateTime effectiveDate() const;
+ QDateTime expiryDate() const;
+ QSslKey publicKey() const;
+
+ QByteArray toPem() const;
+ QByteArray toDer() const;
+
+ static QList<QSslCertificate> fromPath(
+ const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
+ QRegExp::PatternSyntax syntax = QRegExp::FixedString);
+ static QList<QSslCertificate> fromDevice(
+ QIODevice *device, QSsl::EncodingFormat format = QSsl::Pem);
+ static QList<QSslCertificate> fromData(
+ const QByteArray &data, QSsl::EncodingFormat format = QSsl::Pem);
+
+ Qt::HANDLE handle() const;
+
+private:
+ QExplicitlySharedDataPointer<QSslCertificatePrivate> d;
+ friend class QSslCertificatePrivate;
+ friend class QSslSocketBackendPrivate;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslCertificate &certificate);
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, QSslCertificate::SubjectInfo info);
+#endif
+
+#endif // QT_NO_OPENSSL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/network/ssl/qsslcertificate_p.h b/src/network/ssl/qsslcertificate_p.h
new file mode 100644
index 0000000000..1ce33d3bfd
--- /dev/null
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLCERTIFICATE_P_H
+#define QSSLCERTIFICATE_P_H
+
+#include "qsslcertificate.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsslsocket_p.h"
+#include <QtCore/qdatetime.h>
+#include <QtCore/qmap.h>
+
+#include <openssl/x509.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSslCertificatePrivate
+{
+public:
+ QSslCertificatePrivate()
+ : null(true), x509(0)
+ {
+ QSslSocketPrivate::ensureInitialized();
+ }
+
+ ~QSslCertificatePrivate()
+ {
+ if (x509)
+ q_X509_free(x509);
+ }
+
+ bool null;
+ QByteArray versionString;
+ QByteArray serialNumberString;
+
+ QMap<QString, QString> issuerInfo;
+ QMap<QString, QString> subjectInfo;
+ QDateTime notValidAfter;
+ QDateTime notValidBefore;
+
+ X509 *x509;
+
+ void init(const QByteArray &data, QSsl::EncodingFormat format);
+
+ static QByteArray QByteArray_from_X509(X509 *x509, QSsl::EncodingFormat format);
+ static QSslCertificate QSslCertificate_from_X509(X509 *x509);
+ static QList<QSslCertificate> certificatesFromPem(const QByteArray &pem, int count = -1);
+ static QList<QSslCertificate> certificatesFromDer(const QByteArray &der, int count = -1);
+ static bool isBlacklisted(const QSslCertificate &certificate);
+
+ friend class QSslSocketBackendPrivate;
+
+ QAtomicInt ref;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/ssl/qsslcipher.cpp b/src/network/ssl/qsslcipher.cpp
new file mode 100644
index 0000000000..33d4b66a50
--- /dev/null
+++ b/src/network/ssl/qsslcipher.cpp
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QSslCipher
+ \brief The QSslCipher class represents an SSL cryptographic cipher.
+ \since 4.3
+
+ \reentrant
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ QSslCipher stores information about one cryptographic cipher. It
+ is most commonly used with QSslSocket, either for configuring
+ which ciphers the socket can use, or for displaying the socket's
+ ciphers to the user.
+
+ \sa QSslSocket, QSslKey
+*/
+
+#include "qsslcipher.h"
+#include "qsslcipher_p.h"
+#include "qsslsocket.h"
+
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ Constructs an empty QSslCipher object.
+*/
+QSslCipher::QSslCipher()
+ : d(new QSslCipherPrivate)
+{
+}
+
+/*!
+ Constructs a QSslCipher object for the cipher determined by \a
+ name and \a protocol. The constructor accepts only supported
+ ciphers (i.e., the \a name and \a protocol must identify a cipher
+ in the list of ciphers returned by
+ QSslSocket::supportedCiphers()).
+
+ You can call isNull() after construction to check if \a name and
+ \a protocol correctly identified a supported cipher.
+*/
+QSslCipher::QSslCipher(const QString &name, QSsl::SslProtocol protocol)
+ : d(new QSslCipherPrivate)
+{
+ foreach (const QSslCipher &cipher, QSslSocket::supportedCiphers()) {
+ if (cipher.name() == name && cipher.protocol() == protocol) {
+ *this = cipher;
+ return;
+ }
+ }
+}
+
+/*!
+ Constructs an identical copy of the \a other cipher.
+*/
+QSslCipher::QSslCipher(const QSslCipher &other)
+ : d(new QSslCipherPrivate)
+{
+ *d.data() = *other.d.data();
+}
+
+/*!
+ Destroys the QSslCipher object.
+*/
+QSslCipher::~QSslCipher()
+{
+}
+
+/*!
+ Copies the contents of \a other into this cipher, making the two
+ ciphers identical.
+*/
+QSslCipher &QSslCipher::operator=(const QSslCipher &other)
+{
+ *d.data() = *other.d.data();
+ return *this;
+}
+
+/*!
+ Returns true if this cipher is the same as \a other; otherwise,
+ false is returned.
+*/
+bool QSslCipher::operator==(const QSslCipher &other) const
+{
+ return d->name == other.d->name && d->protocol == other.d->protocol;
+}
+
+/*!
+ \fn bool QSslCipher::operator!=(const QSslCipher &other) const
+
+ Returns true if this cipher is not the same as \a other;
+ otherwise, false is returned.
+*/
+
+/*!
+ Returns true if this is a null cipher; otherwise returns false.
+*/
+bool QSslCipher::isNull() const
+{
+ return d->isNull;
+}
+
+/*!
+ Returns the name of the cipher, or an empty QString if this is a null
+ cipher.
+
+ \sa isNull()
+*/
+QString QSslCipher::name() const
+{
+ return d->name;
+}
+
+/*!
+ Returns the number of bits supported by the cipher.
+
+ \sa usedBits()
+*/
+int QSslCipher::supportedBits()const
+{
+ return d->supportedBits;
+}
+
+/*!
+ Returns the number of bits used by the cipher.
+
+ \sa supportedBits()
+*/
+int QSslCipher::usedBits() const
+{
+ return d->bits;
+}
+
+/*!
+ Returns the cipher's key exchange method as a QString.
+*/
+QString QSslCipher::keyExchangeMethod() const
+{
+ return d->keyExchangeMethod;
+}
+
+/*!
+ Returns the cipher's authentication method as a QString.
+*/
+QString QSslCipher::authenticationMethod() const
+{
+ return d->authenticationMethod;
+}
+
+/*!
+ Returns the cipher's encryption method as a QString.
+*/
+QString QSslCipher::encryptionMethod() const
+{
+ return d->encryptionMethod;
+}
+
+/*!
+ Returns the cipher's protocol as a QString.
+
+ \sa protocol()
+*/
+QString QSslCipher::protocolString() const
+{
+ return d->protocolString;
+}
+
+/*!
+ Returns the cipher's protocol type, or \l QSsl::UnknownProtocol if
+ QSslCipher is unable to determine the protocol (protocolString() may
+ contain more information).
+
+ \sa protocolString()
+*/
+QSsl::SslProtocol QSslCipher::protocol() const
+{
+ return d->protocol;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QSslCipher &cipher)
+{
+ debug << "QSslCipher(name=" << qPrintable(cipher.name())
+ << ", bits=" << cipher.usedBits()
+ << ", proto=" << qPrintable(cipher.protocolString())
+ << ')';
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslcipher.h b/src/network/ssl/qsslcipher.h
new file mode 100644
index 0000000000..edaed2c2e8
--- /dev/null
+++ b/src/network/ssl/qsslcipher.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLCIPHER_H
+#define QSSLCIPHER_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qscopedpointer.h>
+#include <QtNetwork/qssl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_OPENSSL
+
+class QSslCipherPrivate;
+class Q_NETWORK_EXPORT QSslCipher
+{
+public:
+ QSslCipher();
+ QSslCipher(const QString &name, QSsl::SslProtocol protocol);
+ QSslCipher(const QSslCipher &other);
+ ~QSslCipher();
+ QSslCipher &operator=(const QSslCipher &other);
+ bool operator==(const QSslCipher &other) const;
+ inline bool operator!=(const QSslCipher &other) const { return !operator==(other); }
+
+ bool isNull() const;
+ QString name() const;
+ int supportedBits() const;
+ int usedBits() const;
+
+ QString keyExchangeMethod() const;
+ QString authenticationMethod() const;
+ QString encryptionMethod() const;
+ QString protocolString() const;
+ QSsl::SslProtocol protocol() const;
+
+private:
+ QScopedPointer<QSslCipherPrivate> d;
+ friend class QSslSocketBackendPrivate;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslCipher &cipher);
+#endif
+
+#endif // QT_NO_OPENSSL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
+
diff --git a/src/network/ssl/qsslcipher_p.h b/src/network/ssl/qsslcipher_p.h
new file mode 100644
index 0000000000..79fe911280
--- /dev/null
+++ b/src/network/ssl/qsslcipher_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsslcipher.h"
+
+QT_BEGIN_NAMESPACE
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+class QSslCipherPrivate
+{
+public:
+ QSslCipherPrivate()
+ : isNull(true), supportedBits(0), bits(0),
+ exportable(false), protocol(QSsl::UnknownProtocol)
+ {
+ }
+
+ bool isNull;
+ QString name;
+ int supportedBits;
+ int bits;
+ QString keyExchangeMethod;
+ QString authenticationMethod;
+ QString encryptionMethod;
+ bool exportable;
+ QString protocolString;
+ QSsl::SslProtocol protocol;
+};
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp
new file mode 100644
index 0000000000..70d7dd8df1
--- /dev/null
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -0,0 +1,542 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsslconfiguration.h"
+#include "qsslconfiguration_p.h"
+#include "qsslsocket.h"
+#include "qmutex.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSslConfiguration
+ \brief The QSslConfiguration class holds the configuration and state of an SSL connection
+ \since 4.4
+
+ \reentrant
+ \inmodule QtNetwork
+ \ingroup network
+ \ingroup ssl
+
+ QSslConfiguration is used by Qt networking classes to relay
+ information about an open SSL connection and to allow the
+ application to control certain features of that connection.
+
+ The settings that QSslConfiguration currently supports are:
+
+ \list
+ \o The SSL/TLS protocol to be used
+ \o The certificate to be presented to the peer during connection
+ and its associated private key
+ \o The ciphers allowed to be used for encrypting the connection
+ \o The list of Certificate Authorities certificates that are
+ used to validate the peer's certificate
+ \endlist
+
+ These settings are applied only during the connection
+ handshake. Setting them after the connection has been established
+ has no effect.
+
+ The state that QSslConfiguration supports are:
+ \list
+ \o The certificate the peer presented during handshake, along
+ with the chain leading to a CA certificate
+ \o The cipher used to encrypt this session
+ \endlist
+
+ The state can only be obtained once the SSL connection starts, but
+ not necessarily before it's done. Some settings may change during
+ the course of the SSL connection without need to restart it (for
+ instance, the cipher can be changed over time).
+
+ State in QSslConfiguration objects cannot be changed.
+
+ QSslConfiguration can be used with QSslSocket and the Network
+ Access API.
+
+ Note that changing settings in QSslConfiguration is not enough to
+ change the settings in the related SSL connection. You must call
+ setSslConfiguration on a modified QSslConfiguration object to
+ achieve that. The following example illustrates how to change the
+ protocol to TLSv1 in a QSslSocket object:
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslconfiguration.cpp 0
+
+ \sa QSsl::SslProtocol, QSslCertificate, QSslCipher, QSslKey
+ QSslSocket, QNetworkAccessManager,
+ QSslSocket::sslConfiguration(), QSslSocket::setSslConfiguration()
+*/
+
+/*!
+ Constructs an empty SSL configuration. This configuration contains
+ no valid settings and the state will be empty. isNull() will
+ return true after this constructor is called.
+
+ Once any setter methods are called, isNull() will return false.
+*/
+QSslConfiguration::QSslConfiguration()
+ : d(new QSslConfigurationPrivate)
+{
+}
+
+/*!
+ Copies the configuration and state of \a other. If \a other is
+ null, this object will be null too.
+*/
+QSslConfiguration::QSslConfiguration(const QSslConfiguration &other)
+ : d(other.d)
+{
+}
+
+/*!
+ Releases any resources held by QSslConfiguration.
+*/
+QSslConfiguration::~QSslConfiguration()
+{
+ // QSharedDataPointer deletes d for us if necessary
+}
+
+/*!
+ Copies the configuration and state of \a other. If \a other is
+ null, this object will be null too.
+*/
+QSslConfiguration &QSslConfiguration::operator=(const QSslConfiguration &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if this QSslConfiguration object is equal to \a
+ other.
+
+ Two QSslConfiguration objects are considered equal if they have
+ the exact same settings and state.
+
+ \sa operator!=()
+*/
+bool QSslConfiguration::operator==(const QSslConfiguration &other) const
+{
+ if (d == other.d)
+ return true;
+ return d->peerCertificate == other.d->peerCertificate &&
+ d->peerCertificateChain == other.d->peerCertificateChain &&
+ d->localCertificate == other.d->localCertificate &&
+ d->privateKey == other.d->privateKey &&
+ d->sessionCipher == other.d->sessionCipher &&
+ d->ciphers == other.d->ciphers &&
+ d->caCertificates == other.d->caCertificates &&
+ d->protocol == other.d->protocol &&
+ d->peerVerifyMode == other.d->peerVerifyMode &&
+ d->peerVerifyDepth == other.d->peerVerifyDepth;
+}
+
+/*!
+ \fn QSslConfiguration::operator!=(const QSslConfiguration &other) const
+
+ Returns true if this QSslConfiguration differs from \a other. Two
+ QSslConfiguration objects are considered different if any state or
+ setting is different.
+
+ \sa operator==()
+*/
+
+/*!
+ Returns true if this is a null QSslConfiguration object.
+
+ A QSslConfiguration object is null if it has been
+ default-constructed and no setter methods have been called.
+
+ \sa setProtocol(), setLocalCertificate(), setPrivateKey(),
+ setCiphers(), setCaCertificates()
+*/
+bool QSslConfiguration::isNull() const
+{
+ return (d->protocol == QSsl::SecureProtocols &&
+ d->peerVerifyMode == QSslSocket::AutoVerifyPeer &&
+ d->peerVerifyDepth == 0 &&
+ d->caCertificates.count() == 0 &&
+ d->ciphers.count() == 0 &&
+ d->localCertificate.isNull() &&
+ d->privateKey.isNull() &&
+ d->peerCertificate.isNull() &&
+ d->peerCertificateChain.count() == 0);
+}
+
+/*!
+ Returns the protocol setting for this SSL configuration.
+
+ \sa setProtocol()
+*/
+QSsl::SslProtocol QSslConfiguration::protocol() const
+{
+ return d->protocol;
+}
+
+/*!
+ Sets the protocol setting for this configuration to be \a
+ protocol.
+
+ Setting the protocol once the connection has already been
+ established has no effect.
+
+ \sa protocol()
+*/
+void QSslConfiguration::setProtocol(QSsl::SslProtocol protocol)
+{
+ d->protocol = protocol;
+}
+
+/*!
+ Returns the verify mode. This mode decides whether QSslSocket should
+ request a certificate from the peer (i.e., the client requests a
+ certificate from the server, or a server requesting a certificate from the
+ client), and whether it should require that this certificate is valid.
+
+ The default mode is AutoVerifyPeer, which tells QSslSocket to use
+ VerifyPeer for clients, QueryPeer for clients.
+
+ \sa setPeerVerifyMode()
+*/
+QSslSocket::PeerVerifyMode QSslConfiguration::peerVerifyMode() const
+{
+ return d->peerVerifyMode;
+}
+
+/*!
+ Sets the verify mode to \a mode. This mode decides whether QSslSocket
+ should request a certificate from the peer (i.e., the client requests a
+ certificate from the server, or a server requesting a certificate from the
+ client), and whether it should require that this certificate is valid.
+
+ The default mode is AutoVerifyPeer, which tells QSslSocket to use
+ VerifyPeer for clients, QueryPeer for clients.
+
+ \sa peerVerifyMode()
+*/
+void QSslConfiguration::setPeerVerifyMode(QSslSocket::PeerVerifyMode mode)
+{
+ d->peerVerifyMode = mode;
+}
+
+
+/*!
+ Returns the maximum number of certificates in the peer's certificate chain
+ to be checked during the SSL handshake phase, or 0 (the default) if no
+ maximum depth has been set, indicating that the whole certificate chain
+ should be checked.
+
+ The certificates are checked in issuing order, starting with the peer's
+ own certificate, then its issuer's certificate, and so on.
+
+ \sa setPeerVerifyDepth(), peerVerifyMode()
+*/
+int QSslConfiguration::peerVerifyDepth() const
+{
+ return d->peerVerifyDepth;
+}
+
+/*!
+ Sets the maximum number of certificates in the peer's certificate chain to
+ be checked during the SSL handshake phase, to \a depth. Setting a depth of
+ 0 means that no maximum depth is set, indicating that the whole
+ certificate chain should be checked.
+
+ The certificates are checked in issuing order, starting with the peer's
+ own certificate, then its issuer's certificate, and so on.
+
+ \sa peerVerifyDepth(), setPeerVerifyMode()
+*/
+void QSslConfiguration::setPeerVerifyDepth(int depth)
+{
+ if (depth < 0) {
+ qWarning("QSslConfiguration::setPeerVerifyDepth: cannot set negative depth of %d", depth);
+ return;
+ }
+ d->peerVerifyDepth = depth;
+}
+
+/*!
+ Returns the certificate to be presented to the peer during the SSL
+ handshake process.
+
+ \sa setLocalCertificate()
+*/
+QSslCertificate QSslConfiguration::localCertificate() const
+{
+ return d->localCertificate;
+}
+
+/*!
+ Sets the certificate to be presented to the peer during SSL
+ handshake to be \a certificate.
+
+ Setting the certificate once the connection has been established
+ has no effect.
+
+ A certificate is the means of identification used in the SSL
+ process. The local certificate is used by the remote end to verify
+ the local user's identity against its list of Certification
+ Authorities. In most cases, such as in HTTP web browsing, only
+ servers identify to the clients, so the client does not send a
+ certificate.
+
+ \sa localCertificate()
+*/
+void QSslConfiguration::setLocalCertificate(const QSslCertificate &certificate)
+{
+ d->localCertificate = certificate;
+}
+
+/*!
+ Returns the peer's digital certificate (i.e., the immediate
+ certificate of the host you are connected to), or a null
+ certificate, if the peer has not assigned a certificate.
+
+ The peer certificate is checked automatically during the
+ handshake phase, so this function is normally used to fetch
+ the certificate for display or for connection diagnostic
+ purposes. It contains information about the peer, including
+ its host name, the certificate issuer, and the peer's public
+ key.
+
+ Because the peer certificate is set during the handshake phase, it
+ is safe to access the peer certificate from a slot connected to
+ the QSslSocket::sslErrors() signal, QNetworkReply::sslErrors()
+ signal, or the QSslSocket::encrypted() signal.
+
+ If a null certificate is returned, it can mean the SSL handshake
+ failed, or it can mean the host you are connected to doesn't have
+ a certificate, or it can mean there is no connection.
+
+ If you want to check the peer's complete chain of certificates,
+ use peerCertificateChain() to get them all at once.
+
+ \sa peerCertificateChain(),
+ QSslSocket::sslErrors(), QSslSocket::ignoreSslErrors(),
+ QNetworkReply::sslErrors(), QNetworkReply::ignoreSslErrors()
+*/
+QSslCertificate QSslConfiguration::peerCertificate() const
+{
+ return d->peerCertificate;
+}
+
+/*!
+ Returns the peer's chain of digital certificates, starting with
+ the peer's immediate certificate and ending with the CA's
+ certificate.
+
+ Peer certificates are checked automatically during the handshake
+ phase. This function is normally used to fetch certificates for
+ display, or for performing connection diagnostics. Certificates
+ contain information about the peer and the certificate issuers,
+ including host name, issuer names, and issuer public keys.
+
+ Because the peer certificate is set during the handshake phase, it
+ is safe to access the peer certificate from a slot connected to
+ the QSslSocket::sslErrors() signal, QNetworkReply::sslErrors()
+ signal, or the QSslSocket::encrypted() signal.
+
+ If an empty list is returned, it can mean the SSL handshake
+ failed, or it can mean the host you are connected to doesn't have
+ a certificate, or it can mean there is no connection.
+
+ If you want to get only the peer's immediate certificate, use
+ peerCertificate().
+
+ \sa peerCertificate(),
+ QSslSocket::sslErrors(), QSslSocket::ignoreSslErrors(),
+ QNetworkReply::sslErrors(), QNetworkReply::ignoreSslErrors()
+*/
+QList<QSslCertificate> QSslConfiguration::peerCertificateChain() const
+{
+ return d->peerCertificateChain;
+}
+
+/*!
+ Returns the socket's cryptographic \l {QSslCipher} {cipher}, or a
+ null cipher if the connection isn't encrypted. The socket's cipher
+ for the session is set during the handshake phase. The cipher is
+ used to encrypt and decrypt data transmitted through the socket.
+
+ The SSL infrastructure also provides functions for setting the
+ ordered list of ciphers from which the handshake phase will
+ eventually select the session cipher. This ordered list must be in
+ place before the handshake phase begins.
+
+ \sa ciphers(), setCiphers(), QSslSocket::supportedCiphers()
+*/
+QSslCipher QSslConfiguration::sessionCipher() const
+{
+ return d->sessionCipher;
+}
+
+/*!
+ Returns the \l {QSslKey} {SSL key} assigned to this connection or
+ a null key if none has been assigned yet.
+
+ \sa setPrivateKey(), localCertificate()
+*/
+QSslKey QSslConfiguration::privateKey() const
+{
+ return d->privateKey;
+}
+
+/*!
+ Sets the connection's private \l {QSslKey} {key} to \a key. The
+ private key and the local \l {QSslCertificate} {certificate} are
+ used by clients and servers that must prove their identity to
+ SSL peers.
+
+ Both the key and the local certificate are required if you are
+ creating an SSL server socket. If you are creating an SSL client
+ socket, the key and local certificate are required if your client
+ must identify itself to an SSL server.
+
+ \sa privateKey(), setLocalCertificate()
+*/
+void QSslConfiguration::setPrivateKey(const QSslKey &key)
+{
+ d->privateKey = key;
+}
+
+/*!
+ Returns this connection's current cryptographic cipher suite. This
+ list is used during the handshake phase for choosing a
+ session cipher. The returned list of ciphers is ordered by
+ descending preference. (i.e., the first cipher in the list is the
+ most preferred cipher). The session cipher will be the first one
+ in the list that is also supported by the peer.
+
+ By default, the handshake phase can choose any of the ciphers
+ supported by this system's SSL libraries, which may vary from
+ system to system. The list of ciphers supported by this system's
+ SSL libraries is returned by QSslSocket::supportedCiphers(). You can restrict
+ the list of ciphers used for choosing the session cipher for this
+ socket by calling setCiphers() with a subset of the supported
+ ciphers. You can revert to using the entire set by calling
+ setCiphers() with the list returned by QSslSocket::supportedCiphers().
+
+ \sa setCiphers(), QSslSocket::supportedCiphers()
+*/
+QList<QSslCipher> QSslConfiguration::ciphers() const
+{
+ return d->ciphers;
+}
+
+/*!
+ Sets the cryptographic cipher suite for this socket to \a ciphers,
+ which must contain a subset of the ciphers in the list returned by
+ supportedCiphers().
+
+ Restricting the cipher suite must be done before the handshake
+ phase, where the session cipher is chosen.
+
+ \sa ciphers(), QSslSocket::supportedCiphers()
+*/
+void QSslConfiguration::setCiphers(const QList<QSslCipher> &ciphers)
+{
+ d->ciphers = ciphers;
+}
+
+/*!
+ Returns this connection's CA certificate database. The CA certificate
+ database is used by the socket during the handshake phase to
+ validate the peer's certificate. It can be modified prior to the
+ handshake with setCaCertificates(), or with \l{QSslSocket}'s
+ \l{QSslSocket::}{addCaCertificate()} and
+ \l{QSslSocket::}{addCaCertificates()}.
+
+ \sa setCaCertificates()
+*/
+QList<QSslCertificate> QSslConfiguration::caCertificates() const
+{
+ return d->caCertificates;
+}
+
+/*!
+ Sets this socket's CA certificate database to be \a certificates.
+ The certificate database must be set prior to the SSL handshake.
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ \sa caCertificates()
+*/
+void QSslConfiguration::setCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ d->caCertificates = certificates;
+}
+
+/*!
+ Returns the default SSL configuration to be used in new SSL
+ connections.
+
+ The default SSL configuration consists of:
+
+ \list
+ \o no local certificate and no private key
+ \o protocol SecureProtocols (meaning either TLS 1.0 or SSL 3 will be used)
+ \o the system's default CA certificate list
+ \o the cipher list equal to the list of the SSL libraries'
+ supported SSL ciphers
+ \endlist
+
+ \sa QSslSocket::supportedCiphers(), setDefaultConfiguration()
+*/
+QSslConfiguration QSslConfiguration::defaultConfiguration()
+{
+ return QSslConfigurationPrivate::defaultConfiguration();
+}
+
+/*!
+ Sets the default SSL configuration to be used in new SSL
+ connections to be \a configuration. Existing connections are not
+ affected by this call.
+
+ \sa QSslSocket::supportedCiphers(), defaultConfiguration()
+*/
+void QSslConfiguration::setDefaultConfiguration(const QSslConfiguration &configuration)
+{
+ QSslConfigurationPrivate::setDefaultConfiguration(configuration);
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslconfiguration.h b/src/network/ssl/qsslconfiguration.h
new file mode 100644
index 0000000000..143566bef1
--- /dev/null
+++ b/src/network/ssl/qsslconfiguration.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** In addition, as a special exception, Nokia gives permission to link
+** the code of its release of Qt with the OpenSSL project's "OpenSSL" library
+** (or modified versions of the "OpenSSL" library that use the same license
+** as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#ifndef QSSLCONFIGURATION_H
+#define QSSLCONFIGURATION_H
+
+#include <QtCore/qshareddata.h>
+#include <QtNetwork/qsslsocket.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_OPENSSL
+
+template<typename T> class QList;
+class QSslCertificate;
+class QSslCipher;
+class QSslKey;
+
+class QSslConfigurationPrivate;
+class Q_NETWORK_EXPORT QSslConfiguration
+{
+public:
+ QSslConfiguration();
+ QSslConfiguration(const QSslConfiguration &other);
+ ~QSslConfiguration();
+ QSslConfiguration &operator=(const QSslConfiguration &other);
+
+ bool operator==(const QSslConfiguration &other) const;
+ inline bool operator!=(const QSslConfiguration &other) const
+ { return !(*this == other); }
+
+ bool isNull() const; // ### Qt 5: remove; who would need this?
+
+ QSsl::SslProtocol protocol() const;
+ void setProtocol(QSsl::SslProtocol protocol);
+
+ // Verification
+ QSslSocket::PeerVerifyMode peerVerifyMode() const;
+ void setPeerVerifyMode(QSslSocket::PeerVerifyMode mode);
+
+ int peerVerifyDepth() const;
+ void setPeerVerifyDepth(int depth);
+
+ // Certificate & cipher configuration
+ QSslCertificate localCertificate() const;
+ void setLocalCertificate(const QSslCertificate &certificate);
+
+ QSslCertificate peerCertificate() const;
+ QList<QSslCertificate> peerCertificateChain() const;
+ QSslCipher sessionCipher() const;
+
+ // Private keys, for server sockets
+ QSslKey privateKey() const;
+ void setPrivateKey(const QSslKey &key);
+
+ // Cipher settings
+ QList<QSslCipher> ciphers() const;
+ void setCiphers(const QList<QSslCipher> &ciphers);
+
+ // Certificate Authority (CA) settings
+ QList<QSslCertificate> caCertificates() const;
+ void setCaCertificates(const QList<QSslCertificate> &certificates);
+
+ static QSslConfiguration defaultConfiguration();
+ static void setDefaultConfiguration(const QSslConfiguration &configuration);
+
+private:
+ friend class QSslSocket;
+ friend class QSslConfigurationPrivate;
+ QSslConfiguration(QSslConfigurationPrivate *dd);
+ QSharedDataPointer<QSslConfigurationPrivate> d;
+};
+
+#endif // QT_NO_OPENSSL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/network/ssl/qsslconfiguration_p.h b/src/network/ssl/qsslconfiguration_p.h
new file mode 100644
index 0000000000..a5af51a8db
--- /dev/null
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** In addition, as a special exception, Nokia gives permission to link
+** the code of its release of Qt with the OpenSSL project's "OpenSSL" library
+** (or modified versions of the "OpenSSL" library that use the same license
+** as the original version), and distribute the linked executables.
+**
+** You must comply with the GNU General Public License version 2 in all
+** respects for all of the code used other than the "OpenSSL" code. If you
+** modify this file, you may extend this exception to your version of the file,
+** but you are not obligated to do so. If you do not wish to do so, delete
+** this exception statement from your version of this file.
+**
+****************************************************************************/
+
+#ifndef QSSLCONFIGURATION_P_H
+#define QSSLCONFIGURATION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QSslSocket API. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsslconfiguration.h"
+#include "qlist.h"
+#include "qsslcertificate.h"
+#include "qsslcipher.h"
+#include "qsslkey.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSslConfigurationPrivate: public QSharedData
+{
+public:
+ QSslConfigurationPrivate()
+ : protocol(QSsl::SecureProtocols),
+ peerVerifyMode(QSslSocket::AutoVerifyPeer),
+ peerVerifyDepth(0)
+ { }
+
+ QSslCertificate peerCertificate;
+ QList<QSslCertificate> peerCertificateChain;
+ QSslCertificate localCertificate;
+
+ QSslKey privateKey;
+ QSslCipher sessionCipher;
+ QList<QSslCipher> ciphers;
+ QList<QSslCertificate> caCertificates;
+
+ QSsl::SslProtocol protocol;
+ QSslSocket::PeerVerifyMode peerVerifyMode;
+ int peerVerifyDepth;
+
+ // in qsslsocket.cpp:
+ static QSslConfiguration defaultConfiguration();
+ static void setDefaultConfiguration(const QSslConfiguration &configuration);
+ static void deepCopyDefaultConfiguration(QSslConfigurationPrivate *config);
+};
+
+// implemented here for inlining purposes
+inline QSslConfiguration::QSslConfiguration(QSslConfigurationPrivate *dd)
+ : d(dd)
+{
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/ssl/qsslerror.cpp b/src/network/ssl/qsslerror.cpp
new file mode 100644
index 0000000000..ae18b47170
--- /dev/null
+++ b/src/network/ssl/qsslerror.cpp
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QSslError
+ \brief The QSslError class provides an SSL error.
+ \since 4.3
+
+ \reentrant
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ QSslError provides a simple API for managing errors during QSslSocket's
+ SSL handshake.
+
+ \sa QSslSocket, QSslCertificate, QSslCipher
+*/
+
+/*!
+ \enum QSslError::SslError
+
+ Describes all recognized errors that can occur during an SSL handshake.
+
+ \value NoError
+ \value UnableToGetIssuerCertificate
+ \value UnableToDecryptCertificateSignature
+ \value UnableToDecodeIssuerPublicKey
+ \value CertificateSignatureFailed
+ \value CertificateNotYetValid
+ \value CertificateExpired
+ \value InvalidNotBeforeField
+ \value InvalidNotAfterField
+ \value SelfSignedCertificate
+ \value SelfSignedCertificateInChain
+ \value UnableToGetLocalIssuerCertificate
+ \value UnableToVerifyFirstCertificate
+ \value CertificateRevoked
+ \value InvalidCaCertificate
+ \value PathLengthExceeded
+ \value InvalidPurpose
+ \value CertificateUntrusted
+ \value CertificateRejected
+ \value SubjectIssuerMismatch
+ \value AuthorityIssuerSerialNumberMismatch
+ \value NoPeerCertificate
+ \value HostNameMismatch
+ \value UnspecifiedError
+ \value NoSslSupport
+ \value CertificateBlacklisted
+
+ \sa QSslError::errorString()
+*/
+
+#include "qsslerror.h"
+#include "qsslsocket.h"
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+#endif
+
+class QSslErrorPrivate
+{
+public:
+ QSslError::SslError error;
+ QSslCertificate certificate;
+};
+
+/*!
+ Constructs a QSslError object with no error and default certificate.
+
+*/
+
+// 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();
+}
+
+/*!
+ Constructs a QSslError object. The argument specifies the \a
+ error that occurred.
+
+*/
+QSslError::QSslError(SslError error)
+ : d(new QSslErrorPrivate)
+{
+ d->error = error;
+ d->certificate = QSslCertificate();
+}
+
+/*!
+ Constructs a QSslError object. The two arguments specify the \a
+ error that occurred, and which \a certificate the error relates to.
+
+ \sa QSslCertificate
+*/
+QSslError::QSslError(SslError error, const QSslCertificate &certificate)
+ : d(new QSslErrorPrivate)
+{
+ d->error = error;
+ d->certificate = certificate;
+}
+
+/*!
+ Constructs an identical copy of \a other.
+*/
+QSslError::QSslError(const QSslError &other)
+ : d(new QSslErrorPrivate)
+{
+ *d.data() = *other.d.data();
+}
+
+/*!
+ Destroys the QSslError object.
+*/
+QSslError::~QSslError()
+{
+}
+
+/*!
+ \since 4.4
+
+ Assigns the contents of \a other to this error.
+*/
+QSslError &QSslError::operator=(const QSslError &other)
+{
+ *d.data() = *other.d.data();
+ return *this;
+}
+
+/*!
+ \since 4.4
+
+ Returns true if this error is equal to \a other; otherwise returns false.
+*/
+bool QSslError::operator==(const QSslError &other) const
+{
+ return d->error == other.d->error
+ && d->certificate == other.d->certificate;
+}
+
+/*!
+ \fn bool QSslError::operator!=(const QSslError &other) const
+ \since 4.4
+
+ Returns true if this error is not equal to \a other; otherwise returns
+ false.
+*/
+
+/*!
+ Returns the type of the error.
+
+ \sa errorString(), certificate()
+*/
+QSslError::SslError QSslError::error() const
+{
+ return d->error;
+}
+
+/*!
+ Returns a short localized human-readable description of the error.
+
+ \sa error(), certificate()
+*/
+QString QSslError::errorString() const
+{
+ QString errStr;
+ switch (d->error) {
+ case NoError:
+ errStr = QSslSocket::tr("No error");
+ break;
+ case UnableToGetIssuerCertificate:
+ errStr = QSslSocket::tr("The issuer certificate could not be found");
+ break;
+ case UnableToDecryptCertificateSignature:
+ errStr = QSslSocket::tr("The certificate signature could not be decrypted");
+ break;
+ case UnableToDecodeIssuerPublicKey:
+ errStr = QSslSocket::tr("The public key in the certificate could not be read");
+ break;
+ case CertificateSignatureFailed:
+ errStr = QSslSocket::tr("The signature of the certificate is invalid");
+ break;
+ case CertificateNotYetValid:
+ errStr = QSslSocket::tr("The certificate is not yet valid");
+ break;
+ case CertificateExpired:
+ errStr = QSslSocket::tr("The certificate has expired");
+ break;
+ case InvalidNotBeforeField:
+ errStr = QSslSocket::tr("The certificate's notBefore field contains an invalid time");
+ break;
+ case InvalidNotAfterField:
+ errStr = QSslSocket::tr("The certificate's notAfter field contains an invalid time");
+ break;
+ case SelfSignedCertificate:
+ errStr = QSslSocket::tr("The certificate is self-signed, and untrusted");
+ break;
+ case SelfSignedCertificateInChain:
+ errStr = QSslSocket::tr("The root certificate of the certificate chain is self-signed, and untrusted");
+ break;
+ case UnableToGetLocalIssuerCertificate:
+ errStr = QSslSocket::tr("The issuer certificate of a locally looked up certificate could not be found");
+ break;
+ case UnableToVerifyFirstCertificate:
+ errStr = QSslSocket::tr("No certificates could be verified");
+ break;
+ case InvalidCaCertificate:
+ errStr = QSslSocket::tr("One of the CA certificates is invalid");
+ break;
+ case PathLengthExceeded:
+ errStr = QSslSocket::tr("The basicConstraints path length parameter has been exceeded");
+ break;
+ case InvalidPurpose:
+ errStr = QSslSocket::tr("The supplied certificate is unsuitable for this purpose");
+ break;
+ case CertificateUntrusted:
+ errStr = QSslSocket::tr("The root CA certificate is not trusted for this purpose");
+ break;
+ case CertificateRejected:
+ errStr = QSslSocket::tr("The root CA certificate is marked to reject the specified purpose");
+ break;
+ case SubjectIssuerMismatch: // hostname mismatch
+ errStr = QSslSocket::tr("The current candidate issuer certificate was rejected because its"
+ " subject name did not match the issuer name of the current certificate");
+ break;
+ case AuthorityIssuerSerialNumberMismatch:
+ errStr = QSslSocket::tr("The current candidate issuer certificate was rejected because"
+ " its issuer name and serial number was present and did not match the"
+ " authority key identifier of the current certificate");
+ break;
+ case NoPeerCertificate:
+ errStr = QSslSocket::tr("The peer did not present any certificate");
+ break;
+ case HostNameMismatch:
+ errStr = QSslSocket::tr("The host name did not match any of the valid hosts"
+ " for this certificate");
+ break;
+ case NoSslSupport:
+ break;
+ case CertificateBlacklisted:
+ errStr = QSslSocket::tr("The peer certificate is blacklisted");
+ break;
+ default:
+ errStr = QSslSocket::tr("Unknown error");
+ break;
+ }
+
+ return errStr;
+}
+
+/*!
+ Returns the certificate associated with this error, or a null certificate
+ if the error does not relate to any certificate.
+
+ \sa error(), errorString()
+*/
+QSslCertificate QSslError::certificate() const
+{
+ return d->certificate;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+//class QDebug;
+QDebug operator<<(QDebug debug, const QSslError &error)
+{
+ debug << error.errorString();
+ return debug;
+}
+QDebug operator<<(QDebug debug, const QSslError::SslError &error)
+{
+ debug << QSslError(error).errorString();
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslerror.h b/src/network/ssl/qsslerror.h
new file mode 100644
index 0000000000..c30c02a8af
--- /dev/null
+++ b/src/network/ssl/qsslerror.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLERROR_H
+#define QSSLERROR_H
+
+#include <QtCore/qvariant.h>
+#include <QtNetwork/qsslcertificate.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_OPENSSL
+
+class QSslErrorPrivate;
+class Q_NETWORK_EXPORT QSslError
+{
+public:
+ enum SslError {
+ NoError,
+ UnableToGetIssuerCertificate,
+ UnableToDecryptCertificateSignature,
+ UnableToDecodeIssuerPublicKey,
+ CertificateSignatureFailed,
+ CertificateNotYetValid,
+ CertificateExpired,
+ InvalidNotBeforeField,
+ InvalidNotAfterField,
+ SelfSignedCertificate,
+ SelfSignedCertificateInChain,
+ UnableToGetLocalIssuerCertificate,
+ UnableToVerifyFirstCertificate,
+ CertificateRevoked,
+ InvalidCaCertificate,
+ PathLengthExceeded,
+ InvalidPurpose,
+ CertificateUntrusted,
+ CertificateRejected,
+ SubjectIssuerMismatch, // hostname mismatch?
+ AuthorityIssuerSerialNumberMismatch,
+ NoPeerCertificate,
+ HostNameMismatch,
+ NoSslSupport,
+ CertificateBlacklisted,
+ UnspecifiedError = -1
+ };
+
+ // 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;
+ inline bool operator!=(const QSslError &other) const
+ { return !(*this == other); }
+
+ SslError error() const;
+ QString errorString() const;
+ QSslCertificate certificate() const;
+
+private:
+ QScopedPointer<QSslErrorPrivate> d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslError &error);
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslError::SslError &error);
+#endif
+
+#endif // QT_NO_OPENSSL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/network/ssl/qsslkey.cpp b/src/network/ssl/qsslkey.cpp
new file mode 100644
index 0000000000..8b32f65405
--- /dev/null
+++ b/src/network/ssl/qsslkey.cpp
@@ -0,0 +1,460 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QSslKey
+ \brief The QSslKey class provides an interface for private and public keys.
+ \since 4.3
+
+ \reentrant
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ QSslKey provides a simple API for managing keys.
+
+ \sa QSslSocket, QSslCertificate, QSslCipher
+*/
+
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qsslkey.h"
+#include "qsslkey_p.h"
+#include "qsslsocket.h"
+#include "qsslsocket_p.h"
+
+#include <QtCore/qatomic.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qiodevice.h>
+#ifndef QT_NO_DEBUG_STREAM
+#include <QtCore/qdebug.h>
+
+QT_BEGIN_NAMESPACE
+#endif
+
+
+/*!
+ \internal
+ */
+void QSslKeyPrivate::clear(bool deep)
+{
+ isNull = true;
+ if (!QSslSocket::supportsSsl())
+ return;
+ if (rsa) {
+ if (deep)
+ q_RSA_free(rsa);
+ rsa = 0;
+ }
+ if (dsa) {
+ if (deep)
+ q_DSA_free(dsa);
+ dsa = 0;
+ }
+}
+
+/*!
+ \internal
+
+ Allocates a new rsa or dsa struct and decodes \a pem into it
+ according to the current algorithm and type.
+
+ If \a deepClear is true, the rsa/dsa struct is freed if it is was
+ already allocated, otherwise we "leak" memory (which is exactly
+ what we want for copy construction).
+
+ If \a passPhrase is non-empty, it will be used for decrypting
+ \a pem.
+*/
+void QSslKeyPrivate::decodePem(const QByteArray &pem, const QByteArray &passPhrase,
+ bool deepClear)
+{
+ if (pem.isEmpty())
+ return;
+
+ clear(deepClear);
+
+ if (!QSslSocket::supportsSsl())
+ return;
+
+ BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pem.data()), pem.size());
+ if (!bio)
+ return;
+
+ void *phrase = (void *)passPhrase.constData();
+
+ if (algorithm == QSsl::Rsa) {
+ RSA *result = (type == QSsl::PublicKey)
+ ? q_PEM_read_bio_RSA_PUBKEY(bio, &rsa, 0, phrase)
+ : q_PEM_read_bio_RSAPrivateKey(bio, &rsa, 0, phrase);
+ if (rsa && rsa == result)
+ isNull = false;
+ } else {
+ DSA *result = (type == QSsl::PublicKey)
+ ? q_PEM_read_bio_DSA_PUBKEY(bio, &dsa, 0, phrase)
+ : q_PEM_read_bio_DSAPrivateKey(bio, &dsa, 0, phrase);
+ if (dsa && dsa == result)
+ isNull = false;
+ }
+
+ q_BIO_free(bio);
+}
+
+/*!
+ Constructs a null key.
+
+ \sa isNull()
+*/
+QSslKey::QSslKey()
+ : d(new QSslKeyPrivate)
+{
+}
+
+/*!
+ \internal
+*/
+QByteArray QSslKeyPrivate::pemHeader() const
+{
+ // ### use QByteArray::fromRawData() instead
+ if (type == QSsl::PublicKey)
+ return QByteArray("-----BEGIN PUBLIC KEY-----\n");
+ else if (algorithm == QSsl::Rsa)
+ return QByteArray("-----BEGIN RSA PRIVATE KEY-----\n");
+ return QByteArray("-----BEGIN DSA PRIVATE KEY-----\n");
+}
+
+/*!
+ \internal
+*/
+QByteArray QSslKeyPrivate::pemFooter() const
+{
+ // ### use QByteArray::fromRawData() instead
+ if (type == QSsl::PublicKey)
+ return QByteArray("-----END PUBLIC KEY-----\n");
+ else if (algorithm == QSsl::Rsa)
+ return QByteArray("-----END RSA PRIVATE KEY-----\n");
+ return QByteArray("-----END DSA PRIVATE KEY-----\n");
+}
+
+/*!
+ \internal
+
+ Returns a DER key formatted as PEM.
+*/
+QByteArray QSslKeyPrivate::pemFromDer(const QByteArray &der) const
+{
+ QByteArray pem(der.toBase64());
+
+ const int lineWidth = 64; // RFC 1421
+ const int newLines = pem.size() / lineWidth;
+ const bool rem = pem.size() % lineWidth;
+
+ // ### optimize
+ for (int i = 0; i < newLines; ++i)
+ pem.insert((i + 1) * lineWidth + i, '\n');
+ if (rem)
+ pem.append('\n'); // ###
+
+ pem.prepend(pemHeader());
+ pem.append(pemFooter());
+
+ return pem;
+}
+
+/*!
+ \internal
+
+ Returns a PEM key formatted as DER.
+*/
+QByteArray QSslKeyPrivate::derFromPem(const QByteArray &pem) const
+{
+ const QByteArray header = pemHeader();
+ const QByteArray footer = pemFooter();
+
+ QByteArray der(pem);
+
+ const int headerIndex = der.indexOf(header);
+ const int footerIndex = der.indexOf(footer);
+ if (headerIndex == -1 || footerIndex == -1)
+ return QByteArray();
+
+ der = der.mid(headerIndex + header.size(), footerIndex - (headerIndex + header.size()));
+
+ return QByteArray::fromBase64(der); // ignores newlines
+}
+
+/*!
+ Constructs a QSslKey by decoding the string in the byte array
+ \a encoded using a specified \a algorithm and \a encoding format.
+ If the encoded key is encrypted, \a passPhrase is used to decrypt
+ it. \a type specifies whether the key is public or private.
+
+ After construction, use isNull() to check if \a encoded contained
+ a valid key.
+*/
+QSslKey::QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
+ QSsl::EncodingFormat encoding, QSsl::KeyType type, const QByteArray &passPhrase)
+ : d(new QSslKeyPrivate)
+{
+ d->type = type;
+ d->algorithm = algorithm;
+ d->decodePem((encoding == QSsl::Der)
+ ? d->pemFromDer(encoded) : encoded,
+ passPhrase);
+}
+
+/*!
+ Constructs a QSslKey by reading and decoding data from a
+ \a device using a specified \a algorithm and \a encoding format.
+ If the encoded key is encrypted, \a passPhrase is used to decrypt
+ it. \a type specifies whether the key is public or private.
+
+ After construction, use isNull() to check if \a device provided
+ a valid key.
+*/
+QSslKey::QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm, QSsl::EncodingFormat encoding,
+ QSsl::KeyType type, const QByteArray &passPhrase)
+ : d(new QSslKeyPrivate)
+{
+ QByteArray encoded;
+ if (device)
+ encoded = device->readAll();
+ d->type = type;
+ d->algorithm = algorithm;
+ d->decodePem((encoding == QSsl::Der) ?
+ d->pemFromDer(encoded) : encoded,
+ passPhrase);
+}
+
+/*!
+ Constructs an identical copy of \a other.
+*/
+QSslKey::QSslKey(const QSslKey &other) : d(other.d)
+{
+}
+
+/*!
+ Destroys the QSslKey object.
+*/
+QSslKey::~QSslKey()
+{
+}
+
+/*!
+ Copies the contents of \a other into this key, making the two keys
+ identical.
+
+ Returns a reference to this QSslKey.
+*/
+QSslKey &QSslKey::operator=(const QSslKey &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if this is a null key; otherwise false.
+
+ \sa clear()
+*/
+bool QSslKey::isNull() const
+{
+ return d->isNull;
+}
+
+/*!
+ Clears the contents of this key, making it a null key.
+
+ \sa isNull()
+*/
+void QSslKey::clear()
+{
+ d = new QSslKeyPrivate;
+}
+
+/*!
+ Returns the length of the key in bits, or -1 if the key is null.
+*/
+int QSslKey::length() const
+{
+ if (d->isNull)
+ return -1;
+ return (d->algorithm == QSsl::Rsa)
+ ? q_BN_num_bits(d->rsa->n) : q_BN_num_bits(d->dsa->p);
+}
+
+/*!
+ Returns the type of the key (i.e., PublicKey or PrivateKey).
+*/
+QSsl::KeyType QSslKey::type() const
+{
+ return d->type;
+}
+
+/*!
+ Returns the key algorithm.
+*/
+QSsl::KeyAlgorithm QSslKey::algorithm() const
+{
+ return d->algorithm;
+}
+
+/*!
+ Returns the key in DER encoding. The result is encrypted with
+ \a passPhrase if the key is a private key and \a passPhrase is
+ non-empty.
+*/
+// ### autotest failure for non-empty passPhrase and private key
+QByteArray QSslKey::toDer(const QByteArray &passPhrase) const
+{
+ if (d->isNull)
+ return QByteArray();
+ return d->derFromPem(toPem(passPhrase));
+}
+
+/*!
+ Returns the key in PEM encoding. The result is encrypted with
+ \a passPhrase if the key is a private key and \a passPhrase is
+ non-empty.
+*/
+QByteArray QSslKey::toPem(const QByteArray &passPhrase) const
+{
+ if (!QSslSocket::supportsSsl() || d->isNull)
+ return QByteArray();
+
+ BIO *bio = q_BIO_new(q_BIO_s_mem());
+ if (!bio)
+ return QByteArray();
+
+ bool fail = false;
+
+ if (d->algorithm == QSsl::Rsa) {
+ if (d->type == QSsl::PublicKey) {
+ if (!q_PEM_write_bio_RSA_PUBKEY(bio, d->rsa))
+ fail = true;
+ } else {
+ if (!q_PEM_write_bio_RSAPrivateKey(
+ bio, d->rsa,
+ // ### the cipher should be selectable in the API:
+ passPhrase.isEmpty() ? (const EVP_CIPHER *)0 : q_EVP_des_ede3_cbc(),
+ (uchar *)passPhrase.data(), passPhrase.size(), 0, 0)) {
+ fail = true;
+ }
+ }
+ } else {
+ if (d->type == QSsl::PublicKey) {
+ if (!q_PEM_write_bio_DSA_PUBKEY(bio, d->dsa))
+ fail = true;
+ } else {
+ if (!q_PEM_write_bio_DSAPrivateKey(
+ bio, d->dsa,
+ // ### the cipher should be selectable in the API:
+ passPhrase.isEmpty() ? (const EVP_CIPHER *)0 : q_EVP_des_ede3_cbc(),
+ (uchar *)passPhrase.data(), passPhrase.size(), 0, 0)) {
+ fail = true;
+ }
+ }
+ }
+
+ QByteArray pem;
+ if (!fail) {
+ char *data;
+ long size = q_BIO_get_mem_data(bio, &data);
+ pem = QByteArray(data, size);
+ }
+ q_BIO_free(bio);
+ return pem;
+}
+
+/*!
+ Returns a pointer to the native key handle, if it is available;
+ otherwise a null pointer is returned.
+
+ You can use this handle together with the native API to access
+ extended information about the key.
+
+ \warning Use of this function has a high probability of being
+ non-portable, and its return value may vary across platforms, and
+ between minor Qt releases.
+*/
+Qt::HANDLE QSslKey::handle() const
+{
+ return (d->algorithm == QSsl::Rsa) ? Qt::HANDLE(d->rsa) : Qt::HANDLE(d->dsa);
+}
+
+/*!
+ Returns true if this key is equal to \a other; otherwise returns false.
+*/
+bool QSslKey::operator==(const QSslKey &other) const
+{
+ if (isNull())
+ return other.isNull();
+ if (other.isNull())
+ return isNull();
+ if (algorithm() != other.algorithm())
+ return false;
+ if (type() != other.type())
+ return false;
+ if (length() != other.length())
+ return false;
+ return toDer() == other.toDer();
+}
+
+/*! \fn bool QSslKey::operator!=(const QSslKey &other) const
+
+ Returns true if this key is not equal to key \a other; otherwise
+ returns false.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+QDebug operator<<(QDebug debug, const QSslKey &key)
+{
+ debug << "QSslKey("
+ << (key.type() == QSsl::PublicKey ? "PublicKey" : "PrivateKey")
+ << ", " << (key.algorithm() == QSsl::Rsa ? "RSA" : "DSA")
+ << ", " << key.length()
+ << ')';
+ return debug;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslkey.h b/src/network/ssl/qsslkey.h
new file mode 100644
index 0000000000..89973042f9
--- /dev/null
+++ b/src/network/ssl/qsslkey.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLKEY_H
+#define QSSLKEY_H
+
+#include <QtCore/qnamespace.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qsharedpointer.h>
+#include <QtNetwork/qssl.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_OPENSSL
+
+template <typename A, typename B> struct QPair;
+
+class QIODevice;
+
+class QSslKeyPrivate;
+class Q_NETWORK_EXPORT QSslKey
+{
+public:
+ QSslKey();
+ QSslKey(const QByteArray &encoded, QSsl::KeyAlgorithm algorithm,
+ QSsl::EncodingFormat format = QSsl::Pem,
+ QSsl::KeyType type = QSsl::PrivateKey,
+ const QByteArray &passPhrase = QByteArray());
+ QSslKey(QIODevice *device, QSsl::KeyAlgorithm algorithm,
+ QSsl::EncodingFormat format = QSsl::Pem,
+ QSsl::KeyType type = QSsl::PrivateKey,
+ const QByteArray &passPhrase = QByteArray());
+ QSslKey(const QSslKey &other);
+ ~QSslKey();
+ QSslKey &operator=(const QSslKey &other);
+
+ bool isNull() const;
+ void clear();
+
+ int length() const;
+ QSsl::KeyType type() const;
+ QSsl::KeyAlgorithm algorithm() const;
+
+ QByteArray toPem(const QByteArray &passPhrase = QByteArray()) const;
+ QByteArray toDer(const QByteArray &passPhrase = QByteArray()) const;
+
+ Qt::HANDLE handle() const;
+
+ bool operator==(const QSslKey &key) const;
+ inline bool operator!=(const QSslKey &key) const { return !operator==(key); }
+
+private:
+ QExplicitlySharedDataPointer<QSslKeyPrivate> d;
+ friend class QSslCertificate;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+Q_NETWORK_EXPORT QDebug operator<<(QDebug debug, const QSslKey &key);
+#endif
+
+#endif // QT_NO_OPENSSL
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/network/ssl/qsslkey_p.h b/src/network/ssl/qsslkey_p.h
new file mode 100644
index 0000000000..e476ecea8c
--- /dev/null
+++ b/src/network/ssl/qsslkey_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLKEY_P_H
+#define QSSLKEY_P_H
+
+#include "qsslkey.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qsslcertificate.cpp. This header file may change from version to version
+// without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <openssl/rsa.h>
+#include <openssl/dsa.h>
+
+QT_BEGIN_NAMESPACE
+
+class QSslKeyPrivate
+{
+public:
+ inline QSslKeyPrivate()
+ : rsa(0)
+ , dsa(0)
+ {
+ clear();
+ }
+
+ inline ~QSslKeyPrivate()
+ { clear(); }
+
+ void clear(bool deep = true);
+
+ void decodePem(const QByteArray &pem, const QByteArray &passPhrase,
+ bool deepClear = true);
+ QByteArray pemHeader() const;
+ QByteArray pemFooter() const;
+ QByteArray pemFromDer(const QByteArray &der) const;
+ QByteArray derFromPem(const QByteArray &pem) const;
+
+ bool isNull;
+ QSsl::KeyType type;
+ QSsl::KeyAlgorithm algorithm;
+ RSA *rsa;
+ DSA *dsa;
+
+ QAtomicInt ref;
+
+private:
+ Q_DISABLE_COPY(QSslKeyPrivate)
+};
+
+QT_END_NAMESPACE
+
+#endif // QSSLKEY_P_H
diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp
new file mode 100644
index 0000000000..0dbf4b5196
--- /dev/null
+++ b/src/network/ssl/qsslsocket.cpp
@@ -0,0 +1,2260 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+//#define QSSLSOCKET_DEBUG
+
+/*!
+ \class QSslSocket
+ \brief The QSslSocket class provides an SSL encrypted socket for both
+ clients and servers.
+ \since 4.3
+
+ \reentrant
+ \ingroup network
+ \ingroup ssl
+ \inmodule QtNetwork
+
+ QSslSocket establishes a secure, encrypted TCP connection you can
+ use for transmitting encrypted data. It can operate in both client
+ and server mode, and it supports modern SSL protocols, including
+ SSLv3 and TLSv1. By default, QSslSocket uses TLSv1, but you can
+ change the SSL protocol by calling setProtocol() as long as you do
+ it before the handshake has started.
+
+ SSL encryption operates on top of the existing TCP stream after
+ the socket enters the ConnectedState. There are two simple ways to
+ establish a secure connection using QSslSocket: With an immediate
+ SSL handshake, or with a delayed SSL handshake occurring after the
+ connection has been established in unencrypted mode.
+
+ The most common way to use QSslSocket is to construct an object
+ and start a secure connection by calling connectToHostEncrypted().
+ This method starts an immediate SSL handshake once the connection
+ has been established.
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 0
+
+ As with a plain QTcpSocket, QSslSocket enters the HostLookupState,
+ ConnectingState, and finally the ConnectedState, if the connection
+ is successful. The handshake then starts automatically, and if it
+ succeeds, the encrypted() signal is emitted to indicate the socket
+ has entered the encrypted state and is ready for use.
+
+ Note that data can be written to the socket immediately after the
+ return from connectToHostEncrypted() (i.e., before the encrypted()
+ signal is emitted). The data is queued in QSslSocket until after
+ the encrypted() signal is emitted.
+
+ An example of using the delayed SSL handshake to secure an
+ existing connection is the case where an SSL server secures an
+ incoming connection. Suppose you create an SSL server class as a
+ subclass of QTcpServer. You would override
+ QTcpServer::incomingConnection() with something like the example
+ below, which first constructs an instance of QSslSocket and then
+ calls setSocketDescriptor() to set the new socket's descriptor to
+ the existing one passed in. It then initiates the SSL handshake
+ by calling startServerEncryption().
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 1
+
+ If an error occurs, QSslSocket emits the sslErrors() signal. In this
+ case, if no action is taken to ignore the error(s), the connection
+ is dropped. To continue, despite the occurrence of an error, you
+ can call ignoreSslErrors(), either from within this slot after the
+ error occurs, or any time after construction of the QSslSocket and
+ before the connection is attempted. This will allow QSslSocket to
+ ignore the errors it encounters when establishing the identity of
+ the peer. Ignoring errors during an SSL handshake should be used
+ with caution, since a fundamental characteristic of secure
+ connections is that they should be established with a successful
+ handshake.
+
+ Once encrypted, you use QSslSocket as a regular QTcpSocket. When
+ readyRead() is emitted, you can call read(), canReadLine() and
+ 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 encryptedBytesWritten() once
+ the data has been written to the peer.
+
+ As a convenience, QSslSocket supports QTcpSocket's blocking
+ functions waitForConnected(), waitForReadyRead(),
+ waitForBytesWritten(), and waitForDisconnected(). It also provides
+ waitForEncrypted(), which will block the calling thread until an
+ encrypted connection has been established.
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 2
+
+ QSslSocket provides an extensive, easy-to-use API for handling
+ cryptographic ciphers, private keys, and local, peer, and
+ Certification Authority (CA) certificates. It also provides an API
+ for handling errors that occur during the handshake phase.
+
+ The following features can also be customized:
+
+ \list
+ \o The socket's cryptographic cipher suite can be customized before
+ the handshake phase with setCiphers() and setDefaultCiphers().
+ \o The socket's local certificate and private key can be customized
+ before the handshake phase with setLocalCertificate() and
+ setPrivateKey().
+ \o The CA certificate database can be extended and customized with
+ addCaCertificate(), addCaCertificates(), setCaCertificates(),
+ addDefaultCaCertificate(), addDefaultCaCertificates(), and
+ setDefaultCaCertificates().
+ \endlist
+
+ \note If available, root certificates on Unix (excluding Mac OS X) will be
+ loaded on demand from the standard certificate directories. If
+ you do not want to load root certificates on demand, you need to call either
+ the static function setDefaultCaCertificates() before the first SSL handshake
+ is made in your application, (e.g. via
+ "QSslSocket::setDefaultCaCertificates(QSslSocket::systemCaCertificates());"),
+ or call setCaCertificates() on your QSslSocket instance prior to the SSL
+ handshake.
+
+ For more information about ciphers and certificates, refer to QSslCipher and
+ QSslCertificate.
+
+ This product includes software developed by the OpenSSL Project
+ for use in the OpenSSL Toolkit (\l{http://www.openssl.org/}).
+
+ \note Be aware of the difference between the bytesWritten() signal and
+ the encryptedBytesWritten() signal. For a QTcpSocket, bytesWritten()
+ will get emitted as soon as data has been written to the TCP socket.
+ For a QSslSocket, bytesWritten() will get emitted when the data
+ is being encrypted and encryptedBytesWritten()
+ will get emitted as soon as data has been written to the TCP socket.
+
+ \section1 Symbian Platform Security Requirements
+
+ On Symbian, processes which use this class must have the
+ \c NetworkServices platform security capability. If the client
+ process lacks this capability, operations will fail.
+
+ Platform security capabilities are added via the
+ \l{qmake-variable-reference.html#target-capability}{TARGET.CAPABILITY}
+ qmake variable.
+
+ \sa QSslCertificate, QSslCipher, QSslError
+*/
+
+/*!
+ \enum QSslSocket::SslMode
+
+ Describes the connection modes available for QSslSocket.
+
+ \value UnencryptedMode The socket is unencrypted. Its
+ behavior is identical to QTcpSocket.
+
+ \value SslClientMode The socket is a client-side SSL socket.
+ It is either alreayd encrypted, or it is in the SSL handshake
+ phase (see QSslSocket::isEncrypted()).
+
+ \value SslServerMode The socket is a server-side SSL socket.
+ It is either already encrypted, or it is in the SSL handshake
+ phase (see QSslSocket::isEncrypted()).
+*/
+
+/*!
+ \enum QSslSocket::PeerVerifyMode
+ \since 4.4
+
+ Describes the peer verification modes for QSslSocket. The default mode is
+ AutoVerifyPeer, which selects an appropriate mode depending on the
+ socket's QSocket::SslMode.
+
+ \value VerifyNone QSslSocket will not request a certificate from the
+ peer. You can set this mode if you are not interested in the identity of
+ the other side of the connection. The connection will still be encrypted,
+ and your socket will still send its local certificate to the peer if it's
+ requested.
+
+ \value QueryPeer QSslSocket will request a certificate from the peer, but
+ does not require this certificate to be valid. This is useful when you
+ want to display peer certificate details to the user without affecting the
+ actual SSL handshake. This mode is the default for servers.
+
+ \value VerifyPeer QSslSocket will request a certificate from the peer
+ during the SSL handshake phase, and requires that this certificate is
+ valid. On failure, QSslSocket will emit the QSslSocket::sslErrors()
+ signal. This mode is the default for clients.
+
+ \value AutoVerifyPeer QSslSocket will automatically use QueryPeer for
+ server sockets and VerifyPeer for client sockets.
+
+ \sa QSslSocket::peerVerifyMode()
+*/
+
+/*!
+ \fn QSslSocket::encrypted()
+
+ This signal is emitted when QSslSocket enters encrypted mode. After this
+ signal has been emitted, QSslSocket::isEncrypted() will return true, and
+ all further transmissions on the socket will be encrypted.
+
+ \sa QSslSocket::connectToHostEncrypted(), QSslSocket::isEncrypted()
+*/
+
+/*!
+ \fn QSslSocket::modeChanged(QSslSocket::SslMode mode)
+
+ This signal is emitted when QSslSocket changes from \l
+ QSslSocket::UnencryptedMode to either \l QSslSocket::SslClientMode or \l
+ QSslSocket::SslServerMode. \a mode is the new mode.
+
+ \sa QSslSocket::mode()
+*/
+
+/*!
+ \fn QSslSocket::encryptedBytesWritten(qint64 written)
+ \since 4.4
+
+ This signal is emitted when QSslSocket writes its encrypted data to the
+ network. The \a written parameter contains the number of bytes that were
+ successfully written.
+
+ \sa QIODevice::bytesWritten()
+*/
+
+/*!
+ \fn void QSslSocket::peerVerifyError(const QSslError &error)
+ \since 4.4
+
+ QSslSocket can emit this signal several times during the SSL handshake,
+ before encryption has been established, to indicate that an error has
+ occurred while establishing the identity of the peer. The \a error is
+ usually an indication that QSslSocket is unable to securely identify the
+ peer.
+
+ This signal provides you with an early indication when something's wrong.
+ By connecting to this signal, you can manually choose to tear down the
+ connection from inside the connected slot before the handshake has
+ completed. If no action is taken, QSslSocket will proceed to emitting
+ QSslSocket::sslErrors().
+
+ \sa sslErrors()
+*/
+
+/*!
+ \fn void QSslSocket::sslErrors(const QList<QSslError> &errors);
+
+ QSslSocket emits this signal after the SSL handshake to indicate that one
+ or more errors have occurred while establishing the identity of the
+ peer. The errors are usually an indication that QSslSocket is unable to
+ securely identify the peer. Unless any action is taken, the connection
+ will be dropped after this signal has been emitted.
+
+ If you want to continue connecting despite the errors that have occurred,
+ you must call QSslSocket::ignoreSslErrors() from inside a slot connected to
+ this signal. If you need to access the error list at a later point, you
+ can call sslErrors() (without arguments).
+
+ \a errors contains one or more errors that prevent QSslSocket from
+ verifying the identity of the peer.
+
+ Note: You cannot use Qt::QueuedConnection when connecting to this signal,
+ or calling QSslSocket::ignoreSslErrors() will have no effect.
+
+ \sa peerVerifyError()
+*/
+
+#include "qsslcipher.h"
+#include "qsslsocket.h"
+#include "qsslsocket_openssl_p.h"
+#include "qsslconfiguration_p.h"
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtNetwork/qhostaddress.h>
+#include <QtNetwork/qhostinfo.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Returns the difference between msecs and elapsed. If msecs is -1,
+ however, -1 is returned.
+*/
+static int qt_timeout_value(int msecs, int elapsed)
+{
+ if (msecs == -1)
+ return -1;
+
+ int timeout = msecs - elapsed;
+ return timeout < 0 ? 0 : timeout;
+}
+
+class QSslSocketGlobalData
+{
+public:
+ QSslSocketGlobalData() : config(new QSslConfigurationPrivate) {}
+
+ QMutex mutex;
+ QList<QSslCipher> supportedCiphers;
+ QExplicitlySharedDataPointer<QSslConfigurationPrivate> config;
+};
+Q_GLOBAL_STATIC(QSslSocketGlobalData, globalData)
+
+/*!
+ Constructs a QSslSocket object. \a parent is passed to QObject's
+ constructor. The new socket's \l {QSslCipher} {cipher} suite is
+ set to the one returned by the static method defaultCiphers().
+*/
+QSslSocket::QSslSocket(QObject *parent)
+ : QTcpSocket(*new QSslSocketBackendPrivate, parent)
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::QSslSocket(" << parent << "), this =" << (void *)this;
+#endif
+ d->q_ptr = this;
+ d->init();
+}
+
+/*!
+ Destroys the QSslSocket.
+*/
+QSslSocket::~QSslSocket()
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::~QSslSocket(), this =" << (void *)this;
+#endif
+ delete d->plainSocket;
+ d->plainSocket = 0;
+}
+
+/*!
+ Starts an encrypted connection to the device \a hostName on \a
+ port, using \a mode as the \l OpenMode. This is equivalent to
+ calling connectToHost() to establish the connection, followed by a
+ call to startClientEncryption().
+
+ QSslSocket first enters the HostLookupState. Then, after entering
+ either the event loop or one of the waitFor...() functions, it
+ enters the ConnectingState, emits connected(), and then initiates
+ the SSL client handshake. At each state change, QSslSocket emits
+ signal stateChanged().
+
+ After initiating the SSL client handshake, if the identity of the
+ peer can't be established, signal sslErrors() is emitted. If you
+ 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
+ disconnected() is emitted, and QSslSocket returns to the
+ UnconnectedState.
+
+ If the SSL handshake is successful, QSslSocket emits encrypted().
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 3
+
+ \bold{Note:} The example above shows that text can be written to
+ the socket immediately after requesting the encrypted connection,
+ before the encrypted() signal has been emitted. In such cases, the
+ text is queued in the object and written to the socket \e after
+ the connection is established and the encrypted() signal has been
+ emitted.
+
+ The default for \a mode is \l ReadWrite.
+
+ If you want to create a QSslSocket on the server side of a connection, you
+ should instead call startServerEncryption() upon receiving the incoming
+ connection through QTcpServer.
+
+ \sa connectToHost(), startClientEncryption(), waitForConnected(), waitForEncrypted()
+*/
+void QSslSocket::connectToHostEncrypted(const QString &hostName, quint16 port, 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;
+
+ // 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);
+}
+
+/*!
+ \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.
+ The socket is opened in the mode specified by \a openMode, and
+ enters the socket state specified by \a state.
+
+ \bold{Note:} It is not possible to initialize two sockets with the same
+ native socket descriptor.
+
+ \sa socketDescriptor()
+*/
+bool QSslSocket::setSocketDescriptor(int socketDescriptor, SocketState state, OpenMode openMode)
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::setSocketDescriptor(" << socketDescriptor << ','
+ << state << ',' << openMode << ')';
+#endif
+ if (!d->plainSocket)
+ d->createPlainSocket(openMode);
+ bool retVal = d->plainSocket->setSocketDescriptor(socketDescriptor, state, openMode);
+ d->cachedSocketDescriptor = d->plainSocket->socketDescriptor();
+ setSocketError(d->plainSocket->error());
+ setSocketState(state);
+ setOpenMode(openMode);
+ setLocalPort(d->plainSocket->localPort());
+ setLocalAddress(d->plainSocket->localAddress());
+ setPeerPort(d->plainSocket->peerPort());
+ setPeerAddress(d->plainSocket->peerAddress());
+ setPeerName(d->plainSocket->peerName());
+ return retVal;
+}
+
+/*!
+ \since 4.6
+ Sets the given \a option to the value described by \a value.
+
+ \sa socketOption()
+*/
+void QSslSocket::setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value)
+{
+ Q_D(QSslSocket);
+ if (d->plainSocket)
+ d->plainSocket->setSocketOption(option, value);
+}
+
+/*!
+ \since 4.6
+ Returns the value of the \a option option.
+
+ \sa setSocketOption()
+*/
+QVariant QSslSocket::socketOption(QAbstractSocket::SocketOption option)
+{
+ Q_D(QSslSocket);
+ if (d->plainSocket)
+ return d->plainSocket->socketOption(option);
+ else
+ return QVariant();
+}
+
+/*!
+ Returns the current mode for the socket; either UnencryptedMode, where
+ QSslSocket behaves identially to QTcpSocket, or one of SslClientMode or
+ SslServerMode, where the client is either negotiating or in encrypted
+ mode.
+
+ When the mode changes, QSslSocket emits modeChanged()
+
+ \sa SslMode
+*/
+QSslSocket::SslMode QSslSocket::mode() const
+{
+ Q_D(const QSslSocket);
+ return d->mode;
+}
+
+/*!
+ Returns true if the socket is encrypted; otherwise, false is returned.
+
+ An encrypted socket encrypts all data that is written by calling write()
+ or putChar() before the data is written to the network, and decrypts all
+ incoming data as the data is received from the network, before you call
+ read(), readLine() or getChar().
+
+ QSslSocket emits encrypted() when it enters encrypted mode.
+
+ You can call sessionCipher() to find which cryptographic cipher is used to
+ encrypt and decrypt your data.
+
+ \sa mode()
+*/
+bool QSslSocket::isEncrypted() const
+{
+ Q_D(const QSslSocket);
+ return d->connectionEncrypted;
+}
+
+/*!
+ Returns the socket's SSL protocol. By default, \l QSsl::SecureProtocols is used.
+
+ \sa setProtocol()
+*/
+QSsl::SslProtocol QSslSocket::protocol() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.protocol;
+}
+
+/*!
+ Sets the socket's SSL protocol to \a protocol. This will affect the next
+ initiated handshake; calling this function on an already-encrypted socket
+ will not affect the socket's protocol.
+*/
+void QSslSocket::setProtocol(QSsl::SslProtocol protocol)
+{
+ Q_D(QSslSocket);
+ d->configuration.protocol = protocol;
+}
+
+/*!
+ \since 4.4
+
+ Returns the socket's verify mode. This mode mode decides whether
+ QSslSocket should request a certificate from the peer (i.e., the client
+ requests a certificate from the server, or a server requesting a
+ certificate from the client), and whether it should require that this
+ certificate is valid.
+
+ The default mode is AutoVerifyPeer, which tells QSslSocket to use
+ VerifyPeer for clients and QueryPeer for servers.
+
+ \sa setPeerVerifyMode(), peerVerifyDepth(), mode()
+*/
+QSslSocket::PeerVerifyMode QSslSocket::peerVerifyMode() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.peerVerifyMode;
+}
+
+/*!
+ \since 4.4
+
+ Sets the socket's verify mode to \a mode. This mode decides whether
+ QSslSocket should request a certificate from the peer (i.e., the client
+ requests a certificate from the server, or a server requesting a
+ certificate from the client), and whether it should require that this
+ certificate is valid.
+
+ The default mode is AutoVerifyPeer, which tells QSslSocket to use
+ VerifyPeer for clients and QueryPeer for servers.
+
+ Setting this mode after encryption has started has no effect on the
+ current connection.
+
+ \sa peerVerifyMode(), setPeerVerifyDepth(), mode()
+*/
+void QSslSocket::setPeerVerifyMode(QSslSocket::PeerVerifyMode mode)
+{
+ Q_D(QSslSocket);
+ d->configuration.peerVerifyMode = mode;
+}
+
+/*!
+ \since 4.4
+
+ Returns the maximum number of certificates in the peer's certificate chain
+ to be checked during the SSL handshake phase, or 0 (the default) if no
+ maximum depth has been set, indicating that the whole certificate chain
+ should be checked.
+
+ The certificates are checked in issuing order, starting with the peer's
+ own certificate, then its issuer's certificate, and so on.
+
+ \sa setPeerVerifyDepth(), peerVerifyMode()
+*/
+int QSslSocket::peerVerifyDepth() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.peerVerifyDepth;
+}
+
+/*!
+ \since 4.4
+
+ Sets the maximum number of certificates in the peer's certificate chain to
+ be checked during the SSL handshake phase, to \a depth. Setting a depth of
+ 0 means that no maximum depth is set, indicating that the whole
+ certificate chain should be checked.
+
+ The certificates are checked in issuing order, starting with the peer's
+ own certificate, then its issuer's certificate, and so on.
+
+ \sa peerVerifyDepth(), setPeerVerifyMode()
+*/
+void QSslSocket::setPeerVerifyDepth(int depth)
+{
+ Q_D(QSslSocket);
+ if (depth < 0) {
+ qWarning("QSslSocket::setPeerVerifyDepth: cannot set negative depth of %d", depth);
+ return;
+ }
+ d->configuration.peerVerifyDepth = depth;
+}
+
+/*!
+ \since 4.8
+
+ Returns the different hostname for the certificate validation, as set by
+ setPeerVerifyName or by connectToHostEncrypted.
+
+ \sa setPeerVerifyName(), connectToHostEncrypted()
+*/
+QString QSslSocket::peerVerifyName() const
+{
+ Q_D(const QSslSocket);
+ return d->verificationPeerName;
+}
+
+/*!
+ \since 4.8
+
+ Sets a different hostname for the certificate validation instead of the one used for the TCP
+ connection.
+
+ \sa connectToHostEncrypted()
+*/
+void QSslSocket::setPeerVerifyName(const QString &hostName)
+{
+ Q_D(QSslSocket);
+ d->verificationPeerName = hostName;
+}
+
+/*!
+ \reimp
+
+ Returns the number of decrypted bytes that are immediately available for
+ reading.
+*/
+qint64 QSslSocket::bytesAvailable() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return QIODevice::bytesAvailable() + (d->plainSocket ? d->plainSocket->bytesAvailable() : 0);
+ return QIODevice::bytesAvailable() + d->readBuffer.size();
+}
+
+/*!
+ \reimp
+
+ Returns the number of unencrypted bytes that are waiting to be encrypted
+ and written to the network.
+*/
+qint64 QSslSocket::bytesToWrite() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return d->plainSocket ? d->plainSocket->bytesToWrite() : 0;
+ return d->writeBuffer.size();
+}
+
+/*!
+ \since 4.4
+
+ Returns the number of encrypted bytes that are awaiting decryption.
+ Normally, this function will return 0 because QSslSocket decrypts its
+ incoming data as soon as it can.
+*/
+qint64 QSslSocket::encryptedBytesAvailable() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return 0;
+ return d->plainSocket->bytesAvailable();
+}
+
+/*!
+ \since 4.4
+
+ Returns the number of encrypted bytes that are waiting to be written to
+ the network.
+*/
+qint64 QSslSocket::encryptedBytesToWrite() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return 0;
+ return d->plainSocket->bytesToWrite();
+}
+
+/*!
+ \reimp
+
+ Returns true if you can read one while line (terminated by a single ASCII
+ '\n' character) of decrypted characters; otherwise, false is returned.
+*/
+bool QSslSocket::canReadLine() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return QIODevice::canReadLine() || (d->plainSocket && d->plainSocket->canReadLine());
+ return QIODevice::canReadLine() || (!d->readBuffer.isEmpty() && d->readBuffer.canReadLine());
+}
+
+/*!
+ \reimp
+*/
+void QSslSocket::close()
+{
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::close()";
+#endif
+ Q_D(QSslSocket);
+ if (d->plainSocket)
+ d->plainSocket->close();
+ QTcpSocket::close();
+
+ // must be cleared, reading/writing not possible on closed socket:
+ d->readBuffer.clear();
+ d->writeBuffer.clear();
+ // for QTcpSocket this is already done because it uses the readBuffer/writeBuffer
+ // if the QIODevice it is based on
+ // ### FIXME QSslSocket should probably do similar instead of having
+ // its own readBuffer/writeBuffer
+}
+
+/*!
+ \reimp
+*/
+bool QSslSocket::atEnd() const
+{
+ Q_D(const QSslSocket);
+ if (d->mode == UnencryptedMode)
+ return QIODevice::atEnd() && (!d->plainSocket || d->plainSocket->atEnd());
+ return QIODevice::atEnd() && d->readBuffer.isEmpty();
+}
+
+/*!
+ This function writes as much as possible from the internal write buffer to
+ the underlying network socket, without blocking. If any data was written,
+ this function returns true; otherwise false is returned.
+
+ Call this function if you need QSslSocket to start sending buffered data
+ immediately. The number of bytes successfully written depends on the
+ operating system. In most cases, you do not need to call this function,
+ because QAbstractSocket will start sending data automatically once control
+ goes back to the event loop. In the absence of an event loop, call
+ waitForBytesWritten() instead.
+
+ \sa write(), waitForBytesWritten()
+*/
+// Note! docs copied from QAbstractSocket::flush()
+bool QSslSocket::flush()
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::flush()";
+#endif
+ if (d->mode != UnencryptedMode)
+ // encrypt any unencrypted bytes in our buffer
+ d->transmit();
+
+ return d->plainSocket ? d->plainSocket->flush() : false;
+}
+
+/*!
+ \since 4.4
+
+ Sets the size of QSslSocket's internal read buffer to be \a size bytes.
+*/
+void QSslSocket::setReadBufferSize(qint64 size)
+{
+ Q_D(QSslSocket);
+ d->readBufferMaxSize = size;
+
+ if (d->plainSocket)
+ d->plainSocket->setReadBufferSize(size);
+}
+
+/*!
+ Aborts the current connection and resets the socket. Unlike
+ disconnectFromHost(), this function immediately closes the socket,
+ clearing any pending data in the write buffer.
+
+ \sa disconnectFromHost(), close()
+*/
+void QSslSocket::abort()
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::abort()";
+#endif
+ if (d->plainSocket)
+ d->plainSocket->abort();
+ close();
+}
+
+/*!
+ \since 4.4
+
+ Returns the socket's SSL configuration state. The default SSL
+ configuration of a socket is to use the default ciphers,
+ default CA certificates, no local private key or certificate.
+
+ The SSL configuration also contains fields that can change with
+ time without notice.
+
+ \sa localCertificate(), peerCertificate(), peerCertificateChain(),
+ sessionCipher(), privateKey(), ciphers(), caCertificates()
+*/
+QSslConfiguration QSslSocket::sslConfiguration() const
+{
+ Q_D(const QSslSocket);
+
+ // create a deep copy of our configuration
+ QSslConfigurationPrivate *copy = new QSslConfigurationPrivate(d->configuration);
+ copy->ref = 0; // the QSslConfiguration constructor refs up
+ copy->sessionCipher = d->sessionCipher();
+
+ return QSslConfiguration(copy);
+}
+
+/*!
+ \since 4.4
+
+ Sets the socket's SSL configuration to be the contents of \a configuration.
+ This function sets the local certificate, the ciphers, the private key and the CA
+ certificates to those stored in \a configuration.
+
+ It is not possible to set the SSL-state related fields.
+
+ \sa setLocalCertificate(), setPrivateKey(), setCaCertificates(), setCiphers()
+*/
+void QSslSocket::setSslConfiguration(const QSslConfiguration &configuration)
+{
+ Q_D(QSslSocket);
+ d->configuration.localCertificate = configuration.localCertificate();
+ d->configuration.privateKey = configuration.privateKey();
+ d->configuration.ciphers = configuration.ciphers();
+ d->configuration.caCertificates = configuration.caCertificates();
+ d->configuration.peerVerifyDepth = configuration.peerVerifyDepth();
+ d->configuration.peerVerifyMode = configuration.peerVerifyMode();
+ d->configuration.protocol = configuration.protocol();
+ d->allowRootCertOnDemandLoading = false;
+}
+
+/*!
+ Sets the socket's local certificate to \a certificate. The local
+ certificate is necessary if you need to confirm your identity to the
+ peer. It is used together with the private key; if you set the local
+ certificate, you must also set the private key.
+
+ The local certificate and private key are always necessary for server
+ sockets, but are also rarely used by client sockets if the server requires
+ the client to authenticate.
+
+ \sa localCertificate(), setPrivateKey()
+*/
+void QSslSocket::setLocalCertificate(const QSslCertificate &certificate)
+{
+ Q_D(QSslSocket);
+ d->configuration.localCertificate = certificate;
+}
+
+/*!
+ \overload
+
+ Sets the socket's local \l {QSslCertificate} {certificate} to the
+ first one found in file \a path, which is parsed according to the
+ specified \a format.
+*/
+void QSslSocket::setLocalCertificate(const QString &path,
+ QSsl::EncodingFormat format)
+{
+ Q_D(QSslSocket);
+ QFile file(path);
+ if (file.open(QIODevice::ReadOnly | QIODevice::Text))
+ d->configuration.localCertificate = QSslCertificate(file.readAll(), format);
+}
+
+/*!
+ Returns the socket's local \l {QSslCertificate} {certificate}, or
+ an empty certificate if no local certificate has been assigned.
+
+ \sa setLocalCertificate(), privateKey()
+*/
+QSslCertificate QSslSocket::localCertificate() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.localCertificate;
+}
+
+/*!
+ Returns the peer's digital certificate (i.e., the immediate
+ certificate of the host you are connected to), or a null
+ certificate, if the peer has not assigned a certificate.
+
+ The peer certificate is checked automatically during the
+ handshake phase, so this function is normally used to fetch
+ the certificate for display or for connection diagnostic
+ purposes. It contains information about the peer, including
+ its host name, the certificate issuer, and the peer's public
+ key.
+
+ Because the peer certificate is set during the handshake phase, it
+ is safe to access the peer certificate from a slot connected to
+ the sslErrors() signal or the encrypted() signal.
+
+ If a null certificate is returned, it can mean the SSL handshake
+ failed, or it can mean the host you are connected to doesn't have
+ a certificate, or it can mean there is no connection.
+
+ If you want to check the peer's complete chain of certificates,
+ use peerCertificateChain() to get them all at once.
+
+ \sa peerCertificateChain()
+*/
+QSslCertificate QSslSocket::peerCertificate() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.peerCertificate;
+}
+
+/*!
+ Returns the peer's chain of digital certificates, or an empty list
+ of certificates.
+
+ Peer certificates are checked automatically during the handshake
+ phase. This function is normally used to fetch certificates for
+ display, or for performing connection diagnostics. Certificates
+ contain information about the peer and the certificate issuers,
+ including host name, issuer names, and issuer public keys.
+
+ The peer certificates are set in QSslSocket during the handshake
+ phase, so it is safe to call this function from a slot connected
+ to the sslErrors() signal or the encrypted() signal.
+
+ If an empty list is returned, it can mean the SSL handshake
+ failed, or it can mean the host you are connected to doesn't have
+ a certificate, or it can mean there is no connection.
+
+ If you want to get only the peer's immediate certificate, use
+ peerCertificate().
+
+ \sa peerCertificate()
+*/
+QList<QSslCertificate> QSslSocket::peerCertificateChain() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.peerCertificateChain;
+}
+
+/*!
+ Returns the socket's cryptographic \l {QSslCipher} {cipher}, or a
+ null cipher if the connection isn't encrypted. The socket's cipher
+ for the session is set during the handshake phase. The cipher is
+ used to encrypt and decrypt data transmitted through the socket.
+
+ QSslSocket also provides functions for setting the ordered list of
+ ciphers from which the handshake phase will eventually select the
+ session cipher. This ordered list must be in place before the
+ handshake phase begins.
+
+ \sa ciphers(), setCiphers(), setDefaultCiphers(), defaultCiphers(),
+ supportedCiphers()
+*/
+QSslCipher QSslSocket::sessionCipher() const
+{
+ Q_D(const QSslSocket);
+ return d->sessionCipher();
+}
+
+/*!
+ Sets the socket's private \l {QSslKey} {key} to \a key. The
+ private key and the local \l {QSslCertificate} {certificate} are
+ used by clients and servers that must prove their identity to
+ SSL peers.
+
+ Both the key and the local certificate are required if you are
+ creating an SSL server socket. If you are creating an SSL client
+ socket, the key and local certificate are required if your client
+ must identify itself to an SSL server.
+
+ \sa privateKey(), setLocalCertificate()
+*/
+void QSslSocket::setPrivateKey(const QSslKey &key)
+{
+ Q_D(QSslSocket);
+ d->configuration.privateKey = key;
+}
+
+/*!
+ \overload
+
+ Reads the string in file \a fileName and decodes it using
+ a specified \a algorithm and encoding \a format to construct
+ an \l {QSslKey} {SSL key}. If the encoded key is encrypted,
+ \a passPhrase is used to decrypt it.
+
+ The socket's private key is set to the constructed key. The
+ private key and the local \l {QSslCertificate} {certificate} are
+ used by clients and servers that must prove their identity to SSL
+ peers.
+
+ Both the key and the local certificate are required if you are
+ creating an SSL server socket. If you are creating an SSL client
+ socket, the key and local certificate are required if your client
+ must identify itself to an SSL server.
+
+ \sa privateKey(), setLocalCertificate()
+*/
+void QSslSocket::setPrivateKey(const QString &fileName, QSsl::KeyAlgorithm algorithm,
+ QSsl::EncodingFormat format, const QByteArray &passPhrase)
+{
+ Q_D(QSslSocket);
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ d->configuration.privateKey = QSslKey(file.readAll(), algorithm,
+ format, QSsl::PrivateKey, passPhrase);
+ }
+}
+
+/*!
+ Returns this socket's private key.
+
+ \sa setPrivateKey(), localCertificate()
+*/
+QSslKey QSslSocket::privateKey() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.privateKey;
+}
+
+/*!
+ Returns this socket's current cryptographic cipher suite. This
+ list is used during the socket's handshake phase for choosing a
+ session cipher. The returned list of ciphers is ordered by
+ descending preference. (i.e., the first cipher in the list is the
+ most preferred cipher). The session cipher will be the first one
+ in the list that is also supported by the peer.
+
+ By default, the handshake phase can choose any of the ciphers
+ supported by this system's SSL libraries, which may vary from
+ system to system. The list of ciphers supported by this system's
+ SSL libraries is returned by supportedCiphers(). You can restrict
+ the list of ciphers used for choosing the session cipher for this
+ socket by calling setCiphers() with a subset of the supported
+ ciphers. You can revert to using the entire set by calling
+ setCiphers() with the list returned by supportedCiphers().
+
+ You can restrict the list of ciphers used for choosing the session
+ cipher for \e all sockets by calling setDefaultCiphers() with a
+ subset of the supported ciphers. You can revert to using the
+ entire set by calling setCiphers() with the list returned by
+ supportedCiphers().
+
+ \sa setCiphers(), defaultCiphers(), setDefaultCiphers(), supportedCiphers()
+*/
+QList<QSslCipher> QSslSocket::ciphers() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.ciphers;
+}
+
+/*!
+ Sets the cryptographic cipher suite for this socket to \a ciphers,
+ which must contain a subset of the ciphers in the list returned by
+ supportedCiphers().
+
+ Restricting the cipher suite must be done before the handshake
+ phase, where the session cipher is chosen.
+
+ \sa ciphers(), setDefaultCiphers(), supportedCiphers()
+*/
+void QSslSocket::setCiphers(const QList<QSslCipher> &ciphers)
+{
+ Q_D(QSslSocket);
+ d->configuration.ciphers = ciphers;
+}
+
+/*!
+ Sets the cryptographic cipher suite for this socket to \a ciphers, which
+ is a colon-separated list of cipher suite names. The ciphers are listed in
+ order of preference, starting with the most preferred cipher. For example:
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 4
+
+ Each cipher name in \a ciphers must be the name of a cipher in the
+ list returned by supportedCiphers(). Restricting the cipher suite
+ must be done before the handshake phase, where the session cipher
+ is chosen.
+
+ \sa ciphers(), setDefaultCiphers(), supportedCiphers()
+*/
+void QSslSocket::setCiphers(const QString &ciphers)
+{
+ Q_D(QSslSocket);
+ d->configuration.ciphers.clear();
+ foreach (const QString &cipherName, ciphers.split(QLatin1String(":"),QString::SkipEmptyParts)) {
+ for (int i = 0; i < 3; ++i) {
+ // ### Crude
+ QSslCipher cipher(cipherName, QSsl::SslProtocol(i));
+ if (!cipher.isNull())
+ d->configuration.ciphers << cipher;
+ }
+ }
+}
+
+/*!
+ Sets the default cryptographic cipher suite for all sockets in
+ this application to \a ciphers, which must contain a subset of the
+ ciphers in the list returned by supportedCiphers().
+
+ Restricting the default cipher suite only affects SSL sockets
+ that perform their handshake phase after the default cipher
+ suite has been changed.
+
+ \sa setCiphers(), defaultCiphers(), supportedCiphers()
+*/
+void QSslSocket::setDefaultCiphers(const QList<QSslCipher> &ciphers)
+{
+ QSslSocketPrivate::setDefaultCiphers(ciphers);
+}
+
+/*!
+ Returns the default cryptographic cipher suite for all sockets in
+ this application. This list is used during the socket's handshake
+ phase when negotiating with the peer to choose a session cipher.
+ The list is ordered by preference (i.e., the first cipher in the
+ list is the most preferred cipher).
+
+ By default, the handshake phase can choose any of the ciphers
+ supported by this system's SSL libraries, which may vary from
+ system to system. The list of ciphers supported by this system's
+ SSL libraries is returned by supportedCiphers().
+
+ \sa supportedCiphers()
+*/
+QList<QSslCipher> QSslSocket::defaultCiphers()
+{
+ return QSslSocketPrivate::defaultCiphers();
+}
+
+/*!
+ Returns the list of cryptographic ciphers supported by this
+ system. This list is set by the system's SSL libraries and may
+ vary from system to system.
+
+ \sa defaultCiphers(), ciphers(), setCiphers()
+*/
+QList<QSslCipher> QSslSocket::supportedCiphers()
+{
+ return QSslSocketPrivate::supportedCiphers();
+}
+
+/*!
+ Searches all files in the \a path for certificates encoded in the
+ specified \a format and adds them to this socket's CA certificate
+ database. \a path can be explicit, or it can contain wildcards in
+ the format specified by \a syntax. Returns true if one or more
+ certificates are added to the socket's CA certificate database;
+ otherwise returns false.
+
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ For more precise control, use addCaCertificate().
+
+ \sa addCaCertificate(), QSslCertificate::fromPath()
+*/
+bool QSslSocket::addCaCertificates(const QString &path, QSsl::EncodingFormat format,
+ QRegExp::PatternSyntax syntax)
+{
+ Q_D(QSslSocket);
+ QList<QSslCertificate> certs = QSslCertificate::fromPath(path, format, syntax);
+ if (certs.isEmpty())
+ return false;
+
+ d->configuration.caCertificates += certs;
+ return true;
+}
+
+/*!
+ Adds the \a certificate to this socket's CA certificate database.
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ To add multiple certificates, use addCaCertificates().
+
+ \sa caCertificates(), setCaCertificates()
+*/
+void QSslSocket::addCaCertificate(const QSslCertificate &certificate)
+{
+ Q_D(QSslSocket);
+ d->configuration.caCertificates += certificate;
+}
+
+/*!
+ Adds the \a certificates to this socket's CA certificate database.
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ For more precise control, use addCaCertificate().
+
+ \sa caCertificates(), addDefaultCaCertificate()
+*/
+void QSslSocket::addCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ Q_D(QSslSocket);
+ d->configuration.caCertificates += certificates;
+}
+
+/*!
+ Sets this socket's CA certificate database to be \a certificates.
+ The certificate database must be set prior to the SSL handshake.
+ The CA certificate database is used by the socket during the
+ handshake phase to validate the peer's certificate.
+
+ The CA certificate database can be reset to the current default CA
+ certificate database by calling this function with the list of CA
+ certificates returned by defaultCaCertificates().
+
+ \sa defaultCaCertificates()
+*/
+void QSslSocket::setCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ Q_D(QSslSocket);
+ d->configuration.caCertificates = certificates;
+ d->allowRootCertOnDemandLoading = false;
+}
+
+/*!
+ Returns this socket's CA certificate database. The CA certificate
+ database is used by the socket during the handshake phase to
+ validate the peer's certificate. It can be moodified prior to the
+ handshake with addCaCertificate(), addCaCertificates(), and
+ setCaCertificates().
+
+ \note On Unix, this method may return an empty list if the root
+ certificates are loaded on demand.
+
+ \sa addCaCertificate(), addCaCertificates(), setCaCertificates()
+*/
+QList<QSslCertificate> QSslSocket::caCertificates() const
+{
+ Q_D(const QSslSocket);
+ return d->configuration.caCertificates;
+}
+
+/*!
+ Searches all files in the \a path for certificates with the
+ specified \a encoding and adds them to the default CA certificate
+ database. \a path can be an explicit file, or it can contain
+ wildcards in the format specified by \a syntax. Returns true if
+ any CA certificates are added to the default database.
+
+ Each SSL socket's CA certificate database is initialized to the
+ default CA certificate database.
+
+ \sa defaultCaCertificates(), addCaCertificates(), addDefaultCaCertificate()
+*/
+bool QSslSocket::addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat encoding,
+ QRegExp::PatternSyntax syntax)
+{
+ return QSslSocketPrivate::addDefaultCaCertificates(path, encoding, syntax);
+}
+
+/*!
+ Adds \a certificate to the default CA certificate database. Each
+ SSL socket's CA certificate database is initialized to the default
+ CA certificate database.
+
+ \sa defaultCaCertificates(), addCaCertificates()
+*/
+void QSslSocket::addDefaultCaCertificate(const QSslCertificate &certificate)
+{
+ QSslSocketPrivate::addDefaultCaCertificate(certificate);
+}
+
+/*!
+ Adds \a certificates to the default CA certificate database. Each
+ SSL socket's CA certificate database is initialized to the default
+ CA certificate database.
+
+ \sa defaultCaCertificates(), addCaCertificates()
+*/
+void QSslSocket::addDefaultCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ QSslSocketPrivate::addDefaultCaCertificates(certificates);
+}
+
+/*!
+ Sets the default CA certificate database to \a certificates. The
+ default CA certificate database is originally set to your system's
+ default CA certificate database. You can override the default CA
+ certificate database with your own CA certificate database using
+ this function.
+
+ Each SSL socket's CA certificate database is initialized to the
+ default CA certificate database.
+
+ \sa addDefaultCaCertificate()
+*/
+void QSslSocket::setDefaultCaCertificates(const QList<QSslCertificate> &certificates)
+{
+ QSslSocketPrivate::setDefaultCaCertificates(certificates);
+}
+
+/*!
+ Returns the current default CA certificate database. This database
+ is originally set to your system's default CA certificate database.
+ If no system default database is found, an empty database will be
+ returned. You can override the default CA certificate database
+ with your own CA certificate database using setDefaultCaCertificates().
+
+ Each SSL socket's CA certificate database is initialized to the
+ default CA certificate database.
+
+ \note On Unix, this method may return an empty list if the root
+ certificates are loaded on demand.
+
+ \sa caCertificates()
+*/
+QList<QSslCertificate> QSslSocket::defaultCaCertificates()
+{
+ return QSslSocketPrivate::defaultCaCertificates();
+}
+
+/*!
+ This function provides the CA certificate database
+ provided by the operating system. The CA certificate database
+ returned by this function is used to initialize the database
+ returned by defaultCaCertificates(). You can replace that database
+ with your own with setDefaultCaCertificates().
+
+ \sa caCertificates(), defaultCaCertificates(), setDefaultCaCertificates()
+*/
+QList<QSslCertificate> QSslSocket::systemCaCertificates()
+{
+ // we are calling ensureInitialized() in the method below
+ return QSslSocketPrivate::systemCaCertificates();
+}
+
+/*!
+ Waits until the socket is connected, or \a msecs milliseconds,
+ whichever happens first. If the connection has been established,
+ this function returns true; otherwise it returns false.
+
+ \sa QAbstractSocket::waitForConnected()
+*/
+bool QSslSocket::waitForConnected(int msecs)
+{
+ Q_D(QSslSocket);
+ if (!d->plainSocket)
+ return false;
+ bool retVal = d->plainSocket->waitForConnected(msecs);
+ if (!retVal) {
+ setSocketState(d->plainSocket->state());
+ setSocketError(d->plainSocket->error());
+ setErrorString(d->plainSocket->errorString());
+ }
+ return retVal;
+}
+
+/*!
+ Waits until the socket has completed the SSL handshake and has
+ emitted encrypted(), or \a msecs milliseconds, whichever comes
+ first. If encrypted() has been emitted, this function returns
+ true; otherwise (e.g., the socket is disconnected, or the SSL
+ handshake fails), false is returned.
+
+ The following example waits up to one second for the socket to be
+ encrypted:
+
+ \snippet doc/src/snippets/code/src_network_ssl_qsslsocket.cpp 5
+
+ If msecs is -1, this function will not time out.
+
+ \sa startClientEncryption(), startServerEncryption(), encrypted(), isEncrypted()
+*/
+bool QSslSocket::waitForEncrypted(int msecs)
+{
+ Q_D(QSslSocket);
+ if (!d->plainSocket || d->connectionEncrypted)
+ return false;
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake)
+ return false;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ if (d->plainSocket->state() != QAbstractSocket::ConnectedState) {
+ // Wait until we've entered connected state.
+ if (!d->plainSocket->waitForConnected(msecs))
+ return false;
+ }
+
+ while (!d->connectionEncrypted) {
+ // Start the handshake, if this hasn't been started yet.
+ if (d->mode == UnencryptedMode)
+ startClientEncryption();
+ // Loop, waiting until the connection has been encrypted or an error
+ // occurs.
+ if (!d->plainSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed())))
+ return false;
+ }
+ return d->connectionEncrypted;
+}
+
+/*!
+ \reimp
+*/
+bool QSslSocket::waitForReadyRead(int msecs)
+{
+ Q_D(QSslSocket);
+ if (!d->plainSocket)
+ return false;
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake)
+ return d->plainSocket->waitForReadyRead(msecs);
+
+ // This function must return true if and only if readyRead() *was* emitted.
+ // So we initialize "readyReadEmitted" to false and check if it was set to true.
+ // waitForReadyRead() could be called recursively, so we can't use the same variable
+ // (the inner waitForReadyRead() may fail, but the outer one still succeeded)
+ bool readyReadEmitted = false;
+ bool *previousReadyReadEmittedPointer = d->readyReadEmittedPointer;
+ d->readyReadEmittedPointer = &readyReadEmitted;
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ if (!d->connectionEncrypted) {
+ // Wait until we've entered encrypted mode, or until a failure occurs.
+ if (!waitForEncrypted(msecs)) {
+ d->readyReadEmittedPointer = previousReadyReadEmittedPointer;
+ return false;
+ }
+ }
+
+ if (!d->writeBuffer.isEmpty()) {
+ // empty our cleartext write buffer first
+ d->transmit();
+ }
+
+ // test readyReadEmitted first because either operation above
+ // (waitForEncrypted or transmit) may have set it
+ while (!readyReadEmitted &&
+ d->plainSocket->waitForReadyRead(qt_timeout_value(msecs, stopWatch.elapsed()))) {
+ }
+
+ d->readyReadEmittedPointer = previousReadyReadEmittedPointer;
+ return readyReadEmitted;
+}
+
+/*!
+ \reimp
+*/
+bool QSslSocket::waitForBytesWritten(int msecs)
+{
+ Q_D(QSslSocket);
+ if (!d->plainSocket)
+ return false;
+ if (d->mode == UnencryptedMode)
+ return d->plainSocket->waitForBytesWritten(msecs);
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ if (!d->connectionEncrypted) {
+ // Wait until we've entered encrypted mode, or until a failure occurs.
+ if (!waitForEncrypted(msecs))
+ return false;
+ }
+ if (!d->writeBuffer.isEmpty()) {
+ // empty our cleartext write buffer first
+ d->transmit();
+ }
+
+ return d->plainSocket->waitForBytesWritten(qt_timeout_value(msecs, stopWatch.elapsed()));
+}
+
+/*!
+ Waits until the socket has disconnected or \a msecs milliseconds,
+ whichever comes first. If the connection has been disconnected,
+ this function returns true; otherwise it returns false.
+
+ \sa QAbstractSocket::waitForDisconnected()
+*/
+bool QSslSocket::waitForDisconnected(int msecs)
+{
+ Q_D(QSslSocket);
+
+ // require calling connectToHost() before waitForDisconnected()
+ if (state() == UnconnectedState) {
+ qWarning("QSslSocket::waitForDisconnected() is not allowed in UnconnectedState");
+ return false;
+ }
+
+ if (!d->plainSocket)
+ return false;
+ if (d->mode == UnencryptedMode)
+ return d->plainSocket->waitForDisconnected(msecs);
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+
+ if (!d->connectionEncrypted) {
+ // Wait until we've entered encrypted mode, or until a failure occurs.
+ if (!waitForEncrypted(msecs))
+ return false;
+ }
+ bool retVal = d->plainSocket->waitForDisconnected(qt_timeout_value(msecs, stopWatch.elapsed()));
+ if (!retVal) {
+ setSocketState(d->plainSocket->state());
+ setSocketError(d->plainSocket->error());
+ setErrorString(d->plainSocket->errorString());
+ }
+ return retVal;
+}
+
+/*!
+ Returns a list of the last SSL errors that occurred. This is the
+ same list as QSslSocket passes via the sslErrors() signal. If the
+ connection has been encrypted with no errors, this function will
+ return an empty list.
+
+ \sa connectToHostEncrypted()
+*/
+QList<QSslError> QSslSocket::sslErrors() const
+{
+ Q_D(const QSslSocket);
+ return d->sslErrors;
+}
+
+/*!
+ Returns true if this platform supports SSL; otherwise, returns
+ false. If the platform doesn't support SSL, the socket will fail
+ in the connection phase.
+*/
+bool QSslSocket::supportsSsl()
+{
+ return QSslSocketPrivate::supportsSsl();
+}
+
+/*!
+ Starts a delayed SSL handshake for a client connection. This
+ function can be called when the socket is in the \l ConnectedState
+ but still in the \l UnencryptedMode. If it is not yet connected,
+ or if it is already encrypted, this function has no effect.
+
+ Clients that implement STARTTLS functionality often make use of
+ delayed SSL handshakes. Most other clients can avoid calling this
+ function directly by using connectToHostEncrypted() instead, which
+ automatically performs the handshake.
+
+ \sa connectToHostEncrypted(), startServerEncryption()
+*/
+void QSslSocket::startClientEncryption()
+{
+ Q_D(QSslSocket);
+ if (d->mode != UnencryptedMode) {
+ qWarning("QSslSocket::startClientEncryption: cannot start handshake on non-plain connection");
+ return;
+ }
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::startClientEncryption()";
+#endif
+ d->mode = SslClientMode;
+ emit modeChanged(d->mode);
+ d->startClientEncryption();
+}
+
+/*!
+ Starts a delayed SSL handshake for a server connection. This
+ function can be called when the socket is in the \l ConnectedState
+ but still in \l UnencryptedMode. If it is not connected or it is
+ already encrypted, the function has no effect.
+
+ For server sockets, calling this function is the only way to
+ initiate the SSL handshake. Most servers will call this function
+ immediately upon receiving a connection, or as a result of having
+ received a protocol-specific command to enter SSL mode (e.g, the
+ server may respond to receiving the string "STARTTLS\r\n" by
+ calling this function).
+
+ The most common way to implement an SSL server is to create a
+ subclass of QTcpServer and reimplement
+ QTcpServer::incomingConnection(). The returned socket descriptor
+ is then passed to QSslSocket::setSocketDescriptor().
+
+ \sa connectToHostEncrypted(), startClientEncryption()
+*/
+void QSslSocket::startServerEncryption()
+{
+ Q_D(QSslSocket);
+ if (d->mode != UnencryptedMode) {
+ qWarning("QSslSocket::startServerEncryption: cannot start handshake on non-plain connection");
+ return;
+ }
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::startServerEncryption()";
+#endif
+ d->mode = SslServerMode;
+ emit modeChanged(d->mode);
+ d->startServerEncryption();
+}
+
+/*!
+ This slot tells QSslSocket to ignore errors during QSslSocket's
+ handshake phase and continue connecting. If you want to continue
+ with the connection even if errors occur during the handshake
+ phase, then you must call this slot, either from a slot connected
+ to sslErrors(), or before the handshake phase. If you don't call
+ this slot, either in response to errors or before the handshake,
+ the connection will be dropped after the sslErrors() signal has
+ been emitted.
+
+ If there are no errors during the SSL handshake phase (i.e., the
+ identity of the peer is established with no problems), QSslSocket
+ will not emit the sslErrors() signal, and it is unnecessary to
+ call this function.
+
+ Ignoring errors that occur during an SSL handshake should be done
+ with caution. A fundamental characteristic of secure connections
+ is that they should be established with an error free handshake.
+
+ \sa sslErrors()
+*/
+void QSslSocket::ignoreSslErrors()
+{
+ Q_D(QSslSocket);
+ 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;
+}
+
+/*!
+ \internal
+*/
+void QSslSocket::connectToHostImplementation(const QString &hostName, quint16 port,
+ OpenMode openMode)
+{
+ Q_D(QSslSocket);
+ if (!d->initialized)
+ d->init();
+ d->initialized = false;
+
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::connectToHostImplementation("
+ << hostName << ',' << port << ',' << openMode << ')';
+#endif
+ if (!d->plainSocket) {
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "\tcreating internal plain socket";
+#endif
+ d->createPlainSocket(openMode);
+ }
+#ifndef QT_NO_NETWORKPROXY
+ d->plainSocket->setProxy(proxy());
+#endif
+ QIODevice::open(openMode);
+ d->plainSocket->connectToHost(hostName, port, openMode);
+ d->cachedSocketDescriptor = d->plainSocket->socketDescriptor();
+}
+
+/*!
+ \internal
+*/
+void QSslSocket::disconnectFromHostImplementation()
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::disconnectFromHostImplementation()";
+#endif
+ if (!d->plainSocket)
+ return;
+ if (d->state == UnconnectedState)
+ return;
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake) {
+ d->plainSocket->disconnectFromHost();
+ return;
+ }
+ if (d->state <= ConnectingState) {
+ d->pendingClose = true;
+ return;
+ }
+
+ // Perhaps emit closing()
+ if (d->state != ClosingState) {
+ d->state = ClosingState;
+ emit stateChanged(d->state);
+ }
+
+ if (!d->writeBuffer.isEmpty())
+ return;
+
+ if (d->mode == UnencryptedMode) {
+ d->plainSocket->disconnectFromHost();
+ } else {
+ d->disconnectFromHost();
+ }
+}
+
+/*!
+ \reimp
+*/
+qint64 QSslSocket::readData(char *data, qint64 maxlen)
+{
+ Q_D(QSslSocket);
+ qint64 readBytes = 0;
+
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake) {
+ readBytes = d->plainSocket->read(data, maxlen);
+ } else {
+ do {
+ const char *readPtr = d->readBuffer.readPointer();
+ int bytesToRead = qMin<int>(maxlen - readBytes, d->readBuffer.nextDataBlockSize());
+ ::memcpy(data + readBytes, readPtr, bytesToRead);
+ readBytes += bytesToRead;
+ d->readBuffer.free(bytesToRead);
+ } while (!d->readBuffer.isEmpty() && readBytes < maxlen);
+ }
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::readData(" << (void *)data << ',' << maxlen << ") ==" << readBytes;
+#endif
+
+ // possibly trigger another transmit() to decrypt more data from the socket
+ if (d->readBuffer.isEmpty() && d->plainSocket->bytesAvailable())
+ QMetaObject::invokeMethod(this, "_q_flushReadBuffer", Qt::QueuedConnection);
+
+ return readBytes;
+}
+
+/*!
+ \reimp
+*/
+qint64 QSslSocket::writeData(const char *data, qint64 len)
+{
+ Q_D(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::writeData(" << (void *)data << ',' << len << ')';
+#endif
+ if (d->mode == UnencryptedMode && !d->autoStartHandshake)
+ return d->plainSocket->write(data, len);
+
+ char *writePtr = d->writeBuffer.reserve(len);
+ ::memcpy(writePtr, data, len);
+
+ // make sure we flush to the plain socket's buffer
+ QMetaObject::invokeMethod(this, "_q_flushWriteBuffer", Qt::QueuedConnection);
+
+ return len;
+}
+
+/*!
+ \internal
+*/
+QSslSocketPrivate::QSslSocketPrivate()
+ : initialized(false)
+ , mode(QSslSocket::UnencryptedMode)
+ , autoStartHandshake(false)
+ , connectionEncrypted(false)
+ , ignoreAllSslErrors(false)
+ , readyReadEmittedPointer(0)
+ , allowRootCertOnDemandLoading(true)
+ , plainSocket(0)
+{
+ QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
+}
+
+/*!
+ \internal
+*/
+QSslSocketPrivate::~QSslSocketPrivate()
+{
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::init()
+{
+ mode = QSslSocket::UnencryptedMode;
+ autoStartHandshake = false;
+ connectionEncrypted = 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();
+ configuration.peerCertificate.clear();
+ configuration.peerCertificateChain.clear();
+}
+
+/*!
+ \internal
+*/
+QList<QSslCipher> QSslSocketPrivate::defaultCiphers()
+{
+ QMutexLocker locker(&globalData()->mutex);
+ return globalData()->config->ciphers;
+}
+
+/*!
+ \internal
+*/
+QList<QSslCipher> QSslSocketPrivate::supportedCiphers()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ return globalData()->supportedCiphers;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultCiphers(const QList<QSslCipher> &ciphers)
+{
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->ciphers = ciphers;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers)
+{
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->supportedCiphers = ciphers;
+}
+
+/*!
+ \internal
+*/
+QList<QSslCertificate> QSslSocketPrivate::defaultCaCertificates()
+{
+ // ### Qt5: rename everything containing "caCertificates" to "rootCertificates" or similar
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ return globalData()->config->caCertificates;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::setDefaultCaCertificates(const QList<QSslCertificate> &certs)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->caCertificates = certs;
+ // when the certificates are set explicitly, we do not want to
+ // load the system certificates on demand
+ s_loadRootCertsOnDemand = false;
+}
+
+/*!
+ \internal
+*/
+bool QSslSocketPrivate::addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat format,
+ QRegExp::PatternSyntax syntax)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QList<QSslCertificate> certs = QSslCertificate::fromPath(path, format, syntax);
+ if (certs.isEmpty())
+ return false;
+
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->caCertificates += certs;
+ return true;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::addDefaultCaCertificate(const QSslCertificate &cert)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->caCertificates += cert;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::addDefaultCaCertificates(const QList<QSslCertificate> &certs)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ globalData()->config.detach();
+ globalData()->config->caCertificates += certs;
+}
+
+/*!
+ \internal
+*/
+QSslConfiguration QSslConfigurationPrivate::defaultConfiguration()
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ return QSslConfiguration(globalData()->config.data());
+}
+
+/*!
+ \internal
+*/
+void QSslConfigurationPrivate::setDefaultConfiguration(const QSslConfiguration &configuration)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ if (globalData()->config == configuration.d)
+ return; // nothing to do
+
+ globalData()->config = const_cast<QSslConfigurationPrivate*>(configuration.d.constData());
+}
+
+/*!
+ \internal
+*/
+void QSslConfigurationPrivate::deepCopyDefaultConfiguration(QSslConfigurationPrivate *ptr)
+{
+ QSslSocketPrivate::ensureInitialized();
+ QMutexLocker locker(&globalData()->mutex);
+ const QSslConfigurationPrivate *global = globalData()->config.constData();
+
+ if (!global) {
+ ptr = 0;
+ return;
+ }
+
+ ptr->ref = 1;
+ ptr->peerCertificate = global->peerCertificate;
+ ptr->peerCertificateChain = global->peerCertificateChain;
+ ptr->localCertificate = global->localCertificate;
+ ptr->privateKey = global->privateKey;
+ ptr->sessionCipher = global->sessionCipher;
+ ptr->ciphers = global->ciphers;
+ ptr->caCertificates = global->caCertificates;
+ ptr->protocol = global->protocol;
+ ptr->peerVerifyMode = global->peerVerifyMode;
+ ptr->peerVerifyDepth = global->peerVerifyDepth;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::createPlainSocket(QIODevice::OpenMode openMode)
+{
+ Q_Q(QSslSocket);
+ q->setOpenMode(openMode); // <- from QIODevice
+ q->setSocketState(QAbstractSocket::UnconnectedState);
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ q->setLocalPort(0);
+ q->setLocalAddress(QHostAddress());
+ q->setPeerPort(0);
+ q->setPeerAddress(QHostAddress());
+ q->setPeerName(QString());
+
+ plainSocket = new QTcpSocket(q);
+#ifndef QT_NO_BEARERMANAGEMENT
+ //copy network session down to the plain socket (if it has been set)
+ plainSocket->setProperty("_q_networksession", q->property("_q_networksession"));
+#endif
+ q->connect(plainSocket, SIGNAL(connected()),
+ q, SLOT(_q_connectedSlot()),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(hostFound()),
+ q, SLOT(_q_hostFoundSlot()),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(disconnected()),
+ q, SLOT(_q_disconnectedSlot()),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
+ q, SLOT(_q_stateChangedSlot(QAbstractSocket::SocketState)),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(error(QAbstractSocket::SocketError)),
+ q, SLOT(_q_errorSlot(QAbstractSocket::SocketError)),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(readyRead()),
+ q, SLOT(_q_readyReadSlot()),
+ Qt::DirectConnection);
+ q->connect(plainSocket, SIGNAL(bytesWritten(qint64)),
+ q, SLOT(_q_bytesWrittenSlot(qint64)),
+ Qt::DirectConnection);
+#ifndef QT_NO_NETWORKPROXY
+ q->connect(plainSocket, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)),
+ q, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
+#endif
+
+ readBuffer.clear();
+ writeBuffer.clear();
+ connectionEncrypted = false;
+ configuration.peerCertificate.clear();
+ configuration.peerCertificateChain.clear();
+ mode = QSslSocket::UnencryptedMode;
+ q->setReadBufferSize(readBufferMaxSize);
+}
+
+void QSslSocketPrivate::pauseSocketNotifiers(QSslSocket *socket)
+{
+ if (!socket->d_func()->plainSocket)
+ return;
+ QAbstractSocketPrivate::pauseSocketNotifiers(socket->d_func()->plainSocket);
+}
+
+void QSslSocketPrivate::resumeSocketNotifiers(QSslSocket *socket)
+{
+ if (!socket->d_func()->plainSocket)
+ return;
+ QAbstractSocketPrivate::resumeSocketNotifiers(socket->d_func()->plainSocket);
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_connectedSlot()
+{
+ Q_Q(QSslSocket);
+ q->setLocalPort(plainSocket->localPort());
+ q->setLocalAddress(plainSocket->localAddress());
+ q->setPeerPort(plainSocket->peerPort());
+ q->setPeerAddress(plainSocket->peerAddress());
+ q->setPeerName(plainSocket->peerName());
+ cachedSocketDescriptor = plainSocket->socketDescriptor();
+
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_connectedSlot()";
+ qDebug() << "\tstate =" << q->state();
+ qDebug() << "\tpeer =" << q->peerName() << q->peerAddress() << q->peerPort();
+ qDebug() << "\tlocal =" << QHostInfo::fromName(q->localAddress().toString()).hostName()
+ << q->localAddress() << q->localPort();
+#endif
+ emit q->connected();
+
+ if (autoStartHandshake) {
+ q->startClientEncryption();
+ } else if (pendingClose) {
+ pendingClose = false;
+ q->disconnectFromHost();
+ }
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_hostFoundSlot()
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_hostFoundSlot()";
+ qDebug() << "\tstate =" << q->state();
+#endif
+ emit q->hostFound();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_disconnectedSlot()
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_disconnectedSlot()";
+ qDebug() << "\tstate =" << q->state();
+#endif
+ disconnected();
+ emit q->disconnected();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_stateChangedSlot(QAbstractSocket::SocketState state)
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_stateChangedSlot(" << state << ')';
+#endif
+ q->setSocketState(state);
+ emit q->stateChanged(state);
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_errorSlot(QAbstractSocket::SocketError error)
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_errorSlot(" << error << ')';
+ qDebug() << "\tstate =" << q->state();
+ qDebug() << "\terrorString =" << q->errorString();
+#endif
+ q->setSocketError(plainSocket->error());
+ q->setErrorString(plainSocket->errorString());
+ emit q->error(error);
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_readyReadSlot()
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_readyReadSlot() -" << plainSocket->bytesAvailable() << "bytes available";
+#endif
+ if (mode == QSslSocket::UnencryptedMode) {
+ if (readyReadEmittedPointer)
+ *readyReadEmittedPointer = true;
+ emit q->readyRead();
+ return;
+ }
+
+ transmit();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_bytesWrittenSlot(qint64 written)
+{
+ Q_Q(QSslSocket);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocket::_q_bytesWrittenSlot(" << written << ')';
+#endif
+
+ if (mode == QSslSocket::UnencryptedMode)
+ emit q->bytesWritten(written);
+ else
+ emit q->encryptedBytesWritten(written);
+ if (state == QAbstractSocket::ClosingState && writeBuffer.isEmpty())
+ q->disconnectFromHost();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_flushWriteBuffer()
+{
+ Q_Q(QSslSocket);
+ if (!writeBuffer.isEmpty())
+ q->flush();
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::_q_flushReadBuffer()
+{
+ // trigger a read from the plainSocket into SSL
+ if (mode != QSslSocket::UnencryptedMode)
+ transmit();
+}
+
+/*!
+ \internal
+*/
+QList<QByteArray> QSslSocketPrivate::unixRootCertDirectories()
+{
+ return QList<QByteArray>() << "/etc/ssl/certs/" // (K)ubuntu, OpenSUSE, Mandriva, MeeGo ...
+ << "/usr/lib/ssl/certs/" // Gentoo, Mandrake
+ << "/usr/share/ssl/" // Centos, Redhat, SuSE
+ << "/usr/local/ssl/" // Normal OpenSSL Tarball
+ << "/var/ssl/certs/" // AIX
+ << "/usr/local/ssl/certs/" // Solaris
+ << "/opt/openssl/certs/"; // HP-UX
+}
+
+QT_END_NAMESPACE
+
+// For private slots
+#define d d_ptr
+#include "moc_qsslsocket.cpp"
diff --git a/src/network/ssl/qsslsocket.h b/src/network/ssl/qsslsocket.h
new file mode 100644
index 0000000000..648fd8c1d0
--- /dev/null
+++ b/src/network/ssl/qsslsocket.h
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLSOCKET_H
+#define QSSLSOCKET_H
+
+#include <QtCore/qlist.h>
+#include <QtCore/qregexp.h>
+#ifndef QT_NO_OPENSSL
+# include <QtNetwork/qtcpsocket.h>
+# include <QtNetwork/qsslerror.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Network)
+
+#ifndef QT_NO_OPENSSL
+
+class QDir;
+class QSslCipher;
+class QSslCertificate;
+class QSslConfiguration;
+
+class QSslSocketPrivate;
+class Q_NETWORK_EXPORT QSslSocket : public QTcpSocket
+{
+ Q_OBJECT
+public:
+ enum SslMode {
+ UnencryptedMode,
+ SslClientMode,
+ SslServerMode
+ };
+
+ enum PeerVerifyMode {
+ VerifyNone,
+ QueryPeer,
+ VerifyPeer,
+ AutoVerifyPeer
+ };
+
+ QSslSocket(QObject *parent = 0);
+ ~QSslSocket();
+
+ // 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);
+
+ // ### Qt 5: Make virtual
+ void setSocketOption(QAbstractSocket::SocketOption option, const QVariant &value);
+ QVariant socketOption(QAbstractSocket::SocketOption option);
+
+ SslMode mode() const;
+ bool isEncrypted() const;
+
+ QSsl::SslProtocol protocol() const;
+ void setProtocol(QSsl::SslProtocol protocol);
+
+ QSslSocket::PeerVerifyMode peerVerifyMode() const;
+ void setPeerVerifyMode(QSslSocket::PeerVerifyMode mode);
+
+ int peerVerifyDepth() const;
+ void setPeerVerifyDepth(int depth);
+
+ QString peerVerifyName() const;
+ void setPeerVerifyName(const QString &hostName);
+
+ // From QIODevice
+ qint64 bytesAvailable() const;
+ qint64 bytesToWrite() const;
+ bool canReadLine() const;
+ void close();
+ bool atEnd() const;
+ bool flush();
+ void abort();
+
+ // From QAbstractSocket:
+ void setReadBufferSize(qint64 size);
+
+ // Similar to QIODevice's:
+ qint64 encryptedBytesAvailable() const;
+ qint64 encryptedBytesToWrite() const;
+
+ // SSL configuration
+ QSslConfiguration sslConfiguration() const;
+ void setSslConfiguration(const QSslConfiguration &config);
+
+ // Certificate & cipher accessors.
+ void setLocalCertificate(const QSslCertificate &certificate);
+ void setLocalCertificate(const QString &fileName, QSsl::EncodingFormat format = QSsl::Pem);
+ QSslCertificate localCertificate() const;
+ QSslCertificate peerCertificate() const;
+ QList<QSslCertificate> peerCertificateChain() const;
+ QSslCipher sessionCipher() const;
+
+ // Private keys, for server sockets.
+ void setPrivateKey(const QSslKey &key);
+ void setPrivateKey(const QString &fileName, QSsl::KeyAlgorithm algorithm = QSsl::Rsa,
+ QSsl::EncodingFormat format = QSsl::Pem,
+ const QByteArray &passPhrase = QByteArray());
+ QSslKey privateKey() const;
+
+ // Cipher settings.
+ QList<QSslCipher> ciphers() const;
+ void setCiphers(const QList<QSslCipher> &ciphers);
+ void setCiphers(const QString &ciphers);
+ static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
+ static QList<QSslCipher> defaultCiphers();
+ static QList<QSslCipher> supportedCiphers();
+
+ // CA settings.
+ bool addCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
+ QRegExp::PatternSyntax syntax = QRegExp::FixedString);
+ void addCaCertificate(const QSslCertificate &certificate);
+ void addCaCertificates(const QList<QSslCertificate> &certificates);
+ void setCaCertificates(const QList<QSslCertificate> &certificates);
+ QList<QSslCertificate> caCertificates() const;
+ static bool addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat format = QSsl::Pem,
+ QRegExp::PatternSyntax syntax = QRegExp::FixedString);
+ static void addDefaultCaCertificate(const QSslCertificate &certificate);
+ static void addDefaultCaCertificates(const QList<QSslCertificate> &certificates);
+ static void setDefaultCaCertificates(const QList<QSslCertificate> &certificates);
+ static QList<QSslCertificate> defaultCaCertificates();
+ static QList<QSslCertificate> systemCaCertificates();
+
+ bool waitForConnected(int msecs = 30000);
+ bool waitForEncrypted(int msecs = 30000);
+ bool waitForReadyRead(int msecs = 30000);
+ bool waitForBytesWritten(int msecs = 30000);
+ bool waitForDisconnected(int msecs = 30000);
+
+ QList<QSslError> sslErrors() const;
+
+ static bool supportsSsl();
+ void ignoreSslErrors(const QList<QSslError> &errors);
+
+public Q_SLOTS:
+ void startClientEncryption();
+ void startServerEncryption();
+ void ignoreSslErrors();
+
+Q_SIGNALS:
+ void encrypted();
+ void peerVerifyError(const QSslError &error);
+ void sslErrors(const QList<QSslError> &errors);
+ void modeChanged(QSslSocket::SslMode newMode);
+ void encryptedBytesWritten(qint64 totalBytes);
+
+protected Q_SLOTS:
+ void connectToHostImplementation(const QString &hostName, quint16 port,
+ OpenMode openMode);
+ void disconnectFromHostImplementation();
+
+protected:
+ qint64 readData(char *data, qint64 maxlen);
+ qint64 writeData(const char *data, qint64 len);
+
+private:
+ Q_DECLARE_PRIVATE(QSslSocket)
+ Q_DISABLE_COPY(QSslSocket)
+ Q_PRIVATE_SLOT(d_func(), void _q_connectedSlot())
+ Q_PRIVATE_SLOT(d_func(), void _q_hostFoundSlot())
+ Q_PRIVATE_SLOT(d_func(), void _q_disconnectedSlot())
+ Q_PRIVATE_SLOT(d_func(), void _q_stateChangedSlot(QAbstractSocket::SocketState))
+ Q_PRIVATE_SLOT(d_func(), void _q_errorSlot(QAbstractSocket::SocketError))
+ Q_PRIVATE_SLOT(d_func(), void _q_readyReadSlot())
+ Q_PRIVATE_SLOT(d_func(), void _q_bytesWrittenSlot(qint64))
+ Q_PRIVATE_SLOT(d_func(), void _q_flushWriteBuffer())
+ Q_PRIVATE_SLOT(d_func(), void _q_flushReadBuffer())
+ friend class QSslSocketBackendPrivate;
+};
+
+#endif // QT_NO_OPENSSL
+
+QT_END_NAMESPACE
+
+#ifndef QT_NO_OPENSSL
+Q_DECLARE_METATYPE(QList<QSslError>)
+#endif
+
+QT_END_HEADER
+
+#endif
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp
new file mode 100644
index 0000000000..78a78a26f6
--- /dev/null
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -0,0 +1,1459 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#define QSSLSOCKET_DEBUG
+
+#include "qsslsocket_openssl_p.h"
+#include "qsslsocket_openssl_symbols_p.h"
+#include "qsslsocket.h"
+#include "qsslcertificate_p.h"
+#include "qsslcipher_p.h"
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qdiriterator.h>
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QLibrary> // for loading the security lib for the CA store
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+// Symbian does not seem to have the symbol for SNI defined
+#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
+#define SSL_CTRL_SET_TLSEXT_HOSTNAME 55
+#endif
+#endif
+QT_BEGIN_NAMESPACE
+
+#if defined(Q_OS_MAC)
+#define kSecTrustSettingsDomainSystem 2 // so we do not need to include the header file
+ PtrSecCertificateGetData QSslSocketPrivate::ptrSecCertificateGetData = 0;
+ PtrSecTrustSettingsCopyCertificates QSslSocketPrivate::ptrSecTrustSettingsCopyCertificates = 0;
+ PtrSecTrustCopyAnchorCertificates QSslSocketPrivate::ptrSecTrustCopyAnchorCertificates = 0;
+#elif defined(Q_OS_WIN)
+ PtrCertOpenSystemStoreW QSslSocketPrivate::ptrCertOpenSystemStoreW = 0;
+ PtrCertFindCertificateInStore QSslSocketPrivate::ptrCertFindCertificateInStore = 0;
+ PtrCertCloseStore QSslSocketPrivate::ptrCertCloseStore = 0;
+#elif defined(Q_OS_SYMBIAN)
+#include <e32base.h>
+#include <e32std.h>
+#include <e32debug.h>
+#include <QtCore/private/qcore_symbian_p.h>
+#endif
+
+bool QSslSocketPrivate::s_libraryLoaded = false;
+bool QSslSocketPrivate::s_loadedCiphersAndCerts = false;
+bool QSslSocketPrivate::s_loadRootCertsOnDemand = false;
+
+/* \internal
+
+ From OpenSSL's thread(3) manual page:
+
+ OpenSSL can safely be used in multi-threaded applications provided that at
+ least two callback functions are set.
+
+ locking_function(int mode, int n, const char *file, int line) is needed to
+ perform locking on shared data structures. (Note that OpenSSL uses a
+ number of global data structures that will be implicitly shared
+ when-whenever ever multiple threads use OpenSSL.) Multi-threaded
+ applications will crash at random if it is not set. ...
+ ...
+ id_function(void) is a function that returns a thread ID. It is not
+ needed on Windows nor on platforms where getpid() returns a different
+ ID for each thread (most notably Linux)
+*/
+class QOpenSslLocks
+{
+public:
+ inline QOpenSslLocks()
+ : initLocker(QMutex::Recursive),
+ locksLocker(QMutex::Recursive)
+ {
+ QMutexLocker locker(&locksLocker);
+ int numLocks = q_CRYPTO_num_locks();
+ locks = new QMutex *[numLocks];
+ memset(locks, 0, numLocks * sizeof(QMutex *));
+ }
+ inline ~QOpenSslLocks()
+ {
+ QMutexLocker locker(&locksLocker);
+ for (int i = 0; i < q_CRYPTO_num_locks(); ++i)
+ delete locks[i];
+ delete [] locks;
+
+ QSslSocketPrivate::deinitialize();
+ }
+ inline QMutex *lock(int num)
+ {
+ QMutexLocker locker(&locksLocker);
+ QMutex *tmp = locks[num];
+ if (!tmp)
+ tmp = locks[num] = new QMutex(QMutex::Recursive);
+ return tmp;
+ }
+
+ QMutex *globalLock()
+ {
+ return &locksLocker;
+ }
+
+ QMutex *initLock()
+ {
+ return &initLocker;
+ }
+
+private:
+ QMutex initLocker;
+ QMutex locksLocker;
+ QMutex **locks;
+};
+Q_GLOBAL_STATIC(QOpenSslLocks, openssl_locks)
+
+extern "C" {
+static void locking_function(int mode, int lockNumber, const char *, int)
+{
+ QMutex *mutex = openssl_locks()->lock(lockNumber);
+
+ // Lock or unlock it
+ if (mode & CRYPTO_LOCK)
+ mutex->lock();
+ else
+ mutex->unlock();
+}
+static unsigned long id_function()
+{
+ return (quintptr)QThread::currentThreadId();
+}
+} // extern "C"
+
+QSslSocketBackendPrivate::QSslSocketBackendPrivate()
+ : ssl(0),
+ ctx(0),
+ pkey(0),
+ readBio(0),
+ writeBio(0),
+ session(0)
+{
+ // Calls SSL_library_init().
+ ensureInitialized();
+}
+
+QSslSocketBackendPrivate::~QSslSocketBackendPrivate()
+{
+}
+
+QSslCipher QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher)
+{
+ QSslCipher ciph;
+
+ char buf [256];
+ QString descriptionOneLine = QString::fromLatin1(q_SSL_CIPHER_description(cipher, buf, sizeof(buf)));
+
+ QStringList descriptionList = descriptionOneLine.split(QLatin1String(" "), QString::SkipEmptyParts);
+ if (descriptionList.size() > 5) {
+ // ### crude code.
+ ciph.d->isNull = false;
+ ciph.d->name = descriptionList.at(0);
+
+ QString protoString = descriptionList.at(1);
+ ciph.d->protocolString = protoString;
+ ciph.d->protocol = QSsl::UnknownProtocol;
+ if (protoString == QLatin1String("SSLv3"))
+ ciph.d->protocol = QSsl::SslV3;
+ else if (protoString == QLatin1String("SSLv2"))
+ ciph.d->protocol = QSsl::SslV2;
+ else if (protoString == QLatin1String("TLSv1"))
+ ciph.d->protocol = QSsl::TlsV1;
+
+ if (descriptionList.at(2).startsWith(QLatin1String("Kx=")))
+ ciph.d->keyExchangeMethod = descriptionList.at(2).mid(3);
+ if (descriptionList.at(3).startsWith(QLatin1String("Au=")))
+ ciph.d->authenticationMethod = descriptionList.at(3).mid(3);
+ if (descriptionList.at(4).startsWith(QLatin1String("Enc=")))
+ ciph.d->encryptionMethod = descriptionList.at(4).mid(4);
+ ciph.d->exportable = (descriptionList.size() > 6 && descriptionList.at(6) == QLatin1String("export"));
+
+ ciph.d->bits = cipher->strength_bits;
+ ciph.d->supportedBits = cipher->alg_bits;
+
+ }
+ return ciph;
+}
+
+// ### This list is shared between all threads, and protected by a
+// mutex. Investigate using thread local storage instead.
+struct QSslErrorList
+{
+ QMutex mutex;
+ QList<QPair<int, int> > errors;
+};
+Q_GLOBAL_STATIC(QSslErrorList, _q_sslErrorList)
+static int q_X509Callback(int ok, X509_STORE_CTX *ctx)
+{
+ if (!ok) {
+ // Store the error and at which depth the error was detected.
+ _q_sslErrorList()->errors << qMakePair<int, int>(ctx->error, ctx->error_depth);
+ }
+ // Always return OK to allow verification to continue. We're handle the
+ // errors gracefully after collecting all errors, after verification has
+ // completed.
+ return 1;
+}
+
+bool QSslSocketBackendPrivate::initSslContext()
+{
+ Q_Q(QSslSocket);
+
+ // Create and initialize SSL context. Accept SSLv2, SSLv3 and TLSv1.
+ bool client = (mode == QSslSocket::SslClientMode);
+
+ bool reinitialized = false;
+init_context:
+ switch (configuration.protocol) {
+ case QSsl::SslV2:
+ ctx = q_SSL_CTX_new(client ? q_SSLv2_client_method() : q_SSLv2_server_method());
+ break;
+ case QSsl::SslV3:
+ ctx = q_SSL_CTX_new(client ? q_SSLv3_client_method() : q_SSLv3_server_method());
+ break;
+ case QSsl::SecureProtocols: // SslV2 will be disabled below
+ case QSsl::TlsV1SslV3: // SslV2 will be disabled below
+ case QSsl::AnyProtocol:
+ default:
+ ctx = q_SSL_CTX_new(client ? q_SSLv23_client_method() : q_SSLv23_server_method());
+ break;
+ case QSsl::TlsV1:
+ ctx = q_SSL_CTX_new(client ? q_TLSv1_client_method() : q_TLSv1_server_method());
+ break;
+ }
+ if (!ctx) {
+ // After stopping Flash 10 the SSL library looses its ciphers. Try re-adding them
+ // by re-initializing the library.
+ if (!reinitialized) {
+ reinitialized = true;
+ if (q_SSL_library_init() == 1)
+ goto init_context;
+ }
+
+ // ### Bad error code
+ q->setErrorString(QSslSocket::tr("Error creating SSL context (%1)").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ // Enable all bug workarounds.
+ if (configuration.protocol == QSsl::TlsV1SslV3 || configuration.protocol == QSsl::SecureProtocols) {
+ q_SSL_CTX_set_options(ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
+ } else {
+ q_SSL_CTX_set_options(ctx, SSL_OP_ALL);
+ }
+
+ // Initialize ciphers
+ QByteArray cipherString;
+ int first = true;
+ QList<QSslCipher> ciphers = configuration.ciphers;
+ if (ciphers.isEmpty())
+ ciphers = defaultCiphers();
+ foreach (const QSslCipher &cipher, ciphers) {
+ if (first)
+ first = false;
+ else
+ cipherString.append(':');
+ cipherString.append(cipher.name().toLatin1());
+ }
+
+ if (!q_SSL_CTX_set_cipher_list(ctx, cipherString.data())) {
+ // ### Bad error code
+ q->setErrorString(QSslSocket::tr("Invalid or empty cipher list (%1)").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ // Add all our CAs to this store.
+ QList<QSslCertificate> expiredCerts;
+ foreach (const QSslCertificate &caCertificate, q->caCertificates()) {
+ // add expired certs later, so that the
+ // valid ones are used before the expired ones
+ if (! caCertificate.isValid()) {
+ expiredCerts.append(caCertificate);
+ } else {
+ q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
+ }
+ }
+
+ bool addExpiredCerts = true;
+#if defined(Q_OS_MAC) && (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5)
+ //On Leopard SSL does not work if we add the expired certificates.
+ if (QSysInfo::MacintoshVersion == QSysInfo::MV_10_5)
+ addExpiredCerts = false;
+#endif
+ // now add the expired certs
+ if (addExpiredCerts) {
+ foreach (const QSslCertificate &caCertificate, expiredCerts) {
+ q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
+ }
+ }
+
+ if (s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) {
+ // tell OpenSSL the directories where to look up the root certs on demand
+ QList<QByteArray> unixDirs = unixRootCertDirectories();
+ for (int a = 0; a < unixDirs.count(); ++a)
+ q_SSL_CTX_load_verify_locations(ctx, 0, unixDirs.at(a).constData());
+ }
+
+ // Register a custom callback to get all verification errors.
+ X509_STORE_set_verify_cb_func(ctx->cert_store, q_X509Callback);
+
+ if (!configuration.localCertificate.isNull()) {
+ // Require a private key as well.
+ if (configuration.privateKey.isNull()) {
+ q->setErrorString(QSslSocket::tr("Cannot provide a certificate with no key, %1").arg(getErrorsFromOpenSsl()));
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ // Load certificate
+ if (!q_SSL_CTX_use_certificate(ctx, (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 (!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;
+ }
+
+ // Check if the certificate matches the private key.
+ if (!q_SSL_CTX_check_private_key(ctx)) {
+ q->setErrorString(QSslSocket::tr("Private key does not certify public key, %1").arg(getErrorsFromOpenSsl()));
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+ }
+
+ // Initialize peer verification.
+ if (configuration.peerVerifyMode == QSslSocket::VerifyNone) {
+ q_SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
+ } else {
+ q_SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, q_X509Callback);
+ }
+
+ // Set verification depth.
+ if (configuration.peerVerifyDepth != 0)
+ q_SSL_CTX_set_verify_depth(ctx, configuration.peerVerifyDepth);
+
+ // Create and initialize SSL session
+ if (!(ssl = q_SSL_new(ctx))) {
+ // ### Bad error code
+ q->setErrorString(QSslSocket::tr("Error creating SSL session, %1").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+ if ((configuration.protocol == QSsl::TlsV1SslV3 ||
+ configuration.protocol == QSsl::TlsV1 ||
+ configuration.protocol == QSsl::SecureProtocols ||
+ configuration.protocol == QSsl::AnyProtocol) &&
+ client && q_SSLeay() >= 0x00090806fL) {
+ // Set server hostname on TLS extension. RFC4366 section 3.1 requires it in ACE format.
+ QString tlsHostName = verificationPeerName.isEmpty() ? q->peerName() : verificationPeerName;
+ if (tlsHostName.isEmpty())
+ tlsHostName = hostName;
+ QByteArray ace = QUrl::toAce(tlsHostName);
+ // only send the SNI header if the URL is valid and not an IP
+ if (!ace.isEmpty() && !QHostAddress().setAddress(tlsHostName)) {
+ if (!q_SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, ace.constData()))
+ qWarning("could not set SSL_CTRL_SET_TLSEXT_HOSTNAME, Server Name Indication disabled");
+ }
+ }
+#endif
+
+ // Clear the session.
+ q_SSL_clear(ssl);
+ errorList.clear();
+
+ // Initialize memory BIOs for encryption and decryption.
+ readBio = q_BIO_new(q_BIO_s_mem());
+ writeBio = q_BIO_new(q_BIO_s_mem());
+ if (!readBio || !writeBio) {
+ // ### Bad error code
+ q->setErrorString(QSslSocket::tr("Error creating SSL session: %1").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ // Assign the bios.
+ q_SSL_set_bio(ssl, readBio, writeBio);
+
+ if (mode == QSslSocket::SslClientMode)
+ q_SSL_set_connect_state(ssl);
+ else
+ q_SSL_set_accept_state(ssl);
+
+ return true;
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::deinitialize()
+{
+ q_CRYPTO_set_id_callback(0);
+ q_CRYPTO_set_locking_callback(0);
+}
+
+/*!
+ \internal
+
+ Does the minimum amount of initialization to determine whether SSL
+ is supported or not.
+*/
+
+bool QSslSocketPrivate::supportsSsl()
+{
+ return ensureLibraryLoaded();
+}
+
+bool QSslSocketPrivate::ensureLibraryLoaded()
+{
+ if (!q_resolveOpenSslSymbols())
+ return false;
+
+ // Check if the library itself needs to be initialized.
+ QMutexLocker locker(openssl_locks()->initLock());
+ if (!s_libraryLoaded) {
+ s_libraryLoaded = true;
+
+ // Initialize OpenSSL.
+ q_CRYPTO_set_id_callback(id_function);
+ q_CRYPTO_set_locking_callback(locking_function);
+ if (q_SSL_library_init() != 1)
+ return false;
+ q_SSL_load_error_strings();
+ q_OpenSSL_add_all_algorithms();
+
+ // Initialize OpenSSL's random seed.
+ if (!q_RAND_status()) {
+ struct {
+ int msec;
+ int sec;
+ void *stack;
+ } randomish;
+
+ int attempts = 500;
+ do {
+ if (attempts < 500) {
+#ifdef Q_OS_UNIX
+ struct timespec ts = {0, 33333333};
+ nanosleep(&ts, 0);
+#else
+ Sleep(3);
+#endif
+ randomish.msec = attempts;
+ }
+ randomish.stack = (void *)&randomish;
+ randomish.msec = QTime::currentTime().msec();
+ randomish.sec = QTime::currentTime().second();
+ q_RAND_seed((const char *)&randomish, sizeof(randomish));
+ } while (!q_RAND_status() && --attempts);
+ if (!attempts)
+ return false;
+ }
+ }
+ return true;
+}
+
+void QSslSocketPrivate::ensureCiphersAndCertsLoaded()
+{
+ QMutexLocker locker(openssl_locks()->initLock());
+ if (s_loadedCiphersAndCerts)
+ return;
+ s_loadedCiphersAndCerts = true;
+
+ resetDefaultCiphers();
+
+ //load symbols needed to receive certificates from system store
+#if defined(Q_OS_MAC)
+ QLibrary securityLib("/System/Library/Frameworks/Security.framework/Versions/Current/Security");
+ if (securityLib.load()) {
+ ptrSecCertificateGetData = (PtrSecCertificateGetData) securityLib.resolve("SecCertificateGetData");
+ if (!ptrSecCertificateGetData)
+ qWarning("could not resolve symbols in security library"); // should never happen
+
+ ptrSecTrustSettingsCopyCertificates = (PtrSecTrustSettingsCopyCertificates) securityLib.resolve("SecTrustSettingsCopyCertificates");
+ if (!ptrSecTrustSettingsCopyCertificates) { // method was introduced in Leopard, use legacy method if it's not there
+ ptrSecTrustCopyAnchorCertificates = (PtrSecTrustCopyAnchorCertificates) securityLib.resolve("SecTrustCopyAnchorCertificates");
+ if (!ptrSecTrustCopyAnchorCertificates)
+ qWarning("could not resolve symbols in security library"); // should never happen
+ }
+ } else {
+ qWarning("could not load security library");
+ }
+#elif defined(Q_OS_WIN)
+ HINSTANCE hLib = LoadLibraryW(L"Crypt32");
+ if (hLib) {
+#if defined(Q_OS_WINCE)
+ ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, L"CertOpenStore");
+ ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, L"CertFindCertificateInStore");
+ ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, L"CertCloseStore");
+#else
+ ptrCertOpenSystemStoreW = (PtrCertOpenSystemStoreW)GetProcAddress(hLib, "CertOpenSystemStoreW");
+ ptrCertFindCertificateInStore = (PtrCertFindCertificateInStore)GetProcAddress(hLib, "CertFindCertificateInStore");
+ ptrCertCloseStore = (PtrCertCloseStore)GetProcAddress(hLib, "CertCloseStore");
+#endif
+ if (!ptrCertOpenSystemStoreW || !ptrCertFindCertificateInStore || !ptrCertCloseStore)
+ qWarning("could not resolve symbols in crypt32 library"); // should never happen
+ } else {
+ qWarning("could not load crypt32 library"); // should never happen
+ }
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN) && !defined(Q_OS_MAC)
+ // check whether we can enable on-demand root-cert loading (i.e. check whether the sym links are there)
+ QList<QByteArray> dirs = unixRootCertDirectories();
+ QStringList symLinkFilter;
+ symLinkFilter << QLatin1String("[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].[0-9]");
+ for (int a = 0; a < dirs.count(); ++a) {
+ QDirIterator iterator(QLatin1String(dirs.at(a)), symLinkFilter, QDir::Files);
+ if (iterator.hasNext()) {
+ s_loadRootCertsOnDemand = true;
+ break;
+ }
+ }
+#endif
+ // if on-demand loading was not enabled, load the certs now
+ if (!s_loadRootCertsOnDemand)
+ setDefaultCaCertificates(systemCaCertificates());
+}
+
+/*!
+ \internal
+
+ Declared static in QSslSocketPrivate, makes sure the SSL libraries have
+ been initialized.
+*/
+
+void QSslSocketPrivate::ensureInitialized()
+{
+ if (!supportsSsl())
+ return;
+
+ ensureCiphersAndCertsLoaded();
+}
+
+/*!
+ \internal
+
+ Declared static in QSslSocketPrivate, backend-dependent loading of
+ application-wide global ciphers.
+*/
+void QSslSocketPrivate::resetDefaultCiphers()
+{
+ SSL_CTX *myCtx = q_SSL_CTX_new(q_SSLv23_client_method());
+ SSL *mySsl = q_SSL_new(myCtx);
+
+ QList<QSslCipher> ciphers;
+
+ STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(mySsl);
+ for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {
+ if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {
+ if (cipher->valid) {
+ QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher);
+ if (!ciph.isNull()) {
+ if (!ciph.name().toLower().startsWith(QLatin1String("adh")))
+ ciphers << ciph;
+ }
+ }
+ }
+ }
+
+ q_SSL_CTX_free(myCtx);
+ q_SSL_free(mySsl);
+
+ setDefaultSupportedCiphers(ciphers);
+ setDefaultCiphers(ciphers);
+}
+
+#if defined(Q_OS_SYMBIAN)
+
+CSymbianCertificateRetriever::CSymbianCertificateRetriever() : CActive(CActive::EPriorityStandard),
+ iCertificatePtr(0,0,0), iSequenceError(KErrNone)
+{
+}
+
+CSymbianCertificateRetriever::~CSymbianCertificateRetriever()
+{
+ iThread.Close();
+}
+
+CSymbianCertificateRetriever* CSymbianCertificateRetriever::NewL()
+{
+ CSymbianCertificateRetriever* self = new (ELeave) CSymbianCertificateRetriever();
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop();
+ return self;
+}
+
+int CSymbianCertificateRetriever::GetCertificates(QList<QByteArray> &certificates)
+{
+ iCertificates = &certificates;
+
+ TRequestStatus status;
+ iThread.Logon(status);
+ iThread.Resume();
+ User::WaitForRequest(status);
+ if (iThread.ExitType() == EExitKill)
+ return KErrDied;
+ else
+ return status.Int(); // Logon() completes with the thread's exit value
+}
+
+void CSymbianCertificateRetriever::doThreadEntryL()
+{
+ CActiveScheduler* activeScheduler = new (ELeave) CActiveScheduler;
+ CleanupStack::PushL(activeScheduler);
+ CActiveScheduler::Install(activeScheduler);
+
+ CActiveScheduler::Add(this);
+
+ // These aren't deleted in the destructor so leaving the to CS is ok
+ iCertStore = CUnifiedCertStore::NewLC(qt_s60GetRFs(), EFalse);
+ iCertFilter = CCertAttributeFilter::NewLC();
+
+ // only interested in CA certs
+ iCertFilter->SetOwnerType(ECACertificate);
+ // only interested in X.509 format (we don't support WAP formats)
+ iCertFilter->SetFormat(EX509Certificate);
+
+ // Kick off the sequence by initializing the cert store
+ iState = Initializing;
+ iCertStore->Initialize(iStatus);
+ SetActive();
+
+ CActiveScheduler::Start();
+
+ // Sequence complete, clean up
+
+ // These MUST be cleaned up before the installed CActiveScheduler is destroyed and can't be left to the
+ // destructor of CSymbianCertificateRetriever. Otherwise the destructor of CActiveScheduler will get
+ // stuck.
+ iCertInfos.Close();
+ CleanupStack::PopAndDestroy(3); // activeScheduler, iCertStore, iCertFilter
+}
+
+
+TInt CSymbianCertificateRetriever::ThreadEntryPoint(TAny* aParams)
+{
+ User::SetCritical(User::EProcessCritical);
+ CTrapCleanup* cleanupStack = CTrapCleanup::New();
+
+ CSymbianCertificateRetriever* self = (CSymbianCertificateRetriever*) aParams;
+ TRAPD(err, self->doThreadEntryL());
+ delete cleanupStack;
+
+ // doThreadEntryL() can leave only before the retrieval sequence is started
+ if (err)
+ return err;
+ else
+ return self->iSequenceError; // return any error that occurred during the retrieval
+}
+
+void CSymbianCertificateRetriever::ConstructL()
+{
+ TInt err;
+ int i=0;
+ QString name(QLatin1String("CertWorkerThread-%1"));
+ //recently closed thread names remain in use for a while until all handles have been closed
+ //including users of RUndertaker
+ do {
+ err = iThread.Create(qt_QString2TPtrC(name.arg(i++)),
+ CSymbianCertificateRetriever::ThreadEntryPoint, 16384, NULL, this);
+ } while (err == KErrAlreadyExists);
+ User::LeaveIfError(err);
+}
+
+void CSymbianCertificateRetriever::DoCancel()
+{
+ switch(iState) {
+ case Initializing:
+ iCertStore->CancelInitialize();
+ break;
+ case Listing:
+ iCertStore->CancelList();
+ break;
+ case RetrievingCertificates:
+ iCertStore->CancelGetCert();
+ break;
+ }
+}
+
+TInt CSymbianCertificateRetriever::RunError(TInt aError)
+{
+ // If something goes wrong in the sequence, abort the sequence
+ iSequenceError = aError; // this gets reported to the client in the TRequestStatus
+ CActiveScheduler::Stop();
+ return KErrNone;
+}
+
+void CSymbianCertificateRetriever::GetCertificateL()
+{
+ if (iCurrentCertIndex < iCertInfos.Count()) {
+ CCTCertInfo* certInfo = iCertInfos[iCurrentCertIndex++];
+ iCertificateData = QByteArray();
+ QT_TRYCATCH_LEAVING(iCertificateData.resize(certInfo->Size()));
+ iCertificatePtr.Set((TUint8*)iCertificateData.data(), 0, iCertificateData.size());
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "getting " << qt_TDesC2QString(certInfo->Label()) << " size=" << certInfo->Size();
+ qDebug() << "format=" << certInfo->CertificateFormat();
+ qDebug() << "ownertype=" << certInfo->CertificateOwnerType();
+ qDebug() << "type=" << hex << certInfo->Type().iUid;
+#endif
+ iCertStore->Retrieve(*certInfo, iCertificatePtr, iStatus);
+ iState = RetrievingCertificates;
+ SetActive();
+ } else {
+ //reached end of list
+ CActiveScheduler::Stop();
+ }
+}
+
+void CSymbianCertificateRetriever::RunL()
+{
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "CSymbianCertificateRetriever::RunL status " << iStatus.Int() << " count " << iCertInfos.Count() << " index " << iCurrentCertIndex;
+#endif
+ switch (iState) {
+ case Initializing:
+ User::LeaveIfError(iStatus.Int()); // initialise fail means pointless to continue
+ iState = Listing;
+ iCertStore->List(iCertInfos, *iCertFilter, iStatus);
+ SetActive();
+ break;
+
+ case Listing:
+ User::LeaveIfError(iStatus.Int()); // listing fail means pointless to continue
+ iCurrentCertIndex = 0;
+ GetCertificateL();
+ break;
+
+ case RetrievingCertificates:
+ if (iStatus.Int() == KErrNone)
+ iCertificates->append(iCertificateData);
+ else
+ qWarning() << "CSymbianCertificateRetriever: failed to retrieve a certificate, error " << iStatus.Int();
+ GetCertificateL();
+ break;
+ }
+}
+#endif // defined(Q_OS_SYMBIAN)
+
+QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
+{
+ ensureInitialized();
+#ifdef QSSLSOCKET_DEBUG
+ QElapsedTimer timer;
+ timer.start();
+#endif
+ QList<QSslCertificate> systemCerts;
+#if defined(Q_OS_MAC)
+ CFArrayRef cfCerts;
+ OSStatus status = 1;
+
+ OSStatus SecCertificateGetData (
+ SecCertificateRef certificate,
+ CSSM_DATA_PTR data
+ );
+
+ if (ptrSecCertificateGetData) {
+ if (ptrSecTrustSettingsCopyCertificates)
+ status = ptrSecTrustSettingsCopyCertificates(kSecTrustSettingsDomainSystem, &cfCerts);
+ else if (ptrSecTrustCopyAnchorCertificates)
+ status = ptrSecTrustCopyAnchorCertificates(&cfCerts);
+ if (!status) {
+ CFIndex size = CFArrayGetCount(cfCerts);
+ for (CFIndex i = 0; i < size; ++i) {
+ SecCertificateRef cfCert = (SecCertificateRef)CFArrayGetValueAtIndex(cfCerts, i);
+ CSSM_DATA data;
+ CSSM_DATA_PTR dataPtr = &data;
+ if (ptrSecCertificateGetData(cfCert, dataPtr)) {
+ qWarning("error retrieving a CA certificate from the system store");
+ } else {
+ int len = data.Length;
+ char *rawData = reinterpret_cast<char *>(data.Data);
+ QByteArray rawCert(rawData, len);
+ systemCerts.append(QSslCertificate::fromData(rawCert, QSsl::Der));
+ }
+ }
+ CFRelease(cfCerts);
+ }
+ else {
+ // no detailed error handling here
+ qWarning("could not retrieve system CA certificates");
+ }
+ }
+#elif defined(Q_OS_WIN)
+ if (ptrCertOpenSystemStoreW && ptrCertFindCertificateInStore && ptrCertCloseStore) {
+ HCERTSTORE hSystemStore;
+#if defined(Q_OS_WINCE)
+ hSystemStore = ptrCertOpenSystemStoreW(CERT_STORE_PROV_SYSTEM_W,
+ 0,
+ 0,
+ CERT_STORE_NO_CRYPT_RELEASE_FLAG|CERT_SYSTEM_STORE_CURRENT_USER,
+ L"ROOT");
+#else
+ hSystemStore = ptrCertOpenSystemStoreW(0, L"ROOT");
+#endif
+ if(hSystemStore) {
+ PCCERT_CONTEXT pc = NULL;
+ while(1) {
+ pc = ptrCertFindCertificateInStore( hSystemStore, X509_ASN_ENCODING, 0, CERT_FIND_ANY, NULL, pc);
+ if(!pc)
+ break;
+ QByteArray der((const char *)(pc->pbCertEncoded), static_cast<int>(pc->cbCertEncoded));
+ QSslCertificate cert(der, QSsl::Der);
+ systemCerts.append(cert);
+ }
+ ptrCertCloseStore(hSystemStore, 0);
+ }
+ }
+#elif defined(Q_OS_UNIX) && !defined(Q_OS_SYMBIAN)
+ QSet<QString> certFiles;
+ QList<QByteArray> directories = unixRootCertDirectories();
+ QDir currentDir;
+ QStringList nameFilters;
+ nameFilters << QLatin1String("*.pem") << QLatin1String("*.crt");
+ currentDir.setNameFilters(nameFilters);
+ for (int a = 0; a < directories.count(); a++) {
+ currentDir.setPath(QLatin1String(directories.at(a)));
+ QDirIterator it(currentDir);
+ while(it.hasNext()) {
+ it.next();
+ // use canonical path here to not load the same certificate twice if symlinked
+ certFiles.insert(it.fileInfo().canonicalFilePath());
+ }
+ }
+ QSetIterator<QString> it(certFiles);
+ while(it.hasNext()) {
+ systemCerts.append(QSslCertificate::fromPath(it.next()));
+ }
+ systemCerts.append(QSslCertificate::fromPath(QLatin1String("/etc/pki/tls/certs/ca-bundle.crt"), QSsl::Pem)); // Fedora, Mandriva
+ systemCerts.append(QSslCertificate::fromPath(QLatin1String("/usr/local/share/certs/ca-root-nss.crt"), QSsl::Pem)); // FreeBSD's ca_root_nss
+
+#elif defined(Q_OS_SYMBIAN)
+ QList<QByteArray> certs;
+ QScopedPointer<CSymbianCertificateRetriever> retriever(CSymbianCertificateRetriever::NewL());
+
+ retriever->GetCertificates(certs);
+ foreach (const QByteArray &encodedCert, certs) {
+ QSslCertificate cert(encodedCert, QSsl::Der);
+ if (!cert.isNull()) {
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "imported certificate: " << cert.issuerInfo(QSslCertificate::CommonName);
+#endif
+ systemCerts.append(cert);
+ }
+ }
+#endif
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "systemCaCertificates retrieval time " << timer.elapsed() << "ms";
+ qDebug() << "imported " << systemCerts.count() << " certificates";
+#endif
+
+ return systemCerts;
+}
+
+void QSslSocketBackendPrivate::startClientEncryption()
+{
+ if (!initSslContext()) {
+ // ### report error: internal OpenSSL failure
+ return;
+ }
+
+ // Start connecting. This will place outgoing data in the BIO, so we
+ // follow up with calling transmit().
+ startHandshake();
+ transmit();
+}
+
+void QSslSocketBackendPrivate::startServerEncryption()
+{
+ if (!initSslContext()) {
+ // ### report error: internal OpenSSL failure
+ return;
+ }
+
+ // Start connecting. This will place outgoing data in the BIO, so we
+ // follow up with calling transmit().
+ startHandshake();
+ transmit();
+}
+
+/*!
+ \internal
+
+ Transmits encrypted data between the BIOs and the socket.
+*/
+void QSslSocketBackendPrivate::transmit()
+{
+ Q_Q(QSslSocket);
+
+ // If we don't have any SSL context, don't bother transmitting.
+ if (!ssl)
+ return;
+
+ bool transmitting;
+ do {
+ transmitting = false;
+
+ // If the connection is secure, we can transfer data from the write
+ // buffer (in plain text) to the write BIO through SSL_write.
+ if (connectionEncrypted && !writeBuffer.isEmpty()) {
+ qint64 totalBytesWritten = 0;
+ int nextDataBlockSize;
+ while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {
+ int writtenBytes = q_SSL_write(ssl, writeBuffer.readPointer(), nextDataBlockSize);
+ if (writtenBytes <= 0) {
+ // ### Better error handling.
+ q->setErrorString(QSslSocket::tr("Unable to write data: %1").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return;
+ }
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: encrypted" << writtenBytes << "bytes";
+#endif
+ writeBuffer.free(writtenBytes);
+ totalBytesWritten += writtenBytes;
+
+ if (writtenBytes < nextDataBlockSize) {
+ // break out of the writing loop and try again after we had read
+ transmitting = true;
+ break;
+ }
+ }
+
+ if (totalBytesWritten > 0) {
+ // Don't emit bytesWritten() recursively.
+ if (!emittedBytesWritten) {
+ emittedBytesWritten = true;
+ emit q->bytesWritten(totalBytesWritten);
+ emittedBytesWritten = false;
+ }
+ }
+ }
+
+ // Check if we've got any data to be written to the socket.
+ QVarLengthArray<char, 4096> data;
+ int pendingBytes;
+ while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0) {
+ // Read encrypted data from the write BIO into a buffer.
+ data.resize(pendingBytes);
+ int encryptedBytesRead = q_BIO_read(writeBio, data.data(), pendingBytes);
+
+ // Write encrypted data from the buffer to the socket.
+ plainSocket->write(data.constData(), encryptedBytesRead);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: wrote" << encryptedBytesRead << "encrypted bytes to the socket";
+#endif
+ transmitting = true;
+ }
+
+ // Check if we've got any data to be read from the socket.
+ if (!connectionEncrypted || !readBufferMaxSize || readBuffer.size() < readBufferMaxSize)
+ while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {
+ // Read encrypted data from the socket into a buffer.
+ data.resize(pendingBytes);
+ // just peek() here because q_BIO_write could write less data than expected
+ int encryptedBytesRead = plainSocket->peek(data.data(), pendingBytes);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: read" << encryptedBytesRead << "encrypted bytes from the socket";
+#endif
+ // Write encrypted data from the buffer into the read BIO.
+ int writtenToBio = q_BIO_write(readBio, data.constData(), encryptedBytesRead);
+
+ // do the actual read() here and throw away the results.
+ if (writtenToBio > 0) {
+ // ### TODO: make this cheaper by not making it memcpy. E.g. make it work with data=0x0 or make it work with seek
+ plainSocket->read(data.data(), writtenToBio);
+ } else {
+ // ### Better error handling.
+ q->setErrorString(QSslSocket::tr("Unable to decrypt data: %1").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return;
+ }
+
+ transmitting = true;
+ }
+
+ // If the connection isn't secured yet, this is the time to retry the
+ // connect / accept.
+ if (!connectionEncrypted) {
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: testing encryption";
+#endif
+ if (startHandshake()) {
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: encryption established";
+#endif
+ connectionEncrypted = true;
+ transmitting = true;
+ } else if (plainSocket->state() != QAbstractSocket::ConnectedState) {
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: connection lost";
+#endif
+ break;
+ } else {
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: encryption not done yet";
+#endif
+ }
+ }
+
+ // If the request is small and the remote host closes the transmission
+ // after sending, there's a chance that startHandshake() will already
+ // have triggered a shutdown.
+ if (!ssl)
+ continue;
+
+ // We always read everything from the SSL decryption buffers, even if
+ // we have a readBufferMaxSize. There's no point in leaving data there
+ // just so that readBuffer.size() == readBufferMaxSize.
+ int readBytes = 0;
+ data.resize(4096);
+ ::memset(data.data(), 0, data.size());
+ do {
+ // Don't use SSL_pending(). It's very unreliable.
+ if ((readBytes = q_SSL_read(ssl, data.data(), data.size())) > 0) {
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: decrypted" << readBytes << "bytes";
+#endif
+ char *ptr = readBuffer.reserve(readBytes);
+ ::memcpy(ptr, data.data(), readBytes);
+
+ if (readyReadEmittedPointer)
+ *readyReadEmittedPointer = true;
+ emit q->readyRead();
+ transmitting = true;
+ continue;
+ }
+
+ // Error.
+ switch (q_SSL_get_error(ssl, readBytes)) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ // Out of data.
+ break;
+ case SSL_ERROR_ZERO_RETURN:
+ // The remote host closed the connection.
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: remote disconnect";
+#endif
+ plainSocket->disconnectFromHost();
+ break;
+ case SSL_ERROR_SYSCALL: // some IO error
+ case SSL_ERROR_SSL: // error in the SSL library
+ // we do not know exactly what the error is, nor whether we can recover from it,
+ // so just return to prevent an endless loop in the outer "while" statement
+ q->setErrorString(QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return;
+ default:
+ // SSL_ERROR_WANT_CONNECT, SSL_ERROR_WANT_ACCEPT: can only happen with a
+ // BIO_s_connect() or BIO_s_accept(), which we do not call.
+ // SSL_ERROR_WANT_X509_LOOKUP: can only happen with a
+ // SSL_CTX_set_client_cert_cb(), which we do not call.
+ // So this default case should never be triggered.
+ q->setErrorString(QSslSocket::tr("Error while reading: %1").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ break;
+ }
+ } while (ssl && readBytes > 0);
+ } while (ssl && ctx && transmitting);
+}
+
+static QSslError _q_OpenSSL_to_QSslError(int errorCode, const QSslCertificate &cert)
+{
+ QSslError error;
+ switch (errorCode) {
+ case X509_V_OK:
+ // X509_V_OK is also reported if the peer had no certificate.
+ break;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ error = QSslError(QSslError::UnableToGetIssuerCertificate, cert); break;
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ error = QSslError(QSslError::UnableToDecryptCertificateSignature, cert); break;
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ error = QSslError(QSslError::UnableToDecodeIssuerPublicKey, cert); break;
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ error = QSslError(QSslError::CertificateSignatureFailed, cert); break;
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ error = QSslError(QSslError::CertificateNotYetValid, cert); break;
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ error = QSslError(QSslError::CertificateExpired, cert); break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ error = QSslError(QSslError::InvalidNotBeforeField, cert); break;
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ error = QSslError(QSslError::InvalidNotAfterField, cert); break;
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ error = QSslError(QSslError::SelfSignedCertificate, cert); break;
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ error = QSslError(QSslError::SelfSignedCertificateInChain, cert); break;
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ error = QSslError(QSslError::UnableToGetLocalIssuerCertificate, cert); break;
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ error = QSslError(QSslError::UnableToVerifyFirstCertificate, cert); break;
+ case X509_V_ERR_CERT_REVOKED:
+ error = QSslError(QSslError::CertificateRevoked, cert); break;
+ case X509_V_ERR_INVALID_CA:
+ error = QSslError(QSslError::InvalidCaCertificate, cert); break;
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ error = QSslError(QSslError::PathLengthExceeded, cert); break;
+ case X509_V_ERR_INVALID_PURPOSE:
+ error = QSslError(QSslError::InvalidPurpose, cert); break;
+ case X509_V_ERR_CERT_UNTRUSTED:
+ error = QSslError(QSslError::CertificateUntrusted, cert); break;
+ case X509_V_ERR_CERT_REJECTED:
+ error = QSslError(QSslError::CertificateRejected, cert); break;
+ default:
+ error = QSslError(QSslError::UnspecifiedError, cert); break;
+ }
+ return error;
+}
+
+bool QSslSocketBackendPrivate::startHandshake()
+{
+ Q_Q(QSslSocket);
+
+ // Check if the connection has been established. Get all errors from the
+ // verification stage.
+ _q_sslErrorList()->mutex.lock();
+ _q_sslErrorList()->errors.clear();
+ int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl);
+
+ const QList<QPair<int, int> > &lastErrors = _q_sslErrorList()->errors;
+ for (int i = 0; i < lastErrors.size(); ++i) {
+ const QPair<int, int> &currentError = lastErrors.at(i);
+ // Initialize the peer certificate chain in order to find which certificate caused this error
+ if (configuration.peerCertificateChain.isEmpty())
+ configuration.peerCertificateChain = STACKOFX509_to_QSslCertificates(q_SSL_get_peer_cert_chain(ssl));
+ emit q->peerVerifyError(_q_OpenSSL_to_QSslError(currentError.first,
+ configuration.peerCertificateChain.value(currentError.second)));
+ if (q->state() != QAbstractSocket::ConnectedState)
+ break;
+ }
+
+ errorList << lastErrors;
+ _q_sslErrorList()->mutex.unlock();
+
+ // Connection aborted during handshake phase.
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+
+ // Check if we're encrypted or not.
+ if (result <= 0) {
+ switch (q_SSL_get_error(ssl, result)) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ // The handshake is not yet complete.
+ break;
+ default:
+ q->setErrorString(QSslSocket::tr("Error during SSL handshake: %1").arg(getErrorsFromOpenSsl()));
+ q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::startHandshake: error!" << q->errorString();
+#endif
+ emit q->error(QAbstractSocket::SslHandshakeFailedError);
+ q->abort();
+ }
+ return false;
+ }
+
+ // Store the peer certificate and chain. For clients, the peer certificate
+ // chain includes the peer certificate; for servers, it doesn't. Both the
+ // peer certificate and the chain may be empty if the peer didn't present
+ // any certificate.
+ if (configuration.peerCertificateChain.isEmpty())
+ configuration.peerCertificateChain = STACKOFX509_to_QSslCertificates(q_SSL_get_peer_cert_chain(ssl));
+ X509 *x509 = q_SSL_get_peer_certificate(ssl);
+ configuration.peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);
+ q_X509_free(x509);
+
+ // Start translating errors.
+ QList<QSslError> errors;
+
+ if (QSslCertificatePrivate::isBlacklisted(configuration.peerCertificate)) {
+ QSslError error(QSslError::CertificateBlacklisted, configuration.peerCertificate);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+
+ bool doVerifyPeer = configuration.peerVerifyMode == QSslSocket::VerifyPeer
+ || (configuration.peerVerifyMode == QSslSocket::AutoVerifyPeer
+ && mode == QSslSocket::SslClientMode);
+
+ // Check the peer certificate itself. First try the subject's common name
+ // (CN) as a wildcard, then try all alternate subject name DNS entries the
+ // same way.
+ if (!configuration.peerCertificate.isNull()) {
+ // 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 = (verificationPeerName.isEmpty () ? q->peerName() : verificationPeerName);
+ QString commonName = configuration.peerCertificate.subjectInfo(QSslCertificate::CommonName);
+
+ if (!isMatchingHostname(commonName.toLower(), peerName.toLower())) {
+ bool matched = false;
+ foreach (const QString &altName, configuration.peerCertificate
+ .alternateSubjectNames().values(QSsl::DnsEntry)) {
+ if (isMatchingHostname(altName.toLower(), peerName.toLower())) {
+ matched = true;
+ break;
+ }
+ }
+
+ if (!matched) {
+ // No matches in common names or alternate names.
+ QSslError error(QSslError::HostNameMismatch, configuration.peerCertificate);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+ }
+ } else {
+ // No peer certificate presented. Report as error if the socket
+ // expected one.
+ if (doVerifyPeer) {
+ QSslError error(QSslError::NoPeerCertificate);
+ errors << error;
+ emit q->peerVerifyError(error);
+ if (q->state() != QAbstractSocket::ConnectedState)
+ return false;
+ }
+ }
+
+ // Translate errors from the error list into QSslErrors.
+ for (int i = 0; i < errorList.size(); ++i) {
+ const QPair<int, int> &errorAndDepth = errorList.at(i);
+ int err = errorAndDepth.first;
+ int depth = errorAndDepth.second;
+ errors << _q_OpenSSL_to_QSslError(err, configuration.peerCertificateChain.value(depth));
+ }
+
+ if (!errors.isEmpty()) {
+ sslErrors = errors;
+ emit q->sslErrors(errors);
+
+ 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);
+ plainSocket->disconnectFromHost();
+ return false;
+ }
+ } else {
+ sslErrors.clear();
+ }
+
+ // if we have a max read buffer size, reset the plain socket's to 1k
+ if (readBufferMaxSize)
+ plainSocket->setReadBufferSize(1024);
+
+ connectionEncrypted = true;
+ emit q->encrypted();
+ if (autoStartHandshake && pendingClose) {
+ pendingClose = false;
+ q->disconnectFromHost();
+ }
+ return true;
+}
+
+void QSslSocketBackendPrivate::disconnectFromHost()
+{
+ if (ssl) {
+ q_SSL_shutdown(ssl);
+ transmit();
+ }
+ plainSocket->disconnectFromHost();
+}
+
+void QSslSocketBackendPrivate::disconnected()
+{
+ if (ssl) {
+ q_SSL_free(ssl);
+ ssl = 0;
+ }
+ if (ctx) {
+ q_SSL_CTX_free(ctx);
+ ctx = 0;
+ }
+ if (pkey) {
+ q_EVP_PKEY_free(pkey);
+ pkey = 0;
+ }
+
+}
+
+QSslCipher QSslSocketBackendPrivate::sessionCipher() const
+{
+ if (!ssl || !ctx)
+ return QSslCipher();
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+ // FIXME This is fairly evil, but needed to keep source level compatibility
+ // with the OpenSSL 0.9.x implementation at maximum -- some other functions
+ // don't take a const SSL_CIPHER* when they should
+ SSL_CIPHER *sessionCipher = const_cast<SSL_CIPHER *>(q_SSL_get_current_cipher(ssl));
+#else
+ SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);
+#endif
+ return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher();
+}
+
+QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509)
+{
+ ensureInitialized();
+ QList<QSslCertificate> certificates;
+ for (int i = 0; i < q_sk_X509_num(x509); ++i) {
+ if (X509 *entry = q_sk_X509_value(x509, i))
+ certificates << QSslCertificatePrivate::QSslCertificate_from_X509(entry);
+ }
+ return certificates;
+}
+
+QString QSslSocketBackendPrivate::getErrorsFromOpenSsl()
+{
+ QString errorString;
+ unsigned long errNum;
+ while((errNum = q_ERR_get_error())) {
+ if (! errorString.isEmpty())
+ errorString.append(QLatin1String(", "));
+ const char *error = q_ERR_error_string(errNum, NULL);
+ errorString.append(QString::fromAscii(error)); // error is ascii according to man ERR_error_string
+ }
+ return errorString;
+}
+
+bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QString &hostname)
+{
+ int wildcard = cn.indexOf(QLatin1Char('*'));
+
+ // Check this is a wildcard cert, if not then just compare the strings
+ if (wildcard < 0)
+ return cn == hostname;
+
+ int firstCnDot = cn.indexOf(QLatin1Char('.'));
+ int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1);
+
+ // Check at least 3 components
+ if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length()))
+ return false;
+
+ // Check * is last character of 1st component (ie. there's a following .)
+ if (wildcard+1 != firstCnDot)
+ return false;
+
+ // Check only one star
+ if (cn.lastIndexOf(QLatin1Char('*')) != wildcard)
+ return false;
+
+ // Check characters preceding * (if any) match
+ if (wildcard && (hostname.leftRef(wildcard) != cn.leftRef(wildcard)))
+ return false;
+
+ // Check characters following first . match
+ if (hostname.midRef(hostname.indexOf(QLatin1Char('.'))) != cn.midRef(firstCnDot))
+ return false;
+
+ // Check if the hostname is an IP address, if so then wildcards are not allowed
+ QHostAddress addr(hostname);
+ if (!addr.isNull())
+ return false;
+
+ // Ok, I guess this was a wildcard CN and the hostname matches.
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_p.h b/src/network/ssl/qsslsocket_openssl_p.h
new file mode 100644
index 0000000000..ca49fabc13
--- /dev/null
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLSOCKET_OPENSSL_P_H
+#define QSSLSOCKET_OPENSSL_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsslsocket_p.h"
+
+#ifdef Q_OS_WIN
+#include <qt_windows.h>
+#if defined(OCSP_RESPONSE)
+#undef OCSP_RESPONSE
+#endif
+#endif
+
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/bn.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/pem.h>
+#include <openssl/pkcs12.h>
+#include <openssl/pkcs7.h>
+#include <openssl/rand.h>
+#include <openssl/ssl.h>
+#include <openssl/stack.h>
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/dsa.h>
+#include <openssl/rsa.h>
+#include <openssl/crypto.h>
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+#include <openssl/tls1.h>
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+typedef _STACK STACK;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QSslSocketBackendPrivate : public QSslSocketPrivate
+{
+ Q_DECLARE_PUBLIC(QSslSocket)
+public:
+ QSslSocketBackendPrivate();
+ virtual ~QSslSocketBackendPrivate();
+
+ // SSL context
+ bool initSslContext();
+ SSL *ssl;
+ SSL_CTX *ctx;
+ EVP_PKEY *pkey;
+ BIO *readBio;
+ BIO *writeBio;
+ SSL_SESSION *session;
+ X509_STORE *certificateStore;
+ X509_STORE_CTX *certificateStoreCtx;
+ QList<QPair<int, int> > errorList;
+
+ // Platform specific functions
+ void startClientEncryption();
+ void startServerEncryption();
+ void transmit();
+ bool startHandshake();
+ void disconnectFromHost();
+ void disconnected();
+ QSslCipher sessionCipher() const;
+
+ static QSslCipher QSslCipher_from_SSL_CIPHER(SSL_CIPHER *cipher);
+ static QList<QSslCertificate> STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509);
+ Q_AUTOTEST_EXPORT static bool isMatchingHostname(const QString &cn, const QString &hostname);
+ static QString getErrorsFromOpenSsl();
+};
+
+#if defined(Q_OS_SYMBIAN)
+
+#include <QByteArray>
+#include <e32base.h>
+#include <f32file.h>
+#include <unifiedcertstore.h> // link against certstore.lib
+#include <ccertattributefilter.h> // link against ctframework.lib
+
+// The purpose of this class is to wrap the asynchronous API of Symbian certificate store to one
+// synchronizable call. The user of this class needs to provide a TRequestStatus object which can
+// be used with User::WaitForRequest() unlike with the calls of the certificate store API.
+// A thread is used instead of a CActiveSchedulerWait scheme, because that would make the call
+// asynchronous (other events might be processed during the call even though the call would be seemingly
+// synchronous).
+
+class CSymbianCertificateRetriever : public CActive
+{
+public:
+ static CSymbianCertificateRetriever* NewL();
+ ~CSymbianCertificateRetriever();
+
+ int GetCertificates(QList<QByteArray> &aCertificates);
+
+private:
+ void ConstructL();
+ CSymbianCertificateRetriever();
+ static TInt ThreadEntryPoint(TAny* aParams);
+ void doThreadEntryL();
+ void GetCertificateL();
+ void DoCancel();
+ void RunL();
+ TInt RunError(TInt aError);
+
+private:
+ enum {
+ Initializing,
+ Listing,
+ RetrievingCertificates
+ } iState;
+
+ RThread iThread;
+ CUnifiedCertStore* iCertStore;
+ RMPointerArray<CCTCertInfo> iCertInfos;
+ CCertAttributeFilter* iCertFilter;
+ TInt iCurrentCertIndex;
+ QByteArray iCertificateData;
+ TPtr8 iCertificatePtr;
+ QList<QByteArray>* iCertificates;
+ TInt iSequenceError;
+};
+
+
+#endif
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/ssl/qsslsocket_openssl_symbols.cpp b/src/network/ssl/qsslsocket_openssl_symbols.cpp
new file mode 100644
index 0000000000..b1310ccb8d
--- /dev/null
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -0,0 +1,888 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsslsocket_openssl_symbols_p.h"
+
+#ifdef Q_OS_WIN
+# include <private/qsystemlibrary_p.h>
+#else
+# include <QtCore/qlibrary.h>
+#endif
+#include <QtCore/qmutex.h>
+#include <private/qmutexpool_p.h>
+#include <QtCore/qdatetime.h>
+#if defined(Q_OS_UNIX)
+#include <QtCore/qdir.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+/*
+ Note to maintainer:
+ -------------------
+
+ We load OpenSSL symbols dynamically. Because symbols are known to
+ disappear, and signatures sometimes change, between releases, we need to
+ be careful about how this is done. To ensure we don't end up dereferencing
+ null function pointers, and continue running even if certain functions are
+ missing, we define helper functions for each of the symbols we load from
+ OpenSSL, all prefixed with "q_" (declared in
+ qsslsocket_openssl_symbols_p.h). So instead of calling SSL_connect
+ directly, we call q_SSL_connect, which is a function that checks if the
+ actual SSL_connect fptr is null, and returns a failure if it is, or calls
+ SSL_connect if it isn't.
+
+ This requires a somewhat tedious process of declaring each function we
+ want to call in OpenSSL thrice: once with the q_, in _p.h, once using the
+ DEFINEFUNC macros below, and once in the function that actually resolves
+ the symbols, below the DEFINEFUNC declarations below.
+
+ There's one DEFINEFUNC macro declared for every number of arguments
+ exposed by OpenSSL (feel free to extend when needed). The easiest thing to
+ do is to find an existing entry that matches the arg count of the function
+ you want to import, and do the same.
+
+ The first macro arg is the function return type. The second is the
+ verbatim name of the function/symbol. Then follows a list of N pairs of
+ argument types with a variable name, and just the variable name (char *a,
+ a, char *b, b, etc). Finally there's two arguments - a suitable return
+ statement for the error case (for an int function, return 0 or return -1
+ is usually right). Then either just "return" or DUMMYARG, the latter being
+ for void functions.
+
+ Note: Take into account that these macros and declarations are processed
+ at compile-time, and the result depends on the OpenSSL headers the
+ compiling host has installed, but the symbols are resolved at run-time,
+ possibly with a different version of OpenSSL.
+*/
+
+#ifdef SSLEAY_MACROS
+DEFINEFUNC3(void *, ASN1_dup, i2d_of_void *a, a, d2i_of_void *b, b, char *c, c, return 0, return)
+#endif
+DEFINEFUNC(long, ASN1_INTEGER_get, ASN1_INTEGER *a, a, return 0, return)
+DEFINEFUNC(unsigned char *, ASN1_STRING_data, ASN1_STRING *a, a, return 0, return)
+DEFINEFUNC(int, ASN1_STRING_length, ASN1_STRING *a, a, return 0, return)
+DEFINEFUNC4(long, BIO_ctrl, BIO *a, a, int b, b, long c, c, void *d, d, return -1, return)
+DEFINEFUNC(int, BIO_free, BIO *a, a, return 0, return)
+DEFINEFUNC(BIO *, BIO_new, BIO_METHOD *a, a, return 0, return)
+DEFINEFUNC2(BIO *, BIO_new_mem_buf, void *a, a, int b, b, return 0, return)
+DEFINEFUNC3(int, BIO_read, BIO *a, a, void *b, b, int c, c, return -1, return)
+DEFINEFUNC(BIO_METHOD *, BIO_s_mem, void, DUMMYARG, return 0, return)
+DEFINEFUNC3(int, BIO_write, BIO *a, a, const void *b, b, int c, c, return -1, return)
+DEFINEFUNC(int, BN_num_bits, const BIGNUM *a, a, return 0, return)
+DEFINEFUNC(int, CRYPTO_num_locks, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(void, CRYPTO_set_locking_callback, void (*a)(int, int, const char *, int), a, return, DUMMYARG)
+DEFINEFUNC(void, CRYPTO_set_id_callback, unsigned long (*a)(), a, return, DUMMYARG)
+DEFINEFUNC(void, CRYPTO_free, void *a, a, return, DUMMYARG)
+DEFINEFUNC(void, DSA_free, DSA *a, a, return, DUMMYARG)
+#if OPENSSL_VERSION_NUMBER < 0x00908000L
+DEFINEFUNC3(X509 *, d2i_X509, X509 **a, a, unsigned char **b, b, long c, c, return 0, return)
+#else // 0.9.8 broke SC and BC by changing this signature.
+DEFINEFUNC3(X509 *, d2i_X509, X509 **a, a, const unsigned char **b, b, long c, c, return 0, return)
+#endif
+DEFINEFUNC2(char *, ERR_error_string, unsigned long a, a, char *b, b, return 0, return)
+DEFINEFUNC(unsigned long, ERR_get_error, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const EVP_CIPHER *, EVP_des_ede3_cbc, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC3(int, EVP_PKEY_assign, EVP_PKEY *a, a, int b, b, char *c, c, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_RSA, EVP_PKEY *a, a, RSA *b, b, return -1, return)
+DEFINEFUNC2(int, EVP_PKEY_set1_DSA, EVP_PKEY *a, a, DSA *b, b, return -1, return)
+DEFINEFUNC(void, EVP_PKEY_free, EVP_PKEY *a, a, return, DUMMYARG)
+DEFINEFUNC(DSA *, EVP_PKEY_get1_DSA, EVP_PKEY *a, a, return 0, return)
+DEFINEFUNC(RSA *, EVP_PKEY_get1_RSA, EVP_PKEY *a, a, return 0, return)
+DEFINEFUNC(EVP_PKEY *, EVP_PKEY_new, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(int, EVP_PKEY_type, int a, a, return NID_undef, return)
+DEFINEFUNC2(int, i2d_X509, X509 *a, a, unsigned char **b, b, return -1, return)
+DEFINEFUNC(const char *, OBJ_nid2sn, int a, a, return 0, return)
+DEFINEFUNC(int, OBJ_obj2nid, const ASN1_OBJECT *a, a, return NID_undef, return)
+#ifdef SSLEAY_MACROS
+DEFINEFUNC6(void *, PEM_ASN1_read_bio, d2i_of_void *a, a, const char *b, b, BIO *c, c, void **d, d, pem_password_cb *e, e, void *f, f, return 0, return)
+DEFINEFUNC6(void *, PEM_ASN1_write_bio, d2i_of_void *a, a, const char *b, b, BIO *c, c, void **d, d, pem_password_cb *e, e, void *f, f, return 0, return)
+#else
+DEFINEFUNC4(DSA *, PEM_read_bio_DSAPrivateKey, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
+DEFINEFUNC4(RSA *, PEM_read_bio_RSAPrivateKey, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_DSAPrivateKey, BIO *a, a, DSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+DEFINEFUNC7(int, PEM_write_bio_RSAPrivateKey, BIO *a, a, RSA *b, b, const EVP_CIPHER *c, c, unsigned char *d, d, int e, e, pem_password_cb *f, f, void *g, g, return 0, return)
+#endif
+DEFINEFUNC4(DSA *, PEM_read_bio_DSA_PUBKEY, BIO *a, a, DSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
+DEFINEFUNC4(RSA *, PEM_read_bio_RSA_PUBKEY, BIO *a, a, RSA **b, b, pem_password_cb *c, c, void *d, d, return 0, return)
+DEFINEFUNC2(int, PEM_write_bio_DSA_PUBKEY, BIO *a, a, DSA *b, b, return 0, return)
+DEFINEFUNC2(int, PEM_write_bio_RSA_PUBKEY, BIO *a, a, RSA *b, b, return 0, return)
+DEFINEFUNC2(void, RAND_seed, const void *a, a, int b, b, return, DUMMYARG)
+DEFINEFUNC(int, RAND_status, void, DUMMYARG, return -1, return)
+DEFINEFUNC(void, RSA_free, RSA *a, a, return, DUMMYARG)
+DEFINEFUNC(int, sk_num, STACK *a, a, return -1, return)
+DEFINEFUNC2(void, sk_pop_free, STACK *a, a, void (*b)(void*), b, return, DUMMYARG)
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+DEFINEFUNC(void, sk_free, _STACK *a, a, return, DUMMYARG)
+DEFINEFUNC2(void *, sk_value, STACK *a, a, int b, b, return 0, return)
+#else
+DEFINEFUNC(void, sk_free, STACK *a, a, return, DUMMYARG)
+DEFINEFUNC2(char *, sk_value, STACK *a, a, int b, b, return 0, return)
+#endif
+DEFINEFUNC(int, SSL_accept, SSL *a, a, return -1, return)
+DEFINEFUNC(int, SSL_clear, SSL *a, a, return -1, return)
+DEFINEFUNC3(char *, SSL_CIPHER_description, SSL_CIPHER *a, a, char *b, b, int c, c, return 0, return)
+DEFINEFUNC(int, SSL_connect, SSL *a, a, return -1, return)
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+// 0.9.8 broke SC and BC by changing this function's signature.
+DEFINEFUNC(int, SSL_CTX_check_private_key, const SSL_CTX *a, a, return -1, return)
+#else
+DEFINEFUNC(int, SSL_CTX_check_private_key, SSL_CTX *a, a, return -1, return)
+#endif
+DEFINEFUNC4(long, SSL_CTX_ctrl, SSL_CTX *a, a, int b, b, long c, c, void *d, d, return -1, return)
+DEFINEFUNC(void, SSL_CTX_free, SSL_CTX *a, a, return, DUMMYARG)
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+DEFINEFUNC(SSL_CTX *, SSL_CTX_new, const SSL_METHOD *a, a, return 0, return)
+#else
+DEFINEFUNC(SSL_CTX *, SSL_CTX_new, SSL_METHOD *a, a, return 0, return)
+#endif
+DEFINEFUNC2(int, SSL_CTX_set_cipher_list, SSL_CTX *a, a, const char *b, b, return -1, return)
+DEFINEFUNC(int, SSL_CTX_set_default_verify_paths, SSL_CTX *a, a, return -1, return)
+DEFINEFUNC3(void, SSL_CTX_set_verify, SSL_CTX *a, a, int b, b, int (*c)(int, X509_STORE_CTX *), c, return, DUMMYARG)
+DEFINEFUNC2(void, SSL_CTX_set_verify_depth, SSL_CTX *a, a, int b, b, return, DUMMYARG)
+DEFINEFUNC2(int, SSL_CTX_use_certificate, SSL_CTX *a, a, X509 *b, b, return -1, return)
+DEFINEFUNC3(int, SSL_CTX_use_certificate_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
+DEFINEFUNC2(int, SSL_CTX_use_PrivateKey, SSL_CTX *a, a, EVP_PKEY *b, b, return -1, return)
+DEFINEFUNC2(int, SSL_CTX_use_RSAPrivateKey, SSL_CTX *a, a, RSA *b, b, return -1, return)
+DEFINEFUNC3(int, SSL_CTX_use_PrivateKey_file, SSL_CTX *a, a, const char *b, b, int c, c, return -1, return)
+DEFINEFUNC(void, SSL_free, SSL *a, a, return, DUMMYARG)
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+// 0.9.8 broke SC and BC by changing this function's signature.
+DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, const SSL *a, a, return 0, return)
+#else
+DEFINEFUNC(STACK_OF(SSL_CIPHER) *, SSL_get_ciphers, SSL *a, a, return 0, return)
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+DEFINEFUNC(const SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, return)
+#else
+DEFINEFUNC(SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, return)
+#endif
+DEFINEFUNC2(int, SSL_get_error, SSL *a, a, int b, b, return -1, return)
+DEFINEFUNC(STACK_OF(X509) *, SSL_get_peer_cert_chain, SSL *a, a, return 0, return)
+DEFINEFUNC(X509 *, SSL_get_peer_certificate, SSL *a, a, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+// 0.9.8 broke SC and BC by changing this function's signature.
+DEFINEFUNC(long, SSL_get_verify_result, const SSL *a, a, return -1, return)
+#else
+DEFINEFUNC(long, SSL_get_verify_result, SSL *a, a, return -1, return)
+#endif
+DEFINEFUNC(int, SSL_library_init, void, DUMMYARG, return -1, return)
+DEFINEFUNC(void, SSL_load_error_strings, void, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC(SSL *, SSL_new, SSL_CTX *a, a, return 0, return)
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+DEFINEFUNC4(long, SSL_ctrl, SSL *a, a, int cmd, cmd, long larg, larg, const void *parg, parg, return -1, return)
+#endif
+DEFINEFUNC3(int, SSL_read, SSL *a, a, void *b, b, int c, c, return -1, return)
+DEFINEFUNC3(void, SSL_set_bio, SSL *a, a, BIO *b, b, BIO *c, c, return, DUMMYARG)
+DEFINEFUNC(void, SSL_set_accept_state, SSL *a, a, return, DUMMYARG)
+DEFINEFUNC(void, SSL_set_connect_state, SSL *a, a, return, DUMMYARG)
+DEFINEFUNC(int, SSL_shutdown, SSL *a, a, return -1, return)
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+DEFINEFUNC(const SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, SSLv3_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, SSLv23_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, TLSv1_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, SSLv2_server_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, SSLv3_server_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, SSLv23_server_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(const SSL_METHOD *, TLSv1_server_method, DUMMYARG, DUMMYARG, return 0, return)
+#else
+DEFINEFUNC(SSL_METHOD *, SSLv2_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(SSL_METHOD *, SSLv3_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(SSL_METHOD *, SSLv23_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(SSL_METHOD *, TLSv1_client_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(SSL_METHOD *, SSLv2_server_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(SSL_METHOD *, SSLv3_server_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(SSL_METHOD *, SSLv23_server_method, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC(SSL_METHOD *, TLSv1_server_method, DUMMYARG, DUMMYARG, return 0, return)
+#endif
+DEFINEFUNC3(int, SSL_write, SSL *a, a, const void *b, b, int c, c, return -1, return)
+DEFINEFUNC2(int, X509_cmp, X509 *a, a, X509 *b, b, return -1, return)
+#ifndef SSLEAY_MACROS
+DEFINEFUNC(X509 *, X509_dup, X509 *a, a, return 0, return)
+#endif
+DEFINEFUNC(ASN1_OBJECT *, X509_EXTENSION_get_object, X509_EXTENSION *a, a, return 0, return)
+DEFINEFUNC(void, X509_free, X509 *a, a, return, DUMMYARG)
+DEFINEFUNC2(X509_EXTENSION *, X509_get_ext, X509 *a, a, int b, b, return 0, return)
+DEFINEFUNC(int, X509_get_ext_count, X509 *a, a, return 0, return)
+DEFINEFUNC4(void *, X509_get_ext_d2i, X509 *a, a, int b, b, int *c, c, int *d, d, return 0, return)
+DEFINEFUNC(X509_NAME *, X509_get_issuer_name, X509 *a, a, return 0, return)
+DEFINEFUNC(X509_NAME *, X509_get_subject_name, X509 *a, a, return 0, return)
+DEFINEFUNC(int, X509_verify_cert, X509_STORE_CTX *a, a, return -1, return)
+DEFINEFUNC3(char *, X509_NAME_oneline, X509_NAME *a, a, char *b, b, int c, c, return 0, return)
+DEFINEFUNC(EVP_PKEY *, X509_PUBKEY_get, X509_PUBKEY *a, a, return 0, return)
+DEFINEFUNC(void, X509_STORE_free, X509_STORE *a, a, return, DUMMYARG)
+DEFINEFUNC(X509_STORE *, X509_STORE_new, DUMMYARG, DUMMYARG, return 0, return)
+DEFINEFUNC2(int, X509_STORE_add_cert, X509_STORE *a, a, X509 *b, b, return 0, return)
+DEFINEFUNC(void, X509_STORE_CTX_free, X509_STORE_CTX *a, a, return, DUMMYARG)
+DEFINEFUNC4(int, X509_STORE_CTX_init, X509_STORE_CTX *a, a, X509_STORE *b, b, X509 *c, c, STACK_OF(X509) *d, d, return -1, return)
+DEFINEFUNC2(int, X509_STORE_CTX_set_purpose, X509_STORE_CTX *a, a, int b, b, return -1, return)
+DEFINEFUNC(X509_STORE_CTX *, X509_STORE_CTX_new, DUMMYARG, DUMMYARG, return 0, return)
+#ifdef SSLEAY_MACROS
+DEFINEFUNC2(int, i2d_DSAPrivateKey, const DSA *a, a, unsigned char **b, b, return -1, return)
+DEFINEFUNC2(int, i2d_RSAPrivateKey, const RSA *a, a, unsigned char **b, b, return -1, return)
+DEFINEFUNC3(RSA *, d2i_RSAPrivateKey, RSA **a, a, unsigned char **b, b, long c, c, return 0, return)
+DEFINEFUNC3(DSA *, d2i_DSAPrivateKey, DSA **a, a, unsigned char **b, b, long c, c, return 0, return)
+#endif
+DEFINEFUNC(void, OPENSSL_add_all_algorithms_noconf, void, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC(void, OPENSSL_add_all_algorithms_conf, void, DUMMYARG, return, DUMMYARG)
+DEFINEFUNC3(int, SSL_CTX_load_verify_locations, SSL_CTX *ctx, ctx, const char *CAfile, CAfile, const char *CApath, CApath, return 0, return)
+DEFINEFUNC(long, SSLeay, void, DUMMYARG, return 0, return)
+
+#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
+
+#ifdef QT_NO_LIBRARY
+bool q_resolveOpenSslSymbols()
+{
+ qWarning("QSslSocket: unable to resolve symbols. "
+ "QT_NO_LIBRARY is defined which means runtime resolving of "
+ "libraries won't work.");
+ qWarning("Either compile Qt statically or with support for runtime resolving "
+ "of libraries.");
+ return false;
+}
+#else
+
+# ifdef Q_OS_UNIX
+static bool libGreaterThan(const QString &lhs, const QString &rhs)
+{
+ QStringList lhsparts = lhs.split(QLatin1Char('.'));
+ QStringList rhsparts = rhs.split(QLatin1Char('.'));
+ Q_ASSERT(lhsparts.count() > 1 && rhsparts.count() > 1);
+
+ for (int i = 1; i < rhsparts.count(); ++i) {
+ if (lhsparts.count() <= i)
+ // left hand side is shorter, so it's less than rhs
+ return false;
+
+ bool ok = false;
+ int b = 0;
+ int a = lhsparts.at(i).toInt(&ok);
+ if (ok)
+ b = rhsparts.at(i).toInt(&ok);
+ if (ok) {
+ // both toInt succeeded
+ if (a == b)
+ continue;
+ return a > b;
+ } else {
+ // compare as strings;
+ if (lhsparts.at(i) == rhsparts.at(i))
+ continue;
+ return lhsparts.at(i) > rhsparts.at(i);
+ }
+ }
+
+ // they compared strictly equally so far
+ // lhs cannot be less than rhs
+ return true;
+}
+
+static QStringList findAllLibSsl()
+{
+ QStringList paths;
+# ifdef Q_OS_DARWIN
+ paths = QString::fromLatin1(qgetenv("DYLD_LIBRARY_PATH"))
+ .split(QLatin1Char(':'), QString::SkipEmptyParts);
+# else
+ paths = QString::fromLatin1(qgetenv("LD_LIBRARY_PATH"))
+ .split(QLatin1Char(':'), QString::SkipEmptyParts);
+# endif
+ paths << QLatin1String("/lib") << QLatin1String("/usr/lib") << QLatin1String("/usr/local/lib");
+
+ QStringList foundSsls;
+ foreach (const QString &path, paths) {
+ QDir dir = QDir(path);
+ QStringList entryList = dir.entryList(QStringList() << QLatin1String("libssl.*"), QDir::Files);
+
+ qSort(entryList.begin(), entryList.end(), libGreaterThan);
+ foreach (const QString &entry, entryList)
+ foundSsls << path + QLatin1Char('/') + entry;
+ }
+
+ return foundSsls;
+}
+# endif
+
+#ifdef Q_OS_WIN
+static QPair<QSystemLibrary*, QSystemLibrary*> loadOpenSslWin32()
+{
+ QPair<QSystemLibrary*,QSystemLibrary*> pair;
+ pair.first = 0;
+ pair.second = 0;
+
+ QSystemLibrary *ssleay32 = new QSystemLibrary(QLatin1String("ssleay32"));
+ if (!ssleay32->load(false)) {
+ // Cannot find ssleay32.dll
+ delete ssleay32;
+ return pair;
+ }
+
+ QSystemLibrary *libeay32 = new QSystemLibrary(QLatin1String("libeay32"));
+ if (!libeay32->load(false)) {
+ delete ssleay32;
+ delete libeay32;
+ return pair;
+ }
+
+ pair.first = ssleay32;
+ pair.second = libeay32;
+ return pair;
+}
+#else
+
+static QPair<QLibrary*, QLibrary*> loadOpenSsl()
+{
+ QPair<QLibrary*,QLibrary*> pair;
+ pair.first = 0;
+ pair.second = 0;
+
+# if 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;
+ libssl = new QLibrary;
+ libcrypto = new QLibrary;
+
+ // Try to find the libssl library on the system.
+ //
+ // Up until Qt 4.3, this only searched for the "ssl" library at version -1, that
+ // is, libssl.so on most Unix systems. However, the .so file isn't present in
+ // user installations because it's considered a development file.
+ //
+ // The right thing to do is to load the library at the major version we know how
+ // to work with: the SHLIB_VERSION_NUMBER version (macro defined in opensslv.h)
+ //
+ // However, OpenSSL is a well-known case of binary-compatibility breakage. To
+ // avoid such problems, many system integrators and Linux distributions change
+ // the soname of the binary, letting the full version number be the soname. So
+ // we'll find libssl.so.0.9.7, libssl.so.0.9.8, etc. in the system. For that
+ // reason, we will search a few common paths (see findAllLibSsl() above) in hopes
+ // we find one that works.
+ //
+ // It is important, however, to try the canonical name and the unversioned name
+ // without going through the loop. By not specifying a path, we let the system
+ // dlopen(3) function determine it for us. This will include any DT_RUNPATH or
+ // DT_RPATH tags on our library header as well as other system-specific search
+ // paths. See the man page for dlopen(3) on your system for more information.
+
+#ifdef Q_OS_OPENBSD
+ libcrypto->setLoadHints(QLibrary::ExportExternalSymbolsHint);
+#endif
+#ifdef SHLIB_VERSION_NUMBER
+ // first attempt: the canonical name is libssl.so.<SHLIB_VERSION_NUMBER>
+ libssl->setFileNameAndVersion(QLatin1String("ssl"), QLatin1String(SHLIB_VERSION_NUMBER));
+ libcrypto->setFileNameAndVersion(QLatin1String("crypto"), QLatin1String(SHLIB_VERSION_NUMBER));
+ if (libcrypto->load() && libssl->load()) {
+ // libssl.so.<SHLIB_VERSION_NUMBER> and libcrypto.so.<SHLIB_VERSION_NUMBER> found
+ return pair;
+ } else {
+ libssl->unload();
+ libcrypto->unload();
+ }
+#endif
+
+ // second attempt: find the development files libssl.so and libcrypto.so
+ libssl->setFileNameAndVersion(QLatin1String("ssl"), -1);
+ libcrypto->setFileNameAndVersion(QLatin1String("crypto"), -1);
+ if (libcrypto->load() && libssl->load()) {
+ // libssl.so.0 and libcrypto.so.0 found
+ return pair;
+ } else {
+ libssl->unload();
+ libcrypto->unload();
+ }
+
+ // third attempt: loop on the most common library paths and find libssl
+ QStringList sslList = findAllLibSsl();
+ foreach (const QString &ssl, sslList) {
+ QString crypto = ssl;
+ crypto.replace(QLatin1String("ssl"), QLatin1String("crypto"));
+ libssl->setFileNameAndVersion(ssl, -1);
+ libcrypto->setFileNameAndVersion(crypto, -1);
+ if (libcrypto->load() && libssl->load()) {
+ // libssl.so.0 and libcrypto.so.0 found
+ return pair;
+ } else {
+ libssl->unload();
+ libcrypto->unload();
+ }
+ }
+
+ // failed to load anything
+ delete libssl;
+ delete libcrypto;
+ libssl = libcrypto = 0;
+ return pair;
+
+# else
+ // not implemented for this platform yet
+ return pair;
+# endif
+}
+#endif
+
+bool q_resolveOpenSslSymbols()
+{
+ static volatile bool symbolsResolved = false;
+ static volatile bool triedToResolveSymbols = false;
+#ifndef QT_NO_THREAD
+ QMutexLocker locker(QMutexPool::globalInstanceGet((void *)&q_SSL_library_init));
+#endif
+ if (symbolsResolved)
+ return true;
+ if (triedToResolveSymbols)
+ return false;
+ triedToResolveSymbols = true;
+
+#ifdef Q_OS_WIN
+ QPair<QSystemLibrary *, QSystemLibrary *> libs = loadOpenSslWin32();
+#else
+ QPair<QLibrary *, QLibrary *> libs = loadOpenSsl();
+#endif
+ if (!libs.first || !libs.second)
+ // failed to load them
+ return false;
+
+#ifdef Q_OS_SYMBIAN
+#ifdef SSLEAY_MACROS
+ RESOLVEFUNC(ASN1_dup, 125, libs.second )
+#endif
+ RESOLVEFUNC(ASN1_INTEGER_get, 48, libs.second )
+ 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_set1_RSA, 880, libs.second )
+ RESOLVEFUNC(EVP_PKEY_set1_DSA, 879, 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_pop_free, 2578, 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 )
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+ RESOLVEFUNC(SSL_ctrl, 95, libs.first )
+#endif
+ 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(SSL_CTX_load_verify_locations, 34, 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 )
+ RESOLVEFUNC(SSLeay, 1504, libs.second )
+#else // Q_OS_SYMBIAN
+#ifdef SSLEAY_MACROS
+ RESOLVEFUNC(ASN1_dup)
+#endif
+ RESOLVEFUNC(ASN1_INTEGER_get)
+ RESOLVEFUNC(ASN1_STRING_data)
+ RESOLVEFUNC(ASN1_STRING_length)
+ RESOLVEFUNC(BIO_ctrl)
+ RESOLVEFUNC(BIO_free)
+ RESOLVEFUNC(BIO_new)
+ RESOLVEFUNC(BIO_new_mem_buf)
+ RESOLVEFUNC(BIO_read)
+ RESOLVEFUNC(BIO_s_mem)
+ RESOLVEFUNC(BIO_write)
+ RESOLVEFUNC(BN_num_bits)
+ RESOLVEFUNC(CRYPTO_free)
+ RESOLVEFUNC(CRYPTO_num_locks)
+ RESOLVEFUNC(CRYPTO_set_id_callback)
+ RESOLVEFUNC(CRYPTO_set_locking_callback)
+ RESOLVEFUNC(DSA_free)
+ RESOLVEFUNC(ERR_error_string)
+ RESOLVEFUNC(ERR_get_error)
+ RESOLVEFUNC(EVP_des_ede3_cbc)
+ RESOLVEFUNC(EVP_PKEY_assign)
+ RESOLVEFUNC(EVP_PKEY_set1_RSA)
+ RESOLVEFUNC(EVP_PKEY_set1_DSA)
+ RESOLVEFUNC(EVP_PKEY_free)
+ RESOLVEFUNC(EVP_PKEY_get1_DSA)
+ RESOLVEFUNC(EVP_PKEY_get1_RSA)
+ RESOLVEFUNC(EVP_PKEY_new)
+ RESOLVEFUNC(EVP_PKEY_type)
+ RESOLVEFUNC(OBJ_nid2sn)
+ RESOLVEFUNC(OBJ_obj2nid)
+#ifdef SSLEAY_MACROS // ### verify
+ RESOLVEFUNC(PEM_ASN1_read_bio)
+#else
+ RESOLVEFUNC(PEM_read_bio_DSAPrivateKey)
+ RESOLVEFUNC(PEM_read_bio_RSAPrivateKey)
+ RESOLVEFUNC(PEM_write_bio_DSAPrivateKey)
+ RESOLVEFUNC(PEM_write_bio_RSAPrivateKey)
+#endif
+ RESOLVEFUNC(PEM_read_bio_DSA_PUBKEY)
+ RESOLVEFUNC(PEM_read_bio_RSA_PUBKEY)
+ RESOLVEFUNC(PEM_write_bio_DSA_PUBKEY)
+ RESOLVEFUNC(PEM_write_bio_RSA_PUBKEY)
+ RESOLVEFUNC(RAND_seed)
+ RESOLVEFUNC(RAND_status)
+ RESOLVEFUNC(RSA_free)
+ RESOLVEFUNC(sk_free)
+ RESOLVEFUNC(sk_num)
+ RESOLVEFUNC(sk_pop_free)
+ RESOLVEFUNC(sk_value)
+ RESOLVEFUNC(SSL_CIPHER_description)
+ RESOLVEFUNC(SSL_CTX_check_private_key)
+ RESOLVEFUNC(SSL_CTX_ctrl)
+ RESOLVEFUNC(SSL_CTX_free)
+ RESOLVEFUNC(SSL_CTX_new)
+ RESOLVEFUNC(SSL_CTX_set_cipher_list)
+ RESOLVEFUNC(SSL_CTX_set_default_verify_paths)
+ RESOLVEFUNC(SSL_CTX_set_verify)
+ RESOLVEFUNC(SSL_CTX_set_verify_depth)
+ RESOLVEFUNC(SSL_CTX_use_certificate)
+ RESOLVEFUNC(SSL_CTX_use_certificate_file)
+ RESOLVEFUNC(SSL_CTX_use_PrivateKey)
+ RESOLVEFUNC(SSL_CTX_use_RSAPrivateKey)
+ RESOLVEFUNC(SSL_CTX_use_PrivateKey_file)
+ RESOLVEFUNC(SSL_accept)
+ RESOLVEFUNC(SSL_clear)
+ RESOLVEFUNC(SSL_connect)
+ RESOLVEFUNC(SSL_free)
+ RESOLVEFUNC(SSL_get_ciphers)
+ RESOLVEFUNC(SSL_get_current_cipher)
+ RESOLVEFUNC(SSL_get_error)
+ RESOLVEFUNC(SSL_get_peer_cert_chain)
+ RESOLVEFUNC(SSL_get_peer_certificate)
+ RESOLVEFUNC(SSL_get_verify_result)
+ RESOLVEFUNC(SSL_library_init)
+ RESOLVEFUNC(SSL_load_error_strings)
+ RESOLVEFUNC(SSL_new)
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+ RESOLVEFUNC(SSL_ctrl)
+#endif
+ RESOLVEFUNC(SSL_read)
+ RESOLVEFUNC(SSL_set_accept_state)
+ RESOLVEFUNC(SSL_set_bio)
+ RESOLVEFUNC(SSL_set_connect_state)
+ RESOLVEFUNC(SSL_shutdown)
+ RESOLVEFUNC(SSL_write)
+ RESOLVEFUNC(SSLv2_client_method)
+ RESOLVEFUNC(SSLv3_client_method)
+ RESOLVEFUNC(SSLv23_client_method)
+ RESOLVEFUNC(TLSv1_client_method)
+ RESOLVEFUNC(SSLv2_server_method)
+ RESOLVEFUNC(SSLv3_server_method)
+ RESOLVEFUNC(SSLv23_server_method)
+ RESOLVEFUNC(TLSv1_server_method)
+ RESOLVEFUNC(X509_NAME_oneline)
+ RESOLVEFUNC(X509_PUBKEY_get)
+ RESOLVEFUNC(X509_STORE_free)
+ RESOLVEFUNC(X509_STORE_new)
+ RESOLVEFUNC(X509_STORE_add_cert)
+ RESOLVEFUNC(X509_STORE_CTX_free)
+ RESOLVEFUNC(X509_STORE_CTX_init)
+ RESOLVEFUNC(X509_STORE_CTX_new)
+ RESOLVEFUNC(X509_STORE_CTX_set_purpose)
+ RESOLVEFUNC(X509_cmp)
+#ifndef SSLEAY_MACROS
+ RESOLVEFUNC(X509_dup)
+#endif
+ RESOLVEFUNC(X509_EXTENSION_get_object)
+ RESOLVEFUNC(X509_free)
+ RESOLVEFUNC(X509_get_ext)
+ RESOLVEFUNC(X509_get_ext_count)
+ RESOLVEFUNC(X509_get_ext_d2i)
+ RESOLVEFUNC(X509_get_issuer_name)
+ RESOLVEFUNC(X509_get_subject_name)
+ RESOLVEFUNC(X509_verify_cert)
+ RESOLVEFUNC(d2i_X509)
+ RESOLVEFUNC(i2d_X509)
+#ifdef SSLEAY_MACROS
+ RESOLVEFUNC(i2d_DSAPrivateKey)
+ RESOLVEFUNC(i2d_RSAPrivateKey)
+ RESOLVEFUNC(d2i_DSAPrivateKey)
+ RESOLVEFUNC(d2i_RSAPrivateKey)
+#endif
+ RESOLVEFUNC(OPENSSL_add_all_algorithms_noconf)
+ RESOLVEFUNC(OPENSSL_add_all_algorithms_conf)
+ RESOLVEFUNC(SSL_CTX_load_verify_locations)
+ RESOLVEFUNC(SSLeay)
+#endif // Q_OS_SYMBIAN
+ symbolsResolved = true;
+ delete libs.first;
+ delete libs.second;
+ return true;
+}
+#endif // QT_NO_LIBRARY
+
+#else // !defined QT_LINKED_OPENSSL
+
+bool q_resolveOpenSslSymbols()
+{
+#ifdef QT_NO_OPENSSL
+ return false;
+#endif
+ return true;
+}
+#endif // !defined QT_LINKED_OPENSSL
+
+//==============================================================================
+// contributed by Jay Case of Sarvega, Inc.; http://sarvega.com/
+// Based on X509_cmp_time() for intitial buffer hacking.
+//==============================================================================
+QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime)
+{
+ size_t lTimeLength = aTime->length;
+ char *pString = (char *) aTime->data;
+
+ if (aTime->type == V_ASN1_UTCTIME) {
+
+ char lBuffer[24];
+ char *pBuffer = lBuffer;
+
+ if ((lTimeLength < 11) || (lTimeLength > 17))
+ return QDateTime();
+
+ memcpy(pBuffer, pString, 10);
+ pBuffer += 10;
+ pString += 10;
+
+ if ((*pString == 'Z') || (*pString == '-') || (*pString == '+')) {
+ *pBuffer++ = '0';
+ *pBuffer++ = '0';
+ } else {
+ *pBuffer++ = *pString++;
+ *pBuffer++ = *pString++;
+ // Skip any fractional seconds...
+ if (*pString == '.') {
+ pString++;
+ while ((*pString >= '0') && (*pString <= '9'))
+ pString++;
+ }
+ }
+
+ *pBuffer++ = 'Z';
+ *pBuffer++ = '\0';
+
+ time_t lSecondsFromUCT;
+ if (*pString == 'Z') {
+ lSecondsFromUCT = 0;
+ } else {
+ if ((*pString != '+') && (*pString != '-'))
+ return QDateTime();
+
+ lSecondsFromUCT = ((pString[1] - '0') * 10 + (pString[2] - '0')) * 60;
+ lSecondsFromUCT += (pString[3] - '0') * 10 + (pString[4] - '0');
+ lSecondsFromUCT *= 60;
+ if (*pString == '-')
+ lSecondsFromUCT = -lSecondsFromUCT;
+ }
+
+ tm lTime;
+ lTime.tm_sec = ((lBuffer[10] - '0') * 10) + (lBuffer[11] - '0');
+ lTime.tm_min = ((lBuffer[8] - '0') * 10) + (lBuffer[9] - '0');
+ lTime.tm_hour = ((lBuffer[6] - '0') * 10) + (lBuffer[7] - '0');
+ lTime.tm_mday = ((lBuffer[4] - '0') * 10) + (lBuffer[5] - '0');
+ lTime.tm_mon = (((lBuffer[2] - '0') * 10) + (lBuffer[3] - '0')) - 1;
+ lTime.tm_year = ((lBuffer[0] - '0') * 10) + (lBuffer[1] - '0');
+ if (lTime.tm_year < 50)
+ lTime.tm_year += 100; // RFC 2459
+
+ QDate resDate(lTime.tm_year + 1900, lTime.tm_mon + 1, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+
+ QDateTime result(resDate, resTime, Qt::UTC);
+ result = result.addSecs(lSecondsFromUCT);
+ return result;
+
+ } else if (aTime->type == V_ASN1_GENERALIZEDTIME) {
+
+ if (lTimeLength < 15)
+ return QDateTime(); // hopefully never triggered
+
+ // generalized time is always YYYYMMDDHHMMSSZ (RFC 2459, section 4.1.2.5.2)
+ tm lTime;
+ lTime.tm_sec = ((pString[12] - '0') * 10) + (pString[13] - '0');
+ lTime.tm_min = ((pString[10] - '0') * 10) + (pString[11] - '0');
+ lTime.tm_hour = ((pString[8] - '0') * 10) + (pString[9] - '0');
+ lTime.tm_mday = ((pString[6] - '0') * 10) + (pString[7] - '0');
+ lTime.tm_mon = (((pString[4] - '0') * 10) + (pString[5] - '0'));
+ lTime.tm_year = ((pString[0] - '0') * 1000) + ((pString[1] - '0') * 100) +
+ ((pString[2] - '0') * 10) + (pString[3] - '0');
+
+ QDate resDate(lTime.tm_year, lTime.tm_mon, lTime.tm_mday);
+ QTime resTime(lTime.tm_hour, lTime.tm_min, lTime.tm_sec);
+
+ QDateTime result(resDate, resTime, Qt::UTC);
+ return result;
+
+ } else {
+ qWarning("unsupported date format detected");
+ return QDateTime();
+ }
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/network/ssl/qsslsocket_openssl_symbols_p.h b/src/network/ssl/qsslsocket_openssl_symbols_p.h
new file mode 100644
index 0000000000..49830acc1e
--- /dev/null
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -0,0 +1,427 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLSOCKET_OPENSSL_SYMBOLS_P_H
+#define QSSLSOCKET_OPENSSL_SYMBOLS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qsslsocket_openssl_p.h"
+
+QT_BEGIN_NAMESPACE
+
+#define DUMMYARG
+
+#if !defined QT_LINKED_OPENSSL
+// **************** Shared declarations ******************
+// ret func(arg)
+
+# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg) { \
+ if (!_q_##func) { \
+ qWarning("QSslSocket: cannot call unresolved function "#func); \
+ err; \
+ } \
+ funcret _q_##func(a); \
+ }
+
+// ret func(arg1, arg2)
+# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2) { \
+ if (!_q_##func) { \
+ qWarning("QSslSocket: cannot call unresolved function "#func);\
+ err; \
+ } \
+ funcret _q_##func(a, b); \
+ }
+
+// ret func(arg1, arg2, arg3)
+# define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3) { \
+ if (!_q_##func) { \
+ qWarning("QSslSocket: cannot call unresolved function "#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4)
+# define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4) { \
+ if (!_q_##func) { \
+ qWarning("QSslSocket: cannot call unresolved function "#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg5)
+# define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5) { \
+ if (!_q_##func) { \
+ qWarning("QSslSocket: cannot call unresolved function "#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6)
+# define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6) { \
+ if (!_q_##func) { \
+ qWarning("QSslSocket: cannot call unresolved function "#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7)
+# define DEFINEFUNC7(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { \
+ if (!_q_##func) { \
+ qWarning("QSslSocket: cannot call unresolved function "#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f, g); \
+ }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7, arg8, arg9)
+# define DEFINEFUNC9(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, arg8, h, arg9, i, err, funcret) \
+ typedef ret (*_q_PTR_##func)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); \
+ static _q_PTR_##func _q_##func = 0; \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { \
+ if (_q_##func) { \
+ qWarning("QSslSocket: cannot call unresolved function "#func); \
+ err; \
+ } \
+ funcret _q_##func(a, b, c, d, e, f, g, h, i); \
+ }
+// **************** Shared declarations ******************
+
+#else // !defined QT_LINKED_OPENSSL
+
+// **************** Static declarations ******************
+
+// ret func(arg)
+# define DEFINEFUNC(ret, func, arg, a, err, funcret) \
+ ret q_##func(arg) { funcret func(a); }
+
+// ret func(arg1, arg2)
+# define DEFINEFUNC2(ret, func, arg1, a, arg2, b, err, funcret) \
+ ret q_##func(arg1, arg2) { funcret func(a, b); }
+
+// ret func(arg1, arg2, arg3)
+# define DEFINEFUNC3(ret, func, arg1, a, arg2, b, arg3, c, err, funcret) \
+ ret q_##func(arg1, arg2, arg3) { funcret func(a, b, c); }
+
+// ret func(arg1, arg2, arg3, arg4)
+# define DEFINEFUNC4(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4) { funcret func(a, b, c, d); }
+
+// ret func(arg1, arg2, arg3, arg4, arg5)
+# define DEFINEFUNC5(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5) { funcret func(a, b, c, d, e); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6)
+# define DEFINEFUNC6(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6) { funcret func(a, b, c, d, e, f); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7)
+# define DEFINEFUNC7(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7) { funcret func(a, b, c, d, e, f, g); }
+
+// ret func(arg1, arg2, arg3, arg4, arg6, arg7, arg8, arg9)
+# define DEFINEFUNC9(ret, func, arg1, a, arg2, b, arg3, c, arg4, d, arg5, e, arg6, f, arg7, g, arg8, h, arg9, i, err, funcret) \
+ ret q_##func(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) { funcret func(a, b, c, d, e, f, g, h, i); }
+
+// **************** Static declarations ******************
+
+#endif // !defined QT_LINKED_OPENSSL
+
+bool q_resolveOpenSslSymbols();
+long q_ASN1_INTEGER_get(ASN1_INTEGER *a);
+unsigned char * q_ASN1_STRING_data(ASN1_STRING *a);
+int q_ASN1_STRING_length(ASN1_STRING *a);
+long q_BIO_ctrl(BIO *a, int b, long c, void *d);
+int q_BIO_free(BIO *a);
+BIO *q_BIO_new(BIO_METHOD *a);
+BIO *q_BIO_new_mem_buf(void *a, int b);
+int q_BIO_read(BIO *a, void *b, int c);
+BIO_METHOD *q_BIO_s_mem();
+int q_BIO_write(BIO *a, const void *b, int c);
+int q_BN_num_bits(const BIGNUM *a);
+int q_CRYPTO_num_locks();
+void q_CRYPTO_set_locking_callback(void (*a)(int, int, const char *, int));
+void q_CRYPTO_set_id_callback(unsigned long (*a)());
+void q_CRYPTO_free(void *a);
+void q_DSA_free(DSA *a);
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+// 0.9.8 broke SC and BC by changing this function's signature.
+X509 *q_d2i_X509(X509 **a, const unsigned char **b, long c);
+#else
+X509 *q_d2i_X509(X509 **a, unsigned char **b, long c);
+#endif
+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);
+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();
+int q_i2d_X509(X509 *a, unsigned char **b);
+const char *q_OBJ_nid2sn(int a);
+int q_OBJ_obj2nid(const ASN1_OBJECT *a);
+#ifdef SSLEAY_MACROS
+// ### verify
+void *q_PEM_ASN1_read_bio(d2i_of_void *a, const char *b, BIO *c, void **d, pem_password_cb *e,
+ void *f);
+// ### ditto for write
+#else
+DSA *q_PEM_read_bio_DSAPrivateKey(BIO *a, DSA **b, pem_password_cb *c, void *d);
+RSA *q_PEM_read_bio_RSAPrivateKey(BIO *a, RSA **b, pem_password_cb *c, void *d);
+int q_PEM_write_bio_DSAPrivateKey(BIO *a, DSA *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+int q_PEM_write_bio_RSAPrivateKey(BIO *a, RSA *b, const EVP_CIPHER *c, unsigned char *d,
+ int e, pem_password_cb *f, void *g);
+#endif
+DSA *q_PEM_read_bio_DSA_PUBKEY(BIO *a, DSA **b, pem_password_cb *c, void *d);
+RSA *q_PEM_read_bio_RSA_PUBKEY(BIO *a, RSA **b, pem_password_cb *c, void *d);
+int q_PEM_write_bio_DSA_PUBKEY(BIO *a, DSA *b);
+int q_PEM_write_bio_RSA_PUBKEY(BIO *a, RSA *b);
+void q_RAND_seed(const void *a, int b);
+int q_RAND_status();
+void q_RSA_free(RSA *a);
+int q_sk_num(STACK *a);
+void q_sk_pop_free(STACK *a, void (*b)(void *));
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+void q_sk_free(_STACK *a);
+void * q_sk_value(STACK *a, int b);
+#else
+void q_sk_free(STACK *a);
+char * q_sk_value(STACK *a, int b);
+#endif
+int q_SSL_accept(SSL *a);
+int q_SSL_clear(SSL *a);
+char *q_SSL_CIPHER_description(SSL_CIPHER *a, char *b, int c);
+int q_SSL_connect(SSL *a);
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+// 0.9.8 broke SC and BC by changing this function's signature.
+int q_SSL_CTX_check_private_key(const SSL_CTX *a);
+#else
+int q_SSL_CTX_check_private_key(SSL_CTX *a);
+#endif
+long q_SSL_CTX_ctrl(SSL_CTX *a, int b, long c, void *d);
+void q_SSL_CTX_free(SSL_CTX *a);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+SSL_CTX *q_SSL_CTX_new(const SSL_METHOD *a);
+#else
+SSL_CTX *q_SSL_CTX_new(SSL_METHOD *a);
+#endif
+int q_SSL_CTX_set_cipher_list(SSL_CTX *a, const char *b);
+int q_SSL_CTX_set_default_verify_paths(SSL_CTX *a);
+void q_SSL_CTX_set_verify(SSL_CTX *a, int b, int (*c)(int, X509_STORE_CTX *));
+void q_SSL_CTX_set_verify_depth(SSL_CTX *a, int b);
+int q_SSL_CTX_use_certificate(SSL_CTX *a, X509 *b);
+int q_SSL_CTX_use_certificate_file(SSL_CTX *a, const char *b, int c);
+int q_SSL_CTX_use_PrivateKey(SSL_CTX *a, EVP_PKEY *b);
+int q_SSL_CTX_use_RSAPrivateKey(SSL_CTX *a, RSA *b);
+int q_SSL_CTX_use_PrivateKey_file(SSL_CTX *a, const char *b, int c);
+void q_SSL_free(SSL *a);
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+// 0.9.8 broke SC and BC by changing this function's signature.
+STACK_OF(SSL_CIPHER) *q_SSL_get_ciphers(const SSL *a);
+#else
+STACK_OF(SSL_CIPHER) *q_SSL_get_ciphers(SSL *a);
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+const SSL_CIPHER *q_SSL_get_current_cipher(SSL *a);
+#else
+SSL_CIPHER *q_SSL_get_current_cipher(SSL *a);
+#endif
+int q_SSL_get_error(SSL *a, int b);
+STACK_OF(X509) *q_SSL_get_peer_cert_chain(SSL *a);
+X509 *q_SSL_get_peer_certificate(SSL *a);
+#if OPENSSL_VERSION_NUMBER >= 0x00908000L
+// 0.9.8 broke SC and BC by changing this function's signature.
+long q_SSL_get_verify_result(const SSL *a);
+#else
+long q_SSL_get_verify_result(SSL *a);
+#endif
+int q_SSL_library_init();
+void q_SSL_load_error_strings();
+SSL *q_SSL_new(SSL_CTX *a);
+#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
+long q_SSL_ctrl(SSL *ssl,int cmd, long larg, const void *parg);
+#endif
+int q_SSL_read(SSL *a, void *b, int c);
+void q_SSL_set_bio(SSL *a, BIO *b, BIO *c);
+void q_SSL_set_accept_state(SSL *a);
+void q_SSL_set_connect_state(SSL *a);
+int q_SSL_shutdown(SSL *a);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+const SSL_METHOD *q_SSLv2_client_method();
+const SSL_METHOD *q_SSLv3_client_method();
+const SSL_METHOD *q_SSLv23_client_method();
+const SSL_METHOD *q_TLSv1_client_method();
+const SSL_METHOD *q_SSLv2_server_method();
+const SSL_METHOD *q_SSLv3_server_method();
+const SSL_METHOD *q_SSLv23_server_method();
+const SSL_METHOD *q_TLSv1_server_method();
+#else
+SSL_METHOD *q_SSLv2_client_method();
+SSL_METHOD *q_SSLv3_client_method();
+SSL_METHOD *q_SSLv23_client_method();
+SSL_METHOD *q_TLSv1_client_method();
+SSL_METHOD *q_SSLv2_server_method();
+SSL_METHOD *q_SSLv3_server_method();
+SSL_METHOD *q_SSLv23_server_method();
+SSL_METHOD *q_TLSv1_server_method();
+#endif
+int q_SSL_write(SSL *a, const void *b, int c);
+int q_X509_cmp(X509 *a, X509 *b);
+#ifdef SSLEAY_MACROS
+void *q_ASN1_dup(i2d_of_void *i2d, d2i_of_void *d2i, char *x);
+#define q_X509_dup(x509) (X509 *)q_ASN1_dup((i2d_of_void *)q_i2d_X509, \
+ (d2i_of_void *)q_d2i_X509,(char *)x509)
+#else
+X509 *q_X509_dup(X509 *a);
+#endif
+ASN1_OBJECT *q_X509_EXTENSION_get_object(X509_EXTENSION *a);
+void q_X509_free(X509 *a);
+X509_EXTENSION *q_X509_get_ext(X509 *a, int b);
+int q_X509_get_ext_count(X509 *a);
+void *q_X509_get_ext_d2i(X509 *a, int b, int *c, int *d);
+X509_NAME *q_X509_get_issuer_name(X509 *a);
+X509_NAME *q_X509_get_subject_name(X509 *a);
+int q_X509_verify_cert(X509_STORE_CTX *ctx);
+char *q_X509_NAME_oneline(X509_NAME *a, char *b, int c);
+EVP_PKEY *q_X509_PUBKEY_get(X509_PUBKEY *a);
+void q_X509_STORE_free(X509_STORE *store);
+X509_STORE *q_X509_STORE_new();
+int q_X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
+void q_X509_STORE_CTX_free(X509_STORE_CTX *storeCtx);
+int q_X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store,
+ X509 *x509, STACK_OF(X509) *chain);
+X509_STORE_CTX *q_X509_STORE_CTX_new();
+int q_X509_STORE_CTX_set_purpose(X509_STORE_CTX *ctx, int purpose);
+
+#define q_BIO_get_mem_data(b, pp) (int)q_BIO_ctrl(b,BIO_CTRL_INFO,0,(char *)pp)
+#define q_BIO_pending(b) (int)q_BIO_ctrl(b,BIO_CTRL_PENDING,0,NULL)
+#ifdef SSLEAY_MACROS
+int q_i2d_DSAPrivateKey(const DSA *a, unsigned char **pp);
+int q_i2d_RSAPrivateKey(const RSA *a, unsigned char **pp);
+RSA *q_d2i_RSAPrivateKey(RSA **a, unsigned char **pp, long length);
+DSA *q_d2i_DSAPrivateKey(DSA **a, unsigned char **pp, long length);
+#define q_PEM_read_bio_RSAPrivateKey(bp, x, cb, u) \
+ (RSA *)q_PEM_ASN1_read_bio( \
+ (void *(*)(void**, const unsigned char**, long int))q_d2i_RSAPrivateKey, PEM_STRING_RSA, bp, (void **)x, cb, u)
+#define q_PEM_read_bio_DSAPrivateKey(bp, x, cb, u) \
+ (DSA *)q_PEM_ASN1_read_bio( \
+ (void *(*)(void**, const unsigned char**, long int))q_d2i_DSAPrivateKey, PEM_STRING_DSA, bp, (void **)x, cb, u)
+#define q_PEM_write_bio_RSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
+ PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_RSAPrivateKey,PEM_STRING_RSA,\
+ bp,(char *)x,enc,kstr,klen,cb,u)
+#define q_PEM_write_bio_DSAPrivateKey(bp,x,enc,kstr,klen,cb,u) \
+ PEM_ASN1_write_bio((int (*)(void*, unsigned char**))q_i2d_DSAPrivateKey,PEM_STRING_DSA,\
+ bp,(char *)x,enc,kstr,klen,cb,u)
+#endif
+#define q_SSL_CTX_set_options(ctx,op) q_SSL_CTX_ctrl((ctx),SSL_CTRL_OPTIONS,(op),NULL)
+#define q_SKM_sk_num(type, st) ((int (*)(const STACK_OF(type) *))q_sk_num)(st)
+#define q_SKM_sk_value(type, st,i) ((type * (*)(const STACK_OF(type) *, int))q_sk_value)(st, i)
+#define q_sk_GENERAL_NAME_num(st) q_SKM_sk_num(GENERAL_NAME, (st))
+#define q_sk_GENERAL_NAME_value(st, i) q_SKM_sk_value(GENERAL_NAME, (st), (i))
+#define q_sk_X509_num(st) q_SKM_sk_num(X509, (st))
+#define q_sk_X509_value(st, i) q_SKM_sk_value(X509, (st), (i))
+#define q_sk_SSL_CIPHER_num(st) q_SKM_sk_num(SSL_CIPHER, (st))
+#define q_sk_SSL_CIPHER_value(st, i) q_SKM_sk_value(SSL_CIPHER, (st), (i))
+#define q_SSL_CTX_add_extra_chain_cert(ctx,x509) \
+ q_SSL_CTX_ctrl(ctx,SSL_CTRL_EXTRA_CHAIN_CERT,0,(char *)x509)
+#define q_X509_get_notAfter(x) X509_get_notAfter(x)
+#define q_X509_get_notBefore(x) X509_get_notBefore(x)
+#define q_EVP_PKEY_assign_RSA(pkey,rsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_RSA,\
+ (char *)(rsa))
+#define q_EVP_PKEY_assign_DSA(pkey,dsa) q_EVP_PKEY_assign((pkey),EVP_PKEY_DSA,\
+ (char *)(dsa))
+#ifdef OPENSSL_LOAD_CONF
+#define q_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_conf()
+#else
+#define q_OpenSSL_add_all_algorithms() q_OPENSSL_add_all_algorithms_noconf()
+#endif
+void q_OPENSSL_add_all_algorithms_noconf();
+void q_OPENSSL_add_all_algorithms_conf();
+int q_SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath);
+long q_SSLeay();
+
+// Helper function
+class QDateTime;
+QDateTime q_getTimeFromASN1(const ASN1_TIME *aTime);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h
new file mode 100644
index 0000000000..4662c56ec4
--- /dev/null
+++ b/src/network/ssl/qsslsocket_p.h
@@ -0,0 +1,181 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtNetwork module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLSOCKET_P_H
+#define QSSLSOCKET_P_H
+
+#include "qsslsocket.h"
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of the QLibrary class. This header file may change from
+// version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qtcpsocket_p.h>
+#include "qsslkey.h"
+#include "qsslconfiguration_p.h"
+
+#include <QtCore/qstringlist.h>
+
+#include <private/qringbuffer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(Q_OS_MAC)
+#include <Security/SecCertificate.h>
+#include <CoreFoundation/CFArray.h>
+ typedef OSStatus (*PtrSecCertificateGetData)(SecCertificateRef, CSSM_DATA_PTR);
+ typedef OSStatus (*PtrSecTrustSettingsCopyCertificates)(int, CFArrayRef*);
+ typedef OSStatus (*PtrSecTrustCopyAnchorCertificates)(CFArrayRef*);
+#elif defined(Q_OS_WIN)
+#include <windows.h>
+#include <wincrypt.h>
+#ifndef HCRYPTPROV_LEGACY
+#define HCRYPTPROV_LEGACY HCRYPTPROV
+#endif
+#if defined(Q_OS_WINCE)
+ typedef HCERTSTORE (WINAPI *PtrCertOpenSystemStoreW)(LPCSTR, DWORD, HCRYPTPROV_LEGACY, DWORD, const void*);
+#else
+ typedef HCERTSTORE (WINAPI *PtrCertOpenSystemStoreW)(HCRYPTPROV_LEGACY, LPCWSTR);
+#endif
+ typedef PCCERT_CONTEXT (WINAPI *PtrCertFindCertificateInStore)(HCERTSTORE, DWORD, DWORD, DWORD, const void*, PCCERT_CONTEXT);
+ typedef BOOL (WINAPI *PtrCertCloseStore)(HCERTSTORE, DWORD);
+#endif
+
+
+
+class QSslSocketPrivate : public QTcpSocketPrivate
+{
+ Q_DECLARE_PUBLIC(QSslSocket)
+public:
+ QSslSocketPrivate();
+ virtual ~QSslSocketPrivate();
+
+ void init();
+ bool initialized;
+
+ QSslSocket::SslMode mode;
+ bool autoStartHandshake;
+ bool connectionEncrypted;
+ bool ignoreAllSslErrors;
+ QList<QSslError> ignoreErrorsList;
+ bool* readyReadEmittedPointer;
+
+ 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;
+
+ bool allowRootCertOnDemandLoading;
+
+ static bool supportsSsl();
+ static void ensureInitialized();
+ static void deinitialize();
+ static QList<QSslCipher> defaultCiphers();
+ static QList<QSslCipher> supportedCiphers();
+ static void setDefaultCiphers(const QList<QSslCipher> &ciphers);
+ static void setDefaultSupportedCiphers(const QList<QSslCipher> &ciphers);
+ static void resetDefaultCiphers();
+
+ static QList<QSslCertificate> defaultCaCertificates();
+ static QList<QSslCertificate> systemCaCertificates();
+ static void setDefaultCaCertificates(const QList<QSslCertificate> &certs);
+ static bool addDefaultCaCertificates(const QString &path, QSsl::EncodingFormat format,
+ QRegExp::PatternSyntax syntax);
+ static void addDefaultCaCertificate(const QSslCertificate &cert);
+ static void addDefaultCaCertificates(const QList<QSslCertificate> &certs);
+
+#if defined(Q_OS_MAC)
+ static PtrSecCertificateGetData ptrSecCertificateGetData;
+ static PtrSecTrustSettingsCopyCertificates ptrSecTrustSettingsCopyCertificates;
+ static PtrSecTrustCopyAnchorCertificates ptrSecTrustCopyAnchorCertificates;
+#elif defined(Q_OS_WIN)
+ static PtrCertOpenSystemStoreW ptrCertOpenSystemStoreW;
+ static PtrCertFindCertificateInStore ptrCertFindCertificateInStore;
+ static PtrCertCloseStore ptrCertCloseStore;
+#endif
+
+ // The socket itself, including private slots.
+ QTcpSocket *plainSocket;
+ void createPlainSocket(QIODevice::OpenMode openMode);
+ static void pauseSocketNotifiers(QSslSocket*);
+ static void resumeSocketNotifiers(QSslSocket*);
+ void _q_connectedSlot();
+ void _q_hostFoundSlot();
+ void _q_disconnectedSlot();
+ void _q_stateChangedSlot(QAbstractSocket::SocketState);
+ void _q_errorSlot(QAbstractSocket::SocketError);
+ void _q_readyReadSlot();
+ void _q_bytesWrittenSlot(qint64);
+ void _q_flushWriteBuffer();
+ void _q_flushReadBuffer();
+
+ // Platform specific functions
+ virtual void startClientEncryption() = 0;
+ virtual void startServerEncryption() = 0;
+ virtual void transmit() = 0;
+ virtual void disconnectFromHost() = 0;
+ virtual void disconnected() = 0;
+ virtual QSslCipher sessionCipher() const = 0;
+
+private:
+ static bool ensureLibraryLoaded();
+ static void ensureCiphersAndCertsLoaded();
+
+ static bool s_libraryLoaded;
+ static bool s_loadedCiphersAndCerts;
+protected:
+ static bool s_loadRootCertsOnDemand;
+ static QList<QByteArray> unixRootCertDirectories();
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
new file mode 100644
index 0000000000..8b2e2c1917
--- /dev/null
+++ b/src/network/ssl/ssl.pri
@@ -0,0 +1,36 @@
+# OpenSSL support; compile in QSslSocket.
+contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
+
+
+symbian {
+ INCLUDEPATH *= $$OS_LAYER_SSL_SYSTEMINCLUDE
+} else {
+ include($$QT_SOURCE_TREE/config.tests/unix/openssl/openssl.pri)
+}
+
+ HEADERS += ssl/qssl.h \
+ ssl/qsslcertificate.h \
+ ssl/qsslcertificate_p.h \
+ ssl/qsslconfiguration.h \
+ ssl/qsslconfiguration_p.h \
+ ssl/qsslcipher.h \
+ ssl/qsslcipher_p.h \
+ ssl/qsslerror.h \
+ ssl/qsslkey.h \
+ ssl/qsslsocket.h \
+ ssl/qsslsocket_openssl_p.h \
+ ssl/qsslsocket_openssl_symbols_p.h \
+ ssl/qsslsocket_p.h
+ SOURCES += ssl/qssl.cpp \
+ ssl/qsslcertificate.cpp \
+ ssl/qsslconfiguration.cpp \
+ ssl/qsslcipher.cpp \
+ ssl/qsslerror.cpp \
+ ssl/qsslkey.cpp \
+ ssl/qsslsocket.cpp \
+ ssl/qsslsocket_openssl.cpp \
+ ssl/qsslsocket_openssl_symbols.cpp
+
+ # Add optional SSL libs
+ LIBS_PRIVATE += $$OPENSSL_LIBS
+}