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