aboutsummaryrefslogtreecommitdiffstats
path: root/src/tests/unit_tls.cpp
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2018-01-27 14:23:42 -0500
committerJack Lloyd <[email protected]>2018-01-27 14:23:42 -0500
commitca32f9fd4128bf8ab4e8b78a16c44777bf7b041f (patch)
tree1f6970016dd8ec6fc63bc4209f7fa5e449677300 /src/tests/unit_tls.cpp
parentd708030ecb20cebc548fced882141cc7f03a8ac1 (diff)
Add tests for server passing CA names for client auth
Diffstat (limited to 'src/tests/unit_tls.cpp')
-rw-r--r--src/tests/unit_tls.cpp885
1 files changed, 289 insertions, 596 deletions
diff --git a/src/tests/unit_tls.cpp b/src/tests/unit_tls.cpp
index ae2146304..8368445e0 100644
--- a/src/tests/unit_tls.cpp
+++ b/src/tests/unit_tls.cpp
@@ -105,13 +105,17 @@ class Credentials_Manager_Test final : public Botan::Credentials_Manager
return v;
}
- std::vector<Botan::X509_Certificate> cert_chain(
+ std::vector<Botan::X509_Certificate> find_cert_chain(
const std::vector<std::string>& cert_key_types,
+ const std::vector<Botan::X509_DN>& acceptable_CAs,
const std::string& type,
const std::string& context) override
{
std::vector<Botan::X509_Certificate> chain;
+ if(m_acceptable_cas.empty())
+ m_acceptable_cas = acceptable_CAs;
+
if(type == "tls-server" || (type == "tls-client" && m_provides_client_certs))
{
for(auto const& key_type : cert_key_types)
@@ -189,6 +193,8 @@ class Credentials_Manager_Test final : public Botan::Credentials_Manager
throw Test_Error("No PSK set for " + type + "/" + context);
}
+ const std::vector<Botan::X509_DN>& get_acceptable_cas() const { return m_acceptable_cas; }
+
private:
Botan::X509_Certificate m_rsa_cert, m_rsa_ca;
std::unique_ptr<Botan::Private_Key> m_rsa_key;
@@ -201,6 +207,7 @@ class Credentials_Manager_Test final : public Botan::Credentials_Manager
std::unique_ptr<Botan::X509_CRL> m_dsa_crl;
std::vector<std::unique_ptr<Botan::Certificate_Store>> m_stores;
bool m_provides_client_certs;
+ std::vector<Botan::X509_DN> m_acceptable_cas;
};
Botan::Credentials_Manager*
@@ -289,41 +296,196 @@ create_creds(Botan::RandomNumberGenerator& rng,
return cmt;
}
-std::function<void (const uint8_t[], size_t)> queue_inserter(std::vector<uint8_t>& q)
+class Test_TLS_Alert_Strings : public Test
{
- return [&](const uint8_t buf[], size_t sz) { q.insert(q.end(), buf, buf + sz); };
- }
+ public:
+ std::vector<Test::Result> run() override
+ {
+ Test::Result result("TLS::Alert::type_string");
+
+ const std::vector<Botan::TLS::Alert::Type> alert_types =
+ {
+ Botan::TLS::Alert::CLOSE_NOTIFY,
+ Botan::TLS::Alert::UNEXPECTED_MESSAGE,
+ Botan::TLS::Alert::BAD_RECORD_MAC,
+ Botan::TLS::Alert::DECRYPTION_FAILED,
+ Botan::TLS::Alert::RECORD_OVERFLOW,
+ Botan::TLS::Alert::DECOMPRESSION_FAILURE,
+ Botan::TLS::Alert::HANDSHAKE_FAILURE,
+ Botan::TLS::Alert::NO_CERTIFICATE,
+ Botan::TLS::Alert::BAD_CERTIFICATE,
+ Botan::TLS::Alert::UNSUPPORTED_CERTIFICATE,
+ Botan::TLS::Alert::CERTIFICATE_REVOKED,
+ Botan::TLS::Alert::CERTIFICATE_EXPIRED,
+ Botan::TLS::Alert::CERTIFICATE_UNKNOWN,
+ Botan::TLS::Alert::ILLEGAL_PARAMETER,
+ Botan::TLS::Alert::UNKNOWN_CA,
+ Botan::TLS::Alert::ACCESS_DENIED,
+ Botan::TLS::Alert::DECODE_ERROR,
+ Botan::TLS::Alert::DECRYPT_ERROR,
+ Botan::TLS::Alert::EXPORT_RESTRICTION,
+ Botan::TLS::Alert::PROTOCOL_VERSION,
+ Botan::TLS::Alert::INSUFFICIENT_SECURITY,
+ Botan::TLS::Alert::INTERNAL_ERROR,
+ Botan::TLS::Alert::INAPPROPRIATE_FALLBACK,
+ Botan::TLS::Alert::USER_CANCELED,
+ Botan::TLS::Alert::NO_RENEGOTIATION,
+ Botan::TLS::Alert::UNSUPPORTED_EXTENSION,
+ Botan::TLS::Alert::CERTIFICATE_UNOBTAINABLE,
+ Botan::TLS::Alert::UNRECOGNIZED_NAME,
+ Botan::TLS::Alert::BAD_CERTIFICATE_STATUS_RESPONSE,
+ Botan::TLS::Alert::BAD_CERTIFICATE_HASH_VALUE,
+ Botan::TLS::Alert::UNKNOWN_PSK_IDENTITY,
+ Botan::TLS::Alert:: NO_APPLICATION_PROTOCOL,
+ };
+
+ std::set<std::string> seen;
+
+ for(auto alert : alert_types)
+ {
+ const std::string str = Botan::TLS::Alert(alert).type_string();
+ result.test_eq("No duplicate strings", seen.count(str), 0);
+ seen.insert(str);
+ }
+
+ Botan::TLS::Alert unknown_alert = Botan::TLS::Alert({01, 66});
+
+ result.test_eq("Unknown alert str", unknown_alert.type_string(), "unrecognized_alert_66");
+
+ return {result};
+ }
+ };
-void print_alert(Botan::TLS::Alert)
+BOTAN_REGISTER_TEST("tls_alert_strings", Test_TLS_Alert_Strings);
+
+class Test_TLS_Ciphersuites : public Test
{
- }
+ public:
+ std::vector<Test::Result> run() override
+ {
+ Test::Result result("TLS::Ciphersuite");
+
+ for(size_t csuite_id = 0; csuite_id <= 0xFFFF; ++csuite_id)
+ {
+ Botan::TLS::Ciphersuite ciphersuite = Botan::TLS::Ciphersuite::by_id(csuite_id);
+
+ if(ciphersuite.valid())
+ {
+ result.test_eq("Valid Ciphersuite is not SCSV", Botan::TLS::Ciphersuite::is_scsv(csuite_id), false);
-void alert_cb_with_data(Botan::TLS::Alert, const uint8_t[], size_t)
+ if(ciphersuite.cbc_ciphersuite() == false)
+ {
+ result.test_eq("Expected MAC name for AEAD ciphersuites", ciphersuite.mac_algo(), "AEAD");
+ }
+ else
+ {
+ result.test_eq("MAC algo and PRF algo same for CBC suites", ciphersuite.prf_algo(), ciphersuite.mac_algo());
+ }
+
+ // TODO more tests here
+ }
+ }
+
+ return {result};
+ }
+ };
+
+BOTAN_REGISTER_TEST("tls_ciphersuites", Test_TLS_Ciphersuites);
+
+class Test_TLS_Policy_Test : public Test
{
- }
+ public:
+ std::vector<Test::Result> run() override
+ {
+ Test::Result result("TLS Policy");
+
+ const std::vector<std::string> policies = { "default", "suiteb", "strict", "datagram", "bsi" };
+
+ for(std::string policy : policies)
+ {
+ result.test_eq("Values for TLS " + policy + " policy",
+ tls_policy_string(policy),
+ read_tls_policy(policy));
+ }
+
+ return {result};
+ }
+
+ private:
+ std::string read_tls_policy(const std::string& policy_str)
+ {
+ const std::string fspath = Test::data_file("tls-policy/" + policy_str + ".txt");
+
+ std::ifstream is(fspath.c_str());
+ if(!is.good())
+ {
+ throw Test_Error("Missing policy file " + fspath);
+ }
+
+ Botan::TLS::Text_Policy policy(is);
+ return policy.to_string();
+ }
+
+ std::string tls_policy_string(const std::string& policy_str)
+ {
+ std::unique_ptr<Botan::TLS::Policy> policy;
+ if(policy_str == "default")
+ {
+ policy.reset(new Botan::TLS::Policy);
+ }
+ else if(policy_str == "suiteb")
+ {
+ policy.reset(new Botan::TLS::NSA_Suite_B_128);
+ }
+ else if(policy_str == "bsi")
+ {
+ policy.reset(new Botan::TLS::BSI_TR_02102_2);
+ }
+ else if(policy_str == "strict")
+ {
+ policy.reset(new Botan::TLS::Strict_Policy);
+ }
+ else if(policy_str == "datagram")
+ {
+ policy.reset(new Botan::TLS::Datagram_Policy);
+ }
+ else
+ {
+ throw Test_Error("Unknown TLS policy type '" + policy_str + "'");
+ }
+
+ return policy->to_string();
+ }
+ };
+
+BOTAN_REGISTER_TEST("tls_policy_test", Test_TLS_Policy_Test);
class TLS_Handshake_Test final
{
public:
- TLS_Handshake_Test(Botan::TLS::Protocol_Version offer_version,
+ TLS_Handshake_Test(const std::string& test_descr,
+ Botan::TLS::Protocol_Version offer_version,
Botan::Credentials_Manager& creds,
const Botan::TLS::Policy& client_policy,
const Botan::TLS::Policy& server_policy,
Botan::RandomNumberGenerator& rng,
Botan::TLS::Session_Manager& client_sessions,
- Botan::TLS::Session_Manager& server_sessions) :
+ Botan::TLS::Session_Manager& server_sessions,
+ bool expect_client_auth) :
m_offer_version(offer_version),
- m_results(offer_version.to_string()), // TODO descriptive constructor arg
+ m_results(test_descr),
m_creds(creds),
m_client_policy(client_policy),
m_client_sessions(client_sessions),
- m_rng(rng)
+ m_rng(rng),
+ m_client_auth(expect_client_auth)
{
m_server_cb.reset(new Test_Callbacks(m_results, offer_version, m_s2c, m_server_recv));
m_client_cb.reset(new Test_Callbacks(m_results, offer_version, m_c2s, m_client_recv));
m_server.reset(
- new Botan::TLS::Server(*m_server_cb, server_sessions, m_creds, server_policy, m_rng)
+ new Botan::TLS::Server(*m_server_cb, server_sessions, m_creds, server_policy, m_rng,
+ offer_version.is_datagram_protocol())
);
}
@@ -470,6 +632,8 @@ class TLS_Handshake_Test final
std::unique_ptr<Test_Callbacks> m_server_cb;
std::unique_ptr<Botan::TLS::Server> m_server;
+ const bool m_client_auth;
+
std::vector<uint8_t> m_c2s, m_s2c, m_client_recv, m_server_recv;
};
@@ -482,14 +646,12 @@ void TLS_Handshake_Test::go()
const std::vector<std::string> protocols_offered = { "test/1", "test/2" };
// Choose random application data to send
- //const size_t c_len = 1 + ((static_cast<size_t>(rng.next_byte()) << 4) ^ rng.next_byte());
- const size_t c_len = 180;
+ const size_t c_len = 1 + ((static_cast<size_t>(rng.next_byte()) << 4) ^ rng.next_byte());
std::vector<uint8_t> client_msg(c_len);
Test::rng().randomize(client_msg.data(), client_msg.size());
bool client_has_written = false;
- //const size_t s_len = 1 + ((static_cast<size_t>(rng.next_byte()) << 4) ^ rng.next_byte());
- const size_t s_len = 400;
+ const size_t s_len = 1 + ((static_cast<size_t>(rng.next_byte()) << 4) ^ rng.next_byte());
std::vector<uint8_t> server_msg(s_len);
Test::rng().randomize(server_msg.data(), server_msg.size());
bool server_has_written = false;
@@ -607,364 +769,43 @@ void TLS_Handshake_Test::go()
break;
}
- if(m_server_recv.size() && m_client_recv.size())
+ if(m_server->is_active())
{
- Botan::SymmetricKey client_key = client->key_material_export("label", "context", 32);
- Botan::SymmetricKey server_key = m_server->key_material_export("label", "context", 32);
-
- m_results.test_eq("TLS key material export", client_key.bits_of(), server_key.bits_of());
-
- client->close();
- }
- }
-
- m_results.end_timer();
- }
-
-Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version,
- Botan::Credentials_Manager& creds,
- const Botan::TLS::Policy& client_policy,
- const Botan::TLS::Policy& server_policy,
- Botan::RandomNumberGenerator& rng,
- Botan::TLS::Session_Manager& client_sessions,
- Botan::TLS::Session_Manager& server_sessions)
- {
- TLS_Handshake_Test test(offer_version, creds,
- client_policy, server_policy, rng,
- client_sessions, server_sessions);
-
- test.go();
- return test.results();
- }
-
-Test::Result test_tls_handshake(Botan::TLS::Protocol_Version offer_version,
- Botan::Credentials_Manager& creds,
- const Botan::TLS::Policy& policy,
- Botan::RandomNumberGenerator& rng,
- Botan::TLS::Session_Manager& client_sessions,
- Botan::TLS::Session_Manager& server_sessions)
- {
- return test_tls_handshake(offer_version, creds, policy, policy, rng,
- client_sessions, server_sessions);
- }
-
-Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version,
- Botan::Credentials_Manager& creds,
- const Botan::TLS::Policy& client_policy,
- const Botan::TLS::Policy& server_policy,
- Botan::RandomNumberGenerator& rng,
- Botan::TLS::Session_Manager& client_sessions,
- Botan::TLS::Session_Manager& server_sessions)
- {
- BOTAN_ASSERT(offer_version.is_datagram_protocol(), "Test is for datagram version");
-
- Test::Result result(offer_version.to_string());
-
- result.start_timer();
-
- for(size_t r = 1; r <= 2; ++r)
- {
- bool handshake_done = false;
-
- auto handshake_complete = [&](const Botan::TLS::Session & session) -> bool
- {
- handshake_done = true;
-
- if(session.version() != offer_version)
+ std::vector<Botan::X509_Certificate> certs = m_server->peer_cert_chain();
+ if(m_client_auth)
{
- result.test_failure("Offered " + offer_version.to_string() + " got " + session.version().to_string());
- }
+ m_results.test_eq("got client certs", certs.size(), 2);
- return true;
- };
+ Credentials_Manager_Test& test_creds = dynamic_cast<Credentials_Manager_Test&>(m_creds);
- auto next_protocol_chooser = [&](std::vector<std::string> protos) -> std::string
- {
- if(r <= 2)
- {
- result.test_eq("protocol count", protos.size(), 2);
- result.test_eq("protocol[0]", protos[0], "test/1");
- result.test_eq("protocol[1]", protos[1], "test/2");
- }
- return "test/3";
- };
+ std::vector<Botan::X509_DN> acceptable_CAs = test_creds.get_acceptable_cas();
- const std::vector<std::string> protocols_offered = { "test/1", "test/2" };
+ m_results.test_gte("client got CA list", acceptable_CAs.size(), 2); // DSA is optional
- try
- {
- std::vector<uint8_t> c2s_traffic, s2c_traffic, client_recv, server_recv, client_sent, server_sent;
-
- std::unique_ptr<Botan::TLS::Callbacks> server_cb(new Botan::TLS::Compat_Callbacks(
- queue_inserter(s2c_traffic),
- queue_inserter(server_recv),
- std::function<void (Botan::TLS::Alert)>(print_alert),
- handshake_complete,
- nullptr,
- next_protocol_chooser));
-
- std::unique_ptr<Botan::TLS::Callbacks> client_cb(new Botan::TLS::Compat_Callbacks(
- queue_inserter(c2s_traffic),
- queue_inserter(client_recv),
- std::function<void (Botan::TLS::Alert)>(print_alert),
- handshake_complete));
-
- // TLS::Server object constructed by new constructor using virtual callback interface.
- std::unique_ptr<Botan::TLS::Server> server(
- new Botan::TLS::Server(*server_cb,
- server_sessions,
- creds,
- server_policy,
- rng,
- true));
-
- // TLS::Client object constructed by new constructor using virtual callback interface.
- std::unique_ptr<Botan::TLS::Client> client(
- new Botan::TLS::Client(*client_cb,
- client_sessions,
- creds,
- client_policy,
- rng,
- Botan::TLS::Server_Information("server.example.com"),
- offer_version,
- protocols_offered));
-
- size_t rounds = 0;
-
- // Test DTLS using both new and legacy constructors.
- for(size_t ctor_sel = 0; ctor_sel < 2; ++ctor_sel)
- {
- if(ctor_sel == 1)
+ for(const Botan::X509_DN& dn : acceptable_CAs)
{
- c2s_traffic.clear();
- s2c_traffic.clear();
- server_recv.clear();
- client_recv.clear();
- client_sent.clear();
- server_sent.clear();
- // TLS::Server object constructed by legacy constructor.
- server.reset(
- new Botan::TLS::Server(queue_inserter(s2c_traffic),
- queue_inserter(server_recv),
- alert_cb_with_data,
- handshake_complete,
- server_sessions,
- creds,
- server_policy,
- rng,
- next_protocol_chooser,
- true));
-
- // TLS::Client object constructed by legacy constructor.
- client.reset(
- new Botan::TLS::Client(queue_inserter(c2s_traffic),
- queue_inserter(client_recv),
- alert_cb_with_data,
- handshake_complete,
- client_sessions,
- creds,
- client_policy,
- rng,
- Botan::TLS::Server_Information("server.example.com"),
- offer_version,
- protocols_offered));
- }
-
- while(true)
- {
-#if defined(BOTAN_TARGET_OS_HAS_THREADS)
- // TODO: client and server should be in different threads
- std::this_thread::sleep_for(std::chrono::microseconds(rng.next_byte() % 128));
-#endif
- ++rounds;
-
- if(rounds > 100)
- {
- result.test_failure("Still here after many rounds");
- break;
- }
-
- if(handshake_done && (client->is_closed() || server->is_closed()))
- {
- break;
- }
-
- if(client->is_active() && client_sent.empty())
- {
- // Choose a len between 1 and 511, todo use random chunks
- const size_t c_len = 1 + rng.next_byte() + rng.next_byte();
- client_sent = unlock(rng.random_vec(c_len));
- client->send(client_sent);
- }
-
- if(server->is_active() && server_sent.empty())
- {
- result.test_eq("server ALPN", server->next_protocol(), "test/3");
-
- const size_t s_len = 1 + rng.next_byte() + rng.next_byte();
- server_sent = unlock(rng.random_vec(s_len));
- server->send(server_sent);
- }
-
- const bool corrupt_client_data = (r == 3 && rng.next_byte() % 3 <= 1 && rounds < 10);
- const bool corrupt_server_data = (r == 4 && rng.next_byte() % 3 <= 1 && rounds < 10);
-
- if(c2s_traffic.size() > 0)
- {
- /*
- * Use this as a temp value to hold the queues as otherwise they
- * might end up appending more in response to messages during the
- * handshake.
- */
- std::vector<uint8_t> input;
- std::swap(c2s_traffic, input);
-
- if(corrupt_server_data)
- {
- try
- {
- input = Test::mutate_vec(input, true, 5);
- size_t needed = server->received_data(input.data(), input.size());
-
- if(needed > 0 &&
- result.test_lt("Never requesting more than max protocol len", needed, Botan::TLS::MAX_CIPHERTEXT_SIZE + 1))
- {
- input.resize(needed);
- rng.randomize(input.data(), input.size());
- client->received_data(input.data(), input.size());
- }
- }
- catch(std::exception&)
- {
- result.test_note("corruption caused server exception");
- }
- }
- else
- {
- try
- {
- size_t needed = server->received_data(input.data(), input.size());
- result.test_eq("full packet received", needed, 0);
- }
- catch(std::exception& e)
- {
- result.test_failure("server error", e.what());
- }
- }
-
- continue;
- }
-
- if(s2c_traffic.size() > 0)
- {
- std::vector<uint8_t> input;
- std::swap(s2c_traffic, input);
-
- if(corrupt_client_data)
- {
- try
- {
- input = Test::mutate_vec(input, true, 5);
- size_t needed = client->received_data(input.data(), input.size());
-
- if(needed > 0 &&
- result.test_lt("Never requesting more than max protocol len", needed, Botan::TLS::MAX_CIPHERTEXT_SIZE + 1))
- {
- input.resize(needed);
- rng.randomize(input.data(), input.size());
- client->received_data(input.data(), input.size());
- }
- }
- catch(std::exception&)
- {
- result.test_note("corruption caused client exception");
- }
- }
- else
- {
- try
- {
- size_t needed = client->received_data(input.data(), input.size());
- result.test_eq("full packet received", needed, 0);
- }
- catch(std::exception& e)
- {
- result.test_failure("client error", e.what());
- }
- }
-
- continue;
- }
-
- // If we corrupted a DTLS application message, resend it:
- if(client->is_active() && corrupt_client_data && server_recv.empty())
- {
- client->send(client_sent);
- }
- if(server->is_active() && corrupt_server_data && client_recv.empty())
- {
- server->send(server_sent);
- }
-
- if(client_recv.size())
- {
- result.test_eq("client recv", client_recv, server_sent);
- }
-
- if(server_recv.size())
- {
- result.test_eq("server recv", server_recv, client_sent);
- }
-
- if(client->is_closed() && server->is_closed())
- {
- break;
- }
-
- if(server_recv.size() && client_recv.size())
- {
- Botan::SymmetricKey client_key = client->key_material_export("label", "context", 32);
- Botan::SymmetricKey server_key = server->key_material_export("label", "context", 32);
-
- result.test_eq("key material export", client_key.bits_of(), server_key.bits_of());
-
- if(r % 2 == 0)
- {
- client->close();
- }
- else
- {
- server->close();
- }
- }
+ m_results.test_eq("Expected CA country field",
+ dn.get_first_attribute("C"), "VT");
}
}
- }
- catch(std::exception& e)
- {
- if(r > 2)
- {
- result.test_note("Corruption caused failure");
- }
else
{
- result.test_failure("DTLS handshake", e.what());
+ m_results.test_eq("no client certs", certs.size(), 0);
}
}
- }
- result.end_timer();
- return result;
- }
+ if(m_server_recv.size() && m_client_recv.size())
+ {
+ Botan::SymmetricKey client_key = client->key_material_export("label", "context", 32);
+ Botan::SymmetricKey server_key = m_server->key_material_export("label", "context", 32);
-Test::Result test_dtls_handshake(Botan::TLS::Protocol_Version offer_version,
- Botan::Credentials_Manager& creds,
- const Botan::TLS::Policy& policy,
- Botan::RandomNumberGenerator& rng,
- Botan::TLS::Session_Manager& client_ses,
- Botan::TLS::Session_Manager& server_ses)
- {
- return test_dtls_handshake(offer_version, creds, policy, policy, rng, client_ses, server_ses);
+ m_results.test_eq("TLS key material export", client_key.bits_of(), server_key.bits_of());
+
+ client->close();
+ }
+ }
+
+ m_results.end_timer();
}
class Test_Policy final : public Botan::TLS::Text_Policy
@@ -1000,157 +841,40 @@ class Test_Policy final : public Botan::TLS::Text_Policy
}
};
-Test::Result test_tls_alert_strings()
- {
- Test::Result result("TLS::Alert::type_string");
-
- const std::vector<Botan::TLS::Alert::Type> alert_types =
- {
- Botan::TLS::Alert::CLOSE_NOTIFY,
- Botan::TLS::Alert::UNEXPECTED_MESSAGE,
- Botan::TLS::Alert::BAD_RECORD_MAC,
- Botan::TLS::Alert::DECRYPTION_FAILED,
- Botan::TLS::Alert::RECORD_OVERFLOW,
- Botan::TLS::Alert::DECOMPRESSION_FAILURE,
- Botan::TLS::Alert::HANDSHAKE_FAILURE,
- Botan::TLS::Alert::NO_CERTIFICATE,
- Botan::TLS::Alert::BAD_CERTIFICATE,
- Botan::TLS::Alert::UNSUPPORTED_CERTIFICATE,
- Botan::TLS::Alert::CERTIFICATE_REVOKED,
- Botan::TLS::Alert::CERTIFICATE_EXPIRED,
- Botan::TLS::Alert::CERTIFICATE_UNKNOWN,
- Botan::TLS::Alert::ILLEGAL_PARAMETER,
- Botan::TLS::Alert::UNKNOWN_CA,
- Botan::TLS::Alert::ACCESS_DENIED,
- Botan::TLS::Alert::DECODE_ERROR,
- Botan::TLS::Alert::DECRYPT_ERROR,
- Botan::TLS::Alert::EXPORT_RESTRICTION,
- Botan::TLS::Alert::PROTOCOL_VERSION,
- Botan::TLS::Alert::INSUFFICIENT_SECURITY,
- Botan::TLS::Alert::INTERNAL_ERROR,
- Botan::TLS::Alert::INAPPROPRIATE_FALLBACK,
- Botan::TLS::Alert::USER_CANCELED,
- Botan::TLS::Alert::NO_RENEGOTIATION,
- Botan::TLS::Alert::UNSUPPORTED_EXTENSION,
- Botan::TLS::Alert::CERTIFICATE_UNOBTAINABLE,
- Botan::TLS::Alert::UNRECOGNIZED_NAME,
- Botan::TLS::Alert::BAD_CERTIFICATE_STATUS_RESPONSE,
- Botan::TLS::Alert::BAD_CERTIFICATE_HASH_VALUE,
- Botan::TLS::Alert::UNKNOWN_PSK_IDENTITY,
- Botan::TLS::Alert:: NO_APPLICATION_PROTOCOL,
- };
-
- std::set<std::string> seen;
-
- for(auto alert : alert_types)
- {
- const std::string str = Botan::TLS::Alert(alert).type_string();
- result.test_eq("No duplicate strings", seen.count(str), 0);
- seen.insert(str);
- }
-
- Botan::TLS::Alert unknown_alert = Botan::TLS::Alert({01, 66});
-
- result.test_eq("Unknown alert str", unknown_alert.type_string(), "unrecognized_alert_66");
-
- return result;
- }
-
-
-std::string read_tls_policy(const std::string& policy_str)
- {
- const std::string fspath = Test::data_file("tls-policy/" + policy_str + ".txt");
-
- std::ifstream is(fspath.c_str());
- if(!is.good())
- {
- throw Test_Error("Missing policy file " + fspath);
- }
-
- Botan::TLS::Text_Policy policy(is);
- return policy.to_string();
- }
-
-std::string tls_policy_string(const std::string& policy_str)
- {
- std::unique_ptr<Botan::TLS::Policy> policy;
- if(policy_str == "default")
- {
- policy.reset(new Botan::TLS::Policy);
- }
- else if(policy_str == "suiteb")
- {
- policy.reset(new Botan::TLS::NSA_Suite_B_128);
- }
- else if(policy_str == "bsi")
- {
- policy.reset(new Botan::TLS::BSI_TR_02102_2);
- }
- else if(policy_str == "strict")
- {
- policy.reset(new Botan::TLS::Strict_Policy);
- }
- else if(policy_str == "datagram")
- {
- policy.reset(new Botan::TLS::Datagram_Policy);
- }
- else
- {
- throw Test_Error("Unknown TLS policy type '" + policy_str + "'");
- }
-
- return policy->to_string();
- }
-
-Test::Result test_tls_policy()
- {
- Test::Result result("TLS Policy");
-
- const std::vector<std::string> policies = { "default", "suiteb", "strict", "datagram", "bsi" };
-
- for(std::string policy : policies)
- {
- result.test_eq("Values for TLS " + policy + " policy",
- tls_policy_string(policy),
- read_tls_policy(policy));
- }
-
- return result;
- }
-
class TLS_Unit_Tests final : public Test
{
private:
- void test_with_policy(std::vector<Test::Result>& results,
+ void test_with_policy(const std::string& test_descr,
+ std::vector<Test::Result>& results,
Botan::TLS::Session_Manager& client_ses,
Botan::TLS::Session_Manager& server_ses,
Botan::Credentials_Manager& creds,
const std::vector<Botan::TLS::Protocol_Version>& versions,
- const Botan::TLS::Policy& policy)
+ const Botan::TLS::Policy& policy,
+ bool client_auth = false)
{
Botan::RandomNumberGenerator& rng = Test::rng();
for(auto const& version : versions)
{
- if(version.is_datagram_protocol())
- {
- results.push_back(test_dtls_handshake(version, creds, policy, rng, client_ses, server_ses));
- }
- else
- {
- results.push_back(test_tls_handshake(version, creds, policy, rng, client_ses, server_ses));
- }
+ TLS_Handshake_Test test(
+ version.to_string() + " " + test_descr,
+ version, creds, policy, policy, rng, client_ses, server_ses, client_auth);
+ test.go();
+ results.push_back(test.results());
}
}
- void test_all_versions(std::vector<Test::Result>& results,
+ void test_all_versions(const std::string& test_descr,
+ std::vector<Test::Result>& results,
Botan::TLS::Session_Manager& client_ses,
Botan::TLS::Session_Manager& server_ses,
Botan::Credentials_Manager& creds,
const std::string& kex_policy,
const std::string& cipher_policy,
const std::string& mac_policy,
- const std::string& etm_policy)
+ const std::string& etm_policy,
+ bool client_auth = false)
{
Test_Policy policy;
policy.set("ciphers", cipher_policy);
@@ -1172,30 +896,34 @@ class TLS_Unit_Tests final : public Test
Botan::TLS::Protocol_Version::DTLS_V12
};
- return test_with_policy(results, client_ses, server_ses, creds, versions, policy);
+ return test_with_policy(test_descr, results, client_ses, server_ses, creds, versions, policy, client_auth);
}
- void test_modern_versions(std::vector<Test::Result>& results,
+ void test_modern_versions(const std::string& test_descr,
+ std::vector<Test::Result>& results,
Botan::TLS::Session_Manager& client_ses,
Botan::TLS::Session_Manager& server_ses,
Botan::Credentials_Manager& creds,
const std::string& kex_policy,
const std::string& cipher_policy,
- const std::string& mac_policy = "AEAD")
+ const std::string& mac_policy = "AEAD",
+ bool client_auth = false)
{
std::map<std::string, std::string> no_extra_policies;
- return test_modern_versions(results, client_ses, server_ses, creds,
- kex_policy, cipher_policy, mac_policy, no_extra_policies);
+ return test_modern_versions(test_descr, results, client_ses, server_ses, creds,
+ kex_policy, cipher_policy, mac_policy, no_extra_policies, client_auth);
}
- void test_modern_versions(std::vector<Test::Result>& results,
+ void test_modern_versions(const std::string& test_descr,
+ std::vector<Test::Result>& results,
Botan::TLS::Session_Manager& client_ses,
Botan::TLS::Session_Manager& server_ses,
Botan::Credentials_Manager& creds,
const std::string& kex_policy,
const std::string& cipher_policy,
const std::string& mac_policy,
- const std::map<std::string, std::string>& extra_policies)
+ const std::map<std::string, std::string>& extra_policies,
+ bool client_auth = false)
{
Test_Policy policy;
policy.set("ciphers", cipher_policy);
@@ -1213,44 +941,13 @@ class TLS_Unit_Tests final : public Test
Botan::TLS::Protocol_Version::DTLS_V12
};
- return test_with_policy(results, client_ses, server_ses, creds, versions, policy);
- }
-
- Test::Result test_tls_ciphersuites()
- {
- Test::Result result("TLS::Ciphersuite");
-
- for(size_t csuite_id = 0; csuite_id <= 0xFFFF; ++csuite_id)
- {
- Botan::TLS::Ciphersuite ciphersuite = Botan::TLS::Ciphersuite::by_id(csuite_id);
-
- if(ciphersuite.valid())
- {
- result.test_eq("Valid Ciphersuite is not SCSV", Botan::TLS::Ciphersuite::is_scsv(csuite_id), false);
-
- if(ciphersuite.cbc_ciphersuite() == false)
- {
- result.test_eq("Expected MAC name for AEAD ciphersuites", ciphersuite.mac_algo(), "AEAD");
- }
- else
- {
- result.test_eq("MAC algo and PRF algo same for CBC suites", ciphersuite.prf_algo(), ciphersuite.mac_algo());
- }
-
- // TODO more tests here
- }
- }
-
- return result;
+ return test_with_policy(test_descr, results, client_ses, server_ses, creds, versions, policy, client_auth);
}
public:
std::vector<Test::Result> run() override
{
std::vector<Test::Result> results;
- results.push_back(test_tls_alert_strings());
- results.push_back(test_tls_policy());
- results.push_back(test_tls_ciphersuites());
Botan::RandomNumberGenerator& rng = Test::rng();
@@ -1259,11 +956,10 @@ class TLS_Unit_Tests final : public Test
#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
client_ses.reset(
- new Botan::TLS::Session_Manager_SQLite("pass", rng, ":memory:", 5,
- std::chrono::seconds(2)));
+ new Botan::TLS::Session_Manager_SQLite("pass", rng, ":memory:", 5, std::chrono::seconds(2)));
server_ses.reset(
- new Botan::TLS::Session_Manager_SQLite("pass", rng, ":memory:", 10,
- std::chrono::seconds(4)));
+ new Botan::TLS::Session_Manager_SQLite("pass", rng, ":memory:", 10, std::chrono::seconds(4)));
+
#else
client_ses.reset(new Botan::TLS::Session_Manager_In_Memory(rng));
server_ses.reset(new Botan::TLS::Session_Manager_In_Memory(rng));
@@ -1274,119 +970,115 @@ class TLS_Unit_Tests final : public Test
#if defined(BOTAN_HAS_TLS_CBC)
for(std::string etm_setting : { "false", "true" })
{
- test_all_versions(results, *client_ses, *server_ses, *creds, "RSA", "AES-128", "SHA-256 SHA-1", etm_setting);
- test_all_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128", "SHA-256 SHA-1", etm_setting);
-
- test_all_versions(results, *client_ses, *server_ses, *creds, "RSA", "AES-256", "SHA-1", etm_setting);
- test_all_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-256", "SHA-1", etm_setting);
+ test_all_versions("AES-128 RSA", results, *client_ses, *server_ses, *creds, "RSA", "AES-128", "SHA-256 SHA-1", etm_setting);
+ test_all_versions("AES-128 ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "AES-128", "SHA-256 SHA-1", etm_setting);
#if defined(BOTAN_HAS_CAMELLIA)
- test_all_versions(results, *client_ses, *server_ses, *creds, "RSA", "Camellia-128", "SHA-256 SHA-1", etm_setting);
- test_all_versions(results, *client_ses, *server_ses, *creds, "RSA", "Camellia-256", "SHA-256 SHA-384 SHA-1",
- etm_setting);
+ test_all_versions("Camellia-128 RSA", results, *client_ses, *server_ses,
+ *creds, "RSA", "Camellia-128", "SHA-256 SHA-1", etm_setting);
+ test_all_versions("Camellia-128 RSA SHA-2", results, *client_ses, *server_ses,
+ *creds, "RSA", "Camellia-256", "SHA-256 SHA-384 SHA-1", etm_setting);
#endif
#if defined(BOTAN_HAS_DES)
- test_all_versions(results, *client_ses, *server_ses, *creds, "RSA", "3DES", "SHA-1", etm_setting);
- test_all_versions(results, *client_ses, *server_ses, *creds, "ECDH", "3DES", "SHA-1", etm_setting);
+ test_all_versions("3DES RSA", results, *client_ses, *server_ses, *creds, "RSA", "3DES", "SHA-1", etm_setting);
+ test_all_versions("3DES ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "3DES", "SHA-1", etm_setting);
#endif
#if defined(BOTAN_HAS_SEED)
- test_all_versions(results, *client_ses, *server_ses, *creds, "RSA", "SEED", "SHA-1", etm_setting);
+ test_all_versions("SEED RSA", results, *client_ses, *server_ses, *creds, "RSA", "SEED", "SHA-1", etm_setting);
#endif
server_ses->remove_all();
}
client_ses->remove_all();
- test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-128", "SHA-256");
+ test_modern_versions("AES-128 DH", results, *client_ses, *server_ses, *creds, "DH", "AES-128", "SHA-256");
#if defined(BOTAN_HAS_DSA)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-128", "SHA-256",
- { { "signature_methods", "DSA" } });
- test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-256", "SHA-256",
- { { "signature_methods", "DSA" } });
+ test_modern_versions("AES-128 DSA", results, *client_ses, *server_ses, *creds, "DH", "AES-128", "SHA-256",
+ { { "signature_methods", "DSA" } });
+
+ test_modern_versions("AES-128/GCM DSA", results, *client_ses, *server_ses, *creds, "DH", "AES-128/GCM", "AEAD",
+ { { "signature_methods", "DSA" } });
#endif
#endif
Botan::TLS::Strict_Policy strict_policy;
- test_with_policy(results, *client_ses, *server_ses, *creds,
+ test_with_policy("Strict policy", results, *client_ses, *server_ses, *creds,
{Botan::TLS::Protocol_Version::TLS_V12}, strict_policy);
Botan::TLS::NSA_Suite_B_128 suiteb_128;
- test_with_policy(results, *client_ses, *server_ses, *creds,
+ test_with_policy("Suite B", results, *client_ses, *server_ses, *creds,
{Botan::TLS::Protocol_Version::TLS_V12}, suiteb_128);
// Remove server sessions before client, so clients retry with session server doesn't know
server_ses->remove_all();
- test_modern_versions(results, *client_ses, *server_ses, *creds, "RSA", "AES-128/GCM");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM");
-
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
- { { "signature_methods", "RSA" } });
+ test_modern_versions("AES-128/GCM RSA", results, *client_ses, *server_ses, *creds, "RSA", "AES-128/GCM");
+ test_modern_versions("AES-128/GCM ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
- { { "support_cert_status_message", "false" } });
+ test_modern_versions("AES-128/GCM ECDH RSA",
+ results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
+ { { "signature_methods", "RSA" } });
-#if defined(BOTAN_HAS_DSA)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-128/GCM", "AEAD",
- { { "signature_methods", "DSA" } });
- test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-256/GCM", "AEAD",
- { { "signature_methods", "DSA" } });
-#endif
+ test_modern_versions("AES-128/GCM ECDH no OCSP",
+ results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
+ { { "support_cert_status_message", "false" } });
client_ses->remove_all();
#if defined(BOTAN_HAS_CAMELLIA)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "RSA", "Camellia-128", "SHA-256");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "RSA", "Camellia-256", "SHA-384 SHA-256");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "Camellia-128/GCM", "AEAD");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "Camellia-256/GCM", "AEAD");
+ test_modern_versions("Camellia-256 SHA-2", results, *client_ses, *server_ses, *creds, "RSA", "Camellia-256", "SHA-384 SHA-256");
+ test_modern_versions("Camellia-128/GCM ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "Camellia-128/GCM", "AEAD");
#endif
#if defined(BOTAN_HAS_ARIA)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "ARIA-128/GCM", "AEAD");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "ARIA-256/GCM", "AEAD");
+ test_modern_versions("ARIA ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "ARIA-128/GCM", "AEAD");
#endif
#if defined(BOTAN_HAS_CECPQ1)
#if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_AEAD_GCM)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "CECPQ1", "AES-256/GCM", "AEAD");
+ test_modern_versions("AES-256/GCM CECPQ1", results, *client_ses, *server_ses, *creds, "CECPQ1", "AES-256/GCM", "AEAD");
#endif
#if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_AEAD_OCB)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "CECPQ1", "AES-256/OCB(12)", "AEAD");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "CECPQ1", "AES-256/OCB(12)", "AEAD",
- {{ "signature_methods", "RSA" }});
+ test_modern_versions("AES-256/OCB CECPQ1", results, *client_ses, *server_ses, *creds,
+ "CECPQ1", "AES-256/OCB(12)", "AEAD");
+ test_modern_versions("AES-256/OCB CECPQ1 RSA", results, *client_ses, *server_ses, *creds,
+ "CECPQ1", "AES-256/OCB(12)", "AEAD",
+ {{ "signature_methods", "RSA" }});
#endif
#if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "CECPQ1", "ChaCha20Poly1305", "AEAD",
- { { "signature_methods", "RSA" }});
+ test_modern_versions("ChaCha20Poly1305 CECPQ1", results, *client_ses, *server_ses, *creds,
+ "CECPQ1", "ChaCha20Poly1305", "AEAD",
+ { { "signature_methods", "RSA" }});
#endif
#endif
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
- { { "use_ecc_point_compression", "true" } });
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-256/GCM", "AEAD",
- { { "groups", "secp521r1" } });
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
- { { "groups", "brainpool256r1" } });
+ test_modern_versions("AES-128/GCM point compression", results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
+ { { "use_ecc_point_compression", "true" } });
+ test_modern_versions("AES-256/GCM p521", results, *client_ses, *server_ses, *creds, "ECDH", "AES-256/GCM", "AEAD",
+ { { "groups", "secp521r1" } });
+ test_modern_versions("AES-128/GCM bp256r1", results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
+ { { "groups", "brainpool256r1" } });
#if defined(BOTAN_HAS_CURVE_25519)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
- { { "groups", "x25519" } });
+ test_modern_versions("AES-128/GCM x25519", results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
+ { { "groups", "x25519" } });
#endif
- test_modern_versions(results, *client_ses, *server_ses, *creds, "DH", "AES-128/GCM", "AEAD",
- { { "groups", "ffdhe/ietf/2048" } });
+ test_modern_versions("AES-128/GCM FFDHE-2048",
+ results, *client_ses, *server_ses, *creds, "DH", "AES-128/GCM", "AEAD",
+ { { "groups", "ffdhe/ietf/2048" } });
std::unique_ptr<Botan::Credentials_Manager> creds_with_client_cert(create_creds(rng, true));
- test_modern_versions(results, *client_ses, *server_ses, *creds_with_client_cert, "ECDH", "AES-256/GCM");
+ test_modern_versions("AES-256/GCM client certs",
+ results, *client_ses, *server_ses, *creds_with_client_cert, "ECDH", "AES-256/GCM", "AEAD", true);
#if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
client_ses.reset(new Botan::TLS::Session_Manager_In_Memory(rng));
@@ -1394,31 +1086,32 @@ class TLS_Unit_Tests final : public Test
#endif
#if defined(BOTAN_HAS_AEAD_OCB)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/OCB(12)");
+ test_modern_versions("AES-128/OCB ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/OCB(12)");
#endif
server_ses->remove_all();
#if defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "ChaCha20Poly1305");
+ test_modern_versions("ChaCha20Poly1305 ECDH", results, *client_ses, *server_ses, *creds, "ECDH", "ChaCha20Poly1305");
#endif
- test_modern_versions(results, *client_ses, *server_ses, *creds, "PSK", "AES-128/GCM");
+ test_modern_versions("AES-128/GCM PSK", results, *client_ses, *server_ses, *creds, "PSK", "AES-128/GCM");
#if defined(BOTAN_HAS_CCM)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "PSK", "AES-128/CCM");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "PSK", "AES-128/CCM(8)");
+ test_modern_versions("AES-128/CCM PSK", results, *client_ses, *server_ses, *creds, "PSK", "AES-128/CCM");
+ test_modern_versions("AES-128/CCM-8 PSK", results, *client_ses, *server_ses, *creds, "PSK", "AES-128/CCM(8)");
#endif
#if defined(BOTAN_HAS_TLS_CBC)
// For whatever reason no (EC)DHE_PSK GCM ciphersuites are defined
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDHE_PSK", "AES-128", "SHA-256");
- test_modern_versions(results, *client_ses, *server_ses, *creds, "DHE_PSK", "AES-128", "SHA-1");
+ test_modern_versions("AES-128 ECDHE_PSK", results, *client_ses, *server_ses, *creds, "ECDHE_PSK", "AES-128", "SHA-256");
+ test_modern_versions("AES-128 DHE_PSK", results, *client_ses, *server_ses, *creds, "DHE_PSK", "AES-128", "SHA-1");
#endif
#if defined(BOTAN_HOUSE_ECC_CURVE_NAME)
- test_modern_versions(results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
- { { "groups", BOTAN_HOUSE_ECC_CURVE_NAME } });
+ test_modern_versions("AES-128/GCM house curve",
+ results, *client_ses, *server_ses, *creds, "ECDH", "AES-128/GCM", "AEAD",
+ { { "groups", BOTAN_HOUSE_ECC_CURVE_NAME } });
#endif
return results;