aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2017-12-23 10:12:50 -0500
committerJack Lloyd <[email protected]>2017-12-23 10:12:50 -0500
commit726e54725110bc7ef2bf115731074dd11bd229ec (patch)
treef322c1759cd0c3058d5bc8c4e6d7fc616c5c6438 /src
parentd79347f0ffbc4e5f102531f0d0d3f703a64b55b2 (diff)
parent2d719e51266408bd08f14880d2399c671cbc8a7b (diff)
Merge GH #1371 Add socket helpers, convert tls_server to new API
Diffstat (limited to 'src')
-rw-r--r--src/cli/socket_utils.h81
-rw-r--r--src/cli/tls_client.cpp58
-rw-r--r--src/cli/tls_server.cpp196
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);