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

randombit / botan / 15426479995

03 Jun 2025 07:49PM UTC coverage: 90.968%. Remained the same
15426479995

push

github

web-flow
Merge pull request #4776 from cariad-tech/add-null-ciphers

Add support for NULL cipher suites in TLS 1.2

98225 of 107978 relevant lines covered (90.97%)

12556325.78 hits per line

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

93.94
/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,508✔
21
   switch(m_nonce_format) {
5,508✔
22
      case Nonce_Format::CBC_MODE: {
792✔
23
         if(cipher_algo() == "3DES") {
792✔
24
            return 8;
25
         } else {
26
            return 16;
660✔
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,607✔
41
   BOTAN_UNUSED(version);
3,607✔
42
   switch(m_nonce_format) {
3,607✔
43
      case Nonce_Format::CBC_MODE:
525✔
44
         return cipher_algo() == "3DES" ? 8 : 16;
962✔
45
      case Nonce_Format::AEAD_IMPLICIT_4:
46
         return 8;
47
      case Nonce_Format::AEAD_XOR_12:
48
         return 0;
49
      case Nonce_Format::NULL_CIPHER:
50
         return 0;
51
   }
52

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

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

61
bool Ciphersuite::psk_ciphersuite() const {
866✔
62
   return kex_method() == Kex_Algo::PSK || kex_method() == Kex_Algo::ECDHE_PSK;
866✔
63
}
64

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

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

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

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

91
bool Ciphersuite::aead_ciphersuite() const {
1,287✔
92
   return (mac_algo() == "AEAD");
1,287✔
93
}
94

95
bool Ciphersuite::signature_used() const {
6,235✔
96
   return auth_method() != Auth_Method::IMPLICIT;
6,235✔
97
}
98

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

103
   if(s != all_suites.end() && s->ciphersuite_code() == suite) {
78,685✔
104
      return *s;
13,205✔
105
   }
106

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

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

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

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

122
namespace {
123

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

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

132
}  // namespace
133

134
bool Ciphersuite::is_usable() const {
213,078✔
135
   if(((cipher_algo() != "NULL") && (m_cipher_keylen == 0)) ||
426,156✔
136
      ((cipher_algo() == "NULL") && (m_cipher_keylen != 0))) {  // invalid keylen state
426,156✔
137
      return false;
138
   }
139

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

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

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

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

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

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

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

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

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

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

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

221
   return true;
222
}
223

224
}  // 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