Coverage Report

Created: 2021-02-21 07:20

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