diff options
Diffstat (limited to 'src/network/ssl/qsslsocket_openssl.cpp')
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 190 |
1 files changed, 112 insertions, 78 deletions
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 0315749cb3..1d675edbbb 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtNetwork module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Digia. For licensing terms and -** conditions see http://qt.digia.com/licensing. For further information +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** 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. +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional -** rights. These rights are described in the Digia Qt LGPL Exception +** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, 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. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -62,6 +54,7 @@ #include "qsslsocket.h" #include "qsslcertificate_p.h" #include "qsslcipher_p.h" +#include "qsslkey_p.h" #include <QtCore/qdatetime.h> #include <QtCore/qdebug.h> @@ -585,6 +578,16 @@ QString QSslSocketPrivate::sslLibraryVersionString() return QString::fromLatin1(versionString); } +long QSslSocketPrivate::sslLibraryBuildVersionNumber() +{ + return OPENSSL_VERSION_NUMBER; +} + +QString QSslSocketPrivate::sslLibraryBuildVersionString() +{ + return QLatin1String(OPENSSL_VERSION_TEXT); +} + /*! \internal @@ -1429,6 +1432,28 @@ QSslCipher QSslSocketBackendPrivate::sessionCipher() const return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher(); } +QSsl::SslProtocol QSslSocketBackendPrivate::sessionProtocol() const +{ + if (!ssl) + return QSsl::UnknownProtocol; + int ver = q_SSL_version(ssl); + + switch (ver) { + case 0x2: + return QSsl::SslV2; + case 0x300: + return QSsl::SslV3; + case 0x301: + return QSsl::TlsV1_0; + case 0x302: + return QSsl::TlsV1_1; + case 0x303: + return QSsl::TlsV1_2; + } + + return QSsl::UnknownProtocol; +} + void QSslSocketBackendPrivate::continueHandshake() { Q_Q(QSslSocket); @@ -1519,65 +1544,6 @@ QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates return certificates; } -bool QSslSocketBackendPrivate::isMatchingHostname(const QSslCertificate &cert, const QString &peerName) -{ - QStringList commonNameList = cert.subjectInfo(QSslCertificate::CommonName); - - foreach (const QString &commonName, commonNameList) { - if (isMatchingHostname(commonName.toLower(), peerName.toLower())) { - return true; - } - } - - foreach (const QString &altName, cert.subjectAlternativeNames().values(QSsl::DnsEntry)) { - if (isMatchingHostname(altName.toLower(), peerName.toLower())) { - return true; - } - } - - return false; -} - -bool QSslSocketBackendPrivate::isMatchingHostname(const QString &cn, const QString &hostname) -{ - int wildcard = cn.indexOf(QLatin1Char('*')); - - // Check this is a wildcard cert, if not then just compare the strings - if (wildcard < 0) - return cn == hostname; - - int firstCnDot = cn.indexOf(QLatin1Char('.')); - int secondCnDot = cn.indexOf(QLatin1Char('.'), firstCnDot+1); - - // Check at least 3 components - if ((-1 == secondCnDot) || (secondCnDot+1 >= cn.length())) - return false; - - // Check * is last character of 1st component (ie. there's a following .) - if (wildcard+1 != firstCnDot) - return false; - - // Check only one star - if (cn.lastIndexOf(QLatin1Char('*')) != wildcard) - return false; - - // Check characters preceding * (if any) match - if (wildcard && (hostname.leftRef(wildcard) != cn.leftRef(wildcard))) - return false; - - // Check characters following first . match - if (hostname.midRef(hostname.indexOf(QLatin1Char('.'))) != cn.midRef(firstCnDot)) - return false; - - // Check if the hostname is an IP address, if so then wildcards are not allowed - QHostAddress addr(hostname); - if (!addr.isNull()) - return false; - - // Ok, I guess this was a wildcard CN and the hostname matches. - return true; -} - QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certificateChain, const QString &hostName) { QList<QSslError> errors; @@ -1703,4 +1669,72 @@ QList<QSslError> QSslSocketBackendPrivate::verify(QList<QSslCertificate> certifi return errors; } +bool QSslSocketBackendPrivate::importPKCS12(QIODevice *device, + QSslKey *key, QSslCertificate *cert, + QList<QSslCertificate> *caCertificates, + const QByteArray &passPhrase) +{ + if (!supportsSsl()) + return false; + + // These are required + Q_ASSERT(device); + Q_ASSERT(key); + Q_ASSERT(cert); + + // Read the file into a BIO + QByteArray pkcs12data = device->readAll(); + if (pkcs12data.size() == 0) + return false; + + BIO *bio = q_BIO_new_mem_buf(const_cast<char *>(pkcs12data.constData()), pkcs12data.size()); + + // Create the PKCS#12 object + PKCS12 *p12 = q_d2i_PKCS12_bio(bio, 0); + if (!p12) { + qWarning("Unable to read PKCS#12 structure, %s", q_ERR_error_string(q_ERR_get_error(), 0)); + q_BIO_free(bio); + return false; + } + + // Extract the data + EVP_PKEY *pkey; + X509 *x509; + STACK_OF(X509) *ca = 0; + + if (!q_PKCS12_parse(p12, passPhrase.constData(), &pkey, &x509, &ca)) { + qWarning("Unable to parse PKCS#12 structure, %s", q_ERR_error_string(q_ERR_get_error(), 0)); + q_PKCS12_free(p12); + q_BIO_free(bio); + return false; + } + + // Convert to Qt types + if (!key->d->fromEVP_PKEY(pkey)) { + qWarning("Unable to convert private key"); + q_sk_pop_free(reinterpret_cast<STACK *>(ca), reinterpret_cast<void(*)(void*)>(q_sk_free)); + q_X509_free(x509); + q_EVP_PKEY_free(pkey); + q_PKCS12_free(p12); + q_BIO_free(bio); + + return false; + } + + *cert = QSslCertificatePrivate::QSslCertificate_from_X509(x509); + + if (caCertificates) + *caCertificates = QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(ca); + + // Clean up + q_sk_pop_free(reinterpret_cast<STACK *>(ca), reinterpret_cast<void(*)(void*)>(q_sk_free)); + q_X509_free(x509); + q_EVP_PKEY_free(pkey); + q_PKCS12_free(p12); + q_BIO_free(bio); + + return true; +} + + QT_END_NAMESPACE |