diff --git a/doc/newsfragments/client-certificate-checking.bugfix b/doc/newsfragments/client-certificate-checking.bugfix new file mode 100644 index 00000000..01d4d03d --- /dev/null +++ b/doc/newsfragments/client-certificate-checking.bugfix @@ -0,0 +1,7 @@ +SECURITY ISSUE + +Barrier now supports client identity verification (fixes CVE-2021-42072, CVE-2021-42073). + +To support seamless upgrades from older versions of Barrier this is currently disabled by default. +The feature can be enabled in the settings dialog. If enabled, older clients of Barrier will be +rejected. diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 7d4a9a5e..2172507b 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -427,7 +427,7 @@ void MainWindow::checkConnected(const QString& line) void MainWindow::checkFingerprint(const QString& line) { - QRegExp fingerprintRegex(".*server fingerprint \\(SHA1\\): ([A-F0-9:]+) \\(SHA256\\): ([A-F0-9:]+)"); + QRegExp fingerprintRegex(".*peer fingerprint \\(SHA1\\): ([A-F0-9:]+) \\(SHA256\\): ([A-F0-9:]+)"); if (!fingerprintRegex.exactMatch(line)) { return; } @@ -442,7 +442,11 @@ void MainWindow::checkFingerprint(const QString& line) barrier::string::from_hex(fingerprintRegex.cap(2).toStdString()) }; - auto db_path = barrier::DataDirectories::trusted_servers_ssl_fingerprints_path(); + bool is_client = barrierType() == barrierClient; + + auto db_path = is_client + ? barrier::DataDirectories::trusted_servers_ssl_fingerprints_path() + : barrier::DataDirectories::trusted_clients_ssl_fingerprints_path(); auto db_dir = db_path.parent_path(); if (!barrier::fs::exists(db_dir)) { @@ -461,17 +465,17 @@ void MainWindow::checkFingerprint(const QString& line) static bool messageBoxAlreadyShown = false; if (!messageBoxAlreadyShown) { - stopBarrier(); + if (is_client) { + stopBarrier(); + } - messageBoxAlreadyShown = true; - QMessageBox::StandardButton fingerprintReply = - QMessageBox::information( - this, tr("Security question"), - tr("Do you trust this fingerprint?\n\n" + QString message; + if (is_client) { + message = tr("Do you trust this fingerprint?\n\n" "SHA256:\n" "%1\n" "%2\n\n" - "SHA1 (obsolete, when using old Barrier server):\n" + "SHA1 (obsolete, when using old Barrier client):\n" "%3\n\n" "This is a server fingerprint. You should compare this " "fingerprint to the one on your server's screen. If the " @@ -483,14 +487,38 @@ void MainWindow::checkFingerprint(const QString& line) .arg(QString::fromStdString(barrier::format_ssl_fingerprint(fingerprint_sha256.data))) .arg(QString::fromStdString( barrier::create_fingerprint_randomart(fingerprint_sha256.data))) - .arg(QString::fromStdString(barrier::format_ssl_fingerprint(fingerprint_sha1.data))), + .arg(QString::fromStdString(barrier::format_ssl_fingerprint(fingerprint_sha1.data))); + } else { + message = tr("Do you trust this fingerprint?\n\n" + "SHA256:\n" + "%1\n" + "%2\n\n" + "This is a client fingerprint. You should compare this " + "fingerprint to the one on your client's screen. If the " + "two don't match exactly, then it's probably not the client " + "you're expecting (it could be a malicious user).\n\n" + "To automatically trust this fingerprint for future " + "connections, click Yes. To reject this fingerprint and " + "disconnect the client, click No.") + .arg(QString::fromStdString(barrier::format_ssl_fingerprint(fingerprint_sha256.data))) + .arg(QString::fromStdString( + barrier::create_fingerprint_randomart(fingerprint_sha256.data))); + } + + messageBoxAlreadyShown = true; + QMessageBox::StandardButton fingerprintReply = + QMessageBox::information( + this, tr("Security question"), + message, QMessageBox::Yes | QMessageBox::No); if (fingerprintReply == QMessageBox::Yes) { // restart core process after trusting fingerprint. db.add_trusted(fingerprint_sha256); db.write(db_path); - startBarrier(); + if (is_client) { + startBarrier(); + } } messageBoxAlreadyShown = false; @@ -734,6 +762,10 @@ bool MainWindow::serverArgs(QStringList& args, QString& app) args << "--log" << appConfig().logFilenameCmd(); } + if (!appConfig().getRequireClientCertificate()) { + args << "--disable-client-cert-checking"; + } + QString configFilename = this->configFilename(); #if defined(Q_OS_WIN) // wrap in quotes in case username contains spaces. diff --git a/src/lib/barrier/ArgParser.cpp b/src/lib/barrier/ArgParser.cpp index 44e29491..99cd803b 100644 --- a/src/lib/barrier/ArgParser.cpp +++ b/src/lib/barrier/ArgParser.cpp @@ -65,7 +65,9 @@ ArgParser::parseServerArgs(ServerArgs& args, int argc, const char* const* argv) // save screen change script path args.m_screenChangeScript = argv[++i]; } - else { + else if (isArg(i, argc, argv, nullptr, "--disable-client-cert-checking")) { + args.check_client_certificates = false; + } else { LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_exename.c_str(), argv[i], args.m_exename.c_str())); return false; } diff --git a/src/lib/barrier/ServerApp.cpp b/src/lib/barrier/ServerApp.cpp index 8870e0de..4810b8a5 100644 --- a/src/lib/barrier/ServerApp.cpp +++ b/src/lib/barrier/ServerApp.cpp @@ -148,7 +148,10 @@ ServerApp::help() << "Options:\n" << " -a, --address
listen for clients on the given address.\n" << " -c, --config