Skip to content

Commit 73fb8d4

Browse files
authored
Drop Botan 2 support and support Botan 3 (#262)
1 parent 31cb406 commit 73fb8d4

File tree

4 files changed

+103
-108
lines changed

4 files changed

+103
-108
lines changed

.github/workflows/cmake.yml

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,6 @@ jobs:
6767
buildname: 'ubuntu-20.04/gcc'
6868
triplet: x64-linux
6969
compiler: gcc_64
70-
- os: ubuntu-22.04
71-
buildname: 'ubuntu-22.04/gcc - Botan'
72-
triplet: x64-linux
73-
compiler: gcc_64
7470
- os: macos-latest
7571
buildname: 'macos/clang'
7672
triplet: x64-osx
@@ -94,12 +90,6 @@ jobs:
9490
# Installing packages might fail as the github image becomes outdated
9591
sudo apt update
9692
sudo apt install openssl libssl-dev dos2unix
97-
- name: (Linux) Install dependencies - Botan
98-
if: matrix.buildname == 'ubuntu-22.04/gcc - Botan'
99-
run: |
100-
# Installing packages might fail as the github image becomes outdated
101-
sudo apt update
102-
sudo apt install libbotan-2-dev dos2unix
10393
- name: (Linux) Install dependencies
10494
if: matrix.buildname == 'ubuntu-20.04/gcc'
10595
run: |
@@ -120,21 +110,11 @@ jobs:
120110
# We'll use this as our working directory for all subsequent commands
121111
shell: bash
122112
working-directory: ${{env.GITHUB_WORKSPACE}}
123-
if: matrix.buildname != 'ubuntu-22.04/gcc - Botan'
124113
run: |
125114
mkdir build
126115
cd build
127116
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_TESTING=on
128117
129-
- name: Create Build Environment & Configure Cmake (Botan)
130-
shell: bash
131-
working-directory: ${{env.GITHUB_WORKSPACE}}
132-
if: matrix.buildname == 'ubuntu-22.04/gcc - Botan'
133-
run: |
134-
mkdir build
135-
cd build
136-
cmake .. -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_TESTING=on -DTRANTOR_USE_TLS="botan"
137-
138118
- name: Build
139119
working-directory: ${{env.GITHUB_WORKSPACE}}
140120
shell: bash

cmake_modules/FindBotan.cmake

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,28 @@
1+
function(find_botan_pkgconfig package_name botan_ver)
2+
if (TARGET Botan::Botan)
3+
return()
4+
endif ()
15

2-
find_package(PkgConfig)
3-
if(NOT WIN32 AND PKG_CONFIG_FOUND)
4-
if (NOT TARGET Botan::Botan)
5-
pkg_check_modules(Botan QUIET IMPORTED_TARGET botan-2)
6-
if (TARGET PkgConfig::Botan)
7-
add_library(Botan::Botan ALIAS PkgConfig::Botan)
8-
endif ()
9-
endif()
10-
endif()
6+
pkg_check_modules(Botan QUIET IMPORTED_TARGET ${package_name})
7+
if (TARGET PkgConfig::Botan)
8+
add_library(Botan::Botan ALIAS PkgConfig::Botan)
9+
10+
if(botan_ver EQUAL 3)
11+
target_compile_features(PkgConfig::Botan INTERFACE cxx_std_20)
12+
endif()
13+
endif ()
14+
endfunction()
1115

12-
if (NOT TARGET Botan::Botan)
16+
function(find_botan_search package_name botan_ver)
17+
if (TARGET Botan::Botan)
18+
return()
19+
endif ()
1320
find_path(Botan_INCLUDE_DIRS NAMES botan/botan.h
14-
PATH_SUFFIXES botan-2
21+
PATH_SUFFIXES ${package_name}
1522
DOC "The Botan include directory")
1623

17-
find_library(Botan_LIBRARIES NAMES botan botan-2
18-
DOC "The Botan library")
24+
find_library(Botan_LIBRARIES NAMES botan ${package_name}
25+
DOC "The Botan library")
1926

2027
mark_as_advanced(Botan_INCLUDE_DIRS Botan_LIBRARIES)
2128

@@ -26,11 +33,26 @@ if (NOT TARGET Botan::Botan)
2633
IMPORTED_LOCATION "${Botan_LIBRARIES}"
2734
INTERFACE_INCLUDE_DIRECTORIES "${Botan_INCLUDE_DIRS}"
2835
)
36+
if(botan_ver EQUAL 3)
37+
target_compile_features(Botan::Botan INTERFACE cxx_std_20)
38+
endif()
2939

3040
if (WIN32)
3141
target_compile_definitions(Botan::Botan INTERFACE -DNOMINMAX=1)
3242
endif ()
33-
endif ()
43+
endfunction()
44+
45+
46+
find_package(PkgConfig)
47+
if(NOT WIN32 AND PKG_CONFIG_FOUND)
48+
# find_botan_pkgconfig(botan-2 2)
49+
find_botan_pkgconfig(botan-3 3)
50+
endif()
51+
52+
if(NOT TARGET Botan::Botan)
53+
# find_botan_search(botan-2 2)
54+
find_botan_search(botan-3 3)
55+
endif()
3456

3557
include(FindPackageHandleStandardArgs)
3658
find_package_handle_standard_args(

trantor/net/inner/tlsprovider/BotanTLSProvider.cc

Lines changed: 59 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,23 @@
1717
#include <botan/pkix_types.h>
1818
#include <botan/certstor_flatfile.h>
1919
#include <botan/x509path.h>
20+
#include <botan/tls_session_manager_memory.h>
2021

2122
using namespace trantor;
2223
using namespace std::placeholders;
2324

24-
static Botan::System_RNG sessionManagerRng;
25-
// Is this Ok? C++ technically doesn't guarantee static object initialization
26-
// order.
27-
static Botan::TLS::Session_Manager_In_Memory sessionManager(sessionManagerRng);
28-
static thread_local Botan::System_RNG rng;
25+
static std::once_flag sessionManagerInitFlag;
26+
static std::shared_ptr<Botan::AutoSeeded_RNG> sessionManagerRng;
27+
static std::shared_ptr<Botan::TLS::Session_Manager_In_Memory> sessionManager;
28+
static thread_local std::shared_ptr<Botan::AutoSeeded_RNG> rng;
2929
static Botan::System_Certificate_Store certStore;
3030

3131
using namespace trantor;
3232

3333
class Credentials : public Botan::Credentials_Manager
3434
{
3535
public:
36-
Credentials(Botan::Private_Key *key,
36+
Credentials(std::shared_ptr<Botan::Private_Key> key,
3737
Botan::X509_Certificate *cert,
3838
Botan::Certificate_Store *certStore)
3939
: certStore_(certStore), cert_(cert), key_(key)
@@ -50,28 +50,33 @@ class Credentials : public Botan::Credentials_Manager
5050
return {certStore_};
5151
}
5252

53-
std::vector<Botan::X509_Certificate> cert_chain(
53+
std::vector<Botan::X509_Certificate> find_cert_chain(
5454
const std::vector<std::string> &cert_key_types,
55+
const std::vector<Botan::AlgorithmIdentifier> &cert_signature_schemes,
56+
const std::vector<Botan::X509_DN> &acceptable_CAs,
5557
const std::string &type,
5658
const std::string &context) override
5759
{
5860
(void)type;
5961
(void)context;
62+
(void)cert_signature_schemes;
63+
(void)acceptable_CAs;
6064
if (cert_ == nullptr)
6165
return {};
6266

6367
auto key_algo =
64-
cert_->subject_public_key_algo().get_oid().to_formatted_string();
68+
cert_->subject_public_key_algo().oid().to_formatted_string();
6569
auto it =
6670
std::find(cert_key_types.begin(), cert_key_types.end(), key_algo);
6771
if (it == cert_key_types.end())
6872
return {};
6973
return {*cert_};
7074
}
7175

72-
Botan::Private_Key *private_key_for(const Botan::X509_Certificate &cert,
73-
const std::string &type,
74-
const std::string &context) override
76+
std::shared_ptr<Botan::Private_Key> private_key_for(
77+
const Botan::X509_Certificate &cert,
78+
const std::string &type,
79+
const std::string &context) override
7580
{
7681
(void)cert;
7782
(void)type;
@@ -80,7 +85,7 @@ class Credentials : public Botan::Credentials_Manager
8085
}
8186
Botan::Certificate_Store *certStore_ = nullptr;
8287
Botan::X509_Certificate *cert_ = nullptr;
83-
Botan::Private_Key *key_ = nullptr;
88+
std::shared_ptr<Botan::Private_Key> key_ = nullptr;
8489
};
8590

8691
struct BotanCertificate : public Certificate
@@ -110,7 +115,7 @@ namespace trantor
110115
{
111116
struct SSLContext
112117
{
113-
std::unique_ptr<Botan::Private_Key> key;
118+
std::shared_ptr<Botan::Private_Key> key;
114119
std::unique_ptr<Botan::X509_Certificate> cert;
115120
std::shared_ptr<Botan::Certificate_Store> certStore;
116121
bool isServer = false;
@@ -136,14 +141,16 @@ class TrantorPolicy : public Botan::TLS::Policy
136141

137142
struct BotanTLSProvider : public TLSProvider,
138143
public NonCopyable,
139-
public Botan::TLS::Callbacks
144+
public Botan::TLS::Callbacks,
145+
public std::enable_shared_from_this<BotanTLSProvider>
140146
{
141147
public:
142148
BotanTLSProvider(TcpConnection *conn,
143149
TLSPolicyPtr policy,
144150
SSLContextPtr ctx)
145151
: TLSProvider(conn, std::move(policy), std::move(ctx))
146152
{
153+
validationPolicy_ = std::make_shared<TrantorPolicy>();
147154
}
148155

149156
virtual void recvData(MsgBuffer *buffer) override
@@ -163,7 +170,7 @@ struct BotanTLSProvider : public TLSProvider,
163170

164171
if (tlsConnected_ == false)
165172
{
166-
if (e.type() == Botan::TLS::Alert::BAD_CERTIFICATE)
173+
if (e.type() == Botan::TLS::Alert::BadCertificate)
167174
handleSSLError(SSLError::kSSLInvalidCertificate);
168175
else
169176
handleSSLError(SSLError::kSSLHandshakeError);
@@ -226,31 +233,44 @@ struct BotanTLSProvider : public TLSProvider,
226233

227234
virtual void startEncryption() override
228235
{
229-
credsPtr_ = std::make_unique<Credentials>(contextPtr_->key.get(),
236+
credsPtr_ = std::make_shared<Credentials>(contextPtr_->key,
230237
contextPtr_->cert.get(),
231238
contextPtr_->certStore.get());
232239
if (policyPtr_->getConfCmds().empty() == false)
233240
LOG_WARN << "BotanTLSConnectionImpl does not support sslConfCmds.";
241+
242+
// initialize rng and session manager if we haven't already
243+
std::call_once(sessionManagerInitFlag, []() {
244+
sessionManagerRng = std::make_shared<Botan::AutoSeeded_RNG>();
245+
sessionManager =
246+
std::make_shared<Botan::TLS::Session_Manager_In_Memory>(
247+
sessionManagerRng);
248+
});
249+
if (rng == nullptr)
250+
rng = std::make_shared<Botan::AutoSeeded_RNG>();
234251
if (contextPtr_->isServer)
235252
{
236253
// TODO: Need a more scalable way to manage session validation rules
237-
validationPolicy_.requireClientCert_ =
254+
validationPolicy_->requireClientCert_ =
238255
contextPtr_->requireClientCert;
239-
channel_ = std::make_unique<Botan::TLS::Server>(
240-
*this, sessionManager, *credsPtr_, validationPolicy_, rng);
256+
channel_ = std::make_unique<Botan::TLS::Server>(shared_from_this(),
257+
sessionManager,
258+
credsPtr_,
259+
validationPolicy_,
260+
rng);
241261
}
242262
else
243263
{
244-
validationPolicy_.requireClientCert_ =
264+
validationPolicy_->requireClientCert_ =
245265
contextPtr_->requireClientCert;
246266
// technically Botan2 does support TLS 1.0 and 1.1, but Botan3 does
247267
// not. So we just disable them to keep compatibility.
248268
if (policyPtr_->getUseOldTLS())
249269
LOG_WARN << "Old TLS not supported by Botan (only >= TLS 1.2)";
250270
channel_ = std::make_unique<Botan::TLS::Client>(
251-
*this,
271+
shared_from_this(),
252272
sessionManager,
253-
*credsPtr_,
273+
credsPtr_,
254274
validationPolicy_,
255275
rng,
256276
Botan::TLS::Server_Information(policyPtr_->getHostname(),
@@ -270,32 +290,32 @@ struct BotanTLSProvider : public TLSProvider,
270290

271291
virtual ~BotanTLSProvider() override = default;
272292

273-
void tls_emit_data(const uint8_t data[], size_t size) override
293+
void tls_emit_data(std::span<const uint8_t> data) override
274294
{
275-
auto n = writeCallback_(conn_, data, size);
295+
auto n = writeCallback_(conn_, data.data(), data.size_bytes());
276296
lastWriteSize_ = n;
277297

278298
// store the unsent data and send it later
279-
if (n == ssize_t(size))
299+
if (n == ssize_t(data.size_bytes()))
280300
return;
281301
if (n == -1)
282302
n = 0;
283-
appendToWriteBuffer((const char *)data + n, size - n);
303+
appendToWriteBuffer((const char *)data.data() + n,
304+
data.size_bytes() - n);
284305
}
285306

286307
void tls_record_received(uint64_t seq_no,
287-
const uint8_t data[],
288-
size_t size) override
308+
std::span<const uint8_t> data) override
289309
{
290310
(void)seq_no;
291-
recvBuffer_.append((const char *)data, size);
311+
recvBuffer_.append((const char *)data.data(), data.size_bytes());
292312
if (messageCallback_)
293313
messageCallback_(conn_, &recvBuffer_);
294314
}
295315

296316
void tls_alert(Botan::TLS::Alert alert) override
297317
{
298-
if (alert.type() == Botan::TLS::Alert::CLOSE_NOTIFY)
318+
if (alert.type() == Botan::TLS::Alert::CloseNotify)
299319
{
300320
LOG_TRACE << "TLS close notify received";
301321
if (closeCallback_)
@@ -324,7 +344,7 @@ struct BotanTLSProvider : public TLSProvider,
324344

325345
void tls_verify_cert_chain(
326346
const std::vector<Botan::X509_Certificate> &certs,
327-
const std::vector<std::shared_ptr<const Botan::OCSP::Response>> &ocsp,
347+
const std::vector<std::optional<Botan::OCSP::Response>> &ocsp,
328348
const std::vector<Botan::Certificate_Store *> &trusted_roots,
329349
Botan::Usage_Type usage,
330350
const std::string &hostname,
@@ -338,38 +358,31 @@ struct BotanTLSProvider : public TLSProvider,
338358
{
339359
if (certs.size() == 0)
340360
throw Botan::TLS::TLS_Exception(
341-
Botan::TLS::Alert::NO_CERTIFICATE,
361+
Botan::TLS::Alert::NoCertificate,
342362
"Certificate validation failed: no certificate");
343363
// handle self-signed certificate
344-
std::vector<std::shared_ptr<const Botan::X509_Certificate>>
345-
selfSigned = {
346-
std::make_shared<Botan::X509_Certificate>(certs[0])};
364+
std::vector<Botan::X509_Certificate> selfSigned = {certs[0]};
347365

348366
Botan::Path_Validation_Restrictions restrictions(
349367
false, // require revocation
350-
validationPolicy_.minimum_signature_strength());
368+
validationPolicy_->minimum_signature_strength());
351369

352370
auto now = std::chrono::system_clock::now();
353-
const auto status =
354-
Botan::PKIX::check_chain(selfSigned,
355-
now,
356-
hostname,
357-
usage,
358-
restrictions.minimum_key_strength(),
359-
restrictions.trusted_hashes());
371+
const auto status = Botan::PKIX::check_chain(
372+
selfSigned, now, hostname, usage, restrictions);
360373

361374
const auto result = Botan::PKIX::overall_status(status);
362375

363376
if (result != Botan::Certificate_Status_Code::OK)
364377
throw Botan::TLS::TLS_Exception(
365-
Botan::TLS::Alert::BAD_CERTIFICATE,
378+
Botan::TLS::Alert::BadCertificate,
366379
std::string("Certificate validation failed: ") +
367380
Botan::to_string(result));
368381
}
369382
}
370383

371-
TrantorPolicy validationPolicy_;
372-
std::unique_ptr<Botan::Credentials_Manager> credsPtr_;
384+
std::shared_ptr<TrantorPolicy> validationPolicy_;
385+
std::shared_ptr<Botan::Credentials_Manager> credsPtr_;
373386
std::unique_ptr<Botan::TLS::Channel> channel_;
374387
bool tlsConnected_ = false;
375388
ssize_t lastWriteSize_ = 0;

0 commit comments

Comments
 (0)