Coverage Report

Created: 2022-09-23 06:05

/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::TLS {
17
18
size_t Ciphersuite::nonce_bytes_from_handshake() const
19
15.8k
   {
20
15.8k
   switch(m_nonce_format)
21
15.8k
      {
22
12.4k
      case Nonce_Format::CBC_MODE:
23
12.4k
         {
24
12.4k
         if(cipher_algo() == "3DES")
25
2.52k
            return 8;
26
9.90k
         else
27
9.90k
            return 16;
28
12.4k
         }
29
973
      case Nonce_Format::AEAD_IMPLICIT_4:
30
973
         return 4;
31
2.42k
      case Nonce_Format::AEAD_XOR_12:
32
2.42k
         return 12;
33
15.8k
      }
34
35
0
   throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
36
15.8k
   }
37
38
size_t Ciphersuite::nonce_bytes_from_record(Protocol_Version version) const
39
930
   {
40
930
   BOTAN_UNUSED(version);
41
930
   switch(m_nonce_format)
42
930
      {
43
359
      case Nonce_Format::CBC_MODE:
44
359
         return cipher_algo() == "3DES" ? 8 : 16;
45
239
      case Nonce_Format::AEAD_IMPLICIT_4:
46
239
         return 8;
47
332
      case Nonce_Format::AEAD_XOR_12:
48
332
         return 0;
49
930
      }
50
51
0
   throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
52
930
   }
53
54
bool Ciphersuite::is_scsv(uint16_t suite)
55
0
   {
56
   // TODO: derive from IANA file in script
57
0
   return (suite == 0x00FF || suite == 0x5600);
58
0
   }
59
60
bool Ciphersuite::psk_ciphersuite() const
61
0
   {
62
0
   return kex_method() == Kex_Algo::PSK ||
63
0
          kex_method() == Kex_Algo::ECDHE_PSK;
64
0
   }
65
66
bool Ciphersuite::ecc_ciphersuite() const
67
23.6k
   {
68
23.6k
   return kex_method() == Kex_Algo::ECDH ||
69
23.6k
          kex_method() == Kex_Algo::ECDHE_PSK ||
70
23.6k
          auth_method() == Auth_Method::ECDSA;
71
23.6k
   }
72
73
bool Ciphersuite::usable_in_version(Protocol_Version version) const
74
0
   {
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
0
   const auto is_legacy_suite = (ciphersuite_code() & 0xFF00) != 0x1300;
85
0
   return version.is_pre_tls_13() == is_legacy_suite;
86
0
   }
87
88
bool Ciphersuite::cbc_ciphersuite() const
89
21.6k
   {
90
21.6k
   return (mac_algo() != "AEAD");
91
21.6k
   }
92
93
bool Ciphersuite::signature_used() const
94
65.1k
   {
95
65.1k
   return auth_method() != Auth_Method::IMPLICIT;
96
65.1k
   }
97
98
std::optional<Ciphersuite> Ciphersuite::by_id(uint16_t suite)
99
65.7k
   {
100
65.7k
   const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
101
65.7k
   auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite);
102
103
65.7k
   if(s != all_suites.end() && s->ciphersuite_code() == suite)
104
65.6k
      {
105
65.6k
      return *s;
106
65.6k
      }
107
108
101
   return std::nullopt; // some unknown ciphersuite
109
65.7k
   }
110
111
std::optional<Ciphersuite> Ciphersuite::from_name(const std::string& name)
112
0
   {
113
0
   const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
114
115
0
   for(auto suite : all_suites)
116
0
      {
117
0
      if(suite.to_string() == name)
118
0
         return suite;
119
0
      }
120
121
0
   return std::nullopt; // some unknown ciphersuite
122
0
   }
123
124
namespace {
125
126
bool have_hash(const std::string& prf)
127
260
   {
128
260
   return (!HashFunction::providers(prf).empty());
129
260
   }
130
131
bool have_cipher(const std::string& cipher)
132
184
   {
133
184
   return (!BlockCipher::providers(cipher).empty()) ||
134
184
      (!StreamCipher::providers(cipher).empty());
135
184
   }
136
137
}
138
139
bool Ciphersuite::is_usable() const
140
200
   {
141
200
   if(!m_cipher_keylen) // uninitialized object
142
0
      return false;
143
144
200
   if(!have_hash(prf_algo()))
145
0
      return false;
146
147
#if !defined(BOTAN_HAS_TLS_CBC)
148
   if(cbc_ciphersuite())
149
      return false;
150
#endif
151
152
200
   if(mac_algo() == "AEAD")
153
140
      {
154
140
      if(cipher_algo() == "ChaCha20Poly1305")
155
16
         {
156
#if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
157
         return false;
158
#endif
159
16
         }
160
124
      else
161
124
         {
162
124
         auto cipher_and_mode = split_on(cipher_algo(), '/');
163
124
         BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo");
164
124
         if(!have_cipher(cipher_and_mode[0]))
165
0
            return false;
166
167
124
         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
124
         }
184
140
      }
185
60
   else
186
60
      {
187
      // Old non-AEAD schemes
188
60
      if(!have_cipher(cipher_algo()))
189
0
         return false;
190
60
      if(!have_hash(mac_algo())) // HMAC
191
0
         return false;
192
60
      }
193
194
200
   if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK)
195
82
      {
196
#if !defined(BOTAN_HAS_ECDH)
197
      return false;
198
#endif
199
82
      }
200
118
   else if(kex_method() == Kex_Algo::DH)
201
32
      {
202
#if !defined(BOTAN_HAS_DIFFIE_HELLMAN)
203
      return false;
204
#endif
205
32
      }
206
86
   else if(kex_method() == Kex_Algo::CECPQ1)
207
12
      {
208
#if !defined(BOTAN_HAS_CECPQ1)
209
      return false;
210
#endif
211
12
      }
212
213
200
   if(auth_method() == Auth_Method::ECDSA)
214
40
      {
215
#if !defined(BOTAN_HAS_ECDSA)
216
      return false;
217
#endif
218
40
      }
219
160
   else if(auth_method() == Auth_Method::RSA)
220
64
      {
221
#if !defined(BOTAN_HAS_RSA)
222
      return false;
223
#endif
224
64
      }
225
226
200
   return true;
227
200
   }
228
229
}
230