diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/tls/c_hello.cpp | 2 | ||||
-rw-r--r-- | src/tls/tls_policy.cpp | 232 | ||||
-rw-r--r-- | src/tls/tls_policy.h | 58 | ||||
-rw-r--r-- | src/tls/tls_server.cpp | 11 | ||||
-rw-r--r-- | src/tls/tls_suites.cpp | 72 |
5 files changed, 231 insertions, 144 deletions
diff --git a/src/tls/c_hello.cpp b/src/tls/c_hello.cpp index 99011822e..e56996ee5 100644 --- a/src/tls/c_hello.cpp +++ b/src/tls/c_hello.cpp @@ -85,7 +85,7 @@ Client_Hello::Client_Hello(Record_Writer& writer, const std::string& srp_identifier) : m_version(policy.pref_version()), m_random(make_hello_random(rng)), - m_suites(policy.ciphersuites(srp_identifier != "")), + m_suites(policy.ciphersuite_list((srp_identifier != ""))), m_comp_methods(policy.compression()), m_hostname(hostname), m_srp_identifier(srp_identifier), diff --git a/src/tls/tls_policy.cpp b/src/tls/tls_policy.cpp index b510c3d4b..bc0cd53f5 100644 --- a/src/tls/tls_policy.cpp +++ b/src/tls/tls_policy.cpp @@ -1,95 +1,166 @@ /* * Policies for TLS -* (C) 2004-2010 Jack Lloyd +* (C) 2004-2010,2012 Jack Lloyd * * Released under the terms of the Botan license */ #include <botan/tls_policy.h> +#include <botan/tls_suites.h> #include <botan/tls_exceptn.h> +#include <botan/internal/stl_util.h> namespace Botan { -/* -* Return allowed ciphersuites -*/ -std::vector<u16bit> TLS_Policy::ciphersuites(bool have_srp) const +std::vector<std::string> TLS_Policy::allowed_ciphers() const { - return suite_list(allow_static_rsa(), allow_edh_rsa(), allow_edh_dsa(), - allow_srp() && have_srp); + std::vector<std::string> allowed; + allowed.push_back("AES-256"); + allowed.push_back("AES-128"); + allowed.push_back("TripleDES"); + allowed.push_back("ARC4"); + // Note that SEED is not included by default + return allowed; } -/* -* Return allowed ciphersuites -*/ -std::vector<u16bit> TLS_Policy::suite_list(bool use_rsa, - bool use_edh_rsa, - bool use_edh_dsa, - bool use_srp) const +std::vector<std::string> TLS_Policy::allowed_hashes() const { - std::vector<u16bit> suites; + std::vector<std::string> allowed; + allowed.push_back("SHA-256"); + allowed.push_back("SHA-1"); + // Note that MD5 is not included by default + return allowed; + } - if(use_srp) - { - if(use_edh_rsa) - { - suites.push_back(TLS_SRP_SHA_DSS_WITH_AES_256_SHA); - suites.push_back(TLS_SRP_SHA_DSS_WITH_AES_128_SHA); - suites.push_back(TLS_SRP_SHA_DSS_WITH_3DES_EDE_SHA); - } +std::vector<std::string> TLS_Policy::allowed_key_exchange_methods() const + { + std::vector<std::string> allowed; + //allowed.push_back("ECDH"); + //allowed.push_back("SRP"); + allowed.push_back("DH"); + allowed.push_back(""); // means RSA via server cert + return allowed; + } - if(use_edh_dsa) +std::vector<std::string> TLS_Policy::allowed_signature_methods() const + { + std::vector<std::string> allowed; + //allowed.push_back("ECDSA"); + allowed.push_back("RSA"); + allowed.push_back("DSA"); + return allowed; + } + +namespace { + +class Ciphersuite_Preference_Ordering + { + public: + Ciphersuite_Preference_Ordering(const std::vector<std::string>& ciphers, + const std::vector<std::string>& hashes, + const std::vector<std::string>& kex, + const std::vector<std::string>& sigs) : + m_ciphers(ciphers), m_hashes(hashes), m_kex(kex), m_sigs(sigs) {} + + bool operator()(const TLS_Ciphersuite& a, const TLS_Ciphersuite& b) const { - suites.push_back(TLS_SRP_SHA_RSA_WITH_AES_256_SHA); - suites.push_back(TLS_SRP_SHA_RSA_WITH_AES_128_SHA); - suites.push_back(TLS_SRP_SHA_RSA_WITH_3DES_EDE_SHA); + if(a.kex_algo() != b.kex_algo()) + { + for(size_t i = 0; i != m_kex.size(); ++i) + { + if(a.kex_algo() == m_kex[i]) + return true; + if(b.kex_algo() == m_kex[i]) + return false; + } + } + + if(a.cipher_algo() != b.cipher_algo()) + { + for(size_t i = 0; i != m_ciphers.size(); ++i) + { + if(a.cipher_algo() == m_ciphers[i]) + return true; + if(b.cipher_algo() == m_ciphers[i]) + return false; + } + } + + if(a.sig_algo() != b.sig_algo()) + { + for(size_t i = 0; i != m_sigs.size(); ++i) + { + if(a.sig_algo() == m_sigs[i]) + return true; + if(b.sig_algo() == m_sigs[i]) + return false; + } + } + + if(a.mac_algo() != b.mac_algo()) + { + for(size_t i = 0; i != m_hashes.size(); ++i) + { + if(a.mac_algo() == m_hashes[i]) + return true; + if(b.mac_algo() == m_hashes[i]) + return false; + } + } + + return false; // equal (?!?) } - } + private: + std::vector<std::string> m_ciphers, m_hashes, m_kex, m_sigs; - if(use_edh_dsa) - { - suites.push_back(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256); - suites.push_back(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256); + }; - suites.push_back(TLS_DHE_DSS_WITH_AES_256_CBC_SHA); - suites.push_back(TLS_DHE_DSS_WITH_AES_128_CBC_SHA); +} - suites.push_back(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA); - suites.push_back(TLS_DHE_DSS_WITH_SEED_CBC_SHA); - } +std::vector<u16bit> TLS_Policy::ciphersuite_list(bool have_srp) const + { + std::vector<std::string> ciphers = allowed_ciphers(); + std::vector<std::string> hashes = allowed_hashes(); + std::vector<std::string> kex = allowed_key_exchange_methods(); + std::vector<std::string> sigs = allowed_signature_methods(); - if(use_edh_rsa) + if(!have_srp) { - suites.push_back(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256); - suites.push_back(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256); - - suites.push_back(TLS_DHE_RSA_WITH_AES_256_CBC_SHA); - suites.push_back(TLS_DHE_RSA_WITH_AES_128_CBC_SHA); + std::vector<std::string>::iterator i = std::find(kex.begin(), kex.end(), "SRP"); - suites.push_back(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA); - suites.push_back(TLS_DHE_RSA_WITH_SEED_CBC_SHA); + if(i != kex.end()) + kex.erase(i); } - if(use_rsa) - { - suites.push_back(TLS_RSA_WITH_AES_256_CBC_SHA256); - suites.push_back(TLS_RSA_WITH_AES_128_CBC_SHA256); + Ciphersuite_Preference_Ordering order(ciphers, hashes, kex, sigs); - suites.push_back(TLS_RSA_WITH_AES_256_CBC_SHA); - suites.push_back(TLS_RSA_WITH_AES_128_CBC_SHA); + std::map<TLS_Ciphersuite, u16bit, Ciphersuite_Preference_Ordering> ciphersuites(order); - suites.push_back(TLS_RSA_WITH_3DES_EDE_CBC_SHA); - suites.push_back(TLS_RSA_WITH_SEED_CBC_SHA); - - suites.push_back(TLS_RSA_WITH_RC4_128_SHA); - suites.push_back(TLS_RSA_WITH_RC4_128_MD5); + // When in doubt use brute force :) + for(u32bit i = 0; i != 65536; ++i) + { + TLS_Ciphersuite suite = TLS_Ciphersuite::lookup_ciphersuite(i); + if(suite.cipher_keylen() == 0) + continue; // not a ciphersuite we know + + if(value_exists(ciphers, suite.cipher_algo()) && + value_exists(hashes, suite.mac_algo()) && + value_exists(kex, suite.kex_algo()) && + value_exists(sigs, suite.sig_algo())) + { + ciphersuites[suite] = i; + } } - if(suites.size() == 0) - throw TLS_Exception(INTERNAL_ERROR, - "TLS_Policy error: All ciphersuites disabled"); + std::vector<u16bit> ciphersuite_codes; + + for(std::map<TLS_Ciphersuite, u16bit, Ciphersuite_Preference_Ordering>::iterator i = ciphersuites.begin(); + i != ciphersuites.end(); ++i) + { + ciphersuite_codes.push_back(i->second); + } - return suites; + return ciphersuite_codes; } /* @@ -105,23 +176,30 @@ std::vector<byte> TLS_Policy::compression() const /* * Choose which ciphersuite to use */ -u16bit TLS_Policy::choose_suite(const std::vector<u16bit>& c_suites, +u16bit TLS_Policy::choose_suite(const std::vector<u16bit>& client_suites, bool have_rsa, bool have_dsa, bool have_srp) const { - const bool use_static_rsa = allow_static_rsa() && have_rsa; - const bool use_edh_rsa = allow_edh_rsa() && have_rsa; - const bool use_edh_dsa = allow_edh_dsa() && have_dsa; - const bool use_srp = allow_srp() && have_srp; - - std::vector<u16bit> s_suites = suite_list(use_static_rsa, use_edh_rsa, - use_edh_dsa, use_srp); - - for(size_t i = 0; i != s_suites.size(); ++i) - for(size_t j = 0; j != c_suites.size(); ++j) - if(s_suites[i] == c_suites[j]) - return s_suites[i]; + for(size_t i = 0; i != client_suites.size(); ++i) + { + u16bit suite_id = client_suites[i]; + TLS_Ciphersuite suite = TLS_Ciphersuite::lookup_ciphersuite(suite_id); + if(suite.cipher_keylen() == 0) + continue; // not a ciphersuite we know + + if(!have_srp && suite.kex_algo() == "SRP") + continue; + + if(suite.sig_algo() == "RSA" && have_rsa) + return suite_id; + else if(suite.sig_algo() == "DSA" && have_dsa) + return suite_id; +#if 0 + else if(suite.sig_algo() == "") // anonymous server + return suite_id; +#endif + } return 0; } @@ -141,12 +219,4 @@ byte TLS_Policy::choose_compression(const std::vector<byte>& c_comp) const return NO_COMPRESSION; } -/* -* Return the group to use for empheral DH -*/ -DL_Group TLS_Policy::dh_group() const - { - return DL_Group("modp/ietf/1024"); - } - } diff --git a/src/tls/tls_policy.h b/src/tls/tls_policy.h index 48ff9185e..c14709e7e 100644 --- a/src/tls/tls_policy.h +++ b/src/tls/tls_policy.h @@ -22,27 +22,50 @@ namespace Botan { class BOTAN_DLL TLS_Policy { public: - std::vector<u16bit> ciphersuites(bool have_srp) const; - virtual std::vector<byte> compression() const; + /* + * Return allowed ciphersuites, in order of preference + */ + std::vector<u16bit> ciphersuite_list(bool have_srp) const; + + u16bit choose_suite(const std::vector<u16bit>& client_suites, + bool have_rsa, + bool have_dsa, + bool have_srp) const; + + byte choose_compression(const std::vector<byte>& client_algos) const; + + std::vector<std::string> allowed_ciphers() const; + + std::vector<std::string> allowed_hashes() const; - virtual u16bit choose_suite(const std::vector<u16bit>& client_suites, - bool rsa_ok, - bool dsa_ok, - bool srp_ok) const; + std::vector<std::string> allowed_key_exchange_methods() const; - virtual byte choose_compression(const std::vector<byte>& client) const; + std::vector<std::string> allowed_signature_methods() const; - virtual bool allow_static_rsa() const { return true; } - virtual bool allow_edh_rsa() const { return true; } - virtual bool allow_edh_dsa() const { return true; } - virtual bool allow_srp() const { return true; } + virtual std::vector<byte> compression() const; - virtual bool require_client_auth() const { return false; } + 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. + * + * @warning Changing this to false exposes you to injected + * plaintext attacks. + */ virtual bool require_secure_renegotiation() const { return true; } - virtual DL_Group dh_group() const; - virtual size_t rsa_export_keysize() const { return 512; } + /** + * Return the group to use for ephemeral Diffie-Hellman key agreement + */ + virtual DL_Group dh_group() const { return DL_Group("modp/ietf/1536"); } /* * @return the minimum version that we will negotiate @@ -54,14 +77,7 @@ class BOTAN_DLL TLS_Policy */ virtual Version_Code pref_version() const { return TLS_V11; } - virtual bool check_cert(const std::vector<X509_Certificate>& cert_chain) const = 0; - virtual ~TLS_Policy() {} - private: - virtual std::vector<u16bit> suite_list(bool use_rsa, - bool use_edh_rsa, - bool use_edh_dsa, - bool use_srp) const; }; } diff --git a/src/tls/tls_server.cpp b/src/tls/tls_server.cpp index c2627ac23..90ce3bf88 100644 --- a/src/tls/tls_server.cpp +++ b/src/tls/tls_server.cpp @@ -9,7 +9,6 @@ #include <botan/internal/tls_handshake_state.h> #include <botan/internal/tls_messages.h> #include <botan/internal/stl_util.h> -#include <botan/rsa.h> #include <botan/dh.h> namespace Botan { @@ -269,15 +268,13 @@ void TLS_Server::process_handshake_msg(Handshake_Type type, else state->kex_priv = PKCS8::copy_key(*private_key, rng); - if(policy.require_client_auth()) - { - // FIXME: figure out the allowed CAs/cert types - - std::vector<X509_Certificate> allowed_cas; + std::vector<X509_Certificate> client_auth_CAs = policy.client_auth_CAs(); + if(!client_auth_CAs.empty() && state->suite.sig_algo() != "") + { state->cert_req = new Certificate_Req(writer, state->hash, - allowed_cas, + client_auth_CAs, state->version); state->set_expected_next(CERTIFICATE); diff --git a/src/tls/tls_suites.cpp b/src/tls/tls_suites.cpp index 9a541d124..9c63cd593 100644 --- a/src/tls/tls_suites.cpp +++ b/src/tls/tls_suites.cpp @@ -15,27 +15,27 @@ namespace Botan { */ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) { - // RSA ciphersuites - switch(suite) { + // RSA ciphersuites + case TLS_RSA_WITH_RC4_128_MD5: return TLS_Ciphersuite("RSA", "", "MD5", "ARC4", 16); case TLS_RSA_WITH_RC4_128_SHA: - return TLS_Ciphersuite("RSA", "", "SHA1", "ARC4", 16); + return TLS_Ciphersuite("RSA", "", "SHA-1", "ARC4", 16); case TLS_RSA_WITH_3DES_EDE_CBC_SHA: - return TLS_Ciphersuite("RSA", "", "SHA1", "TripleDES", 24); + return TLS_Ciphersuite("RSA", "", "SHA-1", "TripleDES", 24); case TLS_RSA_WITH_AES_128_CBC_SHA: - return TLS_Ciphersuite("RSA", "", "SHA1", "AES-128", 16); + return TLS_Ciphersuite("RSA", "", "SHA-1", "AES-128", 16); case TLS_RSA_WITH_AES_256_CBC_SHA: - return TLS_Ciphersuite("RSA", "", "SHA1", "AES-256", 32); + return TLS_Ciphersuite("RSA", "", "SHA-1", "AES-256", 32); case TLS_RSA_WITH_SEED_CBC_SHA: - return TLS_Ciphersuite("RSA", "", "SHA1", "SEED", 16); + return TLS_Ciphersuite("RSA", "", "SHA-1", "SEED", 16); case TLS_RSA_WITH_AES_128_CBC_SHA256: return TLS_Ciphersuite("RSA", "", "SHA-256", "AES-128", 16); @@ -43,21 +43,22 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) case TLS_RSA_WITH_AES_256_CBC_SHA256: return TLS_Ciphersuite("RSA", "", "SHA-256", "AES-256", 32); - // DHE/DSS ciphersuites + // DHE/DSS ciphersuites + case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: - return TLS_Ciphersuite("DSA", "DH", "SHA1", "TripleDES", 24); + return TLS_Ciphersuite("DSA", "DH", "SHA-1", "TripleDES", 24); case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: - return TLS_Ciphersuite("DSA", "DH", "SHA1", "AES-128", 16); + return TLS_Ciphersuite("DSA", "DH", "SHA-1", "AES-128", 16); case TLS_DHE_DSS_WITH_SEED_CBC_SHA: - return TLS_Ciphersuite("DSA", "DH", "SHA1", "SEED", 16); + return TLS_Ciphersuite("DSA", "DH", "SHA-1", "SEED", 16); case TLS_DHE_DSS_WITH_RC4_128_SHA: - return TLS_Ciphersuite("DSA", "DH", "SHA1", "ARC4", 16); + return TLS_Ciphersuite("DSA", "DH", "SHA-1", "ARC4", 16); case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: - return TLS_Ciphersuite("DSA", "DH", "SHA1", "AES-256", 32); + return TLS_Ciphersuite("DSA", "DH", "SHA-1", "AES-256", 32); case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: return TLS_Ciphersuite("DSA", "DH", "SHA-256", "AES-128", 16); @@ -65,18 +66,19 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: return TLS_Ciphersuite("DSA", "DH", "SHA-256", "AES-256", 32); - // DHE/RSA ciphersuites + // DHE/RSA ciphersuites + case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: - return TLS_Ciphersuite("RSA", "DH", "SHA1", "TripleDES", 24); + return TLS_Ciphersuite("RSA", "DH", "SHA-1", "TripleDES", 24); case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: - return TLS_Ciphersuite("RSA", "DH", "SHA1", "AES-128", 16); + return TLS_Ciphersuite("RSA", "DH", "SHA-1", "AES-128", 16); case TLS_DHE_RSA_WITH_SEED_CBC_SHA: - return TLS_Ciphersuite("RSA", "DH", "SHA1", "SEED", 16); + return TLS_Ciphersuite("RSA", "DH", "SHA-1", "SEED", 16); case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: - return TLS_Ciphersuite("RSA", "DH", "SHA1", "AES-256", 32); + return TLS_Ciphersuite("RSA", "DH", "SHA-1", "AES-256", 32); case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: return TLS_Ciphersuite("RSA", "DH", "SHA-256", "AES-128", 16); @@ -84,37 +86,39 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: return TLS_Ciphersuite("RSA", "DH", "SHA-256", "AES-256", 32); - // SRP ciphersuites + // SRP ciphersuites + case TLS_SRP_SHA_RSA_WITH_3DES_EDE_SHA: - return TLS_Ciphersuite("RSA", "SRP", "SHA1", "TripleDES", 24); + return TLS_Ciphersuite("RSA", "SRP", "SHA-1", "TripleDES", 24); case TLS_SRP_SHA_DSS_WITH_3DES_EDE_SHA: - return TLS_Ciphersuite("DSA", "SRP", "SHA1", "TripleDES", 24); + return TLS_Ciphersuite("DSA", "SRP", "SHA-1", "TripleDES", 24); case TLS_SRP_SHA_RSA_WITH_AES_128_SHA: - return TLS_Ciphersuite("RSA", "SRP", "SHA1", "AES-128", 16); + return TLS_Ciphersuite("RSA", "SRP", "SHA-1", "AES-128", 16); case TLS_SRP_SHA_DSS_WITH_AES_128_SHA: - return TLS_Ciphersuite("DSA", "SRP", "SHA1", "AES-128", 16); + return TLS_Ciphersuite("DSA", "SRP", "SHA-1", "AES-128", 16); case TLS_SRP_SHA_RSA_WITH_AES_256_SHA: - return TLS_Ciphersuite("RSA", "SRP", "SHA1", "AES-256", 32); + return TLS_Ciphersuite("RSA", "SRP", "SHA-1", "AES-256", 32); case TLS_SRP_SHA_DSS_WITH_AES_256_SHA: - return TLS_Ciphersuite("DSA", "SRP", "SHA1", "AES-256", 32); + return TLS_Ciphersuite("DSA", "SRP", "SHA-1", "AES-256", 32); + + // ECC ciphersuites - // ECC ciphersuites case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: - return TLS_Ciphersuite("ECDSA", "ECDH", "SHA1", "ARC4", 16); + return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-1", "ARC4", 16); case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: - return TLS_Ciphersuite("ECDSA", "ECDH", "SHA1", "TripleDES", 24); + return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-1", "TripleDES", 24); case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: - return TLS_Ciphersuite("ECDSA", "ECDH", "SHA1", "AES-128", 16); + return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-128", 16); case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: - return TLS_Ciphersuite("ECDSA", "ECDH", "SHA1", "AES-256", 32); + return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-1", "AES-256", 32); case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-256", "AES-128", 16); @@ -123,16 +127,16 @@ TLS_Ciphersuite TLS_Ciphersuite::lookup_ciphersuite(u16bit suite) return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-384", "AES-256", 32); case TLS_ECDHE_RSA_WITH_RC4_128_SHA: - return TLS_Ciphersuite("RSA", "ECDH", "SHA1", "ARC4", 16); + return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "ARC4", 16); case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: - return TLS_Ciphersuite("RSA", "ECDH", "SHA1", "TripleDES", 24); + return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "TripleDES", 24); case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: - return TLS_Ciphersuite("RSA", "ECDH", "SHA1", "AES-128", 16); + return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "AES-128", 16); case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: - return TLS_Ciphersuite("RSA", "ECDH", "SHA1", "AES-256", 32); + return TLS_Ciphersuite("RSA", "ECDH", "SHA-1", "AES-256", 32); case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: return TLS_Ciphersuite("ECDSA", "ECDH", "SHA-256", "AES-128", 16); |