mumble/src/SSL.cpp
2019-10-10 03:14:38 +02:00

163 lines
4.5 KiB
C++

// 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 <https://www.mumble.info/LICENSE>.
#include "SSL.h"
#include "SSLLocks.h"
#include "Version.h"
#include <QtNetwork/QSslConfiguration>
#include <QtNetwork/QSslSocket>
#include <openssl/ssl.h>
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<QSslCipher> MumbleSSL::ciphersFromOpenSSLCipherString(QString cipherString) {
QList<QSslCipher> 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<SSL_METHOD *>(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<QSslCertificate> caList = sslCfg.caCertificates();
QList<QSslCertificate> 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");
}
}