~singpolyma/biboumi

ref: 7784c568432231c737c789b065af6b81e038c54d biboumi/louloulibs/network/credentials_manager.cpp -rw-r--r-- 4.6 KiB
7784c568 — louiz’ Update the verify_certificate_chain code to work with botan >= 1.11.34 as well 6 years ago
                                                                                
06db9b36 Florent Le Coz
e8386bd1 Florent Le Coz
f928f762 Florent Le Coz
06db9b36 Florent Le Coz
5ce9d3f1 Florent Le Coz
f928f762 Florent Le Coz
e8386bd1 Florent Le Coz
5ce9d3f1 Florent Le Coz
a13285d0 Florent Le Coz
e8386bd1 Florent Le Coz
a13285d0 Florent Le Coz
e8386bd1 Florent Le Coz
1f8333f2 Florent Le Coz
f928f762 Florent Le Coz
f50f5065 louiz’
f928f762 Florent Le Coz
e8386bd1 Florent Le Coz
a13285d0 Florent Le Coz
1f8333f2 Florent Le Coz
7784c568 louiz’
a13285d0 Florent Le Coz
f928f762 Florent Le Coz
5a2e6116 louiz’
e8386bd1 Florent Le Coz
5a2e6116 louiz’
7784c568 louiz’
e8386bd1 Florent Le Coz
7784c568 louiz’
e8386bd1 Florent Le Coz
f928f762 Florent Le Coz
7784c568 louiz’
e8386bd1 Florent Le Coz
f50f5065 louiz’
f928f762 Florent Le Coz
5ce9d3f1 Florent Le Coz
5a2e6116 louiz’
5ce9d3f1 Florent Le Coz
73ad709d louiz’
f50f5065 louiz’
73ad709d louiz’
5ce9d3f1 Florent Le Coz
f50f5065 louiz’
5ce9d3f1 Florent Le Coz
f50f5065 louiz’
f928f762 Florent Le Coz
5ce9d3f1 Florent Le Coz
f928f762 Florent Le Coz
f50f5065 louiz’
f928f762 Florent Le Coz
e8386bd1 Florent Le Coz
a13285d0 Florent Le Coz
f928f762 Florent Le Coz
06db9b36 Florent Le Coz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "louloulibs.h"

#ifdef BOTAN_FOUND
#include <network/tcp_socket_handler.hpp>
#include <network/credentials_manager.hpp>
#include <logger/logger.hpp>
#include <botan/tls_exceptn.h>
#include <config/config.hpp>

#ifdef USE_DATABASE
# include <database/database.hpp>
#endif

/**
 * 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"
};

Botan::Certificate_Store_In_Memory BasicCredentialsManager::certificate_store;
bool BasicCredentialsManager::certs_loaded = false;

BasicCredentialsManager::BasicCredentialsManager(const TCPSocketHandler* const socket_handler):
    Botan::Credentials_Manager(),
    socket_handler(socket_handler),
    trusted_fingerprint{}
{
  BasicCredentialsManager::load_certs();
}

void BasicCredentialsManager::set_trusted_fingerprint(const std::string& fingerprint)
{
  this->trusted_fingerprint = fingerprint;
}

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,
                           std::exception_ptr exc)
{

  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);
}

#if BOTAN_VERSION_CODE < BOTAN_VERSION_CODE_FOR(1,11,34)
void BasicCredentialsManager::verify_certificate_chain(const std::string& type,
                                                       const std::string& purported_hostname,
                                                       const std::vector<Botan::X509_Certificate>& certs)
{
  log_debug("Checking remote certificate (", type, ") for hostname ", purported_hostname);
  try
    {
      Botan::Credentials_Manager::verify_certificate_chain(type, purported_hostname, certs);
      log_debug("Certificate is valid");
    }
  catch (const std::exception& tls_exception)
    {
      log_warning("TLS certificate check failed: ", tls_exception.what());
      std::exception_ptr exception_ptr{};
      if (this->socket_handler->abort_on_invalid_cert())
        exception_ptr = std::current_exception();

      check_tls_certificate(certs, purported_hostname, this->trusted_fingerprint, exception_ptr);
    }
}
#endif

bool BasicCredentialsManager::try_to_open_one_ca_bundle(const std::vector<std::string>& paths)
{
  for (const auto& path: paths)
    {
      try
        {
          Botan::DataSource_Stream bundle(path);
          log_debug("Using ca bundle: ", path);
          while (!bundle.end_of_data() && bundle.check_available(27))
            {
              // 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 {
                  Botan::X509_Certificate cert(bundle);
                  BasicCredentialsManager::certificate_store.add_certificate(std::move(cert));
                } catch (const Botan::Decoding_Error& error) {
                  continue;
                }
            }
          // Only use the first file that can successfully be read.
          return true;
        }
      catch (const Botan::Stream_IO_Error& e)
        {
          log_debug(e.what());
        }
    }
  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.");
}

std::vector<Botan::Certificate_Store*> BasicCredentialsManager::trusted_certificate_authorities(const std::string&, const std::string&)
{
  return {&this->certificate_store};
}

#endif