summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrancis Dupont <fdupont@isc.org>2024-08-30 11:34:23 +0200
committerFrancis Dupont <fdupont@isc.org>2024-10-11 15:20:20 +0200
commit78737d8786060304081e38c6e22460eb9828aff6 (patch)
tree99b9f43b642f071980a1497145daff368a29b7ed
parent[#3588] Improved no test logs (diff)
downloadkea-78737d8786060304081e38c6e22460eb9828aff6.tar.xz
kea-78737d8786060304081e38c6e22460eb9828aff6.zip
[#3552] Updated Botan support
-rw-r--r--configure.ac17
-rw-r--r--doc/sphinx/arm/security.rst7
-rw-r--r--m4macros/ax_crypto.m430
-rw-r--r--src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc2
-rw-r--r--src/lib/asiolink/Makefile.am14
-rw-r--r--src/lib/asiolink/botan_boost_tls.cc339
-rw-r--r--src/lib/asiolink/botan_boost_tls.h208
-rw-r--r--src/lib/asiolink/botan_tls.cc311
-rw-r--r--src/lib/asiolink/botan_tls.h102
-rw-r--r--src/lib/asiolink/botan_wrapper.h (renamed from src/lib/asiolink/botan_boost_wrapper.h)14
-rw-r--r--src/lib/asiolink/crypto_tls.h1
-rw-r--r--src/lib/asiolink/tests/Makefile.am2
-rw-r--r--src/lib/asiolink/testutils/.gitignore4
-rw-r--r--src/lib/asiolink/testutils/Makefile.am22
-rw-r--r--src/lib/asiolink/testutils/botan_sample_client.cc (renamed from src/lib/asiolink/testutils/botan_boost_sample_client.cc)2
-rw-r--r--src/lib/asiolink/testutils/botan_sample_server.cc (renamed from src/lib/asiolink/testutils/botan_boost_sample_server.cc)2
-rw-r--r--src/lib/cryptolink/botan_common.h9
-rw-r--r--src/lib/cryptolink/botan_hash.cc18
-rw-r--r--src/lib/cryptolink/botan_hmac.cc78
-rw-r--r--src/lib/http/tests/Makefile.am2
-rw-r--r--src/lib/tcp/tests/Makefile.am2
21 files changed, 460 insertions, 726 deletions
diff --git a/configure.ac b/configure.ac
index fcf4bebe1b..0e44735fdf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1270,22 +1270,6 @@ AC_SUBST(PKGPYTHONDIR)
AC_SUBST(PYTHON_PREFIX)
AC_SUBST(PYTHON_EXEC_PREFIX)
-# Decide if TLS is supported.
-tls_support=no
-if test "x${CRYPTO_NAME}" = "xOpenSSL"; then
- tls_support=yes
-fi
-if test "x${CRYPTO_NAME}" = "xBotan" && test "x$BOTAN_BOOST" = "xyes"; then
- tls_support=yes
-fi
-
-# Decide if the shell TLS test can work.
-ca_tls_test=no
-if test "x$enable_shell" != "xno"; then
- ca_tls_test="$tls_support"
-fi
-AM_CONDITIONAL(CA_TLS_TEST, test x$ca_tls_test != xno)
-
AC_ARG_WITH([sphinx],
[AS_HELP_STRING([--with-sphinx=PATH],[path to sphinx-build tool])],
[sphinx_path="$withval"])
@@ -1988,7 +1972,6 @@ ${CRYPTO_NAME}:
CRYPTO_INCLUDES: ${CRYPTO_INCLUDES}
CRYPTO_LDFLAGS: ${CRYPTO_LDFLAGS}
CRYPTO_LIBS: ${CRYPTO_LIBS}
- TLS support: $tls_support
${DISABLED_CRYPTO}: no
diff --git a/doc/sphinx/arm/security.rst b/doc/sphinx/arm/security.rst
index 3063fb0667..d729455fd7 100644
--- a/doc/sphinx/arm/security.rst
+++ b/doc/sphinx/arm/security.rst
@@ -59,8 +59,7 @@ that must be used:
- LibreSSL 3.2.4 has been tested. LibreSSL shares the OpenSSL 1.0.2 API, so
it should work, but is not supported.
-- Botan 1.x versions are obsolete and should not be used.
- Kea TLS support has not been tested and is not supported with these versions.
+- Botan 1.x versions are obsolete and must not be used.
- Botan versions 2.14.0 and later have been tested and are supported. Kea TLS
support requires the four Asio header files which are included in Botan
@@ -76,8 +75,8 @@ that must be used:
directory, but this should be a last-resort procedure.
Without these header files, or with a Botan version prior
- to 2.14.0, Kea can still build, but the TLS/HTTPS support is disabled;
- any attempt to use it will fail with a fatal error.
+ to 2.14.0, Kea cannot build as the TLS/HTTPS support is considered
+ as essential for security.
- Very old Boost versions provide SSL support (based on OpenSSL)
without offering a choice of the TLS version; Kea can still use them,
diff --git a/m4macros/ax_crypto.m4 b/m4macros/ax_crypto.m4
index c075aba840..389582c9d5 100644
--- a/m4macros/ax_crypto.m4
+++ b/m4macros/ax_crypto.m4
@@ -40,9 +40,9 @@ AC_DEFUN([ACX_TRY_BOTAN_TOOL], [
CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS"
#AC_MSG_RESULT([found])
AC_LINK_IFELSE(
- [AC_LANG_PROGRAM([#include <botan/lookup.h>],
+ [AC_LANG_PROGRAM([#include <botan/hash.h>],
[using namespace Botan;
- HashFunction *h = HashFunction::create("MD5").release();
+ auto h = HashFunction::create("MD5");
])],
[ AC_MSG_RESULT([ok])
$3
@@ -199,13 +199,13 @@ EOF
# failure handler we can detect the difference between a header not existing
# (or not even passing the pre-processor phase) and a header file resulting
# in compilation failures.
- AC_CHECK_HEADERS([botan/botan.h],,[
+ AC_CHECK_HEADERS([botan/build.h],,[
CRYPTO_INCLUDES=""
CRYPTO_LIBS=""
CRYPTO_LDFLAGS=""
CRYPTO_RPATH=""
if test "x$ac_header_preproc" = "xyes"; then
- AC_MSG_RESULT([botan/botan.h
+ AC_MSG_RESULT([botan/build.h
was found but is unusable. The most common cause of this problem
is attempting to use an updated C++ compiler with older C++ libraries, such as
the version of Botan that comes with your distribution. If you have updated
@@ -226,10 +226,9 @@ then
LIBS_SAVED="$LIBS"
LIBS="$LIBS $CRYPTO_LIBS"
AC_LINK_IFELSE(
- [AC_LANG_PROGRAM([#include <botan/lookup.h>],
+ [AC_LANG_PROGRAM([#include <botan/hash.h>],
[using namespace Botan;
- HashFunction *h = HashFunction::create("MD5")
-.release();
+ auto h = HashFunction::create("MD5");
])],
[AC_MSG_RESULT([checking for Botan library... yes])],
[AC_MSG_RESULT([checking for Botan library... no])
@@ -391,24 +390,17 @@ then
dnl Check Botan boost ASIO TLS
CPPFLAGS_SAVED=$CPPFLAGS
CPPFLAGS="$CRYPTO_INCLUDES $CPPFLAGS $BOOST_INCLUDES"
- BOTAN_BOOST=""
AC_CHECK_HEADERS([botan/asio_stream.h],
- [BOTAN_BOOST="maybe"
- AC_MSG_CHECKING([Botan boost TLS support])
+ [AC_MSG_CHECKING([Botan boost TLS support])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([#include <botan/asio_stream.h>],
[#ifndef BOTAN_TLS_SERVER_H_
#error botan/tls_server.h is not included by botan/asio_stream.h
#endif])],
- [AC_MSG_RESULT(yes)
- BOTAN_BOOST="yes"
- AC_DEFINE([WITH_BOTAN_BOOST], [1],
- [Define to 1 if Botan boost TLS is available])],
+ [AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)
- BOTAN_BOOST="no"
- AC_MSG_WARN([Botan is configured with boost support but is too old: only Botan >= 2.14.0 can be used for TLS support.])])],
- [BOTAN_BOOST="no"
- AC_MSG_WARN([Botan cannot be used for TLS support, because it was compiled without boost support, so required headers are missing.])])
+ AC_MSG_ERROR([Botan is configured with boost support but is too old: only Botan >= 2.14.0 can be used for TLS support.])])],
+ [AC_MSG_ERROR([Botan cannot be used for TLS support, because it was installed without boost support, so required headers are missing.])])
CPPFLAGS=${CPPFLAGS_SAVED}
fi
if test "x${CRYPTO_NAME}" = "xOpenSSL"
@@ -454,7 +446,5 @@ then
[AC_MSG_ERROR([Can not find a definition for stream_truncated (SSL short read) error: sorry, your boost library is too old])])])
CPPFLAGS=${CPPFLAGS_SAVED}
fi
-AM_CONDITIONAL(HAVE_BOTAN_BOOST,
- test "$CRYPTO_NAME" = "Botan" && test "$BOTAN_BOOST" = "yes")
])
# End of AX_TLS
diff --git a/src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc b/src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc
index 62951d4eed..1c17ea4a4c 100644
--- a/src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc
+++ b/src/hooks/dhcp/high_availability/tests/ha_config_unittest.cc
@@ -1419,7 +1419,6 @@ TEST_F(HAConfigTest, passiveBackupDelayedUpdatesLimit) {
"'delayed-updates-limit' must be set to 0 in the passive backup configuration");
}
-#if (defined(WITH_OPENSSL) || defined(WITH_BOTAN_BOOST))
/// Test that TLS parameters are correctly inherited.
TEST_F(HAConfigTest, tlsParameterInheritance) {
const std::string ha_config =
@@ -1743,7 +1742,6 @@ TEST_F(HAConfigTest, badKeyFile) {
#endif
testInvalidConfig(patched, expected);
}
-#endif // WITH_OPENSSL || WITH_BOTAN_BOOST
// Test that conversion of the role names works correctly.
TEST_F(HAConfigTest, stringToRole) {
diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am
index 9654c931ac..21fbee30b3 100644
--- a/src/lib/asiolink/Makefile.am
+++ b/src/lib/asiolink/Makefile.am
@@ -17,8 +17,6 @@ libkea_asiolink_la_LDFLAGS += $(CRYPTO_LDFLAGS)
libkea_asiolink_la_SOURCES = asiolink.h
libkea_asiolink_la_SOURCES += asio_wrapper.h
libkea_asiolink_la_SOURCES += addr_utilities.cc addr_utilities.h
-libkea_asiolink_la_SOURCES += botan_boost_tls.h botan_boost_wrapper.h
-libkea_asiolink_la_SOURCES += botan_tls.h
libkea_asiolink_la_SOURCES += common_tls.cc common_tls.h
libkea_asiolink_la_SOURCES += crypto_tls.h
libkea_asiolink_la_SOURCES += dummy_io_cb.h
@@ -33,7 +31,6 @@ libkea_asiolink_la_SOURCES += io_service_mgr.h io_service_mgr.cc
libkea_asiolink_la_SOURCES += io_service_signal.cc io_service_signal.h
libkea_asiolink_la_SOURCES += io_service_thread_pool.cc io_service_thread_pool.h
libkea_asiolink_la_SOURCES += io_socket.h io_socket.cc
-libkea_asiolink_la_SOURCES += openssl_tls.h
libkea_asiolink_la_SOURCES += process_spawn.h process_spawn.cc
libkea_asiolink_la_SOURCES += tcp_acceptor.h
libkea_asiolink_la_SOURCES += tcp_endpoint.h
@@ -47,14 +44,10 @@ libkea_asiolink_la_SOURCES += unix_domain_socket_acceptor.h
libkea_asiolink_la_SOURCES += unix_domain_socket_endpoint.h
if HAVE_BOTAN
-if HAVE_BOTAN_BOOST
-libkea_asiolink_la_SOURCES += botan_boost_tls.cc
-else
-libkea_asiolink_la_SOURCES += botan_tls.cc
-endif
+libkea_asiolink_la_SOURCES += botan_tls.cc botan_tls.h botan_wrapper.h
endif
if HAVE_OPENSSL
-libkea_asiolink_la_SOURCES += openssl_tls.cc
+libkea_asiolink_la_SOURCES += openssl_tls.cc openssl_tls.h
endif
# Note: the ordering matters: -Wno-... must follow -Wextra (defined in KEA_CXXFLAGS)
@@ -70,9 +63,8 @@ libkea_asiolink_include_HEADERS = \
addr_utilities.h \
asio_wrapper.h \
asiolink.h \
- botan_boost_tls.h \
- botan_boost_wrapper.h \
botan_tls.h \
+ botan_wrapper.h \
common_tls.h \
crypto_tls.h \
dummy_io_cb.h \
diff --git a/src/lib/asiolink/botan_boost_tls.cc b/src/lib/asiolink/botan_boost_tls.cc
deleted file mode 100644
index 12db353b04..0000000000
--- a/src/lib/asiolink/botan_boost_tls.cc
+++ /dev/null
@@ -1,339 +0,0 @@
-// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-#include <config.h>
-
-/// @file botan_boost_tls.cc Botan boost ASIO implementation of the TLS API.
-
-#if defined(WITH_BOTAN) && defined(WITH_BOTAN_BOOST)
-
-#include <asiolink/asio_wrapper.h>
-#include <asiolink/crypto_tls.h>
-
-#include <botan/auto_rng.h>
-#include <botan/certstor_flatfile.h>
-#include <botan/data_src.h>
-#include <botan/pem.h>
-#include <botan/pkcs8.h>
-
-using namespace isc::cryptolink;
-
-namespace isc {
-namespace asiolink {
-
-// Classes of Kea certificate stores.
-using KeaCertificateStorePath = Botan::Certificate_Store_In_Memory;
-using KeaCertificateStoreFile = Botan::Flatfile_Certificate_Store;
-
-// Class of Kea credential managers.
-class KeaCredentialsManager : public Botan::Credentials_Manager {
-public:
- // Constructor.
- KeaCredentialsManager() : store_(), use_stores_(true), certs_(), key_() {
- }
-
- // Destructor.
- virtual ~KeaCredentialsManager() {
- }
-
- // CA certificate stores.
- // nullptr means do not require or check peer certificate.
- std::vector<Botan::Certificate_Store*>
- trusted_certificate_authorities(const std::string&,
- const std::string&) override {
- std::vector<Botan::Certificate_Store*> result;
- if (use_stores_ && store_) {
- result.push_back(store_.get());
- }
- return (result);
- }
-
- // Certificate chain.
- std::vector<Botan::X509_Certificate>
- cert_chain(const std::vector<std::string>&,
- const std::string&,
- const std::string&) override {
- return (certs_);
- }
-
- // Private key.
- Botan::Private_Key*
- private_key_for(const Botan::X509_Certificate&,
- const std::string&,
- const std::string&) override {
- return (key_.get());
- }
-
- // Set the store from a path.
- void setStorePath(const std::string& path) {
- store_.reset(new KeaCertificateStorePath(path));
- }
-
- // Set the store from a file.
- void setStoreFile(const std::string& file) {
- store_.reset(new KeaCertificateStoreFile(file));
- }
-
- // Get the use of CA certificate stores flag.
- bool getUseStores() const {
- return (use_stores_);
- }
-
- // Set the use of CA certificate stores flag.
- void setUseStores(bool use_stores) {
- use_stores_ = use_stores;
- }
-
- // Set the certificate chain.
- void setCertChain(const std::string& file) {
- Botan::DataSource_Stream source(file);
- certs_.clear();
- while (!source.end_of_data()) {
- std::string label;
- std::vector<uint8_t> cert;
- try {
- cert = unlock(Botan::PEM_Code::decode(source, label));
- if ((label != "CERTIFICATE") &&
- (label != "X509 CERTIFICATE") &&
- (label != "TRUSTED CERTIFICATE")) {
- isc_throw(LibraryError, "Expected a certificate, got '"
- << label << "'");
- }
- certs_.push_back(Botan::X509_Certificate(cert));
- } catch (const std::exception& ex) {
- if (certs_.empty()) {
- throw;
- }
- // Got one certificate so skipping garbage.
- continue;
- }
- }
- if (certs_.empty()) {
- isc_throw(LibraryError, "Found no certificate?");
- }
- }
-
- // Set the private key.
- void setPrivateKey(const std::string& file,
- Botan::RandomNumberGenerator& rng,
- bool& is_rsa) {
- key_.reset(Botan::PKCS8::load_key(file, rng));
- if (!key_) {
- isc_throw(Unexpected,
- "Botan::PKCS8::load_key failed but not threw?");
- }
- is_rsa = (key_->algo_name() == "RSA");
- }
-
- // Pointer to the CA certificate store.
- std::unique_ptr<Botan::Certificate_Store> store_;
-
- // Use the CA certificate store flag.
- bool use_stores_;
-
- // The certificate chain.
- std::vector<Botan::X509_Certificate> certs_;
-
- // Pointer to the private key.
- std::unique_ptr<Botan::Private_Key> key_;
-};
-
-// Class of Kea policy.
-// Use Strict_Policy?
-class KeaPolicy : public Botan::TLS::Default_Policy {
-public:
- // Constructor.
- KeaPolicy() : prefer_rsa_(true) {
- }
-
- // Destructor.
- virtual ~KeaPolicy() {
- }
-
- // Allowed signature methods in preference order.
- std::vector<std::string> allowed_signature_methods() const override {
- if (prefer_rsa_) {
- return (AllowedSignatureMethodsRSA);
- } else {
- return (AllowedSignatureMethodsECDSA);
- }
- }
-
- // Disable OSCP.
- bool require_cert_revocation_info() const override {
- return false;
- }
-
- // Set the RSA preferred flag.
- void setPrefRSA(bool prefer_rsa) {
- prefer_rsa_ = prefer_rsa;
- }
-
- // Prefer RSA preferred flag.
- bool prefer_rsa_;
-
- // Allowed signature methods which prefers RSA.
- static const std::vector<std::string> AllowedSignatureMethodsRSA;
-
- // Allowed signature methods which prefers ECDSA.
- static const std::vector<std::string> AllowedSignatureMethodsECDSA;
-};
-
-
-// Kea session manager.
-using KeaSessionManager = Botan::TLS::Session_Manager_Noop;
-
-// Allowed signature methods which prefers RSA.
-const std::vector<std::string>
-KeaPolicy::AllowedSignatureMethodsRSA = { "RSA", "DSA", "ECDSA" };
-
-// Allowed signature methods which prefers ECDSA.
-const std::vector<std::string>
-KeaPolicy::AllowedSignatureMethodsECDSA = { "ECDSA", "RSA", "DSA" };
-
-// Class of Botan TLS context implementations.
-class TlsContextImpl {
-public:
- // Constructor.
- TlsContextImpl() : cred_mgr_(), rng_(), sess_mgr_(), policy_() {
- }
-
- // Destructor.
- virtual ~TlsContextImpl() {
- }
-
- // Get the peer certificate requirement mode.
- virtual bool getCertRequired() const {
- return (cred_mgr_.getUseStores());
- }
-
- // Set the peer certificate requirement mode.
- //
- // With Botan this means to provide or not the CA certificate stores.
- virtual void setCertRequired(bool cert_required) {
- cred_mgr_.setUseStores(cert_required);
- }
-
- // Load the trust anchor aka certificate authority (path).
- virtual void loadCaPath(const std::string& ca_path) {
- try {
- cred_mgr_.setStorePath(ca_path);
- } catch (const std::exception& ex) {
- isc_throw(LibraryError, ex.what());
- }
- }
-
- // Load the trust anchor aka certificate authority (file).
- virtual void loadCaFile(const std::string& ca_file) {
- try {
- cred_mgr_.setStoreFile(ca_file);
- } catch (const std::exception& ex) {
- isc_throw(LibraryError, ex.what());
- }
- }
-
- /// @brief Load the certificate file.
- virtual void loadCertFile(const std::string& cert_file) {
- try {
- cred_mgr_.setCertChain(cert_file);
- } catch (const std::exception& ex) {
- isc_throw(LibraryError, ex.what());
- }
- }
-
- /// @brief Load the private key file.
- ///
- /// As a side effect set the preference for RSA in the policy.
- virtual void loadKeyFile(const std::string& key_file) {
- try {
- bool is_rsa = true;
- cred_mgr_.setPrivateKey(key_file, rng_, is_rsa);
- policy_.setPrefRSA(is_rsa);
- } catch (const std::exception& ex) {
- isc_throw(LibraryError, ex.what());
- }
- }
-
- // Build the context if not yet done.
- virtual void build() {
- if (context_) {
- return;
- }
- context_.reset(new Botan::TLS::Context(cred_mgr_,
- rng_,
- sess_mgr_,
- policy_));
- }
-
- virtual Botan::TLS::Context& get() {
- return (*context_);
- }
-
- // Credentials Manager.
- KeaCredentialsManager cred_mgr_;
-
- // Random Number Generator.
- Botan::AutoSeeded_RNG rng_;
-
- // Session Manager.
- KeaSessionManager sess_mgr_;
-
- KeaPolicy policy_;
-
- std::unique_ptr<Botan::TLS::Context> context_;
-};
-
-TlsContext::~TlsContext() {
-}
-
-TlsContext::TlsContext(TlsRole role)
- : TlsContextBase(role), impl_(new TlsContextImpl()) {
-}
-
-Botan::TLS::Context&
-TlsContext::getContext() {
- impl_->build();
- return (impl_->get());
-}
-
-void
-TlsContext::setCertRequired(bool cert_required) {
- if (!cert_required && (getRole() == TlsRole::CLIENT)) {
- isc_throw(BadValue,
- "'cert-required' parameter must be true for a TLS client");
- }
- impl_->setCertRequired(cert_required);
-}
-
-bool
-TlsContext::getCertRequired() const {
- return (impl_->getCertRequired());
-}
-
-void
-TlsContext::loadCaFile(const std::string& ca_file) {
- impl_->loadCaFile(ca_file);
-}
-
-void
-TlsContext::loadCaPath(const std::string& ca_path) {
- impl_->loadCaPath(ca_path);
-}
-
-void
-TlsContext::loadCertFile(const std::string& cert_file) {
- impl_->loadCertFile(cert_file);
-}
-
-void
-TlsContext::loadKeyFile(const std::string& key_file) {
- impl_->loadKeyFile(key_file);
-}
-
-} // namespace asiolink
-} // namespace isc
-
-#endif // WITH_BOTAN && WITH_BOTAN_BOOST
diff --git a/src/lib/asiolink/botan_boost_tls.h b/src/lib/asiolink/botan_boost_tls.h
deleted file mode 100644
index 32b4d06597..0000000000
--- a/src/lib/asiolink/botan_boost_tls.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright (C) 2021-2024 Internet Systems Consortium, Inc. ("ISC")
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this
-// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// Do not include this header directly: use crypto_tls.h instead.
-
-#ifndef BOTAN_BOOST_TLS_H
-#define BOTAN_BOOST_TLS_H
-
-/// @file botan_boost_tls.h Botan boost ASIO implementation of the TLS API.
-
-#if defined(WITH_BOTAN) && defined(WITH_BOTAN_BOOST)
-
-#include <asiolink/asio_wrapper.h>
-#include <asiolink/io_asio_socket.h>
-#include <asiolink/io_service.h>
-#include <asiolink/common_tls.h>
-#include <exceptions/exceptions.h>
-
-#include <asiolink/botan_boost_wrapper.h>
-#include <botan/asio_stream.h>
-
-namespace isc {
-namespace asiolink {
-
-/// @brief Translate TLS role into implementation.
-inline Botan::TLS::Connection_Side roleToImpl(TlsRole role) {
- if (role == TlsRole::SERVER) {
- return (Botan::TLS::Connection_Side::SERVER);
- } else {
- return (Botan::TLS::Connection_Side::CLIENT);
- }
-}
-
-/// @brief Forward declaration of Botan TLS context.
-class TlsContextImpl;
-
-/// @brief Botan boost ASIO TLS context.
-class TlsContext : public TlsContextBase {
-public:
-
- /// @brief Destructor.
- ///
- /// @note The destructor can't be defined here because a unique
- /// pointer to an incomplete type is used.
- virtual ~TlsContext();
-
- /// @brief Create a fresh context.
- ///
- /// @param role The TLS role client or server.
- explicit TlsContext(TlsRole role);
-
- /// @brief Return the underlying context.
- Botan::TLS::Context& getContext();
-
- /// @brief Get the peer certificate requirement mode.
- ///
- /// @return True if peer certificates are required, false if they
- /// are optional.
- virtual bool getCertRequired() const;
-
-protected:
- /// @brief Set the peer certificate requirement mode.
- ///
- /// @param cert_required True if peer certificates are required,
- /// false if they are optional.
- virtual void setCertRequired(bool cert_required);
-
- /// @brief Load the trust anchor aka certification authority.
- ///
- /// @param ca_file The certificate file name.
- virtual void loadCaFile(const std::string& ca_file);
-
- /// @brief Load the trust anchor aka certification authority.
- ///
- /// @param ca_path The certificate directory name.
- virtual void loadCaPath(const std::string& ca_path);
-
- /// @brief Load the certificate file.
- ///
- /// @param cert_file The certificate file name.
- virtual void loadCertFile(const std::string& cert_file);
-
- /// @brief Load the private key from a file.
- ///
- /// @param key_file The private key file name.
- virtual void loadKeyFile(const std::string& key_file);
-
- /// @brief Botan TLS context.
- std::unique_ptr<TlsContextImpl> impl_;
-
- /// @brief Allow access to protected methods by the base class.
- friend class TlsContextBase;
-};
-
-/// @brief The type of underlying TLS streams.
-typedef Botan::TLS::Stream<boost::asio::ip::tcp::socket> TlsStreamImpl;
-
-/// @brief TlsStreamBase constructor.
-///
-/// @tparam Callback The type of callbacks.
-/// @tparam TlsStreamImpl The type of underlying TLS streams.
-/// @param service I/O Service object used to manage the stream.
-/// @param context Pointer to the TLS context.
-/// @note The caller must not provide a null pointer to the TLS context.
-template <typename Callback, typename TlsStreamImpl>
-TlsStreamBase<Callback, TlsStreamImpl>::
-TlsStreamBase(const IOServicePtr& io_service, TlsContextPtr context)
- : StreamService(io_service, context),
- TlsStreamImpl(io_service->getInternalIOService(),
- context->getContext()), role_(context->getRole()) {
-}
-
-/// @brief Botan boost ASIO TLS stream.
-///
-/// @tparam callback The callback.
-template <typename Callback>
-class TlsStream : public TlsStreamBase<Callback, TlsStreamImpl>
-{
-public:
-
- /// @brief Type of the base.
- typedef TlsStreamBase<Callback, TlsStreamImpl> Base;
-
- /// @brief Constructor.
- ///
- /// @param service I/O Service object used to manage the stream.
- /// @param context Pointer to the TLS context.
- /// @note The caller must not provide a null pointer to the TLS context.
- TlsStream(const IOServicePtr& service, TlsContextPtr context)
- : Base(service, context) {
- }
-
- /// @brief Destructor.
- virtual ~TlsStream() { }
-
- /// @brief TLS Handshake.
- ///
- /// @param callback Callback object.
- virtual void handshake(Callback& callback) {
- Base::async_handshake(roleToImpl(Base::getRole()), callback);
- }
-
- /// @brief TLS shutdown.
- ///
- /// @param callback Callback object.
- virtual void shutdown(Callback& callback) {
- Base::async_shutdown(callback);
- }
-
- /// @brief Clear the TLS object.
- ///
- /// @note The idea to reuse a TCP connection for a fresh TLS is at
- /// least arguable. Currently it does nothing so the socket is
- /// **not** reusable.
- virtual void clear() {
- }
-
- /// @brief Return the commonName part of the subjectName of
- /// the peer certificate.
- ///
- /// First commonName when there are more than one, in UTF-8.
- /// RFC 3280 provides as a commonName example "Susan Housley",
- /// to idea to give access to this come from the Role Based
- /// Access Control experiment.
- ///
- /// @return The commonName part of the subjectName or the empty string.
- virtual std::string getSubject() {
- const std::vector<Botan::X509_Certificate>& cert_chain =
- Base::native_handle()->peer_cert_chain();
- if (cert_chain.empty()) {
- return ("");
- }
- const Botan::X509_DN& subject = cert_chain[0].subject_dn();
- return (subject.get_first_attribute("CommonName"));
- }
-
- /// @brief Return the commonName part of the issuerName of
- /// the peer certificate.
- ///
- /// First commonName when there are more than one, in UTF-8.
- /// The issuerName is the subjectName of the signing certificate
- /// (the issue in PKIX terms). The idea is to encode a group as
- /// members of an intermediate certification authority.
- ///
- /// @return The commonName part of the issuerName or the empty string.
- virtual std::string getIssuer() {
- const std::vector<Botan::X509_Certificate>& cert_chain =
- Base::native_handle()->peer_cert_chain();
- if (cert_chain.empty()) {
- return ("");
- }
- const Botan::X509_DN& issuer = cert_chain[0].issuer_dn();
- return (issuer.get_first_attribute("CommonName"));
- }
-};
-
-// Stream truncated error code.
-const int STREAM_TRUNCATED = Botan::TLS::StreamError::StreamTruncated;
-
-} // namespace asiolink
-} // namespace isc
-
-#endif // WITH_BOTAN && WITH_BOTAN_BOOST
-
-#endif // BOTAN_BOOST_TLS_H
diff --git a/src/lib/asiolink/botan_tls.cc b/src/lib/asiolink/botan_tls.cc
index 3cd18189d0..b95485ccc3 100644
--- a/src/lib/asiolink/botan_tls.cc
+++ b/src/lib/asiolink/botan_tls.cc
@@ -1,23 +1,302 @@
-// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2021-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
-/// @file botan_tls.cc Botan fake implementation of the TLS API.
-
#include <config.h>
-#if defined(WITH_BOTAN) && !defined(WITH_BOTAN_BOOST)
+/// @file botan_tls.cc Botan ASIO implementation of the TLS API.
+
+#ifdef WITH_BOTAN
#include <asiolink/asio_wrapper.h>
#include <asiolink/crypto_tls.h>
+#include <botan/auto_rng.h>
+#include <botan/certstor_flatfile.h>
+#include <botan/data_src.h>
+#include <botan/pem.h>
+#include <botan/pkcs8.h>
+
+using namespace isc::cryptolink;
+
namespace isc {
namespace asiolink {
+// Classes of Kea certificate stores.
+using KeaCertificateStorePath = Botan::Certificate_Store_In_Memory;
+using KeaCertificateStoreFile = Botan::Flatfile_Certificate_Store;
+
+// Class of Kea credential managers.
+class KeaCredentialsManager : public Botan::Credentials_Manager {
+public:
+ // Constructor.
+ KeaCredentialsManager() : store_(), use_stores_(true), certs_(), key_() {
+ }
+
+ // Destructor.
+ virtual ~KeaCredentialsManager() {
+ }
+
+ // CA certificate stores.
+ // nullptr means do not require or check peer certificate.
+ std::vector<Botan::Certificate_Store*>
+ trusted_certificate_authorities(const std::string&,
+ const std::string&) override {
+ std::vector<Botan::Certificate_Store*> result;
+ if (use_stores_ && store_) {
+ result.push_back(store_.get());
+ }
+ return (result);
+ }
+
+ // Certificate chain.
+ std::vector<Botan::X509_Certificate>
+ cert_chain(const std::vector<std::string>&,
+ const std::string&,
+ const std::string&) override {
+ return (certs_);
+ }
+
+ // Private key.
+ Botan::Private_Key*
+ private_key_for(const Botan::X509_Certificate&,
+ const std::string&,
+ const std::string&) override {
+ return (key_.get());
+ }
+
+ // Set the store from a path.
+ void setStorePath(const std::string& path) {
+ store_.reset(new KeaCertificateStorePath(path));
+ }
+
+ // Set the store from a file.
+ void setStoreFile(const std::string& file) {
+ store_.reset(new KeaCertificateStoreFile(file));
+ }
+
+ // Get the use of CA certificate stores flag.
+ bool getUseStores() const {
+ return (use_stores_);
+ }
+
+ // Set the use of CA certificate stores flag.
+ void setUseStores(bool use_stores) {
+ use_stores_ = use_stores;
+ }
+
+ // Set the certificate chain.
+ void setCertChain(const std::string& file) {
+ Botan::DataSource_Stream source(file);
+ certs_.clear();
+ while (!source.end_of_data()) {
+ std::string label;
+ std::vector<uint8_t> cert;
+ try {
+ cert = unlock(Botan::PEM_Code::decode(source, label));
+ if ((label != "CERTIFICATE") &&
+ (label != "X509 CERTIFICATE") &&
+ (label != "TRUSTED CERTIFICATE")) {
+ isc_throw(LibraryError, "Expected a certificate, got '"
+ << label << "'");
+ }
+ certs_.push_back(Botan::X509_Certificate(cert));
+ } catch (const std::exception& ex) {
+ if (certs_.empty()) {
+ throw;
+ }
+ // Got one certificate so skipping garbage.
+ continue;
+ }
+ }
+ if (certs_.empty()) {
+ isc_throw(LibraryError, "Found no certificate?");
+ }
+ }
+
+ // Set the private key.
+ void setPrivateKey(const std::string& file,
+ Botan::RandomNumberGenerator& rng,
+ bool& is_rsa) {
+ key_.reset(Botan::PKCS8::load_key(file, rng));
+ if (!key_) {
+ isc_throw(Unexpected,
+ "Botan::PKCS8::load_key failed but not threw?");
+ }
+ is_rsa = (key_->algo_name() == "RSA");
+ }
+
+ // Pointer to the CA certificate store.
+ std::unique_ptr<Botan::Certificate_Store> store_;
+
+ // Use the CA certificate store flag.
+ bool use_stores_;
+
+ // The certificate chain.
+ std::vector<Botan::X509_Certificate> certs_;
+
+ // Pointer to the private key.
+ std::unique_ptr<Botan::Private_Key> key_;
+};
+
+// Class of Kea policy.
+// Use Strict_Policy?
+class KeaPolicy : public Botan::TLS::Default_Policy {
+public:
+ // Constructor.
+ KeaPolicy() : prefer_rsa_(true) {
+ }
+
+ // Destructor.
+ virtual ~KeaPolicy() {
+ }
+
+ // Allowed signature methods in preference order.
+ std::vector<std::string> allowed_signature_methods() const override {
+ if (prefer_rsa_) {
+ return (AllowedSignatureMethodsRSA);
+ } else {
+ return (AllowedSignatureMethodsECDSA);
+ }
+ }
+
+ // Disable OSCP.
+ bool require_cert_revocation_info() const override {
+ return false;
+ }
+
+ // Set the RSA preferred flag.
+ void setPrefRSA(bool prefer_rsa) {
+ prefer_rsa_ = prefer_rsa;
+ }
+
+ // Prefer RSA preferred flag.
+ bool prefer_rsa_;
+
+ // Allowed signature methods which prefers RSA.
+ static const std::vector<std::string> AllowedSignatureMethodsRSA;
+
+ // Allowed signature methods which prefers ECDSA.
+ static const std::vector<std::string> AllowedSignatureMethodsECDSA;
+};
+
+
+// Kea session manager.
+using KeaSessionManager = Botan::TLS::Session_Manager_Noop;
+
+// Allowed signature methods which prefers RSA.
+const std::vector<std::string>
+KeaPolicy::AllowedSignatureMethodsRSA = { "RSA", "DSA", "ECDSA" };
+
+// Allowed signature methods which prefers ECDSA.
+const std::vector<std::string>
+KeaPolicy::AllowedSignatureMethodsECDSA = { "ECDSA", "RSA", "DSA" };
+
+// Class of Botan TLS context implementations.
+class TlsContextImpl {
+public:
+ // Constructor.
+ TlsContextImpl() : cred_mgr_(), rng_(), sess_mgr_(), policy_() {
+ }
+
+ // Destructor.
+ virtual ~TlsContextImpl() {
+ }
+
+ // Get the peer certificate requirement mode.
+ virtual bool getCertRequired() const {
+ return (cred_mgr_.getUseStores());
+ }
+
+ // Set the peer certificate requirement mode.
+ //
+ // With Botan this means to provide or not the CA certificate stores.
+ virtual void setCertRequired(bool cert_required) {
+ cred_mgr_.setUseStores(cert_required);
+ }
+
+ // Load the trust anchor aka certificate authority (path).
+ virtual void loadCaPath(const std::string& ca_path) {
+ try {
+ cred_mgr_.setStorePath(ca_path);
+ } catch (const std::exception& ex) {
+ isc_throw(LibraryError, ex.what());
+ }
+ }
+
+ // Load the trust anchor aka certificate authority (file).
+ virtual void loadCaFile(const std::string& ca_file) {
+ try {
+ cred_mgr_.setStoreFile(ca_file);
+ } catch (const std::exception& ex) {
+ isc_throw(LibraryError, ex.what());
+ }
+ }
+
+ /// @brief Load the certificate file.
+ virtual void loadCertFile(const std::string& cert_file) {
+ try {
+ cred_mgr_.setCertChain(cert_file);
+ } catch (const std::exception& ex) {
+ isc_throw(LibraryError, ex.what());
+ }
+ }
+
+ /// @brief Load the private key file.
+ ///
+ /// As a side effect set the preference for RSA in the policy.
+ virtual void loadKeyFile(const std::string& key_file) {
+ try {
+ bool is_rsa = true;
+ cred_mgr_.setPrivateKey(key_file, rng_, is_rsa);
+ policy_.setPrefRSA(is_rsa);
+ } catch (const std::exception& ex) {
+ isc_throw(LibraryError, ex.what());
+ }
+ }
+
+ // Build the context if not yet done.
+ virtual void build() {
+ if (context_) {
+ return;
+ }
+ context_.reset(new Botan::TLS::Context(cred_mgr_,
+ rng_,
+ sess_mgr_,
+ policy_));
+ }
+
+ virtual Botan::TLS::Context& get() {
+ return (*context_);
+ }
+
+ // Credentials Manager.
+ KeaCredentialsManager cred_mgr_;
+
+ // Random Number Generator.
+ Botan::AutoSeeded_RNG rng_;
+
+ // Session Manager.
+ KeaSessionManager sess_mgr_;
+
+ KeaPolicy policy_;
+
+ std::unique_ptr<Botan::TLS::Context> context_;
+};
+
+TlsContext::~TlsContext() {
+}
+
TlsContext::TlsContext(TlsRole role)
- : TlsContextBase(role), cert_required_(true) {
+ : TlsContextBase(role), impl_(new TlsContextImpl()) {
+}
+
+Botan::TLS::Context&
+TlsContext::getContext() {
+ impl_->build();
+ return (impl_->get());
}
void
@@ -26,35 +305,35 @@ TlsContext::setCertRequired(bool cert_required) {
isc_throw(BadValue,
"'cert-required' parameter must be true for a TLS client");
}
- cert_required_ = cert_required;
+ impl_->setCertRequired(cert_required);
}
bool
TlsContext::getCertRequired() const {
- return (cert_required_);
+ return (impl_->getCertRequired());
}
void
-TlsContext::loadCaFile(const std::string&) {
- isc_throw(NotImplemented, "Botan TLS is not yet supported");
+TlsContext::loadCaFile(const std::string& ca_file) {
+ impl_->loadCaFile(ca_file);
}
void
-TlsContext::loadCaPath(const std::string&) {
- isc_throw(NotImplemented, "loadCaPath is not implemented by Botan");
+TlsContext::loadCaPath(const std::string& ca_path) {
+ impl_->loadCaPath(ca_path);
}
void
-TlsContext::loadCertFile(const std::string&) {
- isc_throw(NotImplemented, "Botan TLS is not yet supported");
+TlsContext::loadCertFile(const std::string& cert_file) {
+ impl_->loadCertFile(cert_file);
}
void
-TlsContext::loadKeyFile(const std::string&) {
- isc_throw(NotImplemented, "Botan TLS is not yet supported");
+TlsContext::loadKeyFile(const std::string& key_file) {
+ impl_->loadKeyFile(key_file);
}
} // namespace asiolink
} // namespace isc
-#endif // WITH_BOTAN && !WITH_BOTAN_BOOST
+#endif // WITH_BOTAN
diff --git a/src/lib/asiolink/botan_tls.h b/src/lib/asiolink/botan_tls.h
index 1dbed1e1fd..6004672336 100644
--- a/src/lib/asiolink/botan_tls.h
+++ b/src/lib/asiolink/botan_tls.h
@@ -9,32 +9,52 @@
#ifndef BOTAN_TLS_H
#define BOTAN_TLS_H
-/// @file botan_tls.h Botan fake implementation of the TLS API.
+/// @file botan_tls.h Botan ASIO implementation of the TLS API.
-#if defined(WITH_BOTAN) && !defined(WITH_BOTAN_BOOST)
+#ifdef WITH_BOTAN
#include <asiolink/asio_wrapper.h>
#include <asiolink/io_asio_socket.h>
#include <asiolink/io_service.h>
#include <asiolink/common_tls.h>
-
#include <exceptions/exceptions.h>
+#include <asiolink/botan_wrapper.h>
+#include <botan/asio_stream.h>
+
namespace isc {
namespace asiolink {
-/// @brief Botan TLS context.
+/// @brief Translate TLS role into implementation.
+inline Botan::TLS::Connection_Side roleToImpl(TlsRole role) {
+ if (role == TlsRole::SERVER) {
+ return (Botan::TLS::Connection_Side::SERVER);
+ } else {
+ return (Botan::TLS::Connection_Side::CLIENT);
+ }
+}
+
+/// @brief Forward declaration of Botan TLS context.
+class TlsContextImpl;
+
+/// @brief Botan ASIO TLS context.
class TlsContext : public TlsContextBase {
public:
/// @brief Destructor.
- virtual ~TlsContext() { }
+ ///
+ /// @note The destructor can't be defined here because a unique
+ /// pointer to an incomplete type is used.
+ virtual ~TlsContext();
/// @brief Create a fresh context.
///
/// @param role The TLS role client or server.
explicit TlsContext(TlsRole role);
+ /// @brief Return the underlying context.
+ Botan::TLS::Context& getContext();
+
/// @brief Get the peer certificate requirement mode.
///
/// @return True if peer certificates are required, false if they
@@ -51,40 +71,32 @@ protected:
/// @brief Load the trust anchor aka certification authority.
///
/// @param ca_file The certificate file name.
- /// @throw isc::cryptolink::LibraryError on various errors as
- /// file not found, bad format, etc.
virtual void loadCaFile(const std::string& ca_file);
/// @brief Load the trust anchor aka certification authority.
///
/// @param ca_path The certificate directory name.
- /// @throw isc::cryptolink::LibraryError on various errors as
- /// file not found, bad format, etc.
virtual void loadCaPath(const std::string& ca_path);
/// @brief Load the certificate file.
///
/// @param cert_file The certificate file name.
- /// @throw isc::cryptolink::LibraryError on various errors as
- /// file not found, bad format, etc.
virtual void loadCertFile(const std::string& cert_file);
/// @brief Load the private key from a file.
///
/// @param key_file The private key file name.
- /// @throw isc::cryptolink::LibraryError on various errors as
- /// file not found, bad format, etc.
virtual void loadKeyFile(const std::string& key_file);
- /// @brief Cached cert_required value.
- bool cert_required_;
+ /// @brief Botan TLS context.
+ std::unique_ptr<TlsContextImpl> impl_;
/// @brief Allow access to protected methods by the base class.
friend class TlsContextBase;
};
-/// @brief The type of Botan TLS streams (in fact pure TCP streams).
-typedef boost::asio::ip::tcp::socket TlsStreamImpl;
+/// @brief The type of underlying TLS streams.
+typedef Botan::TLS::Stream<boost::asio::ip::tcp::socket> TlsStreamImpl;
/// @brief TlsStreamBase constructor.
///
@@ -97,15 +109,16 @@ template <typename Callback, typename TlsStreamImpl>
TlsStreamBase<Callback, TlsStreamImpl>::
TlsStreamBase(const IOServicePtr& io_service, TlsContextPtr context)
: StreamService(io_service, context),
- TlsStreamImpl(io_service->getInternalIOService()),
- role_(context->getRole()) {
+ TlsStreamImpl(io_service->getInternalIOService(),
+ context->getContext()), role_(context->getRole()) {
}
-/// @brief Botan fake TLS stream.
+/// @brief Botan ASIO TLS stream.
///
/// @tparam callback The callback.
template <typename Callback>
-class TlsStream : public TlsStreamBase<Callback, TlsStreamImpl> {
+class TlsStream : public TlsStreamBase<Callback, TlsStreamImpl>
+{
public:
/// @brief Type of the base.
@@ -124,13 +137,25 @@ public:
virtual ~TlsStream() { }
/// @brief TLS Handshake.
- virtual void handshake(Callback&) {
- isc_throw(NotImplemented, "Botan TLS is not yet supported");
+ ///
+ /// @param callback Callback object.
+ virtual void handshake(Callback& callback) {
+ Base::async_handshake(roleToImpl(Base::getRole()), callback);
}
/// @brief TLS shutdown.
- virtual void shutdown(Callback&) {
- isc_throw(NotImplemented, "Botan TLS is not yet supported");
+ ///
+ /// @param callback Callback object.
+ virtual void shutdown(Callback& callback) {
+ Base::async_shutdown(callback);
+ }
+
+ /// @brief Clear the TLS object.
+ ///
+ /// @note The idea to reuse a TCP connection for a fresh TLS is at
+ /// least arguable. Currently it does nothing so the socket is
+ /// **not** reusable.
+ virtual void clear() {
}
/// @brief Return the commonName part of the subjectName of
@@ -141,10 +166,15 @@ public:
/// to idea to give access to this come from the Role Based
/// Access Control experiment.
///
- ///
/// @return The commonName part of the subjectName or the empty string.
- std::string getSubject() {
- return ("");
+ virtual std::string getSubject() {
+ const std::vector<Botan::X509_Certificate>& cert_chain =
+ Base::native_handle()->peer_cert_chain();
+ if (cert_chain.empty()) {
+ return ("");
+ }
+ const Botan::X509_DN& subject = cert_chain[0].subject_dn();
+ return (subject.get_first_attribute("CommonName"));
}
/// @brief Return the commonName part of the issuerName of
@@ -155,16 +185,24 @@ public:
/// (the issue in PKIX terms). The idea is to encode a group as
/// members of an intermediate certification authority.
///
- ///
/// @return The commonName part of the issuerName or the empty string.
- std::string getIssuer() {
- return ("");
+ virtual std::string getIssuer() {
+ const std::vector<Botan::X509_Certificate>& cert_chain =
+ Base::native_handle()->peer_cert_chain();
+ if (cert_chain.empty()) {
+ return ("");
+ }
+ const Botan::X509_DN& issuer = cert_chain[0].issuer_dn();
+ return (issuer.get_first_attribute("CommonName"));
}
};
+// Stream truncated error code.
+const int STREAM_TRUNCATED = Botan::TLS::StreamError::StreamTruncated;
+
} // namespace asiolink
} // namespace isc
-#endif // WITH_BOTAN && !WITH_BOTAN_BOOST
+#endif // WITH_BOTAN
#endif // BOTAN_TLS_H
diff --git a/src/lib/asiolink/botan_boost_wrapper.h b/src/lib/asiolink/botan_wrapper.h
index e244bbb9cd..09d14838de 100644
--- a/src/lib/asiolink/botan_boost_wrapper.h
+++ b/src/lib/asiolink/botan_wrapper.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2021-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -6,12 +6,12 @@
// Do not include this header directly: use crypto_tls.h instead.
-#ifndef BOTAN_BOOST_WRAPPER_H
-#define BOTAN_BOOST_WRAPPER_H
+#ifndef BOTAN_WRAPPER_H
+#define BOTAN_WRAPPER_H
-/// @file botan_boost_wrapper.h Botan boost ASIO wrapper.
+/// @file botan_wrapper.h Botan ASIO wrapper.
-#if defined(WITH_BOTAN) && defined(WITH_BOTAN_BOOST)
+#ifdef WITH_BOTAN
/// The error classes do not define virtual destructors.
/// This workaround is taken from the boost header.
@@ -27,6 +27,6 @@
#pragma GCC diagnostic pop
#endif
-#endif // WITH_BOTAN && WITH_BOTAN_BOOST
+#endif // WITH_BOTAN
-#endif // BOTAN_BOOST_WRAPPER_H
+#endif // BOTAN_WRAPPER_H
diff --git a/src/lib/asiolink/crypto_tls.h b/src/lib/asiolink/crypto_tls.h
index c3e899febb..256c476707 100644
--- a/src/lib/asiolink/crypto_tls.h
+++ b/src/lib/asiolink/crypto_tls.h
@@ -15,7 +15,6 @@
#endif
// Include different versions.
-#include <asiolink/botan_boost_tls.h>
#include <asiolink/botan_tls.h>
#include <asiolink/openssl_tls.h>
diff --git a/src/lib/asiolink/tests/Makefile.am b/src/lib/asiolink/tests/Makefile.am
index e9e13d57aa..1ae8d05869 100644
--- a/src/lib/asiolink/tests/Makefile.am
+++ b/src/lib/asiolink/tests/Makefile.am
@@ -46,7 +46,7 @@ run_unittests_SOURCES += tls_unittest.cc
run_unittests_SOURCES += tls_acceptor_unittest.cc
run_unittests_SOURCES += tls_socket_unittest.cc
endif
-if HAVE_BOTAN_BOOST
+if HAVE_BOTAN
run_unittests_SOURCES += tls_unittest.cc
run_unittests_SOURCES += tls_acceptor_unittest.cc
run_unittests_SOURCES += tls_socket_unittest.cc
diff --git a/src/lib/asiolink/testutils/.gitignore b/src/lib/asiolink/testutils/.gitignore
index cc30b7cbc2..34750c0b49 100644
--- a/src/lib/asiolink/testutils/.gitignore
+++ b/src/lib/asiolink/testutils/.gitignore
@@ -1,4 +1,4 @@
-/botan_boost_sample_client
-/botan_boost_sample_server
+/botan_sample_client
+/botan_sample_server
/openssl_sample_client
/openssl_sample_server
diff --git a/src/lib/asiolink/testutils/Makefile.am b/src/lib/asiolink/testutils/Makefile.am
index cb06448a70..3bd402c8b4 100644
--- a/src/lib/asiolink/testutils/Makefile.am
+++ b/src/lib/asiolink/testutils/Makefile.am
@@ -75,19 +75,19 @@ openssl_sample_server_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS)
openssl_sample_server_LDADD = $(BOOST_LIBS) $(CRYPTO_LIBS)
endif
-if HAVE_BOTAN_BOOST
-# Same samples ported to Botan boost ASIO.
+if HAVE_BOTAN
+# Same samples ported to Botan ASIO.
-noinst_PROGRAMS = botan_boost_sample_client botan_boost_sample_server
+noinst_PROGRAMS = botan_sample_client botan_sample_server
-botan_boost_sample_client_SOURCES = botan_boost_sample_client.cc
-botan_boost_sample_client_CPPFLAGS = $(AM_CPPFLAGS)
-botan_boost_sample_client_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS)
-botan_boost_sample_client_LDADD = $(BOOST_LIBS) $(CRYPTO_LIBS)
+botan_sample_client_SOURCES = botan_sample_client.cc
+botan_sample_client_CPPFLAGS = $(AM_CPPFLAGS)
+botan_sample_client_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS)
+botan_sample_client_LDADD = $(BOOST_LIBS) $(CRYPTO_LIBS)
-botan_boost_sample_server_SOURCES = botan_boost_sample_server.cc
-botan_boost_sample_server_CPPFLAGS = $(AM_CPPFLAGS)
-botan_boost_sample_server_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS)
-botan_boost_sample_server_LDADD = $(BOOST_LIBS) $(CRYPTO_LIBS)
+botan_sample_server_SOURCES = botan_sample_server.cc
+botan_sample_server_CPPFLAGS = $(AM_CPPFLAGS)
+botan_sample_server_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS)
+botan_sample_server_LDADD = $(BOOST_LIBS) $(CRYPTO_LIBS)
endif
endif
diff --git a/src/lib/asiolink/testutils/botan_boost_sample_client.cc b/src/lib/asiolink/testutils/botan_sample_client.cc
index 16a83e8d2b..9e322fb543 100644
--- a/src/lib/asiolink/testutils/botan_boost_sample_client.cc
+++ b/src/lib/asiolink/testutils/botan_sample_client.cc
@@ -16,7 +16,7 @@
#include <iostream>
#include <asiolink/asio_wrapper.h>
-#include <asiolink/botan_boost_wrapper.h>
+#include <asiolink/botan_wrapper.h>
#include <botan/asio_stream.h>
#include <botan/certstor_flatfile.h>
#include <botan/pkcs8.h>
diff --git a/src/lib/asiolink/testutils/botan_boost_sample_server.cc b/src/lib/asiolink/testutils/botan_sample_server.cc
index 9d7e8c55b8..2d6be475ce 100644
--- a/src/lib/asiolink/testutils/botan_boost_sample_server.cc
+++ b/src/lib/asiolink/testutils/botan_sample_server.cc
@@ -15,7 +15,7 @@
#include <iostream>
#include <asiolink/asio_wrapper.h>
-#include <asiolink/botan_boost_wrapper.h>
+#include <asiolink/botan_wrapper.h>
#include <botan/asio_stream.h>
#include <botan/certstor_flatfile.h>
#include <botan/pkcs8.h>
diff --git a/src/lib/cryptolink/botan_common.h b/src/lib/cryptolink/botan_common.h
index 05cae30fbb..b617e78238 100644
--- a/src/lib/cryptolink/botan_common.h
+++ b/src/lib/cryptolink/botan_common.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -15,6 +15,13 @@ namespace btn {
const std::string
getHashAlgorithmName(isc::cryptolink::HashAlgorithm algorithm);
+/// @brief Decode the HashAlgorithm enum into a name usable by Botan
+///
+/// @param algorithm algorithm to be converted
+/// @return static text representation of the algorithm name
+const std::string
+getHmacAlgorithmName(isc::cryptolink::HashAlgorithm algorithm);
+
} // namespace btn
} // namespace cryptolink
} // namespace isc
diff --git a/src/lib/cryptolink/botan_hash.cc b/src/lib/cryptolink/botan_hash.cc
index 06dca6d05d..8859379a26 100644
--- a/src/lib/cryptolink/botan_hash.cc
+++ b/src/lib/cryptolink/botan_hash.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2020 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -9,9 +9,8 @@
#include <cryptolink.h>
#include <cryptolink/crypto_hash.h>
-#include <boost/scoped_ptr.hpp>
-
-#include <botan/lookup.h>
+#include <botan/hash.h>
+#include <botan/exceptn.h>
#include <cryptolink/botan_common.h>
@@ -51,12 +50,11 @@ public:
/// @param hash_algorithm The hash algorithm
explicit HashImpl(const HashAlgorithm hash_algorithm)
: hash_algorithm_(hash_algorithm), hash_() {
- Botan::HashFunction* hash;
try {
const std::string& name =
btn::getHashAlgorithmName(hash_algorithm);
- hash = Botan::HashFunction::create(name).release();
- } catch (const Botan::Algorithm_Not_Found&) {
+ hash_ = Botan::HashFunction::create_or_throw(name);
+ } catch (const Botan::Lookup_Error&) {
isc_throw(isc::cryptolink::UnsupportedAlgorithm,
"Unknown hash algorithm: " <<
static_cast<int>(hash_algorithm));
@@ -64,12 +62,10 @@ public:
isc_throw(isc::cryptolink::LibraryError,
"Botan error: " << exc.what());
}
-
- hash_.reset(hash);
}
/// @brief Destructor
- ~HashImpl() { }
+ ~HashImpl() = default;
/// @brief Returns the HashAlgorithm of the object
HashAlgorithm getHashAlgorithm() const {
@@ -153,7 +149,7 @@ private:
HashAlgorithm hash_algorithm_;
/// @brief The protected pointer to the Botan HashFunction object
- boost::scoped_ptr<Botan::HashFunction> hash_;
+ std::unique_ptr<Botan::HashFunction> hash_;
};
Hash::Hash(const HashAlgorithm hash_algorithm)
diff --git a/src/lib/cryptolink/botan_hmac.cc b/src/lib/cryptolink/botan_hmac.cc
index 88efb2efc0..14cb00f7e2 100644
--- a/src/lib/cryptolink/botan_hmac.cc
+++ b/src/lib/cryptolink/botan_hmac.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2011-2019 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2024 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -9,16 +9,37 @@
#include <cryptolink.h>
#include <cryptolink/crypto_hmac.h>
-#include <boost/scoped_ptr.hpp>
-
-#include <botan/hmac.h>
-#include <botan/lookup.h>
+#include <botan/mac.h>
+#include <botan/exceptn.h>
#include <cryptolink/botan_common.h>
namespace isc {
namespace cryptolink {
+const std::string
+btn::getHmacAlgorithmName(HashAlgorithm algorithm) {
+ switch (algorithm) {
+ case isc::cryptolink::MD5:
+ return ("HMAC(MD5)");
+ case isc::cryptolink::SHA1:
+ return ("HMAC(SHA-1)");
+ case isc::cryptolink::SHA256:
+ return ("HMAC(SHA-256)");
+ case isc::cryptolink::SHA224:
+ return ("HMAC(SHA-224)");
+ case isc::cryptolink::SHA384:
+ return ("HMAC(SHA-384)");
+ case isc::cryptolink::SHA512:
+ return ("HMAC(SHA-512)");
+ case isc::cryptolink::UNKNOWN_HASH:
+ return ("HMAC(Unknown)");
+ }
+ // compiler should have prevented us to reach this, since we have
+ // no default. But we need a return value anyway
+ return ("Unknown");
+}
+
/// @brief Botan implementation of HMAC. Each method is the counterpart
/// of the HMAC corresponding method.
class HMACImpl {
@@ -33,18 +54,11 @@ public:
explicit HMACImpl(const void* secret, size_t secret_len,
const HashAlgorithm hash_algorithm)
: hash_algorithm_(hash_algorithm), hmac_() {
- Botan::HashFunction* hash;
try {
const std::string& name =
- btn::getHashAlgorithmName(hash_algorithm);
- std::unique_ptr<Botan::HashFunction> hash_ptr =
- Botan::HashFunction::create(name);
- if (hash_ptr) {
- hash = hash_ptr.release();
- } else {
- throw Botan::Algorithm_Not_Found(name);
- }
- } catch (const Botan::Algorithm_Not_Found&) {
+ btn::getHmacAlgorithmName(hash_algorithm);
+ hmac_ = Botan::MessageAuthenticationCode::create_or_throw(name);
+ } catch (const Botan::Lookup_Error&) {
isc_throw(UnsupportedAlgorithm,
"Unknown hash algorithm: " <<
static_cast<int>(hash_algorithm));
@@ -52,28 +66,16 @@ public:
isc_throw(LibraryError, "Botan error: " << exc.what());
}
- hmac_.reset(new Botan::HMAC(hash));
-
// If the key length is larger than the block size, we hash the
// key itself first.
try {
- // use a temp var so we don't have blocks spanning
- // preprocessor directives
- size_t block_length = hash->hash_block_size();
- if (secret_len > block_length) {
- Botan::secure_vector<Botan::byte> hashed_key =
- hash->process(static_cast<const Botan::byte*>(secret),
- secret_len);
- hmac_->set_key(&hashed_key[0], hashed_key.size());
- } else {
- // Botan 1.8 considers len 0 a bad key. 1.9 does not,
- // but we won't accept it anyway, and fail early
- if (secret_len == 0) {
- isc_throw(BadKey, "Bad HMAC secret length: 0");
- }
- hmac_->set_key(static_cast<const Botan::byte*>(secret),
- secret_len);
+ // Botan 1.8 considers len 0 a bad key. 1.9 does not,
+ // but we won't accept it anyway, and fail early
+ if (secret_len == 0) {
+ isc_throw(BadKey, "Bad HMAC secret length: 0");
}
+ hmac_->set_key(static_cast<const Botan::byte*>(secret),
+ secret_len);
} catch (const Botan::Invalid_Key_Length& ikl) {
isc_throw(BadKey, ikl.what());
} catch (const Botan::Exception& exc) {
@@ -82,8 +84,7 @@ public:
}
/// @brief Destructor
- ~HMACImpl() {
- }
+ ~HMACImpl() = default;
/// @brief Returns the HashAlgorithm of the object
HashAlgorithm getHashAlgorithm() const {
@@ -177,9 +178,8 @@ public:
if (digest_.size() == 0) {
digest_ = hmac_->final();
}
- return (Botan::same_mem(&digest_[0],
- static_cast<const unsigned char*>(sig),
- len));
+ const uint8_t* sig8 = static_cast<const uint8_t*>(sig);
+ return (Botan::constant_time_compare(&digest_[0], sig8, len));
} catch (const Botan::Exception& exc) {
isc_throw(LibraryError, "Botan error: " << exc.what());
}
@@ -190,7 +190,7 @@ private:
HashAlgorithm hash_algorithm_;
/// @brief The protected pointer to the Botan HMAC object
- boost::scoped_ptr<Botan::HMAC> hmac_;
+ std::unique_ptr<Botan::MessageAuthenticationCode> hmac_;
/// @brief The digest cache for multiple verify
Botan::secure_vector<Botan::byte> digest_;
diff --git a/src/lib/http/tests/Makefile.am b/src/lib/http/tests/Makefile.am
index 232d6e2b0c..b2f629d671 100644
--- a/src/lib/http/tests/Makefile.am
+++ b/src/lib/http/tests/Makefile.am
@@ -54,7 +54,7 @@ libhttp_unittests_SOURCES += tls_response_creator_test.h
libhttp_unittests_SOURCES += tls_server_unittests.cc
libhttp_unittests_SOURCES += tls_client_unittests.cc
endif
-if HAVE_BOTAN_BOOST
+if HAVE_BOTAN
libhttp_unittests_SOURCES += tls_response_creator_test.h
libhttp_unittests_SOURCES += tls_server_unittests.cc
libhttp_unittests_SOURCES += tls_client_unittests.cc
diff --git a/src/lib/tcp/tests/Makefile.am b/src/lib/tcp/tests/Makefile.am
index 492c6272c7..422cf49c38 100644
--- a/src/lib/tcp/tests/Makefile.am
+++ b/src/lib/tcp/tests/Makefile.am
@@ -27,7 +27,7 @@ run_unittests_SOURCES += mt_tcp_listener_mgr_unittests.cc
if HAVE_OPENSSL
run_unittests_SOURCES += tls_listener_unittests.cc
endif
-if HAVE_BOTAN_BOOST
+if HAVE_BOTAN
run_unittests_SOURCES += tls_listener_unittests.cc
endif