summaryrefslogtreecommitdiffstats
path: root/src/network/ssl
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 10:18:55 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 10:18:55 +0100
commite5fcad302d86d316390c6b0f62759a067313e8a9 (patch)
treec2afbf6f1066b6ce261f14341cf6d310e5595bc1 /src/network/ssl
Long live Qt 4.5!
Diffstat (limited to 'src/network/ssl')
-rw-r--r--src/network/ssl/qssl.cpp117
-rw-r--r--src/network/ssl/qssl.h88
-rw-r--r--src/network/ssl/qsslcertificate.cpp795
-rw-r--r--src/network/ssl/qsslcertificate.h138
-rw-r--r--src/network/ssl/qsslcertificate_p.h108
-rw-r--r--src/network/ssl/qsslcipher.cpp239
-rw-r--r--src/network/ssl/qsslcipher.h97
-rw-r--r--src/network/ssl/qsslcipher_p.h78
-rw-r--r--src/network/ssl/qsslconfiguration.cpp545
-rw-r--r--src/network/ssl/qsslconfiguration.h137
-rw-r--r--src/network/ssl/qsslconfiguration_p.h115
-rw-r--r--src/network/ssl/qsslerror.cpp293
-rw-r--r--src/network/ssl/qsslerror.h117
-rw-r--r--src/network/ssl/qsslkey.cpp468
-rw-r--r--src/network/ssl/qsslkey.h110
-rw-r--r--src/network/ssl/qsslkey_p.h98
-rw-r--r--src/network/ssl/qsslsocket.cpp2045
-rw-r--r--src/network/ssl/qsslsocket.h217
-rw-r--r--src/network/ssl/qsslsocket_openssl.cpp929
-rw-r--r--src/network/ssl/qsslsocket_openssl_p.h116
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols.cpp650
-rw-r--r--src/network/ssl/qsslsocket_openssl_symbols_p.h394
-rw-r--r--src/network/ssl/qsslsocket_p.h130
-rw-r--r--src/network/ssl/qt-ca-bundle.crt1984
-rw-r--r--src/network/ssl/ssl.pri33
25 files changed, 10041 insertions, 0 deletions
diff --git a/src/network/ssl/qssl.cpp b/src/network/ssl/qssl.cpp
new file mode 100644
index 0000000000..e2d0743f85
--- /dev/null
+++ b/src/network/ssl/qssl.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 io
+ \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 - the default protocol.
+ \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.
+
+ 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..bd0d943b11
--- /dev/null
+++ b/src/network/ssl/qssl.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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,
+ AnyProtocol,
+ 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..a2ba644833
--- /dev/null
+++ b/src/network/ssl/qsslcertificate.cpp
@@ -0,0 +1,795 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QSslCertificate
+ \brief The QSslCertificate class provides a convenient API for an X509 certificate.
+ \since 4.3
+
+ \reentrant
+ \ingroup io
+ \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 notValidBefore() and
+ notValidAfter() to check when the certificate was issued, 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
+
+/*!
+ 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)
+{
+ d->ref.ref();
+}
+
+/*!
+ Destroys the QSslCertificate.
+*/
+QSslCertificate::~QSslCertificate()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ Copies the contents of \a other into this certificate, making the two
+ certificates identical.
+*/
+QSslCertificate &QSslCertificate::operator=(const QSslCertificate &other)
+{
+ qAtomicAssign(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 only checks that the current
+ data-time is within the date-time range during which the
+ certificate is considered valid. No other checks are
+ currently performed.
+
+ \sa isNull()
+*/
+bool QSslCertificate::isValid() const
+{
+ const QDateTime currentTime = QDateTime::currentDateTime();
+ return currentTime >= d->notValidBefore && currentTime <= d->notValidAfter;
+}
+
+/*!
+ Clears the contents of this certificate, making it a null
+ certificate.
+
+ \sa isNull()
+*/
+void QSslCertificate::clear()
+{
+ if (isNull())
+ return;
+ if (d->ref == 1)
+ delete d;
+ else
+ d->ref.deref();
+
+ d = new QSslCertificatePrivate;
+}
+
+/*!
+ Returns the certificate's version string.
+*/
+QByteArray QSslCertificate::version() const
+{
+ return d->versionString;
+}
+
+/*!
+ Returns the certificate's serial number string.
+*/
+QByteArray QSslCertificate::serialNumber() const
+{
+ return d->serialNumberString;
+}
+
+/*!
+ Returns a cryptographic digest of this certificate. By default,
+ and 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
+{
+ 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
+{
+ // ### Use a QByteArray for the keys in the map
+ 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
+{
+ 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
+{
+ // ### Use a QByteArray for the keys in the map
+ 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 *altNames = (STACK *)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 = QLatin1String(QByteArray(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_free(altNames);
+ }
+
+ 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()) {
+ 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;
+
+ certificate.d->issuerInfo =
+ _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_issuer_name(x509), 0, 0));
+ certificate.d->subjectInfo =
+ _q_mapFromOnelineName(q_X509_NAME_oneline(q_X509_get_subject_name(x509), 0, 0));
+
+ ASN1_TIME *nbef = q_X509_get_notBefore(x509);
+ ASN1_TIME *naft = q_X509_get_notAfter(x509);
+ certificate.d->notValidBefore = q_getTimeFromASN1(nbef);
+ 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 = pem.at(*offset);
+
+ // ignore extra whitespace at the end of the line
+ while (ch == ' ' && *offset < pem.size())
+ ch = pem.at(++*offset);
+
+ if (ch == '\n') {
+ *offset++;
+ 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 (!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;
+}
+
+#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..d4597cd5b2
--- /dev/null
+++ b/src/network/ssl/qsslcertificate.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 <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:
+ 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..cbf374b618
--- /dev/null
+++ b/src/network/ssl/qsslcertificate_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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();
+ ref = 1;
+ }
+
+ ~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);
+
+ 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..505c6625fd
--- /dev/null
+++ b/src/network/ssl/qsslcipher.cpp
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QSslCipher
+ \brief The QSslCipher class represents an SSL cryptographic cipher.
+ \since 4.3
+
+ \reentrant
+ \ingroup io
+ \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>
+
+QT_BEGIN_NAMESPACE
+#endif
+
+/*!
+ 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 = *other.d;
+}
+
+/*!
+ Destroys the QSslCipher object.
+*/
+QSslCipher::~QSslCipher()
+{
+ delete d;
+}
+
+/*!
+ Copies the contents of \a other into this cipher, making the two
+ ciphers identical.
+*/
+QSslCipher &QSslCipher::operator=(const QSslCipher &other)
+{
+ *d = *other.d;
+ 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..404dc3db25
--- /dev/null
+++ b/src/network/ssl/qsslcipher.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLCIPHER_H
+#define QSSLCIPHER_H
+
+#include <QtCore/qstring.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:
+ 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..46e5054f29
--- /dev/null
+++ b/src/network/ssl/qsslcipher_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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..4a0f226b14
--- /dev/null
+++ b/src/network/ssl/qsslconfiguration.cpp
@@ -0,0 +1,545 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsslconfiguration.h"
+#include "qsslconfiguration_p.h"
+#include "qsslsocket.h"
+#include "qmutex.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+template<> void QSharedDataPointer<QSslConfigurationPrivate>::detach()
+{
+ if (d && d->ref == 1)
+ return;
+ QSslConfigurationPrivate *x = (d ? new QSslConfigurationPrivate(*d)
+ : new QSslConfigurationPrivate);
+ x->ref.ref();
+ if (d && !d->ref.deref())
+ delete d;
+ d = x;
+}
+
+/*!
+ \class QSslConfiguration
+ \brief The QSslConfiguration class holds the configuration and state of an SSL connection
+ \since 4.4
+
+ \reentrant
+ \inmodule QtNetwork
+ \ingroup io
+ \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(0)
+{
+}
+
+/*!
+ 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 == 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 == 0;
+}
+
+/*!
+ Returns the protocol setting for this SSL configuration.
+
+ \sa setProtocol()
+*/
+QSsl::SslProtocol QSslConfiguration::protocol() const
+{
+ return d ? d->protocol : QSsl::SslV3;
+}
+
+/*!
+ 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 ? d->peerVerifyMode : QSslSocket::AutoVerifyPeer;
+}
+
+/*!
+ 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 ? d->peerVerifyDepth : 0;
+}
+
+/*!
+ 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 ? d->localCertificate : QSslCertificate();
+}
+
+/*!
+ 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 ? d->peerCertificate : QSslCertificate();
+}
+
+/*!
+ 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 ? d->peerCertificateChain : QList<QSslCertificate>();
+}
+
+/*!
+ 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 ? d->sessionCipher : QSslCipher();
+}
+
+/*!
+ 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 ? d->privateKey : QSslKey();
+}
+
+/*!
+ 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 ? d->ciphers : QList<QSslCipher>();
+}
+
+/*!
+ 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 moodified prior to the
+ handshake with addCaCertificate(), addCaCertificates(), and
+ setCaCertificates().
+
+ \sa setCaCertificates()
+*/
+QList<QSslCertificate> QSslConfiguration::caCertificates() const
+{
+ return d ? d->caCertificates : QList<QSslCertificate>();
+}
+
+/*!
+ 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 SSLv3
+ \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..fa3d646caa
--- /dev/null
+++ b/src/network/ssl/qsslconfiguration.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** In addition, as a special exception, Trolltech 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;
+
+ 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..3c4dbeee65
--- /dev/null
+++ b/src/network/ssl/qsslconfiguration_p.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** In addition, as a special exception, Trolltech 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::SslV3),
+ 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..daa6533af5
--- /dev/null
+++ b/src/network/ssl/qsslerror.cpp
@@ -0,0 +1,293 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QSslError
+ \brief The QSslError class provides an SSL error.
+ \since 4.3
+
+ \reentrant
+ \ingroup io
+ \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
+
+ \sa QSslError::errorString()
+*/
+
+#include "qsslerror.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. The two optional 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 = *other.d;
+}
+
+/*!
+ Destroys the QSslError object.
+*/
+QSslError::~QSslError()
+{
+ delete d;
+}
+
+/*!
+ \since 4.4
+
+ Assigns the contents of \a other to this error.
+*/
+QSslError &QSslError::operator=(const QSslError &other)
+{
+ *d = *other.d;
+ 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 = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "No error"));
+ break;
+ case UnableToGetIssuerCertificate:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The issuer certificate could not be found"));
+ break;
+ case UnableToDecryptCertificateSignature:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The certificate signature could not be decrypted"));
+ break;
+ case UnableToDecodeIssuerPublicKey:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The public key in the certificate could not be read"));
+ break;
+ case CertificateSignatureFailed:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The signature of the certificate is invalid"));
+ break;
+ case CertificateNotYetValid:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The certificate is not yet valid"));
+ break;
+ case CertificateExpired:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The certificate has expired"));
+ break;
+ case InvalidNotBeforeField:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The certificate's notBefore field contains an invalid time"));
+ break;
+ case InvalidNotAfterField:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The certificate's notAfter field contains an invalid time"));
+ break;
+ case SelfSignedCertificate:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The certificate is self-signed, and untrusted"));
+ break;
+ case SelfSignedCertificateInChain:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The root certificate of the certificate chain is self-signed, and untrusted"));
+ break;
+ case UnableToGetLocalIssuerCertificate:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The issuer certificate of a locally looked up certificate could not be found"));
+ break;
+ case UnableToVerifyFirstCertificate:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "No certificates could be verified"));
+ break;
+ case InvalidCaCertificate:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "One of the CA certificates is invalid"));
+ break;
+ case PathLengthExceeded:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The basicConstraints pathlength parameter has been exceeded"));
+ break;
+ case InvalidPurpose:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The supplied certificate is unsuited for this purpose"));
+ break;
+ case CertificateUntrusted:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The root CA certificate is not trusted for this purpose"));
+ break;
+ case CertificateRejected:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The root CA certificate is marked to reject the specified purpose"));
+ break;
+ case SubjectIssuerMismatch: // hostname mismatch
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError,
+ "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 = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "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 = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "The peer did not present any certificate"));
+ break;
+ case HostNameMismatch:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError,
+ "The host name did not match any of the valid hosts"
+ " for this certificate"));
+ break;
+ case NoSslSupport:
+ break;
+ default:
+ errStr = QObject::tr(QT_TRANSLATE_NOOP(QSslError, "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..c120215f42
--- /dev/null
+++ b/src/network/ssl/qsslerror.h
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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,
+ UnspecifiedError = -1
+ };
+
+ QSslError(SslError error = NoError, const QSslCertificate &certificate = QSslCertificate());
+ 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:
+ 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..8d550c0f6f
--- /dev/null
+++ b/src/network/ssl/qsslkey.cpp
@@ -0,0 +1,468 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \class QSslKey
+ \brief The QSslKey class provides an interface for private and public keys.
+ \since 4.3
+
+ \reentrant
+ \ingroup io
+ \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 = passPhrase.isEmpty()
+ ? (void *)0
+ : (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)
+{
+ d->ref.ref();
+}
+
+/*!
+ Destroys the QSslKey object.
+*/
+QSslKey::~QSslKey()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ 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)
+{
+ qAtomicAssign(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()
+{
+ if (!d->ref.deref()) {
+ delete d;
+ 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..45d03f7b95
--- /dev/null
+++ b/src/network/ssl/qsslkey.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QSSLKEY_H
+#define QSSLKEY_H
+
+#include <QtCore/qnamespace.h>
+#include <QtCore/qbytearray.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:
+ 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..c809015145
--- /dev/null
+++ b/src/network/ssl/qsslkey_p.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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();
+ ref = 1;
+ }
+
+ 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;
+};
+
+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..ea64042bb1
--- /dev/null
+++ b/src/network/ssl/qsslsocket.cpp
@@ -0,0 +1,2045 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 io
+ \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 SSLv3, 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 bytesWritten() 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
+
+ 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/}).
+
+ \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 automaticaly 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/qdatetime.h>
+#include <QtCore/qmutex.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);
+}
+
+/*!
+ 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;
+}
+
+/*!
+ 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 descrypts 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::SslV3 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, QueryPeer for clients.
+
+ \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, QueryPeer for clients.
+
+ 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;
+}
+
+/*!
+ \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
+ QTcpSocket::close();
+}
+
+/*!
+ \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;
+
+ // set the plain socket's buffer size to 1k if we have a limit
+ // see also the same logic in QSslSocketPrivate::createPlainSocket
+ if (d->plainSocket) {
+ if (d->mode == UnencryptedMode)
+ d->plainSocket->setReadBufferSize(size);
+ else
+ d->plainSocket->setReadBufferSize(size ? 1024 : 0);
+ }
+}
+
+/*!
+ 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();
+}
+
+/*!
+ 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 (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;
+}
+
+/*!
+ 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().
+
+ \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. If no system default database is
+ found, Qt will provide its own default 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, Qt will provide its own
+ default database. 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.
+
+ \sa caCertificates()
+*/
+QList<QSslCertificate> QSslSocket::defaultCaCertificates()
+{
+ return QSslSocketPrivate::defaultCaCertificates();
+}
+
+/*!
+ Returns the system default CA certificate database for your
+ system. This database is normally found in a standard place for
+ your system. If it is not found there, Qt will provide its own
+ default CA certificate database. 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()
+{
+ QSslSocketPrivate::ensureInitialized();
+ 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;
+
+ QTime 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;
+
+ QTime 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);
+
+ QTime 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);
+
+ QTime 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::ensureInitialized();
+}
+
+/*!
+ 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::startClientEncryption: 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->ignoreSslErrors = true;
+}
+
+/*!
+ \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
+ 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), readyReadEmittedPointer(0), plainSocket(0)
+{
+ QSslConfigurationPrivate::deepCopyDefaultConfiguration(&configuration);
+}
+
+/*!
+ \internal
+*/
+QSslSocketPrivate::~QSslSocketPrivate()
+{
+}
+
+/*!
+ \internal
+*/
+void QSslSocketPrivate::init()
+{
+ mode = QSslSocket::UnencryptedMode;
+ autoStartHandshake = false;
+ connectionEncrypted = false;
+ ignoreSslErrors = false;
+
+ 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()
+{
+ 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;
+}
+
+/*!
+ \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();
+
+ 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);
+ 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);
+}
+
+/*!
+ \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();
+}
+
+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..b8db65443f
--- /dev/null
+++ b/src/network/ssl/qsslsocket.h
@@ -0,0 +1,217 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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);
+ bool setSocketDescriptor(int socketDescriptor, SocketState state = ConnectedState,
+ OpenMode openMode = ReadWrite);
+
+ 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);
+
+ // 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();
+
+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())
+ 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..6f8cf42762
--- /dev/null
+++ b/src/network/ssl/qsslsocket_openssl.cpp
@@ -0,0 +1,929 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qthread.h>
+#include <QtCore/qurl.h>
+#include <QtCore/qvarlengtharray.h>
+
+static void initNetworkResources()
+{
+ // Initialize resources
+ Q_INIT_RESOURCE(network);
+}
+
+QT_BEGIN_NAMESPACE
+
+// Useful defines
+#define SSL_ERRORSTR() QString::fromLocal8Bit(q_ERR_error_string(q_ERR_get_error(), NULL))
+
+/* \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 (unsigned long)QThread::currentThreadId();
+}
+} // extern "C"
+
+QSslSocketBackendPrivate::QSslSocketBackendPrivate()
+ : ssl(0),
+ ctx(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::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(SSL_ERRORSTR()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ // Enable all bug workarounds.
+ 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(SSL_ERRORSTR()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ // Add all our CAs to this store.
+ foreach (const QSslCertificate &caCertificate, q->caCertificates())
+ q_X509_STORE_add_cert(ctx->cert_store, (X509 *)caCertificate.handle());
+
+ // 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(SSL_ERRORSTR()));
+ 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(SSL_ERRORSTR()));
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ // Load private key
+ EVP_PKEY *pkey = q_EVP_PKEY_new();
+ if (configuration.privateKey.algorithm() == QSsl::Rsa)
+ q_EVP_PKEY_assign_RSA(pkey, (RSA *)configuration.privateKey.handle());
+ else
+ q_EVP_PKEY_assign_DSA(pkey, (DSA *)configuration.privateKey.handle());
+ if (!q_SSL_CTX_use_PrivateKey(ctx, pkey)) {
+ q->setErrorString(QSslSocket::tr("Error loading private key, %1").arg(SSL_ERRORSTR()));
+ 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 certificate public key, %1").arg(SSL_ERRORSTR()));
+ 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(SSL_ERRORSTR()));
+ q->setSocketError(QAbstractSocket::UnknownSocketError);
+ emit q->error(QAbstractSocket::UnknownSocketError);
+ return false;
+ }
+
+ // 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(SSL_ERRORSTR()));
+ 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
+
+ Declared static in QSslSocketPrivate, makes sure the SSL libraries have
+ been initialized.
+*/
+bool QSslSocketPrivate::ensureInitialized()
+{
+ if (!q_resolveOpenSslSymbols())
+ return false;
+
+ // Check if the library itself needs to be initialized.
+ QMutexLocker locker(openssl_locks()->initLock());
+ static int q_initialized = false;
+ if (!q_initialized) {
+ q_initialized = true;
+
+ // Initialize resources
+ initNetworkResources();
+
+ // 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;
+ }
+
+ resetDefaultCiphers();
+ setDefaultCaCertificates(systemCaCertificates());
+ }
+ return true;
+}
+
+/*!
+ \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);
+}
+
+QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates()
+{
+#ifdef QQ_OS_UNIX
+ // Check known locations for the system's default bundle. ### On Windows,
+ // we should use CAPI to find the bundle, and not rely on default unix
+ // locations.
+ const char *standardLocations[] = {"/etc/ssl/certs/",
+#if 0
+ // KDE uses KConfig for its SSL store,
+ // but it also stores the bundle at
+ // this location
+ "$HOME/.kde/share/apps/kssl/ca-bundle.crt",
+#endif
+ 0};
+ const char **it = standardLocations;
+ QStringList nameFilter;
+ nameFilter << QLatin1String("*.pem") << QLatin1String("*.crt");
+ while (*it) {
+ if (QDirIterator(QLatin1String(*it), nameFilter).hasNext())
+ return certificatesFromPath(QLatin1String(*it));
+ ++it;
+ }
+#endif
+
+ // Qt provides a default bundle when we cannot detect the system's default
+ // bundle.
+ QFile caBundle(QLatin1String(":/trolltech/network/ssl/qt-ca-bundle.crt"));
+ if (caBundle.open(QIODevice::ReadOnly | QIODevice::Text))
+ return QSslCertificate::fromDevice(&caBundle);
+
+ // Unreachable; return no bundle.
+ return QList<QSslCertificate>();
+}
+
+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().
+ testConnection();
+ 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().
+ testConnection();
+ 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(SSL_ERRORSTR()));
+ 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 (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);
+ int decryptedBytesRead = plainSocket->read(data.data(), pendingBytes);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::transmit: read" << decryptedBytesRead << "encrypted bytes from the socket";
+#endif
+ // Write encrypted data from the buffer into the read BIO.
+ q_BIO_write(readBio, data.constData(), decryptedBytesRead);
+ 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 (testConnection()) {
+#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 testConnection() 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;
+ default:
+ // ### Handle errors better.
+ q->setErrorString(QSslSocket::tr("Error while reading: %1").arg(SSL_ERRORSTR()));
+ 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::testConnection()
+{
+ 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:
+ // ### Handle errors better
+ q->setErrorString(QSslSocket::tr("Error during SSL handshake: %1").arg(SSL_ERRORSTR()));
+ q->setSocketError(QAbstractSocket::SslHandshakeFailedError);
+#ifdef QSSLSOCKET_DEBUG
+ qDebug() << "QSslSocketBackendPrivate::testConnection: error!" << q->errorString();
+#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;
+ 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 = q->peerName();
+ QString commonName = configuration.peerCertificate.subjectInfo(QSslCertificate::CommonName);
+
+ QRegExp regexp(commonName, Qt::CaseInsensitive, QRegExp::Wildcard);
+ if (!regexp.exactMatch(peerName)) {
+ bool matched = false;
+ foreach (QString altName, configuration.peerCertificate
+ .alternateSubjectNames().values(QSsl::DnsEntry)) {
+ regexp.setPattern(altName);
+ if (regexp.exactMatch(peerName)) {
+ 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);
+ if (doVerifyPeer && !ignoreSslErrors) {
+ 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;
+ }
+}
+
+QSslCipher QSslSocketBackendPrivate::sessionCipher() const
+{
+ if (!ssl || !ctx)
+ return QSslCipher();
+ SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);
+ 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;
+}
+
+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..b3be42afc7
--- /dev/null
+++ b/src/network/ssl/qsslsocket_openssl_p.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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 <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>
+
+QT_BEGIN_NAMESPACE
+
+class QSslSocketBackendPrivate : public QSslSocketPrivate
+{
+ Q_DECLARE_PUBLIC(QSslSocket)
+public:
+ QSslSocketBackendPrivate();
+ virtual ~QSslSocketBackendPrivate();
+
+ // SSL context
+ bool initSslContext();
+ SSL *ssl;
+ SSL_CTX *ctx;
+ 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 testConnection();
+ 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);
+};
+
+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..e09e764bec
--- /dev/null
+++ b/src/network/ssl/qsslsocket_openssl_symbols.cpp
@@ -0,0 +1,650 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qsslsocket_openssl_symbols_p.h"
+
+#include <QtCore/qlibrary.h>
+#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(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)
+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(void, sk_free, STACK *a, a, return, DUMMYARG)
+DEFINEFUNC(int, sk_num, STACK *a, a, return -1, return)
+DEFINEFUNC2(char *, sk_value, STACK *a, a, int b, b, return 0, return)
+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)
+DEFINEFUNC(SSL_CTX *, SSL_CTX_new, SSL_METHOD *a, a, return 0, return)
+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
+DEFINEFUNC(SSL_CIPHER *, SSL_get_current_cipher, SSL *a, a, return 0, return)
+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)
+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)
+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)
+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)
+
+#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);
+
+#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("/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
+
+static QPair<QLibrary*, QLibrary*> loadOpenSsl()
+{
+ QPair<QLibrary*,QLibrary*> pair;
+ pair.first = 0;
+ pair.second = 0;
+
+# ifdef Q_OS_WIN
+ QLibrary *ssleay32 = new QLibrary(QLatin1String("ssleay32"));
+ if (!ssleay32->load()) {
+ // Cannot find ssleay32.dll
+ delete ssleay32;
+ return pair;
+ }
+
+ QLibrary *libeay32 = new QLibrary(QLatin1String("libeay32"));
+ if (!libeay32->load()) {
+ delete ssleay32;
+ delete libeay32;
+ return pair;
+ }
+
+ pair.first = ssleay32;
+ pair.second = libeay32;
+ 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 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 (libssl->load() && libcrypto->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 (libssl->load() && libcrypto->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 (libssl->load() && libcrypto->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
+}
+
+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;
+
+ QPair<QLibrary *, QLibrary *> libs = loadOpenSsl();
+ if (!libs.first || !libs.second)
+ // failed to load them
+ return false;
+
+#ifdef SSLEAY_MACROS
+ RESOLVEFUNC(ASN1_dup)
+#endif
+ 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_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_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)
+ 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)
+ 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_SSL
+ 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)
+{
+ char lBuffer[24];
+ char *pBuffer = lBuffer;
+
+ size_t lTimeLength = aTime->length;
+ char *pString = (char *) aTime->data;
+
+ if (aTime->type == V_ASN1_UTCTIME) {
+ if ((lTimeLength < 11) || (lTimeLength > 17))
+ return QDateTime();
+
+ memcpy(pBuffer, pString, 10);
+ pBuffer += 10;
+ pString += 10;
+ } else {
+ if (lTimeLength < 13)
+ return QDateTime();
+
+ memcpy(pBuffer, pString, 12);
+ pBuffer += 12;
+ pString += 12;
+ }
+
+ 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;
+}
+
+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..c6ae91e6a5
--- /dev/null
+++ b/src/network/ssl/qsslsocket_openssl_symbols_p.h
@@ -0,0 +1,394 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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();
+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);
+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);
+void q_sk_free(STACK *a);
+int q_sk_num(STACK *a);
+char * q_sk_value(STACK *a, int b);
+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);
+SSL_CTX *q_SSL_CTX_new(SSL_METHOD *a);
+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
+SSL_CIPHER *q_SSL_get_current_cipher(SSL *a);
+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);
+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);
+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();
+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();
+
+// 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..825df46b6e
--- /dev/null
+++ b/src/network/ssl/qsslsocket_p.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (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 either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** 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.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@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
+
+class QSslSocketPrivate : public QTcpSocketPrivate
+{
+ Q_DECLARE_PUBLIC(QSslSocket)
+public:
+ QSslSocketPrivate();
+ virtual ~QSslSocketPrivate();
+
+ void init();
+ bool initialized;
+
+ QSslSocket::SslMode mode;
+ bool autoStartHandshake;
+ bool connectionEncrypted;
+ bool ignoreSslErrors;
+ bool* readyReadEmittedPointer;
+
+ QRingBuffer readBuffer;
+ QRingBuffer writeBuffer;
+
+ QSslConfigurationPrivate configuration;
+ QList<QSslError> sslErrors;
+
+ static bool 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);
+
+ // The socket itself, including private slots.
+ QTcpSocket *plainSocket;
+ void createPlainSocket(QIODevice::OpenMode openMode);
+ 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();
+
+ // 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;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/network/ssl/qt-ca-bundle.crt b/src/network/ssl/qt-ca-bundle.crt
new file mode 100644
index 0000000000..7755ca0091
--- /dev/null
+++ b/src/network/ssl/qt-ca-bundle.crt
@@ -0,0 +1,1984 @@
+##
+## ca-bundle.crt -- Bundle of CA Certificates
+##
+## This is a bundle of X.509 certificates of public
+## Certificate Authorities (CA).
+##
+
+-----BEGIN CERTIFICATE-----
+MIICfTCCAeagAwIBAgIEAgAAuDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSkwJwYD
+VQQDEyBCYWx0aW1vcmUgQ3liZXJUcnVzdCBNb2JpbGUgUm9vdDAeFw0wMDA1MTIx
+ODIwMDBaFw0yMDA1MTIyMzU5MDBaMGExCzAJBgNVBAYTAklFMRIwEAYDVQQKEwlC
+YWx0aW1vcmUxEzARBgNVBAsTCkN5YmVyVHJ1c3QxKTAnBgNVBAMTIEJhbHRpbW9y
+ZSBDeWJlclRydXN0IE1vYmlsZSBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQCjbbE4Vqz8tVYh3sCQXSZHgsZ9jx+ghY8vu9ThHB3yJB8osC+5pKVvoiIg
+ZP6ERzx+K2xparjUwJaOjFINzW9B1L8ErqeBLy2YSNLBlKO1GV1dUWT0jkGwm8At
+IqBexthaEmO8EUpeJhId4iYF5g9fIh96X3aUrs9aKA6rRdoiMQIDAQABo0IwQDAd
+BgNVHQ4EFgQUyeKPwAImWrbAB+N/lAcY2y6lmnAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQEFBQADgYEAUwgLJgl4QnPU7Hp3Rw3j
+CzNx764zFE37+v0at1H15JkcBnHXKRnX5hUgUVFGbU/eGEmY0Ph4u3HojQEG1ddk
+j5TfR/6ghWk2qS9CemhKEtaLC3BECqQE7yaIwTVxOF0bW0hC8OeUHHCVNKir9avi
+eK318FL9m+pCDOjYVL5TZvU=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMTAeFw05ODEyMTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCg
+bIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJENySZ
+j9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlV
+Sn5JTe2io74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMTAxODEw
+MjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFGp5
+fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i
++DAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lN
+QseSJqBcNJo4cvj9axY+IO6CizEqkzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+
+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4RbyhkwS7hp86W0N6w4pl
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACEQDQHkCLAAACfAAAAAIAAAABMA0GCSqGSIb3DQEBBQUAMIGpMQsw
+CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp
+dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE
+CxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDExITAfBgkqhkiG9w0B
+CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODEyMDExODE4NTVaFw0wODExMjgx
+ODE4NTVaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO
+U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0
+IENvLjERMA8GA1UECxMIRFNUQ0EgWDExFjAUBgNVBAMTDURTVCBSb290Q0EgWDEx
+ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANLGJrbnpT3BxGjVUG9TxW9JEwm4ryxIjRRqoxdf
+WvnTLnUv2Chi0ZMv/E3Uq4flCMeZ55I/db3rJbQVwZsZPdJEjdd0IG03Ao9pk1uK
+xBmd9LIO/BZsubEFkoPRhSxglD5FVaDZqwgh5mDoO3TymVBRaNADLbGAvqPYUrBE
+zUNKcI5YhZXhTizWLUFv1oTnyJhEykfbLCSlaSbPa7gnYsP0yXqSI+0TZ4KuRS5F
+5X5yP4WdlGIQ5jyRoa13AOAV7POEgHJ6jm5gl8ckWRA0g1vhpaRptlc1HHhZxtMv
+OnNn7pTKBBMFYgZwI7P0fO5F2WQLW0mqpEPOJsREEmy43XkCAwEAATANBgkqhkiG
+9w0BAQUFAAOCAQEAojeyP2n714Z5VEkxlTMr89EJFEliYIalsBHiUMIdBlc+Legz
+ZL6bqq1fG03UmZWii5rJYnK1aerZWKs17RWiQ9a2vAd5ZWRzfdd5ynvVWlHG4VME
+lo04z6MXrDlxawHDi1M8Y+nuecDkvpIyZHqzH5eUYr3qsiAVlfuX8ngvYzZAOONG
+Dx3drJXK50uQe7FLqdTF65raqtWjlBRGjS0f8zrWkzr2Pnn86Oawde3uPclwx12q
+gUtGJRzHbBXjlU4PqjI3lAoXJJIThFjSY28r9+ZbYgsTF7ANUkz+/m9c4pFuHf2k
+Ytdo+o56T9II2pPc8JIRetDccpMMc5NihWjQ9A==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJV
+UzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQL
+EwhEU1RDQSBFMjAeFw05ODEyMDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJ
+BgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4x
+ETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQC/
+k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGODVvso
+LeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3o
+TQPMx7JSxhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCG
+SAGG+EIBAQQEAwIABzBoBgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMx
+JDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UECxMI
+RFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQwIoAPMTk5ODEyMDkxOTE3
+MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFB6C
+TShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5
+WzAMBgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqG
+SIb3DQEBBQUAA4GBAEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHR
+xdf0CiUPPXiBng+xZ8SQTGPdXqfiup/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVL
+B3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1mPnHfxsb1gYgAlihw6ID
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID2DCCAsACEQDQHkCLAAB3bQAAAAEAAAAEMA0GCSqGSIb3DQEBBQUAMIGpMQsw
+CQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp
+dHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjERMA8GA1UE
+CxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIxITAfBgkqhkiG9w0B
+CQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTAeFw05ODExMzAyMjQ2MTZaFw0wODExMjcy
+MjQ2MTZaMIGpMQswCQYDVQQGEwJ1czENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMO
+U2FsdCBMYWtlIENpdHkxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0
+IENvLjERMA8GA1UECxMIRFNUQ0EgWDIxFjAUBgNVBAMTDURTVCBSb290Q0EgWDIx
+ITAfBgkqhkiG9w0BCQEWEmNhQGRpZ3NpZ3RydXN0LmNvbTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBANx18IzAdZaawGIfJvfE4Zrq4FZzW5nNAUSoCLbV
+p9oaBBg5kkp4o4HC9Xd6ULRw/5qrxsfKboNPQpj7Jgva3G3WqZlVUmfpKAOS3OWw
+BZoPFflrWXJW8vo5/Kpo7g8fEIMv/J36F5bdguPmRX3AS4BEH+0s4IT9kVySVGkl
+5WJp3OXuAFK9MwutdQKFp2RQLcUZGTDAJtvJ0/0uma1ZtQtN1EGuhUhDWdy3qOKi
+3sOP17ihYqZoUFLkzzGnlIXan0YyF1bl8utmPRL/Q9uY73fPy4GNNLHGUEom0eQ+
+QVCvbK4iNC7Va26Dunm4dmVI2gkpZGMiuftHdoWMhkTLCdsCAwEAATANBgkqhkiG
+9w0BAQUFAAOCAQEAtTYOXeFhKFoRZcA/gwN5Tb4opgsHAlKFzfiR0BBstWogWxyQ
+2TA8xkieil5k+aFxd+8EJx8H6+Qm93N0yUQYGmbT4EOvkTvRyyzYdFQ6HE3K1GjN
+I3wdEJ5F6fYAbqbNGf9PLCmPV03Ed5K+4EwJ+11EhmYhqLkyolbV6YyDfFk/xPEL
+553snr2cGA4+wjl5KLcDDQjLxufZATdQEOzMYRZA1K8xdHv8PzGn0EdzMzkbzE5q
+10mDEQb+64JYMzJM8FasHpwvVpp7wUocpf1VNs78lk30sPDst2yC7S8xmUJMqbIN
+uBVd8d+6ybVK1GSYsyapMMj9puyrliGtf8J4tg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50cnVzdC5u
+ZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBsaW1pdHMgbGlh
+Yi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
+BAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBaMIHJMQswCQYDVQQGEwJVUzEU
+MBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9D
+bGllbnRfQ0FfSW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjEl
+MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMq
+RW50cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0G
+CSqGSIb3DQEBAQUAA4GLADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo
+6oT9n3V5z8GKUZSvx1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux
+5zDeg7K6PvHViTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zm
+AqTmT173iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSC
+ARkwggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50
+cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5m
+by9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMp
+IDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQg
+Q2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCyg
+KqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9DbGllbnQxLmNybDArBgNV
+HRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkxMDEyMTkyNDMwWjALBgNVHQ8E
+BAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW/O5bs8qZdIuV6kwwHQYDVR0OBBYE
+FMT7nCl7l81MlvzuW7PKmXSLlepMMAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EA
+BAwwChsEVjQuMAMCBJAwDQYJKoZIhvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7
+pFuPeJoSSJn59DXeDDYHAmsQOokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzz
+wy5E97BnRqqS5TvaHBkUODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/a
+EkP/TOYGJqibGapEPHayXOw=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIE2DCCBEGgAwIBAgIEN0rSQzANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC
+VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u
+ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc
+KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u
+ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05OTA1
+MjUxNjA5NDBaFw0xOTA1MjUxNjM5NDBaMIHDMQswCQYDVQQGEwJVUzEUMBIGA1UE
+ChMLRW50cnVzdC5uZXQxOzA5BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5j
+b3JwLiBieSByZWYuIChsaW1pdHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBF
+bnRydXN0Lm5ldCBMaW1pdGVkMTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUg
+U2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUA
+A4GLADCBhwKBgQDNKIM0VBuJ8w+vN5Ex/68xYMmo6LIQaO2f55M28Qpku0f1BBc/
+I0dNxScZgSYMVHINiC3ZH5oSn7yzcdOAGT9HZnuMNSjSuQrfJNqc1lB5gXpa0zf3
+wkrYKZImZNHkmGw6AIr1NJtl+O3jEP/9uElY3KDegjlrgbEWGWG5VLbmQwIBA6OC
+AdcwggHTMBEGCWCGSAGG+EIBAQQEAwIABzCCARkGA1UdHwSCARAwggEMMIHeoIHb
+oIHYpIHVMIHSMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxOzA5
+BgNVBAsTMnd3dy5lbnRydXN0Lm5ldC9DUFMgaW5jb3JwLiBieSByZWYuIChsaW1p
+dHMgbGlhYi4pMSUwIwYDVQQLExwoYykgMTk5OSBFbnRydXN0Lm5ldCBMaW1pdGVk
+MTowOAYDVQQDEzFFbnRydXN0Lm5ldCBTZWN1cmUgU2VydmVyIENlcnRpZmljYXRp
+b24gQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMCmgJ6AlhiNodHRwOi8vd3d3LmVu
+dHJ1c3QubmV0L0NSTC9uZXQxLmNybDArBgNVHRAEJDAigA8xOTk5MDUyNTE2MDk0
+MFqBDzIwMTkwNTI1MTYwOTQwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAU8Bdi
+E1U9s/8KAGv7UISX8+1i0BowHQYDVR0OBBYEFPAXYhNVPbP/CgBr+1CEl/PtYtAa
+MAwGA1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI
+hvcNAQEFBQADgYEAkNwwAvpkdMKnCqV8IY00F6j7Rw7/JXyNEwr75Ji174z4xRAN
+95K+8cPV1ZVqBLssziY2ZcgxxufuP+NXdYR6Ee9GTxj005i7qIcyunL2POI9n9cd
+2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIzCCAoygAwIBAgIENeHvHjANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEuMCwGA1UECxMlRXF1aWZheCBQcmVtaXVtIENl
+cnRpZmljYXRlIEF1dGhvcml0eTAeFw05ODA4MjQyMjU0MjNaFw0xODA4MjQyMjU0
+MjNaME8xCzAJBgNVBAYTAlVTMRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVF
+cXVpZmF4IFByZW1pdW0gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3
+DQEBAQUAA4GNADCBiQKBgQDOoQaOBswIC8GGqN4g1Q0O0Q3En+pq2bPCMkdAb4qI
+pAm9OCwd5svmpPM269rrvPxkswf2Lbyqzp8ZSGhK/PWiRX4JEPWPs0lcIwY56hOL
+uAvNkR12X9k3oUT7X5DyZ7PNGJlDH3YSawLylYM4Q8L2YjTKyXhdX9LYupr/vhBg
+WwIDAQABo4IBCjCCAQYwcQYDVR0fBGowaDBmoGSgYqRgMF4xCzAJBgNVBAYTAlVT
+MRAwDgYDVQQKEwdFcXVpZmF4MS4wLAYDVQQLEyVFcXVpZmF4IFByZW1pdW0gQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIw
+MTgwODI0MjI1NDIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUFe6yKFmrbuX4
+z4uB9CThrj91G5gwHQYDVR0OBBYEFBXusihZq27l+M+LgfQk4a4/dRuYMAwGA1Ud
+EwQFMAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEB
+BQUAA4GBAL0LnCepA9so3JipS9DRjqeoGlqR4Jzx9xh8LiKeNh/JqLXNRkpu+jUH
+G4YI65/iqPmdQS06rlxctl80BOv8KmCw+3TkhellOJbuFcfGd2MSvYpoH6tsfdrK
+XBPO6snrCVzFc+cSAdXZUwee4A+W8Iu0u0VIn4bFGVWgy5bFA/xI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2Vj
+dXJlIGVCdXNpbmVzcyBDQS0yMB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0
+NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkVxdWlmYXggU2VjdXJlMSYwJAYD
+VQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn2Z0G
+vxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/
+BPO3QSQ5BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0C
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJl
+IGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTkw
+NjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9euSBIplBq
+y/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAAyGgq3oThr1jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy
+0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1
+E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUmV+GRMOrN
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICWjCCAcMCAgGlMA0GCSqGSIb3DQEBBAUAMHUxCzAJBgNVBAYTAlVTMRgwFgYD
+VQQKEw9HVEUgQ29ycG9yYXRpb24xJzAlBgNVBAsTHkdURSBDeWJlclRydXN0IFNv
+bHV0aW9ucywgSW5jLjEjMCEGA1UEAxMaR1RFIEN5YmVyVHJ1c3QgR2xvYmFsIFJv
+b3QwHhcNOTgwODEzMDAyOTAwWhcNMTgwODEzMjM1OTAwWjB1MQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xIzAhBgNVBAMTGkdURSBDeWJlclRydXN0IEds
+b2JhbCBSb290MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCVD6C28FCc6HrH
+iM3dFw4usJTQGz0O9pTAipTHBsiQl8i4ZBp6fmw8U+E3KHNgf7KXUwefU/ltWJTS
+r41tiGeA5u2ylc9yMcqlHHK6XALnZELn+aks1joNrI1CqiQBOeacPwGFVw1Yh0X4
+04Wqk2kmhXBIgD8SFcd5tB8FLztimQIDAQABMA0GCSqGSIb3DQEBBAUAA4GBAG3r
+GwnpXtlR22ciYaQqPEh346B8pt5zohQDhT37qw4wxYMWM4ETCJ57NE7fQMh017l9
+3PR2VX2bY1QY6fDq81yx2YtCHrnAlU66+tXifPVoYb+O7AWXX1uw16OFNMQkpw0P
+lZPvy5TYnh+dXIVtx6quTx8itc2VrbqnzPmrC3p/
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDtjCCAp6gAwIBAgICAbYwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVVMx
+GDAWBgNVBAoTD0dURSBDb3Jwb3JhdGlvbjEnMCUGA1UECxMeR1RFIEN5YmVyVHJ1
+c3QgU29sdXRpb25zLCBJbmMuMR4wHAYDVQQDExVHVEUgQ3liZXJUcnVzdCBSb290
+IDUwHhcNOTgwODE0MTQ1MDAwWhcNMTMwODE0MjM1OTAwWjBwMQswCQYDVQQGEwJV
+UzEYMBYGA1UEChMPR1RFIENvcnBvcmF0aW9uMScwJQYDVQQLEx5HVEUgQ3liZXJU
+cnVzdCBTb2x1dGlvbnMsIEluYy4xHjAcBgNVBAMTFUdURSBDeWJlclRydXN0IFJv
+b3QgNTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALwSbj+KfHqXAewe
+uzlaAvR4RKJIG457SVJ6uHtHs6+Um2+7lvoramVcuByUc76/iQoigO5X/IwFu3Cf
+lzkE2qOHXKjlyq/AM5rVN1xLrOSA0KYjYPv9ci6UncfOwgQy73hgXe2thw9FZR48
+mgqavl0dmezn8tHGehfZrZtUln/EfGC/haoVNR1A2hG87FQhKC0joajwzy3N3fx+
+D17hZQdWywe00lboXjHMGGPEhtIthc+Tkqtt/mg5+95zvYb45EZ66p8My/QZ/mO8
+0Sx7iDM29uThnAxTgWAc2i6rlqkWiBNQmbK9Vd8VMH7o5Zj7cH5stQf8/Ea30O03
+ln4y/iECAwEAAaNaMFgwEgYDVR0TAQH/BAgwBgEB/wIBBTAOBgNVHQ8BAf8EBAMC
+AQYwFwYDVR0gBBAwDjAMBgoqhkiG+GMBAgEDMBkGA1UdDgQSBBB2CkkhOEyf3vjE
+ScdxcZGdMA0GCSqGSIb3DQEBBQUAA4IBAQBBOtQYW9q43iEc4Y4J5fFoNP/elvQH
+9ac886xKsZv6kvqb7eYyIapKdsXcTzjl39WG5NXIdn2Y17HNj021kSNsi4rr6nzv
+FJTExvAfSi0ycWMrY5EmAgm2gB3t4sy4f9uHY8jh0GwmsTUdQGYQG82VVBgzYewT
+T9oT95mvPtDPjqZyorPDBZrJJ32SzH5SjbOrcG2eiZ9N6xp1wpiq1QIW1wyKvyXk
+6y28mOlYOBl8uTf+2+KZCHMGx5eDan0QAS8yuRcFSmXmL86+XlOmgumaUwqEdC2D
+ysiUFnZflGEo8IWnObvXi9moshMdVAk0JH0ggX1mfqKQdFwQxr3sqxvC
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDnjCCAoagAwIBAgILAgAAAAAA1ni50a8wDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw
+MDBaFw0wOTAxMjgxMjAwMDBaMF8xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRQwEgYDVQQLEwtQYXJ0bmVycyBDQTEfMB0GA1UEAxMWR2xv
+YmFsU2lnbiBQYXJ0bmVycyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBANIs+DKsShJ6N8gpkaWujG4eDsA0M4jlM3EWHHiEaMMYNFAuFj6xlIJPsZqf
+APjGETXGaXuYAq0ABohs50wzKACIJ0Yfh7NxdWO8MruI3mYYDlAGk7T2vBQ3MD0i
+3z3/dX7ZChrFn7P80KyzCHqJ0wHoAFznSgs9TXsmordiBovaRt2TFz8/WwJLC7aI
+IBGSAK27xy7U40Wu9YlafI2krYVkMsAnjMbyioCShiRWWY10aKKDQrOePVBBhm8g
+bvb9ztMZ4zLMj+2aXm0fKPVSrG4YXvg90ZLlumwBiEsK8i3eZTMFQqBMqjF2vv2/
+gXj5cRxGXi0VlS0wWY5MQdFiqz0CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgAGMB0G
+A1UdDgQWBBRDJI1wFQhiVZxPDEAXXYZeD6JM+zAfBgNVHSMEGDAWgBRge2YaRQ2X
+yolQL30EzTSo//z9SzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBAUAA4IB
+AQBm7bSIaRGZgiGDrKFti5uErQ8tyB6Mynt+rarUjt4H1p5Fx6W4nAc5YCVVGsBP
+GeXPFylJiRg1ZuXrKEBOV8mvs+S4IAWjO5VQkUmUKX0s5YhBpUWIXp2CJ/fS71u1
+T5++/jVlLFVkn+FR2iJhd7pYTo/GeVlZbjCAok+QbiELrdBoOZAQm+0iZW8eETjm
+f4zS8zltR9Uh6Op1OkHRrfYWnV0LIb3zH2MGJR3BHzVxLOsgGdXBsOw95W/tAgc/
+E3tmktZEwZj3X1CLelvCb22w0fjldKBAN6MlD+Q9ymQxk5BcMHu5OTGaXkzNuUFP
+UOQ9OK7IZtnHO11RR6ybq/Kt
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4N88wDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MTUxMjAw
+MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDEgQ0ExJjAkBgNV
+BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAxIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAvSA1R9Eo1gijEjkjRw29cCFSDlcxlaY0V2vsfkN5
+wwZSSM28taGZvdgfMrzP125ybS53IpCCTkuPmgwBQprZcFm2nR/mY9EMrR1O+IWB
++a7vn6ZSYUR5GnVF4GFWRW1CjD1yy6akErea9dZg0GBQs46mpuy09BLNf6jO77Ph
+hTD+csTm53eznlhB1lGDiAfGtmlPNt7RC0g/vdafIXRkbycGPkv9Dqabv6RIV4yQ
+7okYCwKBGL5n/lNgiCe6o3M0S1pWtN5zBe2Yll3sSudA/EsJYuvQ4zFPhdF6q1ln
+K/uID+uqg701/WEn7GYOQlf3acIM7/xqwm5J2o9BOK5IqQIDAQABo2MwYTAOBgNV
+HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFPzgZvZaNZnrQB7SuB5DvJiOH4rDMB8GA1Ud
+IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEEBQADggEBAJujCETO8pCdcfMyswVqterPKZjeVT6gFn0GekTWr9L6
+E1iM+BzHqx20G+9paJhcCDmP4Pf7SMwh57gz2wWqNCRsSuXpe2Deg7MfCr5BdfzM
+MEi3wSYdBDOqtnjtKsu6VpcybvcxlS5G8hTuJ8f3Yom5XFrTOIpk9Te08bM0ctXV
+IT1L13iT1zFmNR6j2EdJbxyt4YB/+JgkbHOsDsIadwKjJge3x2tdvILVKkgdY89Q
+Mqb7HBhHFQpbDFw4JJoEmKgISF98NIdjqy2NTAB3lBt2uvUWGKMVry+U9ikAdsEV
+F9PpN0121MtLKVkkrNpKoOpj3l9Usfrz0UXLxWS0cyE=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDrDCCApSgAwIBAgILAgAAAAAA1ni4jY0wDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw
+MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDIgQ0ExJjAkBgNV
+BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAyIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAkoz+7/RFjhdBbvzYvyFvqwadUsEsAJ0/joW4f0qP
+vaBjKspJJ65agvR04lWS/8LRqnmitvrVnYIET8ayxl5jpzq62O7rim+ftrsoQcAi
++05IGgaS17/Xz7nZvThPOw1EblVB/vwJ29i/844h8egStfYTpdPGTJMisAL/7h0M
+xKhrT3VoVujcKBJQ96gknS4kOfsJBd7lo2RJIdBofnEwkbFg4Dn0UPh6TZgAa3x5
+uk7OSuK6Nh23xTYVlZxkQupfxLr1QAW+4TpZvYSnGbjeTVNQzgfR0lHT7w2BbObn
+bctdfD98zOxPgycl/3BQ9oNZdYQGZlgs3omNAKZJ+aVDdwIDAQABo2MwYTAOBgNV
+HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFHznsrEs3rGna+l2DOGj/U5sx7n2MB8GA1Ud
+IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEEBQADggEBAGPdWc6KeaqYnU7FiWQ3foqTZy8Q6m8nw413bfJcVpQZ
+GmlgMEZdj/JtRTyONZd8L7hR4uiJvYjPJxwINFyIwWgk25GF5M/7+0ON6CUBG8QO
+9wBCSIYfJAhYWoyN8mtHLGiRsWlC/Q2NySbmkoamZG6Sxc4+PH1x4yOkq8fVqKnf
+gqc76IbVw08Y40TQ4NzzxWgu/qUvBYTIfkdCU2uHSv4y/14+cIy3qBXMF8L/RuzQ
+7C20bhIoqflA6evUZpdTqWlVwKmqsi7N0Wn0vvi7fGnuVKbbnvtapj7+mu+UUUt1
+7tjU4ZrxAlYTiQ6nQouWi4UMG4W+Jq6rppm8IvFz30I=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDrDCCApSgAwIBAgILAgAAAAAA1ni41sMwDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05OTAxMjgxMjAw
+MDBaFw0wOTAxMjgxMjAwMDBaMG0xCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRswGQYDVQQLExJQcmltYXJ5IENsYXNzIDMgQ0ExJjAkBgNV
+BAMTHUdsb2JhbFNpZ24gUHJpbWFyeSBDbGFzcyAzIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAkV5WZdbAwAScv0fEXHt6MQH5WJaZ4xyEL9xWj631
+WYHVQ2ZdWpOMdcqp5xHBURAUYMks1HuvxneGq3onrm+VuQvKtkb7fhr0DRRt0slO
+sq7wVPZcQEw2SHToVIxlZhCnvSu3II0FSa14fdIkI1Dj8LR5mwE5/6870y3u4UmN
+jS88akFFL5vjPeES5JF1ns+gPjySgW+KLhjc4PKMjP2H2Qf0QJTJTk9D32dWb70D
+UHyZZ6S5PJFsAm6E1vxG98xvGD4X8O8LZBZX5qyG8UiqQ8HJJ3hzREXihX26/7Ph
++xsFpEs7mRIlAVAUaq9d6sgM7uTa7EuLXGgTldzDtTA61wIDAQABo2MwYTAOBgNV
+HQ8BAf8EBAMCAAYwHQYDVR0OBBYEFMw2zBe0RZEv7c87MEh3+7UUmb7jMB8GA1Ud
+IwQYMBaAFGB7ZhpFDZfKiVAvfQTNNKj//P1LMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEEBQADggEBAFeyVMy9lRdkYIm2U5EMRZLDPahsw8yyGPV4QXTYfaMn
+r3cNWT6UHWn6idMMvRoB9D/o4Hcagiha5mLXt+M2yQ6feuPC08xZiQzvFovwNnci
+yqS2t8FCZwFAY8znOGSHWxSWZnstFO69SW3/d9DiTlvTgMJND8q4nYGXpzRux+Oc
+SOW0qkX19mVMSPISwtKTjMIVJPMrUv/jCK64btYsEs85yxIq56l7X5g9o+HMpmOJ
+XH0xdfnV1l3y0NQ9355xqA7c5CCXeOZ/U6QNUU+OOwOuow1aTcN55zVYcELJXqFe
+tNkio0RTNaTQz3OAxc+fVph2+RRMd4eCydx+XTTVNnU=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU
+YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
+AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7
+5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
+gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR
+rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7
+ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o
+Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDITCCAoqgAwIBAgIBADANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFBlcnNvbmFsIEJhc2lj
+IENBMSgwJgYJKoZIhvcNAQkBFhlwZXJzb25hbC1iYXNpY0B0aGF3dGUuY29tMB4X
+DTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgcsxCzAJBgNVBAYTAlpBMRUw
+EwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEaMBgGA1UE
+ChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRpb24gU2Vy
+dmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQZXJzb25hbCBCYXNpYyBD
+QTEoMCYGCSqGSIb3DQEJARYZcGVyc29uYWwtYmFzaWNAdGhhd3RlLmNvbTCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvLyTU23AUE+CFeZIlDWmWr5vQvoPR+53
+dXLdjUmbllegeNTKP1GzaQuRdhciB5dqxFGTS+CN7zeVoQxN2jSQHReJl+A1OFdK
+wPQIcOk8RHtQfmGakOMj04gRRif1CwcOu93RfyAKiLlWCy4cgNrx454p7xS9CkT7
+G1sY0b8jkyECAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQQF
+AAOBgQAt4plrsD16iddZopQBHyvdEktTwq1/qqcAXJFAVyVKOKqEcLnZgA+le1z7
+c8a914phXAPjLSeoF+CEhULcXpvGt7Jtu3Sv5D/Lp7ew4F2+eIMllNLbgQ95B21P
+9DkVWlIBe94y1k049hJcBlDfBVu9FEuh3ym6O0GN92NWod8isQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDLTCCApagAwIBAgIBADANBgkqhkiG9w0BAQQFADCB0TELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEkMCIGA1UEAxMbVGhhd3RlIFBlcnNvbmFsIEZyZWVt
+YWlsIENBMSswKQYJKoZIhvcNAQkBFhxwZXJzb25hbC1mcmVlbWFpbEB0aGF3dGUu
+Y29tMB4XDTk2MDEwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgdExCzAJBgNVBAYT
+AlpBMRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEa
+MBgGA1UEChMRVGhhd3RlIENvbnN1bHRpbmcxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xJDAiBgNVBAMTG1RoYXd0ZSBQZXJzb25hbCBG
+cmVlbWFpbCBDQTErMCkGCSqGSIb3DQEJARYccGVyc29uYWwtZnJlZW1haWxAdGhh
+d3RlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1GnX1LCUZFtx6UfY
+DFG26nKRsIRefS0Nj3sS34UldSh0OkIsYyeflXtL734Zhx2G6qPduc6WZBrCFG5E
+rHzmj+hND3EfQDimAKOHePb5lIZererAXnbr2RSjXW56fAylS1V/Bhkpf56aJtVq
+uzgkCGqYx7Hao5iR/Xnb5VrEHLkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQQFAAOBgQDH7JJ+Tvj1lqVnYiqk8E0RYNBvjWBYYawmu1I1XAjP
+MPuoSpaKH2JCI4wXD/S6ZJwXrEcp352YXtJsYHFcoqzceePnbgBHH7UNKOgCneSa
+/RP0ptl8sfjcXyMmCZGAc9AUG95DqYMl8uacLxXK/qarigd1iwzdUYRr5PjRznei
+gQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDKTCCApKgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBzzELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMRowGAYD
+VQQKExFUaGF3dGUgQ29uc3VsdGluZzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBT
+ZXJ2aWNlcyBEaXZpc2lvbjEjMCEGA1UEAxMaVGhhd3RlIFBlcnNvbmFsIFByZW1p
+dW0gQ0ExKjAoBgkqhkiG9w0BCQEWG3BlcnNvbmFsLXByZW1pdW1AdGhhd3RlLmNv
+bTAeFw05NjAxMDEwMDAwMDBaFw0yMDEyMzEyMzU5NTlaMIHPMQswCQYDVQQGEwJa
+QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xGjAY
+BgNVBAoTEVRoYXd0ZSBDb25zdWx0aW5nMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9u
+IFNlcnZpY2VzIERpdmlzaW9uMSMwIQYDVQQDExpUaGF3dGUgUGVyc29uYWwgUHJl
+bWl1bSBDQTEqMCgGCSqGSIb3DQEJARYbcGVyc29uYWwtcHJlbWl1bUB0aGF3dGUu
+Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJZtn4B0TPuYwu8KHvE0Vs
+Bd/eJxZRNkERbGw77f4QfRKe5ZtCmv5gMcNmt3M6SK5O0DI3lIi1DbbZ8/JE2dWI
+Et12TfIa/G8jHnrx2JhFTgcQ7xZC0EN1bUre4qrJMf8fAHB8Zs8QJQi6+u4A6UYD
+ZicRFTuqW/KY3TZCstqIdQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
+SIb3DQEBBAUAA4GBAGk2ifc0KjNyL2071CKyuG+axTZmDhs8obF1Wub9NdP4qPIH
+b4Vnjt4rueIXsDqg8A6iAJrf8xQVbrvIhVqYgPn/vnQdPfP+MCXRNzRn+qVxeTBh
+KXLA4CxM+1bkOqhv5TJZUtt1KFBZDPgLGeSs2a+WjS9Q2wfD6h+rM+D1KzGJ
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDJzCCApCgAwIBAgIBATANBgkqhkiG9w0BAQQFADCBzjELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhhd3RlIFByZW1pdW0gU2Vy
+dmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNlcnZlckB0aGF3dGUuY29t
+MB4XDTk2MDgwMTAwMDAwMFoXDTIwMTIzMTIzNTk1OVowgc4xCzAJBgNVBAYTAlpB
+MRUwEwYDVQQIEwxXZXN0ZXJuIENhcGUxEjAQBgNVBAcTCUNhcGUgVG93bjEdMBsG
+A1UEChMUVGhhd3RlIENvbnN1bHRpbmcgY2MxKDAmBgNVBAsTH0NlcnRpZmljYXRp
+b24gU2VydmljZXMgRGl2aXNpb24xITAfBgNVBAMTGFRoYXd0ZSBQcmVtaXVtIFNl
+cnZlciBDQTEoMCYGCSqGSIb3DQEJARYZcHJlbWl1bS1zZXJ2ZXJAdGhhd3RlLmNv
+bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0jY2aovXwlue2oFBYo847kkE
+VdbQ7xwblRZH7xhINTpS9CtqBo87L+pW46+GjZ4X9560ZXUCTe/LCaIhUdib0GfQ
+ug2SBhRz1JPLlyoAnFxODLz6FVL88kRu2hFKbgifLy3j+ao6hnO2RlNYyIkFvYMR
+uHM/qgeN9EJN50CdHDcCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQQFAAOBgQAmSCwWwlj66BZ0DKqqX1Q/8tfJeGBeXm43YyJ3Nn6yF8Q0ufUI
+hfzJATj/Tb7yFkJD57taRvvBxhEf8UqwKEbJw8RCfbz6q1lu1bdRiBHjpIUZa4JM
+pAwSremkrj/xw0llmozFyD4lt5SZu5IycQfwhl7tUCemDaYj+bvLpgcUQg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDEzCCAnygAwIBAgIBATANBgkqhkiG9w0BAQQFADCBxDELMAkGA1UEBhMCWkEx
+FTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYD
+VQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlv
+biBTZXJ2aWNlcyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEm
+MCQGCSqGSIb3DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wHhcNOTYwODAx
+MDAwMDAwWhcNMjAxMjMxMjM1OTU5WjCBxDELMAkGA1UEBhMCWkExFTATBgNVBAgT
+DFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJQ2FwZSBUb3duMR0wGwYDVQQKExRUaGF3
+dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNl
+cyBEaXZpc2lvbjEZMBcGA1UEAxMQVGhhd3RlIFNlcnZlciBDQTEmMCQGCSqGSIb3
+DQEJARYXc2VydmVyLWNlcnRzQHRoYXd0ZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBANOkUG7I/1Zr5s9dtuoMaHVHoqrC2oQl/Kj0R1HahbUgdJSGHg91
+yekIYfUGbTBuFRkC6VLAYttNmZ7iagxEOM3+vuNkCXDF/rFrKbYvScg71CcEJRCX
+L+eQbcAoQpnXTEPew/UhbVSfXcNY4cDk2VuwuNy0e982OsK1ZiIS1ocNAgMBAAGj
+EzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEAB/pMaVz7lcxG
+7oWDTSEwjsrZqG9JGubaUeNgcGyEYRGhGshIPllDfU+VPaGLtwtimHp1it2ITk6e
+QNuozDJ0uW8NxuOzRAvZim+aKZuZGCg70eNAKJpaPNW15yAbi8qkq43pUdniTCxZ
+qdq5snUb9kLy78fyGPmJvKP/iiMucEc=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIRIjCCCQoCAQAwDQYJKoZIhvcNAQEFBQAwVzEPMA0GA1UEChMGVGhhd3RlMSEw
+HwYDVQQLExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3QxITAfBgNVBAMTGFRoYXd0
+ZSBVbml2ZXJzYWwgQ0EgUm9vdDAeFw05OTEyMDUxMzU2MDVaFw0zNzA0MDMxMzU2
+MDVaMFcxDzANBgNVBAoTBlRoYXd0ZTEhMB8GA1UECxMYVGhhd3RlIFVuaXZlcnNh
+bCBDQSBSb290MSEwHwYDVQQDExhUaGF3dGUgVW5pdmVyc2FsIENBIFJvb3Qwgggi
+MA0GCSqGSIb3DQEBAQUAA4IIDwAwgggKAoIIAQDiiQVtw3+tpok6/7vHzZ03seHS
+IR6bYSoV53tXT1U80Lv52T0+przstK1TmhYC6wty/Yryj0QFxevT5b22RDnm+0e/
+ap4KlRjiaOLWltYhrYj99Rf109pCpZDtKZWWdTrah6HU9dOH3gVipuNmdJLPpby7
+32j/cXVWQVk16zNaZlHy0qMKwYzOc1wRby2MlYyRsf3P5a1WlcyFkoOQVUHJwnft
++aN0QgpoCPPQ0WX9Zyw0/yR/53nIBzslV92kDJg9vuDMGWXb8lSir0LUneKuhCMl
+CTMStWoedsSL2UkAbF66H/Ib2mfKJ6qjRCMbg4LO8qsz7VSk3MmrWWXROA7BPhtn
+j9Z1AeBVIt12d+yO3fTPeSJtuVcD9ZkIpzw+NPvEF64jWM0k8yPKagIolAGBNLRs
+a66LGsOj0gk8FlT1Nl8k459KoeJkxhbDpoF6JDZHjsFeDvv5FXgE1g5Z2Z1YZmLS
+lCkyMsh4uWb2tVbhbMYUS5ZSWZECJGpVR9c/tiMaYHeXLuJAr54EV56tEcXJQ3Dv
+SLRerBxpLi6C1VuLvoK+GRRe5w0ix1Eb/x6b8TCPcTEGszQnj196ZoJPii0Tq0LP
+IVael45mNg+Wm+Ur9AKpKmqMLMTDuHAsLSkeP1B3Hm0qVORVCpE4ocW1ZqJ2Wu4P
+v7Rn4ShuD+E2oYLRv9R34cRnMpN4yOdUU/4jeeZozCaQ9hBjXSpvkS2kczJRIfK7
+Fd+qJAhIBt6hnia/uoO/fKTIoIy90v+8hGknEyQYxEUYIyZeGBTKLoiHYqNT5iG3
+uIV7moW7FSZy+Ln3anQPST+SvqkFt5knv78JF0uZTK0REHzfdDH2jyZfqoiuOFfI
+VS3T+9gbUZm+JRs6usB9G+3O0km5z/PFfYmQgdhpSCAQo/jvklEYMosRGMA/G4VW
+zlfJ8oJkxt8CCS5KES+xJ203UvDwFmHxZ43fh3Kvh9rP+1CUbtSUheuKLOoh9ZZK
+RNXgzmp0RE3QBdOHFe020KSLZlVwk+5HBsF+LqUYeWfzKIXxcPcOg6R+VJ5adjLL
+ZRu4zfvIKAPSVJHRp8WFQwgXdqXmL2cI2KGigi0M+MGvY9RQd21rRkpBhdWQX3kt
+xOzXEYdAiuFo4mT4VTL7b5Ms2nfZIcEX5TYsTn6Qf6yUKzJnvjhQdriuQbnXIcUJ
+TGDIo1HENJtXN9/LyTNXi+v7dp8ZTcVqHypFrivtL42npQDLBPolYi50SBvKKoy6
+27Z+9rsCfKnD21h4ob/w/hoQVRHO6GlOlmXGFwPWB2iMVIKuHCJVP/H0CZcowEb3
+TgslHfcH1wkdOhhXODvoMwbnj3hGHlv1BrbsuKYN8boTS9YYIN1pM0ozFa64yJiK
+JyyTvC377jO/ZuZNurabBlVgl0u8RM1+9KHYqi/AAighFmJ42whU8vz0NOPGjxxD
+V86QGkvcLjsokYk/eto1HY4s7kns9DOtyVOojJ8EUz4kHFLJEvliV6O87izrQHwg
+I3ArlflzF4rRwRxpprc4mmf3cB16WgxAz2IPhTzCAk5+tfbFKimEsx83KuGqckLE
+7Wsaj5IcXb7R8lvyq6qp0vW4pEErK5FuEkjKmNg3jcjtADC1tgROfpzahOzA+nvl
+HYikU0awlORcG6ElLA9IUneXCWzsWxgzgwLlgn7NhSEwEf0nT8/kHuw/pVds6Sow
+GSqI5cNpOKtvOXF/hOFBw+HMKokgUi6DD2w5P0stFqwt8CSsAHP0m7MGPwW4FIUf
+q55cPJ5inQ5tO4AJ/ALqopd0ysf541bhw8qlpprAkOAkElPSwovavu0CQ15n4YmY
+ee7LqsrDG9znpUalfGsWh7ZaKNfbJzxepb22Ud0fQ887Jsg6jSVhwUn0PBvJROqv
+HMIrlAEqDjDRW4srR+XD0QQDmw45LNYn1OZwWtl1zyrYyQAF5BOI7MM5+4dhMDZD
+A8ienKIGwi/F/PCAY7FUBKBMqS7G9XZ62NDk1JQR5RW1eAbcuICPmakgMz0QhUxl
+Cco+WF5gk5qqYl3AUQYcXWCgDZxLQ/anFiGkh6rywS7ukjC4nt/fEAGLhglw2Gyo
+t1AeFpa092f9NTohkCoyxwB7TQcQCbkvc9gYfmeZBE8G/FDHhZudQJ2zljf6pdyy
+ck7vTgks/ZH9Tfe7pqE+q3uiA0CmqVUn4vr5Gc6HdarxdTbz87iR+JHDi3UTjkxl
+mhY5auU06HqWWX81sAD9W2n8Qyb69Shu/ofZfiT7tKCCblSi/66/YrT0cgHCy5hH
+mOFMtReAgM6PpijuHkVq+9/xHfxaO9bq9GwdYklXO4qPhurwUwTOnBZo/7q5/IgP
+R/cCRHJAuMo7LVOd3DxWjFl7aBosjXG7bADHGs5vQJKxoy8P2UTyo3Aunu4OrjLQ
+Oz6LB+rmebNcKeJ9a6he+Vox6AiWoowDmEbxuH2QVCbtdmL+numabl7JScdcNFMp
+VNns5EbhgDt12d/7edWH8bqe6xnOTFJz5luHriVPOXnMxrj5EHvs8JtxpAWg0ynT
+Tn8f9C0oeMxVlXsekS/MVhhzi7LbvGkH5tDYT+2i/1iFo23gSlO3Z32NDFxbe3co
+AjVEegTTKEPIazAXXTK4KTW6dto7FEp2GFik+JI8nk0zb0ZrCNkxSGjd9PskVjSy
+z2lmvkjSimYizfJpzcJTE0UpQSLWXZgftqSyo8LuAi9RG9yDpOxwJajUCGEyb+Sh
+gS58Y3L6KWW8cETPXQIDAQABMA0GCSqGSIb3DQEBBQUAA4IIAQBVmjRqIgZpCUUz
+x66pXMcJTpuGvEGQ1JRS9s0jKZRLIs3ovf6dzVLyve2rh8mrq0YEtL2iPyIwR1DA
+S4x2DwP1ktKxLcR6NZzJc4frpp/eD3ON03+Z2LqPb8Tzvhqui6KUNpDi5euNBfT8
+Zd+V8cSUTRdW1588j1A853e/lYYmZPtq/8ba6YyuQrtp5TPG2OkNxlUhScEMtKP5
+m0tc3oNPQQPOKnloOH3wVEkg9bYQ/wjcM2aWm/8G3gCe185WQ5pR/HDN9vBRo7fN
+tFyFYs1xt8YrIyvdw25AQvo3/zcc9npXlIeFI9fUycdfwU0vyQ3XXOycJe6eMIKR
+lnK4dR34CWhXl7ItS+4l7HokKe5y1JwT26vcAwrYShTJCFdEXaG1U4A08hSXz1Le
+og6KEOkU79BgvmGh8SVd1RhzP5MQypbus0DS26NVz1dapQ5PdUff6veQmm31cC4d
+FBw3ZARZULDccoZvnDc9XSivc1Xv0u4kdHQT79zbMUn7P2P10wg+M6XnnQreUyxR
+jmfbm0FlQVC91KSWbIe8EuCUx9PA5MtzWACD4awnhdadU51cvQo+A0OcDJH1bXv4
+QHJ1qxF2kSvhxqofcGl2cBUJ/pPQ1i23FWqbZ1y0aZ8lpn2K+30iqXHyzk6MuCEt
+3v5BcQ3/nexzprsHT4gOWEcufqnCx3jdunqeTuAwTmNvhdQgQen6/kNF5/uverLO
+pAUdIppYht/kzkyp/tgWpW/72M5We/XWIO/kR81jJP+5vvFIo8EBcua9wK3tJg3K
+NJ/8Ai0gTwUgriE9DMIgPD/wBITcz4n9uSWRjtBD5rMgq1wt1UCeoEvY9LLMffFY
+Co6H7YisNpbkVqARivKa0LNXozS7Gas44XRrIsQxzgHVGzbjHjhMM5PfQONZV06s
+bnseWj3FHVusyBCCNQIisvx16BCRjcR9eJNHnhydrGtiAliM1hwj1q94woCcpKok
+VBS1FJjG+CsaJMtxMgrimw5pa91+jGTRLmPvDn+xPohMnVXlyW4XBLdB/72KQcsl
+MW9Edz9HsfyBiAeOBUkgtxHZaQMqA525M4Sa399640Zzo9iijFMZiFVMdLj2RIQr
+0RQtTjkukmj/afyFYhvrVU/vJYRiRZnW2E5vP1MIfR0GlYGAf09OdDaYteKHcJjc
+1/XcUhXmxtZ5ljl/j5XPq4BTrRsLRUAO1Bi9LN6Kd3b98kRHxiHQ5HTw2BgFyHww
+csff8bv8AjCp9EImWQ2TBYKhc+005ThdzVCQ/pT8E7y9/KiiiKdzxLKo0V2IxAKi
+evEEyf6MdMnvHWRBn6welmdkrKsoQced98CYG24HwmR9WoNmVig2nOf7HHcOKKDE
+92t5OQQghMdXk7wboOq860LlqBH+/KxlzP34KIj0pZrlc1HgqJsNA3dO5eCYs4ja
+febGnnwUZsEuU0qSBzegfuk9CeQVfM/9uEGl755mncReBx2H+EGt6ucv0kFjGDf5
+FONN0OX3Q/0V4/k2cwYm3wFPqcNO3iBGd5i0eiQrO3UrTliNm12kxxagvDKIP6GD
+8wDI+NhY6WNdTCu18HJB2Kt3N9ZydK62NpzIpoNJS+DJVgspvgAwy93WyEKKANns
+FdE0cfJbZIf2J9K364awkL8p2yGeNozjIC+VI1FsG8Kk1ebYAkNnoP6bUANEf7vk
+ctXR5NqPkhRk+10UEBJKlQbJZQgpyiGjJjgRySffcGcE/cpIMn9jskV0MVBPh9kg
+cNIhcLHWEJ0zXXiDkW1Vguza5GJjx4FG1xllcipDGZC41yNNTBzgRKlmZ6zucXkn
+Jnhtcg71XUsjtXx8ZekXxjoLDd1eHlHDhrjsf8cnSqVG6GotGcGHo8uZk4dkolUU
+TLdDpZPX59JOeUDKZZlGPT96gHqIaswe5WszRvRQwNUfCbjNii6hJ+tdc6foawrl
+V4IqsPziVFJW8KupEsYjlgcknOC8RqW0IATaCZNj5dQuwn7FMe21FXSGF7mz8yaK
+HQJq2ho/6LrxBG2UUVTiWrRZgx1g0C1zzAe1Joz518aIke+Az10PoWDLRdRCItGx
+cB390LcwkDrGSG1n5TLaj9vjqOMdICWiHOFMuaT2xj9cWA27xrJ3ARaRnxcGDbdA
+PsyPjpxL4J1+mx4Fq4gi+tMoG1cUZEo+JCw4TSFpAHMu0FUtdPIV6JRDPkAqxsa5
+alveoswYUFRdTiqFbPaSiykZfufqSuAiKyW892bPd5pBdPI8FA10afVQg83NLyHb
+IkaK0PdRGpVX8gWLGhntO0XoNsJufvtXIgAfBlOprpPGj3EqMUWS545t5pkiwIP8
+79xXZndPojYx+6ETjeXKo5V9AQxkcDtTQmiAx7udqAA1aZgMqGfYQ+Wqz5XgUZWk
+Fz9CnbgEztN5ecjTihYykuDXou7XN0wvrLh7vkX28RgznHs3piTZvECrAOnDN4ur
+2LbzXoFOsBRrBz4f7ML2RCKVu7Pmb9b5cGW6CoNlqg4TL4MTI1OLQBb6zi/8TQT4
+69isxTbCFVdIOOxVs7Qeuq3SQgYXDXPIV6a+lk2p8sD7eiEc9clwqYKQtfEM1HkQ
+voGm6VxhnHd5mqTDNyZXN8lSLPoI/9BfxmHA9Ha+/N5Oz6tRmXHH33701s8GVhkT
+UwttdFlIGZtTBS2dMlTT5SxTi2Q+1GR744AJFMz+FkZja3Fp+PnLJ/aIVLxFs84C
+yJTuQFv5QgLC/7DYLOsof17JJgGZpw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNTIyMjM0OFoXDTE5MDYy
+NTIyMjM0OFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDEgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYWYJ6ibiWuqYvaG9Y
+LqdUHAZu9OqNSLwxlBfw8068srg1knaw0KWlAdcAAxIiGQj4/xEjm84H9b9pGib+
+TunRf50sQB1ZaG6m+FiwnRqP0z/x3BkGgagO4DrdyFNFCQbmD3DD+kCmDuJWBQ8Y
+TfwggtFzVXSNdnKgHZ0dwN0/cQIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFBoPUn0
+LBwGlN+VYH+Wexf+T3GtZMjdd9LvWVXoP+iOBSoh8gfStadS/pyxtuJbdxdA6nLW
+I8sogTLDAHkY7FkXicnGah5xyf23dKUlRWnFSKsZ4UWKJWsZ7uW7EvV/96aNUcPw
+nXS3qT6gpf+2SQMT2iLM7XGCK5nPOrf1LXLI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMTk1NFoXDTE5MDYy
+NjAwMTk1NFowgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDIgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOOnHK5avIWZJV16vY
+dA757tn2VUdZZUcOBVXc65g2PFxTXdMwzzjsvUGJ7SVCCSRrCl6zfN1SLUzm1NZ9
+WlmpZdRJEy0kTRxQb7XBhVQ7/nHk01xC+YDgkRoKWzk2Z/M/VXwbP7RfZHM047QS
+v4dk+NoS/zcnwbNDu+97bi5p9wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBADt/UG9v
+UJSZSWI4OB9L+KXIPqeCgfYrx+jFzug6EILLGACOTb2oWH+heQC1u+mNr0HZDzTu
+IYEZoDJJKPTEjlbVUjP9UNV+mWwD5MlM/Mtsq2azSiGM5bUMMj4QssxsodyamEwC
+W/POuZ6lcg5Ktz885hZo+L7tdEy8W9ViH0Pd
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIC5zCCAlACAQEwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0
+IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAz
+BgNVBAsTLFZhbGlDZXJ0IENsYXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9y
+aXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG
+9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTk5MDYyNjAwMjIzM1oXDTE5MDYy
+NjAwMjIzM1owgbsxJDAiBgNVBAcTG1ZhbGlDZXJ0IFZhbGlkYXRpb24gTmV0d29y
+azEXMBUGA1UEChMOVmFsaUNlcnQsIEluYy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENs
+YXNzIDMgUG9saWN5IFZhbGlkYXRpb24gQXV0aG9yaXR5MSEwHwYDVQQDExhodHRw
+Oi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAeBgkqhkiG9w0BCQEWEWluZm9AdmFsaWNl
+cnQuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDjmFGWHOjVsQaBalfD
+cnWTq8+epvzzFlLWLU2fNUSoLgRNB0mKOCn1dzfnt6td3zZxFJmP3MKS8edgkpfs
+2Ejcv8ECIMYkpChMMFp2bbFc893enhBxoYjHW5tBbcqwuI4V7q0zK89HBFx1cQqY
+JJgpp0lZpd34t0NiYfPT4tBVPwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFa7AliE
+Zwgs3x/be0kz9dNnnfS0ChCzycUs4pJqcXgn8nCDQtM+z6lU9PHYkhaM0QTLS6vJ
+n0WuPIqpsHEzXcjFV9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/A
+PhmcGcwTTYJBtYze4D1gCCAPRX5ron+jjBXu
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPTCCAaYCEQDNun9W8N/kvFT+IqyzcqpVMA0GCSqGSIb3DQEBAgUAMF8xCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw05
+NjAxMjkwMDAwMDBaFw0yODA4MDEyMzU5NTlaMF8xCzAJBgNVBAYTAlVTMRcwFQYD
+VQQKEw5WZXJpU2lnbiwgSW5jLjE3MDUGA1UECxMuQ2xhc3MgMSBQdWJsaWMgUHJp
+bWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOB
+jQAwgYkCgYEA5Rm/baNWYS2ZSHH2Z965jeu3noaACpEO+jglr0aIguVzqKCbJF0N
+H8xlbgyw0FaEGIeaBpsQoXPftFg5a27B9hXVqKg/qhIGjTGsf7A01480Z4gJzRQR
+4k5FVmkfeAKA2txHkSm7NsljXMXg1y2He6G3MrB7MLoqLzGq7qNn2tsCAwEAATAN
+BgkqhkiG9w0BAQIFAAOBgQBMP7iLxmjf7kMzDl3ppssHhE16M/+SG/Q2rdiVIjZo
+EWx8QszznC7EBz8UsA9P/5CSdvnivErpj82ggAr3xSnxgiJduLHdgSOjeyUVRjB5
+FvjqBUuUfx3CHMjjt/QQQDwTw18fU+hI5Ia0e6E1sHslurjTjqs/OJ0ANACY89Fx
+lA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMSBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgdk4xWArzZbxpvUjZudVYK
+VdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIqWpDBucSm
+Fc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0J
+h9ZrbWB85a7FkCMMXErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2ul
+uIncrKTdcu1OofdPvAbT6shkdHvClUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68
+DzFc6PLZ
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN2E1Lm0+afY8wR4
+nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/EbRrsC+MO
+8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjV
+ojYJrKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjb
+PG7PoBMAGrgnoeS+Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP2
+6KbqxzcSXKMpHgLZ2x87tNcPVkeBFQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vr
+n5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAq2aN17O6x5q25lXQBfGfMY1a
+qtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/Ny9Sn2WCVhDr4
+wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3
+ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
+pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
+E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEC0b/EoXjaOR6+f/9YtFvgswDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAyIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQC2WoujDWojg4BrzzmH9CETMwZMJaLtVRKXxaeAufqDwSCg+i8VDXyh
+YGt+eSz6Bg86rvYbb7HS/y8oUl+DfUvEerf4Zh+AVPy3wo5ZShRXRtGak75BkQO7
+FYCTXOvnzAhsPz6zSvz/S2wj1VCCJkQZjiPDceoZJEcEnnW/yKYAHwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBAIobK/o5wXTXXtgZZKJYSi034DNHD6zt96rbHuSLBlxg
+J8pFUs4W7z8GZOeUaHxgMxURaa+dYo2jA1Rrpr7l7gUYYAS/QoD90KioHgE796Nc
+r6Pc5iaAIzy4RHT3Cq5Ji2F4zCS/iIqnDupzGUH9TQPwiNHleI2lKk/2lw0Xd8rY
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0Ns
+YXNzIDIgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y
+aXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazAe
+Fw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGlj
+IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMx
+KGMpIDE5OTggVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjxnNuX6Zr8wgQGE75fUsjM
+HiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRCwiNPStjw
+DqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cC
+AwEAATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9ji
+nb3/7aHmZuovCfTK1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAX
+rXfMSTWqz9iP0b63GJZHc2pUIjRkLbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnIn
+jBJ7xUS0rg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy
+aVNpZ24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24s
+IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNp
+Z24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJBgNV
+BAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNp
+Z24gVHJ1c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIElu
+Yy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24g
+Q2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAt
+IEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArwoNwtUs22e5LeWU
+J92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6tW8UvxDO
+JxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUY
+wZF7C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9o
+koqQHgiBVrKtaaNS0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjN
+qWm6o+sdDZykIKbBoMXRRkwXbdKsZj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/E
+Srg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0JhU8wI1NQ0kdvekhktdmnLfe
+xbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf0xwLRtxyID+u
+7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU
+sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI
+sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP
+cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICPDCCAaUCEHC65B0Q2Sk0tjjKewPMur8wDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFz
+cyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2
+MDEyOTAwMDAwMFoXDTI4MDgwMTIzNTk1OVowXzELMAkGA1UEBhMCVVMxFzAVBgNV
+BAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAzIFB1YmxpYyBQcmlt
+YXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQDJXFme8huKARS0EN8EQNvjV69qRUCPhAwL0TPZ2RHP7gJYHyX3KqhE
+BarsAx94f56TuZoAqiN91qyFomNFx3InzPRMxnVx0jnvT0Lwdd8KkMaOIG+YD/is
+I19wKTakyYbnsZogy1Olhec9vn2a/iRFM9x2Fe0PonFkTGUugWhFpwIDAQABMA0G
+CSqGSIb3DQEBAgUAA4GBALtMEivPLCYATxQT3ab7/AoRhIzzKBxnki98tsX63/Do
+lbwdj2wsqFHMc9ikwFPwTtYmwHYBV4GSXiHx0bH/59AhWM1pF+NEHJwZRDmJXNyc
+AA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2OmufTqj/ZA1k
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4
+pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg0
+13gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSk
+U01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7i
+F6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpY
+oJ2daZH9
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
+N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
+KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
+kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
+CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
+Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
+imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
+2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
+DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
+/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
+F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
+TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDAjCCAmsCEDKIjprS9esTR/h/xCA3JfgwDQYJKoZIhvcNAQEFBQAwgcExCzAJ
+BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xh
+c3MgNCBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcy
+MTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3Jp
+emVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4X
+DTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcw
+FQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgNCBQdWJsaWMg
+UHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEo
+YykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5
+MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQC68OTP+cSuhVS5B1f5j8V/aBH4xBewRNzjMHPVKmIquNDM
+HO0oW369atyzkSTKQWI8/AIBvxwWMZQFl3Zuoq29YRdsTjCG8FE3KlDHqGKB3FtK
+qsGgtG7rL+VXxbErQHDbWk2hjh+9Ax/YA9SPTJlxvOKCzFjomDqG04Y48wApHwID
+AQABMA0GCSqGSIb3DQEBBQUAA4GBAIWMEsGnuVAVess+rLhDityq3RS6iYF+ATwj
+cSGIL4LcY/oCRaxFWdcqWERbt5+BO5JoPeI3JPV7bI92NZYJqFmduc4jq3TWg/0y
+cyfYaT5DdPauxYma51N86Xv2S/PBZYPejYqcPIiNOVn8qj8ijaHBZlCBckztImRP
+T8qAkbYp
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwICEQDsoKeLbnVqAc/EfMwvlF7XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
+CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
+cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
+LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
+aWduIENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
+dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
+VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
+aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
+bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
+IENsYXNzIDQgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK3LpRFpxlmr8Y+1
+GQ9Wzsy1HyDkniYlS+BzZYlZ3tCD5PUPtbut8XzoIfzk6AzufEUiGXaStBO3IFsJ
++mGuqPKljYXCKtbeZjbSmwL0qJJgfJxptI8kHtCGUvYynEFYHiK9zUVilQhu0Gbd
+U6LM8BDcVHOLBKFGMzNcF0C5nk3T875Vg+ixiY5afJqWIpA7iCXy0lOIAgwLePLm
+NxdLMEYH5IBtptiWLugs+BGzOA1mppvqySNb247i8xOOGlktqgLw7KSHZtzBP/XY
+ufTsgsbSPZUd5cBPhMnZo0QoBmrXRazwa2rvTl/4EYIeOGM0ZlDUPpNz+jDDZq3/
+ky2X7wMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAj/ola09b5KROJ1WrIhVZPMq1
+CtRK26vdoV9TxaBXOcLORyu+OshWv8LZJxA6sQU8wHcxuzrTBXttmhwwjIDLk5Mq
+g6sFUYICABFna/OIYUdfA5PVWw3g8dShMjWFsjrbsIKr0csKvE+MW8VLADsfKoKm
+fjaF3H48ZwC15DtS4KjrXRX5xm3wrR0OhbepmnMUWluPQSjA1egtTaRezarZ7c7c
+2NU8Qh0XwRJdRTjDOPP8hS6DRkiy1yBfkjaP53kPmF6Z6PDQpLv1U70qzlmwr25/
+bLvSHgCwIe34QWKCudiyxLtGUPMxxY8BqHTr9Xgn2uf3ZkPznoM+IKrDNWCRzg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICNDCCAaECEAKtZn5ORf5eV288mBle3cAwDQYJKoZIhvcNAQECBQAwXzELMAkG
+A1UEBhMCVVMxIDAeBgNVBAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYD
+VQQLEyVTZWN1cmUgU2VydmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk0
+MTEwOTAwMDAwMFoXDTEwMDEwNzIzNTk1OVowXzELMAkGA1UEBhMCVVMxIDAeBgNV
+BAoTF1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2Vy
+dmVyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGbMA0GCSqGSIb3DQEBAQUAA4GJ
+ADCBhQJ+AJLOesGugz5aqomDV6wlAXYMra6OLDfO6zV4ZFQD5YRAUcm/jwjiioII
+0haGN1XpsSECrXZogZoFokvJSyVmIlZsiAeP94FZbYQHZXATcXY+m3dM41CJVphI
+uR2nKRoTLkoRWZweFdVJVCxzOmmCsZc5nG1wZ0jl3S3WyB57AgMBAAEwDQYJKoZI
+hvcNAQECBQADfgBl3X7hsuyw4jrg7HFGmhkRuNPHoLQDQCYCPgmc4RKz0Vr2N6W3
+YQO2WxZpO8ZECAyIUwxrl0nHPjXcbLm7qt9cuzovk2C2qUtN8iD3zV9/ZHuO3ABc
+1/p3yjkWWW8O6tO1g39NTUJWdrTJXwT4OPjr0l91X817/OWOgHz8UA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA2MTExMDQ2MzlaFw0yNzA2MTExMDQ2MzlaMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6xwS7TT3zNJc4YPk/E
+jG+AanPIW1H4m9LcuwBcsaD8dQPugfCI7iNS6eYVM42sLQnFdvkrOYCJ5JdLkKWo
+ePhzQ3ukYbDYWMzhbGZ+nPMJXlVjhNWo7/OxLjBos8Q82KxujZlakE403Daaj4GI
+ULdtlkIJ89eVgw1BS7Bqa/j8D35in2fE7SZfECYPCE/wpFcozo+47UX2bu4lXapu
+Ob7kky/ZR6By6/qmW6/KUz/iDsaWVhFu9+lmqSbYf5VT7QqFiLpPKaVCjF62/IUg
+AKpoC6EahQGcxEZjgoi2IrHu/qpGWX7PNSzVttpd90gzFFS269lvzs2I1qsb2pY7
+HVkCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
+uI3O7+cUus/usESSbLQ5PqKEbq24IXfS1HeCh+YgQYHu4vgRt2PRFze+GXYkHAQa
+TOs9qmdvLdTN/mUxcMUbpgIKumB7bVjCmkn+YzILa+M6wKyrO7Do0wlRjBCDxjTg
+xSvgGrZgFCdsMneMvLJymM/NzD+5yCRCFNZX/OYmQ6kd5YCQzgNUKD73P9P4Te1q
+CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
+O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
+6GAqm4VKQPNriiTsBhYscw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjTCCAXWgAwIBAgIDAQAhMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMxNTNaFw0xMjA3MTIxNjMxNTNaMEMxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xFzAVBgNVBAMTDkNlcnR1bSBM
+ZXZlbCBJMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCl73pZ9DFcn7Qy0qBZ
+K+So18cav7drUrJ8SiYOlDDVskt81+eIcL/4FelTSGjuAOvYdmm+HGYG998RPB0i
+Z+Ak67vXFJ537vRWOcu6aMjNuAwu8BOdc5eSgB0Y8X4+3LOYfugtaZa8mrEQ8Hit
+0yLE9UBcU9J+4PmkVGecmZ8jZQIDAQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQAlDS4aTmgK0YgmUvt/3zN7G2/ZrtBBCtONlUvC69c7
+TmLJWJ842y2AH7ryNXXkcsn6p0ZBTrTJ2tA2y/j2PXJeXrCkK/qAJIpM0l4u0MT7
+enY5akasduHp2NXMP9vDlgMy7elU2s3nkOT79gfh5XttC+5D/x4JDNi1DMAA9hk1
+6DK4zWmDVfjkiP/G3fEndtJgNDQsyqnaQ3E3bljv3f1KJTjZUvtA2Ml6MP2hFRhg
+ZPsxuhW8QXidQYNiua1h7XUUiPiERLDLWZmfY6dxGrHXjSTx3shHNaQM0qkDs9gS
+6UK8uWJN2bf2YBnvGmzy0IQvx5wDCH7h8AdaBD6DgIG1
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjjCCAXagAwIBAgIDAQAiMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMDNaFw0xMjA3MTIxNjMyMDNaMEQxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBM
+ZXZlbCBJSTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAyMQSaN5fA94hNE46
+bMKpGUb5yIPEowReGZzGttYBQnC6oUOy+iM3md8WerzXeBKf7iIZEDW2HAp7BKhS
+4rMB6taxT07vDtkNfEKwOk6X7dODw6KY4mxnzjmjh5pf2feKKJ3MoZxi2HAz2a6J
+vHKFMq8dAlGL2GBtLvzlFp2jwkMCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQUFAAOCAQEAWo3wgy+/0B7UiTCu4Wn1rvGRXIUtbPNp4Bc4PP/i
+1q6pPheIe0ooCopuqnDX9maTHhZeNpnApgCUSbyw71EaOremD7HjWXASRUTylhwL
+5FdSx+D6MgF2uW9uwZ+NErkeRJYT2aRXe5FBOVIseC4g93Ay0D8Hg50MkAC5pQqW
++8GSszT94NzT7ppIaMtq53PZpUtLGiL3UBZ5vUJ5pE4lLKD7Ce+pXzZevy/MnkMG
+D1L7LgjRWL17OcMlASFETyUTajNjvxMy+oM4C22rwHRh2WQrvgw5MO+Q3UyYA1r5
+VrSaqgQ1g06ZcQt+mhzoc2swlOSwm8iis8H6orR8xmCWrA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjzCCAXegAwIBAgIDAQAjMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMTdaFw0xMjA3MTIxNjMyMTdaMEUxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGTAXBgNVBAMTEENlcnR1bSBM
+ZXZlbCBJSUkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALZjBbfGFmlsLjPe
+pWaDwG0LqhF11lWKabaHi1sQhK3qomHY7Em7qpL11dUQ1vsMcnnpzz/J0AEH6KDh
++yAyXV1SE/tVToLYYByZK+JGacLYIYF9aCwV8AhqyzOGurO5QX6vLboXB2WNnwmX
+hyNVKUgnUVy4ktAR2qZJIw5Bjsn/AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAIsLt3vKCZqd/gui45ovm3FSO6FLjzzq4pagPvbN
+nZ39HrhRaCpqkHDAj71L5L27U3eW2D4ILL0iUmZadbC4i3at/PUL9mjhGlajcCN8
+EF6IXGT87Tbcii735jRaaXSbEY4YhNOg9DPBoD4uJMkA8Z0Y/6lYmk4S6KUMCzzt
+t5zZBiWjdd08yFi5VGMvpE74KVOMdMa3JNVaR0XvT0Q8yXo1XKCrY9OFIxnhVgDb
+hzr9fwjKWDwu8kxhT9khAETm0BU2Buu+CTasaJdT/bBR2YEx9qcN7XyXTeDtkOO5
+QeGSqFgzquwjWEbKhf7l/e+efdRCg+ikH3O5snHB6iS+dgg=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICjjCCAXagAwIBAgIDAQAkMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
+QTAeFw0wMjA3MTIxNjMyMzVaFw0xMjA3MTIxNjMyMzVaMEQxCzAJBgNVBAYTAlBM
+MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xGDAWBgNVBAMTD0NlcnR1bSBM
+ZXZlbCBJVjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmyb1lKqCAKE4juAy
+6lpVNUl6aJ2DuWPSiJ3BBk3/6ty6I4Lr2Dpy1b1vjVelhaFsVKEDgK2JyQlk9XMq
+LPZI2Ql166mJiPKFg77aY/W78EcQfGyjnRvVcs0tG40mAs/p84OEpFcVe/RSqDrD
+/D7R01u+Wj5xLl0PUsFplIGDbikCAwEAAaMTMBEwDwYDVR0TAQH/BAUwAwEB/zAN
+BgkqhkiG9w0BAQUFAAOCAQEAPS99JujKGVRfa50TKfieq+uK1SxjidErYaZTb3cJ
+NNfQDYn6nk4lnrnab5EUVhO/NegP2yIu3YOnZGfxFDhvVozMTKKAB5r5XKOvzsP9
+9C9578PVMLozucfUMCSwau7Z4l5uuQOHuzjzlVLCibbbf4RwfvZ7hh5sB5c0pNbw
+RQq64RXQUUEvul/W9gUeT9ISHOsASGTq+HJ5i7vNARjukEAXW/maqs9vyTWWbGVI
+1FSOnVyteymq4Xk+9YlIyNPNyacgnsMnU72XKBLDS0KJdhIWALFAZI4dSh5WZNuW
+ZguUnEmeH81lLbR+p/N3iuN8+oSo8UXik92jxeUY2tQJUA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+owDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAyIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMiBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANo46O0y
+AClxgwENv4wB3NrGrTmkqYov1YtcaF9QxmL1Zr3KkSLsqh1R1z2zUbKDTl3LSbDw
+TFXlay3HhQswHJJOgtTKAu33b77c4OMUuAVT8pr0VotanoWT0bSCVq5Nu6hLVxa8
+/vhYnvgpjbB7zXjJT6yLZwzxnPv8V5tXXE8NAgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBAIRS+yjf/x91AbwBvgRWl2p0QiQxg/lGsQaKic+WLDO/
+jLVfenKhhQbOhvgFjuj5Jcrag4wGrOs2bYWRNAQ29ELw+HkuCkhcq8xRT3h2oNms
+Gb0q0WkEKJHKNhAngFdb0lz1wlurZIFjdFH0l7/NEij3TWZ/p/AcASZ4smZHcFFk
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDXDCCAsWgAwIBAgICA+swDQYJKoZIhvcNAQEEBQAwgbwxCzAJBgNVBAYTAkRF
+MRAwDgYDVQQIEwdIYW1idXJnMRAwDgYDVQQHEwdIYW1idXJnMTowOAYDVQQKEzFU
+QyBUcnVzdENlbnRlciBmb3IgU2VjdXJpdHkgaW4gRGF0YSBOZXR3b3JrcyBHbWJI
+MSIwIAYDVQQLExlUQyBUcnVzdENlbnRlciBDbGFzcyAzIENBMSkwJwYJKoZIhvcN
+AQkBFhpjZXJ0aWZpY2F0ZUB0cnVzdGNlbnRlci5kZTAeFw05ODAzMDkxMTU5NTla
+Fw0xMTAxMDExMTU5NTlaMIG8MQswCQYDVQQGEwJERTEQMA4GA1UECBMHSGFtYnVy
+ZzEQMA4GA1UEBxMHSGFtYnVyZzE6MDgGA1UEChMxVEMgVHJ1c3RDZW50ZXIgZm9y
+IFNlY3VyaXR5IGluIERhdGEgTmV0d29ya3MgR21iSDEiMCAGA1UECxMZVEMgVHJ1
+c3RDZW50ZXIgQ2xhc3MgMyBDQTEpMCcGCSqGSIb3DQEJARYaY2VydGlmaWNhdGVA
+dHJ1c3RjZW50ZXIuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALa0wTUF
+Lg2N7KBAahwOJ6ZQkmtQGwfeLud2zODa/ISoXoxjaitN2U4CdhHBC/KNecoAtvGw
+Dtf7pBc9r6tpepYnv68zoZoqWarEtTcI8hKlMbZD9TKWcSgoq40oht+77uMMfTDW
+w1Krj10nnGvAo+cFa1dJRLNu6mTP0o56UHd3AgMBAAGjazBpMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgGGMDMGCWCGSAGG+EIBCAQmFiRodHRwOi8vd3d3
+LnRydXN0Y2VudGVyLmRlL2d1aWRlbGluZXMwEQYJYIZIAYb4QgEBBAQDAgAHMA0G
+CSqGSIb3DQEBBAUAA4GBABY9xs3Bu4VxhUafPiCPUSiZ7C1FIWMjWwS7TJC4iJIE
+Tb19AaM/9uzO8d7+feXhPrvGq14L3T2WxMup1Pkm5gZOngylerpuw3yCGdHHsbHD
+2w2Om0B8NwvxXej9H5CIpQ5ON2QhqE6NtJ/x3kit1VYYUimLRzQSCdS7kjXvD9s0
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIG2jCCBcKgAwIBAgIDFc/9MA0GCSqGSIb3DQEBBQUAMIGsMQswCQYDVQQGEwJE
+RTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYDVQQLEw1E
+Rk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRERk4gVG9w
+bGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEmNl
+cnRpZnlAcGNhLmRmbi5kZTAeFw0wMTEyMDExMjExMTZaFw0xMDAxMzExMjExMTZa
+MIGsMQswCQYDVQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3Nu
+ZXR6MRYwFAYDVQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0w
+KwYDVQQDEyRERk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAf
+BgkqhkiG9w0BCQEWEmNlcnRpZnlAcGNhLmRmbi5kZTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMF5rhMt6zmhxK5oWPwT2FG7Up7T5DovHSD/YKPIRxsv
+DWmC4dTzByIBLnOmEflk+5KAqAYao6eY1qF0hR4WiS4DjCsn7l3zNo/4i2eF4EmG
+EksBygb4tRlTThcO7heFX+Du5qFoks+ONqa70RlwOr2l53KVwjMXBCtCLFSKRLVu
+xeh5+Smkm+FuOmwEugndM2n74Djjyf9DCOaHGZrHwVDh+Vpy5Ny4bKCSboujRxd5
+NxsStUshDVbTeS3B8TuzAJbywYWEE7erox+7WTfQr8ivSCBhrNJ36VRjAb8hiV9I
+uy2TmJYo2oPyC8a3eM3xj9Ku2IW3tS2zpfiIzt9xvFMCAwEAAaOCAwEwggL9MA8G
+A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFAYL+rX4SHijILELPs+g0MTRf33QMIHb
+BgNVHSMEgdMwgdCAFAYL+rX4SHijILELPs+g0MTRf33QoYGypIGvMIGsMQswCQYD
+VQQGEwJERTEhMB8GA1UEChMYRGV1dHNjaGVzIEZvcnNjaHVuZ3NuZXR6MRYwFAYD
+VQQLEw1ERk4tQ0VSVCBHbWJIMRAwDgYDVQQLEwdERk4tUENBMS0wKwYDVQQDEyRE
+Rk4gVG9wbGV2ZWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxITAfBgkqhkiG9w0B
+CQEWEmNlcnRpZnlAcGNhLmRmbi5kZYIDFc/9MAsGA1UdDwQEAwIBBjARBglghkgB
+hvhCAQEEBAMCAAcwgaUGA1UdHwSBnTCBmjBLoEmgR4ZFaHR0cDovL3d3dy5kZm4t
+cGNhLmRlL2NlcnRpZmljYXRpb24veDUwOS9nMS9kYXRhL2NybHMvcm9vdC1jYS1j
+cmwuY3J4MEugSaBHhkVodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlv
+bi94NTA5L2cxL2RhdGEvY3Jscy9yb290LWNhLWNybC5jcmwwOAYJYIZIAYb4QgED
+BCsWKWh0dHBzOi8vd3d3LmRmbi1wY2EuZGUvY2dpL2NoZWNrLXJldi5jZ2k/MEsG
+CWCGSAGG+EIBCAQ+FjxodHRwOi8vd3d3LmRmbi1wY2EuZGUvY2VydGlmaWNhdGlv
+bi9wb2xpY2llcy94NTA5cG9saWN5Lmh0bWwwOAYJYIZIAYb4QgENBCsWKVRoZSBE
+Rk4gVG9wLUxldmVsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MGQGA1UdIARdMFsw
+WQYLKwYBBAHZGoIsAQEwSjBIBggrBgEFBQcCARY8aHR0cDovL3d3dy5kZm4tcGNh
+LmRlL2NlcnRpZmljYXRpb24vcG9saWNpZXMveDUwOXBvbGljeS5odG1sMA0GCSqG
+SIb3DQEBBQUAA4IBAQAmbai6JMt7nkuavyvxKzLGn04Gyt0zKrp8zmERp4inktvY
+7p+vkaomYu2QYC7cHq0tlrPXQQhhetjiXGb+36aJtHDkEA0NwrJzYnHgPsvx7z0w
+ysENP4wxf97KsSWm07RY+f6/gIQF7Je7CW30Rzq7N6R0NMBs32mJgdn3ntqlFNw3
+Nbs050FEjPNq54RdawlJo85x+w+QJd7uQM4yZjHpRhvwgte9Ge1UqCUdpMsLHzeM
+KJ0B9GhwIIqOJCMiPgKjcUBrn6ehSX70POvXvjjE2+FzhPGTyTkS474d2UCAnL9q
+hPrdWXzBjOumOjhJutT1aecm9eljlshmh1cNen00
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB
+ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt
+TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1
+NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
+IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD
+VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS
+Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2
+N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH
+iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe
+YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1
+axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g
+yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
+AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh
+ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V
+VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB
+BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y
+IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs
+QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4
+ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM
+YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb
+QErNaLly7HF27FSOH4UMAWr6pjisH8SE
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
+ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
+fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
+BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
+cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
+HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
+CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
+3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
+6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
+HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
+Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
+Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
+DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
+5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
+gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
+aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
+izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx
+MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG
+29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk
+oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk
+3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL
+qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN
+nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX
+ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H
+DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO
+TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv
+kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w
+zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
+MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
+Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
+5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
+3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
+vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
+8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
+zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
+3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
+FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
+Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
+ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB
+rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt
+Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa
+Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV
+BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l
+dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE
+AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B
+YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9
+hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l
+L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm
+SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM
+1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws
+6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw
+Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50
+aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
+AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u
+7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0
+xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ
+rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim
+eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk
+USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB
+lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt
+T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc
+BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3
+dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP
+HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO
+KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo
+5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+
+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb
+kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC
+AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
+L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV
+HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN
+AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw
+NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB
+mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU
+4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5
+81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR
+Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFTzCCBLigAwIBAgIBaDANBgkqhkiG9w0BAQQFADCBmzELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTQwMgYDVQQD
+EytOZXRMb2NrIEV4cHJlc3N6IChDbGFzcyBDKSBUYW51c2l0dmFueWtpYWRvMB4X
+DTk5MDIyNTE0MDgxMVoXDTE5MDIyMDE0MDgxMVowgZsxCzAJBgNVBAYTAkhVMREw
+DwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9u
+c2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE0MDIGA1UEAxMr
+TmV0TG9jayBFeHByZXNzeiAoQ2xhc3MgQykgVGFudXNpdHZhbnlraWFkbzCBnzAN
+BgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6+ywbGGKIyWvYCDj2Z/8kwvbXY2wobNA
+OoLO/XXgeDIDhlqGlZHtU/qdQPzm6N3ZW3oDvV3zOwzDUXmbrVWg6dADEK8KuhRC
+2VImESLH0iDMgqSaqf64gXadarfSNnU+sYYJ9m5tfk63euyucYT2BDMIJTLrdKwW
+RMbkQJMdf60CAwEAAaOCAp8wggKbMBIGA1UdEwEB/wQIMAYBAf8CAQQwDgYDVR0P
+AQH/BAQDAgAGMBEGCWCGSAGG+EIBAQQEAwIABzCCAmAGCWCGSAGG+EIBDQSCAlEW
+ggJNRklHWUVMRU0hIEV6ZW4gdGFudXNpdHZhbnkgYSBOZXRMb2NrIEtmdC4gQWx0
+YWxhbm9zIFN6b2xnYWx0YXRhc2kgRmVsdGV0ZWxlaWJlbiBsZWlydCBlbGphcmFz
+b2sgYWxhcGphbiBrZXN6dWx0LiBBIGhpdGVsZXNpdGVzIGZvbHlhbWF0YXQgYSBO
+ZXRMb2NrIEtmdC4gdGVybWVrZmVsZWxvc3NlZy1iaXp0b3NpdGFzYSB2ZWRpLiBB
+IGRpZ2l0YWxpcyBhbGFpcmFzIGVsZm9nYWRhc2FuYWsgZmVsdGV0ZWxlIGF6IGVs
+b2lydCBlbGxlbm9yemVzaSBlbGphcmFzIG1lZ3RldGVsZS4gQXogZWxqYXJhcyBs
+ZWlyYXNhIG1lZ3RhbGFsaGF0byBhIE5ldExvY2sgS2Z0LiBJbnRlcm5ldCBob25s
+YXBqYW4gYSBodHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIGNpbWVuIHZhZ3kg
+a2VyaGV0byBheiBlbGxlbm9yemVzQG5ldGxvY2submV0IGUtbWFpbCBjaW1lbi4g
+SU1QT1JUQU5UISBUaGUgaXNzdWFuY2UgYW5kIHRoZSB1c2Ugb2YgdGhpcyBjZXJ0
+aWZpY2F0ZSBpcyBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIENQUyBhdmFpbGFibGUg
+YXQgaHR0cHM6Ly93d3cubmV0bG9jay5uZXQvZG9jcyBvciBieSBlLW1haWwgYXQg
+Y3BzQG5ldGxvY2submV0LjANBgkqhkiG9w0BAQQFAAOBgQAQrX/XDDKACtiG8XmY
+ta3UzbM2xJZIwVzNmtkFLp++UOv0JhQQLdRmF/iewSf98e3ke0ugbLWrmldwpu2g
+pO0u9f38vf5NNwgMvOOWgyL1SRt/Syu0VMGAfJlOHdCM7tCs5ZL6dVb+ZKATj7i4
+Fp1hBWeAyNDYpQcCNJgEjTME1A==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIGfTCCBWWgAwIBAgICAQMwDQYJKoZIhvcNAQEEBQAwga8xCzAJBgNVBAYTAkhV
+MRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhCdWRhcGVzdDEnMCUGA1UEChMe
+TmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQuMRowGAYDVQQLExFUYW51c2l0
+dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBLb3pqZWd5em9pIChDbGFzcyBB
+KSBUYW51c2l0dmFueWtpYWRvMB4XDTk5MDIyNDIzMTQ0N1oXDTE5MDIxOTIzMTQ0
+N1owga8xCzAJBgNVBAYTAkhVMRAwDgYDVQQIEwdIdW5nYXJ5MREwDwYDVQQHEwhC
+dWRhcGVzdDEnMCUGA1UEChMeTmV0TG9jayBIYWxvemF0Yml6dG9uc2FnaSBLZnQu
+MRowGAYDVQQLExFUYW51c2l0dmFueWtpYWRvazE2MDQGA1UEAxMtTmV0TG9jayBL
+b3pqZWd5em9pIChDbGFzcyBBKSBUYW51c2l0dmFueWtpYWRvMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvHSMD7tM9DceqQWC2ObhbHDqeLVu0ThEDaiD
+zl3S1tWBxdRL51uUcCbbO51qTGL3cfNk1mE7PetzozfZz+qMkjvN9wfcZnSX9EUi
+3fRc4L9t875lM+QVOr/bmJBVOMTtplVjC7B4BPTjbsE/jvxReB+SnoPC/tmwqcm8
+WgD/qaiYdPv2LD4VOQ22BFWoDpggQrOxJa1+mm9dU7GrDPzr4PN6s6iz/0b2Y6LY
+Oph7tqyF/7AlT3Rj5xMHpQqPBffAZG9+pyeAlt7ULoZgx2srXnN7F+eRP2QM2Esi
+NCubMvJIH5+hCoR64sKtlz2O1cH5VqNQ6ca0+pii7pXmKgOM3wIDAQABo4ICnzCC
+ApswDgYDVR0PAQH/BAQDAgAGMBIGA1UdEwEB/wQIMAYBAf8CAQQwEQYJYIZIAYb4
+QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1GSUdZRUxFTSEgRXplbiB0
+YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFub3MgU3pvbGdhbHRhdGFz
+aSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBhbGFwamFuIGtlc3p1bHQu
+IEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExvY2sgS2Z0LiB0ZXJtZWtm
+ZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGlnaXRhbGlzIGFsYWlyYXMg
+ZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0IGVsbGVub3J6ZXNpIGVs
+amFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJhc2EgbWVndGFsYWxoYXRv
+IGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGphbiBhIGh0dHBzOi8vd3d3
+Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJoZXRvIGF6IGVsbGVub3J6
+ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBPUlRBTlQhIFRoZSBpc3N1
+YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGlzIHN1YmplY3Qg
+dG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBodHRwczovL3d3dy5uZXRs
+b2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNAbmV0bG9jay5uZXQuMA0G
+CSqGSIb3DQEBBAUAA4IBAQBIJEb3ulZv+sgoA0BO5TE5ayZrU3/b39/zcT0mwBQO
+xmd7I6gMc90Bu8bKbjc5VdXHjFYgDigKDtIqpLBJUsY4B/6+CgmM0ZjPytoUMaFP
+0jn8DxEsQ8Pdq5PHVT5HfBgaANzze9jyf1JsIPQLX2lS9O74silg6+NJMSEN1rUQ
+QeJBCWziGppWS3cC9qCbmieH6FUpccKQn0V4GuEVZD3QDtigdp+uxdAu6tYPVuxk
+f1qbFFgBJ34TUMdrKuZoPL9coAob4Q566eKAw+np9v1sEZ7Q5SgnK1QyQhSCdeZK
+8CtmdWOMovsEPoMOmzbwGOQmIMOM8CgHrTwXZoi1/baI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFSzCCBLSgAwIBAgIBaTANBgkqhkiG9w0BAQQFADCBmTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMTIwMAYDVQQD
+EylOZXRMb2NrIFV6bGV0aSAoQ2xhc3MgQikgVGFudXNpdHZhbnlraWFkbzAeFw05
+OTAyMjUxNDEwMjJaFw0xOTAyMjAxNDEwMjJaMIGZMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxMjAwBgNVBAMTKU5l
+dExvY2sgVXpsZXRpIChDbGFzcyBCKSBUYW51c2l0dmFueWtpYWRvMIGfMA0GCSqG
+SIb3DQEBAQUAA4GNADCBiQKBgQCx6gTsIKAjwo84YM/HRrPVG/77uZmeBNwcf4xK
+gZjupNTKihe5In+DCnVMm8Bp2GQ5o+2So/1bXHQawEfKOml2mrriRBf8TKPV/riX
+iK+IA4kfpPIEPsgHC+b5sy96YhQJRhTKZPWLgLViqNhr1nGTLbO/CVRY7QbrqHvc
+Q7GhaQIDAQABo4ICnzCCApswEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8E
+BAMCAAYwEQYJYIZIAYb4QgEBBAQDAgAHMIICYAYJYIZIAYb4QgENBIICURaCAk1G
+SUdZRUxFTSEgRXplbiB0YW51c2l0dmFueSBhIE5ldExvY2sgS2Z0LiBBbHRhbGFu
+b3MgU3pvbGdhbHRhdGFzaSBGZWx0ZXRlbGVpYmVuIGxlaXJ0IGVsamFyYXNvayBh
+bGFwamFuIGtlc3p1bHQuIEEgaGl0ZWxlc2l0ZXMgZm9seWFtYXRhdCBhIE5ldExv
+Y2sgS2Z0LiB0ZXJtZWtmZWxlbG9zc2VnLWJpenRvc2l0YXNhIHZlZGkuIEEgZGln
+aXRhbGlzIGFsYWlyYXMgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYXogZWxvaXJ0
+IGVsbGVub3J6ZXNpIGVsamFyYXMgbWVndGV0ZWxlLiBBeiBlbGphcmFzIGxlaXJh
+c2EgbWVndGFsYWxoYXRvIGEgTmV0TG9jayBLZnQuIEludGVybmV0IGhvbmxhcGph
+biBhIGh0dHBzOi8vd3d3Lm5ldGxvY2submV0L2RvY3MgY2ltZW4gdmFneSBrZXJo
+ZXRvIGF6IGVsbGVub3J6ZXNAbmV0bG9jay5uZXQgZS1tYWlsIGNpbWVuLiBJTVBP
+UlRBTlQhIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmlj
+YXRlIGlzIHN1YmplY3QgdG8gdGhlIE5ldExvY2sgQ1BTIGF2YWlsYWJsZSBhdCBo
+dHRwczovL3d3dy5uZXRsb2NrLm5ldC9kb2NzIG9yIGJ5IGUtbWFpbCBhdCBjcHNA
+bmV0bG9jay5uZXQuMA0GCSqGSIb3DQEBBAUAA4GBAATbrowXr/gOkDFOzT4JwG06
+sPgzTEdM43WIEJessDgVkcYplswhwG08pXTP2IKlOcNl40JwuyKQ433bNXbhoLXa
+n3BukxowOR0w2y7jfLKRstE3Kfq51hdcR0/jHTjrn9V7lagonhVK0dHQKwCXoOKS
+NitjrFgBazMpUIaD8QFI
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIICiTCCAfKgAwIBAgIEN4dnrDANBgkqhkiG9w0BAQUFADB1MQswCQYDVQQGEwJi
+ZTERMA8GA1UEChMIQmVsZ2Fjb20xDDAKBgNVBAsTA01UTTEkMCIGA1UEAxMbQmVs
+Z2Fjb20gRS1UcnVzdCBQcmltYXJ5IENBMR8wHQYKCZImiZPyLGQBAxQPaW5mb0Bl
+LXRydXN0LmJlMB4XDTk4MTEwNDEzMDQzOVoXDTEwMDEyMTEzMDQzOVowdTELMAkG
+A1UEBhMCYmUxETAPBgNVBAoTCEJlbGdhY29tMQwwCgYDVQQLEwNNVE0xJDAiBgNV
+BAMTG0JlbGdhY29tIEUtVHJ1c3QgUHJpbWFyeSBDQTEfMB0GCgmSJomT8ixkAQMU
+D2luZm9AZS10cnVzdC5iZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqtm5
+s9VPak3FQdB7BGFqi3GBB9pk41huJ1XCrc4XsPz6ko0I8Bxy/7LDMf7gaoeXTMxD
+V6coeTq1g12kHWrxasU+FCIdWQZv8KYxd9ywSTjmywwP/qpyNIjaKDohWu50Kxuk
+21sTFrVzX8OujNLAPj2wy/Dsi4YLwsFEGFpjqNUCAwEAAaMmMCQwDwYDVR0TBAgw
+BgEB/wIBATARBglghkgBhvhCAQEEBAMCAAcwDQYJKoZIhvcNAQEFBQADgYEAerKx
+pbF9M+nC4RvO05OMfwH9Gx1amq6rB1Ev7Ymr3VBCux//SrWknLFhKQpM6oNZSY2v
+hmnXgaxHqqRxblnvynxqblSK2qiSyfVms3lf1IsBniFjRjWTpcJfImIDcB1jI+hr
+SB0jECfY9t9HorrsgFBKbMRwpnrkdCJ/9oRiMn8=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE
+SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw
+ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU
+REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr
+2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s
+2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU
+GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj
+dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r
+TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB
+AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv
+c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl
+ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu
+MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg
+T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud
+HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD
+VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny
+bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy
+MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ
+J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG
+SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom
+JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO
+inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y
+caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB
+mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ
+YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9
+BKNDLdr8C2LqL19iUw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE
+SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg
+Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV
+BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl
+cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA
+vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu
+Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a
+0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1
+4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN
+eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD
+R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG
+A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu
+dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME
+Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3
+WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw
+HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ
+KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO
+Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX
+wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89
+9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0
+jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38
+aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD
+EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz
+aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w
+MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l
+dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh
+bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq
+eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe
+r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5
+3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd
+vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l
+mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC
+wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg
+hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0
+TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh
+biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg
+ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg
+dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6
+b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl
+c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0
+ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3
+dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu
+ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh
+bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo
+ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3
+Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u
+ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA
+A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ
+MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+
+NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR
+VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY
+83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3
+macqaJVmlaut74nLYKkGEsaUR+ko
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBEMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3QgR2xvYmFs
+IENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMTkwMzA0MDUwMDAwWjBEMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEdMBsGA1UEAxMUR2VvVHJ1c3Qg
+R2xvYmFsIENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDvPE1A
+PRDfO1MA4Wf+lGAVPoWI8YkNkMgoI5kF6CsgncbzYEbYwbLVjDHZ3CB5JIG/NTL8
+Y2nbsSpr7iFY8gjpeMtvy/wWUsiRxP89c96xPqfCfWbB9X5SJBri1WeR0IIQ13hL
+TytCOb1kLUCgsBDTOEhGiKEMuzozKmKY+wCdE1l/bztyqu6mD4b5BWHqZ38MN5aL
+5mkWRxHCJ1kDs6ZgwiFAVvqgx306E+PsV8ez1q6diYD3Aecs9pYrEw15LNnA5IZ7
+S4wMcoKK+xfNAGw6EzywhIdLFnopsk/bHdQL82Y3vdj2V7teJHq4PIu5+pIaGoSe
+2HSPqht/XvT+RSIhAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
+FHE4NvICMVNHK266ZUapEBVYIAUJMB8GA1UdIwQYMBaAFHE4NvICMVNHK266ZUap
+EBVYIAUJMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOCAQEAA/e1K6td
+EPx7srJerJsOflN4WT5CBP51o62sgU7XAotexC3IUnbHLB/8gTKY0UvGkpMzNTEv
+/NgdRN3ggX+d6YvhZJFiCzkIjKx0nVnZellSlxG5FntvRdOW2TF9AjYPnDtuzywN
+A0ZF66D0f0hExghAzN4bcLUprbqLOzRldRtxIR0sFAqwlpW41uryZfspuk/qkZN0
+abby/+Ea0AzRdoXLiiW9l14sbxWZJue2Kf8i7MkCx1YAzUm5s2x7UwQa4qjJqhIF
+I8LO57sEAszAR6LkxCkvW0VXiVHuPOtSCP8HNR6fNWpHSlaY0VqFH4z1Ir+rzoPz
+4iIprn2DQKi6bA==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE
+BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0
+IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV
+VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8
+cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT
+QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh
+F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v
+c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w
+mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd
+VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX
+teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ
+f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe
+Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+
+nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB
+/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY
+MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG
+9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc
+aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX
+IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn
+ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z
+uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN
+Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja
+QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW
+koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9
+ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt
+DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm
+bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW
+MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy
+c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD
+VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1
+c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81
+WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG
+FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq
+XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL
+se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb
+KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd
+IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73
+y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt
+hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc
+QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4
+Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV
+HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
+KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z
+dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ
+L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr
+Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo
+ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY
+T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz
+GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m
+1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV
+OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH
+6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX
+QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
+MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
+IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
+dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
+li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
+rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
+WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
+F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
+xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
+Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
+dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
+ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
+IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
+c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
+ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
+KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
+KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
+y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
+dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
+VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
+MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
+fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
+7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
+cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
+mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
+xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
+SnQ2+Q==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa
+GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg
+Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J
+WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB
+rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp
++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1
+ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i
+Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz
+PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og
+/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH
+oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
+yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud
+EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2
+A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL
+MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f
+BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn
+g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl
+fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K
+WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha
+B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc
+hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR
+TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD
+mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z
+ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
+4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
+8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM
+V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB
+4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr
+H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd
+8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv
+vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT
+mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe
+btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc
+T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt
+WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ
+c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
+4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD
+VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG
+CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0
+aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw
+czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G
+A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg
+Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0
+7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem
+d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd
++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B
+4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN
+t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
+DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57
+k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s
+zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j
+Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
+mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
+4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
diff --git a/src/network/ssl/ssl.pri b/src/network/ssl/ssl.pri
new file mode 100644
index 0000000000..196e19d7f6
--- /dev/null
+++ b/src/network/ssl/ssl.pri
@@ -0,0 +1,33 @@
+# OpenSSL support; compile in QSslSocket.
+contains(QT_CONFIG, openssl) | contains(QT_CONFIG, openssl-linked) {
+ 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
+
+ # Include Qt's default CA bundle
+ RESOURCES += network.qrc
+
+ # Add optional SSL libs
+ LIBS += $$OPENSSL_LIBS
+}