diff options
-rw-r--r-- | src/cli/socket_utils.h | 81 | ||||
-rw-r--r-- | src/cli/tls_client.cpp | 58 | ||||
-rw-r--r-- | src/cli/tls_server.cpp | 196 |
3 files changed, 159 insertions, 176 deletions
diff --git a/src/cli/socket_utils.h b/src/cli/socket_utils.h new file mode 100644 index 000000000..a8e2a51a6 --- /dev/null +++ b/src/cli/socket_utils.h @@ -0,0 +1,81 @@ +/* +* (C) 2014,2017 Jack Lloyd +* 2017 René Korthaus, Rohde & Schwarz Cybersecurity +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#ifndef BOTAN_SOCKET_H_ +#define BOTAN_SOCKET_H_ + +#include <botan/build.h> +#include "cli_exceptions.h" + +#if defined(BOTAN_TARGET_OS_IS_WINDOWS) + +#include <winsock2.h> +#include <WS2tcpip.h> + +typedef size_t ssize_t; + +#define STDIN_FILENO _fileno(stdin) + +inline void init_sockets() + { + WSAData wsa_data; + WORD wsa_version = MAKEWORD(2, 2); + + if(::WSAStartup(wsa_version, &wsa_data) != 0) + { + throw Botan_CLI::CLI_Error("WSAStartup() failed: " + std::to_string(WSAGetLastError())); + } + + if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) + { + ::WSACleanup(); + throw Botan_CLI::CLI_Error("Could not find a usable version of Winsock.dll"); + } + } + +inline void stop_sockets() + { + ::WSACleanup(); + } + +inline int close(int fd) + { + return ::closesocket(fd); + } + +inline int read(int s, void* buf, size_t len) + { + return ::recv(s, reinterpret_cast<char*>(buf), static_cast<int>(len), 0); + } + +inline int send(int s, const uint8_t* buf, size_t len, int flags) + { + return ::send(s, reinterpret_cast<const char*>(buf), static_cast<int>(len), flags); + } + +#else + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netdb.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +inline void init_sockets() {} +inline void stop_sockets() {} + +#endif + +#if !defined(MSG_NOSIGNAL) + #define MSG_NOSIGNAL 0 +#endif + +#endif diff --git a/src/cli/tls_client.cpp b/src/cli/tls_client.cpp index 8adc90139..ddc443614 100644 --- a/src/cli/tls_client.cpp +++ b/src/cli/tls_client.cpp @@ -25,43 +25,7 @@ #include <string> #include <memory> -#if defined(BOTAN_TARGET_OS_IS_WINDOWS) -#include <winsock2.h> -#include <WS2tcpip.h> - -int close(int fd) - { - return ::closesocket(fd); - } - -int read(int s, void* buf, size_t len) - { - return ::recv(s, reinterpret_cast<char*>(buf), static_cast<int>(len), 0); - } - -int send(int s, const uint8_t* buf, size_t len, int flags) - { - return ::send(s, reinterpret_cast<const char*>(buf), static_cast<int>(len), flags); - } - -#define STDIN_FILENO _fileno(stdin) -typedef size_t ssize_t; -#else -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#endif - -#if !defined(MSG_NOSIGNAL) - #define MSG_NOSIGNAL 0 -#endif - +#include "socket_utils.h" #include "credentials.h" namespace Botan_CLI { @@ -74,28 +38,12 @@ class TLS_Client final : public Command, public Botan::TLS::Callbacks "--tls1.0 --tls1.1 --tls1.2 " "--session-db= --session-db-pass= --next-protocols= --type=tcp") { -#if defined(BOTAN_TARGET_OS_IS_WINDOWS) - WSAData wsa_data; - WORD wsa_version = MAKEWORD(2, 2); - - if(::WSAStartup(wsa_version, &wsa_data) != 0) - { - throw CLI_Error("WSAStartup() failed: " + std::to_string(WSAGetLastError())); - } - - if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) - { - ::WSACleanup(); - throw CLI_Error("Could not find a usable version of Winsock.dll"); - } -#endif + init_sockets(); } ~TLS_Client() { -#if defined(BOTAN_TARGET_OS_IS_WINDOWS) - ::WSACleanup(); -#endif + stop_sockets(); } void go() override diff --git a/src/cli/tls_server.cpp b/src/cli/tls_server.cpp index 02c15bf7b..44c69bf17 100644 --- a/src/cli/tls_server.cpp +++ b/src/cli/tls_server.cpp @@ -14,65 +14,26 @@ #include <botan/tls_policy.h> #include <botan/hex.h> #include <botan/internal/os_utils.h> -#include "credentials.h" #include <list> #include <fstream> -#if defined(BOTAN_TARGET_OS_IS_WINDOWS) -#include <winsock2.h> -#include <WS2tcpip.h> - -// definitions in tls_client.cpp -int close(int fd); -int read(int s, void* buf, size_t len); -int send(int s, const uint8_t* buf, size_t len, int flags); - -typedef size_t ssize_t; -#else -#include <sys/types.h> -#include <sys/time.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <netdb.h> -#include <unistd.h> -#include <errno.h> -#include <fcntl.h> -#endif - -#if !defined(MSG_NOSIGNAL) - #define MSG_NOSIGNAL 0 -#endif +#include "credentials.h" +#include "socket_utils.h" namespace Botan_CLI { -class TLS_Server final : public Command +class TLS_Server final : public Command, public Botan::TLS::Callbacks { public: TLS_Server() : Command("tls_server cert key --port=443 --type=tcp --policy= --dump-traces=") { -#if defined(BOTAN_TARGET_OS_IS_WINDOWS) - WSAData wsa_data; - WORD wsa_version = MAKEWORD(2, 2); - - if(::WSAStartup(wsa_version, &wsa_data) != 0) - { - throw CLI_Error("WSAStartup() failed: " + std::to_string(WSAGetLastError())); - } - - if(LOBYTE(wsa_data.wVersion) != 2 || HIBYTE(wsa_data.wVersion) != 2) - { - ::WSACleanup(); - throw CLI_Error("Could not find a usable version of Winsock.dll"); - } -#endif + init_sockets(); } ~TLS_Server() { -#if defined(BOTAN_TARGET_OS_IS_WINDOWS) - ::WSACleanup(); -#endif + stop_sockets(); } void go() override @@ -88,7 +49,7 @@ class TLS_Server final : public Command throw CLI_Usage_Error("Invalid transport type '" + transport + "' for TLS"); } - const bool is_tcp = (transport == "tcp"); + m_is_tcp = (transport == "tcp"); std::unique_ptr<Botan::TLS::Policy> policy; const std::string policy_file = get_arg("policy"); @@ -112,23 +73,15 @@ class TLS_Server final : public Command Basic_Credentials_Manager creds(rng(), server_crt, server_key); - auto protocol_chooser = [](const std::vector<std::string>&) -> std::string - { - // we ignore whatever the client sends here - return "echo/1.0"; - }; - output() << "Listening for new connections on " << transport << " port " << port << std::endl; - int server_fd = make_server_socket(is_tcp, port); + int server_fd = make_server_socket(port); while(true) { - int fd; - - if(is_tcp) + if(m_is_tcp) { - fd = ::accept(server_fd, nullptr, nullptr); + m_socket = ::accept(server_fd, nullptr, nullptr); } else { @@ -144,43 +97,16 @@ class TLS_Server final : public Command { throw CLI_Error("Could not connect UDP socket"); } - fd = server_fd; + m_socket = server_fd; } - using namespace std::placeholders; - - auto socket_write = is_tcp ? - std::bind(&TLS_Server::stream_socket_write, this, fd, _1, _2) : - std::bind(&TLS_Server::dgram_socket_write, this, fd, _1, _2); - - std::string s; - std::list<std::string> pending_output; - - auto proc_fn = [&](const uint8_t input[], size_t input_len) - { - for(size_t i = 0; i != input_len; ++i) - { - const char c = static_cast<char>(input[i]); - s += c; - if(c == '\n') - { - pending_output.push_back(s); - s.clear(); - } - } - }; - Botan::TLS::Server server( - socket_write, - proc_fn, - std::bind(&TLS_Server::alert_received, this, _1, _2, _3), - std::bind(&TLS_Server::handshake_complete, this, _1), + *this, session_manager, creds, *policy, rng(), - protocol_chooser, - !is_tcp); + m_is_tcp == false); std::unique_ptr<std::ostream> dump_stream; @@ -199,7 +125,7 @@ class TLS_Server final : public Command try { uint8_t buf[4 * 1024] = { 0 }; - ssize_t got = ::read(fd, buf, sizeof(buf)); + ssize_t got = ::read(m_socket, buf, sizeof(buf)); if(got == -1) { @@ -220,10 +146,10 @@ class TLS_Server final : public Command server.received_data(buf, got); - while(server.is_active() && !pending_output.empty()) + while(server.is_active() && !m_pending_output.empty()) { - std::string output = pending_output.front(); - pending_output.pop_front(); + std::string output = m_pending_output.front(); + m_pending_output.pop_front(); server.send(output); if(output == "quit\n") @@ -235,9 +161,10 @@ class TLS_Server final : public Command catch(std::exception& e) { error_output() << "Connection problem: " << e.what() << std::endl; - if(is_tcp) + if(m_is_tcp) { - ::close(fd); + ::close(m_socket); + m_socket = -1; } } } @@ -247,16 +174,17 @@ class TLS_Server final : public Command error_output() << "Connection failed: " << e.what() << "\n"; } - if(is_tcp) + if(m_is_tcp) { - ::close(fd); + ::close(m_socket); + m_socket = -1; } } } private: - int make_server_socket(bool is_tcp, uint16_t port) + int make_server_socket(uint16_t port) { - const int type = is_tcp ? SOCK_STREAM : SOCK_DGRAM; + const int type = m_is_tcp ? SOCK_STREAM : SOCK_DGRAM; int fd = ::socket(PF_INET, type, 0); if(fd == -1) @@ -278,7 +206,7 @@ class TLS_Server final : public Command throw CLI_Error("server bind failed"); } - if(is_tcp) + if(m_is_tcp) { if(::listen(fd, 100) != 0) { @@ -289,7 +217,7 @@ class TLS_Server final : public Command return fd; } - bool handshake_complete(const Botan::TLS::Session& session) + bool tls_session_established(const Botan::TLS::Session& session) override { output() << "Handshake complete, " << session.version().to_string() << " using " << session.ciphersuite().to_string() << std::endl; @@ -307,48 +235,74 @@ class TLS_Server final : public Command return true; } - void dgram_socket_write(int sockfd, const uint8_t buf[], size_t length) + void tls_record_received(uint64_t, const uint8_t input[], size_t input_len) override { - ssize_t sent = ::send(sockfd, buf, length, MSG_NOSIGNAL); - - if(sent == -1) - { - error_output() << "Error writing to socket - " << std::strerror(errno) << std::endl; - } - else if(sent != static_cast<ssize_t>(length)) + for(size_t i = 0; i != input_len; ++i) { - error_output() << "Packet of length " << length << " truncated to " << sent << std::endl; + const char c = static_cast<char>(input[i]); + m_line_buf += c; + if(c == '\n') + { + m_pending_output.push_back(m_line_buf); + m_line_buf.clear(); + } } - } + }; - void stream_socket_write(int sockfd, const uint8_t buf[], size_t length) + void tls_emit_data(const uint8_t buf[], size_t length) override { - while(length) + if(m_is_tcp) { - ssize_t sent = ::send(sockfd, buf, length, MSG_NOSIGNAL); + ssize_t sent = ::send(m_socket, buf, length, MSG_NOSIGNAL); if(sent == -1) { - if(errno == EINTR) - { - sent = 0; - } - else + error_output() << "Error writing to socket - " << std::strerror(errno) << std::endl; + } + else if(sent != static_cast<ssize_t>(length)) + { + error_output() << "Packet of length " << length << " truncated to " << sent << std::endl; + } + } + else + { + while(length) + { + ssize_t sent = ::send(m_socket, buf, length, MSG_NOSIGNAL); + + if(sent == -1) { - throw CLI_Error("Socket write failed"); + if(errno == EINTR) + { + sent = 0; + } + else + { + throw CLI_Error("Socket write failed"); + } } - } - buf += sent; - length -= sent; + buf += sent; + length -= sent; + } } } - void alert_received(Botan::TLS::Alert alert, const uint8_t[], size_t) + void tls_alert(Botan::TLS::Alert alert) override { output() << "Alert: " << alert.type_string() << std::endl; } + std::string tls_server_choose_app_protocol(const std::vector<std::string>&) override + { + // we ignore whatever the client sends here + return "echo/0.1"; + } + + int m_socket = -1; + bool m_is_tcp = false; + std::string m_line_buf; + std::list<std::string> m_pending_output; }; BOTAN_REGISTER_COMMAND("tls_server", TLS_Server); |