diff --git a/src/lib/asiolink/Makefile.am b/src/lib/asiolink/Makefile.am index 232e072701..2d148f9e2c 100644 --- a/src/lib/asiolink/Makefile.am +++ b/src/lib/asiolink/Makefile.am @@ -17,6 +17,8 @@ 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_tls.h +libkea_asiolink_la_SOURCES += common_tls.h libkea_asiolink_la_SOURCES += crypto_tls.h libkea_asiolink_la_SOURCES += dummy_io_cb.h libkea_asiolink_la_SOURCES += interval_timer.cc interval_timer.h @@ -28,6 +30,7 @@ libkea_asiolink_la_SOURCES += io_error.h libkea_asiolink_la_SOURCES += io_service.h io_service.cc libkea_asiolink_la_SOURCES += io_service_signal.cc io_service_signal.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 @@ -41,10 +44,10 @@ libkea_asiolink_la_SOURCES += unix_domain_socket_acceptor.h libkea_asiolink_la_SOURCES += unix_domain_socket_endpoint.h if HAVE_BOTAN -#libkea_asiolink_la_SOURCES += botan_tls.cc botan_tls.h +#libkea_asiolink_la_SOURCES += botan_tls.cc endif if HAVE_OPENSSL -libkea_asiolink_la_SOURCES += openssl_tls.cc openssl_tls.h +libkea_asiolink_la_SOURCES += openssl_tls.cc endif # Note: the ordering matters: -Wno-... must follow -Wextra (defined in @@ -60,6 +63,8 @@ libkea_asiolink_include_HEADERS = \ addr_utilities.h \ asio_wrapper.h \ asiolink.h \ + botan_tls.h \ + common_tls.h \ crypto_tls.h \ dummy_io_cb.h \ interval_timer.h \ @@ -71,6 +76,7 @@ libkea_asiolink_include_HEADERS = \ io_service.h \ io_service_signal.h \ io_socket.h \ + openssl_tls.h \ process_spawn.h \ tcp_acceptor.h \ tcp_endpoint.h \ diff --git a/src/lib/asiolink/botan_tls.h b/src/lib/asiolink/botan_tls.h index 6065ab322b..7a260270ad 100644 --- a/src/lib/asiolink/botan_tls.h +++ b/src/lib/asiolink/botan_tls.h @@ -4,11 +4,18 @@ // 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_TLS_H #define BOTAN_TLS_H #ifdef WITH_BOTAN +#include +#include +#include +#include + namespace isc { namespace asiolink { diff --git a/src/lib/asiolink/common_tls.h b/src/lib/asiolink/common_tls.h new file mode 100644 index 0000000000..fb932de8b4 --- /dev/null +++ b/src/lib/asiolink/common_tls.h @@ -0,0 +1,170 @@ +// 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/. + +// Do not include this header directly: use crypto_tls.h instead. + +#ifndef COMMON_TLS_H +#define COMMON_TLS_H + +/// @file common_tls.h Common TLS API. + +// Verify that this file was not directly included. +#ifndef CRYPTO_TLS_H +#error crypto_tls.h must be included in place of common_tls.h +#endif + +#include + +#include +#include + +#include +#include + +namespace isc { +namespace asiolink { + +/// @brief Client and server roles. +enum TlsRole { CLIENT, SERVER }; + +/// @brief TLS context base class. +class TlsContextBase : private boost::noncopyable { +public: + /// @brief Destructor. + virtual ~TlsContextBase() { } + + /// @brief Create a fresh context. + /// + /// @param role The TLS role client or server. + explicit TlsContextBase(TlsRole role) : role_(role) { } + + /// @brief Returns the role. + TlsRole getRole() const { + return (role_); + } + + /// @note No need for a role set method. + + /// @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) = 0; + + /// @brief Get the peer certificate requirement mode. + /// + /// @return True if peer certificates are required, false if they + /// are optional. + virtual bool getCertRequired() const = 0; + + /// @brief Load the trust anchor aka certificate 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) = 0; + + /// @brief Load the trust anchor aka certificate 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) = 0; + + /// @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) = 0; + + /// @brief Load the private key file name. + /// + /// @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) = 0; + +public: + /// @brief The role i.e. client or server. + TlsRole role_; +}; + +/// @brief Forward declaration of OpenSSL TLS context. +class TlsContext; + +/// @brief The type of shared pointers to TlsContext objects. +/// +/// @note Not clear we need shared pointers but they covers more use cases... +typedef boost::shared_ptr TlsContextPtr; + +/// @brief TLS stream base class. +/// +/// @tparam Callback The type of callbacks. +/// @tparam TlsStreamImpl The type of underlying TLS streams. +/// @tparam TlsCertificate The type of X509 certificates. +template +class TlsStreamBase : public TlsStreamImpl { +public: + + /// @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. + TlsStreamBase(IOService& service, TlsContextPtr context); + + /// @brief Destructor. + virtual ~TlsStreamBase() { } + + /// @brief Returns the role. + TlsRole getRole() const { + return (role_); + } + + /// @brief TLS Handshake. + /// + /// @param callback Callback object. + virtual void handshake(Callback& callback) = 0; + + /// @brief TLS shutdown. + /// + /// @param callback Callback object. + virtual void shutdown(Callback& callback) = 0; + + /// @brief Clear the TLS state. + virtual void clear() = 0; + + /// @brief Return the peer certificate. + /// + /// @note The native_handle() method is used so it can't be made const. + /// @note Do not forget to free it when no longer used. + virtual TlsCertificate* getPeerCert() = 0; + + /// @break Return the commonName part of the subjectName of + /// the peer certificate. + /// + /// First commonName when there are more than one, in UTF-8. + /// + /// @return The commonName part of the subjectName or the empty string. + virtual std::string getSubject() = 0; + + /// @break Return the commonName part of the issuerName of + /// the peer certificate. + /// + /// First commonName when there are more than one, in UTF-8. + /// + /// @return The commonName part of the issuerName or the empty string. + virtual std::string getIssuer() = 0; + + /// @brief The role i.e. client or server. + TlsRole role_; +}; + +} // namespace asiolink +} // namespace isc + +#endif // COMMON_TLS_H diff --git a/src/lib/asiolink/crypto_tls.h b/src/lib/asiolink/crypto_tls.h index 42309ef41d..256c476707 100644 --- a/src/lib/asiolink/crypto_tls.h +++ b/src/lib/asiolink/crypto_tls.h @@ -7,86 +7,20 @@ #ifndef CRYPTO_TLS_H #define CRYPTO_TLS_H -#include +/// @file crypto_tls.h TLS API. -#include -#include +// Verify that config.h was included. +#ifndef CONFIG_H_WAS_INCLUDED +#error config.h must be included before crypto_tls.h +#endif -#include -#include +// Include different versions. +#include +#include -namespace isc { -namespace asiolink { - -/// @file crypto_tls.h Common TLS API. - -/// @brief Client and server roles. -enum TlsRole { CLIENT, SERVER }; - -/// @brief TLS context base class. -class TlsContextBase : private boost::noncopyable { -public: - /// @brief Destructor. - virtual ~TlsContextBase() { } - - /// @brief Create a fresh context. - /// - /// @param role The TLS role client or server. - explicit TlsContextBase(TlsRole role) : role_(role) { } - - /// @brief Returns the role. - TlsRole getRole() const { - return (role_); - } - - /// @note No need for a role set method. - - /// @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) = 0; - - /// @brief Get the peer certificate requirement mode. - /// - /// @return True if peer certificates are required, false if they - /// are optional. - virtual bool getCertRequired() const = 0; - - /// @brief Load the trust anchor aka certificate 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) = 0; - - /// @brief Load the trust anchor aka certificate 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) = 0; - - /// @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) = 0; - - /// @brief Load the private key file name. - /// - /// @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) = 0; - -public: - /// @brief The role i.e. client or server. - TlsRole role_; -}; - -} // namespace asiolink -} // namespace isc +// Verify that one version matched. +#ifndef COMMON_TLS_H +#error no TLS backend was found +#endif #endif // CRYPTO_TLS_H diff --git a/src/lib/asiolink/openssl_tls.cc b/src/lib/asiolink/openssl_tls.cc index 857ca4f5af..0eecfc099c 100644 --- a/src/lib/asiolink/openssl_tls.cc +++ b/src/lib/asiolink/openssl_tls.cc @@ -10,7 +10,6 @@ #include #include -#include #include diff --git a/src/lib/asiolink/openssl_tls.h b/src/lib/asiolink/openssl_tls.h index 7565fa13c0..3e11c4014f 100644 --- a/src/lib/asiolink/openssl_tls.h +++ b/src/lib/asiolink/openssl_tls.h @@ -4,28 +4,25 @@ // 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 OPENSSL_TLS_H #define OPENSSL_TLS_H +/// @file openssl_tls.h OpenSSL implementation of the TLS API. + #ifdef WITH_OPENSSL #include #include #include +#include #include namespace isc { namespace asiolink { -/// @brief Forward declaration of OpenSSL TLS context. -class TlsContext; - -/// @brief The type of shared pointers to TlsContext objects. -/// -/// @note Not clear we need shared pointers but they covers more use cases... -typedef boost::shared_ptr TlsContextPtr; - /// @brief OpenSSL TLS context. class TlsContext : public TlsContextBase { public: @@ -109,40 +106,50 @@ typedef boost::asio::ssl::stream TlsStreamImpl; /// @brief The type of X509 certificates. typedef ::X509 TlsCertificate; +/// @brief TlsStreamBase constructor. +/// @brief TLS stream base class. +/// +/// @param Callback The type of callbacks. +/// @param TlsStreamImpl The type of underlying TLS streams. +/// @param TlsCertificate The type of X509 certificates. +template +TlsStreamBase:: +TlsStreamBase(IOService& service, TlsContextPtr context) + : TlsStreamImpl(service.get_io_service(), context->getContext()), + role_(context->getRole()) { +} + /// @brief OpenSSL TLS stream. /// /// @param callback The callback. template -class TlsStream : public TlsStreamImpl { +class TlsStream : public TlsStreamBase { public: + /// @brief Type of the base. + typedef TlsStreamBase 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(IOService& service, TlsContextPtr context) - : TlsStreamImpl(service.get_io_service(), context->getContext()), - role_(context->getRole()) { + : Base(service, context) { } /// @brief Destructor. virtual ~TlsStream() { } - /// @brief Returns the role. - TlsRole getRole() const { - return (role_); - } - /// @brief TLS Handshake. /// /// @param callback Callback object. virtual void handshake(Callback& callback) { using namespace boost::asio::ssl; - if (role_ == SERVER) { - async_handshake(stream_base::server, callback); + if (Base::getRole() == SERVER) { + Base::async_handshake(stream_base::server, callback); } else { - async_handshake(stream_base::client, callback); + Base::async_handshake(stream_base::client, callback); } } @@ -150,7 +157,7 @@ public: /// /// @param callback Callback object. virtual void shutdown(Callback& callback) { - async_shutdown(callback); + Base::async_shutdown(callback); } /// @brief Clear the SSL object. @@ -166,16 +173,13 @@ public: return (::SSL_get_peer_certificate(this->native_handle())); } - /// @brief The role i.e. client or server. - TlsRole role_; - /// @break Return the commonName part of the subjectName of /// the peer certificate. /// /// First commonName when there are more than one, in UTF-8. /// /// @return The commonName part of the subjectName or the empty string. - std::string getSubject() { + virtual std::string getSubject() { TlsCertificate* cert = getPeerCert(); if (!cert) { return (""); @@ -205,7 +209,7 @@ public: /// First commonName when there are more than one, in UTF-8. /// /// @return The commonName part of the issuerName or the empty string. - std::string getIssuer() { + virtual std::string getIssuer() { TlsCertificate* cert = getPeerCert(); if (!cert) { return (""); @@ -230,7 +234,6 @@ public: } }; - } // namespace asiolink } // namespace isc diff --git a/src/lib/asiolink/tests/tls_unittest.cc b/src/lib/asiolink/tests/tls_unittest.cc index 78bb35bea5..e16d7aef71 100644 --- a/src/lib/asiolink/tests/tls_unittest.cc +++ b/src/lib/asiolink/tests/tls_unittest.cc @@ -9,8 +9,6 @@ #include #include #include -#include -#include #include #include #include diff --git a/src/lib/asiolink/testutils/test_tls.h b/src/lib/asiolink/testutils/test_tls.h index d761b296f2..3bd9fbcf10 100644 --- a/src/lib/asiolink/testutils/test_tls.h +++ b/src/lib/asiolink/testutils/test_tls.h @@ -12,8 +12,6 @@ #endif #include -#include -#include #include diff --git a/src/lib/asiolink/tls_socket.h b/src/lib/asiolink/tls_socket.h index c9f14104d5..0468788bc2 100644 --- a/src/lib/asiolink/tls_socket.h +++ b/src/lib/asiolink/tls_socket.h @@ -12,8 +12,6 @@ #endif #include -#include -#include #include #include