credentials_manager.cpp 3.61 KB
Newer Older
louiz’'s avatar
louiz’ committed
1
#include "biboumi.h"
2 3

#ifdef BOTAN_FOUND
4
#include <network/tcp_socket_handler.hpp>
5 6
#include <network/credentials_manager.hpp>
#include <logger/logger.hpp>
7
#include <botan/tls_exceptn.h>
8
#include <botan/data_src.h>
louiz’'s avatar
louiz’ committed
9
#include <config/config.hpp>
10

louiz’'s avatar
louiz’ committed
11 12 13 14 15 16 17 18 19 20
/**
 * TODO find a standard way to find that out.
 */
static const std::vector<std::string> default_cert_files = {
    "/etc/ssl/certs/ca-bundle.crt",
    "/etc/pki/tls/certs/ca-bundle.crt",
    "/etc/ssl/certs/ca-certificates.crt",
    "/etc/ca-certificates/extracted/tls-ca-bundle.pem"
};

louiz’'s avatar
louiz’ committed
21 22
Botan::Certificate_Store_In_Memory BasicCredentialsManager::certificate_store;
bool BasicCredentialsManager::certs_loaded = false;
23

louiz’'s avatar
louiz’ committed
24
BasicCredentialsManager::BasicCredentialsManager(const TCPSocketHandler* const socket_handler):
25
    Botan::Credentials_Manager(),
26 27
    socket_handler(socket_handler),
    trusted_fingerprint{}
28
{
louiz’'s avatar
louiz’ committed
29
  BasicCredentialsManager::load_certs();
30
}
31

louiz’'s avatar
louiz’ committed
32
void BasicCredentialsManager::set_trusted_fingerprint(const std::string& fingerprint)
33 34 35 36
{
  this->trusted_fingerprint = fingerprint;
}

37 38 39 40 41 42 43
const std::string& BasicCredentialsManager::get_trusted_fingerprint() const
{
  return this->trusted_fingerprint;
}

void check_tls_certificate(const std::vector<Botan::X509_Certificate>& certs,
                           const std::string& hostname, const std::string& trusted_fingerprint,
44
                           const std::exception_ptr& exc)
45 46 47 48 49 50 51 52 53 54 55 56 57
{

  if (!trusted_fingerprint.empty() && !certs.empty() &&
      trusted_fingerprint == certs[0].fingerprint() &&
      certs[0].matches_dns_name(hostname))
    // We trust the certificate, based on the trusted fingerprint and
    // the fact that the hostname matches
    return;

  if (exc)
    std::rethrow_exception(exc);
}

louiz’'s avatar
louiz’ committed
58
bool BasicCredentialsManager::try_to_open_one_ca_bundle(const std::vector<std::string>& paths)
59 60 61
{
  for (const auto& path: paths)
    {
louiz’'s avatar
louiz’ committed
62 63 64
      try
        {
          Botan::DataSource_Stream bundle(path);
65
          log_debug("Using ca bundle: ", path);
louiz’'s avatar
louiz’ committed
66 67
          while (!bundle.end_of_data() && bundle.check_available(27))
            {
68 69 70 71 72 73
              // TODO: remove this work-around for Botan 1.11.29
              // https://github.com/randombit/botan/issues/438#issuecomment-192866796
              // Note that every certificate that fails to be transcoded into latin-1
              // will be ignored. As a result, some TLS connection may be refused
              // because the certificate is signed by an issuer that was ignored.
              try {
louiz’'s avatar
louiz’ committed
74
                  Botan::X509_Certificate cert(bundle);
75
                  BasicCredentialsManager::certificate_store.add_certificate(cert);
louiz’'s avatar
louiz’ committed
76
                } catch (const Botan::Decoding_Error& error) {
77 78
                  continue;
                }
louiz’'s avatar
louiz’ committed
79 80
            }
          // Only use the first file that can successfully be read.
louiz’'s avatar
louiz’ committed
81
          return true;
louiz’'s avatar
louiz’ committed
82
        }
louiz’'s avatar
louiz’ committed
83
      catch (const Botan::Stream_IO_Error& e)
84
        {
louiz’'s avatar
louiz’ committed
85
          log_debug(e.what());
86 87
        }
    }
louiz’'s avatar
louiz’ committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
  return false;
}

void BasicCredentialsManager::load_certs()
{
  //  Only load the certificates the first time
  if (BasicCredentialsManager::certs_loaded)
    return;
  const std::string conf_path = Config::get("ca_file", "");
  std::vector<std::string> paths;
  if (conf_path.empty())
    paths = default_cert_files;
  else
    paths.push_back(conf_path);

  if (BasicCredentialsManager::try_to_open_one_ca_bundle(paths))
    BasicCredentialsManager::certs_loaded = true;
  else
    log_warning("The CA could not be loaded, TLS negociation will probably fail.");
107
}
108

louiz’'s avatar
louiz’ committed
109
std::vector<Botan::Certificate_Store*> BasicCredentialsManager::trusted_certificate_authorities(const std::string&, const std::string&)
110 111 112
{
  return {&this->certificate_store};
}
113 114

#endif