diff options
author | lloyd <[email protected]> | 2015-01-11 02:30:20 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2015-01-11 02:30:20 +0000 |
commit | e330e8d66faa0faa0c427acbb7ce42eefe06bd08 (patch) | |
tree | db0027da3cfc3c82e7655ab3ae649de9218102a8 /src/cmd | |
parent | 74522169a907715d4d41b3680f20b6f866733de7 (diff) |
Have TLS server take certificate and key from command line
Diffstat (limited to 'src/cmd')
-rw-r--r-- | src/cmd/credentials.h | 303 | ||||
-rw-r--r-- | src/cmd/tls_client.cpp | 4 | ||||
-rw-r--r-- | src/cmd/tls_proxy.cpp | 154 | ||||
-rw-r--r-- | src/cmd/tls_server.cpp | 53 |
4 files changed, 119 insertions, 395 deletions
diff --git a/src/cmd/credentials.h b/src/cmd/credentials.h index c67fe22e3..b5ee701f3 100644 --- a/src/cmd/credentials.h +++ b/src/cmd/credentials.h @@ -27,277 +27,134 @@ inline bool value_exists(const std::vector<std::string>& vec, return false; } -class Credentials_Manager_Simple : public Botan::Credentials_Manager +class Basic_Credentials_Manager : public Credentials_Manager { public: - Credentials_Manager_Simple(Botan::RandomNumberGenerator& rng) : - rng(rng) + Basic_Credentials_Manager() { - try - { - m_certstores.push_back(new Botan::Certificate_Store_In_Memory("/usr/share/ca-certificates")); - } - catch(...) {} + } - std::string srp_identifier(const std::string& type, - const std::string& hostname) + Basic_Credentials_Manager(RandomNumberGenerator& rng, + const std::string& server_crt, + const std::string& server_key) { - if(type == "tls-client" && hostname == "srp-host") - return "user"; - return ""; + Certificate_Info cert; + + cert.key.reset(PKCS8::load_key(server_key, rng)); + + DataSource_Stream in(server_crt); + while(!in.end_of_data()) + { + try + { + cert.certs.push_back(X509_Certificate(in)); + } + catch(std::exception& e) + { + + } + } + + // TODO: attempt to validate chain ourselves + + m_creds.push_back(cert); } - bool attempt_srp(const std::string& type, - const std::string& hostname) + void load_certstores() { - if(hostname == "srp-host" && (type == "tls-client" || type == "tls-server")) - return true; - return false; + try + { + // TODO: make path configurable + const std::vector<std::string> paths = { "/usr/share/ca-certificates" }; + + for(auto&& path : paths) + { + std::shared_ptr<Certificate_Store> cs(new Certificate_Store_In_Memory(path)); + m_certstores.push_back(cs); + } + } + catch(std::exception& e) + { + //std::cout << e.what() << "\n"; + } } std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(const std::string& type, const std::string& /*hostname*/) { - // don't ask for client cert + std::vector<Botan::Certificate_Store*> v; + + // don't ask for client certs if(type == "tls-server") - return std::vector<Botan::Certificate_Store*>(); + return v; - return m_certstores; + for(auto&& cs : m_certstores) + v.push_back(cs.get()); + + return v; } void verify_certificate_chain( const std::string& type, const std::string& purported_hostname, - const std::vector<Botan::X509_Certificate>& cert_chain) + const std::vector<X509_Certificate>& cert_chain) { try { - Botan::Credentials_Manager::verify_certificate_chain(type, - purported_hostname, - cert_chain); + Credentials_Manager::verify_certificate_chain(type, + purported_hostname, + cert_chain); } catch(std::exception& e) { - std::cout << "Certificate verification failed - " << e.what() << " - but will ignore\n"; + std::cout << e.what() << "\n"; + //throw; } } - std::string srp_password(const std::string& type, - const std::string& hostname, - const std::string& identifier) - { - if(type == "tls-client" && hostname == "srp-host" && identifier == "user") - return "password"; - - return ""; - } - - bool srp_verifier(const std::string& /*type*/, - const std::string& context, - const std::string& identifier, - std::string& group_id, - Botan::BigInt& verifier, - std::vector<Botan::byte>& salt, - bool generate_fake_on_unknown) + std::vector<X509_Certificate> cert_chain( + const std::vector<std::string>& algos, + const std::string& type, + const std::string& hostname) { - - std::string pass = srp_password("tls-client", context, identifier); - if(pass == "") + for(auto&& i : m_creds) { - if(!generate_fake_on_unknown) - return false; - - pass.resize(16); - rng.randomize(reinterpret_cast<byte*>(&pass[0]), pass.size()); - } - - group_id = "modp/srp/2048"; - - salt.resize(16); - rng.randomize(&salt[0], salt.size()); + if(std::find(algos.begin(), algos.end(), i.key->algo_name()) == algos.end()) + continue; - verifier = Botan::generate_srp6_verifier(identifier, - pass, - salt, - group_id, - "SHA-1"); + if(hostname != "" && !i.certs[0].matches_dns_name(hostname)) + continue; - return true; - } - - std::string psk_identity_hint(const std::string&, - const std::string&) - { - return ""; - } - - std::string psk_identity(const std::string&, const std::string&, - const std::string& identity_hint) - { - std::cout << "Server sent PSK identity_hint " << identity_hint << "\n"; - return "Client_identity"; - } - - Botan::SymmetricKey psk(const std::string& type, const std::string& context, - const std::string& identity) - { - if(type == "tls-server" && context == "session-ticket") - { - if(session_ticket_key.length() == 0) - session_ticket_key = Botan::SymmetricKey(rng, 32); - return session_ticket_key; + return i.certs; } - if(identity == "Client_identity") - return Botan::SymmetricKey("b5a72e1387552e6dc10766dc0eda12961f5b21e17f98ef4c41e6572e53bd7527"); - if(identity == "lloyd") - return Botan::SymmetricKey("85b3c1b7dc62b507636ac767999c9630"); - - throw Botan::Internal_Error("No PSK set for " + identity); + return std::vector<X509_Certificate>(); } - std::pair<Botan::X509_Certificate,Botan::Private_Key*> - load_or_make_cert(const std::string& hostname, - const std::string& key_type, - Botan::RandomNumberGenerator& rng) + Private_Key* private_key_for(const X509_Certificate& cert, + const std::string& /*type*/, + const std::string& /*context*/) { - using namespace Botan; - - const std::string key_fsname_prefix = hostname + "." + key_type + "."; - const std::string key_file_name = key_fsname_prefix + "key"; - const std::string cert_file_name = key_fsname_prefix + "crt"; - - try + for(auto&& i : m_creds) { - X509_Certificate cert(cert_file_name); - Private_Key* key = PKCS8::load_key(key_file_name, rng); - - //std::cout << "Loaded existing key/cert from " << cert_file_name << " and " << key_file_name << "\n"; - - return std::make_pair(cert, key); + if(cert == i.certs[0]) + return i.key.get(); } - catch(...) {} - - // Failed. Instead, make a new one - - std::cout << "Creating new certificate for identifier '" << hostname << "'\n"; - - X509_Cert_Options opts; - - opts.common_name = hostname; - opts.country = "US"; - opts.email = "root@" + hostname; - opts.dns = hostname; - - std::unique_ptr<Private_Key> key; - if(key_type == "rsa") - key.reset(new RSA_PrivateKey(rng, 1024)); - else if(key_type == "dsa") - key.reset(new DSA_PrivateKey(rng, DL_Group("dsa/jce/1024"))); - else if(key_type == "ecdsa") - key.reset(new ECDSA_PrivateKey(rng, EC_Group("secp256r1"))); - else - throw std::runtime_error("Don't know what to do about key type '" + key_type + "'"); - - X509_Certificate cert = - X509::create_self_signed_cert(opts, *key, "SHA-1", rng); - - // Now save both - std::cout << "Saving new " << key_type << " key to " << key_file_name << "\n"; - std::ofstream key_file(key_file_name.c_str()); - key_file << PKCS8::PEM_encode(*key, rng, ""); - key_file.close(); - - std::cout << "Saving new " << key_type << " cert to " << key_file_name << "\n"; - std::ofstream cert_file(cert_file_name.c_str()); - cert_file << cert.PEM_encode() << "\n"; - cert_file.close(); - - return std::make_pair(cert, key.release()); + return nullptr; } - std::vector<Botan::X509_Certificate> cert_chain( - const std::vector<std::string>& cert_key_types, - const std::string& type, - const std::string& context) + private: + struct Certificate_Info { - using namespace Botan; - std::vector<X509_Certificate> certs; + std::shared_ptr<Private_Key> key; + }; - try - { - if(type == "tls-server") - { - const std::string hostname = (context == "" ? "localhost" : context); - - if(hostname == "nosuchname") - return std::vector<Botan::X509_Certificate>(); - - for(auto i : certs_and_keys) - { - if(hostname != "" && !i.first.matches_dns_name(hostname)) - continue; - - if(!value_exists(cert_key_types, i.second->algo_name())) - continue; - - certs.push_back(i.first); - } - - if(!certs.empty()) - return certs; - - std::string key_name = ""; - - if(value_exists(cert_key_types, "RSA")) - key_name = "rsa"; - else if(value_exists(cert_key_types, "DSA")) - key_name = "dsa"; - else if(value_exists(cert_key_types, "ECDSA")) - key_name = "ecdsa"; - - std::pair<X509_Certificate, Private_Key*> cert_and_key = - load_or_make_cert(hostname, key_name, rng); - - certs_and_keys[cert_and_key.first] = cert_and_key.second; - certs.push_back(cert_and_key.first); - } - else if(type == "tls-client") - { - X509_Certificate cert("user-rsa.crt"); - Private_Key* key = PKCS8::load_key("user-rsa.key", rng); - - certs_and_keys[cert] = key; - certs.push_back(cert); - } - } - catch(std::exception& e) - { - std::cout << e.what() << "\n"; - } - - return certs; - } - - Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert, - const std::string& /*type*/, - const std::string& /*context*/) - { - return certs_and_keys[cert]; - } - - private: - Botan::RandomNumberGenerator& rng; - - Botan::SymmetricKey session_ticket_key; - - std::map<Botan::X509_Certificate, Botan::Private_Key*> certs_and_keys; - - std::vector<Botan::Certificate_Store*> m_certstores; + std::vector<Certificate_Info> m_creds; + std::vector<std::shared_ptr<Certificate_Store>> m_certstores; }; #endif diff --git a/src/cmd/tls_client.cpp b/src/cmd/tls_client.cpp index d10c46ba4..74607469f 100644 --- a/src/cmd/tls_client.cpp +++ b/src/cmd/tls_client.cpp @@ -6,7 +6,7 @@ #include "apps.h" -#if defined(BOTAN_HAS_TLS) +#if defined(BOTAN_HAS_TLS) && !defined(BOTAN_TARGET_OS_IS_WINDOWS) #include <botan/tls_client.h> #include <botan/pkcs8.h> #include <botan/hex.h> @@ -161,7 +161,7 @@ int tls_client(int argc, char* argv[]) TLS::Session_Manager_In_Memory session_manager(rng); #endif - Credentials_Manager_Simple creds(rng); + Basic_Credentials_Manager creds; std::string host = argv[1]; u32bit port = argc >= 3 ? Botan::to_u32bit(argv[2]) : 443; diff --git a/src/cmd/tls_proxy.cpp b/src/cmd/tls_proxy.cpp index 867e2280e..94ce28636 100644 --- a/src/cmd/tls_proxy.cpp +++ b/src/cmd/tls_proxy.cpp @@ -29,23 +29,25 @@ #include <botan/tls_session_manager_sqlite.h> #endif +#include "credentials.h" + using boost::asio::ip::tcp; namespace Botan { namespace { -void log_exception(const char* where, const std::exception& e) +inline void log_exception(const char* where, const std::exception& e) { std::cout << where << ' ' << e.what() << std::endl; } -void log_error(const char* where, const boost::system::error_code& error) +inline void log_error(const char* where, const boost::system::error_code& error) { std::cout << where << ' ' << error.message() << std::endl; } -void log_binary_message(const char* where, const byte buf[], size_t buf_len) +inline void log_binary_message(const char* where, const byte buf[], size_t buf_len) { //std::cout << where << ' ' << hex_encode(buf, buf_len) << std::endl; } @@ -167,12 +169,13 @@ class tls_proxy_session : public boost::enable_shared_from_this<tls_proxy_sessio } m_p2s.clear(); - tls_proxy_write_to_server(nullptr, 0); // initiate another write if needed + proxy_write_to_server(nullptr, 0); // initiate another write if needed } void tls_client_write_to_proxy(const byte buf[], size_t buf_len) { - tls_proxy_write_to_server(buf, buf_len); + // Immediately bounce message to server + proxy_write_to_server(buf, buf_len); } void tls_proxy_write_to_client(const byte buf[], size_t buf_len) @@ -197,7 +200,7 @@ class tls_proxy_session : public boost::enable_shared_from_this<tls_proxy_sessio } } - void tls_proxy_write_to_server(const byte buf[], size_t buf_len) + void proxy_write_to_server(const byte buf[], size_t buf_len) { if(buf_len > 0) m_p2s_pending.insert(m_p2s_pending.end(), buf, buf + buf_len); @@ -271,11 +274,9 @@ class tls_proxy_session : public boost::enable_shared_from_this<tls_proxy_sessio log_error("Server connection", ec); return; } - //std::cout << "Connected to " << endpoint->host_name() << ' ' - //<< endpoint->service_name() << "\n"; - tls_proxy_write_to_server(nullptr, 0); server_read(boost::system::error_code(), 0); // start read loop + proxy_write_to_server(nullptr, 0); }); return true; } @@ -392,139 +393,6 @@ size_t choose_thread_count() return 2; } -class Proxy_Credentials_Manager : public Credentials_Manager - { - public: - Proxy_Credentials_Manager(RandomNumberGenerator& rng, - const std::string& server_crt, - const std::string& server_key) - { - try - { - Certificate_Info cert; - - - try - { - cert.key.reset(PKCS8::load_key(server_key, rng)); - } - catch(std::exception& e) - { - log_exception("Loading server key", e); - throw; // fatal - } - - try - { - DataSource_Stream in(server_crt); - while(!in.end_of_data()) - cert.certs.push_back(X509_Certificate(in)); - } - catch(std::exception& e) - { - log_exception("Loading certs", e); - } - - // TODO: attempt to validate chain ourselves - - m_creds.push_back(cert); - } - catch(std::exception& e) - { - log_exception("Loading server key", e); - throw; // fatal - } - - try - { - // TODO: make path configurable - std::shared_ptr<Certificate_Store> cs(new Certificate_Store_In_Memory("/usr/share/ca-certificates")); - m_certstores.push_back(cs); - } - catch(std::exception& e) - { - log_exception("Loading CA certs", e); - //throw; // not fatal - } - } - - std::vector<Botan::Certificate_Store*> - trusted_certificate_authorities(const std::string& type, - const std::string& /*hostname*/) - { - std::vector<Botan::Certificate_Store*> v; - - // don't ask for client certs - if(type == "tls-server") - return v; - - for(auto&& cs : m_certstores) - v.push_back(cs.get()); - - return v; - } - - void verify_certificate_chain( - const std::string& type, - const std::string& purported_hostname, - const std::vector<X509_Certificate>& cert_chain) - { - try - { - Credentials_Manager::verify_certificate_chain(type, - purported_hostname, - cert_chain); - } - catch(std::exception& e) - { - std::cout << "Certificate validation failure: " << e.what() << "\n"; - throw; - } - } - - std::vector<X509_Certificate> cert_chain( - const std::vector<std::string>& algos, - const std::string& type, - const std::string& hostname) - { - for(auto&& i : m_creds) - { - if(std::find(algos.begin(), algos.end(), i.key->algo_name()) == algos.end()) - continue; - - if(hostname != "" && !i.certs[0].matches_dns_name(hostname)) - continue; - - return i.certs; - } - - return std::vector<X509_Certificate>(); - } - - Private_Key* private_key_for(const X509_Certificate& cert, - const std::string& /*type*/, - const std::string& /*context*/) - { - for(auto&& i : m_creds) - { - if(cert == i.certs[0]) - return i.key.get(); - } - - return nullptr; - } - - private: - struct Certificate_Info - { - std::vector<X509_Certificate> certs; - std::shared_ptr<Private_Key> key; - }; - - std::vector<Certificate_Info> m_creds; - std::vector<std::shared_ptr<Certificate_Store>> m_certstores; - }; - int tls_proxy(int argc, char* argv[]) { if(argc != 6) @@ -543,7 +411,7 @@ int tls_proxy(int argc, char* argv[]) const size_t num_threads = choose_thread_count(); // make configurable AutoSeeded_RNG rng; - Proxy_Credentials_Manager creds(rng, server_crt, server_key); + Basic_Credentials_Manager creds(rng, server_crt, server_key); TLS::Policy policy; // TODO: Read policy from text file diff --git a/src/cmd/tls_server.cpp b/src/cmd/tls_server.cpp index ae51ff55b..fc8499be1 100644 --- a/src/cmd/tls_server.cpp +++ b/src/cmd/tls_server.cpp @@ -1,4 +1,5 @@ /* +* TLS echo server using BSD sockets * (C) 2014 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) @@ -6,7 +7,7 @@ #include "apps.h" -#if defined(BOTAN_HAS_TLS) +#if defined(BOTAN_HAS_TLS) && !defined(BOTAN_TARGET_OS_IS_WINDOWS) #include <botan/tls_server.h> #include <botan/hex.h> @@ -38,9 +39,9 @@ using namespace std::placeholders; namespace { -int make_server_socket(const std::string& transport, u16bit port) +int make_server_socket(bool is_tcp, u16bit port) { - int type = (transport == "tcp") ? SOCK_STREAM : SOCK_DGRAM; + const int type = is_tcp ? SOCK_STREAM : SOCK_DGRAM; int fd = ::socket(PF_INET, type, 0); if(fd == -1) @@ -60,7 +61,7 @@ int make_server_socket(const std::string& transport, u16bit port) throw std::runtime_error("server bind failed"); } - if(transport != "udp") + if(is_tcp) { if(::listen(fd, 100) != 0) { @@ -98,22 +99,19 @@ void dgram_socket_write(int sockfd, const byte buf[], size_t length) void stream_socket_write(int sockfd, const byte buf[], size_t length) { - size_t offset = 0; - while(length) { - ssize_t sent = ::send(sockfd, (const char*)buf + offset, - length, MSG_NOSIGNAL); + ssize_t sent = ::send(sockfd, buf, length, MSG_NOSIGNAL); if(sent == -1) { if(errno == EINTR) sent = 0; else - throw std::runtime_error("Socket::write: Socket write failed"); + throw std::runtime_error("Socket write failed"); } - offset += sent; + buf += sent; length -= sent; } } @@ -125,13 +123,18 @@ void alert_received(TLS::Alert alert, const byte[], size_t) int tls_server(int argc, char* argv[]) { - int port = 4433; - std::string transport = "tcp"; + if(argc != 4 && argc != 5) + { + std::cout << "Usage: " << argv[0] << " server.crt server.key port [tcp|udp]\n"; + return 1; + } + + const std::string server_crt = argv[1]; + const std::string server_key = argv[2]; + const int port = to_u32bit(argv[3]); + const std::string transport = (argc >= 5) ? argv[4] : "tcp"; - if(argc >= 2) - port = to_u32bit(argv[1]); - if(argc >= 3) - transport = argv[2]; + const bool is_tcp = (transport == "tcp"); try { @@ -141,7 +144,7 @@ int tls_server(int argc, char* argv[]) TLS::Session_Manager_In_Memory session_manager(rng); - Credentials_Manager_Simple creds(rng); + Basic_Credentials_Manager creds(rng, server_crt, server_key); /* * These are the protocols we advertise to the client, but the @@ -152,7 +155,7 @@ int tls_server(int argc, char* argv[]) std::cout << "Listening for new connections on " << transport << " port " << port << "\n"; - int server_fd = make_server_socket(transport, port); + int server_fd = make_server_socket(is_tcp, port); while(true) { @@ -160,7 +163,7 @@ int tls_server(int argc, char* argv[]) { int fd; - if(transport == "tcp") + if(is_tcp) fd = ::accept(server_fd, nullptr, nullptr); else { @@ -179,16 +182,12 @@ int tls_server(int argc, char* argv[]) std::cout << "New connection received\n"; - auto socket_write = - (transport == "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; - pending_output.push_back("Welcome to the best echo server evar\n"); - auto proc_fn = [&](const byte input[], size_t input_len) { for(size_t i = 0; i != input_len; ++i) @@ -212,7 +211,7 @@ int tls_server(int argc, char* argv[]) policy, rng, protocols, - (transport != "tcp")); + !is_tcp); while(!server.is_closed()) { @@ -244,7 +243,7 @@ int tls_server(int argc, char* argv[]) } } - if(transport == "tcp") + if(is_tcp) ::close(fd); } |