diff options
author | Jack Lloyd <[email protected]> | 2015-12-19 15:36:40 -0500 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2015-12-19 15:36:40 -0500 |
commit | b48e6fb097c62bb246629ee7a182c57e497e4130 (patch) | |
tree | 0cb8ea2d05a89f5e90467f323ae56268d4d3480e /src/cli/tls_server.cpp | |
parent | d774a9edc46ffcebb28205a678058f083ea75c28 (diff) |
CLI rewrite
The command line tools' origin as a collection of examples and test
programs glued together led to some unfortunate problems; lots of
hardcoded values, missing parameters, and obsolete crypto.
Adds a small library for writing command line programs of the sort
needed here (cli.h), which cuts the length of many of the commands in
half and makes commands more pleasant to write and extend.
Generalizes a lot of the commands also, eg previously only
signing/verification with DSA/SHA-1 was included!
Removes the fuzzer entry point since that's fairly useless outside of
an instrumented build.
Removes the in-library API for benchmarking.
Diffstat (limited to 'src/cli/tls_server.cpp')
-rw-r--r-- | src/cli/tls_server.cpp | 284 |
1 files changed, 130 insertions, 154 deletions
diff --git a/src/cli/tls_server.cpp b/src/cli/tls_server.cpp index ea68208b6..6a5b4e812 100644 --- a/src/cli/tls_server.cpp +++ b/src/cli/tls_server.cpp @@ -5,24 +5,15 @@ * Botan is released under the Simplified BSD License (see license.txt) */ -#include "apps.h" +#include "cli.h" #if defined(BOTAN_HAS_TLS) && defined(BOTAN_TARGET_OS_HAS_SOCKETS) #include <botan/tls_server.h> #include <botan/hex.h> - -#include <botan/rsa.h> -#include <botan/dsa.h> -#include <botan/x509self.h> -#include <botan/secqueue.h> - +#include <botan/auto_rng.h> #include "credentials.h" -using namespace Botan; - -using namespace std::placeholders; - #include <list> #include <sys/types.h> @@ -38,128 +29,44 @@ using namespace std::placeholders; #define MSG_NOSIGNAL 0 #endif -namespace { +namespace Botan_CLI { -int make_server_socket(bool is_tcp, u16bit port) +class TLS_Server : public Command { - const int type = is_tcp ? SOCK_STREAM : SOCK_DGRAM; - - int fd = ::socket(PF_INET, type, 0); - if(fd == -1) - throw std::runtime_error("Unable to acquire socket"); + public: + TLS_Server() : Command("tls_server cert key --port=443 --type=tcp") {} - sockaddr_in socket_info; - ::memset(&socket_info, 0, sizeof(socket_info)); - socket_info.sin_family = AF_INET; - socket_info.sin_port = htons(port); - - // FIXME: support limiting listeners - socket_info.sin_addr.s_addr = INADDR_ANY; - - if(::bind(fd, (sockaddr*)&socket_info, sizeof(struct sockaddr)) != 0) - { - ::close(fd); - throw std::runtime_error("server bind failed"); - } - - if(is_tcp) - { - if(::listen(fd, 100) != 0) + void go() override { - ::close(fd); - throw std::runtime_error("listen failed"); - } - } + const std::string server_crt = get_arg("cert"); + const std::string server_key = get_arg("key"); + const int port = get_arg_sz("port"); + const std::string transport = get_arg("type"); - return fd; - } + if(transport != "tcp" && transport != "udp") + throw CLI_Usage_Error("Invalid transport type '" + transport + "' for TLS"); -bool handshake_complete(const TLS::Session& session) - { - std::cout << "Handshake complete, " << session.version().to_string() - << " using " << session.ciphersuite().to_string() << std::endl; - - if(!session.session_id().empty()) - std::cout << "Session ID " << hex_encode(session.session_id()) << std::endl; + const bool is_tcp = (transport == "tcp"); - if(!session.session_ticket().empty()) - std::cout << "Session ticket " << hex_encode(session.session_ticket()) << std::endl; + Botan::AutoSeeded_RNG rng; - return true; - } - -void dgram_socket_write(int sockfd, const byte buf[], size_t length) - { - ssize_t sent = ::send(sockfd, buf, length, MSG_NOSIGNAL); + Botan::TLS::Policy policy; // TODO read policy from file - if(sent == -1) - std::cout << "Error writing to socket - " << strerror(errno) << std::endl; - else if(sent != static_cast<ssize_t>(length)) - std::cout << "Packet of length " << length << " truncated to " << sent << std::endl; - } + Botan::TLS::Session_Manager_In_Memory session_manager(rng); // TODO sqlite3 -void stream_socket_write(int sockfd, const byte buf[], size_t length) - { - while(length) - { - ssize_t sent = ::send(sockfd, buf, length, MSG_NOSIGNAL); + Basic_Credentials_Manager creds(rng, server_crt, server_key); - if(sent == -1) - { - if(errno == EINTR) - sent = 0; - else - throw std::runtime_error("Socket write failed"); - } + auto protocol_chooser = [](const std::vector<std::string>& protocols) -> std::string { + for(size_t i = 0; i != protocols.size(); ++i) + std::cout << "Client offered protocol " << i << " = " << protocols[i] << std::endl; + return "echo/1.0"; // too bad + }; - buf += sent; - length -= sent; - } - } + output() << "Listening for new connections on " << transport << " port " << port << std::endl; -void alert_received(TLS::Alert alert, const byte[], size_t) - { - std::cout << "Alert: " << alert.type_string() << std::endl; - } + int server_fd = make_server_socket(is_tcp, port); -int tls_server(const std::vector<std::string> &args) - { - if(args.size() != 4 && args.size() != 5) - { - std::cout << "Usage: " << args[0] << " server.crt server.key port [tcp|udp]" << std::endl; - return 1; - } - - const std::string server_crt = args[1]; - const std::string server_key = args[2]; - const int port = to_u32bit(args[3]); - const std::string transport = (args.size() >= 5) ? args[4] : "tcp"; - - const bool is_tcp = (transport == "tcp"); - - try - { - AutoSeeded_RNG rng; - - TLS::Policy policy; - - TLS::Session_Manager_In_Memory session_manager(rng); - - Basic_Credentials_Manager creds(rng, server_crt, server_key); - - auto protocol_chooser = [](const std::vector<std::string>& protocols) -> std::string { - for(size_t i = 0; i != protocols.size(); ++i) - std::cout << "Client offered protocol " << i << " = " << protocols[i] << std::endl; - return "echo/1.0"; // too bad - }; - - std::cout << "Listening for new connections on " << transport << " port " << port << std::endl; - - int server_fd = make_server_socket(is_tcp, port); - - while(true) - { - try + while(true) { int fd; @@ -180,42 +87,42 @@ int tls_server(const std::vector<std::string> &args) fd = server_fd; } - std::cout << "New connection received" << std::endl; + using namespace std::placeholders; - auto socket_write = is_tcp ? std::bind(stream_socket_write, fd, _1, _2) : - std::bind(dgram_socket_write, fd, _1, _2); + auto socket_write = is_tcp ? std::bind(&stream_socket_write, fd, _1, _2) : + std::bind(&dgram_socket_write, fd, _1, _2); std::string s; std::list<std::string> pending_output; - auto proc_fn = [&](const byte input[], size_t input_len) + 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') + for(size_t i = 0; i != input_len; ++i) { - pending_output.push_back(s); - s.clear(); + const char c = static_cast<char>(input[i]); + s += c; + if(c == '\n') + { + pending_output.push_back(s); + s.clear(); + } } - } }; - TLS::Server server(socket_write, - proc_fn, - alert_received, - handshake_complete, - session_manager, - creds, - policy, - rng, - protocol_chooser, - !is_tcp); + 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), + session_manager, + creds, + policy, + rng, + protocol_chooser, + !is_tcp); while(!server.is_closed()) { - byte buf[4*1024] = { 0 }; + uint8_t buf[4*1024] = { 0 }; ssize_t got = ::read(fd, buf, sizeof(buf)); if(got == -1) @@ -245,25 +152,94 @@ int tls_server(const std::vector<std::string> &args) if(is_tcp) ::close(fd); + } + } + private: + int make_server_socket(bool is_tcp, uint16_t port) + { + const int type = is_tcp ? SOCK_STREAM : SOCK_DGRAM; + + int fd = ::socket(PF_INET, type, 0); + if(fd == -1) + throw std::runtime_error("Unable to acquire socket"); + + sockaddr_in socket_info; + ::memset(&socket_info, 0, sizeof(socket_info)); + socket_info.sin_family = AF_INET; + socket_info.sin_port = htons(port); + + // FIXME: support limiting listeners + socket_info.sin_addr.s_addr = INADDR_ANY; + if(::bind(fd, (sockaddr*)&socket_info, sizeof(struct sockaddr)) != 0) + { + ::close(fd); + throw std::runtime_error("server bind failed"); + } + + if(is_tcp) + { + if(::listen(fd, 100) != 0) + { + ::close(fd); + throw std::runtime_error("listen failed"); + } } - catch(std::exception& e) + + return fd; + } + + bool handshake_complete(const Botan::TLS::Session& session) + { + std::cout << "Handshake complete, " << session.version().to_string() + << " using " << session.ciphersuite().to_string() << std::endl; + + if(!session.session_id().empty()) + std::cout << "Session ID " << Botan::hex_encode(session.session_id()) << std::endl; + + if(!session.session_ticket().empty()) + std::cout << "Session ticket " << Botan::hex_encode(session.session_ticket()) << std::endl; + + return true; + } + + static void dgram_socket_write(int sockfd, const uint8_t buf[], size_t length) + { + ssize_t sent = ::send(sockfd, buf, length, MSG_NOSIGNAL); + + if(sent == -1) + std::cout << "Error writing to socket - " << strerror(errno) << std::endl; + else if(sent != static_cast<ssize_t>(length)) + std::cout << "Packet of length " << length << " truncated to " << sent << std::endl; + } + + static void stream_socket_write(int sockfd, const uint8_t buf[], size_t length) + { + while(length) { - std::cout << "Connection problem: " << e.what() << std::endl; - return 1; + ssize_t sent = ::send(sockfd, buf, length, MSG_NOSIGNAL); + + if(sent == -1) + { + if(errno == EINTR) + sent = 0; + else + throw std::runtime_error("Socket write failed"); + } + + buf += sent; + length -= sent; } } - } - catch(std::exception& e) - { - std::cout << e.what() << std::endl; - return 1; - } - return 0; - } + void alert_received(Botan::TLS::Alert alert, const uint8_t[], size_t) + { + std::cout << "Alert: " << alert.type_string() << std::endl; + } + + }; -REGISTER_APP(tls_server); +BOTAN_REGISTER_COMMAND(TLS_Server); } |