/src/botan/src/lib/tls/tls_ciphersuite.cpp
Line | Count | Source (jump to first uncovered line) |
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 | | |
20 | | size_t Ciphersuite::nonce_bytes_from_handshake() const |
21 | 17.5k | { |
22 | 17.5k | switch(m_nonce_format) |
23 | 17.5k | { |
24 | 6.84k | case Nonce_Format::CBC_MODE: |
25 | 6.84k | { |
26 | 6.84k | if(cipher_algo() == "3DES") |
27 | 3.13k | return 8; |
28 | 3.70k | else |
29 | 3.70k | return 16; |
30 | 0 | } |
31 | 9.65k | case Nonce_Format::AEAD_IMPLICIT_4: |
32 | 9.65k | return 4; |
33 | 1.05k | case Nonce_Format::AEAD_XOR_12: |
34 | 1.05k | return 12; |
35 | 0 | } |
36 | 0 | |
37 | 0 | throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); |
38 | 0 | } |
39 | | |
40 | | size_t Ciphersuite::nonce_bytes_from_record(Protocol_Version version) const |
41 | 2.67k | { |
42 | 2.67k | switch(m_nonce_format) |
43 | 2.67k | { |
44 | 1.03k | case Nonce_Format::CBC_MODE: |
45 | 1.03k | { |
46 | 1.03k | if(version.supports_explicit_cbc_ivs()) |
47 | 1.03k | { |
48 | 1.03k | return cipher_algo() == "3DES" ? 8 : 16; |
49 | 1.03k | } |
50 | 0 | else |
51 | 0 | { |
52 | 0 | return 0; |
53 | 0 | } |
54 | 0 | } |
55 | 964 | case Nonce_Format::AEAD_IMPLICIT_4: |
56 | 964 | return 8; |
57 | 676 | case Nonce_Format::AEAD_XOR_12: |
58 | 676 | return 0; |
59 | 0 | } |
60 | 0 | |
61 | 0 | throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); |
62 | 0 | } |
63 | | |
64 | | bool Ciphersuite::is_scsv(uint16_t suite) |
65 | 4.44k | { |
66 | 4.44k | // TODO: derive from IANA file in script |
67 | 4.44k | return (suite == 0x00FF || suite == 0x5600); |
68 | 4.44k | } |
69 | | |
70 | | bool Ciphersuite::psk_ciphersuite() const |
71 | 737 | { |
72 | 737 | return kex_method() == Kex_Algo::PSK || |
73 | 737 | kex_method() == Kex_Algo::DHE_PSK || |
74 | 737 | kex_method() == Kex_Algo::ECDHE_PSK; |
75 | 737 | } |
76 | | |
77 | | bool Ciphersuite::ecc_ciphersuite() const |
78 | 30.8k | { |
79 | 30.8k | return kex_method() == Kex_Algo::ECDH || |
80 | 30.8k | kex_method() == Kex_Algo::ECDHE_PSK || |
81 | 30.8k | auth_method() == Auth_Method::ECDSA; |
82 | 30.8k | } |
83 | | |
84 | | bool Ciphersuite::usable_in_version(Protocol_Version version) const |
85 | 4.45k | { |
86 | 4.45k | if(!version.supports_aead_modes()) |
87 | 5 | { |
88 | 5 | // Old versions do not support AEAD, or any MAC but SHA-1 |
89 | 5 | if(mac_algo() != "SHA-1") |
90 | 1 | return false; |
91 | 4.44k | } |
92 | 4.44k | |
93 | 4.44k | return true; |
94 | 4.44k | } |
95 | | |
96 | | bool Ciphersuite::cbc_ciphersuite() const |
97 | 24.4k | { |
98 | 24.4k | return (mac_algo() != "AEAD"); |
99 | 24.4k | } |
100 | | |
101 | | bool Ciphersuite::signature_used() const |
102 | 79.9k | { |
103 | 79.9k | return auth_method() != Auth_Method::ANONYMOUS && |
104 | 79.9k | auth_method() != Auth_Method::IMPLICIT; |
105 | 79.9k | } |
106 | | |
107 | | Ciphersuite Ciphersuite::by_id(uint16_t suite) |
108 | 83.0k | { |
109 | 83.0k | const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites(); |
110 | 83.0k | auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite); |
111 | 83.0k | |
112 | 83.0k | if(s != all_suites.end() && s->ciphersuite_code() == suite) |
113 | 83.0k | { |
114 | 83.0k | return *s; |
115 | 83.0k | } |
116 | 32 | |
117 | 32 | return Ciphersuite(); // some unknown ciphersuite |
118 | 32 | } |
119 | | |
120 | | Ciphersuite Ciphersuite::from_name(const std::string& name) |
121 | 0 | { |
122 | 0 | const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites(); |
123 | 0 |
|
124 | 0 | for(auto suite : all_suites) |
125 | 0 | { |
126 | 0 | if(suite.to_string() == name) |
127 | 0 | return suite; |
128 | 0 | } |
129 | 0 |
|
130 | 0 | return Ciphersuite(); // some unknown ciphersuite |
131 | 0 | } |
132 | | |
133 | | namespace { |
134 | | |
135 | | bool have_hash(const std::string& prf) |
136 | 540 | { |
137 | 540 | return (HashFunction::providers(prf).size() > 0); |
138 | 540 | } |
139 | | |
140 | | bool have_cipher(const std::string& cipher) |
141 | 350 | { |
142 | 350 | return (BlockCipher::providers(cipher).size() > 0) || |
143 | 350 | (StreamCipher::providers(cipher).size() > 0); |
144 | 350 | } |
145 | | |
146 | | } |
147 | | |
148 | | bool Ciphersuite::is_usable() const |
149 | 366 | { |
150 | 366 | if(!m_cipher_keylen) // uninitialized object |
151 | 0 | return false; |
152 | 366 | |
153 | 366 | if(!have_hash(prf_algo())) |
154 | 0 | return false; |
155 | 366 | |
156 | | #if !defined(BOTAN_HAS_TLS_CBC) |
157 | | if(cbc_ciphersuite()) |
158 | | return false; |
159 | | #endif |
160 | | |
161 | 366 | if(mac_algo() == "AEAD") |
162 | 192 | { |
163 | 192 | if(cipher_algo() == "ChaCha20Poly1305") |
164 | 16 | { |
165 | | #if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) |
166 | | return false; |
167 | | #endif |
168 | | } |
169 | 176 | else |
170 | 176 | { |
171 | 176 | auto cipher_and_mode = split_on(cipher_algo(), '/'); |
172 | 176 | BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); |
173 | 176 | if(!have_cipher(cipher_and_mode[0])) |
174 | 0 | return false; |
175 | 176 | |
176 | 176 | const auto mode = cipher_and_mode[1]; |
177 | 176 | |
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 | 192 | } |
194 | 174 | else |
195 | 174 | { |
196 | 174 | // Old non-AEAD schemes |
197 | 174 | if(!have_cipher(cipher_algo())) |
198 | 0 | return false; |
199 | 174 | if(!have_hash(mac_algo())) // HMAC |
200 | 0 | return false; |
201 | 366 | } |
202 | 366 | |
203 | 366 | if(kex_method() == Kex_Algo::SRP_SHA) |
204 | 18 | { |
205 | | #if !defined(BOTAN_HAS_SRP6) |
206 | | return false; |
207 | | #endif |
208 | | } |
209 | 348 | else if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK) |
210 | 106 | { |
211 | | #if !defined(BOTAN_HAS_ECDH) |
212 | | return false; |
213 | | #endif |
214 | | } |
215 | 242 | else if(kex_method() == Kex_Algo::DH || kex_method() == Kex_Algo::DHE_PSK) |
216 | 150 | { |
217 | | #if !defined(BOTAN_HAS_DIFFIE_HELLMAN) |
218 | | return false; |
219 | | #endif |
220 | | } |
221 | 92 | else if(kex_method() == Kex_Algo::CECPQ1) |
222 | 12 | { |
223 | | #if !defined(BOTAN_HAS_CECPQ1) |
224 | | return false; |
225 | | #endif |
226 | | } |
227 | 366 | |
228 | 366 | if(auth_method() == Auth_Method::DSA) |
229 | 38 | { |
230 | | #if !defined(BOTAN_HAS_DSA) |
231 | | return false; |
232 | | #endif |
233 | | } |
234 | 328 | else if(auth_method() == Auth_Method::ECDSA) |
235 | 46 | { |
236 | | #if !defined(BOTAN_HAS_ECDSA) |
237 | | return false; |
238 | | #endif |
239 | | } |
240 | 282 | else if(auth_method() == Auth_Method::RSA) |
241 | 90 | { |
242 | | #if !defined(BOTAN_HAS_RSA) |
243 | | return false; |
244 | | #endif |
245 | | } |
246 | 366 | |
247 | 366 | return true; |
248 | 366 | } |
249 | | |
250 | | } |
251 | | |
252 | | } |
253 | | |