Why is this an issue?
To establish a SSL/TLS connection not vulnerable to man-in-the-middle attacks, it’s essential to make sure the server presents the right
certificate.
The certificate’s hostname-specific data should match the server hostname.
It’s not recommended to re-invent the wheel by implementing custom hostname verification.
TLS/SSL libraries provide built-in hostname verification functions that should be used.
Noncompliant code example
libcurl
#include <curl/curl.h>
CURL *curl;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // Noncompliant
//Perform the request
curl_easy_perform(curl);
OpenSSL
#include <openssl/ssl.h>
SSL_CTX *ctx = get_ctx();
SSL *ssl = SSL_new(ctx);
// ...
// By default hostname validation is disabled
// `SSL_set1_host` is not called
SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
// ...
SSL_connect(ssl); // Noncompliant
botan
#include <botan/tls_client.h>
#include <botan/tls_callbacks.h>
#include <botan/tls_session_manager.h>
#include <botan/tls_policy.h>
#include <botan/auto_rng.h>
#include <botan/certstor.h>
#include <botan/certstor_system.h>
class Callbacks : public Botan::TLS::Callbacks
{
// ...
virtual void tls_verify_cert_chain(
const std::vector<Botan::X509_Certificate> &cert_chain,
const std::vector<std::shared_ptr<const Botan::OCSP::Response>> &ocsp_responses,
const std::vector<Botan::Certificate_Store *> &trusted_roots,
Botan::Usage_Type usage,
const std::string &hostname,
const Botan::TLS::Policy &policy) override {} // Noncompliant (secondary location), tls_verify_cert_chain never throws. Always accept server certificate and doesn't verify hostname
};
class Client_Credentials : public Botan::Credentials_Manager
{
// ...
};
Callbacks callbacks;
Botan::AutoSeeded_RNG rng;
Botan::TLS::Session_Manager_In_Memory session_mgr(rng);
Client_Credentials creds;
Botan::TLS::Strict_Policy policy;
// open the tls connection
Botan::TLS::Client client(callbacks, session_mgr, creds, policy, rng,
Botan::TLS::Server_Information("example.com", 443),
Botan::TLS::Protocol_Version::TLS_V12); // Noncompliant; uses an implementation of Botan::TLS::Callbacks that doesn't validate server hostname
Compliant solution
libcurl
#include <curl/curl.h>
CURL *curl;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); // Compliant
//Perform the request
curl_easy_perform(curl);
OpenSSL
#include <openssl/ssl.h>
SSL_CTX *ctx = get_ctx();
SSL *ssl = SSL_new(ctx);
// ...
SSL_set1_host(ssl, HOST_NAME); // Compliant
SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
// ...
SSL_connect(ssl);
botan
#include <botan/tls_client.h>
#include <botan/tls_callbacks.h>
#include <botan/tls_session_manager.h>
#include <botan/tls_policy.h>
#include <botan/auto_rng.h>
#include <botan/certstor.h>
#include <botan/certstor_system.h>
// Compliant use the default implementation of tls_verify_cert_chain method which verify server certificate and hostname
class Callbacks : public Botan::TLS::Callbacks
{
// ...
};
class Client_Credentials : public Botan::Credentials_Manager
{
// ...
};
Callbacks callbacks;
Botan::AutoSeeded_RNG rng;
Botan::TLS::Session_Manager_In_Memory session_mgr(rng);
Client_Credentials creds;
Botan::TLS::Strict_Policy policy;
// open the tls connection
Botan::TLS::Client client(callbacks, session_mgr, creds, policy, rng,
Botan::TLS::Server_Information("example.com", 443),
Botan::TLS::Protocol_Version::TLS_V12); // Compliant; uses an implementation of Botan::TLS::Callbacks that validate server hostname
Resources