Coverage Report

Created: 2023-02-13 06:21

/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
14.4k
   {
20
14.4k
   switch(m_nonce_format)
21
14.4k
      {
22
11.8k
      case Nonce_Format::CBC_MODE:
23
11.8k
         {
24
11.8k
         if(cipher_algo() == "3DES")
25
2.08k
            return 8;
26
9.78k
         else
27
9.78k
            return 16;
28
11.8k
         }
29
734
      case Nonce_Format::AEAD_IMPLICIT_4:
30
734
         return 4;
31
1.86k
      case Nonce_Format::AEAD_XOR_12:
32
1.86k
         return 12;
33
14.4k
      }
34
35
0
   throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
36
14.4k
   }
37
38
size_t Ciphersuite::nonce_bytes_from_record(Protocol_Version version) const
39
902
   {
40
902
   BOTAN_UNUSED(version);
41
902
   switch(m_nonce_format)
42
902
      {
43
325
      case Nonce_Format::CBC_MODE:
44
325
         return cipher_algo() == "3DES" ? 8 : 16;
45
284
      case Nonce_Format::AEAD_IMPLICIT_4:
46
284
         return 8;
47
293
      case Nonce_Format::AEAD_XOR_12:
48
293
         return 0;
49
902
      }
50
51
0
   throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
52
902
   }
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
22.3k
   {
68
22.3k
   return kex_method() == Kex_Algo::ECDH ||
69
22.3k
          kex_method() == Kex_Algo::ECDHE_PSK ||
70
22.3k
          auth_method() == Auth_Method::ECDSA;
71
22.3k
   }
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
20.1k
   {
90
20.1k
   return (mac_algo() != "AEAD");
91
20.1k
   }
92
93
bool Ciphersuite::signature_used() const
94
60.6k
   {
95
60.6k
   return auth_method() != Auth_Method::IMPLICIT;
96
60.6k
   }
97
98
std::optional<Ciphersuite> Ciphersuite::by_id(uint16_t suite)
99
61.3k
   {
100
61.3k
   const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
101
61.3k
   auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite);
102
103
61.3k
   if(s != all_suites.end() && s->ciphersuite_code() == suite)
104
61.2k
      {
105
61.2k
      return *s;
106
61.2k
      }
107
108
116
   return std::nullopt; // some unknown ciphersuite
109
61.3k
   }
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
248
   {
128
248
   return (!HashFunction::providers(prf).empty());
129
248
   }
130
131
bool have_cipher(const std::string& cipher)
132
176
   {
133
176
   return (!BlockCipher::providers(cipher).empty()) ||
134
176
      (!StreamCipher::providers(cipher).empty());
135
176
   }
136
137
}
138
139
bool Ciphersuite::is_usable() const
140
188
   {
141
188
   if(!m_cipher_keylen) // uninitialized object
142
0
      return false;
143
144
188
   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
188
   if(mac_algo() == "AEAD")
153
128
      {
154
128
      if(cipher_algo() == "ChaCha20Poly1305")
155
12
         {
156
#if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
157
         return false;
158
#endif
159
12
         }
160
116
      else
161
116
         {
162
116
         auto cipher_and_mode = split_on(cipher_algo(), '/');
163
116
         BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo");
164
116
         if(!have_cipher(cipher_and_mode[0]))
165
0
            return false;
166
167
116
         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
116
         }
184
128
      }
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
188
   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
106
   else if(kex_method() == Kex_Algo::DH)
201
32
      {
202
#if !defined(BOTAN_HAS_DIFFIE_HELLMAN)
203
      return false;
204
#endif
205
32
      }
206
207
188
   if(auth_method() == Auth_Method::ECDSA)
208
34
      {
209
#if !defined(BOTAN_HAS_ECDSA)
210
      return false;
211
#endif
212
34
      }
213
154
   else if(auth_method() == Auth_Method::RSA)
214
58
      {
215
#if !defined(BOTAN_HAS_RSA)
216
      return false;
217
#endif
218
58
      }
219
220
188
   return true;
221
188
   }
222
223
}
224