mirror of
https://github.com/debauchee/barrier.git
synced 2026-05-11 00:58:14 +08:00
Implement client identity verification
This commit fixes two security vulnerabilities: CVE-2021-42072 and CVE-2021-42073. The issues have been reported by Matthias Gerstner <mgerstner@suse.de>.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -148,7 +148,10 @@ ServerApp::help()
|
||||
<< "Options:\n"
|
||||
<< " -a, --address <address> listen for clients on the given address.\n"
|
||||
<< " -c, --config <pathname> use the named configuration file instead.\n"
|
||||
<< HELP_COMMON_INFO_1 << WINAPI_INFO << HELP_SYS_INFO << HELP_COMMON_INFO_2 << "\n"
|
||||
<< HELP_COMMON_INFO_1
|
||||
<< " --disable-client-cert-checking disable client SSL certificate \n"
|
||||
" checking (deprecated)\n"
|
||||
<< WINAPI_INFO << HELP_SYS_INFO << HELP_COMMON_INFO_2 << "\n"
|
||||
<< "Default options are marked with a *\n"
|
||||
<< "\n"
|
||||
<< "The argument for --address is of the form: [<hostname>][:<port>]. The\n"
|
||||
@@ -658,6 +661,9 @@ ServerApp::openClientListener(const NetworkAddress& address)
|
||||
auto security_level = ConnectionSecurityLevel::PLAINTEXT;
|
||||
if (args().m_enableCrypto) {
|
||||
security_level = ConnectionSecurityLevel::ENCRYPTED;
|
||||
if (args().check_client_certificates) {
|
||||
security_level = ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED;
|
||||
}
|
||||
}
|
||||
|
||||
ClientListener* listen = new ClientListener(
|
||||
|
||||
@@ -30,4 +30,5 @@ public:
|
||||
String m_configFile;
|
||||
Config* m_config;
|
||||
String m_screenChangeScript;
|
||||
bool check_client_certificates = true;
|
||||
};
|
||||
|
||||
@@ -129,7 +129,8 @@ Client::connect()
|
||||
|
||||
auto security_level = ConnectionSecurityLevel::PLAINTEXT;
|
||||
if (m_useSecureNetwork) {
|
||||
security_level = ConnectionSecurityLevel::ENCRYPTED;
|
||||
// client always authenticates server
|
||||
security_level = ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED;
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
enum class ConnectionSecurityLevel {
|
||||
PLAINTEXT,
|
||||
ENCRYPTED,
|
||||
ENCRYPTED_AUTHENTICATED
|
||||
};
|
||||
|
||||
#endif // BARRIER_LIB_NET_CONNECTION_SECURITY_LEVEL_H
|
||||
|
||||
@@ -361,6 +361,11 @@ bool SecureSocket::load_certificates(const barrier::fs::path& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
static int cert_verify_ignore_callback(X509_STORE_CTX*, void*)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
SecureSocket::initContext(bool server)
|
||||
{
|
||||
@@ -396,6 +401,14 @@ SecureSocket::initContext(bool server)
|
||||
if (m_ssl->m_context == NULL) {
|
||||
showError("");
|
||||
}
|
||||
|
||||
if (security_level_ == ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED) {
|
||||
// We want to ask for peer certificate, but not verify it. If we don't ask for peer
|
||||
// certificate, e.g. client won't send it.
|
||||
SSL_CTX_set_verify(m_ssl->m_context, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
|
||||
nullptr);
|
||||
SSL_CTX_set_cert_verify_callback(m_ssl->m_context, cert_verify_ignore_callback, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -436,6 +449,24 @@ SecureSocket::secureAccept(int socket)
|
||||
|
||||
// If not fatal and no retry, state is good
|
||||
if (retry == 0) {
|
||||
if (security_level_ == ConnectionSecurityLevel::ENCRYPTED_AUTHENTICATED) {
|
||||
if (verify_cert_fingerprint(
|
||||
barrier::DataDirectories::trusted_clients_ssl_fingerprints_path())) {
|
||||
LOG((CLOG_INFO "accepted secure socket"));
|
||||
if (!ensure_peer_certificate()) {
|
||||
retry = 0;
|
||||
disconnect();
|
||||
return -1;// Cert fail, error
|
||||
}
|
||||
}
|
||||
else {
|
||||
LOG((CLOG_ERR "failed to verify server certificate fingerprint"));
|
||||
retry = 0;
|
||||
disconnect();
|
||||
return -1; // Fingerprint failed, error
|
||||
}
|
||||
}
|
||||
|
||||
m_secureReady = true;
|
||||
LOG((CLOG_INFO "accepted secure socket"));
|
||||
if (CLOG->getFilter() >= kDEBUG1) {
|
||||
@@ -670,7 +701,7 @@ bool SecureSocket::verify_cert_fingerprint(const barrier::fs::path& fingerprint_
|
||||
}
|
||||
|
||||
// note: the GUI parses the following two lines of logs, don't change unnecessarily
|
||||
LOG((CLOG_NOTE "server fingerprint (SHA1): %s (SHA256): %s",
|
||||
LOG((CLOG_NOTE "peer fingerprint (SHA1): %s (SHA256): %s",
|
||||
barrier::format_ssl_fingerprint(fingerprint_sha1.data).c_str(),
|
||||
barrier::format_ssl_fingerprint(fingerprint_sha256.data).c_str()));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user