diff options
author | lloyd <[email protected]> | 2012-01-23 23:36:19 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2012-01-23 23:36:19 +0000 |
commit | f34cc48100c672824aa70869adfb59669055d173 (patch) | |
tree | 6cbcd0d984b1a38b8024cf3b0642edc2a0498368 | |
parent | e3dc1e69f53f93e03411f258e976d2befcf45f91 (diff) |
The credentials manager interface seems a much better place for cert
checking, allowed client auth CAs, etc than the policy class. With
this change, most users won't ever need to modify the default policy
which is likely a good thing.
Remove copy and paste of the credentials manager implemenation in the
examples.
-rw-r--r-- | doc/examples/asio_tls_server.cpp | 56 | ||||
-rw-r--r-- | doc/examples/credentials.h | 53 | ||||
-rw-r--r-- | doc/examples/tls_client.cpp | 54 | ||||
-rw-r--r-- | doc/examples/tls_server.cpp | 55 | ||||
-rw-r--r-- | src/credentials/credentials_manager.cpp | 30 | ||||
-rw-r--r-- | src/credentials/credentials_manager.h | 27 | ||||
-rw-r--r-- | src/tls/tls_client.cpp | 12 | ||||
-rw-r--r-- | src/tls/tls_policy.h | 11 | ||||
-rw-r--r-- | src/tls/tls_server.cpp | 12 |
9 files changed, 137 insertions, 173 deletions
diff --git a/doc/examples/asio_tls_server.cpp b/doc/examples/asio_tls_server.cpp index 90f4fc20a..1a46bc8e8 100644 --- a/doc/examples/asio_tls_server.cpp +++ b/doc/examples/asio_tls_server.cpp @@ -14,6 +14,8 @@ #include <botan/auto_rng.h> #include <botan/init.h> +#include "credentials.h" + using Botan::byte; using asio::ip::tcp; @@ -181,58 +183,6 @@ class tls_server_session : public boost::enable_shared_from_this<tls_server_sess std::vector<byte> m_outbox; }; -class Credentials_Manager_Simple : public Botan::Credentials_Manager - { - public: - Credentials_Manager_Simple(Botan::RandomNumberGenerator& rng) : rng(rng) {} - - std::vector<Botan::X509_Certificate> cert_chain( - const std::string& cert_key_type, - const std::string& type, - const std::string& context) - { - const std::string hostname = (context == "" ? "localhost" : context); - - Botan::X509_Certificate cert(hostname + ".crt"); - Botan::Private_Key* key = Botan::PKCS8::load_key(hostname + ".key", rng); - - certs_and_keys[cert] = key; - - std::vector<Botan::X509_Certificate> certs; - certs.push_back(cert); - 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; - std::map<Botan::X509_Certificate, Botan::Private_Key*> certs_and_keys; - }; - -class Server_TLS_Policy : public Botan::TLS::Policy - { - public: - //bool require_client_auth() const { return true; } - - bool check_cert(const std::vector<Botan::X509_Certificate>& certs) const - { - for(size_t i = 0; i != certs.size(); ++i) - { - std::cout << certs[i].to_string(); - } - - std::cout << "Warning: not checking cert signatures\n"; - - return true; - } - }; - class tls_server { public: @@ -290,7 +240,7 @@ class tls_server Botan::AutoSeeded_RNG m_rng; Botan::TLS::Session_Manager_In_Memory m_session_manager; - Server_TLS_Policy m_policy; + Botan::TLS::Policy m_policy; Credentials_Manager_Simple m_creds; }; diff --git a/doc/examples/credentials.h b/doc/examples/credentials.h new file mode 100644 index 000000000..802e3233c --- /dev/null +++ b/doc/examples/credentials.h @@ -0,0 +1,53 @@ + +#ifndef EXAMPLE_CREDENTIALS_MANAGER_H__ +#define EXAMPLE_CREDENTIALS_MANAGER_H__ + +#include <botan/credentials_manager.h> + +class Credentials_Manager_Simple : public Botan::Credentials_Manager + { + public: + Credentials_Manager_Simple(Botan::RandomNumberGenerator& rng) : rng(rng) {} + + std::vector<Botan::X509_Certificate> cert_chain( + const std::string& cert_key_type, + const std::string& type, + const std::string& context) + { + std::vector<Botan::X509_Certificate> certs; + + if(type == "tls-server") + { + const std::string hostname = (context == "" ? "localhost" : context); + + Botan::X509_Certificate cert(hostname + ".crt"); + Botan::Private_Key* key = Botan::PKCS8::load_key(hostname + ".key", rng); + + certs_and_keys[cert] = key; + certs.push_back(cert); + } + else if(type == "tls-client") + { + Botan::X509_Certificate cert("user-rsa.crt"); + Botan::Private_Key* key = Botan::PKCS8::load_key("user-rsa.key", rng); + + certs_and_keys[cert] = key; + certs.push_back(cert); + } + + 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; + std::map<Botan::X509_Certificate, Botan::Private_Key*> certs_and_keys; + }; + +#endif diff --git a/doc/examples/tls_client.cpp b/doc/examples/tls_client.cpp index 000f63ed4..80947af62 100644 --- a/doc/examples/tls_client.cpp +++ b/doc/examples/tls_client.cpp @@ -16,28 +16,12 @@ #include <errno.h> #include <fcntl.h> +#include "credentials.h" + using namespace Botan; using namespace std::tr1::placeholders; -class Client_TLS_Policy : public TLS::Policy - { - public: - //Version_Code pref_version() const { return TLS_V12; } - - bool check_cert(const std::vector<X509_Certificate>& certs) const - { - for(size_t i = 0; i != certs.size(); ++i) - { - std::cout << certs[i].to_string(); - } - - std::cout << "Warning: not checking cert signatures\n"; - - return true; - } - }; - int connect_to_host(const std::string& host, u16bit port) { hostent* host_addr = ::gethostbyname(host.c_str()); @@ -206,38 +190,6 @@ void doit(RandomNumberGenerator& rng, ::close(sockfd); } -class Credentials_Manager_Simple : public Credentials_Manager - { - public: - Credentials_Manager_Simple(RandomNumberGenerator& rng) : rng(rng) {} - - std::vector<X509_Certificate> cert_chain( - const std::string& cert_key_type, - const std::string& type, - const std::string& context) - { - X509_Certificate cert("user-rsa.crt"); - Private_Key* key = PKCS8::load_key("user-rsa.key", rng); - - certs_and_keys[cert] = key; - - std::vector<X509_Certificate> certs; - certs.push_back(cert); - return certs; - } - - Private_Key* private_key_for(const X509_Certificate& cert, - const std::string& type, - const std::string& context) - { - return certs_and_keys[cert]; - } - - private: - RandomNumberGenerator& rng; - std::map<X509_Certificate, Private_Key*> certs_and_keys; - }; - int main(int argc, char* argv[]) { if(argc != 2 && argc != 3) @@ -250,7 +202,7 @@ int main(int argc, char* argv[]) { LibraryInitializer botan_init; AutoSeeded_RNG rng; - Client_TLS_Policy policy; + TLS::Policy policy; TLS::Session_Manager_In_Memory session_manager; Credentials_Manager_Simple creds(rng); diff --git a/doc/examples/tls_server.cpp b/doc/examples/tls_server.cpp index 0f6287599..e896b5bcc 100644 --- a/doc/examples/tls_server.cpp +++ b/doc/examples/tls_server.cpp @@ -8,6 +8,7 @@ #include <botan/secqueue.h> #include "socket.h" +#include "credentials.h" using namespace Botan; @@ -18,40 +19,6 @@ using namespace std::tr1::placeholders; #include <iostream> #include <memory> -class Credentials_Manager_Simple : public Credentials_Manager - { - public: - Credentials_Manager_Simple(RandomNumberGenerator& rng) : rng(rng) {} - - std::vector<X509_Certificate> cert_chain( - const std::string& cert_key_type, - const std::string& type, - const std::string& context) - { - const std::string hostname = (context == "" ? "localhost" : context); - - X509_Certificate cert(hostname + ".crt"); - Private_Key* key = PKCS8::load_key(hostname + ".key", rng); - - certs_and_keys[cert] = key; - - std::vector<X509_Certificate> certs; - certs.push_back(cert); - return certs; - } - - Private_Key* private_key_for(const X509_Certificate& cert, - const std::string& type, - const std::string& context) - { - return certs_and_keys[cert]; - } - - private: - RandomNumberGenerator& rng; - std::map<X509_Certificate, Private_Key*> certs_and_keys; - }; - bool handshake_complete(const TLS::Session& session) { printf("Handshake complete, protocol=%04X ciphersuite=%s compression=%d\n", @@ -158,24 +125,6 @@ class Blocking_TLS_Server bool exit; }; -class Server_TLS_Policy : public TLS::Policy - { - public: - //bool require_client_auth() const { return true; } - - bool check_cert(const std::vector<X509_Certificate>& certs) const - { - for(size_t i = 0; i != certs.size(); ++i) - { - std::cout << certs[i].to_string(); - } - - std::cout << "Warning: not checking cert signatures\n"; - - return true; - } - }; - int main(int argc, char* argv[]) { int port = 4433; @@ -192,7 +141,7 @@ int main(int argc, char* argv[]) Server_Socket listener(port); - Server_TLS_Policy policy; + TLS::Policy policy; TLS::Session_Manager_In_Memory sessions; diff --git a/src/credentials/credentials_manager.cpp b/src/credentials/credentials_manager.cpp index e7886d307..82da8a75d 100644 --- a/src/credentials/credentials_manager.cpp +++ b/src/credentials/credentials_manager.cpp @@ -49,4 +49,34 @@ Private_Key* Credentials_Manager::private_key_for(const X509_Certificate&, return 0; } +std::vector<X509_Certificate> +Credentials_Manager::trusted_certificate_authorities( + const std::string&, + const std::string&) + { + return std::vector<X509_Certificate>(); + } + +void Credentials_Manager::verify_certificate_chain( + const std::vector<X509_Certificate>& cert_chain, + const std::string& purported_hostname) + { + if(cert_chain.empty()) + throw std::invalid_argument("Certificate chain was empty"); + +#if 0 + if(!cert_chain[0].matches_dns_name(purported_hostname)) + return false; + + X509_Store store; + + std::vector<X509_Certificate> CAs = trusted_certificate_authorities(); + + for(size_t i = 1; i != CAs.size(); ++i) + store.add_cert(CAs[i], true); + for(size_t i = 1; i != cert_chain.size(); ++i) + store.add_cert(cert_chain[i]); +#endif + } + } diff --git a/src/credentials/credentials_manager.h b/src/credentials/credentials_manager.h index 43bccec69..fdcfa74da 100644 --- a/src/credentials/credentials_manager.h +++ b/src/credentials/credentials_manager.h @@ -62,6 +62,10 @@ class BOTAN_DLL Credentials_Manager bool generate_fake_on_unknown); /** + * Return a cert chain we can use, ordered from leaf to root. + * Assumed that we can get the private key of the leaf with + * private_key_for + * * @param cert_key_type is a string representing the key type * ("rsa", "dsa", "ecdsa", etc) or empty if no preference. */ @@ -71,8 +75,29 @@ class BOTAN_DLL Credentials_Manager const std::string& context); /** + * Return a list of the certificates of CAs that we trust in this + * type/context. + */ + virtual std::vector<X509_Certificate> trusted_certificate_authorities( + const std::string& type, + const std::string& context); + + /** + * Check the certificate chain is valid up to a trusted root, and + * optionally (if hostname != "") that the hostname given is + * consistent with the leaf certificate. + * + * This function should throw an exception derived from + * std::exception with an informative what() result if the + * certificate chain cannot be verified. + */ + virtual void verify_certificate_chain( + const std::vector<X509_Certificate>& cert_chain, + const std::string& hostname = ""); + + /** * @return private key associated with this certificate if we should - * use it with this context + * use it with this context. cert was returned by cert_chain */ virtual Private_Key* private_key_for(const X509_Certificate& cert, const std::string& type, diff --git a/src/tls/tls_client.cpp b/src/tls/tls_client.cpp index 835e8d4bd..215ff6972 100644 --- a/src/tls/tls_client.cpp +++ b/src/tls/tls_client.cpp @@ -251,9 +251,15 @@ void Client::process_handshake_msg(Handshake_Type type, throw TLS_Exception(HANDSHAKE_FAILURE, "Client: No certificates sent by server"); - if(!policy.check_cert(peer_certs)) - throw TLS_Exception(BAD_CERTIFICATE, - "Client: Server certificate is not valid"); + try + { + creds.verify_certificate_chain(peer_certs, + state->client_hello->sni_hostname()); + } + catch(std::exception& e) + { + throw TLS_Exception(BAD_CERTIFICATE, e.what()); + } std::auto_ptr<Public_Key> peer_key(peer_certs[0].subject_public_key()); diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h index 61de53dcd..68de2c4df 100644 --- a/src/tls/tls_policy.h +++ b/src/tls/tls_policy.h @@ -46,15 +46,6 @@ class BOTAN_DLL Policy virtual std::vector<byte> compression() const; - virtual bool check_cert(const std::vector<X509_Certificate>& cert_chain) const = 0; - - /** - * If client authentication is desired, returns a list of allowable - * CAs for same. If not desired, returns empty list. - */ - virtual std::vector<X509_Certificate> client_auth_CAs() const - { return std::vector<X509_Certificate>(); } - /** * Require support for RFC 5746 extensions to enable * renegotiation. @@ -70,7 +61,7 @@ class BOTAN_DLL Policy virtual DL_Group dh_group() const { return DL_Group("modp/ietf/1536"); } /* - * @return the minimum version that we will negotiate + * @return the minimum version that we are willing to negotiate */ virtual Protocol_Version min_version() const { return Protocol_Version::SSL_V3; } diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp index cd7888c8b..b38a010dd 100644 --- a/src/tls/tls_server.cpp +++ b/src/tls/tls_server.cpp @@ -270,7 +270,8 @@ void Server::process_handshake_msg(Handshake_Type type, else state->kex_priv = PKCS8::copy_key(*private_key, rng); - std::vector<X509_Certificate> client_auth_CAs = policy.client_auth_CAs(); + std::vector<X509_Certificate> client_auth_CAs = + creds.trusted_certificate_authorities("tls-server", m_hostname); if(!client_auth_CAs.empty() && state->suite.sig_algo() != "") { @@ -342,7 +343,14 @@ void Server::process_handshake_msg(Handshake_Type type, if(!sig_valid) throw TLS_Exception(DECRYPT_ERROR, "Client cert verify failed"); - // FIXME: check cert was issued by a CA we requested, signatures, etc. + try + { + creds.verify_certificate_chain(client_certs); + } + catch(std::exception& e) + { + throw TLS_Exception(BAD_CERTIFICATE, e.what()); + } state->set_expected_next(HANDSHAKE_CCS); } |