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

randombit / botan / 16884363558

11 Aug 2025 03:19PM UTC coverage: 90.663% (-0.001%) from 90.664%
16884363558

Pull #4877

github

web-flow
Merge faf135dbe into 7fe3a730a
Pull Request #4877: Add FFI for X.509 creation

100748 of 111123 relevant lines covered (90.66%)

12297786.9 hits per line

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

99.05
/src/tests/test_x509_rpki.cpp
1
/*
2
* (C) 2025 Jack Lloyd
3
* (C) 2025 Anton Einax, Dominik Schricker
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include "tests.h"
9

10
#if defined(BOTAN_HAS_X509_CERTIFICATES)
11
   #include <botan/certstor.h>
12
   #include <botan/pk_algs.h>
13
   #include <botan/pubkey.h>
14
   #include <botan/x509_builder.h>
15
   #include <botan/x509_ca.h>
16
   #include <botan/x509_ext.h>
17
   #include <botan/x509path.h>
18
   #include <botan/internal/calendar.h>
19
#endif
20

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

25
namespace Botan_Tests {
26

27
namespace {
28

29
#if defined(BOTAN_HAS_X509_CERTIFICATES) && \
30
   (defined(BOTAN_HAS_ECDSA) || defined(BOTAN_HAS_RSA) || defined(BOTAN_HAS_ED25519))
31

32
struct CA_Creation_Result {
33
      Botan::X509_Certificate ca_cert;
34
      Botan::X509_CA ca;
35
      std::unique_ptr<Botan::Private_Key> sub_key;
36
      std::string sig_algo;
37
      std::string hash_fn;
38
};
39

40
Botan::X509_Time from_date(const int y, const int m, const int d) {
2,728✔
41
   const size_t this_year = Botan::calendar_point(std::chrono::system_clock::now()).year();
2,728✔
42

43
   Botan::calendar_point t(static_cast<uint32_t>(this_year + y), m, d, 0, 0, 0);
2,728✔
44
   return Botan::X509_Time(t.to_std_timepoint());
2,728✔
45
}
46

47
std::unique_ptr<Botan::Private_Key> generate_key(const std::string& algo, Botan::RandomNumberGenerator& rng) {
217✔
48
   std::string params;
217✔
49
   if(algo == "ECDSA") {
217✔
50
      params = "secp256r1";
217✔
51

52
   #if defined(BOTAN_HAS_ECC_GROUP)
53
      if(Botan::EC_Group::supports_named_group("secp192r1")) {
217✔
54
         params = "secp192r1";
217✔
55
      }
56
   #endif
57
   } else if(algo == "Ed25519") {
×
58
      params = "";
×
59
   } else if(algo == "RSA") {
×
60
      params = "1024";
×
61
   }
62

63
   return Botan::create_private_key(algo, rng, params);
217✔
64
}
217✔
65

66
Botan::CertificateParametersBuilder ca_params() {
149✔
67
   Botan::CertificateParametersBuilder builder;
149✔
68

69
   builder.add_common_name("RPKI Test CA")
149✔
70
      .add_country("US")
149✔
71
      .add_organization("Botan")
149✔
72
      .add_dns("botan.randombit.net")
149✔
73
      .set_as_ca_certificate(1);
149✔
74

75
   return builder;
149✔
76
}
×
77

78
Botan::CertificateParametersBuilder user_params() {
1,288✔
79
   Botan::CertificateParametersBuilder builder;
1,288✔
80

81
   builder.add_common_name("RPKI Test User")
1,288✔
82
      .add_country("US")
1,288✔
83
      .add_organization("Botan")
1,288✔
84
      .add_allowed_usage(Botan::Key_Constraints::DigitalSignature);
1,288✔
85

86
   return builder;
1,288✔
87
}
×
88

89
std::pair<std::string, std::string> get_sig_algo() {
149✔
90
   #if defined(BOTAN_HAS_ECDSA)
91
   const std::string sig_algo{"ECDSA"};
149✔
92
   const std::string hash_fn{"SHA-256"};
149✔
93
   #elif defined(BOTAN_HAS_ED25519)
94
   const std::string sig_algo{"Ed25519"};
95
   const std::string hash_fn{"SHA-512"};
96
   #elif defined(BOTAN_HAS_RSA)
97
   const std::string sig_algo{"RSA"};
98
   const std::string padding_method{"PKCS1v15(SHA-256)"};
99
   const std::string hash_fn{"SHA-256"};
100
   #endif
101

102
   return std::make_pair(sig_algo, hash_fn);
149✔
103
}
149✔
104

105
Botan::X509_Certificate make_self_signed(Botan::RandomNumberGenerator& rng,
5✔
106
                                         const Botan::CertificateParametersBuilder& params) {
107
   auto [sig_algo, hash_fn] = get_sig_algo();
5✔
108
   auto key = generate_key(sig_algo, rng);
5✔
109

110
   const auto now = std::chrono::system_clock::now();
5✔
111
   const auto not_before = now - std::chrono::seconds(180);
5✔
112
   const auto not_after = now + std::chrono::seconds(86400);
5✔
113

114
   return params.into_self_signed_cert(not_before, not_after, *key, rng, hash_fn);
5✔
115
}
10✔
116

117
CA_Creation_Result make_ca(Botan::RandomNumberGenerator& rng, const Botan::CertificateParametersBuilder& params) {
68✔
118
   auto [sig_algo, hash_fn] = get_sig_algo();
68✔
119
   auto ca_key = generate_key(sig_algo, rng);
68✔
120

121
   const auto now = std::chrono::system_clock::now();
68✔
122
   const auto not_before = now - std::chrono::seconds(180);
68✔
123
   const auto not_after = now + std::chrono::seconds(86400);
68✔
124

125
   const auto ca_cert = params.into_self_signed_cert(not_before, not_after, *ca_key, rng, hash_fn);
68✔
126

127
   Botan::X509_CA ca(ca_cert, *ca_key, hash_fn, rng);
68✔
128
   auto sub_key = generate_key(sig_algo, rng);
68✔
129

130
   return CA_Creation_Result{ca_cert, std::move(ca), std::move(sub_key), sig_algo, hash_fn};
204✔
131
}
204✔
132

133
CA_Creation_Result make_ca(Botan::RandomNumberGenerator& rng) {
6✔
134
   return make_ca(rng, ca_params());
6✔
135
}
136

137
std::pair<Botan::X509_Certificate, Botan::X509_CA> make_and_sign_ca(std::unique_ptr<Botan::Certificate_Extension> ext,
76✔
138
                                                                    Botan::X509_CA& parent_ca,
139
                                                                    Botan::RandomNumberGenerator& rng) {
140
   auto [sig_algo, hash_fn] = get_sig_algo();
76✔
141

142
   auto params = ca_params();
76✔
143
   params.add_extension(std::move(ext));
76✔
144

145
   std::unique_ptr<Botan::Private_Key> key = generate_key(sig_algo, rng);
76✔
146

147
   Botan::PKCS10_Request req = params.into_pkcs10_request(*key, rng, hash_fn);
76✔
148

149
   Botan::X509_Certificate cert = parent_ca.sign_request(req, rng, from_date(-1, 01, 01), from_date(2, 01, 01));
76✔
150
   Botan::X509_CA ca(cert, *key, hash_fn, rng);
76✔
151

152
   return std::make_pair(std::move(cert), std::move(ca));
76✔
153
}
228✔
154

155
constexpr auto IPv4 = Botan::Cert_Extension::IPAddressBlocks::Version::IPv4;
156
constexpr auto IPv6 = Botan::Cert_Extension::IPAddressBlocks::Version::IPv6;
157

158
   #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
159

160
Test::Result test_x509_ip_addr_blocks_extension_decode() {
1✔
161
   Test::Result result("X509 IP Address Block decode");
1✔
162
   result.start_timer();
1✔
163
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
164

165
   {
1✔
166
      const std::string filename("IPAddrBlocksAll.pem");
1✔
167
      Botan::X509_Certificate cert(Test::data_file("x509/x509test/" + filename));
2✔
168
      const auto* ip_addr_blocks = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1✔
169

170
      const auto& addr_blocks = ip_addr_blocks->addr_blocks();
1✔
171
      result.confirm("cert has IPAddrBlocks extension", ip_addr_blocks != nullptr, true);
2✔
172
      result.test_eq("cert has two IpAddrBlocks", addr_blocks.size(), 2);
1✔
173

174
      const auto& ipv4block = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(addr_blocks[0].addr_choice());
1✔
175
      const auto& ipv6block = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(addr_blocks[1].addr_choice());
1✔
176

177
      const auto& v4_blocks = ipv4block.ranges().value();
1✔
178

179
      // cert contains (in this order)
180
      // 192.168.0.0 - 192.168.127.255 (192.168.0.0/17)
181
      // 193.168.0.0 - 193.169.255.255 (193.168.0.0/15)
182
      // 194.168.0.0 - 195.175.1.2
183
      // 196.168.0.1 - 196.168.0.1 (196.168.0.1/32)
184

185
      result.test_eq("ipv4 block 0 min", v4_blocks[0].min().value(), {192, 168, 0, 0});
2✔
186
      result.test_eq("ipv4 block 0 max", v4_blocks[0].max().value(), {192, 168, 127, 255});
2✔
187

188
      result.test_eq("ipv4 block 1 min", v4_blocks[1].min().value(), {193, 168, 0, 0});
2✔
189
      result.test_eq("ipv4 block 1 max", v4_blocks[1].max().value(), {193, 169, 255, 255});
2✔
190
      result.test_eq("ipv4 block 2 min", v4_blocks[2].min().value(), {194, 168, 0, 0});
2✔
191
      result.test_eq("ipv4 block 2 max", v4_blocks[2].max().value(), {195, 175, 1, 2});
2✔
192

193
      result.test_eq("ipv4 block 3 min", v4_blocks[3].min().value(), {196, 168, 0, 1});
2✔
194
      result.test_eq("ipv4 block 3 max", v4_blocks[3].max().value(), {196, 168, 0, 1});
2✔
195

196
      const auto& v6_blocks = ipv6block.ranges().value();
1✔
197

198
      // cert contains (in this order)
199
      // fa80::/65
200
      // fe20::/37
201
      // 2003:0:6829:3435:420:10c5:0:c4/128
202
      // ab01:0:0:0:0:0:0:1-cd02:0:0:0:0:0:0:2
203

204
      result.test_eq("ipv6 block 0 min",
2✔
205
                     v6_blocks[0].min().value(),
1✔
206
                     {0x20, 0x03, 0x00, 0x00, 0x68, 0x29, 0x34, 0x35, 0x04, 0x20, 0x10, 0xc5, 0x00, 0x00, 0x00, 0xc4});
207
      result.test_eq("ipv6 block 0 max",
2✔
208
                     v6_blocks[0].max().value(),
1✔
209
                     {0x20, 0x03, 0x00, 0x00, 0x68, 0x29, 0x34, 0x35, 0x04, 0x20, 0x10, 0xc5, 0x00, 0x00, 0x00, 0xc4});
210
      result.test_eq("ipv6 block 1 min",
2✔
211
                     v6_blocks[1].min().value(),
1✔
212
                     {0xab, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
213
      result.test_eq("ipv6 block 1 max",
2✔
214
                     v6_blocks[1].max().value(),
1✔
215
                     {0xcd, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02});
216
      result.test_eq("ipv6 block 2 min",
2✔
217
                     v6_blocks[2].min().value(),
1✔
218
                     {0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
219
      result.test_eq("ipv6 block 2 max",
2✔
220
                     v6_blocks[2].max().value(),
1✔
221
                     {0xfa, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff});
222
      result.test_eq("ipv6 block 3 min",
2✔
223
                     v6_blocks[3].min().value(),
1✔
224
                     {0xfe, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
225
      result.test_eq("ipv6 block 3 max",
2✔
226
                     v6_blocks[3].max().value(),
1✔
227
                     {0xfe, 0x20, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff});
228
   }
1✔
229
   {
1✔
230
      const std::string filename("IPAddrBlocksUnsorted.pem");
1✔
231
      Botan::X509_Certificate cert(Test::data_file("x509/x509test/" + filename));
2✔
232
      const auto* ip_addr_blocks = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1✔
233

234
      // cert contains (in this order)
235
      // IPv6 (1) inherit
236
      // IPv6 0xff....0xff
237
      // IPv4 (2) inherit
238
      // IPv4 (1) 192.168.0.0 - 192.168.2.1
239
      // IPv4 (1) 192.168.2.2 - 200.0.0.0
240
      // IPv4 inherit
241

242
      // IPv4 ranges should be merged, IPv4 should come before IPv6, all should be sorted by safi
243

244
      const auto& addr_blocks = ip_addr_blocks->addr_blocks();
1✔
245
      result.test_eq("cert has two IpAddrBlocks", addr_blocks.size(), 5);
1✔
246

247
      result.test_eq("block 0 has no safi", addr_blocks[0].safi(), std::optional<uint8_t>{std::nullopt});
1✔
248
      result.confirm(
2✔
249
         "block 0 is inherited",
250
         !std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(addr_blocks[0].addr_choice()).ranges().has_value());
1✔
251

252
      result.test_eq("block 1 has correct safi", addr_blocks[1].safi(), std::optional<uint8_t>{1});
1✔
253
      const auto& block_1 =
1✔
254
         std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(addr_blocks[1].addr_choice()).ranges().value();
1✔
255

256
      result.confirm("block 1 has correct size", block_1.size() == 1);
2✔
257
      result.test_eq("block 1 min is correct", block_1[0].min().value(), {192, 168, 0, 0});
2✔
258
      result.test_eq("block 1 max is correct", block_1[0].max().value(), {200, 0, 0, 0});
2✔
259

260
      result.test_eq("block 2 has correct safi", addr_blocks[2].safi(), std::optional<uint8_t>{2});
1✔
261
      result.confirm(
2✔
262
         "block 2 is inherited",
263
         !std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(addr_blocks[2].addr_choice()).ranges().has_value());
1✔
264

265
      result.test_eq("block 3 has no safi", addr_blocks[3].safi(), std::optional<uint8_t>{std::nullopt});
1✔
266
      const auto& block_3 =
1✔
267
         std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(addr_blocks[3].addr_choice()).ranges().value();
1✔
268

269
      result.confirm("block 3 has correct size", block_3.size() == 1);
2✔
270
      result.test_eq("block 3 min is correct",
2✔
271
                     block_3[0].min().value(),
1✔
272
                     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff});
273
      result.test_eq("block 3 max is correct",
2✔
274
                     block_3[0].max().value(),
1✔
275
                     {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff});
276

277
      result.test_eq("block 24 has correct safi", addr_blocks[4].safi(), std::optional<uint8_t>{1});
1✔
278
      result.confirm(
2✔
279
         "block 4 is inherited",
280
         !std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(addr_blocks[4].addr_choice()).ranges().has_value());
1✔
281
   }
1✔
282
   {
1✔
283
      const std::string filename("InvalidIPAddrBlocks.pem");
1✔
284
      Botan::X509_Certificate cert(Test::data_file("x509/x509test/" + filename));
2✔
285

286
      // cert contains the 10.0.32.0/20 prefix, but with a 9 for the unused bits
287

288
      result.confirm("extension is present", cert.v3_extensions().extension_set(IPAddressBlocks::static_oid()));
2✔
289

290
      const auto* ext = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1✔
291
      result.confirm("extension is not decoded", ext == nullptr);
2✔
292
   }
1✔
293

294
   result.end_timer();
1✔
295
   return result;
1✔
296
}
×
297

298
Test::Result test_x509_as_blocks_extension_decode() {
1✔
299
   Test::Result result("X509 AS Block decode");
1✔
300
   result.start_timer();
1✔
301
   using Botan::Cert_Extension::ASBlocks;
1✔
302

303
   {
1✔
304
      const std::string filename("ASNumberCert.pem");
1✔
305
      Botan::X509_Certificate cert(Test::data_file("x509/x509test/" + filename));
2✔
306

307
      const auto* as_blocks = cert.v3_extensions().get_extension_object_as<ASBlocks>();
1✔
308

309
      const auto& identifier = as_blocks->as_identifiers();
1✔
310
      result.confirm("cert has ASBlock extension", as_blocks != nullptr, true);
2✔
311

312
      const auto& asnum = identifier.asnum().value().ranges().value();
1✔
313
      const auto& rdi = identifier.rdi().value().ranges().value();
1✔
314

315
      // cert contains asnum 0-999, 5042, 0-4294967295
316
      result.confirm("asnum entry 0 min", asnum[0].min() == 0, true);
2✔
317
      result.confirm("asnum entry 0 max", asnum[0].max() == 4294967295, true);
2✔
318

319
      // and rdi 1234-5678, 32768, 0-4294967295
320
      result.confirm("rdi entry 0 min", rdi[0].min() == 0, true);
2✔
321
      result.confirm("rdi entry 0 max", rdi[0].max() == 4294967295, true);
2✔
322
   }
1✔
323
   {
1✔
324
      const std::string filename("ASNumberOnly.pem");
1✔
325
      Botan::X509_Certificate cert(Test::data_file("x509/x509test/" + filename));
2✔
326

327
      const auto* as_blocks = cert.v3_extensions().get_extension_object_as<ASBlocks>();
1✔
328

329
      const auto& identifier = as_blocks->as_identifiers();
1✔
330
      result.confirm("cert has ASBlock extension", as_blocks != nullptr, true);
2✔
331

332
      const auto& asnum = identifier.asnum().value().ranges().value();
1✔
333
      result.confirm("cert has no RDI entries", identifier.rdi().has_value(), false);
2✔
334

335
      // contains 0-999, 0-4294967295
336
      result.confirm("asnum entry 0 min", asnum[0].min() == 0, true);
2✔
337
      result.confirm("asnum entry 0 max", asnum[0].max() == 4294967295, true);
2✔
338
   }
1✔
339
   {
1✔
340
      const std::string filename("ASRdiOnly.pem");
1✔
341
      Botan::X509_Certificate cert(Test::data_file("x509/x509test/" + filename));
2✔
342

343
      const auto* as_blocks = cert.v3_extensions().get_extension_object_as<ASBlocks>();
1✔
344

345
      const auto& identifier = as_blocks->as_identifiers();
1✔
346
      result.confirm("cert has ASBlock extension", as_blocks != nullptr, true);
2✔
347

348
      result.confirm("cert has no ASNUM entries", identifier.asnum().has_value(), false);
2✔
349
      const auto& rdi = identifier.rdi().value().ranges().value();
1✔
350

351
      // contains 1234-5678, 0-4294967295
352
      result.confirm("rdi entry 0 min", rdi[0].min() == 0, true);
2✔
353
      result.confirm("rdi entry 0 max", rdi[0].max() == 4294967295, true);
2✔
354
   }
1✔
355
   {
1✔
356
      const std::string filename("ASNumberInherit.pem");
1✔
357
      Botan::X509_Certificate cert(Test::data_file("x509/x509test/" + filename));
2✔
358

359
      const auto* as_blocks = cert.v3_extensions().get_extension_object_as<ASBlocks>();
1✔
360

361
      const auto& identifier = as_blocks->as_identifiers();
1✔
362
      result.confirm("cert has ASBlock extension", as_blocks != nullptr, true);
2✔
363

364
      result.confirm("asnum has no entries", identifier.asnum().value().ranges().has_value(), false);
2✔
365
      const auto& rdi = identifier.rdi().value().ranges().value();
1✔
366

367
      // contains 1234-5678, 0-4294967295
368
      result.confirm("rdi entry 0 min", rdi[0].min() == 0, true);
2✔
369
      result.confirm("rdi entry 0 max", rdi[0].max() == 4294967295, true);
2✔
370
   }
1✔
371

372
   result.end_timer();
1✔
373
   return result;
1✔
374
}
×
375

376
   #endif
377

378
Test::Result test_x509_ip_addr_blocks_rfc3779_example() {
1✔
379
   Test::Result result("X509 IP Address Blocks rfc3779 example");
1✔
380
   result.start_timer();
1✔
381

382
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
383
   auto rng = Test::new_rng(__func__);
1✔
384

385
   // construct like in https://datatracker.ietf.org/doc/html/rfc3779#page-18
386
   std::unique_ptr<IPAddressBlocks> blocks_1 = std::make_unique<IPAddressBlocks>();
1✔
387
   blocks_1->add_address<IPv4>({10, 0, 32, 0}, {10, 0, 47, 255}, 1);
1✔
388
   blocks_1->add_address<IPv4>({10, 0, 64, 0}, {10, 0, 64, 255}, 1);
1✔
389
   blocks_1->add_address<IPv4>({10, 1, 0, 0}, {10, 1, 255, 255}, 1);
1✔
390
   blocks_1->add_address<IPv4>({10, 2, 48, 0}, {10, 2, 63, 255}, 1);
1✔
391
   blocks_1->add_address<IPv4>({10, 2, 64, 0}, {10, 2, 64, 255}, 1);
1✔
392
   blocks_1->add_address<IPv4>({10, 3, 0, 0}, {10, 3, 255, 255}, 1);
1✔
393
   blocks_1->inherit<IPv6>();
1✔
394

395
   auto cert_1 = make_self_signed(*rng, ca_params().add_extension(std::move(blocks_1)));
2✔
396

397
   auto bits_1 = cert_1.v3_extensions().get_extension_bits(IPAddressBlocks::static_oid());
1✔
398

399
   result.test_eq(
1✔
400
      "extension is encoded as specified",
401
      bits_1,
402
      "3035302B040300010130240304040A00200304000A00400303000A01300C0304040A02300304000A02400303000A033006040200020500");
403

404
   const auto* ext_1 = cert_1.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1✔
405

406
   auto ext_1_addr_fam_1 = ext_1->addr_blocks()[0];
1✔
407
   result.test_eq("extension 1 ipv4 safi", ext_1_addr_fam_1.safi(), std::optional<uint8_t>(1));
1✔
408
   auto ext_1_ranges =
1✔
409
      std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(ext_1_addr_fam_1.addr_choice()).ranges().value();
1✔
410
   result.test_eq("extension 1 range 1 min", ext_1_ranges[0].min().value(), {10, 0, 32, 0});
2✔
411
   result.test_eq("extension 1 range 1 max", ext_1_ranges[0].max().value(), {10, 0, 47, 255});
2✔
412

413
   result.test_eq("extension 1 range 2 min", ext_1_ranges[1].min().value(), {10, 0, 64, 0});
2✔
414
   result.test_eq("extension 1 range 2 max", ext_1_ranges[1].max().value(), {10, 0, 64, 255});
2✔
415

416
   result.test_eq("extension 1 range 3 min", ext_1_ranges[2].min().value(), {10, 1, 0, 0});
2✔
417
   result.test_eq("extension 1 range 3 max", ext_1_ranges[2].max().value(), {10, 1, 255, 255});
2✔
418

419
   result.test_eq("extension 1 range 4 min", ext_1_ranges[3].min().value(), {10, 2, 48, 0});
2✔
420
   result.test_eq("extension 1 range 4 max", ext_1_ranges[3].max().value(), {10, 2, 64, 255});
2✔
421

422
   result.test_eq("extension 1 range 5 min", ext_1_ranges[4].min().value(), {10, 3, 0, 0});
2✔
423
   result.test_eq("extension 1 range 5 max", ext_1_ranges[4].max().value(), {10, 3, 255, 255});
2✔
424

425
   result.test_eq("extension 1 ipv6 safi", ext_1->addr_blocks()[1].safi(), std::optional<uint8_t>{std::nullopt});
1✔
426
   result.confirm(
2✔
427
      "extension 1 ipv6 inherited",
428
      !std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(ext_1->addr_blocks()[1].addr_choice()).ranges().has_value());
1✔
429

430
   // https://datatracker.ietf.org/doc/html/rfc3779#page-20
431
   std::unique_ptr<IPAddressBlocks> blocks_2 = std::make_unique<IPAddressBlocks>();
1✔
432
   blocks_2->add_address<IPv6>(
1✔
433
      {0x20, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
434
      {0x20, 0x01, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff});
435
   blocks_2->add_address<IPv4>({10, 0, 0, 0}, {10, 255, 255, 255}, 1);
1✔
436
   blocks_2->add_address<IPv4>({172, 16, 0, 0}, {172, 31, 255, 255}, 1);
1✔
437
   blocks_2->inherit<IPv4>(2);
1✔
438

439
   auto cert_2 = make_self_signed(*rng, ca_params().add_extension(std::move(blocks_2)));
2✔
440

441
   auto bits_2 = cert_2.v3_extensions().get_extension_bits(IPAddressBlocks::static_oid());
1✔
442

443
   // see https://www.rfc-editor.org/errata/eid6792 as to why the B0 specified in the RFC is a AC here
444
   result.test_eq("extension is encoded as specified",
1✔
445
                  bits_2,
446
                  "302C3010040300010130090302000A030304AC10300704030001020500300F040200023009030700200100000002");
447

448
   const auto* ext_2 = cert_2.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1✔
449

450
   auto ext_2_addr_fam_1 = ext_2->addr_blocks()[0];
1✔
451
   result.test_eq("extension 2 ipv4 1 safi", ext_2_addr_fam_1.safi(), std::optional<uint8_t>(1));
1✔
452
   auto ext_2_ranges_1 =
1✔
453
      std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(ext_2_addr_fam_1.addr_choice()).ranges().value();
1✔
454
   result.test_eq("extension 2 fam 1 range 1 min", ext_2_ranges_1[0].min().value(), {10, 0, 0, 0});
2✔
455
   result.test_eq("extension 2 fam 1 range 1 max", ext_2_ranges_1[0].max().value(), {10, 255, 255, 255});
2✔
456

457
   result.test_eq("extension 2 fam 1 range 2 min", ext_2_ranges_1[1].min().value(), {172, 16, 0, 0});
2✔
458
   result.test_eq("extension 2 fam 1 range 2 max", ext_2_ranges_1[1].max().value(), {172, 31, 255, 255});
2✔
459

460
   result.test_eq("extension 2 ipv4 2 safi", ext_2->addr_blocks()[1].safi(), std::optional<uint8_t>{2});
1✔
461
   result.confirm(
2✔
462
      "extension 2 ipv4 2 inherited",
463
      !std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(ext_2->addr_blocks()[1].addr_choice()).ranges().has_value());
1✔
464

465
   auto ext_2_addr_fam_3 = ext_2->addr_blocks()[2];
1✔
466
   result.test_eq("extension 2 ipv4 1 safi", ext_2_addr_fam_3.safi(), std::optional<uint8_t>(std::nullopt));
1✔
467
   auto ext_2_ranges_3 =
1✔
468
      std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(ext_2_addr_fam_3.addr_choice()).ranges().value();
1✔
469
   result.test_eq("extension 2 fam 3 range 1 min",
2✔
470
                  ext_2_ranges_3[0].min().value(),
1✔
471
                  {0x20, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
472
   result.test_eq("extension 2 fam 3 range 1 max",
2✔
473
                  ext_2_ranges_3[0].max().value(),
1✔
474
                  {0x20, 0x01, 0x00, 0x00, 0x00, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff});
475

476
   result.end_timer();
1✔
477
   return result;
2✔
478
}
7✔
479

480
Test::Result test_x509_ip_addr_blocks_encode_builder() {
1✔
481
   Test::Result result("X509 IP Address Blocks encode (builder)");
1✔
482
   result.start_timer();
1✔
483

484
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
485
   auto rng = Test::new_rng(__func__);
1✔
486

487
   std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>();
1✔
488

489
   // 64 - 127
490
   blocks->add_address<IPv4>({192, 168, 0b01000000, 0}, {192, 168, 0b01111111, 255}, 2);
1✔
491

492
   blocks->add_address<IPv4>({255, 255, 255, 255});
1✔
493
   // encoded as prefix
494
   blocks->add_address<IPv4>({190, 5, 0, 0}, {190, 5, 0b01111111, 255});
1✔
495
   // encoded as min, max
496
   blocks->add_address<IPv4>({127, 0, 0, 1}, {189, 5, 7, 255});
1✔
497

498
   // full address range
499
   blocks->add_address<IPv4>({0, 0, 0, 0}, {255, 255, 255, 255}, 1);
1✔
500

501
   blocks->add_address<IPv4>({123, 123, 2, 1});
1✔
502

503
   auto cert = make_self_signed(*rng, ca_params().add_extension(std::move(blocks)));
2✔
504
   auto bits = cert.v3_extensions().get_extension_bits(IPAddressBlocks::static_oid());
1✔
505

506
   // hand validated with https://lapo.it/asn1js/
507
   result.test_eq(
1✔
508
      "extension is encoded as specified",
509
      bits,
510
      "304630290402000130230305007B7B0201300D0305007F000001030403BD0500030407BE0500030500FFFFFFFF300A04030001013003030100300D04030001023006030406C0A840");
511

512
   result.end_timer();
1✔
513
   return result;
1✔
514
}
2✔
515

516
namespace {
517

518
template <size_t I>
519
bool bit_set(size_t v) {
648✔
520
   if(((v >> I) & 1) == 1) {
648✔
521
      return true;
522
   } else {
523
      return false;
324✔
524
   }
525
}
526

527
}  // namespace
528

529
Test::Result test_x509_ip_addr_blocks_extension_encode_ctor() {
1✔
530
   Test::Result result("X509 IP Address Block encode (ctor)");
1✔
531
   result.start_timer();
1✔
532

533
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
534

535
   auto rng = Test::new_rng(__func__);
1✔
536

537
   auto [ca_cert, ca, sub_key, sig_algo, hash_fn] = make_ca(*rng);
1✔
538

539
   for(size_t i = 0; i < 64; i++) {
65✔
540
      bool push_ipv4_ranges = bit_set<0>(i);
64✔
541
      bool push_ipv6_ranges = bit_set<1>(i);
64✔
542
      bool inherit_ipv4 = bit_set<2>(i);
64✔
543
      bool inherit_ipv6 = bit_set<3>(i);
64✔
544
      bool push_ipv4_family = bit_set<4>(i);
64✔
545
      bool push_ipv6_family = bit_set<5>(i);
64✔
546

547
      std::vector<uint8_t> a = {123, 123, 2, 1};
64✔
548
      auto ipv4_1 = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
549
      a = {255, 255, 255, 255};
64✔
550
      auto ipv4_2 = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
551

552
      // encoded as min, max
553
      a = {127, 0, 0, 1};
64✔
554
      auto ipv4_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
555
      a = {189, 5, 7, 255};
64✔
556
      auto ipv4_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
557

558
      // encoded as prefix
559
      a = {190, 5, 0, 0};
64✔
560
      auto ipv4_range_2_min = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
561
      a = {190, 5, 127, 255};
64✔
562
      auto ipv4_range_2_max = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
563

564
      a = {0xAB, 0xCD, 0xDE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
64✔
565
      auto ipv6_1 = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
566
      a = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
64✔
567
      auto ipv6_2 = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
568

569
      // encoded as min, max
570
      a = {0xAF, 0x23, 0x34, 0x45, 0x67, 0x2A, 0x7A, 0xEF, 0x8C, 0x00, 0x00, 0x00, 0x66, 0x00, 0x52, 0x00};
64✔
571
      auto ipv6_range_1_min = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
572

573
      a = {0xAF, 0xCD, 0xDE, 0xF0, 0x00, 0x0F, 0xEE, 0x00, 0xBB, 0x4A, 0x9B, 0x00, 0x00, 0x4C, 0x00, 0xCC};
64✔
574
      auto ipv6_range_1_max = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
575

576
      // encoded as prefix
577
      a = {0xBF, 0xCD, 0xDE, 0xF0, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
64✔
578
      auto ipv6_range_2_min = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
579
      a = {0xBF, 0xCD, 0xDE, 0xF0, 0x00, 0x00, 0x00, 0x07, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
64✔
580
      auto ipv6_range_2_max = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
581

582
      auto ipv4_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(ipv4_1);
64✔
583
      auto ipv4_range_2 = IPAddressBlocks::IPAddressOrRange<IPv4>(ipv4_range_1_min, ipv4_range_1_max);
64✔
584
      auto ipv4_range_3 = IPAddressBlocks::IPAddressOrRange<IPv4>(ipv4_range_2_min, ipv4_range_2_max);
64✔
585
      auto ipv4_range_4 = IPAddressBlocks::IPAddressOrRange<IPv4>(ipv4_2);
64✔
586

587
      auto ipv6_range_1 = IPAddressBlocks::IPAddressOrRange<IPv6>(ipv6_1);
64✔
588
      auto ipv6_range_2 = IPAddressBlocks::IPAddressOrRange<IPv6>(ipv6_range_1_min, ipv6_range_1_max);
64✔
589
      auto ipv6_range_3 = IPAddressBlocks::IPAddressOrRange<IPv6>(ipv6_range_2_min, ipv6_range_2_max);
64✔
590
      auto ipv6_range_4 = IPAddressBlocks::IPAddressOrRange<IPv6>(ipv6_2);
64✔
591

592
      std::vector<IPAddressBlocks::IPAddressOrRange<IPv4>> ipv4_ranges;
64✔
593
      if(push_ipv4_ranges) {
64✔
594
         ipv4_ranges.push_back(ipv4_range_1);
32✔
595
         ipv4_ranges.push_back(ipv4_range_2);
32✔
596
         ipv4_ranges.push_back(ipv4_range_3);
32✔
597
         ipv4_ranges.push_back(ipv4_range_4);
32✔
598
      }
599

600
      std::vector<IPAddressBlocks::IPAddressOrRange<IPv6>> ipv6_ranges;
64✔
601
      if(push_ipv6_ranges) {
64✔
602
         ipv6_ranges.push_back(ipv6_range_1);
32✔
603
         ipv6_ranges.push_back(ipv6_range_2);
32✔
604
         ipv6_ranges.push_back(ipv6_range_3);
32✔
605
         ipv6_ranges.push_back(ipv6_range_4);
32✔
606
      }
607

608
      auto ipv4_addr_choice = IPAddressBlocks::IPAddressChoice<IPv4>();
64✔
609
      if(!inherit_ipv4) {
64✔
610
         ipv4_addr_choice = IPAddressBlocks::IPAddressChoice<IPv4>(ipv4_ranges);
96✔
611
      }
612

613
      auto ipv6_addr_choice = IPAddressBlocks::IPAddressChoice<IPv6>();
64✔
614
      if(!inherit_ipv6) {
64✔
615
         ipv6_addr_choice = IPAddressBlocks::IPAddressChoice<IPv6>(ipv6_ranges);
96✔
616
      }
617

618
      auto ipv4_addr_family = IPAddressBlocks::IPAddressFamily(ipv4_addr_choice);
160✔
619
      auto ipv6_addr_family = IPAddressBlocks::IPAddressFamily(ipv6_addr_choice);
160✔
620

621
      std::vector<IPAddressBlocks::IPAddressFamily> addr_blocks;
64✔
622
      if(push_ipv4_family) {
64✔
623
         addr_blocks.push_back(ipv4_addr_family);
32✔
624
      }
625
      if(push_ipv6_family) {
64✔
626
         addr_blocks.push_back(ipv6_addr_family);
32✔
627
      }
628

629
      std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>(addr_blocks);
64✔
630

631
      auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
64✔
632
      Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
64✔
633
      {
64✔
634
         const auto* ip_blocks = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
64✔
635
         result.confirm("cert has IPAddrBlocks extension", ip_blocks != nullptr, true);
128✔
636

637
         const auto& dec_addr_blocks = ip_blocks->addr_blocks();
64✔
638
         if(!push_ipv4_family && !push_ipv6_family) {
64✔
639
            result.confirm("no address family entries", dec_addr_blocks.empty(), true);
32✔
640
            continue;
16✔
641
         }
642

643
         if(push_ipv4_family) {
48✔
644
            auto family = dec_addr_blocks[0];
32✔
645
            result.confirm("ipv4 family afi", ipv4_addr_family.afi() == family.afi(), true);
64✔
646
            result.test_eq("ipv4 family safi", ipv4_addr_family.safi(), family.safi());
32✔
647
            auto choice = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(family.addr_choice());
32✔
648

649
            if(!inherit_ipv4) {
32✔
650
               auto ranges = choice.ranges().value();
16✔
651
               if(push_ipv4_ranges) {
16✔
652
                  result.test_eq("ipv4 entry 0 min", ranges[0].min().value(), ipv4_range_1.min().value());
16✔
653
                  result.test_eq("ipv4 entry 0 max", ranges[0].max().value(), ipv4_range_1.max().value());
16✔
654
                  result.test_eq("ipv4 entry 1 min", ranges[1].min().value(), ipv4_range_2.min().value());
16✔
655
                  result.test_eq("ipv4 entry 1 max", ranges[1].max().value(), ipv4_range_2.max().value());
16✔
656
                  result.test_eq("ipv4 entry 2 min", ranges[2].min().value(), ipv4_range_3.min().value());
16✔
657
                  result.test_eq("ipv4 entry 2 max", ranges[2].max().value(), ipv4_range_3.max().value());
16✔
658
                  result.test_eq("ipv4 entry 3 min", ranges[3].min().value(), ipv4_range_4.min().value());
16✔
659
                  result.test_eq("ipv4 entry 3 max", ranges[3].max().value(), ipv4_range_4.max().value());
16✔
660
               } else {
661
                  result.confirm("ipv4 range has no entries", ranges.empty(), true);
16✔
662
               }
663
            } else {
16✔
664
               result.confirm("ipv4 family inherit", choice.ranges().has_value(), false);
32✔
665
            }
666
         }
64✔
667

668
         if(push_ipv6_family) {
48✔
669
            auto family = dec_addr_blocks[dec_addr_blocks.size() - 1];
32✔
670
            result.confirm("ipv6 family afi", ipv6_addr_family.afi() == family.afi(), true);
64✔
671
            result.test_eq("ipv6 family safi", ipv6_addr_family.safi(), family.safi());
32✔
672
            auto choice = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(family.addr_choice());
32✔
673
            if(!inherit_ipv6) {
32✔
674
               auto ranges = choice.ranges().value();
16✔
675
               if(push_ipv6_ranges) {
16✔
676
                  result.test_eq("ipv6 entry 0 min", ranges[0].min().value(), ipv6_range_1.min().value());
16✔
677
                  result.test_eq("ipv6 entry 0 max", ranges[0].max().value(), ipv6_range_1.max().value());
16✔
678
                  result.test_eq("ipv6 entry 1 min", ranges[1].min().value(), ipv6_range_2.min().value());
16✔
679
                  result.test_eq("ipv6 entry 1 max", ranges[1].max().value(), ipv6_range_2.max().value());
16✔
680
                  result.test_eq("ipv6 entry 2 min", ranges[2].min().value(), ipv6_range_3.min().value());
16✔
681
                  result.test_eq("ipv6 entry 2 max", ranges[2].max().value(), ipv6_range_3.max().value());
16✔
682
                  result.test_eq("ipv6 entry 3 min", ranges[3].min().value(), ipv6_range_4.min().value());
16✔
683
                  result.test_eq("ipv6 entry 3 max", ranges[3].max().value(), ipv6_range_4.max().value());
16✔
684
               } else {
685
                  result.confirm("ipv6 range has no entries", ranges.empty(), true);
16✔
686
               }
687
            } else {
16✔
688
               result.confirm("ipv6 family inherit", choice.ranges().has_value(), false);
32✔
689
            }
690
         }
64✔
691
      }
692
   }
320✔
693

694
   result.end_timer();
1✔
695
   return result;
2✔
696
}
2✔
697

698
Test::Result test_x509_ip_addr_blocks_extension_encode_edge_cases_ctor() {
1✔
699
   Test::Result result("X509 IP Address Block encode edge cases (ctor)");
1✔
700
   result.start_timer();
1✔
701

702
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
703

704
   auto rng = Test::new_rng(__func__);
1✔
705

706
   // trailing 0s, trailing 1s, and some arbitrary values
707
   std::vector<uint8_t> edge_values = {0,  2,  4,  8,   16,  32, 64, 128, 1,   3,  7,
1✔
708
                                       15, 31, 63, 127, 255, 12, 46, 123, 160, 234};
1✔
709

710
   auto [ca_cert, ca, sub_key, sig_algo, hash_fn] = make_ca(*rng);
1✔
711

712
   for(size_t i = 0; i < edge_values.size(); i++) {
22✔
713
      for(size_t j = 0; j < 4; j++) {
105✔
714
         bool modify_min = bit_set<0>(j);
84✔
715
         bool modify_max = bit_set<1>(j);
84✔
716

717
         for(size_t k = 0; k < 18; k++) {
1,219✔
718
            if(!modify_min && !modify_max && (k > 0 || i > 0)) {
1,156✔
719
               // we don't modify anything, this is the extreme edge case of 0.0 ... - 255.255. ...
720
               // so we only need to do this once
721
               break;
722
            }
723

724
            std::vector<uint8_t> min_bytes(16, 0x00);
1,135✔
725
            std::vector<uint8_t> max_bytes(16, 0xFF);
1,135✔
726

727
            if(modify_min) {
1,135✔
728
               min_bytes[15 - (k < 2 ? 0 : k - 2)] = edge_values[i];
756✔
729
            }
730
            if(modify_max) {
1,135✔
731
               max_bytes[15 - (k > 15 ? 15 : k)] = edge_values[i];
756✔
732
            }
733

734
            auto address_min = IPAddressBlocks::IPAddress<IPv6>(min_bytes);
1,135✔
735
            auto address_max = IPAddressBlocks::IPAddress<IPv6>(max_bytes);
1,135✔
736

737
            auto ipv6_range = IPAddressBlocks::IPAddressOrRange<IPv6>(address_min, address_max);
1,135✔
738

739
            std::vector<IPAddressBlocks::IPAddressOrRange<IPv6>> ipv6_ranges;
1,135✔
740
            ipv6_ranges.push_back(ipv6_range);
1,135✔
741

742
            auto ipv6_addr_choice = IPAddressBlocks::IPAddressChoice<IPv6>(ipv6_ranges);
1,135✔
743

744
            auto ipv6_addr_family = IPAddressBlocks::IPAddressFamily(ipv6_addr_choice);
3,405✔
745

746
            std::vector<IPAddressBlocks::IPAddressFamily> addr_blocks;
1,135✔
747
            addr_blocks.push_back(ipv6_addr_family);
1,135✔
748

749
            std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>(addr_blocks);
1,135✔
750

751
            auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1,135✔
752
            Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1,135✔
753
            {
1,135✔
754
               const auto* ip_blocks = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1,135✔
755
               result.confirm("cert has IPAddrBlocks extension", ip_blocks != nullptr, true);
2,270✔
756
               const auto& dec_addr_blocks = ip_blocks->addr_blocks();
1,135✔
757
               auto family = dec_addr_blocks[0];
1,135✔
758
               result.confirm("ipv6 family afi", ipv6_addr_family.afi() == family.afi(), true);
2,270✔
759
               result.test_eq("ipv6 family safi", ipv6_addr_family.safi(), family.safi());
1,135✔
760
               auto choice = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(family.addr_choice());
1,135✔
761
               auto ranges = choice.ranges().value();
1,135✔
762

763
               result.test_eq("ipv6 edge case min", ranges[0].min().value(), ipv6_range.min().value());
2,270✔
764
               result.test_eq("ipv6 edge case max", ranges[0].max().value(), ipv6_range.max().value());
2,270✔
765
            }
2,270✔
766
         }
5,675✔
767
      }
768
   }
769
   result.end_timer();
1✔
770
   return result;
2✔
771
}
3✔
772

773
Test::Result test_x509_ip_addr_blocks_range_merge() {
1✔
774
   Test::Result result("X509 IP Address Block range merge");
1✔
775
   result.start_timer();
1✔
776

777
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
778

779
   auto rng = Test::new_rng(__func__);
1✔
780

781
   auto [ca_cert, ca, sub_key, sig_algo, hash_fn] = make_ca(*rng);
1✔
782

783
   std::vector<std::vector<std::vector<uint8_t>>> addresses = {
1✔
784
      {{11, 0, 0, 0}, {{11, 0, 0, 0}}},
785
      {{123, 123, 123, 123}, {123, 123, 123, 123}},
786
      {{10, 4, 5, 9}, {{10, 255, 0, 0}}},
787
      {{12, 0, 0, 0}, {191, 0, 0, 1}},
788
      {{190, 0, 0, 0}, {193, 0, 255, 255}},
789
      {{10, 10, 10, 10}, {10, 20, 20, 20}},
790
      {{5, 0, 0, 0}, {10, 255, 255, 255}},
791
      {{192, 0, 0, 0}, {192, 255, 255, 255}},
792
      {{11, 0, 0, 1}, {11, 255, 255, 255}},
793
   };
46✔
794

795
   std::vector<IPAddressBlocks::IPAddressOrRange<IPv4>> ipv6_ranges;
1✔
796
   for(auto pair : addresses) {
10✔
797
      auto address_min = IPAddressBlocks::IPAddress<IPv4>(pair[0]);
9✔
798
      auto address_max = IPAddressBlocks::IPAddress<IPv4>(pair[1]);
9✔
799
      auto range = IPAddressBlocks::IPAddressOrRange<IPv4>(address_min, address_max);
9✔
800
      ipv6_ranges.push_back(range);
9✔
801
   }
9✔
802

803
   auto ipv6_addr_choice = IPAddressBlocks::IPAddressChoice<IPv4>(ipv6_ranges);
1✔
804
   auto ipv6_addr_family = IPAddressBlocks::IPAddressFamily(ipv6_addr_choice);
3✔
805

806
   std::vector<IPAddressBlocks::IPAddressFamily> addr_blocks;
1✔
807
   addr_blocks.push_back(ipv6_addr_family);
1✔
808

809
   std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>(addr_blocks);
1✔
810

811
   auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1✔
812
   Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1✔
813
   {
1✔
814
      const auto* ip_blocks = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1✔
815
      result.confirm("cert has IPAddrBlocks extension", ip_blocks != nullptr, true);
2✔
816
      const auto& dec_addr_blocks = ip_blocks->addr_blocks();
1✔
817
      auto family = dec_addr_blocks[0];
1✔
818
      auto choice = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(family.addr_choice());
1✔
819
      auto ranges = choice.ranges().value();
1✔
820

821
      std::array<uint8_t, 4> expected_min = {5, 0, 0, 0};
1✔
822
      std::array<uint8_t, 4> expected_max = {193, 0, 255, 255};
1✔
823

824
      result.test_eq("range expected min", ranges[0].min().value(), expected_min);
2✔
825
      result.test_eq("range expected max", ranges[0].max().value(), expected_max);
2✔
826
      result.test_eq("range length", ranges.size(), 1);
1✔
827
   }
2✔
828

829
   result.end_timer();
1✔
830
   return result;
2✔
831
}
24✔
832

833
Test::Result test_x509_ip_addr_blocks_family_merge() {
1✔
834
   Test::Result result("X509 IP Address Block family merge");
1✔
835
   result.start_timer();
1✔
836

837
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
838

839
   auto rng = Test::new_rng(__func__);
1✔
840

841
   auto [ca_cert, ca, sub_key, sig_algo, hash_fn] = make_ca(*rng);
1✔
842

843
   std::vector<IPAddressBlocks::IPAddressFamily> addr_blocks;
1✔
844

845
   IPAddressBlocks::IPAddressChoice<IPv4> v4_empty_choice;
1✔
846
   IPAddressBlocks::IPAddressChoice<IPv6> v6_empty_choice;
1✔
847

848
   uint8_t v4_bytes_1[4] = {123, 123, 123, 123};
1✔
849
   IPAddressBlocks::IPAddress<IPv4> v4_addr_1(v4_bytes_1);
1✔
850
   // create 2 prefixes from the v4 addresses -> they should be merged
851

852
   std::vector<IPAddressBlocks::IPAddressOrRange<IPv4>> v4_choice_vec{
1✔
853
      IPAddressBlocks::IPAddressOrRange<IPv4>(IPAddressBlocks::IPAddress<IPv4>({v4_addr_1}))};
1✔
854
   IPAddressBlocks::IPAddressChoice<IPv4> v4_choice_dupl(v4_choice_vec);
1✔
855
   result.confirm(
2✔
856
      "IPAddressChoice v4 merges ranges already in constructor", v4_choice_dupl.ranges().value().size() == 1, true);
1✔
857
   IPAddressBlocks::IPAddressFamily v4_fam_dupl(v4_choice_dupl, 0);
3✔
858

859
   uint8_t v6_bytes_1[16] = {123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123};
1✔
860
   IPAddressBlocks::IPAddress<IPv6> v6_addr_1(v6_bytes_1);
1✔
861

862
   std::vector<IPAddressBlocks::IPAddressOrRange<IPv6>> v6_choice_vec{
1✔
863
      IPAddressBlocks::IPAddressOrRange<IPv6>(IPAddressBlocks::IPAddress<IPv6>({v6_addr_1}))};
1✔
864
   IPAddressBlocks::IPAddressChoice<IPv6> v6_choice_dupl(v6_choice_vec);
1✔
865
   result.confirm(
2✔
866
      "IPAddressChoice v6 merges already in constructor", v6_choice_dupl.ranges().value().size() == 1, true);
1✔
867
   IPAddressBlocks::IPAddressFamily v6_fam_dupl(v6_choice_dupl, 0);
3✔
868

869
   IPAddressBlocks::IPAddressFamily v4_empty_fam(v4_empty_choice);
2✔
870
   IPAddressBlocks::IPAddressFamily v6_empty_fam(v6_empty_choice);
2✔
871

872
   IPAddressBlocks::IPAddressFamily v4_empty_fam_safi(v4_empty_choice, 2);
2✔
873
   IPAddressBlocks::IPAddressFamily v6_empty_fam_safi(v6_empty_choice, 2);
2✔
874

875
   /*
876
   considering the push order, the resulting order should be
877
   [0] v4 no safi
878
   [2] v4 safi
879
   [1] v6 no safi
880
   [3] v6 safi
881
   */
882
   for(size_t i = 0; i < 3; i++) {
4✔
883
      addr_blocks.push_back(v4_empty_fam_safi);
3✔
884
      addr_blocks.push_back(v6_empty_fam);
3✔
885
      addr_blocks.push_back(v4_fam_dupl);
3✔
886
      addr_blocks.push_back(v6_empty_fam_safi);
3✔
887
      addr_blocks.push_back(v6_fam_dupl);
3✔
888
      addr_blocks.push_back(v4_empty_fam);
3✔
889
   }
890

891
   std::vector<IPAddressBlocks::IPAddressFamily> expected_blocks = {
1✔
892
      v4_empty_fam, v4_fam_dupl, v4_empty_fam_safi, v6_empty_fam, v6_fam_dupl, v6_empty_fam_safi};
7✔
893

894
   std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>(addr_blocks);
1✔
895

896
   auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1✔
897
   Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1✔
898

899
   const auto* ip_blocks = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1✔
900
   result.confirm("cert has IPAddrBlocks extension", ip_blocks != nullptr, true);
2✔
901
   const auto& dec_blocks = ip_blocks->addr_blocks();
1✔
902

903
   result.confirm("blocks got merged lengthwise", dec_blocks.size() == expected_blocks.size(), true);
2✔
904

905
   bool sorted = true;
1✔
906
   for(size_t i = 0; i < dec_blocks.size() - 1; i++) {
6✔
907
      const IPAddressBlocks::IPAddressFamily& a = dec_blocks[i];
5✔
908
      const IPAddressBlocks::IPAddressFamily& b = dec_blocks[i + 1];
5✔
909

910
      uint32_t afam_a = a.afi();
5✔
911
      if(a.safi().has_value()) {
5✔
912
         afam_a = static_cast<uint32_t>(afam_a << 8) | a.safi().value();
3✔
913
      } else {
914
         afam_a = static_cast<uint32_t>(afam_a << 8);
2✔
915
      }
916

917
      uint32_t afam_b = b.afi();
5✔
918
      if(b.safi().has_value()) {
5✔
919
         afam_b = static_cast<uint32_t>(afam_b << 8) | b.safi().value();
4✔
920
      } else {
921
         afam_b = static_cast<uint32_t>(afam_b << 8);
1✔
922
      }
923

924
      if(afam_a > afam_b) {
5✔
925
         sorted = false;
926
         break;
927
      }
928
   }
929

930
   result.confirm("blocks got sorted", sorted, true);
2✔
931

932
   for(size_t i = 0; i < dec_blocks.size(); i++) {
7✔
933
      const IPAddressBlocks::IPAddressFamily& dec = dec_blocks[i];
6✔
934
      const IPAddressBlocks::IPAddressFamily& exp = expected_blocks[i];
6✔
935

936
      result.confirm("blocks match push order by afi at index " + std::to_string(i), dec.afi() == exp.afi(), true);
12✔
937
      result.test_eq("blocks match push order by safi at index " + std::to_string(i), dec.safi(), exp.safi());
18✔
938

939
      if((exp.afi() == 1) && (dec.afi() == 1)) {
6✔
940
         auto dec_choice = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(dec.addr_choice());
3✔
941
         auto exp_choice = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(exp.addr_choice());
3✔
942

943
         if(!exp_choice.ranges().has_value()) {
3✔
944
            result.confirm(
2✔
945
               "block ranges should inherit at index " + std::to_string(i), dec_choice.ranges().has_value(), false);
6✔
946
         } else {
947
            result.confirm(
1✔
948
               "block ranges should not inherit at index " + std::to_string(i), dec_choice.ranges().has_value(), true);
3✔
949

950
            if(dec_choice.ranges().has_value() == false) {
1✔
951
               continue;
×
952
            }
953

954
            auto dec_ranges = dec_choice.ranges().value();
1✔
955
            auto exp_ranges = exp_choice.ranges().value();
1✔
956
            result.confirm("block ranges got merged lengthwise at index " + std::to_string(i),
2✔
957
                           dec_ranges.size() == exp_ranges.size(),
1✔
958
                           true);
959

960
            if(dec_ranges.size() != exp_ranges.size()) {
1✔
961
               continue;
×
962
            }
963

964
            for(size_t j = 0; j < exp_ranges.size(); j++) {
2✔
965
               result.test_eq(
2✔
966
                  "block ranges min got merged valuewise at indices " + std::to_string(i) + "," + std::to_string(j),
4✔
967
                  exp_ranges[j].min().value(),
1✔
968
                  dec_ranges[j].min().value());
1✔
969
               result.test_eq(
2✔
970
                  "block ranges max got merged valuewise at indices " + std::to_string(i) + "," + std::to_string(j),
4✔
971
                  exp_ranges[j].max().value(),
1✔
972
                  dec_ranges[j].max().value());
2✔
973
            }
974
         }
1✔
975
      } else if((exp.afi() == 2) && (dec.afi() == 2)) {
7✔
976
         auto dec_choice = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(dec.addr_choice());
3✔
977
         auto exp_choice = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(exp.addr_choice());
3✔
978

979
         if(!exp_choice.ranges().has_value()) {
3✔
980
            result.confirm(
2✔
981
               "block ranges should inherit at index " + std::to_string(i), dec_choice.ranges().has_value(), false);
6✔
982
         } else {
983
            result.confirm(
1✔
984
               "block ranges should not inherit at index " + std::to_string(i), dec_choice.ranges().has_value(), true);
3✔
985

986
            if(dec_choice.ranges().has_value() == false) {
1✔
987
               continue;
×
988
            }
989

990
            auto dec_ranges = dec_choice.ranges().value();
1✔
991
            auto exp_ranges = exp_choice.ranges().value();
1✔
992
            result.confirm("block ranges got merged lengthwise at index " + std::to_string(i),
2✔
993
                           dec_ranges.size() == exp_ranges.size(),
994
                           true);
995

996
            if(dec_ranges.size() != exp_ranges.size()) {
1✔
997
               continue;
×
998
            }
999

1000
            for(size_t j = 0; j < exp_ranges.size(); j++) {
2✔
1001
               result.test_eq(
2✔
1002
                  "block ranges min got merged valuewise at indices " + std::to_string(i) + "," + std::to_string(j),
4✔
1003
                  exp_ranges[j].min().value(),
1✔
1004
                  dec_ranges[j].min().value());
1✔
1005
               result.test_eq(
2✔
1006
                  "block ranges max got merged valuewise at indices " + std::to_string(i) + "," + std::to_string(j),
4✔
1007
                  exp_ranges[j].max().value(),
1✔
1008
                  dec_ranges[j].max().value());
2✔
1009
            }
1010
         }
1✔
1011
      }
4✔
1012
   }
1013

1014
   result.end_timer();
1✔
1015
   return result;
2✔
1016
}
19✔
1017

1018
Test::Result test_x509_ip_addr_blocks_path_validation_success_builder() {
1✔
1019
   Test::Result result("X509 IP Address Blocks path validation success (builder)");
1✔
1020
   result.start_timer();
1✔
1021

1022
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
1023
   auto rng = Test::new_rng(__func__);
1✔
1024

1025
   /*
1026
   Creates a certificate chain of length 4.
1027
   Root: ipv4 and ipv6
1028
   Inherit: has both values as 'inherit'
1029
   Dynamic: has either both 'inherit', both with values, or just one with a value
1030
   Subject: both ipv4 and ipv6 as a subset of Root / Dynamic
1031
   */
1032

1033
   // Root cert
1034
   std::unique_ptr<IPAddressBlocks> root_blocks = std::make_unique<IPAddressBlocks>();
1✔
1035

1036
   root_blocks->add_address<IPv4>({120, 0, 0, 1}, {130, 140, 150, 160}, 42);
1✔
1037
   root_blocks->add_address<IPv4>({10, 0, 0, 1}, {10, 255, 255, 255}, 42);
1✔
1038

1039
   root_blocks->add_address<IPv6>(
1✔
1040
      {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
1041
      {0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
1042
   root_blocks->add_address<IPv6>(
1✔
1043
      {0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
1044
      {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
1045

1046
   // Inherit cert
1047
   std::unique_ptr<IPAddressBlocks> inherit_blocks = std::make_unique<IPAddressBlocks>();
1✔
1048

1049
   inherit_blocks->inherit<IPv4>(42);
1✔
1050
   inherit_blocks->inherit<IPv6>();
1✔
1051

1052
   // Subject cert
1053
   std::unique_ptr<IPAddressBlocks> sub_blocks = std::make_unique<IPAddressBlocks>();
1✔
1054

1055
   sub_blocks->add_address<IPv4>({124, 0, 255, 0}, {126, 0, 0, 1}, 42);
1✔
1056
   sub_blocks->add_address<IPv4>({10, 0, 2, 1}, {10, 42, 0, 255}, 42);
1✔
1057

1058
   sub_blocks->add_address<IPv6>(
1✔
1059
      {0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
1060
      {0x0D, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
1061

1062
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
1✔
1063
      make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
2✔
1064
   auto [inherit_cert, inherit_ca] = make_and_sign_ca(std::move(inherit_blocks), root_ca, *rng);
2✔
1065

1066
   Botan::Certificate_Store_In_Memory trusted;
1✔
1067
   trusted.add_certificate(root_cert);
1✔
1068

1069
   for(size_t i = 0; i < 4; i++) {
5✔
1070
      bool include_v4 = bit_set<0>(i);
4✔
1071
      bool include_v6 = bit_set<1>(i);
4✔
1072

1073
      // Dynamic Cert
1074
      std::unique_ptr<IPAddressBlocks> dyn_blocks = std::make_unique<IPAddressBlocks>();
4✔
1075
      if(include_v4) {
4✔
1076
         dyn_blocks->add_address<IPv4>({122, 0, 0, 255}, {128, 255, 255, 255}, 42);
2✔
1077
         dyn_blocks->add_address<IPv4>({10, 0, 0, 255}, {10, 255, 0, 1}, 42);
2✔
1078
      } else {
1079
         dyn_blocks->inherit<IPv4>(42);
2✔
1080
      }
1081

1082
      if(include_v6) {
4✔
1083
         dyn_blocks->add_address<IPv6>(
2✔
1084
            {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1085
            {0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
1086
      } else {
1087
         dyn_blocks->inherit<IPv6>();
2✔
1088
      }
1089

1090
      auto [dyn_cert, dyn_ca] = make_and_sign_ca(std::move(dyn_blocks), inherit_ca, *rng);
8✔
1091

1092
      const auto sub_req = user_params().add_extension(sub_blocks->copy()).into_pkcs10_request(*sub_key, *rng, hash_fn);
4✔
1093

1094
      const auto sub_cert = dyn_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
4✔
1095

1096
      const Botan::Path_Validation_Restrictions restrictions(false, 80);
8✔
1097
      std::vector<Botan::X509_Certificate> certs = {sub_cert, dyn_cert, inherit_cert};
16✔
1098

1099
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
4✔
1100
      result.require("path validation succeeds", path_result.successful_validation());
4✔
1101
   }
8✔
1102

1103
   result.end_timer();
1✔
1104
   return result;
2✔
1105
}
7✔
1106

1107
Test::Result test_x509_ip_addr_blocks_path_validation_success_ctor() {
1✔
1108
   Test::Result result("X509 IP Address Block path validation success (ctor)");
1✔
1109
   result.start_timer();
1✔
1110

1111
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
1112
   auto rng = Test::new_rng(__func__);
1✔
1113

1114
   /*
1115
   Creates a certificate chain of length 4.
1116
   Root: ipv4 and ipv6
1117
   Inherit: has both values as 'inherit'
1118
   Dynamic: has either both 'inherit', both with values, or just one with a value
1119
   Subject: both ipv4 and ipv6 as a subset of Root / Dynamic
1120
   */
1121

1122
   // Root cert
1123
   std::vector<uint8_t> a = {120, 0, 0, 1};
1✔
1124
   auto root_ipv4_range_1_min = IPAddressBlocks::IPAddress<IPv4>{a};
1✔
1125
   a = {130, 140, 150, 160};
1✔
1126
   auto root_ipv4_range_1_max = IPAddressBlocks::IPAddress<IPv4>{a};
1✔
1127

1128
   a = {10, 0, 0, 1};
1✔
1129
   auto root_ipv4_range_2_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1130
   a = {10, 255, 255, 255};
1✔
1131
   auto root_ipv4_range_2_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1132

1133
   a = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1134
   auto root_ipv6_range_1_min = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1135
   a = {0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1✔
1136
   auto root_ipv6_range_1_max = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1137

1138
   a = {0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1139
   auto root_ipv6_range_2_min = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1140
   a = {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1✔
1141
   auto root_ipv6_range_2_max = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1142

1143
   auto root_ipv4_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(root_ipv4_range_1_min, root_ipv4_range_1_max);
1✔
1144
   auto root_ipv4_range_2 = IPAddressBlocks::IPAddressOrRange<IPv4>(root_ipv4_range_2_min, root_ipv4_range_2_max);
1✔
1145
   auto root_ipv6_range_1 = IPAddressBlocks::IPAddressOrRange<IPv6>(root_ipv6_range_1_min, root_ipv6_range_1_max);
1✔
1146
   auto root_ipv6_range_2 = IPAddressBlocks::IPAddressOrRange<IPv6>(root_ipv6_range_2_min, root_ipv6_range_2_max);
1✔
1147

1148
   auto root_ipv4_ranges = {root_ipv4_range_1, root_ipv4_range_2};
1✔
1149
   auto root_ipv6_ranges = {root_ipv6_range_1, root_ipv6_range_2};
1✔
1150

1151
   auto root_ipv4_choice = IPAddressBlocks::IPAddressChoice<IPv4>(root_ipv4_ranges);
1✔
1152
   auto root_ipv6_choice = IPAddressBlocks::IPAddressChoice<IPv6>(root_ipv6_ranges);
1✔
1153

1154
   auto root_ipv4_family = IPAddressBlocks::IPAddressFamily(root_ipv4_choice, 42);
3✔
1155
   auto root_ipv6_family = IPAddressBlocks::IPAddressFamily(root_ipv6_choice);
3✔
1156

1157
   auto root_addr_blocks = {root_ipv4_family, root_ipv6_family};
6✔
1158
   std::unique_ptr<IPAddressBlocks> root_blocks = std::make_unique<IPAddressBlocks>(root_addr_blocks);
1✔
1159

1160
   // Inherit cert
1161
   auto inherit_ipv4_choice = IPAddressBlocks::IPAddressChoice<IPv4>();
1✔
1162
   auto inherit_ipv6_choice = IPAddressBlocks::IPAddressChoice<IPv6>();
1✔
1163

1164
   auto inherit_ipv4_family = IPAddressBlocks::IPAddressFamily(inherit_ipv4_choice, 42);
2✔
1165
   auto inherit_ipv6_family = IPAddressBlocks::IPAddressFamily(inherit_ipv6_choice);
2✔
1166

1167
   auto inherit_addr_blocks = {inherit_ipv4_family, inherit_ipv6_family};
6✔
1168
   std::unique_ptr<IPAddressBlocks> inherit_blocks = std::make_unique<IPAddressBlocks>(inherit_addr_blocks);
1✔
1169

1170
   // Dynamic Cert
1171
   a = {122, 0, 0, 255};
1✔
1172
   auto dyn_ipv4_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1173
   a = {128, 255, 255, 255};
1✔
1174
   auto dyn_ipv4_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1175
   a = {10, 0, 0, 255};
1✔
1176
   auto dyn_ipv4_range_2_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1177
   a = {10, 255, 0, 1};
1✔
1178
   auto dyn_ipv4_range_2_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1179

1180
   a = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1✔
1181
   auto dyn_ipv6_range_1_min = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1182
   a = {0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1183
   auto dyn_ipv6_range_1_max = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1184

1185
   auto dyn_ipv4_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(dyn_ipv4_range_1_min, dyn_ipv4_range_1_max);
1✔
1186
   auto dyn_ipv4_range_2 = IPAddressBlocks::IPAddressOrRange<IPv4>(dyn_ipv4_range_2_min, dyn_ipv4_range_2_max);
1✔
1187
   auto dyn_ipv6_range = IPAddressBlocks::IPAddressOrRange<IPv6>(dyn_ipv6_range_1_min, dyn_ipv6_range_1_max);
1✔
1188

1189
   auto dyn_ipv4_ranges = {dyn_ipv4_range_1, dyn_ipv4_range_2};
1✔
1190
   auto dyn_ipv6_ranges = {dyn_ipv6_range};
1✔
1191

1192
   // Subject cert
1193
   a = {124, 0, 255, 0};
1✔
1194
   auto sub_ipv4_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1195
   a = {126, 0, 0, 1};
1✔
1196
   auto sub_ipv4_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1197

1198
   a = {10, 0, 2, 1};
1✔
1199
   auto sub_ipv4_range_2_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1200
   a = {10, 42, 0, 255};
1✔
1201
   auto sub_ipv4_range_2_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1202

1203
   a = {0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1204
   auto sub_ipv6_range_1_min = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1205
   a = {0x0D, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1206
   auto sub_ipv6_range_1_max = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1207

1208
   auto sub_ipv4_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(sub_ipv4_range_1_min, sub_ipv4_range_1_max);
1✔
1209
   auto sub_ipv4_range_2 = IPAddressBlocks::IPAddressOrRange<IPv4>(sub_ipv4_range_2_min, sub_ipv4_range_2_max);
1✔
1210
   auto sub_ipv6_range = IPAddressBlocks::IPAddressOrRange<IPv6>(sub_ipv6_range_1_min, sub_ipv6_range_1_max);
1✔
1211

1212
   auto sub_ipv4_ranges = {sub_ipv4_range_1, sub_ipv4_range_2};
1✔
1213
   auto sub_ipv6_ranges = {sub_ipv6_range};
1✔
1214

1215
   auto sub_ipv4_choice = IPAddressBlocks::IPAddressChoice<IPv4>(sub_ipv4_ranges);
1✔
1216
   auto sub_ipv6_choice = IPAddressBlocks::IPAddressChoice<IPv6>(sub_ipv6_ranges);
1✔
1217

1218
   auto sub_ipv4_family = IPAddressBlocks::IPAddressFamily(sub_ipv4_choice, 42);
3✔
1219
   auto sub_ipv6_family = IPAddressBlocks::IPAddressFamily(sub_ipv6_choice);
3✔
1220

1221
   auto sub_addr_blocks = {sub_ipv4_family, sub_ipv6_family};
6✔
1222
   std::unique_ptr<IPAddressBlocks> sub_blocks = std::make_unique<IPAddressBlocks>(sub_addr_blocks);
1✔
1223

1224
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
1✔
1225
      make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
2✔
1226
   auto [inherit_cert, inherit_ca] = make_and_sign_ca(std::move(inherit_blocks), root_ca, *rng);
2✔
1227

1228
   Botan::Certificate_Store_In_Memory trusted;
1✔
1229
   trusted.add_certificate(root_cert);
1✔
1230

1231
   for(size_t i = 0; i < 4; i++) {
5✔
1232
      bool include_v4 = bit_set<0>(i);
4✔
1233
      bool include_v6 = bit_set<1>(i);
4✔
1234

1235
      auto dyn_ipv4_choice =
4✔
1236
         IPAddressBlocks::IPAddressChoice<IPv4>(include_v4 ? std::optional(dyn_ipv4_ranges) : std::nullopt);
8✔
1237
      auto dyn_ipv6_choice =
4✔
1238
         IPAddressBlocks::IPAddressChoice<IPv6>(include_v6 ? std::optional(dyn_ipv6_ranges) : std::nullopt);
8✔
1239

1240
      auto dyn_ipv4_family = IPAddressBlocks::IPAddressFamily(dyn_ipv4_choice, 42);
10✔
1241
      auto dyn_ipv6_family = IPAddressBlocks::IPAddressFamily(dyn_ipv6_choice);
10✔
1242

1243
      auto dyn_addr_blocks = {dyn_ipv4_family, dyn_ipv6_family};
24✔
1244
      std::unique_ptr<IPAddressBlocks> dyn_blocks = std::make_unique<IPAddressBlocks>(dyn_addr_blocks);
4✔
1245

1246
      auto [dyn_cert, dyn_ca] = make_and_sign_ca(std::move(dyn_blocks), inherit_ca, *rng);
8✔
1247

1248
      const auto sub_req = user_params().add_extension(sub_blocks->copy()).into_pkcs10_request(*sub_key, *rng, hash_fn);
4✔
1249
      const auto sub_cert = dyn_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
4✔
1250

1251
      const Botan::Path_Validation_Restrictions restrictions(false, 80);
8✔
1252
      std::vector<Botan::X509_Certificate> certs = {sub_cert, dyn_cert, inherit_cert};
16✔
1253

1254
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
4✔
1255
      result.require("path validation succeeds", path_result.successful_validation());
4✔
1256
   }
28✔
1257

1258
   result.end_timer();
1✔
1259
   return result;
2✔
1260
}
25✔
1261

1262
Test::Result test_x509_ip_addr_blocks_path_validation_failure_builder() {
1✔
1263
   Test::Result result("X509 IP Address Blocks path validation failure (builder)");
1✔
1264
   result.start_timer();
1✔
1265

1266
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
1267
   auto rng = Test::new_rng(__func__);
1✔
1268

1269
   for(size_t i = 0; i < 7; i++) {
8✔
1270
      bool all_inherit = (i == 0);
7✔
1271
      bool different_safi = (i == 1);
7✔
1272
      bool too_small_subrange = (i == 2);
7✔
1273
      bool too_large_subrange = (i == 3);
7✔
1274
      bool no_more_issuer_ranges = (i == 4);
7✔
1275
      bool empty_issuer_ranges = (i == 5);
7✔
1276
      bool nullptr_extensions = (i == 6);
7✔
1277

1278
      // Root cert
1279
      std::unique_ptr<IPAddressBlocks> root_blocks = std::make_unique<IPAddressBlocks>();
7✔
1280
      if(!all_inherit) {
7✔
1281
         root_blocks->add_address<IPv4>({120, 0, 0, 1}, {130, 140, 150, 160}, 42);
6✔
1282
      } else {
1283
         root_blocks->inherit<IPv4>(42);
1✔
1284
      }
1285

1286
      auto root_params = ca_params();
7✔
1287
      if(!nullptr_extensions) {
7✔
1288
         root_params.add_extension(std::move(root_blocks));
12✔
1289
      }
1290
      auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] = make_ca(*rng, root_params);
7✔
1291

1292
      // Issuer Cert
1293
      std::unique_ptr<IPAddressBlocks> iss_blocks = std::make_unique<IPAddressBlocks>();
7✔
1294
      if(!all_inherit) {
7✔
1295
         if(empty_issuer_ranges) {
6✔
1296
            iss_blocks->restrict<IPv4>(42);
1✔
1297
         } else {
1298
            iss_blocks->add_address<IPv4>({122, 0, 0, 255}, {128, 255, 255, 255}, 42);
5✔
1299
         }
1300
      } else {
1301
         iss_blocks->inherit<IPv4>(42);
1✔
1302
      }
1303

1304
      auto [iss_cert, iss_ca] = make_and_sign_ca(std::move(iss_blocks), root_ca, *rng);
14✔
1305

1306
      // Subject cert
1307
      std::unique_ptr<IPAddressBlocks> sub_blocks = std::make_unique<IPAddressBlocks>();
7✔
1308

1309
      uint8_t safi = different_safi ? 41 : 42;
7✔
1310

1311
      if(!all_inherit) {
7✔
1312
         if(too_small_subrange) {
6✔
1313
            sub_blocks->add_address<IPv4>({118, 0, 255, 0}, {126, 0, 0, 1}, safi);
1✔
1314
         } else if(too_large_subrange) {
5✔
1315
            sub_blocks->add_address<IPv4>({124, 0, 255, 0}, {134, 0, 0, 1}, safi);
1✔
1316
         } else if(no_more_issuer_ranges) {
4✔
1317
            sub_blocks->add_address<IPv4>({140, 0, 0, 1}, {150, 0, 0, 1}, safi);
1✔
1318
         } else {
1319
            sub_blocks->add_address<IPv4>({124, 0, 255, 0}, {126, 0, 0, 1}, safi);
3✔
1320
         }
1321
      } else {
1322
         sub_blocks->inherit<IPv4>(safi);
1✔
1323
      }
1324

1325
      auto sub_req = user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
7✔
1326
      Botan::X509_Certificate sub_cert =
7✔
1327
         iss_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
7✔
1328

1329
      const Botan::Path_Validation_Restrictions restrictions(false, 80);
14✔
1330
      std::vector<Botan::X509_Certificate> certs = {sub_cert, iss_cert};
21✔
1331

1332
      Botan::Certificate_Store_In_Memory trusted;
7✔
1333
      trusted.add_certificate(root_cert);
7✔
1334

1335
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
7✔
1336
      result.require("path validation fails", !path_result.successful_validation());
7✔
1337
   }
15✔
1338

1339
   result.end_timer();
1✔
1340
   return result;
1✔
1341
}
8✔
1342

1343
Test::Result test_x509_ip_addr_blocks_path_validation_failure_ctor() {
1✔
1344
   Test::Result result("X509 IP Address Block path validation failure (ctor)");
1✔
1345
   result.start_timer();
1✔
1346

1347
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
1348
   auto rng = Test::new_rng(__func__);
1✔
1349

1350
   for(size_t i = 0; i < 7; i++) {
8✔
1351
      bool all_inherit = (i == 0);
7✔
1352
      bool different_safi = (i == 1);
7✔
1353
      bool too_small_subrange = (i == 2);
7✔
1354
      bool too_large_subrange = (i == 3);
7✔
1355
      bool no_more_issuer_ranges = (i == 4);
7✔
1356
      bool empty_issuer_ranges = (i == 5);
7✔
1357
      bool nullptr_extensions = (i == 6);
7✔
1358

1359
      // Root cert
1360
      std::vector<uint8_t> a = {120, 0, 0, 1};
7✔
1361
      auto root_range_1_min = IPAddressBlocks::IPAddress<IPv4>{a};
7✔
1362
      a = {130, 140, 150, 160};
7✔
1363
      auto root_range_1_max = IPAddressBlocks::IPAddress<IPv4>{a};
7✔
1364

1365
      auto root_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(root_range_1_min, root_range_1_max);
7✔
1366
      auto root_ranges = {root_range_1};
7✔
1367
      auto root_choice =
7✔
1368
         IPAddressBlocks::IPAddressChoice<IPv4>(all_inherit ? std::nullopt : std::optional(root_ranges));
14✔
1369
      auto root_family = IPAddressBlocks::IPAddressFamily(root_choice, 42);
20✔
1370
      auto root_addr_blocks = {root_family};
21✔
1371
      std::unique_ptr<IPAddressBlocks> root_blocks = std::make_unique<IPAddressBlocks>(root_addr_blocks);
7✔
1372

1373
      auto root_params = ca_params();
7✔
1374
      if(!nullptr_extensions) {
7✔
1375
         root_params.add_extension(std::move(root_blocks));
12✔
1376
      }
1377
      auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] = make_ca(*rng, root_params);
7✔
1378

1379
      // Issuer Cert
1380
      a = {122, 0, 0, 255};
7✔
1381
      auto iss_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
7✔
1382
      a = {128, 255, 255, 255};
7✔
1383
      auto iss_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
7✔
1384
      auto iss_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(iss_range_1_min, iss_range_1_max);
7✔
1385

1386
      std::vector<IPAddressBlocks::IPAddressOrRange<IPv4>> iss_ranges;
7✔
1387

1388
      if(!empty_issuer_ranges) {
7✔
1389
         iss_ranges.push_back(iss_range_1);
6✔
1390
      }
1391

1392
      auto iss_choice = IPAddressBlocks::IPAddressChoice<IPv4>(all_inherit ? std::nullopt : std::optional(iss_ranges));
19✔
1393
      auto iss_family = IPAddressBlocks::IPAddressFamily(iss_choice, 42);
20✔
1394
      auto iss_addr_blocks = {iss_family};
21✔
1395
      std::unique_ptr<IPAddressBlocks> iss_blocks = std::make_unique<IPAddressBlocks>(iss_addr_blocks);
7✔
1396
      auto [iss_cert, iss_ca] = make_and_sign_ca(std::move(iss_blocks), root_ca, *rng);
14✔
1397

1398
      // Subject cert
1399
      if(too_small_subrange) {
7✔
1400
         a = {118, 0, 255, 0};
2✔
1401
      } else if(no_more_issuer_ranges) {
6✔
1402
         a = {140, 0, 0, 1};
2✔
1403
      } else {
1404
         a = {124, 0, 255, 0};
10✔
1405
      }
1406

1407
      auto sub_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
7✔
1408
      if(too_large_subrange) {
7✔
1409
         a = {134, 0, 0, 1};
2✔
1410
      } else if(no_more_issuer_ranges) {
6✔
1411
         a = {150, 0, 0, 1};
2✔
1412
      } else {
1413
         a = {126, 0, 0, 1};
10✔
1414
      }
1415
      auto sub_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
7✔
1416

1417
      auto sub_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(sub_range_1_min, sub_range_1_max);
7✔
1418
      auto sub_ranges = {sub_range_1};
7✔
1419
      auto sub_choice = IPAddressBlocks::IPAddressChoice<IPv4>(all_inherit ? std::nullopt : std::optional(sub_ranges));
14✔
1420
      auto sub_family = IPAddressBlocks::IPAddressFamily(sub_choice, different_safi ? 41 : 42);
26✔
1421

1422
      auto sub_addr_blocks = {sub_family};
21✔
1423
      std::unique_ptr<IPAddressBlocks> sub_blocks = std::make_unique<IPAddressBlocks>(sub_addr_blocks);
7✔
1424

1425
      auto sub_req = user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
7✔
1426
      Botan::X509_Certificate sub_cert =
7✔
1427
         iss_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
7✔
1428

1429
      const Botan::Path_Validation_Restrictions restrictions(false, 80);
14✔
1430
      std::vector<Botan::X509_Certificate> certs = {sub_cert, iss_cert};
21✔
1431

1432
      Botan::Certificate_Store_In_Memory trusted;
7✔
1433
      trusted.add_certificate(root_cert);
7✔
1434

1435
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
7✔
1436
      result.require("path validation fails", !path_result.successful_validation());
7✔
1437
   }
82✔
1438

1439
   result.end_timer();
1✔
1440
   return result;
1✔
1441
}
8✔
1442

1443
Test::Result test_x509_as_blocks_rfc3779_example() {
1✔
1444
   Test::Result result("X509 AS Blocks rfc3779 example");
1✔
1445
   result.start_timer();
1✔
1446

1447
   using Botan::Cert_Extension::ASBlocks;
1✔
1448
   auto rng = Test::new_rng(__func__);
1✔
1449

1450
   // construct like in https://datatracker.ietf.org/doc/html/rfc3779#page-21
1451
   std::unique_ptr<ASBlocks> blocks = std::make_unique<ASBlocks>();
1✔
1452
   blocks->add_asnum(135);
1✔
1453
   blocks->add_asnum(3000, 3999);
1✔
1454
   blocks->add_asnum(5001);
1✔
1455
   blocks->inherit_rdi();
1✔
1456

1457
   auto cert = make_self_signed(*rng, ca_params().add_extension(std::move(blocks)));
2✔
1458
   auto bits = cert.v3_extensions().get_extension_bits(ASBlocks::static_oid());
1✔
1459

1460
   result.test_eq(
1✔
1461
      "extension is encoded as specified", bits, "301AA014301202020087300802020BB802020F9F02021389A1020500");
1462

1463
   auto as_idents = cert.v3_extensions().get_extension_object_as<ASBlocks>()->as_identifiers();
1✔
1464
   auto as_ids = as_idents.asnum().value().ranges().value();
1✔
1465

1466
   result.confirm("extension has correct data", as_ids[0].min() == 135);
2✔
1467

1468
   result.end_timer();
1✔
1469
   return result;
2✔
1470
}
3✔
1471

1472
Test::Result test_x509_as_blocks_encode_builder() {
1✔
1473
   Test::Result result("X509 IP Address Blocks encode (builder)");
1✔
1474
   result.start_timer();
1✔
1475

1476
   using Botan::Cert_Extension::ASBlocks;
1✔
1477
   auto rng = Test::new_rng(__func__);
1✔
1478

1479
   std::unique_ptr<ASBlocks> blocks = std::make_unique<ASBlocks>();
1✔
1480

1481
   blocks->add_rdi(10);
1✔
1482
   blocks->add_rdi(20, 30);
1✔
1483
   blocks->add_rdi(42, 300);
1✔
1484
   blocks->add_rdi(9, 301);
1✔
1485

1486
   blocks->inherit_asnum();
1✔
1487
   blocks->add_asnum(20);
1✔
1488
   // this overwrites the previous two
1489
   blocks->restrict_asnum();
1✔
1490

1491
   auto cert = make_self_signed(*rng, ca_params().add_extension(std::move(blocks)));
2✔
1492
   auto bits = cert.v3_extensions().get_extension_bits(ASBlocks::static_oid());
1✔
1493

1494
   result.test_eq("extension is encoded as specified", bits, "3011A0023000A10B300930070201090202012D");
1✔
1495

1496
   result.end_timer();
1✔
1497
   return result;
1✔
1498
}
2✔
1499

1500
Test::Result test_x509_as_blocks_extension_encode_ctor() {
1✔
1501
   Test::Result result("X509 AS Blocks encode (ctor)");
1✔
1502
   result.start_timer();
1✔
1503

1504
   using Botan::Cert_Extension::ASBlocks;
1✔
1505

1506
   auto rng = Test::new_rng(__func__);
1✔
1507

1508
   auto [ca_cert, ca, sub_key, sig_algo, hash_fn] = make_ca(*rng);
1✔
1509

1510
   for(size_t i = 0; i < 16; i++) {
17✔
1511
      bool push_asnum = bit_set<0>(i);
16✔
1512
      bool push_rdi = bit_set<1>(i);
16✔
1513
      bool include_asnum = bit_set<2>(i);
16✔
1514
      bool include_rdi = bit_set<3>(i);
16✔
1515
      if(!include_asnum && !include_rdi) {
16✔
1516
         continue;
4✔
1517
      }
1518

1519
      ASBlocks::ASIdOrRange asnum_id_or_range0 = ASBlocks::ASIdOrRange(0, 999);
12✔
1520
      ASBlocks::ASIdOrRange asnum_id_or_range1 = ASBlocks::ASIdOrRange(5042);
12✔
1521
      ASBlocks::ASIdOrRange asnum_id_or_range2 = ASBlocks::ASIdOrRange(5043, 4294967295);
12✔
1522

1523
      ASBlocks::ASIdOrRange rdi_id_or_range0 = ASBlocks::ASIdOrRange(1234, 5678);
12✔
1524
      ASBlocks::ASIdOrRange rdi_id_or_range1 = ASBlocks::ASIdOrRange(32768);
12✔
1525
      ASBlocks::ASIdOrRange rdi_id_or_range2 = ASBlocks::ASIdOrRange(32769, 4294967295);
12✔
1526

1527
      std::vector<ASBlocks::ASIdOrRange> as_ranges;
12✔
1528
      if(push_asnum) {
12✔
1529
         as_ranges.push_back(asnum_id_or_range0);
6✔
1530
         as_ranges.push_back(asnum_id_or_range1);
6✔
1531
         as_ranges.push_back(asnum_id_or_range2);
6✔
1532
      }
1533

1534
      std::vector<ASBlocks::ASIdOrRange> rdi_ranges;
12✔
1535
      if(push_rdi) {
12✔
1536
         rdi_ranges.push_back(rdi_id_or_range0);
6✔
1537
         rdi_ranges.push_back(rdi_id_or_range1);
6✔
1538
         rdi_ranges.push_back(rdi_id_or_range2);
6✔
1539
      }
1540

1541
      ASBlocks::ASIdentifierChoice asnum = ASBlocks::ASIdentifierChoice(as_ranges);
12✔
1542
      ASBlocks::ASIdentifierChoice rdi = ASBlocks::ASIdentifierChoice(rdi_ranges);
12✔
1543

1544
      ASBlocks::ASIdentifiers ident = ASBlocks::ASIdentifiers(include_asnum ? std::optional(asnum) : std::nullopt,
32✔
1545
                                                              include_rdi ? std::optional(rdi) : std::nullopt);
32✔
1546

1547
      std::unique_ptr<ASBlocks> blocks = std::make_unique<ASBlocks>(ident);
12✔
1548

1549
      auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
12✔
1550
      Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
12✔
1551

1552
      {
12✔
1553
         const auto* as_blocks = cert.v3_extensions().get_extension_object_as<ASBlocks>();
12✔
1554
         result.confirm("cert has ASBlock extension", as_blocks != nullptr, true);
24✔
1555

1556
         const auto& identifier = as_blocks->as_identifiers();
12✔
1557

1558
         if(include_asnum) {
12✔
1559
            const auto& asnum_entries = identifier.asnum().value().ranges().value();
8✔
1560

1561
            if(push_asnum) {
8✔
1562
               result.confirm("asnum entry 0 min", asnum_entries[0].min() == 0, true);
8✔
1563
               result.confirm("asnum entry 0 max", asnum_entries[0].max() == 999, true);
8✔
1564

1565
               result.confirm("asnum entry 1 min", asnum_entries[1].min() == 5042, true);
8✔
1566
               result.confirm("asnum entry 1 max", asnum_entries[1].max() == 4294967295, true);
8✔
1567
            } else {
1568
               result.confirm("asnum has no entries", asnum_entries.empty(), true);
8✔
1569
            }
1570
         } else {
1571
            result.confirm("no asnum entry", identifier.asnum().has_value(), false);
8✔
1572
         }
1573

1574
         if(include_rdi) {
12✔
1575
            const auto& rdi_entries = identifier.rdi().value().ranges().value();
8✔
1576

1577
            if(push_rdi) {
8✔
1578
               result.confirm("rdi entry 0 min", rdi_entries[0].min() == 1234, true);
8✔
1579
               result.confirm("rdi entry 0 max", rdi_entries[0].max() == 5678, true);
8✔
1580

1581
               result.confirm("rdi entry 1 min", rdi_entries[1].min() == 32768, true);
8✔
1582
               result.confirm("rdi entry 1 max", rdi_entries[1].max() == 4294967295, true);
8✔
1583
            } else {
1584
               result.confirm("rdi has no entries", rdi_entries.empty(), true);
8✔
1585
            }
1586
         } else {
1587
            result.confirm("rdi has no entry", identifier.rdi().has_value(), false);
8✔
1588
         }
1589
      }
1590
   }
36✔
1591

1592
   result.end_timer();
1✔
1593
   return result;
2✔
1594
}
2✔
1595

1596
Test::Result test_x509_as_blocks_range_merge() {
1✔
1597
   Test::Result result("X509 AS Block range merge");
1✔
1598
   result.start_timer();
1✔
1599

1600
   using Botan::Cert_Extension::ASBlocks;
1✔
1601

1602
   auto rng = Test::new_rng(__func__);
1✔
1603

1604
   auto [ca_cert, ca, sub_key, sig_algo, hash_fn] = make_ca(*rng);
1✔
1605

1606
   std::vector<std::vector<uint16_t>> ranges = {
1✔
1607
      {2005, 37005},
1608
      {60, 70},
1609
      {22, 50},
1610
      {35, 2000},
1611
      {2001, 2004},
1612
      {21, 21},
1613
      {0, 20},
1614
   };
9✔
1615

1616
   std::vector<ASBlocks::ASIdOrRange> as_ranges;
1✔
1617
   for(auto pair : ranges) {
8✔
1618
      auto range = ASBlocks::ASIdOrRange(pair[0], pair[1]);
7✔
1619
      as_ranges.push_back(range);
7✔
1620
   }
7✔
1621

1622
   ASBlocks::ASIdentifierChoice asnum = ASBlocks::ASIdentifierChoice(as_ranges);
1✔
1623

1624
   ASBlocks::ASIdentifiers ident = ASBlocks::ASIdentifiers(std::optional(asnum), std::nullopt);
3✔
1625

1626
   std::unique_ptr<ASBlocks> blocks = std::make_unique<ASBlocks>(ident);
1✔
1627

1628
   const auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1✔
1629
   Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1✔
1630
   {
1✔
1631
      const auto* as_blocks = cert.v3_extensions().get_extension_object_as<ASBlocks>();
1✔
1632
      result.confirm("cert has ASBlock extension", as_blocks != nullptr, true);
2✔
1633

1634
      const auto& identifier = as_blocks->as_identifiers();
1✔
1635

1636
      const auto& asnum_entries = identifier.asnum().value().ranges().value();
1✔
1637

1638
      result.confirm("asnum entry 0 min", asnum_entries[0].min() == 0, true);
2✔
1639
      result.confirm("asnum entry 0 max", asnum_entries[0].max() == 37005, true);
2✔
1640
      result.confirm("asnum length", asnum_entries.size() == 1, true);
2✔
1641
   }
1642

1643
   result.end_timer();
1✔
1644
   return result;
2✔
1645
}
5✔
1646

1647
Test::Result test_x509_as_blocks_path_validation_success_builder() {
1✔
1648
   Test::Result result("X509 AS Block path validation success (builder)");
1✔
1649
   result.start_timer();
1✔
1650

1651
   using Botan::Cert_Extension::ASBlocks;
1✔
1652
   auto rng = Test::new_rng(__func__);
1✔
1653

1654
   /*
1655
   Creates a certificate chain of length 4.
1656
   Root: both asnum and rdi
1657
   Inherit: has both values as 'inherit'
1658
   Dynamic: has either both 'inherit', both with values, or just one with a value
1659
   Subject: both asnum and rdi as a subset of Root / Dynamic
1660
   */
1661

1662
   // Root Cert, both as and rdi
1663

1664
   std::unique_ptr<ASBlocks> root_blocks = std::make_unique<ASBlocks>();
1✔
1665

1666
   root_blocks->add_asnum(0, 999);
1✔
1667
   root_blocks->add_asnum(5042);
1✔
1668
   root_blocks->add_asnum(5043, 4294967295);
1✔
1669

1670
   root_blocks->add_rdi(1234, 5678);
1✔
1671
   root_blocks->add_rdi(32768);
1✔
1672
   root_blocks->add_rdi(32769, 4294967295);
1✔
1673

1674
   // Inherit cert, both as 'inherit'
1675
   std::unique_ptr<ASBlocks> inherit_blocks = std::make_unique<ASBlocks>();
1✔
1676
   inherit_blocks->inherit_asnum();
1✔
1677
   inherit_blocks->inherit_rdi();
1✔
1678

1679
   // Subject cert
1680

1681
   std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>();
1✔
1682

1683
   sub_blocks->add_asnum(120, 180);
1✔
1684
   sub_blocks->add_asnum(220, 240);
1✔
1685
   sub_blocks->add_asnum(260, 511);
1✔
1686
   sub_blocks->add_asnum(678);
1✔
1687
   sub_blocks->add_asnum(5043, 5100);
1✔
1688

1689
   sub_blocks->add_rdi(1500, 2300);
1✔
1690
   sub_blocks->add_rdi(2500, 4000);
1✔
1691
   sub_blocks->add_rdi(1567);
1✔
1692
   sub_blocks->add_rdi(33100, 40000);
1✔
1693

1694
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
1✔
1695
      make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
2✔
1696
   auto [inherit_cert, inherit_ca] = make_and_sign_ca(std::move(inherit_blocks), root_ca, *rng);
2✔
1697

1698
   Botan::Certificate_Store_In_Memory trusted;
1✔
1699
   trusted.add_certificate(root_cert);
1✔
1700

1701
   for(size_t i = 0; i < 4; i++) {
5✔
1702
      bool include_asnum = bit_set<0>(i);
4✔
1703
      bool include_rdi = bit_set<1>(i);
4✔
1704

1705
      std::unique_ptr<ASBlocks> dyn_blocks = std::make_unique<ASBlocks>();
4✔
1706
      if(include_asnum) {
4✔
1707
         dyn_blocks->add_asnum(100, 600);
2✔
1708
         dyn_blocks->add_asnum(678);
2✔
1709
         dyn_blocks->add_asnum(5042, 5101);
2✔
1710
      } else {
1711
         dyn_blocks->inherit_asnum();
2✔
1712
      }
1713

1714
      if(include_rdi) {
4✔
1715
         dyn_blocks->add_rdi(1500, 5000);
2✔
1716
         dyn_blocks->add_rdi(33000, 60000);
2✔
1717
      } else {
1718
         dyn_blocks->inherit_rdi();
2✔
1719
      }
1720

1721
      auto [dyn_cert, dyn_ca] = make_and_sign_ca(std::move(dyn_blocks), inherit_ca, *rng);
8✔
1722

1723
      const auto sub_req = user_params().add_extension(sub_blocks->copy()).into_pkcs10_request(*sub_key, *rng, hash_fn);
4✔
1724
      Botan::X509_Certificate sub_cert =
4✔
1725
         dyn_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
4✔
1726

1727
      const Botan::Path_Validation_Restrictions restrictions(false, 80);
8✔
1728
      std::vector<Botan::X509_Certificate> certs = {sub_cert, dyn_cert, inherit_cert};
16✔
1729

1730
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
4✔
1731
      result.require("path validation succeeds", path_result.successful_validation());
4✔
1732
   }
8✔
1733

1734
   result.end_timer();
1✔
1735
   return result;
2✔
1736
}
7✔
1737

1738
Test::Result test_x509_as_blocks_path_validation_success_ctor() {
1✔
1739
   Test::Result result("X509 AS Block path validation success (ctor)");
1✔
1740
   result.start_timer();
1✔
1741

1742
   using Botan::Cert_Extension::ASBlocks;
1✔
1743
   auto rng = Test::new_rng(__func__);
1✔
1744

1745
   /*
1746
   Creates a certificate chain of length 4.
1747
   Root: both asnum and rdi
1748
   Inherit: has both values as 'inherit'
1749
   Dynamic: has either both 'inherit', both with values, or just one with a value
1750
   Subject: both asnum and rdi as a subset of Root / Dynamic
1751
   */
1752

1753
   // Root Cert, both as and rdi
1754
   ASBlocks::ASIdOrRange root_asnum_id_or_range0 = ASBlocks::ASIdOrRange(0, 999);
1✔
1755
   ASBlocks::ASIdOrRange root_asnum_id_or_range1 = ASBlocks::ASIdOrRange(5042);
1✔
1756
   ASBlocks::ASIdOrRange root_asnum_id_or_range2 = ASBlocks::ASIdOrRange(5043, 4294967295);
1✔
1757

1758
   ASBlocks::ASIdOrRange root_rdi_id_or_range0 = ASBlocks::ASIdOrRange(1234, 5678);
1✔
1759
   ASBlocks::ASIdOrRange root_rdi_id_or_range1 = ASBlocks::ASIdOrRange(32768);
1✔
1760
   ASBlocks::ASIdOrRange root_rdi_id_or_range2 = ASBlocks::ASIdOrRange(32769, 4294967295);
1✔
1761

1762
   std::vector<ASBlocks::ASIdOrRange> root_as_ranges;
1✔
1763
   root_as_ranges.push_back(root_asnum_id_or_range0);
1✔
1764
   root_as_ranges.push_back(root_asnum_id_or_range1);
1✔
1765
   root_as_ranges.push_back(root_asnum_id_or_range2);
1✔
1766

1767
   std::vector<ASBlocks::ASIdOrRange> root_rdi_ranges;
1✔
1768
   root_rdi_ranges.push_back(root_rdi_id_or_range0);
1✔
1769
   root_rdi_ranges.push_back(root_rdi_id_or_range1);
1✔
1770
   root_rdi_ranges.push_back(root_rdi_id_or_range2);
1✔
1771

1772
   ASBlocks::ASIdentifierChoice root_asnum = ASBlocks::ASIdentifierChoice(root_as_ranges);
1✔
1773
   ASBlocks::ASIdentifierChoice root_rdi = ASBlocks::ASIdentifierChoice(root_rdi_ranges);
1✔
1774
   ASBlocks::ASIdentifiers root_ident = ASBlocks::ASIdentifiers(root_asnum, root_rdi);
4✔
1775
   std::unique_ptr<ASBlocks> root_blocks = std::make_unique<ASBlocks>(root_ident);
1✔
1776

1777
   // Inherit cert, both as 'inherit'
1778
   ASBlocks::ASIdentifierChoice inherit_asnum = ASBlocks::ASIdentifierChoice();
1✔
1779
   ASBlocks::ASIdentifierChoice inherit_rdi = ASBlocks::ASIdentifierChoice();
1✔
1780
   ASBlocks::ASIdentifiers inherit_ident = ASBlocks::ASIdentifiers(inherit_asnum, inherit_rdi);
2✔
1781
   std::unique_ptr<ASBlocks> inherit_blocks = std::make_unique<ASBlocks>(inherit_ident);
1✔
1782

1783
   // Dynamic cert
1784
   ASBlocks::ASIdOrRange dyn_asnum_id_or_range0 = ASBlocks::ASIdOrRange(100, 600);
1✔
1785
   ASBlocks::ASIdOrRange dyn_asnum_id_or_range1 = ASBlocks::ASIdOrRange(678);
1✔
1786
   ASBlocks::ASIdOrRange dyn_asnum_id_or_range2 = ASBlocks::ASIdOrRange(5042, 5101);
1✔
1787

1788
   ASBlocks::ASIdOrRange dyn_rdi_id_or_range0 = ASBlocks::ASIdOrRange(1500, 5000);
1✔
1789
   ASBlocks::ASIdOrRange dyn_rdi_id_or_range1 = ASBlocks::ASIdOrRange(33000, 60000);
1✔
1790

1791
   std::vector<ASBlocks::ASIdOrRange> dyn_as_ranges;
1✔
1792
   dyn_as_ranges.push_back(dyn_asnum_id_or_range0);
1✔
1793
   dyn_as_ranges.push_back(dyn_asnum_id_or_range1);
1✔
1794
   dyn_as_ranges.push_back(dyn_asnum_id_or_range2);
1✔
1795

1796
   std::vector<ASBlocks::ASIdOrRange> dyn_rdi_ranges;
1✔
1797
   dyn_rdi_ranges.push_back(dyn_rdi_id_or_range0);
1✔
1798
   dyn_rdi_ranges.push_back(dyn_rdi_id_or_range1);
1✔
1799

1800
   // Subject cert
1801
   ASBlocks::ASIdOrRange sub_asnum_id_or_range0 = ASBlocks::ASIdOrRange(120, 180);
1✔
1802
   ASBlocks::ASIdOrRange sub_asnum_id_or_range1 = ASBlocks::ASIdOrRange(220, 240);
1✔
1803
   ASBlocks::ASIdOrRange sub_asnum_id_or_range2 = ASBlocks::ASIdOrRange(260, 511);
1✔
1804
   ASBlocks::ASIdOrRange sub_asnum_id_or_range3 = ASBlocks::ASIdOrRange(678);
1✔
1805
   ASBlocks::ASIdOrRange sub_asnum_id_or_range4 = ASBlocks::ASIdOrRange(5043, 5100);
1✔
1806

1807
   ASBlocks::ASIdOrRange sub_rdi_id_or_range0 = ASBlocks::ASIdOrRange(1500, 2300);
1✔
1808
   ASBlocks::ASIdOrRange sub_rdi_id_or_range1 = ASBlocks::ASIdOrRange(2500, 4000);
1✔
1809
   ASBlocks::ASIdOrRange sub_rdi_id_or_range2 = ASBlocks::ASIdOrRange(1567);
1✔
1810
   ASBlocks::ASIdOrRange sub_rdi_id_or_range3 = ASBlocks::ASIdOrRange(33100, 40000);
1✔
1811

1812
   std::vector<ASBlocks::ASIdOrRange> sub_as_ranges;
1✔
1813
   sub_as_ranges.push_back(sub_asnum_id_or_range0);
1✔
1814
   sub_as_ranges.push_back(sub_asnum_id_or_range1);
1✔
1815
   sub_as_ranges.push_back(sub_asnum_id_or_range2);
1✔
1816
   sub_as_ranges.push_back(sub_asnum_id_or_range3);
1✔
1817
   sub_as_ranges.push_back(sub_asnum_id_or_range4);
1✔
1818

1819
   std::vector<ASBlocks::ASIdOrRange> sub_rdi_ranges;
1✔
1820
   sub_rdi_ranges.push_back(sub_rdi_id_or_range0);
1✔
1821
   sub_rdi_ranges.push_back(sub_rdi_id_or_range1);
1✔
1822
   sub_rdi_ranges.push_back(sub_rdi_id_or_range2);
1✔
1823
   sub_rdi_ranges.push_back(sub_rdi_id_or_range3);
1✔
1824

1825
   ASBlocks::ASIdentifierChoice sub_asnum = ASBlocks::ASIdentifierChoice(sub_as_ranges);
1✔
1826
   ASBlocks::ASIdentifierChoice sub_rdi = ASBlocks::ASIdentifierChoice(sub_rdi_ranges);
1✔
1827
   ASBlocks::ASIdentifiers sub_ident = ASBlocks::ASIdentifiers(sub_asnum, sub_rdi);
4✔
1828
   std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>(sub_ident);
1✔
1829

1830
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
1✔
1831
      make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
2✔
1832
   auto [inherit_cert, inherit_ca] = make_and_sign_ca(std::move(inherit_blocks), root_ca, *rng);
2✔
1833

1834
   Botan::Certificate_Store_In_Memory trusted;
1✔
1835
   trusted.add_certificate(root_cert);
1✔
1836

1837
   for(size_t i = 0; i < 4; i++) {
5✔
1838
      bool include_asnum = bit_set<0>(i);
4✔
1839
      bool include_rdi = bit_set<1>(i);
4✔
1840

1841
      ASBlocks::ASIdentifierChoice dyn_asnum =
4✔
1842
         ASBlocks::ASIdentifierChoice(include_asnum ? std::optional(dyn_as_ranges) : std::nullopt);
6✔
1843
      ASBlocks::ASIdentifierChoice dyn_rdi =
4✔
1844
         ASBlocks::ASIdentifierChoice(include_rdi ? std::optional(dyn_rdi_ranges) : std::nullopt);
6✔
1845
      ASBlocks::ASIdentifiers dyn_ident = ASBlocks::ASIdentifiers(dyn_asnum, dyn_rdi);
12✔
1846
      std::unique_ptr<ASBlocks> dyn_blocks = std::make_unique<ASBlocks>(dyn_ident);
4✔
1847

1848
      auto [dyn_cert, dyn_ca] = make_and_sign_ca(std::move(dyn_blocks), inherit_ca, *rng);
8✔
1849

1850
      const auto sub_req = user_params().add_extension(sub_blocks->copy()).into_pkcs10_request(*sub_key, *rng, hash_fn);
4✔
1851
      Botan::X509_Certificate sub_cert =
4✔
1852
         dyn_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
4✔
1853

1854
      const Botan::Path_Validation_Restrictions restrictions(false, 80);
8✔
1855
      std::vector<Botan::X509_Certificate> certs = {sub_cert, dyn_cert, inherit_cert};
16✔
1856

1857
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
4✔
1858
      result.require("path validation succeeds", path_result.successful_validation());
4✔
1859
   }
12✔
1860

1861
   result.end_timer();
1✔
1862
   return result;
2✔
1863
}
12✔
1864

1865
Test::Result test_x509_as_blocks_path_validation_extension_not_present_builder() {
1✔
1866
   Test::Result result("X509 AS Block path validation extension not present (builder)");
1✔
1867
   result.start_timer();
1✔
1868

1869
   using Botan::Cert_Extension::ASBlocks;
1✔
1870
   auto rng = Test::new_rng(__func__);
1✔
1871

1872
   std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>();
1✔
1873
   sub_blocks->add_asnum(120, 180);
1✔
1874
   sub_blocks->add_asnum(220, 224);
1✔
1875
   sub_blocks->add_asnum(260, 511);
1✔
1876
   sub_blocks->add_asnum(678);
1✔
1877
   sub_blocks->add_asnum(5043, 5100);
1✔
1878

1879
   sub_blocks->add_rdi(1500, 2300);
1✔
1880
   sub_blocks->add_rdi(2500, 4000);
1✔
1881
   sub_blocks->add_rdi(1567);
1✔
1882
   sub_blocks->add_rdi(33100, 40000);
1✔
1883

1884
   // create a root ca that does not have any extension
1885
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] = make_ca(*rng, ca_params());
1✔
1886
   auto sub_req = user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1✔
1887
   Botan::X509_Certificate sub_cert = root_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1✔
1888

1889
   Botan::Certificate_Store_In_Memory trusted;
1✔
1890
   trusted.add_certificate(root_cert);
1✔
1891

1892
   const Botan::Path_Validation_Restrictions restrictions(false, 80);
2✔
1893
   const std::vector<Botan::X509_Certificate> certs = {sub_cert};
2✔
1894

1895
   Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
1✔
1896
   result.require("path validation fails", !path_result.successful_validation());
1✔
1897

1898
   result.end_timer();
1✔
1899
   return result;
2✔
1900
}
3✔
1901

1902
Test::Result test_x509_as_blocks_path_validation_extension_not_present_ctor() {
1✔
1903
   Test::Result result("X509 AS Block path validation extension not present (ctor)");
1✔
1904
   result.start_timer();
1✔
1905

1906
   using Botan::Cert_Extension::ASBlocks;
1✔
1907
   auto rng = Test::new_rng(__func__);
1✔
1908

1909
   // Subject cert
1910
   ASBlocks::ASIdOrRange sub_asnum_id_or_range0 = ASBlocks::ASIdOrRange(120, 180);
1✔
1911
   ASBlocks::ASIdOrRange sub_asnum_id_or_range1 = ASBlocks::ASIdOrRange(220, 240);
1✔
1912
   ASBlocks::ASIdOrRange sub_asnum_id_or_range2 = ASBlocks::ASIdOrRange(260, 511);
1✔
1913
   ASBlocks::ASIdOrRange sub_asnum_id_or_range3 = ASBlocks::ASIdOrRange(678);
1✔
1914
   ASBlocks::ASIdOrRange sub_asnum_id_or_range4 = ASBlocks::ASIdOrRange(5043, 5100);
1✔
1915

1916
   ASBlocks::ASIdOrRange sub_rdi_id_or_range0 = ASBlocks::ASIdOrRange(1500, 2300);
1✔
1917
   ASBlocks::ASIdOrRange sub_rdi_id_or_range1 = ASBlocks::ASIdOrRange(2500, 4000);
1✔
1918
   ASBlocks::ASIdOrRange sub_rdi_id_or_range2 = ASBlocks::ASIdOrRange(1567);
1✔
1919
   ASBlocks::ASIdOrRange sub_rdi_id_or_range3 = ASBlocks::ASIdOrRange(33100, 40000);
1✔
1920

1921
   std::vector<ASBlocks::ASIdOrRange> sub_as_ranges;
1✔
1922
   sub_as_ranges.push_back(sub_asnum_id_or_range0);
1✔
1923
   sub_as_ranges.push_back(sub_asnum_id_or_range1);
1✔
1924
   sub_as_ranges.push_back(sub_asnum_id_or_range2);
1✔
1925
   sub_as_ranges.push_back(sub_asnum_id_or_range3);
1✔
1926
   sub_as_ranges.push_back(sub_asnum_id_or_range4);
1✔
1927

1928
   std::vector<ASBlocks::ASIdOrRange> sub_rdi_ranges;
1✔
1929
   sub_rdi_ranges.push_back(sub_rdi_id_or_range0);
1✔
1930
   sub_rdi_ranges.push_back(sub_rdi_id_or_range1);
1✔
1931
   sub_rdi_ranges.push_back(sub_rdi_id_or_range2);
1✔
1932
   sub_rdi_ranges.push_back(sub_rdi_id_or_range3);
1✔
1933

1934
   ASBlocks::ASIdentifierChoice sub_asnum = ASBlocks::ASIdentifierChoice(sub_as_ranges);
1✔
1935
   ASBlocks::ASIdentifierChoice sub_rdi = ASBlocks::ASIdentifierChoice(sub_rdi_ranges);
1✔
1936
   ASBlocks::ASIdentifiers sub_ident = ASBlocks::ASIdentifiers(sub_asnum, sub_rdi);
4✔
1937
   std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>(sub_ident);
1✔
1938

1939
   // create a root ca that does not have any extension
1940
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] = make_ca(*rng, ca_params());
1✔
1941
   const auto sub_req = user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1✔
1942
   Botan::X509_Certificate sub_cert = root_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1✔
1943

1944
   Botan::Certificate_Store_In_Memory trusted;
1✔
1945
   trusted.add_certificate(root_cert);
1✔
1946

1947
   const Botan::Path_Validation_Restrictions restrictions(false, 80);
2✔
1948
   const std::vector<Botan::X509_Certificate> certs = {sub_cert};
2✔
1949

1950
   Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
1✔
1951
   result.require("path validation fails", !path_result.successful_validation());
1✔
1952

1953
   result.end_timer();
1✔
1954
   return result;
2✔
1955
}
5✔
1956

1957
Test::Result test_x509_as_blocks_path_validation_failure_builder() {
1✔
1958
   Test::Result result("X509 AS Block path validation failure (builder)");
1✔
1959
   result.start_timer();
1✔
1960

1961
   using Botan::Cert_Extension::ASBlocks;
1✔
1962
   auto rng = Test::new_rng(__func__);
1✔
1963

1964
   /*
1965
   This executes a few permutations, messing around with edge cases when it comes to constructing ranges.
1966

1967
   Each test is expected to fail and creates the following certificate chain:
1968
   Root -> Issuer -> Subject
1969

1970
   00: set all the asnum choices to 'inherit' for each cert
1971
   01: 00 but for rdis
1972
   02: make smallest min asnum of the subject smaller than the smallest min asnum of the issuer
1973
   03: 02 but for rdis
1974
   04: both 02 and 03
1975
   05: make largest max asnum of the subject larger than the largest max asnum of the issuer
1976
   06: 05 but for rdis
1977
   07: both 05 and 06
1978
   08: make the certs have multiple ranges and make one asnum range that is not the smallest and not the largest overlap with it's maximum
1979
   09: 08 but for rdis
1980
   10: both 08 and 09
1981
   11: same as 08 but the range in the subject is not contiguous, instead it is the issuers range but split into two ranges (e.g issuer range is 40-60, subject ranges are 40-49 and 51-61)
1982
   12: 11 but for rdis
1983
   13: both 11 and 12
1984
   14: 08 but using the minimum instead of the maximum
1985
   15: 14 but for rdis
1986
   16: both 14 and 15
1987
   17: same as 11 but using the minimum instead of the maximum
1988
   18: 17 but for rdis
1989
   19: both 18 and 19
1990
   20: make the issuer ranges empty but have an entry in the subject ranges
1991
   */
1992
   for(size_t i = 0; i < 21; i++) {
22✔
1993
      // enable / disable all the different edge cases
1994
      bool inherit_all_asnums = (i == 0);
21✔
1995
      bool inherit_all_rdis = (i == 1);
21✔
1996
      bool push_asnum_min_edge_ranges = (i == 2) || (i == 4);
21✔
1997
      bool push_rdi_min_edge_ranges = (i == 3) || (i == 4);
21✔
1998
      bool push_asnum_max_edge_ranges = (i == 5) || (i == 7);
21✔
1999
      bool push_rdi_max_edge_ranges = (i == 6) || (i == 7);
21✔
2000
      bool push_asnum_max_middle_ranges = (i == 8) || (i == 10);
21✔
2001
      bool push_rdi_max_middle_ranges = (i == 9) || (i == 10);
21✔
2002
      bool push_asnum_max_split_ranges = (i == 11) || (i == 13);
21✔
2003
      bool push_rdi_max_split_ranges = (i == 12) || (i == 13);
21✔
2004
      bool push_asnum_min_middle_ranges = (i == 14) || (i == 16);
21✔
2005
      bool push_rdi_min_middle_ranges = (i == 15) || (i == 16);
21✔
2006
      bool push_asnum_min_split_ranges = (i == 17) || (i == 19);
21✔
2007
      bool push_rdi_min_split_ranges = (i == 18) || (i == 19);
21✔
2008
      bool empty_issuer_non_empty_subject = (i == 20);
21✔
2009

2010
      // Root cert
2011
      std::unique_ptr<ASBlocks> root_blocks = std::make_unique<ASBlocks>();
21✔
2012

2013
      if(!inherit_all_asnums) {
21✔
2014
         if(push_asnum_min_edge_ranges || push_asnum_max_edge_ranges) {
20✔
2015
            // 100-200 for 02,03,04
2016
            root_blocks->add_asnum(100, 200);
4✔
2017
         } else if(push_asnum_max_middle_ranges || push_asnum_min_middle_ranges) {
16✔
2018
            // 10-20,30-40,50-60 for 08,09,10
2019
            root_blocks->add_asnum(10, 20);
4✔
2020
            root_blocks->add_asnum(30, 40);
4✔
2021
            root_blocks->add_asnum(50, 60);
4✔
2022
         } else if(push_asnum_max_split_ranges || push_asnum_min_split_ranges) {
12✔
2023
            // 10-20,30-50,60-70 for 11,12,13
2024
            root_blocks->add_asnum(10, 20);
4✔
2025
            root_blocks->add_asnum(30, 50);
4✔
2026
            root_blocks->add_asnum(60, 70);
4✔
2027
         }
2028
      } else {
2029
         root_blocks->inherit_asnum();
1✔
2030
      }
2031

2032
      // same values but for rdis
2033
      if(!inherit_all_rdis) {
21✔
2034
         if(push_rdi_min_edge_ranges || push_rdi_max_edge_ranges) {
2035
            root_blocks->add_rdi(100, 200);
4✔
2036
         } else if(push_rdi_max_middle_ranges || push_rdi_min_middle_ranges) {
2037
            root_blocks->add_rdi(10, 20);
4✔
2038
            root_blocks->add_rdi(30, 40);
4✔
2039
            root_blocks->add_rdi(50, 60);
4✔
2040
         } else if(push_rdi_max_split_ranges || push_rdi_min_split_ranges) {
2041
            root_blocks->add_rdi(10, 20);
4✔
2042
            root_blocks->add_rdi(30, 50);
4✔
2043
            root_blocks->add_rdi(60, 70);
4✔
2044
         }
2045
      } else {
2046
         root_blocks->inherit_rdi();
1✔
2047
      }
2048

2049
      if(empty_issuer_non_empty_subject) {
21✔
2050
         root_blocks->restrict_asnum();
1✔
2051
         root_blocks->restrict_rdi();
1✔
2052
      }
2053

2054
      // Issuer cert
2055
      // the issuer cert has the same ranges as the root cert
2056
      // it is used to check that the 'inherit' check is bubbled up until the root cert is hit
2057
      auto issu_blocks = root_blocks->copy();
21✔
2058

2059
      // Subject cert
2060
      std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>();
21✔
2061

2062
      std::vector<ASBlocks::ASIdOrRange> sub_as_ranges;
21✔
2063
      std::vector<ASBlocks::ASIdOrRange> sub_rdi_ranges;
21✔
2064

2065
      if(!inherit_all_asnums) {
21✔
2066
         // assign the subject asnum ranges
2067
         if(push_asnum_min_edge_ranges) {
2068
            // 99-200 for 02 (so overlapping to the left)
2069
            sub_blocks->add_asnum(99, 200);
2✔
2070
         } else if(push_asnum_max_edge_ranges) {
2071
            // 100-201 for 03 (so overlapping to the right)
2072
            sub_blocks->add_asnum(100, 201);
2✔
2073
         } else if(push_asnum_max_middle_ranges) {
2074
            // same as root, but change the range in the middle to overlap to the right for 08
2075
            sub_blocks->add_asnum(10, 20);
2✔
2076
            sub_blocks->add_asnum(30, 41);
2✔
2077
            sub_blocks->add_asnum(50, 60);
2✔
2078
         } else if(push_asnum_max_split_ranges) {
2079
            // change the range in the middle to be cut at 45 for case 11
2080
            // the left range is 30-44
2081
            // the right range is 46-51 (overlapping the issuer range to the right)
2082
            sub_blocks->add_asnum(10, 20);
2✔
2083
            sub_blocks->add_asnum(30, 44);
2✔
2084
            sub_blocks->add_asnum(46, 51);
2✔
2085
            sub_blocks->add_asnum(60, 70);
2✔
2086
         } else if(push_asnum_min_middle_ranges) {
2087
            // just change the test in the middle to overlap to the left for case 14
2088
            sub_blocks->add_asnum(10, 20);
2✔
2089
            sub_blocks->add_asnum(29, 40);
2✔
2090
            sub_blocks->add_asnum(50, 60);
2✔
2091
         } else if(push_asnum_min_split_ranges) {
2092
            // again split the range in the middle at 45 for case 17
2093
            // creating two ranges 29-44 and 46-50 (so overlapping to the left)
2094
            sub_blocks->add_asnum(10, 20);
2✔
2095
            sub_blocks->add_asnum(29, 44);
2✔
2096
            sub_blocks->add_asnum(46, 50);
2✔
2097
            sub_blocks->add_asnum(60, 70);
2✔
2098
         } else if(empty_issuer_non_empty_subject) {
2099
            sub_blocks->add_asnum(50);
1✔
2100
         }
2101
      } else {
2102
         sub_blocks->inherit_asnum();
1✔
2103
      }
2104

2105
      if(!inherit_all_rdis) {
21✔
2106
         // same values but for rdis
2107
         if(push_rdi_min_edge_ranges) {
2108
            sub_blocks->add_rdi(99, 200);
2✔
2109
         } else if(push_rdi_max_edge_ranges) {
2110
            sub_blocks->add_rdi(100, 201);
2✔
2111
         } else if(push_rdi_max_middle_ranges) {
2112
            sub_blocks->add_rdi(10, 20);
2✔
2113
            sub_blocks->add_rdi(30, 41);
2✔
2114
            sub_blocks->add_rdi(50, 60);
2✔
2115
         } else if(push_rdi_max_split_ranges) {
2116
            sub_blocks->add_rdi(10, 20);
2✔
2117
            sub_blocks->add_rdi(30, 44);
2✔
2118
            sub_blocks->add_rdi(46, 51);
2✔
2119
            sub_blocks->add_rdi(60, 70);
2✔
2120
         } else if(push_rdi_min_middle_ranges) {
2121
            sub_blocks->add_rdi(10, 20);
2✔
2122
            sub_blocks->add_rdi(29, 40);
2✔
2123
            sub_blocks->add_rdi(50, 60);
2✔
2124
         } else if(push_rdi_min_split_ranges) {
2125
            sub_blocks->add_rdi(10, 20);
2✔
2126
            sub_blocks->add_rdi(29, 44);
2✔
2127
            sub_blocks->add_rdi(46, 50);
2✔
2128
            sub_blocks->add_rdi(60, 70);
2✔
2129
         }
2130
      } else {
2131
         sub_blocks->inherit_rdi();
1✔
2132
      }
2133

2134
      auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
21✔
2135
         make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
42✔
2136
      auto [issu_cert, issu_ca] = make_and_sign_ca(std::move(issu_blocks), root_ca, *rng);
42✔
2137

2138
      const auto sub_req =
21✔
2139
         user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
21✔
2140
      Botan::X509_Certificate sub_cert =
21✔
2141
         issu_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
21✔
2142

2143
      Botan::Certificate_Store_In_Memory trusted;
21✔
2144
      trusted.add_certificate(root_cert);
21✔
2145

2146
      const Botan::Path_Validation_Restrictions restrictions(false, 80);
42✔
2147
      const std::vector<Botan::X509_Certificate> certs = {sub_cert, issu_cert};
63✔
2148

2149
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
21✔
2150
      // in all cases, the validation should fail, since we are creating invalid scenarios
2151
      result.confirm("path validation fails at iteration " + std::to_string(i), !path_result.successful_validation());
42✔
2152
   }
42✔
2153

2154
   result.end_timer();
1✔
2155
   return result;
1✔
2156
}
22✔
2157

2158
Test::Result test_x509_as_blocks_path_validation_failure_ctor() {
1✔
2159
   Test::Result result("X509 AS Block path validation failure (ctor)");
1✔
2160
   result.start_timer();
1✔
2161

2162
   using Botan::Cert_Extension::ASBlocks;
1✔
2163
   auto rng = Test::new_rng(__func__);
1✔
2164

2165
   /*
2166
   This executes a few permutations, messing around with edge cases when it comes to constructing ranges.
2167

2168
   Each test is expected to fail and creates the following certificate chain:
2169
   Root -> Issuer -> Subject
2170

2171
   00: set all the asnum choices to 'inherit' for each cert
2172
   01: 00 but for rdis
2173
   02: make smallest min asnum of the subject smaller than the smallest min asnum of the issuer
2174
   03: 02 but for rdis
2175
   04: both 02 and 03
2176
   05: make largest max asnum of the subject larger than the largest max asnum of the issuer
2177
   06: 05 but for rdis
2178
   07: both 05 and 06
2179
   08: make the certs have multiple ranges and make one asnum range that is not the smallest and not the largest overlap with it's maximum
2180
   09: 08 but for rdis
2181
   10: both 08 and 09
2182
   11: same as 08 but the range in the subject is not contiguous, instead it is the issuers range but split into two ranges (e.g issuer range is 40-60, subject ranges are 40-49 and 51-61)
2183
   12: 11 but for rdis
2184
   13: both 11 and 12
2185
   14: 08 but using the minimum instead of the maximum
2186
   15: 14 but for rdis
2187
   16: both 14 and 15
2188
   17: same as 11 but using the minimum instead of the maximum
2189
   18: 17 but for rdis
2190
   19: both 18 and 19
2191
   20: make the issuer ranges empty but have an entry in the subject ranges
2192
   */
2193
   for(size_t i = 0; i < 21; i++) {
22✔
2194
      // enable / disable all the different edge cases
2195
      bool inherit_all_asnums = (i == 0);
21✔
2196
      bool inherit_all_rdis = (i == 1);
21✔
2197
      bool push_asnum_min_edge_ranges = (i == 2) || (i == 4);
21✔
2198
      bool push_rdi_min_edge_ranges = (i == 3) || (i == 4);
21✔
2199
      bool push_asnum_max_edge_ranges = (i == 5) || (i == 7);
21✔
2200
      bool push_rdi_max_edge_ranges = (i == 6) || (i == 7);
21✔
2201
      bool push_asnum_max_middle_ranges = (i == 8) || (i == 10);
21✔
2202
      bool push_rdi_max_middle_ranges = (i == 9) || (i == 10);
21✔
2203
      bool push_asnum_max_split_ranges = (i == 11) || (i == 13);
21✔
2204
      bool push_rdi_max_split_ranges = (i == 12) || (i == 13);
21✔
2205
      bool push_asnum_min_middle_ranges = (i == 14) || (i == 16);
21✔
2206
      bool push_rdi_min_middle_ranges = (i == 15) || (i == 16);
21✔
2207
      bool push_asnum_min_split_ranges = (i == 17) || (i == 19);
21✔
2208
      bool push_rdi_min_split_ranges = (i == 18) || (i == 19);
21✔
2209
      bool empty_issuer_non_empty_subject = (i == 20);
21✔
2210

2211
      // Root cert
2212
      std::vector<ASBlocks::ASIdOrRange> root_as_ranges;
21✔
2213
      std::vector<ASBlocks::ASIdOrRange> root_rdi_ranges;
21✔
2214

2215
      // assign the root ranges
2216
      if(push_asnum_min_edge_ranges || push_asnum_max_edge_ranges) {
21✔
2217
         // 100-200 for 02,03,04
2218
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(100, 200));
8✔
2219
      } else if(push_asnum_max_middle_ranges || push_asnum_min_middle_ranges) {
17✔
2220
         // 10-20,30-40,50-60 for 08,09,10
2221
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(10, 20));
8✔
2222
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(30, 40));
8✔
2223
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(50, 60));
8✔
2224
      } else if(push_asnum_max_split_ranges || push_asnum_min_split_ranges) {
13✔
2225
         // 10-20,30-50,60-70 for 11,12,13
2226
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(10, 20));
8✔
2227
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(30, 50));
8✔
2228
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(60, 70));
8✔
2229
      }
2230

2231
      // same values but for rdis
2232
      if(push_rdi_min_edge_ranges || push_rdi_max_edge_ranges) {
21✔
2233
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(100, 200));
8✔
2234
      } else if(push_rdi_max_middle_ranges || push_rdi_min_middle_ranges) {
2235
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(10, 20));
8✔
2236
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(30, 40));
8✔
2237
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(50, 60));
8✔
2238
      } else if(push_rdi_max_split_ranges || push_rdi_min_split_ranges) {
2239
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(10, 20));
8✔
2240
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(30, 50));
8✔
2241
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(60, 70));
8✔
2242
      }
2243

2244
      // Issuer cert
2245
      // the issuer cert has the same ranges as the root cert
2246
      // it is used to check that the 'inherit' check is bubbled up until the root cert is hit
2247
      std::vector<ASBlocks::ASIdOrRange> issu_as_ranges;
21✔
2248
      std::vector<ASBlocks::ASIdOrRange> issu_rdi_ranges;
21✔
2249

2250
      // Subject cert
2251
      std::vector<ASBlocks::ASIdOrRange> sub_as_ranges;
21✔
2252
      std::vector<ASBlocks::ASIdOrRange> sub_rdi_ranges;
21✔
2253

2254
      // assign the subject asnum ranges
2255
      if(push_asnum_min_edge_ranges) {
21✔
2256
         // 99-200 for 02 (so overlapping to the left)
2257
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(99, 200));
4✔
2258
      } else if(push_asnum_max_edge_ranges) {
2259
         // 100-201 for 03 (so overlapping to the right)
2260
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(100, 201));
4✔
2261
      } else if(push_asnum_max_middle_ranges) {
2262
         // just change the range in the middle to overlap to the right for 08
2263
         sub_as_ranges = root_as_ranges;
2✔
2264
         sub_as_ranges[1] = ASBlocks::ASIdOrRange(30, 41);
2✔
2265
      } else if(push_asnum_max_split_ranges) {
2266
         // change the range in the middle to be cut at 45 for case 11
2267
         // the left range is 30-44
2268
         // the right range is 46-51 (overlapping the issuer range to the right)
2269
         sub_as_ranges = root_as_ranges;
2✔
2270
         sub_as_ranges[1] = ASBlocks::ASIdOrRange(30, 44);
2✔
2271
         // pushing the new range created by splitting to the back since they will be sorted anyway
2272
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(46, 51));
4✔
2273
      } else if(push_asnum_min_middle_ranges) {
2274
         // just change the test in the middle to overlap to the left for case 14
2275
         sub_as_ranges = root_as_ranges;
2✔
2276
         sub_as_ranges[1] = ASBlocks::ASIdOrRange(29, 40);
2✔
2277
      } else if(push_asnum_min_split_ranges) {
2278
         // again split the range in the middle at 45 for case 17
2279
         // creating two ranges 29-44 and 46-50 (so overlapping to the left)
2280
         sub_as_ranges = root_as_ranges;
2✔
2281
         sub_as_ranges[1] = ASBlocks::ASIdOrRange(29, 44);
2✔
2282
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(46, 50));
4✔
2283
      } else if(empty_issuer_non_empty_subject) {
2284
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(50));
1✔
2285
      }
2286

2287
      // same values but for rdis
2288
      if(push_rdi_min_edge_ranges) {
21✔
2289
         sub_rdi_ranges.push_back(ASBlocks::ASIdOrRange(99, 200));
4✔
2290
      } else if(push_rdi_max_edge_ranges) {
2291
         sub_rdi_ranges.push_back(ASBlocks::ASIdOrRange(100, 201));
4✔
2292
      } else if(push_rdi_max_middle_ranges) {
2293
         sub_rdi_ranges = root_rdi_ranges;
2✔
2294
         sub_rdi_ranges[1] = ASBlocks::ASIdOrRange(30, 41);
2✔
2295
      } else if(push_rdi_max_split_ranges) {
2296
         sub_rdi_ranges = root_rdi_ranges;
2✔
2297
         sub_rdi_ranges[1] = ASBlocks::ASIdOrRange(30, 44);
2✔
2298
         sub_rdi_ranges.push_back(ASBlocks::ASIdOrRange(46, 51));
4✔
2299
      } else if(push_rdi_min_middle_ranges) {
2300
         sub_rdi_ranges = root_rdi_ranges;
2✔
2301
         sub_rdi_ranges[1] = ASBlocks::ASIdOrRange(29, 40);
2✔
2302
      } else if(push_rdi_min_split_ranges) {
2303
         sub_rdi_ranges = root_rdi_ranges;
2✔
2304
         sub_rdi_ranges[1] = ASBlocks::ASIdOrRange(29, 44);
2✔
2305
         sub_rdi_ranges.push_back(ASBlocks::ASIdOrRange(46, 50));
4✔
2306
      }
2307

2308
      // for cases 00 and 01, set all certs to inherit (so std::nullopt)
2309
      // in all other cases use the ranges created beforehand
2310
      ASBlocks::ASIdentifierChoice root_asnum =
21✔
2311
         ASBlocks::ASIdentifierChoice(inherit_all_asnums ? std::nullopt : std::optional(root_as_ranges));
41✔
2312
      ASBlocks::ASIdentifierChoice root_rdi =
21✔
2313
         ASBlocks::ASIdentifierChoice(inherit_all_rdis ? std::nullopt : std::optional(root_rdi_ranges));
41✔
2314
      ASBlocks::ASIdentifiers root_ident = ASBlocks::ASIdentifiers(root_asnum, root_rdi);
82✔
2315
      std::unique_ptr<ASBlocks> root_blocks = std::make_unique<ASBlocks>(root_ident);
21✔
2316

2317
      ASBlocks::ASIdentifiers issu_ident = root_ident;
21✔
2318
      std::unique_ptr<ASBlocks> issu_blocks = std::make_unique<ASBlocks>(issu_ident);
21✔
2319

2320
      ASBlocks::ASIdentifierChoice sub_asnum =
21✔
2321
         ASBlocks::ASIdentifierChoice(inherit_all_asnums ? std::nullopt : std::optional(sub_as_ranges));
41✔
2322
      ASBlocks::ASIdentifierChoice sub_rdi =
21✔
2323
         ASBlocks::ASIdentifierChoice(inherit_all_rdis ? std::nullopt : std::optional(sub_rdi_ranges));
41✔
2324
      ASBlocks::ASIdentifiers sub_ident = ASBlocks::ASIdentifiers(sub_asnum, sub_rdi);
82✔
2325
      std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>(sub_ident);
21✔
2326

2327
      auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
21✔
2328
         make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
42✔
2329
      auto [issu_cert, issu_ca] = make_and_sign_ca(std::move(issu_blocks), root_ca, *rng);
42✔
2330

2331
      const auto sub_req =
21✔
2332
         user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
21✔
2333
      Botan::X509_Certificate sub_cert =
21✔
2334
         issu_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
21✔
2335

2336
      Botan::Certificate_Store_In_Memory trusted;
21✔
2337
      trusted.add_certificate(root_cert);
21✔
2338

2339
      const Botan::Path_Validation_Restrictions restrictions(false, 80);
42✔
2340
      const std::vector<Botan::X509_Certificate> certs = {sub_cert, issu_cert};
63✔
2341

2342
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
21✔
2343
      // in all cases, the validation should fail, since we are creating invalid scenarios
2344
      result.confirm("path validation fails at iteration " + std::to_string(i), !path_result.successful_validation());
42✔
2345
   }
122✔
2346

2347
   result.end_timer();
1✔
2348
   return result;
1✔
2349
}
22✔
2350

2351
class X509_RPKI_Tests final : public Test {
×
2352
   public:
2353
      std::vector<Test::Result> run() override {
1✔
2354
         std::vector<Test::Result> results;
1✔
2355

2356
   #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
2357
         results.push_back(test_x509_ip_addr_blocks_extension_decode());
2✔
2358
         results.push_back(test_x509_as_blocks_extension_decode());
2✔
2359
   #endif
2360
         results.push_back(test_x509_ip_addr_blocks_rfc3779_example());
2✔
2361
         results.push_back(test_x509_ip_addr_blocks_encode_builder());
2✔
2362
         results.push_back(test_x509_ip_addr_blocks_extension_encode_ctor());
2✔
2363
         results.push_back(test_x509_ip_addr_blocks_extension_encode_edge_cases_ctor());
2✔
2364
         results.push_back(test_x509_ip_addr_blocks_range_merge());
2✔
2365
         results.push_back(test_x509_ip_addr_blocks_family_merge());
2✔
2366
         results.push_back(test_x509_ip_addr_blocks_path_validation_success_builder());
2✔
2367
         results.push_back(test_x509_ip_addr_blocks_path_validation_success_ctor());
2✔
2368
         results.push_back(test_x509_ip_addr_blocks_path_validation_failure_builder());
2✔
2369
         results.push_back(test_x509_ip_addr_blocks_path_validation_failure_ctor());
2✔
2370
         results.push_back(test_x509_as_blocks_rfc3779_example());
2✔
2371
         results.push_back(test_x509_as_blocks_encode_builder());
2✔
2372
         results.push_back(test_x509_as_blocks_extension_encode_ctor());
2✔
2373
         results.push_back(test_x509_as_blocks_range_merge());
2✔
2374
         results.push_back(test_x509_as_blocks_path_validation_success_builder());
2✔
2375
         results.push_back(test_x509_as_blocks_path_validation_success_ctor());
2✔
2376
         results.push_back(test_x509_as_blocks_path_validation_extension_not_present_builder());
2✔
2377
         results.push_back(test_x509_as_blocks_path_validation_extension_not_present_ctor());
2✔
2378
         results.push_back(test_x509_as_blocks_path_validation_failure_builder());
2✔
2379
         results.push_back(test_x509_as_blocks_path_validation_failure_ctor());
2✔
2380
         return results;
1✔
2381
      }
×
2382
};
2383

2384
BOTAN_REGISTER_TEST("x509", "x509_rpki", X509_RPKI_Tests);
2385

2386
#endif
2387

2388
}  // namespace
2389

2390
}  // namespace Botan_Tests
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