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
|
#include "biboumi.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 <botan/data_src.h>
#include <config/config.hpp>
/**
* 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():
Botan::Credentials_Manager(),
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,
const 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);
}
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(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 negotiation will probably fail.");
}
std::vector<Botan::Certificate_Store*> BasicCredentialsManager::trusted_certificate_authorities(const std::string&, const std::string&)
{
return {&this->certificate_store};
}
#endif
|