/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/internal/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 | 11.5k | { |
22 | 11.5k | switch(m_nonce_format) |
23 | 11.5k | { |
24 | 6.43k | case Nonce_Format::CBC_MODE: |
25 | 6.43k | { |
26 | 6.43k | if(cipher_algo() == "3DES") |
27 | 428 | return 8; |
28 | 6.00k | else |
29 | 6.00k | return 16; |
30 | 0 | } |
31 | 900 | case Nonce_Format::AEAD_IMPLICIT_4: |
32 | 900 | return 4; |
33 | 4.24k | case Nonce_Format::AEAD_XOR_12: |
34 | 4.24k | return 12; |
35 | 0 | } |
36 | | |
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 | 1.34k | { |
42 | 1.34k | BOTAN_UNUSED(version); |
43 | 1.34k | switch(m_nonce_format) |
44 | 1.34k | { |
45 | 564 | case Nonce_Format::CBC_MODE: |
46 | 422 | return cipher_algo() == "3DES" ? 8 : 16; |
47 | 495 | case Nonce_Format::AEAD_IMPLICIT_4: |
48 | 495 | return 8; |
49 | 288 | case Nonce_Format::AEAD_XOR_12: |
50 | 288 | return 0; |
51 | 0 | } |
52 | | |
53 | 0 | throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value"); |
54 | 0 | } |
55 | | |
56 | | bool Ciphersuite::is_scsv(uint16_t suite) |
57 | 0 | { |
58 | | // TODO: derive from IANA file in script |
59 | 0 | return (suite == 0x00FF || suite == 0x5600); |
60 | 0 | } |
61 | | |
62 | | bool Ciphersuite::psk_ciphersuite() const |
63 | 0 | { |
64 | 0 | return kex_method() == Kex_Algo::PSK || |
65 | 0 | kex_method() == Kex_Algo::ECDHE_PSK; |
66 | 0 | } |
67 | | |
68 | | bool Ciphersuite::ecc_ciphersuite() const |
69 | 22.9k | { |
70 | 22.9k | return kex_method() == Kex_Algo::ECDH || |
71 | 22.9k | kex_method() == Kex_Algo::ECDHE_PSK || |
72 | 1.24k | auth_method() == Auth_Method::ECDSA; |
73 | 22.9k | } |
74 | | |
75 | | bool Ciphersuite::usable_in_version(Protocol_Version version) const |
76 | 0 | { |
77 | 0 | BOTAN_UNUSED(version); |
78 | 0 | return true; |
79 | 0 | } |
80 | | |
81 | | bool Ciphersuite::cbc_ciphersuite() const |
82 | 22.3k | { |
83 | 22.3k | return (mac_algo() != "AEAD"); |
84 | 22.3k | } |
85 | | |
86 | | bool Ciphersuite::signature_used() const |
87 | 67.1k | { |
88 | 67.1k | return auth_method() != Auth_Method::IMPLICIT; |
89 | 67.1k | } |
90 | | |
91 | | Ciphersuite Ciphersuite::by_id(uint16_t suite) |
92 | 67.2k | { |
93 | 67.2k | const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites(); |
94 | 67.2k | auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite); |
95 | | |
96 | 67.2k | if(s != all_suites.end() && s->ciphersuite_code() == suite) |
97 | 67.1k | { |
98 | 67.1k | return *s; |
99 | 67.1k | } |
100 | | |
101 | 57 | return Ciphersuite(); // some unknown ciphersuite |
102 | 57 | } |
103 | | |
104 | | Ciphersuite Ciphersuite::from_name(const std::string& name) |
105 | 0 | { |
106 | 0 | const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites(); |
107 | |
|
108 | 0 | for(auto suite : all_suites) |
109 | 0 | { |
110 | 0 | if(suite.to_string() == name) |
111 | 0 | return suite; |
112 | 0 | } |
113 | |
|
114 | 0 | return Ciphersuite(); // some unknown ciphersuite |
115 | 0 | } |
116 | | |
117 | | namespace { |
118 | | |
119 | | bool have_hash(const std::string& prf) |
120 | 250 | { |
121 | 250 | return (HashFunction::providers(prf).size() > 0); |
122 | 250 | } |
123 | | |
124 | | bool have_cipher(const std::string& cipher) |
125 | 176 | { |
126 | 176 | return (BlockCipher::providers(cipher).size() > 0) || |
127 | 0 | (StreamCipher::providers(cipher).size() > 0); |
128 | 176 | } |
129 | | |
130 | | } |
131 | | |
132 | | bool Ciphersuite::is_usable() const |
133 | 190 | { |
134 | 190 | if(!m_cipher_keylen) // uninitialized object |
135 | 0 | return false; |
136 | | |
137 | 190 | if(!have_hash(prf_algo())) |
138 | 0 | return false; |
139 | | |
140 | | #if !defined(BOTAN_HAS_TLS_CBC) |
141 | | if(cbc_ciphersuite()) |
142 | | return false; |
143 | | #endif |
144 | | |
145 | 190 | if(mac_algo() == "AEAD") |
146 | 130 | { |
147 | 130 | if(cipher_algo() == "ChaCha20Poly1305") |
148 | 14 | { |
149 | | #if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305) |
150 | | return false; |
151 | | #endif |
152 | 14 | } |
153 | 116 | else |
154 | 116 | { |
155 | 116 | auto cipher_and_mode = split_on(cipher_algo(), '/'); |
156 | 116 | BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo"); |
157 | 116 | if(!have_cipher(cipher_and_mode[0])) |
158 | 0 | return false; |
159 | | |
160 | 116 | const auto mode = cipher_and_mode[1]; |
161 | | |
162 | | #if !defined(BOTAN_HAS_AEAD_CCM) |
163 | | if(mode == "CCM" || mode == "CCM-8") |
164 | | return false; |
165 | | #endif |
166 | | |
167 | | #if !defined(BOTAN_HAS_AEAD_GCM) |
168 | | if(mode == "GCM") |
169 | | return false; |
170 | | #endif |
171 | | |
172 | | #if !defined(BOTAN_HAS_AEAD_OCB) |
173 | | if(mode == "OCB(12)" || mode == "OCB") |
174 | | return false; |
175 | | #endif |
176 | 116 | } |
177 | 130 | } |
178 | 60 | else |
179 | 60 | { |
180 | | // Old non-AEAD schemes |
181 | 60 | if(!have_cipher(cipher_algo())) |
182 | 0 | return false; |
183 | 60 | if(!have_hash(mac_algo())) // HMAC |
184 | 0 | return false; |
185 | 190 | } |
186 | | |
187 | 190 | if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK) |
188 | 82 | { |
189 | | #if !defined(BOTAN_HAS_ECDH) |
190 | | return false; |
191 | | #endif |
192 | 82 | } |
193 | 108 | else if(kex_method() == Kex_Algo::DH) |
194 | 32 | { |
195 | | #if !defined(BOTAN_HAS_DIFFIE_HELLMAN) |
196 | | return false; |
197 | | #endif |
198 | 32 | } |
199 | 76 | else if(kex_method() == Kex_Algo::CECPQ1) |
200 | 12 | { |
201 | | #if !defined(BOTAN_HAS_CECPQ1) |
202 | | return false; |
203 | | #endif |
204 | 12 | } |
205 | | |
206 | 190 | if(auth_method() == Auth_Method::ECDSA) |
207 | 40 | { |
208 | | #if !defined(BOTAN_HAS_ECDSA) |
209 | | return false; |
210 | | #endif |
211 | 40 | } |
212 | 150 | else if(auth_method() == Auth_Method::RSA) |
213 | 64 | { |
214 | | #if !defined(BOTAN_HAS_RSA) |
215 | | return false; |
216 | | #endif |
217 | 64 | } |
218 | | |
219 | 190 | return true; |
220 | 190 | } |
221 | | |
222 | | } |
223 | | |
224 | | } |
225 | | |