Botan 3.0.0-alpha0
Crypto and TLS for C&
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/internal/parsing.h>
11#include <botan/block_cipher.h>
12#include <botan/stream_cipher.h>
13#include <botan/hash.h>
14#include <algorithm>
15
16namespace Botan::TLS {
17
19 {
20 switch(m_nonce_format)
21 {
23 {
24 if(cipher_algo() == "3DES")
25 return 8;
26 else
27 return 16;
28 }
30 return 4;
32 return 12;
33 }
34
35 throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
36 }
37
39 {
40 BOTAN_UNUSED(version);
41 switch(m_nonce_format)
42 {
44 return cipher_algo() == "3DES" ? 8 : 16;
46 return 8;
48 return 0;
49 }
50
51 throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
52 }
53
54bool Ciphersuite::is_scsv(uint16_t suite)
55 {
56 // TODO: derive from IANA file in script
57 return (suite == 0x00FF || suite == 0x5600);
58 }
59
61 {
62 return kex_method() == Kex_Algo::PSK ||
64 }
65
67 {
68 return kex_method() == Kex_Algo::ECDH ||
71 }
72
74 {
75 // RFC 8446 B.4.:
76 // Although TLS 1.3 uses the same cipher suite space as previous
77 // versions of TLS, TLS 1.3 cipher suites are defined differently, only
78 // specifying the symmetric ciphers, and cannot be used for TLS 1.2.
79 // Similarly, cipher suites for TLS 1.2 and lower cannot be used with
80 // TLS 1.3.
81 //
82 // Currently cipher suite codes {0x13,0x01} through {0x13,0x05} are
83 // allowed for TLS 1.3. This may change in the future.
84 const auto is_legacy_suite = (ciphersuite_code() & 0xFF00) != 0x1300;
85 return version.is_pre_tls_13() == is_legacy_suite;
86 }
87
89 {
90 return (mac_algo() != "AEAD");
91 }
92
94 {
96 }
97
98std::optional<Ciphersuite> Ciphersuite::by_id(uint16_t suite)
99 {
100 const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
101 auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite);
102
103 if(s != all_suites.end() && s->ciphersuite_code() == suite)
104 {
105 return *s;
106 }
107
108 return std::nullopt; // some unknown ciphersuite
109 }
110
111std::optional<Ciphersuite> Ciphersuite::from_name(const std::string& name)
112 {
113 const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
114
115 for(auto suite : all_suites)
116 {
117 if(suite.to_string() == name)
118 return suite;
119 }
120
121 return std::nullopt; // some unknown ciphersuite
122 }
123
124namespace {
125
126bool have_hash(const std::string& prf)
127 {
128 return (!HashFunction::providers(prf).empty());
129 }
130
131bool have_cipher(const std::string& cipher)
132 {
133 return (!BlockCipher::providers(cipher).empty()) ||
134 (!StreamCipher::providers(cipher).empty());
135 }
136
137}
138
139bool Ciphersuite::is_usable() const
140 {
141 if(!m_cipher_keylen) // uninitialized object
142 return false;
143
144 if(!have_hash(prf_algo()))
145 return false;
146
147#if !defined(BOTAN_HAS_TLS_CBC)
148 if(cbc_ciphersuite())
149 return false;
150#endif
151
152 if(mac_algo() == "AEAD")
153 {
154 if(cipher_algo() == "ChaCha20Poly1305")
155 {
156#if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
157 return false;
158#endif
159 }
160 else
161 {
162 auto cipher_and_mode = split_on(cipher_algo(), '/');
163 BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo");
164 if(!have_cipher(cipher_and_mode[0]))
165 return false;
166
167 const auto mode = cipher_and_mode[1];
168
169#if !defined(BOTAN_HAS_AEAD_CCM)
170 if(mode == "CCM" || mode == "CCM-8")
171 return false;
172#endif
173
174#if !defined(BOTAN_HAS_AEAD_GCM)
175 if(mode == "GCM")
176 return false;
177#endif
178
179#if !defined(BOTAN_HAS_AEAD_OCB)
180 if(mode == "OCB(12)" || mode == "OCB")
181 return false;
182#endif
183 }
184 }
185 else
186 {
187 // Old non-AEAD schemes
188 if(!have_cipher(cipher_algo()))
189 return false;
190 if(!have_hash(mac_algo())) // HMAC
191 return false;
192 }
193
195 {
196#if !defined(BOTAN_HAS_ECDH)
197 return false;
198#endif
199 }
200 else if(kex_method() == Kex_Algo::DH)
201 {
202#if !defined(BOTAN_HAS_DIFFIE_HELLMAN)
203 return false;
204#endif
205 }
206 else if(kex_method() == Kex_Algo::CECPQ1)
207 {
208#if !defined(BOTAN_HAS_CECPQ1)
209 return false;
210#endif
211 }
212
214 {
215#if !defined(BOTAN_HAS_ECDSA)
216 return false;
217#endif
218 }
219 else if(auth_method() == Auth_Method::RSA)
220 {
221#if !defined(BOTAN_HAS_RSA)
222 return false;
223#endif
224 }
225
226 return true;
227 }
228
229}
230
#define BOTAN_UNUSED(...)
Definition: assert.h:141
#define BOTAN_ASSERT(expr, assertion_made)
Definition: assert.h:54
static std::vector< std::string > providers(const std::string &algo_spec)
static std::vector< std::string > providers(const std::string &algo_spec)
Definition: hash.cpp:322
static std::vector< std::string > providers(const std::string &algo_spec)
uint16_t ciphersuite_code() const
size_t nonce_bytes_from_record(Protocol_Version version) const
static const std::vector< Ciphersuite > & all_known_ciphersuites()
Auth_Method auth_method() const
bool usable_in_version(Protocol_Version version) const
size_t nonce_bytes_from_handshake() const
static bool is_scsv(uint16_t suite)
static std::optional< Ciphersuite > by_id(uint16_t suite)
Kex_Algo kex_method() const
static std::optional< Ciphersuite > from_name(const std::string &name)
std::string mac_algo() const
std::string prf_algo() const
std::string cipher_algo() const
std::string name
std::vector< std::string > split_on(const std::string &str, char delim)
Definition: parsing.cpp:111