Botan  2.12.1
Crypto and TLS for C++11
tls_ciphersuite.cpp
Go to the documentation of this file.
1 /*
2 * TLS Cipher Suite
3 * (C) 2004-2010,2012,2013 Jack Lloyd
4 *
5 * Botan is released under the Simplified BSD License (see license.txt)
6 */
7 
8 #include <botan/tls_ciphersuite.h>
9 #include <botan/exceptn.h>
10 #include <botan/parsing.h>
11 #include <botan/block_cipher.h>
12 #include <botan/stream_cipher.h>
13 #include <botan/hash.h>
14 #include <algorithm>
15 
16 namespace Botan {
17 
18 namespace TLS {
19 
21  {
22  switch(m_nonce_format)
23  {
25  {
26  if(cipher_algo() == "3DES")
27  return 8;
28  else
29  return 16;
30  }
32  return 4;
34  return 12;
35  }
36 
37  throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
38  }
39 
41  {
42  switch(m_nonce_format)
43  {
45  {
46  if(version.supports_explicit_cbc_ivs())
47  {
48  return cipher_algo() == "3DES" ? 8 : 16;
49  }
50  else
51  {
52  return 0;
53  }
54  }
56  return 8;
58  return 0;
59  }
60 
61  throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
62  }
63 
64 bool Ciphersuite::is_scsv(uint16_t suite)
65  {
66  // TODO: derive from IANA file in script
67  return (suite == 0x00FF || suite == 0x5600);
68  }
69 
71  {
72  return kex_method() == Kex_Algo::PSK ||
75  }
76 
78  {
79  return kex_method() == Kex_Algo::ECDH ||
82  }
83 
85  {
86  if(!version.supports_aead_modes())
87  {
88  // Old versions do not support AEAD, or any MAC but SHA-1
89  if(mac_algo() != "SHA-1")
90  return false;
91  }
92 
93  return true;
94  }
95 
97  {
98  return (mac_algo() != "AEAD");
99  }
100 
102  {
103  return auth_method() != Auth_Method::ANONYMOUS &&
105  }
106 
108  {
109  const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
110  auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite);
111 
112  if(s != all_suites.end() && s->ciphersuite_code() == suite)
113  {
114  return *s;
115  }
116 
117  return Ciphersuite(); // some unknown ciphersuite
118  }
119 
121  {
122  const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
123 
124  for(auto suite : all_suites)
125  {
126  if(suite.to_string() == name)
127  return suite;
128  }
129 
130  return Ciphersuite(); // some unknown ciphersuite
131  }
132 
133 namespace {
134 
135 bool have_hash(const std::string& prf)
136  {
137  return (HashFunction::providers(prf).size() > 0);
138  }
139 
140 bool have_cipher(const std::string& cipher)
141  {
142  return (BlockCipher::providers(cipher).size() > 0) ||
143  (StreamCipher::providers(cipher).size() > 0);
144  }
145 
146 }
147 
148 bool Ciphersuite::is_usable() const
149  {
150  if(!m_cipher_keylen) // uninitialized object
151  return false;
152 
153  if(!have_hash(prf_algo()))
154  return false;
155 
156 #if !defined(BOTAN_HAS_TLS_CBC)
157  if(cbc_ciphersuite())
158  return false;
159 #endif
160 
161  if(mac_algo() == "AEAD")
162  {
163  if(cipher_algo() == "ChaCha20Poly1305")
164  {
165 #if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
166  return false;
167 #endif
168  }
169  else
170  {
171  auto cipher_and_mode = split_on(cipher_algo(), '/');
172  BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo");
173  if(!have_cipher(cipher_and_mode[0]))
174  return false;
175 
176  const auto mode = cipher_and_mode[1];
177 
178 #if !defined(BOTAN_HAS_AEAD_CCM)
179  if(mode == "CCM" || mode == "CCM-8")
180  return false;
181 #endif
182 
183 #if !defined(BOTAN_HAS_AEAD_GCM)
184  if(mode == "GCM")
185  return false;
186 #endif
187 
188 #if !defined(BOTAN_HAS_AEAD_OCB)
189  if(mode == "OCB(12)" || mode == "OCB")
190  return false;
191 #endif
192  }
193  }
194  else
195  {
196  // Old non-AEAD schemes
197  if(!have_cipher(cipher_algo()))
198  return false;
199  if(!have_hash(mac_algo())) // HMAC
200  return false;
201  }
202 
204  {
205 #if !defined(BOTAN_HAS_SRP6)
206  return false;
207 #endif
208  }
210  {
211 #if !defined(BOTAN_HAS_ECDH)
212  return false;
213 #endif
214  }
216  {
217 #if !defined(BOTAN_HAS_DIFFIE_HELLMAN)
218  return false;
219 #endif
220  }
221  else if(kex_method() == Kex_Algo::CECPQ1)
222  {
223 #if !defined(BOTAN_HAS_CECPQ1)
224  return false;
225 #endif
226  }
227 
229  {
230 #if !defined(BOTAN_HAS_DSA)
231  return false;
232 #endif
233  }
234  else if(auth_method() == Auth_Method::ECDSA)
235  {
236 #if !defined(BOTAN_HAS_ECDSA)
237  return false;
238 #endif
239  }
240  else if(auth_method() == Auth_Method::RSA)
241  {
242 #if !defined(BOTAN_HAS_RSA)
243  return false;
244 #endif
245  }
246 
247  return true;
248  }
249 
250 }
251 
252 }
253 
std::string mac_algo() const
size_t nonce_bytes_from_record(Protocol_Version version) const
bool usable_in_version(Protocol_Version version) const
std::string prf_algo() const
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:148
Auth_Method auth_method() const
static bool is_scsv(uint16_t suite)
Kex_Algo kex_method() const
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:55
static std::vector< std::string > providers(const std::string &algo_spec)
std::string name
bool supports_explicit_cbc_ivs() const
Definition: tls_version.cpp:67
size_t nonce_bytes_from_handshake() const
static std::vector< std::string > providers(const std::string &algo_spec)
Definition: hash.cpp:354
Definition: alg_id.cpp:13
static std::vector< std::string > providers(const std::string &algo_spec)
static Ciphersuite by_id(uint16_t suite)
std::string cipher_algo() const
static const std::vector< Ciphersuite > & all_known_ciphersuites()
static Ciphersuite from_name(const std::string &name)