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

randombit / botan / 30974838434

04 Aug 2026 05:33PM UTC coverage: 89.682% (+0.02%) from 89.662%
30974838434

push

github

web-flow
Merge pull request #5793 from randombit/jack/dtls-bounded-retry

Bound DTLS handshake retry attempts and properly abandon timed out states

119137 of 132844 relevant lines covered (89.68%)

10371831.54 hits per line

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

94.77
/src/tests/unit_tls_policy.cpp
1
/*
2
* TLS Policy tests
3
*
4
* (C) 2016 Juraj Somorovsky
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include "tests.h"
10

11
#if defined(BOTAN_HAS_TLS)
12
   #include <botan/assert.h>
13
   #include <botan/tls_ciphersuite.h>
14
   #include <botan/tls_exceptn.h>
15
   #include <botan/tls_policy.h>
16
#endif
17

18
#if defined(BOTAN_HAS_RSA)
19
   #include <botan/rsa.h>
20
#endif
21

22
#if defined(BOTAN_HAS_ECC_GROUP)
23
   #include <botan/ec_group.h>
24
#endif
25

26
#if defined(BOTAN_HAS_ECDH)
27
   #include <botan/ecdh.h>
28
#endif
29

30
#if defined(BOTAN_HAS_ECDSA)
31
   #include <botan/ecdsa.h>
32
#endif
33

34
#if defined(BOTAN_HAS_DIFFIE_HELLMAN)
35
   #include <botan/dh.h>
36
   #include <botan/dl_group.h>
37
#endif
38

39
namespace Botan_Tests {
40

41
namespace {
42

43
#if defined(BOTAN_HAS_TLS)
44
class TLS_Policy_Unit_Tests final : public Test {
1✔
45
   public:
46
      std::vector<Test::Result> run() override {
1✔
47
         std::vector<Test::Result> results;
1✔
48

49
         results.push_back(test_peer_key_acceptable_rsa(this->rng()));
2✔
50
         results.push_back(test_peer_key_acceptable_ecdh(this->rng()));
2✔
51
         results.push_back(test_peer_key_acceptable_ecdsa(this->rng()));
2✔
52
         results.push_back(test_peer_key_acceptable_dh());
2✔
53
         results.push_back(test_key_exchange_groups_to_offer());
2✔
54
         results.push_back(test_require_extended_master_secret());
2✔
55
         results.push_back(test_dtls_refuses_weak_ciphersuites());
2✔
56

57
         return results;
1✔
58
      }
×
59

60
      // RFC 9147 4.5.3 forbids _CCM_8 in DTLS absent forgery safeguards Botan does
61
      // not implement, and CBC+HMAC keeps a residual timing channel that DTLS
62
      // makes observable many times per association. Both are refused for DTLS
63
      // while remaining available to stream TLS.
64
      static Test::Result test_dtls_refuses_weak_ciphersuites() {
1✔
65
         Test::Result result("TLS Policy DTLS ciphersuite refusals");
1✔
66

67
         class Permissive_Policy final : public Botan::TLS::Policy {
2✔
68
            public:
69
               std::vector<std::string> allowed_ciphers() const override {
294✔
70
                  return {"AES-256/CCM(8)", "AES-128/CCM(8)", "AES-256/CCM", "AES-128/CCM", "AES-128/GCM", "AES-128"};
294✔
71
               }
72

73
               std::vector<std::string> allowed_macs() const override { return {"AEAD", "SHA-256", "SHA-1"}; }
111✔
74

75
               bool allow_tls12() const override { return true; }
×
76

77
               bool allow_dtls12() const override { return true; }
×
78
         };
79

80
         const Permissive_Policy policy;
1✔
81

82
         auto classify = [&](Botan::TLS::Protocol_Version version) {
3✔
83
            size_t ccm_8 = 0;
2✔
84
            size_t cbc = 0;
2✔
85
            for(const auto id : policy.ciphersuite_list(version)) {
16✔
86
               const auto suite = Botan::TLS::Ciphersuite::by_id(id);
14✔
87
               if(!suite.has_value()) {
14✔
88
                  continue;
×
89
               }
90
               if(suite->uses_short_authentication_tag()) {
14✔
91
                  ccm_8 += 1;
2✔
92
               }
93
               if(suite->cbc_ciphersuite()) {
14✔
94
                  cbc += 1;
4✔
95
               }
96
            }
2✔
97
            return std::make_pair(ccm_8, cbc);
2✔
98
         };
1✔
99

100
         const auto [tls_ccm_8, tls_cbc] = classify(Botan::TLS::Protocol_Version::TLS_V12);
1✔
101
         const auto [dtls_ccm_8, dtls_cbc] = classify(Botan::TLS::Protocol_Version::DTLS_V12);
1✔
102

103
         // Guard against the test passing because the policy offered none at all.
104
   #if defined(BOTAN_HAS_AEAD_CCM)
105
         result.test_is_true("TLS 1.2 still offers CCM_8 suites", tls_ccm_8 > 0);
1✔
106
   #endif
107
   #if defined(BOTAN_HAS_TLS_CBC)
108
         result.test_is_true("TLS 1.2 still offers CBC suites", tls_cbc > 0);
1✔
109
   #endif
110
         BOTAN_UNUSED(tls_ccm_8, tls_cbc);
1✔
111

112
         result.test_sz_eq("DTLS 1.2 offers no CCM_8 suite", dtls_ccm_8, 0);
1✔
113
         result.test_sz_eq("DTLS 1.2 offers no CBC suite", dtls_cbc, 0);
1✔
114
         result.test_sz_gte("DTLS 1.2 still has usable suites",
1✔
115
                            policy.ciphersuite_list(Botan::TLS::Protocol_Version::DTLS_V12).size(),
1✔
116
                            1);
117

118
         return result;
1✔
119
      }
1✔
120

121
      static Test::Result test_require_extended_master_secret() {
1✔
122
         Test::Result result("TLS Policy require_extended_master_secret");
1✔
123

124
         const Botan::TLS::Policy default_policy;
1✔
125
         result.test_is_true("default Policy requires EMS", default_policy.require_extended_master_secret());
1✔
126

127
         using TP = Botan::TLS::Text_Policy;
1✔
128
         result.test_is_true("default text policy requires EMS", TP("").require_extended_master_secret());
1✔
129
         result.test_is_true("text policy override disables EMS requirement",
2✔
130
                             !TP("require_extended_master_secret = false").require_extended_master_secret());
1✔
131
         result.test_is_true("text policy override re-enables EMS requirement",
2✔
132
                             TP("require_extended_master_secret = true").require_extended_master_secret());
1✔
133
         return result;
1✔
134
      }
1✔
135

136
   private:
137
      static Test::Result test_peer_key_acceptable_rsa([[maybe_unused]] Botan::RandomNumberGenerator& rng) {
1✔
138
         Test::Result result("TLS Policy RSA key verification");
1✔
139
   #if defined(BOTAN_HAS_RSA)
140
         auto rsa_key_1024 = std::make_unique<Botan::RSA_PrivateKey>(rng, 1024);
1✔
141
         const Botan::TLS::Policy policy;
1✔
142

143
         try {
1✔
144
            policy.check_peer_key_acceptable(*rsa_key_1024);
1✔
145
            result.test_failure("Incorrectly accepting 1024 bit RSA keys");
×
146
         } catch(Botan::TLS::TLS_Exception&) {
1✔
147
            result.test_success("Correctly rejecting 1024 bit RSA keys");
1✔
148
         }
1✔
149

150
         auto rsa_key_2048 = std::make_unique<Botan::RSA_PrivateKey>(rng, 2048);
1✔
151
         policy.check_peer_key_acceptable(*rsa_key_2048);
1✔
152
         result.test_success("Correctly accepting 2048 bit RSA keys");
1✔
153
   #endif
154
         return result;
1✔
155
      }
1✔
156

157
      static Test::Result test_peer_key_acceptable_ecdh([[maybe_unused]] Botan::RandomNumberGenerator& rng) {
1✔
158
         Test::Result result("TLS Policy ECDH key verification");
1✔
159
   #if defined(BOTAN_HAS_ECDH)
160

161
         const Botan::TLS::Policy policy;
1✔
162

163
         if(Botan::EC_Group::supports_named_group("secp192r1")) {
1✔
164
            const auto group_192 = Botan::EC_Group::from_name("secp192r1");
1✔
165
            auto ecdh_192 = std::make_unique<Botan::ECDH_PrivateKey>(rng, group_192);
1✔
166

167
            try {
1✔
168
               policy.check_peer_key_acceptable(*ecdh_192);
1✔
169
               result.test_failure("Incorrectly accepting 192 bit EC keys");
×
170
            } catch(Botan::TLS::TLS_Exception&) {
1✔
171
               result.test_success("Correctly rejecting 192 bit EC keys");
1✔
172
            }
1✔
173
         }
1✔
174

175
         if(Botan::EC_Group::supports_named_group("secp256r1")) {
1✔
176
            const auto group_256 = Botan::EC_Group::from_name("secp256r1");
1✔
177
            auto ecdh_256 = std::make_unique<Botan::ECDH_PrivateKey>(rng, group_256);
1✔
178
            policy.check_peer_key_acceptable(*ecdh_256);
1✔
179
            result.test_success("Correctly accepting 256 bit EC keys");
1✔
180
         }
1✔
181
   #endif
182
         return result;
1✔
183
      }
1✔
184

185
      static Test::Result test_peer_key_acceptable_ecdsa([[maybe_unused]] Botan::RandomNumberGenerator& rng) {
1✔
186
         Test::Result result("TLS Policy ECDSA key verification");
1✔
187
   #if defined(BOTAN_HAS_ECDSA)
188
         const Botan::TLS::Policy policy;
1✔
189

190
         if(Botan::EC_Group::supports_named_group("secp192r1")) {
1✔
191
            const auto group_192 = Botan::EC_Group::from_name("secp192r1");
1✔
192
            auto ecdsa_192 = std::make_unique<Botan::ECDSA_PrivateKey>(rng, group_192);
1✔
193

194
            try {
1✔
195
               policy.check_peer_key_acceptable(*ecdsa_192);
1✔
196
               result.test_failure("Incorrectly accepting 192 bit EC keys");
×
197
            } catch(Botan::TLS::TLS_Exception&) {
1✔
198
               result.test_success("Correctly rejecting 192 bit EC keys");
1✔
199
            }
1✔
200
         }
1✔
201

202
         if(Botan::EC_Group::supports_named_group("secp256r1")) {
1✔
203
            const auto group_256 = Botan::EC_Group::from_name("secp256r1");
1✔
204
            auto ecdsa_256 = std::make_unique<Botan::ECDSA_PrivateKey>(rng, group_256);
1✔
205
            policy.check_peer_key_acceptable(*ecdsa_256);
1✔
206
            result.test_success("Correctly accepting 256 bit EC keys");
1✔
207
         }
1✔
208
   #endif
209
         return result;
1✔
210
      }
1✔
211

212
      static Test::Result test_peer_key_acceptable_dh() {
1✔
213
         Test::Result result("TLS Policy DH key verification");
1✔
214
   #if defined(BOTAN_HAS_DIFFIE_HELLMAN)
215
         const BigInt g("2");
1✔
216
         const BigInt p("58458002095536094658683755258523362961421200751439456159756164191494576279467");
1✔
217
         const Botan::DL_Group grp(p, g);
1✔
218
         const Botan::BigInt x("46205663093589612668746163860870963912226379131190812163519349848291472898748");
1✔
219
         auto dhkey = std::make_unique<Botan::DH_PrivateKey>(grp, x);
1✔
220

221
         const Botan::TLS::Policy policy;
1✔
222
         try {
1✔
223
            policy.check_peer_key_acceptable(*dhkey);
1✔
224
            result.test_failure("Incorrectly accepting short bit DH keys");
×
225
         } catch(Botan::TLS::TLS_Exception&) {
1✔
226
            result.test_success("Correctly rejecting short bit DH keys");
1✔
227
         }
1✔
228
   #endif
229
         return result;
2✔
230
      }
2✔
231

232
      static Test::Result test_key_exchange_groups_to_offer() {
1✔
233
         Test::Result result("TLS Policy key share offering");
1✔
234

235
         const Botan::TLS::Policy default_policy;
1✔
236
         result.test_sz_eq(
1✔
237
            "default TLS Policy offers exactly one", default_policy.key_exchange_groups_to_offer().size(), 1);
1✔
238
         result.test_is_true(
1✔
239
            "default TLS Policy offers preferred group",
240
            default_policy.key_exchange_groups().front() == default_policy.key_exchange_groups_to_offer().front());
2✔
241

242
         using TP = Botan::TLS::Text_Policy;
1✔
243

244
         result.test_sz_eq(
2✔
245
            "default behaviour from text policy (size)", TP("").key_exchange_groups_to_offer().size(), 1);
2✔
246
         result.test_is_true("default behaviour from text policy (preferred)",
2✔
247
                             TP("").key_exchange_groups().front() == TP("").key_exchange_groups_to_offer().front());
3✔
248

249
         result.test_is_true("no offerings",
2✔
250
                             TP("key_exchange_groups_to_offer = none").key_exchange_groups_to_offer().empty());
2✔
251

252
         const std::string two_groups = "key_exchange_groups_to_offer = secp256r1 ffdhe/ietf/4096";
1✔
253
         result.test_sz_eq("list of offerings (size)", TP(two_groups).key_exchange_groups_to_offer().size(), 2);
2✔
254
         result.test_is_true("list of offerings (0)",
2✔
255
                             TP(two_groups).key_exchange_groups_to_offer()[0] == Botan::TLS::Group_Params::SECP256R1);
2✔
256
         result.test_is_true("list of offerings (1)",
2✔
257
                             TP(two_groups).key_exchange_groups_to_offer()[1] == Botan::TLS::Group_Params::FFDHE_4096);
2✔
258

259
         return result;
1✔
260
      }
1✔
261
};
262

263
BOTAN_REGISTER_TEST("tls", "tls_policy", TLS_Policy_Unit_Tests);
264

265
#endif
266

267
}  // namespace
268

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

© 2026 Coveralls, Inc