Botan
1.11.15
|
00001 /* 00002 * TLS Cipher Suite 00003 * (C) 2004-2010,2012,2013 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/tls_ciphersuite.h> 00009 #include <botan/parsing.h> 00010 #include <botan/internal/algo_registry.h> 00011 #include <botan/block_cipher.h> 00012 #include <botan/stream_cipher.h> 00013 #include <botan/hash.h> 00014 #include <botan/mac.h> 00015 #include <sstream> 00016 #include <stdexcept> 00017 00018 namespace Botan { 00019 00020 namespace TLS { 00021 00022 namespace { 00023 00024 /* 00025 * This way all work happens at the constuctor call, and we can 00026 * rely on that happening only once in C++11. 00027 */ 00028 std::vector<Ciphersuite> gather_known_ciphersuites() 00029 { 00030 std::vector<Ciphersuite> ciphersuites; 00031 00032 for(size_t i = 0; i <= 0xFFFF; ++i) 00033 { 00034 Ciphersuite suite = Ciphersuite::by_id(i); 00035 00036 if(suite.valid()) 00037 ciphersuites.push_back(suite); 00038 } 00039 00040 return ciphersuites; 00041 } 00042 00043 } 00044 00045 const std::vector<Ciphersuite>& Ciphersuite::all_known_ciphersuites() 00046 { 00047 static std::vector<Ciphersuite> all_ciphersuites(gather_known_ciphersuites()); 00048 return all_ciphersuites; 00049 } 00050 00051 Ciphersuite Ciphersuite::by_name(const std::string& name) 00052 { 00053 for(auto suite : all_known_ciphersuites()) 00054 { 00055 if(suite.to_string() == name) 00056 return suite; 00057 } 00058 00059 return Ciphersuite(); // some unknown ciphersuite 00060 } 00061 00062 bool Ciphersuite::is_scsv(u16bit suite) 00063 { 00064 // TODO: derive from IANA file in script 00065 return (suite == 0x00FF || suite == 0x5600); 00066 } 00067 00068 Ciphersuite::Ciphersuite(u16bit ciphersuite_code, 00069 const char* sig_algo, 00070 const char* kex_algo, 00071 const char* cipher_algo, 00072 size_t cipher_keylen, 00073 size_t nonce_bytes_from_handshake, 00074 size_t nonce_bytes_from_record, 00075 const char* mac_algo, 00076 size_t mac_keylen, 00077 const char* prf_algo) : 00078 m_ciphersuite_code(ciphersuite_code), 00079 m_sig_algo(sig_algo), 00080 m_kex_algo(kex_algo), 00081 m_prf_algo(prf_algo), 00082 m_cipher_algo(cipher_algo), 00083 m_cipher_keylen(cipher_keylen), 00084 m_nonce_bytes_from_handshake(nonce_bytes_from_handshake), 00085 m_nonce_bytes_from_record(nonce_bytes_from_record), 00086 m_mac_algo(mac_algo), 00087 m_mac_keylen(mac_keylen) 00088 { 00089 } 00090 00091 bool Ciphersuite::psk_ciphersuite() const 00092 { 00093 return (kex_algo() == "PSK" || 00094 kex_algo() == "DHE_PSK" || 00095 kex_algo() == "ECDHE_PSK"); 00096 } 00097 00098 bool Ciphersuite::ecc_ciphersuite() const 00099 { 00100 return (sig_algo() == "ECDSA" || kex_algo() == "ECDH" || kex_algo() == "ECDHE_PSK"); 00101 } 00102 00103 namespace { 00104 00105 bool have_hash(const std::string& prf) 00106 { 00107 if(Algo_Registry<HashFunction>::global_registry().providers_of(prf).size() > 0) 00108 return true; 00109 return false; 00110 } 00111 00112 bool have_cipher(const std::string& cipher) 00113 { 00114 if(Algo_Registry<BlockCipher>::global_registry().providers_of(cipher).size() > 0) 00115 return true; 00116 if(Algo_Registry<StreamCipher>::global_registry().providers_of(cipher).size() > 0) 00117 return true; 00118 return false; 00119 } 00120 00121 } 00122 00123 bool Ciphersuite::valid() const 00124 { 00125 if(!m_cipher_keylen) // uninitialized object 00126 return false; 00127 00128 if(!have_hash(prf_algo())) 00129 return false; 00130 00131 if(mac_algo() == "AEAD") 00132 { 00133 if(cipher_algo() == "ChaCha20Poly1305") 00134 { 00135 #if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) 00136 return false; 00137 #endif 00138 } 00139 else 00140 { 00141 auto cipher_and_mode = split_on(cipher_algo(), '/'); 00142 BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); 00143 if(!have_cipher(cipher_and_mode[0])) 00144 return false; 00145 00146 const auto mode = cipher_and_mode[1]; 00147 00148 #if !defined(BOTAN_HAS_AEAD_CCM) 00149 if(mode == "CCM" || mode == "CCM-8") 00150 return false; 00151 #endif 00152 00153 #if !defined(BOTAN_HAS_AEAD_GCM) 00154 if(mode == "GCM") 00155 return false; 00156 #endif 00157 00158 #if !defined(BOTAN_HAS_AEAD_OCB) 00159 if(mode == "OCB(12)" || mode == "OCB") 00160 return false; 00161 #endif 00162 } 00163 } 00164 else 00165 { 00166 // Old non-AEAD schemes 00167 if(!have_cipher(cipher_algo())) 00168 return false; 00169 if(!have_hash(mac_algo())) // HMAC 00170 return false; 00171 } 00172 00173 if(kex_algo() == "SRP_SHA") 00174 { 00175 #if !defined(BOTAN_HAS_SRP6) 00176 return false; 00177 #endif 00178 } 00179 else if(kex_algo() == "ECDH" || kex_algo() == "ECDHE_PSK") 00180 { 00181 #if !defined(BOTAN_HAS_ECDH) 00182 return false; 00183 #endif 00184 } 00185 else if(kex_algo() == "DH" || kex_algo() == "DHE_PSK") 00186 { 00187 #if !defined(BOTAN_HAS_DIFFIE_HELLMAN) 00188 return false; 00189 #endif 00190 } 00191 00192 if(sig_algo() == "DSA") 00193 { 00194 #if !defined(BOTAN_HAS_DSA) 00195 return false; 00196 #endif 00197 } 00198 else if(sig_algo() == "ECDSA") 00199 { 00200 #if !defined(BOTAN_HAS_ECDSA) 00201 return false; 00202 #endif 00203 } 00204 else if(sig_algo() == "RSA") 00205 { 00206 #if !defined(BOTAN_HAS_RSA) 00207 return false; 00208 #endif 00209 } 00210 00211 return true; 00212 } 00213 00214 std::string Ciphersuite::to_string() const 00215 { 00216 if(m_cipher_keylen == 0) 00217 throw std::runtime_error("Ciphersuite::to_string - no value set"); 00218 00219 std::ostringstream out; 00220 00221 out << "TLS_"; 00222 00223 if(kex_algo() != "RSA") 00224 { 00225 if(kex_algo() == "DH") 00226 out << "DHE"; 00227 else if(kex_algo() == "ECDH") 00228 out << "ECDHE"; 00229 else 00230 out << kex_algo(); 00231 00232 out << '_'; 00233 } 00234 00235 if(sig_algo() == "DSA") 00236 out << "DSS_"; 00237 else if(sig_algo() != "") 00238 out << sig_algo() << '_'; 00239 00240 out << "WITH_"; 00241 00242 if(cipher_algo() == "RC4") 00243 { 00244 out << "RC4_128_"; 00245 } 00246 else if(cipher_algo() == "ChaCha20Poly1305") 00247 { 00248 out << "CHACHA20_POLY1305_"; 00249 } 00250 else 00251 { 00252 if(cipher_algo() == "3DES") 00253 out << "3DES_EDE"; 00254 else if(cipher_algo().find("Camellia") == 0) 00255 out << "CAMELLIA_" << std::to_string(8*cipher_keylen()); 00256 else 00257 { 00258 if(cipher_algo().find("OCB(12)") != std::string::npos) 00259 out << replace_chars(cipher_algo().substr(0, cipher_algo().size() - 4), 00260 {'-', '/'}, '_'); 00261 else 00262 out << replace_chars(cipher_algo(), {'-', '/'}, '_'); 00263 } 00264 00265 if(cipher_algo().find("/") != std::string::npos) 00266 out << "_"; // some explicit mode already included 00267 else 00268 out << "_CBC_"; 00269 } 00270 00271 if(mac_algo() == "SHA-1") 00272 out << "SHA"; 00273 else if(mac_algo() == "AEAD") 00274 out << erase_chars(prf_algo(), {'-'}); 00275 else 00276 out << erase_chars(mac_algo(), {'-'}); 00277 00278 return out.str(); 00279 } 00280 00281 } 00282 00283 } 00284