diff options
Diffstat (limited to 'comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp')
-rw-r--r-- | comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp b/comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp new file mode 100644 index 0000000000..cf284e5650 --- /dev/null +++ b/comm/third_party/botan/src/lib/tls/tls_ciphersuite.cpp @@ -0,0 +1,253 @@ +/* +* TLS Cipher Suite +* (C) 2004-2010,2012,2013 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/tls_ciphersuite.h> +#include <botan/exceptn.h> +#include <botan/parsing.h> +#include <botan/block_cipher.h> +#include <botan/stream_cipher.h> +#include <botan/hash.h> +#include <algorithm> + +namespace Botan { + +namespace TLS { + +size_t Ciphersuite::nonce_bytes_from_handshake() const + { + switch(m_nonce_format) + { + case Nonce_Format::CBC_MODE: + { + if(cipher_algo() == "3DES") + return 8; + else + return 16; + } + case Nonce_Format::AEAD_IMPLICIT_4: + return 4; + case Nonce_Format::AEAD_XOR_12: + return 12; + } + + throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); + } + +size_t Ciphersuite::nonce_bytes_from_record(Protocol_Version version) const + { + switch(m_nonce_format) + { + case Nonce_Format::CBC_MODE: + { + if(version.supports_explicit_cbc_ivs()) + { + return cipher_algo() == "3DES" ? 8 : 16; + } + else + { + return 0; + } + } + case Nonce_Format::AEAD_IMPLICIT_4: + return 8; + case Nonce_Format::AEAD_XOR_12: + return 0; + } + + throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); + } + +bool Ciphersuite::is_scsv(uint16_t suite) + { + // TODO: derive from IANA file in script + return (suite == 0x00FF || suite == 0x5600); + } + +bool Ciphersuite::psk_ciphersuite() const + { + return kex_method() == Kex_Algo::PSK || + kex_method() == Kex_Algo::DHE_PSK || + kex_method() == Kex_Algo::ECDHE_PSK; + } + +bool Ciphersuite::ecc_ciphersuite() const + { + return kex_method() == Kex_Algo::ECDH || + kex_method() == Kex_Algo::ECDHE_PSK || + auth_method() == Auth_Method::ECDSA; + } + +bool Ciphersuite::usable_in_version(Protocol_Version version) const + { + if(!version.supports_aead_modes()) + { + // Old versions do not support AEAD, or any MAC but SHA-1 + if(mac_algo() != "SHA-1") + return false; + } + + return true; + } + +bool Ciphersuite::cbc_ciphersuite() const + { + return (mac_algo() != "AEAD"); + } + +bool Ciphersuite::signature_used() const + { + return auth_method() != Auth_Method::ANONYMOUS && + auth_method() != Auth_Method::IMPLICIT; + } + +Ciphersuite Ciphersuite::by_id(uint16_t suite) + { + const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites(); + auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite); + + if(s != all_suites.end() && s->ciphersuite_code() == suite) + { + return *s; + } + + return Ciphersuite(); // some unknown ciphersuite + } + +Ciphersuite Ciphersuite::from_name(const std::string& name) + { + const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites(); + + for(auto suite : all_suites) + { + if(suite.to_string() == name) + return suite; + } + + return Ciphersuite(); // some unknown ciphersuite + } + +namespace { + +bool have_hash(const std::string& prf) + { + return (HashFunction::providers(prf).size() > 0); + } + +bool have_cipher(const std::string& cipher) + { + return (BlockCipher::providers(cipher).size() > 0) || + (StreamCipher::providers(cipher).size() > 0); + } + +} + +bool Ciphersuite::is_usable() const + { + if(!m_cipher_keylen) // uninitialized object + return false; + + if(!have_hash(prf_algo())) + return false; + +#if !defined(BOTAN_HAS_TLS_CBC) + if(cbc_ciphersuite()) + return false; +#endif + + if(mac_algo() == "AEAD") + { + if(cipher_algo() == "ChaCha20Poly1305") + { +#if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) + return false; +#endif + } + else + { + auto cipher_and_mode = split_on(cipher_algo(), '/'); + BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); + if(!have_cipher(cipher_and_mode[0])) + return false; + + const auto mode = cipher_and_mode[1]; + +#if !defined(BOTAN_HAS_AEAD_CCM) + if(mode == "CCM" || mode == "CCM-8") + return false; +#endif + +#if !defined(BOTAN_HAS_AEAD_GCM) + if(mode == "GCM") + return false; +#endif + +#if !defined(BOTAN_HAS_AEAD_OCB) + if(mode == "OCB(12)" || mode == "OCB") + return false; +#endif + } + } + else + { + // Old non-AEAD schemes + if(!have_cipher(cipher_algo())) + return false; + if(!have_hash(mac_algo())) // HMAC + return false; + } + + if(kex_method() == Kex_Algo::SRP_SHA) + { +#if !defined(BOTAN_HAS_SRP6) + return false; +#endif + } + else if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK) + { +#if !defined(BOTAN_HAS_ECDH) + return false; +#endif + } + else if(kex_method() == Kex_Algo::DH || kex_method() == Kex_Algo::DHE_PSK) + { +#if !defined(BOTAN_HAS_DIFFIE_HELLMAN) + return false; +#endif + } + else if(kex_method() == Kex_Algo::CECPQ1) + { +#if !defined(BOTAN_HAS_CECPQ1) + return false; +#endif + } + + if(auth_method() == Auth_Method::DSA) + { +#if !defined(BOTAN_HAS_DSA) + return false; +#endif + } + else if(auth_method() == Auth_Method::ECDSA) + { +#if !defined(BOTAN_HAS_ECDSA) + return false; +#endif + } + else if(auth_method() == Auth_Method::RSA) + { +#if !defined(BOTAN_HAS_RSA) + return false; +#endif + } + + return true; + } + +} + +} + |