summaryrefslogtreecommitdiffstats
path: root/src/network/ssl
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/network/ssl
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
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
+}