diff options
Diffstat (limited to 'src/network/ssl/qsslsocket_openssl.cpp')
-rw-r--r-- | src/network/ssl/qsslsocket_openssl.cpp | 160 |
1 files changed, 101 insertions, 59 deletions
diff --git a/src/network/ssl/qsslsocket_openssl.cpp b/src/network/ssl/qsslsocket_openssl.cpp index 0315749cb3..dc08954d6e 100644 --- a/src/network/ssl/qsslsocket_openssl.cpp +++ b/src/network/ssl/qsslsocket_openssl.cpp @@ -62,6 +62,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 +586,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 +1440,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 +1552,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 +1677,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 |