// Copyright 2005-2019 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #include "SSL.h" #include "SSLLocks.h" #include "Version.h" #include #include #include void MumbleSSL::initialize() { // Let Qt initialize its copy of OpenSSL, if it's different than // Mumble's. (Initialization is a side-effect of calling // QSslSocket::supportsSsl()). QSslSocket::supportsSsl(); // Initialize our copy of OpenSSL. SSL_library_init(); // Safe to discard return value, per OpenSSL man pages. SSL_load_error_strings(); // Determine if a locking callback has not been set. // This should be the case if there are multiple copies // of OpensSSL in the address space. This is mostly due // to Qt dynamically loading OpenSSL when it is not // configured with -openssl-linked. // // If we detect that no locking callback is configured, we // have to set it up ourselves to allow multi-threaded use // of OpenSSL. if (CRYPTO_get_locking_callback() == NULL) { SSLLocks::initialize(); } } void MumbleSSL::destroy() { SSLLocks::destroy(); } QString MumbleSSL::defaultOpenSSLCipherString() { return QLatin1String("EECDH+AESGCM:EDH+aRSA+AESGCM:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA"); } QList MumbleSSL::ciphersFromOpenSSLCipherString(QString cipherString) { QList chosenCiphers; SSL_CTX *ctx = NULL; SSL *ssl = NULL; const SSL_METHOD *meth = NULL; int i = 0; QByteArray csbuf = cipherString.toLatin1(); const char *ciphers = csbuf.constData(); meth = SSLv23_server_method(); if (meth == NULL) { qWarning("MumbleSSL: unable to get SSL method"); goto out; } // We use const_cast to be compatible with OpenSSL 0.9.8. ctx = SSL_CTX_new(const_cast(meth)); if (ctx == NULL) { qWarning("MumbleSSL: unable to allocate SSL_CTX"); goto out; } if (!SSL_CTX_set_cipher_list(ctx, ciphers)) { qWarning("MumbleSSL: error parsing OpenSSL cipher string in ciphersFromOpenSSLCipherString"); goto out; } ssl = SSL_new(ctx); if (ssl == NULL) { qWarning("MumbleSSL: unable to create SSL object in ciphersFromOpenSSLCipherString"); goto out; } while (1) { const char *name = SSL_get_cipher_list(ssl, i); if (name == NULL) { break; } #if QT_VERSION >= 0x050300 QSslCipher c = QSslCipher(QString::fromLatin1(name)); if (!c.isNull()) { chosenCiphers << c; } #else foreach (const QSslCipher &c, QSslSocket::supportedCiphers()) { if (c.name() == QString::fromLatin1(name)) { chosenCiphers << c; } } #endif ++i; } out: SSL_CTX_free(ctx); SSL_free(ssl); return chosenCiphers; } void MumbleSSL::addSystemCA() { QSslSocket::addDefaultCaCertificates(QSslConfiguration::systemCaCertificates()); #ifdef Q_OS_WIN // Work around issue #1271. // Skype's click-to-call feature creates an enormous // amount of certificates in the Root CA store. { QSslConfiguration sslCfg = QSslConfiguration::defaultConfiguration(); QList caList = sslCfg.caCertificates(); QList filteredCaList; foreach (QSslCertificate cert, caList) { QStringList orgs = cert.subjectInfo(QSslCertificate::Organization); bool skip = false; foreach (QString ou, orgs) { if (ou.contains(QLatin1String("Skype"), Qt::CaseInsensitive)) { skip = true; break; } } if (skip) { continue; } filteredCaList.append(cert); } sslCfg.setCaCertificates(filteredCaList); QSslConfiguration::setDefaultConfiguration(sslCfg); qWarning("SSL: CA certificate filter applied. Filtered size: %i, original size: %i", filteredCaList.size(), caList.size()); } #endif } QString MumbleSSL::protocolToString(QSsl::SslProtocol protocol) { switch(protocol) { case QSsl::SslV3: return QLatin1String("SSL 3"); case QSsl::SslV2: return QLatin1String("SSL 2"); case QSsl::TlsV1_0: return QLatin1String("TLS 1.0"); case QSsl::TlsV1_1: return QLatin1String("TLS 1.1"); case QSsl::TlsV1_2: return QLatin1String("TLS 1.2"); #if QT_VERSION >= 0x050C00 case QSsl::TlsV1_3: return QLatin1String("TLS 1.3"); #endif case QSsl::AnyProtocol: return QLatin1String("AnyProtocol"); case QSsl::TlsV1SslV3: return QLatin1String("TlsV1SslV3"); case QSsl::SecureProtocols: return QLatin1String("SecureProtocols"); default: case QSsl::UnknownProtocol: return QLatin1String("UnknownProtocol"); } }