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