• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 16401676880

20 Jul 2025 02:20PM UTC coverage: 90.643% (+0.01%) from 90.633%
16401676880

push

github

web-flow
Merge pull request #5004 from randombit/jack/fix-clang-tidy-bugprone-branch-clone

Enable and fix clang-tidy warning bugprone-branch-clone

99949 of 110267 relevant lines covered (90.64%)

12335823.55 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.2
/src/lib/tls/tls_ciphersuite.cpp
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

10
#include <botan/assert.h>
11
#include <botan/block_cipher.h>
12
#include <botan/exceptn.h>
13
#include <botan/hash.h>
14
#include <botan/stream_cipher.h>
15
#include <botan/internal/parsing.h>
16
#include <algorithm>
17

18
namespace Botan::TLS {
19

20
size_t Ciphersuite::nonce_bytes_from_handshake() const {
5,574✔
21
   switch(m_nonce_format) {
5,574✔
22
      case Nonce_Format::CBC_MODE: {
852✔
23
         if(cipher_algo() == "3DES") {
852✔
24
            return 8;
25
         } else {
26
            return 16;
715✔
27
         }
28
      }
29
      case Nonce_Format::AEAD_IMPLICIT_4:
30
         return 4;
31
      case Nonce_Format::AEAD_XOR_12:
3,354✔
32
         return 12;
3,354✔
33
      case Nonce_Format::NULL_CIPHER:
24✔
34
         return 0;
24✔
35
   }
36

37
   throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
×
38
}
39

40
size_t Ciphersuite::nonce_bytes_from_record(Protocol_Version version) const {
3,646✔
41
   BOTAN_UNUSED(version);
3,646✔
42
   switch(m_nonce_format) {
3,646✔
43
      case Nonce_Format::CBC_MODE:
560✔
44
         return cipher_algo() == "3DES" ? 8 : 16;
1,029✔
45
      case Nonce_Format::AEAD_IMPLICIT_4:
46
         return 8;
47
      case Nonce_Format::AEAD_XOR_12:
2,194✔
48
      case Nonce_Format::NULL_CIPHER:
2,194✔
49
         return 0;
2,194✔
50
   }
51

52
   throw Invalid_State("In Ciphersuite::nonce_bytes_from_handshake invalid enum value");
×
53
}
54

55
bool Ciphersuite::is_scsv(uint16_t suite) {
2,417✔
56
   // TODO: derive from IANA file in script
57
   return (suite == 0x00FF || suite == 0x5600);
2,417✔
58
}
59

60
bool Ciphersuite::psk_ciphersuite() const {
1,064✔
61
   return kex_method() == Kex_Algo::PSK || kex_method() == Kex_Algo::ECDHE_PSK;
1,064✔
62
}
63

64
bool Ciphersuite::ecc_ciphersuite() const {
1,009✔
65
   return kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK || auth_method() == Auth_Method::ECDSA;
1,009✔
66
}
67

68
bool Ciphersuite::usable_in_version(Protocol_Version version) const {
397,522✔
69
   // RFC 8446 B.4.:
70
   //   Although TLS 1.3 uses the same cipher suite space as previous
71
   //   versions of TLS, TLS 1.3 cipher suites are defined differently, only
72
   //   specifying the symmetric ciphers, and cannot be used for TLS 1.2.
73
   //   Similarly, cipher suites for TLS 1.2 and lower cannot be used with
74
   //   TLS 1.3.
75
   //
76
   // Currently cipher suite codes {0x13,0x01} through {0x13,0x05} are
77
   // allowed for TLS 1.3. This may change in the future.
78
   const auto is_legacy_suite = (ciphersuite_code() & 0xFF00) != 0x1300;
397,522✔
79
   return version.is_pre_tls_13() == is_legacy_suite;
397,522✔
80
}
81

82
bool Ciphersuite::cbc_ciphersuite() const {
840✔
83
   return (mac_algo() != "AEAD" && cipher_algo() != "NULL");
1,090✔
84
}
85

86
bool Ciphersuite::null_ciphersuite() const {
190✔
87
   return (cipher_algo() == "NULL");
190✔
88
}
89

90
bool Ciphersuite::aead_ciphersuite() const {
2,434✔
91
   return (mac_algo() == "AEAD");
2,434✔
92
}
93

94
bool Ciphersuite::signature_used() const {
7,542✔
95
   return auth_method() != Auth_Method::IMPLICIT;
7,542✔
96
}
97

98
std::optional<Ciphersuite> Ciphersuite::by_id(uint16_t suite) {
79,831✔
99
   const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
79,831✔
100
   auto s = std::lower_bound(all_suites.begin(), all_suites.end(), suite);
79,831✔
101

102
   if(s != all_suites.end() && s->ciphersuite_code() == suite) {
79,831✔
103
      return *s;
14,351✔
104
   }
105

106
   return std::nullopt;  // some unknown ciphersuite
65,480✔
107
}
108

109
std::optional<Ciphersuite> Ciphersuite::from_name(std::string_view name) {
89✔
110
   const std::vector<Ciphersuite>& all_suites = all_known_ciphersuites();
89✔
111

112
   for(auto suite : all_suites) {
2,672✔
113
      if(suite.to_string() == name) {
8,016✔
114
         return suite;
89✔
115
      }
116
   }
117

118
   return std::nullopt;  // some unknown ciphersuite
×
119
}
120

121
namespace {
122

123
bool have_hash(std::string_view prf) {
292,460✔
124
   return (!HashFunction::providers(prf).empty());
292,460✔
125
}
126

127
bool have_cipher(std::string_view cipher) {
200,544✔
128
   return (!BlockCipher::providers(cipher).empty()) || (!StreamCipher::providers(cipher).empty());
217,256✔
129
}
130

131
}  // namespace
132

133
bool Ciphersuite::is_usable() const {
213,078✔
134
   // NOLINTBEGIN(bugprone-branch-clone) this function needs help
135

136
   if(((cipher_algo() != "NULL") && (m_cipher_keylen == 0)) ||
426,156✔
137
      ((cipher_algo() == "NULL") && (m_cipher_keylen != 0))) {  // invalid keylen state
426,156✔
138
      return false;
139
   }
140

141
   if(!have_hash(prf_algo())) {
213,078✔
142
      return false;
143
   }
144

145
#if !defined(BOTAN_HAS_TLS_CBC)
146
   if(cbc_ciphersuite()) {
147
      return false;
148
   }
149
#endif
150

151
#if !defined(BOTAN_HAS_TLS_NULL)
152
   if(null_ciphersuite()) {
153
      return false;
154
   }
155
#endif
156

157
   if(mac_algo() == "AEAD") {
213,078✔
158
      if(cipher_algo() == "ChaCha20Poly1305") {
133,696✔
159
#if !defined(BOTAN_HAS_AEAD_CHACHA20_POLY1305)
160
         return false;
161
#endif
162
      } else {
163
         auto cipher_and_mode = split_on(cipher_algo(), '/');
121,162✔
164
         BOTAN_ASSERT(cipher_and_mode.size() == 2, "Expected format for AEAD algo");
121,162✔
165
         if(!have_cipher(cipher_and_mode[0])) {
121,162✔
166
            return false;
×
167
         }
168

169
         const auto& mode = cipher_and_mode[1];
121,162✔
170

171
#if !defined(BOTAN_HAS_AEAD_CCM)
172
         if(mode == "CCM" || mode == "CCM-8") {
173
            return false;
174
         }
175
#endif
176

177
#if !defined(BOTAN_HAS_AEAD_GCM)
178
         if(mode == "GCM") {
179
            return false;
180
         }
181
#endif
182

183
#if !defined(BOTAN_HAS_AEAD_OCB)
184
         if(mode == "OCB(12)" || mode == "OCB") {
185
            return false;
186
         }
187
#endif
188

189
         // Potentially unused if all AEADs are available
190
         BOTAN_UNUSED(mode);
121,162✔
191
      }
121,162✔
192
   } else {
193
      // Old non-AEAD schemes
194
      if(!have_cipher(cipher_algo()) && (cipher_algo() != "NULL")) {
112,806✔
195
         return false;
196
      }
197
      if(!have_hash(mac_algo())) {  // HMAC
79,382✔
198
         return false;
199
      }
200
   }
201

202
   if(kex_method() == Kex_Algo::ECDH || kex_method() == Kex_Algo::ECDHE_PSK) {
213,078✔
203
#if !defined(BOTAN_HAS_ECDH)
204
      return false;
205
#endif
206
   } else if(kex_method() == Kex_Algo::DH) {
207
#if !defined(BOTAN_HAS_DIFFIE_HELLMAN)
208
      return false;
209
#endif
210
   }
211

212
   if(auth_method() == Auth_Method::ECDSA) {
213,078✔
213
#if !defined(BOTAN_HAS_ECDSA)
214
      return false;
215
#endif
216
   } else if(auth_method() == Auth_Method::RSA) {
217
#if !defined(BOTAN_HAS_RSA)
218
      return false;
219
#endif
220
   }
221

222
   // NOLINTEND(bugprone-branch-clone)
223

224
   return true;
225
}
226

227
}  // namespace Botan::TLS
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc