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

randombit / botan / 16342066753

17 Jul 2025 09:58AM UTC coverage: 90.601% (-0.03%) from 90.627%
16342066753

Pull #4996

github

web-flow
Merge 7d66b5165 into 421b766f1
Pull Request #4996: Add CertificateParametersBuilder as a replacement for X509_Cert_Options

99700 of 110043 relevant lines covered (90.6%)

12289572.73 hits per line

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

99.04
/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

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

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

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

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

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

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

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

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

74
   return builder;
149✔
75
}
×
76

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

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

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

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

100
   return std::make_pair(sig_algo, hash_fn);
149✔
101
}
149✔
102

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

153
constexpr auto IPv4 = Botan::Cert_Extension::IPAddressBlocks::Version::IPv4;
154
constexpr auto IPv6 = Botan::Cert_Extension::IPAddressBlocks::Version::IPv6;
155

156
   #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
157

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

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

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

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

175
      const auto& v4_blocks = ipv4block.ranges().value();
1✔
176

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

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

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

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

194
      const auto& v6_blocks = ipv6block.ranges().value();
1✔
195

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

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

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

240
      // IPv4 ranges should be merged, IPv4 should come before IPv6, all should be sorted by safi
241

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

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

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

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

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

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

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

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

284
      // cert contains the 10.0.32.0/20 prefix, but with a 9 for the unused bits
285

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

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

292
   result.end_timer();
1✔
293
   return result;
1✔
294
}
×
295

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

370
   result.end_timer();
1✔
371
   return result;
1✔
372
}
×
373

374
   #endif
375

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

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

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

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

395
   auto bits_1 = cert_1.v3_extensions().get_extension_bits(IPAddressBlocks::static_oid());
1✔
396

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

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

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

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

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

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

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

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

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

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

439
   auto bits_2 = cert_2.v3_extensions().get_extension_bits(IPAddressBlocks::static_oid());
1✔
440

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

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

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

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

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

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

474
   result.end_timer();
1✔
475
   return result;
2✔
476
}
7✔
477

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

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

485
   std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>();
1✔
486

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

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

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

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

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

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

510
   result.end_timer();
1✔
511
   return result;
1✔
512
}
2✔
513

514
Test::Result test_x509_ip_addr_blocks_extension_encode_ctor() {
1✔
515
   Test::Result result("X509 IP Address Block encode (ctor)");
1✔
516
   result.start_timer();
1✔
517

518
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
519

520
   auto rng = Test::new_rng(__func__);
1✔
521

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

524
   for(size_t i = 0; i < 64; i++) {
65✔
525
      bool push_ipv4_ranges = i & 1;
64✔
526
      bool push_ipv6_ranges = i >> 1 & 1;
64✔
527
      bool inherit_ipv4 = i >> 2 & 1;
64✔
528
      bool inherit_ipv6 = i >> 3 & 1;
64✔
529
      bool push_ipv4_family = i >> 4 & 1;
64✔
530
      bool push_ipv6_family = i >> 5 & 1;
64✔
531

532
      std::vector<uint8_t> a = {123, 123, 2, 1};
64✔
533
      auto ipv4_1 = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
534
      a = {255, 255, 255, 255};
64✔
535
      auto ipv4_2 = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
536

537
      // encoded as min, max
538
      a = {127, 0, 0, 1};
64✔
539
      auto ipv4_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
540
      a = {189, 5, 7, 255};
64✔
541
      auto ipv4_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
542

543
      // encoded as prefix
544
      a = {190, 5, 0, 0};
64✔
545
      auto ipv4_range_2_min = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
546
      a = {190, 5, 127, 255};
64✔
547
      auto ipv4_range_2_max = IPAddressBlocks::IPAddress<IPv4>(a);
64✔
548

549
      a = {0xAB, 0xCD, 0xDE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
64✔
550
      auto ipv6_1 = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
551
      a = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
64✔
552
      auto ipv6_2 = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
553

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

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

561
      // encoded as prefix
562
      a = {0xBF, 0xCD, 0xDE, 0xF0, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
64✔
563
      auto ipv6_range_2_min = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
564
      a = {0xBF, 0xCD, 0xDE, 0xF0, 0x00, 0x00, 0x00, 0x07, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
64✔
565
      auto ipv6_range_2_max = IPAddressBlocks::IPAddress<IPv6>(a);
64✔
566

567
      auto ipv4_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(ipv4_1);
64✔
568
      auto ipv4_range_2 = IPAddressBlocks::IPAddressOrRange<IPv4>(ipv4_range_1_min, ipv4_range_1_max);
64✔
569
      auto ipv4_range_3 = IPAddressBlocks::IPAddressOrRange<IPv4>(ipv4_range_2_min, ipv4_range_2_max);
64✔
570
      auto ipv4_range_4 = IPAddressBlocks::IPAddressOrRange<IPv4>(ipv4_2);
64✔
571

572
      auto ipv6_range_1 = IPAddressBlocks::IPAddressOrRange<IPv6>(ipv6_1);
64✔
573
      auto ipv6_range_2 = IPAddressBlocks::IPAddressOrRange<IPv6>(ipv6_range_1_min, ipv6_range_1_max);
64✔
574
      auto ipv6_range_3 = IPAddressBlocks::IPAddressOrRange<IPv6>(ipv6_range_2_min, ipv6_range_2_max);
64✔
575
      auto ipv6_range_4 = IPAddressBlocks::IPAddressOrRange<IPv6>(ipv6_2);
64✔
576

577
      std::vector<IPAddressBlocks::IPAddressOrRange<IPv4>> ipv4_ranges;
64✔
578
      if(push_ipv4_ranges) {
64✔
579
         ipv4_ranges.push_back(ipv4_range_1);
32✔
580
         ipv4_ranges.push_back(ipv4_range_2);
32✔
581
         ipv4_ranges.push_back(ipv4_range_3);
32✔
582
         ipv4_ranges.push_back(ipv4_range_4);
32✔
583
      }
584

585
      std::vector<IPAddressBlocks::IPAddressOrRange<IPv6>> ipv6_ranges;
64✔
586
      if(push_ipv6_ranges) {
64✔
587
         ipv6_ranges.push_back(ipv6_range_1);
32✔
588
         ipv6_ranges.push_back(ipv6_range_2);
32✔
589
         ipv6_ranges.push_back(ipv6_range_3);
32✔
590
         ipv6_ranges.push_back(ipv6_range_4);
32✔
591
      }
592

593
      auto ipv4_addr_choice = IPAddressBlocks::IPAddressChoice<IPv4>();
64✔
594
      if(!inherit_ipv4) {
64✔
595
         ipv4_addr_choice = IPAddressBlocks::IPAddressChoice<IPv4>(ipv4_ranges);
96✔
596
      }
597

598
      auto ipv6_addr_choice = IPAddressBlocks::IPAddressChoice<IPv6>();
64✔
599
      if(!inherit_ipv6) {
64✔
600
         ipv6_addr_choice = IPAddressBlocks::IPAddressChoice<IPv6>(ipv6_ranges);
96✔
601
      }
602

603
      auto ipv4_addr_family = IPAddressBlocks::IPAddressFamily(ipv4_addr_choice);
160✔
604
      auto ipv6_addr_family = IPAddressBlocks::IPAddressFamily(ipv6_addr_choice);
160✔
605

606
      std::vector<IPAddressBlocks::IPAddressFamily> addr_blocks;
64✔
607
      if(push_ipv4_family) {
64✔
608
         addr_blocks.push_back(ipv4_addr_family);
32✔
609
      }
610
      if(push_ipv6_family) {
64✔
611
         addr_blocks.push_back(ipv6_addr_family);
32✔
612
      }
613

614
      std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>(addr_blocks);
64✔
615

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

622
         const auto& dec_addr_blocks = ip_blocks->addr_blocks();
64✔
623
         if(!push_ipv4_family && !push_ipv6_family) {
64✔
624
            result.confirm("no address family entries", dec_addr_blocks.empty(), true);
32✔
625
            continue;
16✔
626
         }
627

628
         if(push_ipv4_family) {
48✔
629
            auto family = dec_addr_blocks[0];
32✔
630
            result.confirm("ipv4 family afi", ipv4_addr_family.afi() == family.afi(), true);
64✔
631
            result.test_eq("ipv4 family safi", ipv4_addr_family.safi(), family.safi());
32✔
632
            auto choice = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(family.addr_choice());
32✔
633

634
            if(!inherit_ipv4) {
32✔
635
               auto ranges = choice.ranges().value();
16✔
636
               if(push_ipv4_ranges) {
16✔
637
                  result.test_eq("ipv4 entry 0 min", ranges[0].min().value(), ipv4_range_1.min().value());
16✔
638
                  result.test_eq("ipv4 entry 0 max", ranges[0].max().value(), ipv4_range_1.max().value());
16✔
639
                  result.test_eq("ipv4 entry 1 min", ranges[1].min().value(), ipv4_range_2.min().value());
16✔
640
                  result.test_eq("ipv4 entry 1 max", ranges[1].max().value(), ipv4_range_2.max().value());
16✔
641
                  result.test_eq("ipv4 entry 2 min", ranges[2].min().value(), ipv4_range_3.min().value());
16✔
642
                  result.test_eq("ipv4 entry 2 max", ranges[2].max().value(), ipv4_range_3.max().value());
16✔
643
                  result.test_eq("ipv4 entry 3 min", ranges[3].min().value(), ipv4_range_4.min().value());
16✔
644
                  result.test_eq("ipv4 entry 3 max", ranges[3].max().value(), ipv4_range_4.max().value());
16✔
645
               } else {
646
                  result.confirm("ipv4 range has no entries", ranges.empty(), true);
16✔
647
               }
648
            } else {
16✔
649
               result.confirm("ipv4 family inherit", choice.ranges().has_value(), false);
32✔
650
            }
651
         }
64✔
652

653
         if(push_ipv6_family) {
48✔
654
            auto family = dec_addr_blocks[dec_addr_blocks.size() - 1];
32✔
655
            result.confirm("ipv6 family afi", ipv6_addr_family.afi() == family.afi(), true);
64✔
656
            result.test_eq("ipv6 family safi", ipv6_addr_family.safi(), family.safi());
32✔
657
            auto choice = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(family.addr_choice());
32✔
658
            if(!inherit_ipv6) {
32✔
659
               auto ranges = choice.ranges().value();
16✔
660
               if(push_ipv6_ranges) {
16✔
661
                  result.test_eq("ipv6 entry 0 min", ranges[0].min().value(), ipv6_range_1.min().value());
16✔
662
                  result.test_eq("ipv6 entry 0 max", ranges[0].max().value(), ipv6_range_1.max().value());
16✔
663
                  result.test_eq("ipv6 entry 1 min", ranges[1].min().value(), ipv6_range_2.min().value());
16✔
664
                  result.test_eq("ipv6 entry 1 max", ranges[1].max().value(), ipv6_range_2.max().value());
16✔
665
                  result.test_eq("ipv6 entry 2 min", ranges[2].min().value(), ipv6_range_3.min().value());
16✔
666
                  result.test_eq("ipv6 entry 2 max", ranges[2].max().value(), ipv6_range_3.max().value());
16✔
667
                  result.test_eq("ipv6 entry 3 min", ranges[3].min().value(), ipv6_range_4.min().value());
16✔
668
                  result.test_eq("ipv6 entry 3 max", ranges[3].max().value(), ipv6_range_4.max().value());
16✔
669
               } else {
670
                  result.confirm("ipv6 range has no entries", ranges.empty(), true);
16✔
671
               }
672
            } else {
16✔
673
               result.confirm("ipv6 family inherit", choice.ranges().has_value(), false);
32✔
674
            }
675
         }
64✔
676
      }
677
   }
320✔
678

679
   result.end_timer();
1✔
680
   return result;
2✔
681
}
2✔
682

683
Test::Result test_x509_ip_addr_blocks_extension_encode_edge_cases_ctor() {
1✔
684
   Test::Result result("X509 IP Address Block encode edge cases (ctor)");
1✔
685
   result.start_timer();
1✔
686

687
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
688

689
   auto rng = Test::new_rng(__func__);
1✔
690

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

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

697
   for(size_t i = 0; i < edge_values.size(); i++) {
22✔
698
      for(size_t j = 0; j < 4; j++) {
105✔
699
         bool modify_min = j & 1;
84✔
700
         bool modify_max = (j >> 1) & 1;
84✔
701

702
         for(size_t k = 0; k < 18; k++) {
1,219✔
703
            if(!modify_min && !modify_max && (k > 0 || i > 0)) {
1,156✔
704
               // we don't modify anything, this is the extreme edge case of 0.0 ... - 255.255. ...
705
               // so we only need to do this once
706
               break;
707
            }
708

709
            std::vector<uint8_t> min_bytes(16, 0x00);
1,135✔
710
            std::vector<uint8_t> max_bytes(16, 0xFF);
1,135✔
711

712
            if(modify_min) {
1,135✔
713
               min_bytes[15 - (k < 2 ? 0 : k - 2)] = edge_values[i];
756✔
714
            }
715
            if(modify_max) {
1,135✔
716
               max_bytes[15 - (k > 15 ? 15 : k)] = edge_values[i];
756✔
717
            }
718

719
            auto address_min = IPAddressBlocks::IPAddress<IPv6>(min_bytes);
1,135✔
720
            auto address_max = IPAddressBlocks::IPAddress<IPv6>(max_bytes);
1,135✔
721

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

724
            std::vector<IPAddressBlocks::IPAddressOrRange<IPv6>> ipv6_ranges;
1,135✔
725
            ipv6_ranges.push_back(ipv6_range);
1,135✔
726

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

729
            auto ipv6_addr_family = IPAddressBlocks::IPAddressFamily(ipv6_addr_choice);
3,405✔
730

731
            std::vector<IPAddressBlocks::IPAddressFamily> addr_blocks;
1,135✔
732
            addr_blocks.push_back(ipv6_addr_family);
1,135✔
733

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

736
            auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1,135✔
737
            Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1,135✔
738
            {
1,135✔
739
               const auto* ip_blocks = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1,135✔
740
               result.confirm("cert has IPAddrBlocks extension", ip_blocks != nullptr, true);
2,270✔
741
               const auto& dec_addr_blocks = ip_blocks->addr_blocks();
1,135✔
742
               auto family = dec_addr_blocks[0];
1,135✔
743
               result.confirm("ipv6 family afi", ipv6_addr_family.afi() == family.afi(), true);
2,270✔
744
               result.test_eq("ipv6 family safi", ipv6_addr_family.safi(), family.safi());
1,135✔
745
               auto choice = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(family.addr_choice());
1,135✔
746
               auto ranges = choice.ranges().value();
1,135✔
747

748
               result.test_eq("ipv6 edge case min", ranges[0].min().value(), ipv6_range.min().value());
2,270✔
749
               result.test_eq("ipv6 edge case max", ranges[0].max().value(), ipv6_range.max().value());
2,270✔
750
            }
2,270✔
751
         }
5,675✔
752
      }
753
   }
754
   result.end_timer();
1✔
755
   return result;
2✔
756
}
3✔
757

758
Test::Result test_x509_ip_addr_blocks_range_merge() {
1✔
759
   Test::Result result("X509 IP Address Block range merge");
1✔
760
   result.start_timer();
1✔
761

762
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
763

764
   auto rng = Test::new_rng(__func__);
1✔
765

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

768
   std::vector<std::vector<std::vector<uint8_t>>> addresses = {
1✔
769
      {{11, 0, 0, 0}, {{11, 0, 0, 0}}},
770
      {{123, 123, 123, 123}, {123, 123, 123, 123}},
771
      {{10, 4, 5, 9}, {{10, 255, 0, 0}}},
772
      {{12, 0, 0, 0}, {191, 0, 0, 1}},
773
      {{190, 0, 0, 0}, {193, 0, 255, 255}},
774
      {{10, 10, 10, 10}, {10, 20, 20, 20}},
775
      {{5, 0, 0, 0}, {10, 255, 255, 255}},
776
      {{192, 0, 0, 0}, {192, 255, 255, 255}},
777
      {{11, 0, 0, 1}, {11, 255, 255, 255}},
778
   };
46✔
779

780
   std::vector<IPAddressBlocks::IPAddressOrRange<IPv4>> ipv6_ranges;
1✔
781
   for(auto pair : addresses) {
10✔
782
      auto address_min = IPAddressBlocks::IPAddress<IPv4>(pair[0]);
9✔
783
      auto address_max = IPAddressBlocks::IPAddress<IPv4>(pair[1]);
9✔
784
      auto range = IPAddressBlocks::IPAddressOrRange<IPv4>(address_min, address_max);
9✔
785
      ipv6_ranges.push_back(range);
9✔
786
   }
9✔
787

788
   auto ipv6_addr_choice = IPAddressBlocks::IPAddressChoice<IPv4>(ipv6_ranges);
1✔
789
   auto ipv6_addr_family = IPAddressBlocks::IPAddressFamily(ipv6_addr_choice);
3✔
790

791
   std::vector<IPAddressBlocks::IPAddressFamily> addr_blocks;
1✔
792
   addr_blocks.push_back(ipv6_addr_family);
1✔
793

794
   std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>(addr_blocks);
1✔
795

796
   auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1✔
797
   Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1✔
798
   {
1✔
799
      const auto* ip_blocks = cert.v3_extensions().get_extension_object_as<IPAddressBlocks>();
1✔
800
      result.confirm("cert has IPAddrBlocks extension", ip_blocks != nullptr, true);
2✔
801
      const auto& dec_addr_blocks = ip_blocks->addr_blocks();
1✔
802
      auto family = dec_addr_blocks[0];
1✔
803
      auto choice = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(family.addr_choice());
1✔
804
      auto ranges = choice.ranges().value();
1✔
805

806
      std::array<uint8_t, 4> expected_min = {5, 0, 0, 0};
1✔
807
      std::array<uint8_t, 4> expected_max = {193, 0, 255, 255};
1✔
808

809
      result.test_eq("range expected min", ranges[0].min().value(), expected_min);
2✔
810
      result.test_eq("range expected max", ranges[0].max().value(), expected_max);
2✔
811
      result.test_eq("range length", ranges.size(), 1);
1✔
812
   }
2✔
813

814
   result.end_timer();
1✔
815
   return result;
2✔
816
}
24✔
817

818
Test::Result test_x509_ip_addr_blocks_family_merge() {
1✔
819
   Test::Result result("X509 IP Address Block family merge");
1✔
820
   result.start_timer();
1✔
821

822
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
823

824
   auto rng = Test::new_rng(__func__);
1✔
825

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

828
   std::vector<IPAddressBlocks::IPAddressFamily> addr_blocks;
1✔
829

830
   IPAddressBlocks::IPAddressChoice<IPv4> v4_empty_choice;
1✔
831
   IPAddressBlocks::IPAddressChoice<IPv6> v6_empty_choice;
1✔
832

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

837
   std::vector<IPAddressBlocks::IPAddressOrRange<IPv4>> v4_choice_vec{
1✔
838
      IPAddressBlocks::IPAddressOrRange<IPv4>(IPAddressBlocks::IPAddress<IPv4>({v4_addr_1}))};
1✔
839
   IPAddressBlocks::IPAddressChoice<IPv4> v4_choice_dupl(v4_choice_vec);
1✔
840
   result.confirm(
2✔
841
      "IPAddressChoice v4 merges ranges already in constructor", v4_choice_dupl.ranges().value().size() == 1, true);
1✔
842
   IPAddressBlocks::IPAddressFamily v4_fam_dupl(v4_choice_dupl, 0);
3✔
843

844
   uint8_t v6_bytes_1[16] = {123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123};
1✔
845
   IPAddressBlocks::IPAddress<IPv6> v6_addr_1(v6_bytes_1);
1✔
846

847
   std::vector<IPAddressBlocks::IPAddressOrRange<IPv6>> v6_choice_vec{
1✔
848
      IPAddressBlocks::IPAddressOrRange<IPv6>(IPAddressBlocks::IPAddress<IPv6>({v6_addr_1}))};
1✔
849
   IPAddressBlocks::IPAddressChoice<IPv6> v6_choice_dupl(v6_choice_vec);
1✔
850
   result.confirm(
2✔
851
      "IPAddressChoice v6 merges already in constructor", v6_choice_dupl.ranges().value().size() == 1, true);
1✔
852
   IPAddressBlocks::IPAddressFamily v6_fam_dupl(v6_choice_dupl, 0);
3✔
853

854
   IPAddressBlocks::IPAddressFamily v4_empty_fam(v4_empty_choice);
2✔
855
   IPAddressBlocks::IPAddressFamily v6_empty_fam(v6_empty_choice);
2✔
856

857
   IPAddressBlocks::IPAddressFamily v4_empty_fam_safi(v4_empty_choice, 2);
2✔
858
   IPAddressBlocks::IPAddressFamily v6_empty_fam_safi(v6_empty_choice, 2);
2✔
859

860
   /*
861
   considering the push order, the resulting order should be
862
   [0] v4 no safi
863
   [2] v4 safi
864
   [1] v6 no safi
865
   [3] v6 safi
866
   */
867
   for(size_t i = 0; i < 3; i++) {
4✔
868
      addr_blocks.push_back(v4_empty_fam_safi);
3✔
869
      addr_blocks.push_back(v6_empty_fam);
3✔
870
      addr_blocks.push_back(v4_fam_dupl);
3✔
871
      addr_blocks.push_back(v6_empty_fam_safi);
3✔
872
      addr_blocks.push_back(v6_fam_dupl);
3✔
873
      addr_blocks.push_back(v4_empty_fam);
3✔
874
   }
875

876
   std::vector<IPAddressBlocks::IPAddressFamily> expected_blocks = {
1✔
877
      v4_empty_fam, v4_fam_dupl, v4_empty_fam_safi, v6_empty_fam, v6_fam_dupl, v6_empty_fam_safi};
7✔
878

879
   std::unique_ptr<IPAddressBlocks> blocks = std::make_unique<IPAddressBlocks>(addr_blocks);
1✔
880

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

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

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

890
   bool sorted = true;
1✔
891
   for(size_t i = 0; i < dec_blocks.size() - 1; i++) {
6✔
892
      const IPAddressBlocks::IPAddressFamily& a = dec_blocks[i];
5✔
893
      const IPAddressBlocks::IPAddressFamily& b = dec_blocks[i + 1];
5✔
894

895
      uint32_t afam_a = a.afi();
5✔
896
      if(a.safi().has_value()) {
5✔
897
         afam_a = static_cast<uint32_t>(afam_a << 8) | a.safi().value();
3✔
898
      } else {
899
         afam_a = static_cast<uint32_t>(afam_a << 8);
2✔
900
      }
901

902
      uint32_t afam_b = b.afi();
5✔
903
      if(b.safi().has_value()) {
5✔
904
         afam_b = static_cast<uint32_t>(afam_b << 8) | b.safi().value();
4✔
905
      } else {
906
         afam_b = static_cast<uint32_t>(afam_b << 8);
1✔
907
      }
908

909
      if(afam_a > afam_b) {
5✔
910
         sorted = false;
911
         break;
912
      }
913
   }
914

915
   result.confirm("blocks got sorted", sorted, true);
2✔
916

917
   for(size_t i = 0; i < dec_blocks.size(); i++) {
7✔
918
      const IPAddressBlocks::IPAddressFamily& dec = dec_blocks[i];
6✔
919
      const IPAddressBlocks::IPAddressFamily& exp = expected_blocks[i];
6✔
920

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

924
      if((exp.afi() == 1) && (dec.afi() == 1)) {
6✔
925
         auto dec_choice = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(dec.addr_choice());
3✔
926
         auto exp_choice = std::get<IPAddressBlocks::IPAddressChoice<IPv4>>(exp.addr_choice());
3✔
927

928
         if(!exp_choice.ranges().has_value()) {
3✔
929
            result.confirm(
2✔
930
               "block ranges should inherit at index " + std::to_string(i), dec_choice.ranges().has_value(), false);
6✔
931
         } else {
932
            result.confirm(
1✔
933
               "block ranges should not inherit at index " + std::to_string(i), dec_choice.ranges().has_value(), true);
3✔
934

935
            if(dec_choice.ranges().has_value() == false) {
1✔
936
               continue;
×
937
            }
938

939
            auto dec_ranges = dec_choice.ranges().value();
1✔
940
            auto exp_ranges = exp_choice.ranges().value();
1✔
941
            result.confirm("block ranges got merged lengthwise at index " + std::to_string(i),
2✔
942
                           dec_ranges.size() == exp_ranges.size(),
1✔
943
                           true);
944

945
            if(dec_ranges.size() != exp_ranges.size()) {
1✔
946
               continue;
×
947
            }
948

949
            for(size_t j = 0; j < exp_ranges.size(); j++) {
2✔
950
               result.test_eq(
2✔
951
                  "block ranges min got merged valuewise at indices " + std::to_string(i) + "," + std::to_string(j),
4✔
952
                  exp_ranges[j].min().value(),
1✔
953
                  dec_ranges[j].min().value());
1✔
954
               result.test_eq(
2✔
955
                  "block ranges max got merged valuewise at indices " + std::to_string(i) + "," + std::to_string(j),
4✔
956
                  exp_ranges[j].max().value(),
1✔
957
                  dec_ranges[j].max().value());
2✔
958
            }
959
         }
1✔
960
      } else if((exp.afi() == 2) && (dec.afi() == 2)) {
7✔
961
         auto dec_choice = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(dec.addr_choice());
3✔
962
         auto exp_choice = std::get<IPAddressBlocks::IPAddressChoice<IPv6>>(exp.addr_choice());
3✔
963

964
         if(!exp_choice.ranges().has_value()) {
3✔
965
            result.confirm(
2✔
966
               "block ranges should inherit at index " + std::to_string(i), dec_choice.ranges().has_value(), false);
6✔
967
         } else {
968
            result.confirm(
1✔
969
               "block ranges should not inherit at index " + std::to_string(i), dec_choice.ranges().has_value(), true);
3✔
970

971
            if(dec_choice.ranges().has_value() == false) {
1✔
972
               continue;
×
973
            }
974

975
            auto dec_ranges = dec_choice.ranges().value();
1✔
976
            auto exp_ranges = exp_choice.ranges().value();
1✔
977
            result.confirm("block ranges got merged lengthwise at index " + std::to_string(i),
2✔
978
                           dec_ranges.size() == exp_ranges.size(),
1✔
979
                           true);
980

981
            if(dec_ranges.size() != exp_ranges.size()) {
1✔
982
               continue;
×
983
            }
984

985
            for(size_t j = 0; j < exp_ranges.size(); j++) {
2✔
986
               result.test_eq(
2✔
987
                  "block ranges min got merged valuewise at indices " + std::to_string(i) + "," + std::to_string(j),
4✔
988
                  exp_ranges[j].min().value(),
1✔
989
                  dec_ranges[j].min().value());
1✔
990
               result.test_eq(
2✔
991
                  "block ranges max got merged valuewise at indices " + std::to_string(i) + "," + std::to_string(j),
4✔
992
                  exp_ranges[j].max().value(),
1✔
993
                  dec_ranges[j].max().value());
2✔
994
            }
995
         }
1✔
996
      }
4✔
997
   }
998

999
   result.end_timer();
1✔
1000
   return result;
2✔
1001
}
19✔
1002

1003
Test::Result test_x509_ip_addr_blocks_path_validation_success_builder() {
1✔
1004
   Test::Result result("X509 IP Address Blocks path validation success (builder)");
1✔
1005
   result.start_timer();
1✔
1006

1007
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
1008
   auto rng = Test::new_rng(__func__);
1✔
1009

1010
   /*
1011
   Creates a certificate chain of length 4.
1012
   Root: ipv4 and ipv6
1013
   Inherit: has both values as 'inherit'
1014
   Dynamic: has either both 'inherit', both with values, or just one with a value
1015
   Subject: both ipv4 and ipv6 as a subset of Root / Dynamic
1016
   */
1017

1018
   // Root cert
1019
   std::unique_ptr<IPAddressBlocks> root_blocks = std::make_unique<IPAddressBlocks>();
1✔
1020

1021
   root_blocks->add_address<IPv4>({120, 0, 0, 1}, {130, 140, 150, 160}, 42);
1✔
1022
   root_blocks->add_address<IPv4>({10, 0, 0, 1}, {10, 255, 255, 255}, 42);
1✔
1023

1024
   root_blocks->add_address<IPv6>(
1✔
1025
      {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
1026
      {0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
1027
   root_blocks->add_address<IPv6>(
1✔
1028
      {0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
1029
      {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF});
1030

1031
   // Inherit cert
1032
   std::unique_ptr<IPAddressBlocks> inherit_blocks = std::make_unique<IPAddressBlocks>();
1✔
1033

1034
   inherit_blocks->inherit<IPv4>(42);
1✔
1035
   inherit_blocks->inherit<IPv6>();
1✔
1036

1037
   // Subject cert
1038
   std::unique_ptr<IPAddressBlocks> sub_blocks = std::make_unique<IPAddressBlocks>();
1✔
1039

1040
   sub_blocks->add_address<IPv4>({124, 0, 255, 0}, {126, 0, 0, 1}, 42);
1✔
1041
   sub_blocks->add_address<IPv4>({10, 0, 2, 1}, {10, 42, 0, 255}, 42);
1✔
1042

1043
   sub_blocks->add_address<IPv6>(
1✔
1044
      {0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
1045
      {0x0D, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
1046

1047
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
1✔
1048
      make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
2✔
1049
   auto [inherit_cert, inherit_ca] = make_and_sign_ca(std::move(inherit_blocks), root_ca, *rng);
2✔
1050

1051
   Botan::Certificate_Store_In_Memory trusted;
1✔
1052
   trusted.add_certificate(root_cert);
1✔
1053

1054
   for(size_t i = 0; i < 4; i++) {
5✔
1055
      bool include_v4 = i & 1;
4✔
1056
      bool include_v6 = (i >> 1) & 1;
4✔
1057

1058
      // Dynamic Cert
1059
      std::unique_ptr<IPAddressBlocks> dyn_blocks = std::make_unique<IPAddressBlocks>();
4✔
1060
      if(include_v4) {
4✔
1061
         dyn_blocks->add_address<IPv4>({122, 0, 0, 255}, {128, 255, 255, 255}, 42);
2✔
1062
         dyn_blocks->add_address<IPv4>({10, 0, 0, 255}, {10, 255, 0, 1}, 42);
2✔
1063
      } else {
1064
         dyn_blocks->inherit<IPv4>(42);
2✔
1065
      }
1066

1067
      if(include_v6) {
4✔
1068
         dyn_blocks->add_address<IPv6>(
2✔
1069
            {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF},
1070
            {0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
1071
      } else {
1072
         dyn_blocks->inherit<IPv6>();
2✔
1073
      }
1074

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

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

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

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

1084
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
4✔
1085
      result.require("path validation succeeds", path_result.successful_validation());
4✔
1086
   }
8✔
1087

1088
   result.end_timer();
1✔
1089
   return result;
2✔
1090
}
7✔
1091

1092
Test::Result test_x509_ip_addr_blocks_path_validation_success_ctor() {
1✔
1093
   Test::Result result("X509 IP Address Block path validation success (ctor)");
1✔
1094
   result.start_timer();
1✔
1095

1096
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
1097
   auto rng = Test::new_rng(__func__);
1✔
1098

1099
   /*
1100
   Creates a certificate chain of length 4.
1101
   Root: ipv4 and ipv6
1102
   Inherit: has both values as 'inherit'
1103
   Dynamic: has either both 'inherit', both with values, or just one with a value
1104
   Subject: both ipv4 and ipv6 as a subset of Root / Dynamic
1105
   */
1106

1107
   // Root cert
1108
   std::vector<uint8_t> a = {120, 0, 0, 1};
1✔
1109
   auto root_ipv4_range_1_min = IPAddressBlocks::IPAddress<IPv4>{a};
1✔
1110
   a = {130, 140, 150, 160};
1✔
1111
   auto root_ipv4_range_1_max = IPAddressBlocks::IPAddress<IPv4>{a};
1✔
1112

1113
   a = {10, 0, 0, 1};
1✔
1114
   auto root_ipv4_range_2_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1115
   a = {10, 255, 255, 255};
1✔
1116
   auto root_ipv4_range_2_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1117

1118
   a = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1119
   auto root_ipv6_range_1_min = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1120
   a = {0xA0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1✔
1121
   auto root_ipv6_range_1_max = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1122

1123
   a = {0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1124
   auto root_ipv6_range_2_min = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1125
   a = {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1✔
1126
   auto root_ipv6_range_2_max = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1127

1128
   auto root_ipv4_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(root_ipv4_range_1_min, root_ipv4_range_1_max);
1✔
1129
   auto root_ipv4_range_2 = IPAddressBlocks::IPAddressOrRange<IPv4>(root_ipv4_range_2_min, root_ipv4_range_2_max);
1✔
1130
   auto root_ipv6_range_1 = IPAddressBlocks::IPAddressOrRange<IPv6>(root_ipv6_range_1_min, root_ipv6_range_1_max);
1✔
1131
   auto root_ipv6_range_2 = IPAddressBlocks::IPAddressOrRange<IPv6>(root_ipv6_range_2_min, root_ipv6_range_2_max);
1✔
1132

1133
   auto root_ipv4_ranges = {root_ipv4_range_1, root_ipv4_range_2};
1✔
1134
   auto root_ipv6_ranges = {root_ipv6_range_1, root_ipv6_range_2};
1✔
1135

1136
   auto root_ipv4_choice = IPAddressBlocks::IPAddressChoice<IPv4>(root_ipv4_ranges);
1✔
1137
   auto root_ipv6_choice = IPAddressBlocks::IPAddressChoice<IPv6>(root_ipv6_ranges);
1✔
1138

1139
   auto root_ipv4_family = IPAddressBlocks::IPAddressFamily(root_ipv4_choice, 42);
3✔
1140
   auto root_ipv6_family = IPAddressBlocks::IPAddressFamily(root_ipv6_choice);
3✔
1141

1142
   auto root_addr_blocks = {root_ipv4_family, root_ipv6_family};
6✔
1143
   std::unique_ptr<IPAddressBlocks> root_blocks = std::make_unique<IPAddressBlocks>(root_addr_blocks);
1✔
1144

1145
   // Inherit cert
1146
   auto inherit_ipv4_choice = IPAddressBlocks::IPAddressChoice<IPv4>();
1✔
1147
   auto inherit_ipv6_choice = IPAddressBlocks::IPAddressChoice<IPv6>();
1✔
1148

1149
   auto inherit_ipv4_family = IPAddressBlocks::IPAddressFamily(inherit_ipv4_choice, 42);
2✔
1150
   auto inherit_ipv6_family = IPAddressBlocks::IPAddressFamily(inherit_ipv6_choice);
2✔
1151

1152
   auto inherit_addr_blocks = {inherit_ipv4_family, inherit_ipv6_family};
6✔
1153
   std::unique_ptr<IPAddressBlocks> inherit_blocks = std::make_unique<IPAddressBlocks>(inherit_addr_blocks);
1✔
1154

1155
   // Dynamic Cert
1156
   a = {122, 0, 0, 255};
1✔
1157
   auto dyn_ipv4_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1158
   a = {128, 255, 255, 255};
1✔
1159
   auto dyn_ipv4_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1160
   a = {10, 0, 0, 255};
1✔
1161
   auto dyn_ipv4_range_2_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1162
   a = {10, 255, 0, 1};
1✔
1163
   auto dyn_ipv4_range_2_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1164

1165
   a = {0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1✔
1166
   auto dyn_ipv6_range_1_min = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1167
   a = {0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1168
   auto dyn_ipv6_range_1_max = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1169

1170
   auto dyn_ipv4_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(dyn_ipv4_range_1_min, dyn_ipv4_range_1_max);
1✔
1171
   auto dyn_ipv4_range_2 = IPAddressBlocks::IPAddressOrRange<IPv4>(dyn_ipv4_range_2_min, dyn_ipv4_range_2_max);
1✔
1172
   auto dyn_ipv6_range = IPAddressBlocks::IPAddressOrRange<IPv6>(dyn_ipv6_range_1_min, dyn_ipv6_range_1_max);
1✔
1173

1174
   auto dyn_ipv4_ranges = {dyn_ipv4_range_1, dyn_ipv4_range_2};
1✔
1175
   auto dyn_ipv6_ranges = {dyn_ipv6_range};
1✔
1176

1177
   // Subject cert
1178
   a = {124, 0, 255, 0};
1✔
1179
   auto sub_ipv4_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1180
   a = {126, 0, 0, 1};
1✔
1181
   auto sub_ipv4_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1182

1183
   a = {10, 0, 2, 1};
1✔
1184
   auto sub_ipv4_range_2_min = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1185
   a = {10, 42, 0, 255};
1✔
1186
   auto sub_ipv4_range_2_max = IPAddressBlocks::IPAddress<IPv4>(a);
1✔
1187

1188
   a = {0x00, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1189
   auto sub_ipv6_range_1_min = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1190
   a = {0x0D, 0x00, 0x00, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
1✔
1191
   auto sub_ipv6_range_1_max = IPAddressBlocks::IPAddress<IPv6>(a);
1✔
1192

1193
   auto sub_ipv4_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(sub_ipv4_range_1_min, sub_ipv4_range_1_max);
1✔
1194
   auto sub_ipv4_range_2 = IPAddressBlocks::IPAddressOrRange<IPv4>(sub_ipv4_range_2_min, sub_ipv4_range_2_max);
1✔
1195
   auto sub_ipv6_range = IPAddressBlocks::IPAddressOrRange<IPv6>(sub_ipv6_range_1_min, sub_ipv6_range_1_max);
1✔
1196

1197
   auto sub_ipv4_ranges = {sub_ipv4_range_1, sub_ipv4_range_2};
1✔
1198
   auto sub_ipv6_ranges = {sub_ipv6_range};
1✔
1199

1200
   auto sub_ipv4_choice = IPAddressBlocks::IPAddressChoice<IPv4>(sub_ipv4_ranges);
1✔
1201
   auto sub_ipv6_choice = IPAddressBlocks::IPAddressChoice<IPv6>(sub_ipv6_ranges);
1✔
1202

1203
   auto sub_ipv4_family = IPAddressBlocks::IPAddressFamily(sub_ipv4_choice, 42);
3✔
1204
   auto sub_ipv6_family = IPAddressBlocks::IPAddressFamily(sub_ipv6_choice);
3✔
1205

1206
   auto sub_addr_blocks = {sub_ipv4_family, sub_ipv6_family};
6✔
1207
   std::unique_ptr<IPAddressBlocks> sub_blocks = std::make_unique<IPAddressBlocks>(sub_addr_blocks);
1✔
1208

1209
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
1✔
1210
      make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
2✔
1211
   auto [inherit_cert, inherit_ca] = make_and_sign_ca(std::move(inherit_blocks), root_ca, *rng);
2✔
1212

1213
   Botan::Certificate_Store_In_Memory trusted;
1✔
1214
   trusted.add_certificate(root_cert);
1✔
1215

1216
   for(size_t i = 0; i < 4; i++) {
5✔
1217
      bool include_v4 = i & 1;
4✔
1218
      bool include_v6 = (i >> 1) & 1;
4✔
1219

1220
      auto dyn_ipv4_choice =
4✔
1221
         IPAddressBlocks::IPAddressChoice<IPv4>(include_v4 ? std::optional(dyn_ipv4_ranges) : std::nullopt);
8✔
1222
      auto dyn_ipv6_choice =
4✔
1223
         IPAddressBlocks::IPAddressChoice<IPv6>(include_v6 ? std::optional(dyn_ipv6_ranges) : std::nullopt);
8✔
1224

1225
      auto dyn_ipv4_family = IPAddressBlocks::IPAddressFamily(dyn_ipv4_choice, 42);
10✔
1226
      auto dyn_ipv6_family = IPAddressBlocks::IPAddressFamily(dyn_ipv6_choice);
10✔
1227

1228
      auto dyn_addr_blocks = {dyn_ipv4_family, dyn_ipv6_family};
24✔
1229
      std::unique_ptr<IPAddressBlocks> dyn_blocks = std::make_unique<IPAddressBlocks>(dyn_addr_blocks);
4✔
1230

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

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

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

1239
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
4✔
1240
      result.require("path validation succeeds", path_result.successful_validation());
4✔
1241
   }
28✔
1242

1243
   result.end_timer();
1✔
1244
   return result;
2✔
1245
}
25✔
1246

1247
Test::Result test_x509_ip_addr_blocks_path_validation_failure_builder() {
1✔
1248
   Test::Result result("X509 IP Address Blocks path validation failure (builder)");
1✔
1249
   result.start_timer();
1✔
1250

1251
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
1252
   auto rng = Test::new_rng(__func__);
1✔
1253

1254
   for(size_t i = 0; i < 7; i++) {
8✔
1255
      bool all_inherit = (i == 0);
7✔
1256
      bool different_safi = (i == 1);
7✔
1257
      bool too_small_subrange = (i == 2);
7✔
1258
      bool too_large_subrange = (i == 3);
7✔
1259
      bool no_more_issuer_ranges = (i == 4);
7✔
1260
      bool empty_issuer_ranges = (i == 5);
7✔
1261
      bool nullptr_extensions = (i == 6);
7✔
1262

1263
      // Root cert
1264
      std::unique_ptr<IPAddressBlocks> root_blocks = std::make_unique<IPAddressBlocks>();
7✔
1265
      if(!all_inherit) {
7✔
1266
         root_blocks->add_address<IPv4>({120, 0, 0, 1}, {130, 140, 150, 160}, 42);
6✔
1267
      } else {
1268
         root_blocks->inherit<IPv4>(42);
1✔
1269
      }
1270

1271
      auto root_params = ca_params();
7✔
1272
      if(!nullptr_extensions) {
7✔
1273
         root_params.add_extension(std::move(root_blocks));
12✔
1274
      }
1275
      auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] = make_ca(*rng, root_params);
7✔
1276

1277
      // Issuer Cert
1278
      std::unique_ptr<IPAddressBlocks> iss_blocks = std::make_unique<IPAddressBlocks>();
7✔
1279
      if(!all_inherit) {
7✔
1280
         if(empty_issuer_ranges) {
6✔
1281
            iss_blocks->restrict<IPv4>(42);
1✔
1282
         } else {
1283
            iss_blocks->add_address<IPv4>({122, 0, 0, 255}, {128, 255, 255, 255}, 42);
5✔
1284
         }
1285
      } else {
1286
         iss_blocks->inherit<IPv4>(42);
1✔
1287
      }
1288

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

1291
      // Subject cert
1292
      std::unique_ptr<IPAddressBlocks> sub_blocks = std::make_unique<IPAddressBlocks>();
7✔
1293

1294
      uint8_t safi = different_safi ? 41 : 42;
7✔
1295

1296
      if(!all_inherit) {
7✔
1297
         if(too_small_subrange) {
6✔
1298
            sub_blocks->add_address<IPv4>({118, 0, 255, 0}, {126, 0, 0, 1}, safi);
1✔
1299
         } else if(too_large_subrange) {
5✔
1300
            sub_blocks->add_address<IPv4>({124, 0, 255, 0}, {134, 0, 0, 1}, safi);
1✔
1301
         } else if(no_more_issuer_ranges) {
4✔
1302
            sub_blocks->add_address<IPv4>({140, 0, 0, 1}, {150, 0, 0, 1}, safi);
1✔
1303
         } else {
1304
            sub_blocks->add_address<IPv4>({124, 0, 255, 0}, {126, 0, 0, 1}, safi);
3✔
1305
         }
1306
      } else {
1307
         sub_blocks->inherit<IPv4>(safi);
1✔
1308
      }
1309

1310
      auto sub_req = user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
7✔
1311
      Botan::X509_Certificate sub_cert =
7✔
1312
         iss_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
7✔
1313

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

1317
      Botan::Certificate_Store_In_Memory trusted;
7✔
1318
      trusted.add_certificate(root_cert);
7✔
1319

1320
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
7✔
1321
      result.require("path validation fails", !path_result.successful_validation());
7✔
1322
   }
15✔
1323

1324
   result.end_timer();
1✔
1325
   return result;
1✔
1326
}
8✔
1327

1328
Test::Result test_x509_ip_addr_blocks_path_validation_failure_ctor() {
1✔
1329
   Test::Result result("X509 IP Address Block path validation failure (ctor)");
1✔
1330
   result.start_timer();
1✔
1331

1332
   using Botan::Cert_Extension::IPAddressBlocks;
1✔
1333
   auto rng = Test::new_rng(__func__);
1✔
1334

1335
   for(size_t i = 0; i < 7; i++) {
8✔
1336
      bool all_inherit = (i == 0);
7✔
1337
      bool different_safi = (i == 1);
7✔
1338
      bool too_small_subrange = (i == 2);
7✔
1339
      bool too_large_subrange = (i == 3);
7✔
1340
      bool no_more_issuer_ranges = (i == 4);
7✔
1341
      bool empty_issuer_ranges = (i == 5);
7✔
1342
      bool nullptr_extensions = (i == 6);
7✔
1343

1344
      // Root cert
1345
      std::vector<uint8_t> a = {120, 0, 0, 1};
7✔
1346
      auto root_range_1_min = IPAddressBlocks::IPAddress<IPv4>{a};
7✔
1347
      a = {130, 140, 150, 160};
7✔
1348
      auto root_range_1_max = IPAddressBlocks::IPAddress<IPv4>{a};
7✔
1349

1350
      auto root_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(root_range_1_min, root_range_1_max);
7✔
1351
      auto root_ranges = {root_range_1};
7✔
1352
      auto root_choice =
7✔
1353
         IPAddressBlocks::IPAddressChoice<IPv4>(all_inherit ? std::nullopt : std::optional(root_ranges));
14✔
1354
      auto root_family = IPAddressBlocks::IPAddressFamily(root_choice, 42);
20✔
1355
      auto root_addr_blocks = {root_family};
21✔
1356
      std::unique_ptr<IPAddressBlocks> root_blocks = std::make_unique<IPAddressBlocks>(root_addr_blocks);
7✔
1357

1358
      auto root_params = ca_params();
7✔
1359
      if(!nullptr_extensions) {
7✔
1360
         root_params.add_extension(std::move(root_blocks));
12✔
1361
      }
1362
      auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] = make_ca(*rng, root_params);
7✔
1363

1364
      // Issuer Cert
1365
      a = {122, 0, 0, 255};
7✔
1366
      auto iss_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
7✔
1367
      a = {128, 255, 255, 255};
7✔
1368
      auto iss_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
7✔
1369
      auto iss_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(iss_range_1_min, iss_range_1_max);
7✔
1370

1371
      std::vector<IPAddressBlocks::IPAddressOrRange<IPv4>> iss_ranges;
7✔
1372

1373
      if(!empty_issuer_ranges) {
7✔
1374
         iss_ranges.push_back(iss_range_1);
6✔
1375
      }
1376

1377
      auto iss_choice = IPAddressBlocks::IPAddressChoice<IPv4>(all_inherit ? std::nullopt : std::optional(iss_ranges));
19✔
1378
      auto iss_family = IPAddressBlocks::IPAddressFamily(iss_choice, 42);
20✔
1379
      auto iss_addr_blocks = {iss_family};
21✔
1380
      std::unique_ptr<IPAddressBlocks> iss_blocks = std::make_unique<IPAddressBlocks>(iss_addr_blocks);
7✔
1381
      auto [iss_cert, iss_ca] = make_and_sign_ca(std::move(iss_blocks), root_ca, *rng);
14✔
1382

1383
      // Subject cert
1384
      if(too_small_subrange) {
7✔
1385
         a = {118, 0, 255, 0};
2✔
1386
      } else if(no_more_issuer_ranges) {
6✔
1387
         a = {140, 0, 0, 1};
2✔
1388
      } else {
1389
         a = {124, 0, 255, 0};
10✔
1390
      }
1391

1392
      auto sub_range_1_min = IPAddressBlocks::IPAddress<IPv4>(a);
7✔
1393
      if(too_large_subrange) {
7✔
1394
         a = {134, 0, 0, 1};
2✔
1395
      } else if(no_more_issuer_ranges) {
6✔
1396
         a = {150, 0, 0, 1};
2✔
1397
      } else {
1398
         a = {126, 0, 0, 1};
10✔
1399
      }
1400
      auto sub_range_1_max = IPAddressBlocks::IPAddress<IPv4>(a);
7✔
1401

1402
      auto sub_range_1 = IPAddressBlocks::IPAddressOrRange<IPv4>(sub_range_1_min, sub_range_1_max);
7✔
1403
      auto sub_ranges = {sub_range_1};
7✔
1404
      auto sub_choice = IPAddressBlocks::IPAddressChoice<IPv4>(all_inherit ? std::nullopt : std::optional(sub_ranges));
14✔
1405
      auto sub_family = IPAddressBlocks::IPAddressFamily(sub_choice, different_safi ? 41 : 42);
26✔
1406

1407
      auto sub_addr_blocks = {sub_family};
21✔
1408
      std::unique_ptr<IPAddressBlocks> sub_blocks = std::make_unique<IPAddressBlocks>(sub_addr_blocks);
7✔
1409

1410
      auto sub_req = user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
7✔
1411
      Botan::X509_Certificate sub_cert =
7✔
1412
         iss_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
7✔
1413

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

1417
      Botan::Certificate_Store_In_Memory trusted;
7✔
1418
      trusted.add_certificate(root_cert);
7✔
1419

1420
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
7✔
1421
      result.require("path validation fails", !path_result.successful_validation());
7✔
1422
   }
82✔
1423

1424
   result.end_timer();
1✔
1425
   return result;
1✔
1426
}
8✔
1427

1428
Test::Result test_x509_as_blocks_rfc3779_example() {
1✔
1429
   Test::Result result("X509 AS Blocks rfc3779 example");
1✔
1430
   result.start_timer();
1✔
1431

1432
   using Botan::Cert_Extension::ASBlocks;
1✔
1433
   auto rng = Test::new_rng(__func__);
1✔
1434

1435
   // construct like in https://datatracker.ietf.org/doc/html/rfc3779#page-21
1436
   std::unique_ptr<ASBlocks> blocks = std::make_unique<ASBlocks>();
1✔
1437
   blocks->add_asnum(135);
1✔
1438
   blocks->add_asnum(3000, 3999);
1✔
1439
   blocks->add_asnum(5001);
1✔
1440
   blocks->inherit_rdi();
1✔
1441

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

1445
   result.test_eq(
1✔
1446
      "extension is encoded as specified", bits, "301AA014301202020087300802020BB802020F9F02021389A1020500");
1447

1448
   auto as_idents = cert.v3_extensions().get_extension_object_as<ASBlocks>()->as_identifiers();
1✔
1449
   auto as_ids = as_idents.asnum().value().ranges().value();
1✔
1450

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

1453
   result.end_timer();
1✔
1454
   return result;
2✔
1455
}
3✔
1456

1457
Test::Result test_x509_as_blocks_encode_builder() {
1✔
1458
   Test::Result result("X509 IP Address Blocks encode (builder)");
1✔
1459
   result.start_timer();
1✔
1460

1461
   using Botan::Cert_Extension::ASBlocks;
1✔
1462
   auto rng = Test::new_rng(__func__);
1✔
1463

1464
   std::unique_ptr<ASBlocks> blocks = std::make_unique<ASBlocks>();
1✔
1465

1466
   blocks->add_rdi(10);
1✔
1467
   blocks->add_rdi(20, 30);
1✔
1468
   blocks->add_rdi(42, 300);
1✔
1469
   blocks->add_rdi(9, 301);
1✔
1470

1471
   blocks->inherit_asnum();
1✔
1472
   blocks->add_asnum(20);
1✔
1473
   // this overwrites the previous two
1474
   blocks->restrict_asnum();
1✔
1475

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

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

1481
   result.end_timer();
1✔
1482
   return result;
1✔
1483
}
2✔
1484

1485
Test::Result test_x509_as_blocks_extension_encode_ctor() {
1✔
1486
   Test::Result result("X509 AS Blocks encode (ctor)");
1✔
1487
   result.start_timer();
1✔
1488

1489
   using Botan::Cert_Extension::ASBlocks;
1✔
1490

1491
   auto rng = Test::new_rng(__func__);
1✔
1492

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

1495
   for(size_t i = 0; i < 16; i++) {
17✔
1496
      bool push_asnum = i & 1;
16✔
1497
      bool push_rdi = (i >> 1) & 1;
16✔
1498
      bool include_asnum = (i >> 2) & 1;
16✔
1499
      bool include_rdi = (i >> 3) & 1;
16✔
1500
      if(!include_asnum && !include_rdi) {
16✔
1501
         continue;
4✔
1502
      }
1503

1504
      ASBlocks::ASIdOrRange asnum_id_or_range0 = ASBlocks::ASIdOrRange(0, 999);
12✔
1505
      ASBlocks::ASIdOrRange asnum_id_or_range1 = ASBlocks::ASIdOrRange(5042);
12✔
1506
      ASBlocks::ASIdOrRange asnum_id_or_range2 = ASBlocks::ASIdOrRange(5043, 4294967295);
12✔
1507

1508
      ASBlocks::ASIdOrRange rdi_id_or_range0 = ASBlocks::ASIdOrRange(1234, 5678);
12✔
1509
      ASBlocks::ASIdOrRange rdi_id_or_range1 = ASBlocks::ASIdOrRange(32768);
12✔
1510
      ASBlocks::ASIdOrRange rdi_id_or_range2 = ASBlocks::ASIdOrRange(32769, 4294967295);
12✔
1511

1512
      std::vector<ASBlocks::ASIdOrRange> as_ranges;
12✔
1513
      if(push_asnum) {
12✔
1514
         as_ranges.push_back(asnum_id_or_range0);
6✔
1515
         as_ranges.push_back(asnum_id_or_range1);
6✔
1516
         as_ranges.push_back(asnum_id_or_range2);
6✔
1517
      }
1518

1519
      std::vector<ASBlocks::ASIdOrRange> rdi_ranges;
12✔
1520
      if(push_rdi) {
12✔
1521
         rdi_ranges.push_back(rdi_id_or_range0);
6✔
1522
         rdi_ranges.push_back(rdi_id_or_range1);
6✔
1523
         rdi_ranges.push_back(rdi_id_or_range2);
6✔
1524
      }
1525

1526
      ASBlocks::ASIdentifierChoice asnum = ASBlocks::ASIdentifierChoice(as_ranges);
12✔
1527
      ASBlocks::ASIdentifierChoice rdi = ASBlocks::ASIdentifierChoice(rdi_ranges);
12✔
1528

1529
      ASBlocks::ASIdentifiers ident = ASBlocks::ASIdentifiers(include_asnum ? std::optional(asnum) : std::nullopt,
32✔
1530
                                                              include_rdi ? std::optional(rdi) : std::nullopt);
32✔
1531

1532
      std::unique_ptr<ASBlocks> blocks = std::make_unique<ASBlocks>(ident);
12✔
1533

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

1537
      {
12✔
1538
         const auto* as_blocks = cert.v3_extensions().get_extension_object_as<ASBlocks>();
12✔
1539
         result.confirm("cert has ASBlock extension", as_blocks != nullptr, true);
24✔
1540

1541
         const auto& identifier = as_blocks->as_identifiers();
12✔
1542

1543
         if(include_asnum) {
12✔
1544
            const auto& asnum_entries = identifier.asnum().value().ranges().value();
8✔
1545

1546
            if(push_asnum) {
8✔
1547
               result.confirm("asnum entry 0 min", asnum_entries[0].min() == 0, true);
8✔
1548
               result.confirm("asnum entry 0 max", asnum_entries[0].max() == 999, true);
8✔
1549

1550
               result.confirm("asnum entry 1 min", asnum_entries[1].min() == 5042, true);
8✔
1551
               result.confirm("asnum entry 1 max", asnum_entries[1].max() == 4294967295, true);
8✔
1552
            } else {
1553
               result.confirm("asnum has no entries", asnum_entries.empty(), true);
8✔
1554
            }
1555
         } else {
1556
            result.confirm("no asnum entry", identifier.asnum().has_value(), false);
8✔
1557
         }
1558

1559
         if(include_rdi) {
12✔
1560
            const auto& rdi_entries = identifier.rdi().value().ranges().value();
8✔
1561

1562
            if(push_rdi) {
8✔
1563
               result.confirm("rdi entry 0 min", rdi_entries[0].min() == 1234, true);
8✔
1564
               result.confirm("rdi entry 0 max", rdi_entries[0].max() == 5678, true);
8✔
1565

1566
               result.confirm("rdi entry 1 min", rdi_entries[1].min() == 32768, true);
8✔
1567
               result.confirm("rdi entry 1 max", rdi_entries[1].max() == 4294967295, true);
8✔
1568
            } else {
1569
               result.confirm("rdi has no entries", rdi_entries.empty(), true);
8✔
1570
            }
1571
         } else {
1572
            result.confirm("rdi has no entry", identifier.rdi().has_value(), false);
8✔
1573
         }
1574
      }
1575
   }
36✔
1576

1577
   result.end_timer();
1✔
1578
   return result;
2✔
1579
}
2✔
1580

1581
Test::Result test_x509_as_blocks_range_merge() {
1✔
1582
   Test::Result result("X509 AS Block range merge");
1✔
1583
   result.start_timer();
1✔
1584

1585
   using Botan::Cert_Extension::ASBlocks;
1✔
1586

1587
   auto rng = Test::new_rng(__func__);
1✔
1588

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

1591
   std::vector<std::vector<uint16_t>> ranges = {
1✔
1592
      {2005, 37005},
1593
      {60, 70},
1594
      {22, 50},
1595
      {35, 2000},
1596
      {2001, 2004},
1597
      {21, 21},
1598
      {0, 20},
1599
   };
9✔
1600

1601
   std::vector<ASBlocks::ASIdOrRange> as_ranges;
1✔
1602
   for(auto pair : ranges) {
8✔
1603
      auto range = ASBlocks::ASIdOrRange(pair[0], pair[1]);
7✔
1604
      as_ranges.push_back(range);
7✔
1605
   }
7✔
1606

1607
   ASBlocks::ASIdentifierChoice asnum = ASBlocks::ASIdentifierChoice(as_ranges);
1✔
1608

1609
   ASBlocks::ASIdentifiers ident = ASBlocks::ASIdentifiers(std::optional(asnum), std::nullopt);
3✔
1610

1611
   std::unique_ptr<ASBlocks> blocks = std::make_unique<ASBlocks>(ident);
1✔
1612

1613
   const auto req = user_params().add_extension(std::move(blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
1✔
1614
   Botan::X509_Certificate cert = ca.sign_request(req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
1✔
1615
   {
1✔
1616
      const auto* as_blocks = cert.v3_extensions().get_extension_object_as<ASBlocks>();
1✔
1617
      result.confirm("cert has ASBlock extension", as_blocks != nullptr, true);
2✔
1618

1619
      const auto& identifier = as_blocks->as_identifiers();
1✔
1620

1621
      const auto& asnum_entries = identifier.asnum().value().ranges().value();
1✔
1622

1623
      result.confirm("asnum entry 0 min", asnum_entries[0].min() == 0, true);
2✔
1624
      result.confirm("asnum entry 0 max", asnum_entries[0].max() == 37005, true);
2✔
1625
      result.confirm("asnum length", asnum_entries.size() == 1, true);
2✔
1626
   }
1627

1628
   result.end_timer();
1✔
1629
   return result;
2✔
1630
}
5✔
1631

1632
Test::Result test_x509_as_blocks_path_validation_success_builder() {
1✔
1633
   Test::Result result("X509 AS Block path validation success (builder)");
1✔
1634
   result.start_timer();
1✔
1635

1636
   using Botan::Cert_Extension::ASBlocks;
1✔
1637
   auto rng = Test::new_rng(__func__);
1✔
1638

1639
   /*
1640
   Creates a certificate chain of length 4.
1641
   Root: both asnum and rdi
1642
   Inherit: has both values as 'inherit'
1643
   Dynamic: has either both 'inherit', both with values, or just one with a value
1644
   Subject: both asnum and rdi as a subset of Root / Dynamic
1645
   */
1646

1647
   // Root Cert, both as and rdi
1648

1649
   std::unique_ptr<ASBlocks> root_blocks = std::make_unique<ASBlocks>();
1✔
1650

1651
   root_blocks->add_asnum(0, 999);
1✔
1652
   root_blocks->add_asnum(5042);
1✔
1653
   root_blocks->add_asnum(5043, 4294967295);
1✔
1654

1655
   root_blocks->add_rdi(1234, 5678);
1✔
1656
   root_blocks->add_rdi(32768);
1✔
1657
   root_blocks->add_rdi(32769, 4294967295);
1✔
1658

1659
   // Inherit cert, both as 'inherit'
1660
   std::unique_ptr<ASBlocks> inherit_blocks = std::make_unique<ASBlocks>();
1✔
1661
   inherit_blocks->inherit_asnum();
1✔
1662
   inherit_blocks->inherit_rdi();
1✔
1663

1664
   // Subject cert
1665

1666
   std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>();
1✔
1667

1668
   sub_blocks->add_asnum(120, 180);
1✔
1669
   sub_blocks->add_asnum(220, 240);
1✔
1670
   sub_blocks->add_asnum(260, 511);
1✔
1671
   sub_blocks->add_asnum(678);
1✔
1672
   sub_blocks->add_asnum(5043, 5100);
1✔
1673

1674
   sub_blocks->add_rdi(1500, 2300);
1✔
1675
   sub_blocks->add_rdi(2500, 4000);
1✔
1676
   sub_blocks->add_rdi(1567);
1✔
1677
   sub_blocks->add_rdi(33100, 40000);
1✔
1678

1679
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
1✔
1680
      make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
2✔
1681
   auto [inherit_cert, inherit_ca] = make_and_sign_ca(std::move(inherit_blocks), root_ca, *rng);
2✔
1682

1683
   Botan::Certificate_Store_In_Memory trusted;
1✔
1684
   trusted.add_certificate(root_cert);
1✔
1685

1686
   for(size_t i = 0; i < 4; i++) {
5✔
1687
      bool include_asnum = i & 1;
4✔
1688
      bool include_rdi = (i >> 1) & 1;
4✔
1689

1690
      std::unique_ptr<ASBlocks> dyn_blocks = std::make_unique<ASBlocks>();
4✔
1691
      if(include_asnum) {
4✔
1692
         dyn_blocks->add_asnum(100, 600);
2✔
1693
         dyn_blocks->add_asnum(678);
2✔
1694
         dyn_blocks->add_asnum(5042, 5101);
2✔
1695
      } else {
1696
         dyn_blocks->inherit_asnum();
2✔
1697
      }
1698

1699
      if(include_rdi) {
4✔
1700
         dyn_blocks->add_rdi(1500, 5000);
2✔
1701
         dyn_blocks->add_rdi(33000, 60000);
2✔
1702
      } else {
1703
         dyn_blocks->inherit_rdi();
2✔
1704
      }
1705

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

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

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

1715
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
4✔
1716
      result.require("path validation succeeds", path_result.successful_validation());
4✔
1717
   }
8✔
1718

1719
   result.end_timer();
1✔
1720
   return result;
2✔
1721
}
7✔
1722

1723
Test::Result test_x509_as_blocks_path_validation_success_ctor() {
1✔
1724
   Test::Result result("X509 AS Block path validation success (ctor)");
1✔
1725
   result.start_timer();
1✔
1726

1727
   using Botan::Cert_Extension::ASBlocks;
1✔
1728
   auto rng = Test::new_rng(__func__);
1✔
1729

1730
   /*
1731
   Creates a certificate chain of length 4.
1732
   Root: both asnum and rdi
1733
   Inherit: has both values as 'inherit'
1734
   Dynamic: has either both 'inherit', both with values, or just one with a value
1735
   Subject: both asnum and rdi as a subset of Root / Dynamic
1736
   */
1737

1738
   // Root Cert, both as and rdi
1739
   ASBlocks::ASIdOrRange root_asnum_id_or_range0 = ASBlocks::ASIdOrRange(0, 999);
1✔
1740
   ASBlocks::ASIdOrRange root_asnum_id_or_range1 = ASBlocks::ASIdOrRange(5042);
1✔
1741
   ASBlocks::ASIdOrRange root_asnum_id_or_range2 = ASBlocks::ASIdOrRange(5043, 4294967295);
1✔
1742

1743
   ASBlocks::ASIdOrRange root_rdi_id_or_range0 = ASBlocks::ASIdOrRange(1234, 5678);
1✔
1744
   ASBlocks::ASIdOrRange root_rdi_id_or_range1 = ASBlocks::ASIdOrRange(32768);
1✔
1745
   ASBlocks::ASIdOrRange root_rdi_id_or_range2 = ASBlocks::ASIdOrRange(32769, 4294967295);
1✔
1746

1747
   std::vector<ASBlocks::ASIdOrRange> root_as_ranges;
1✔
1748
   root_as_ranges.push_back(root_asnum_id_or_range0);
1✔
1749
   root_as_ranges.push_back(root_asnum_id_or_range1);
1✔
1750
   root_as_ranges.push_back(root_asnum_id_or_range2);
1✔
1751

1752
   std::vector<ASBlocks::ASIdOrRange> root_rdi_ranges;
1✔
1753
   root_rdi_ranges.push_back(root_rdi_id_or_range0);
1✔
1754
   root_rdi_ranges.push_back(root_rdi_id_or_range1);
1✔
1755
   root_rdi_ranges.push_back(root_rdi_id_or_range2);
1✔
1756

1757
   ASBlocks::ASIdentifierChoice root_asnum = ASBlocks::ASIdentifierChoice(root_as_ranges);
1✔
1758
   ASBlocks::ASIdentifierChoice root_rdi = ASBlocks::ASIdentifierChoice(root_rdi_ranges);
1✔
1759
   ASBlocks::ASIdentifiers root_ident = ASBlocks::ASIdentifiers(root_asnum, root_rdi);
4✔
1760
   std::unique_ptr<ASBlocks> root_blocks = std::make_unique<ASBlocks>(root_ident);
1✔
1761

1762
   // Inherit cert, both as 'inherit'
1763
   ASBlocks::ASIdentifierChoice inherit_asnum = ASBlocks::ASIdentifierChoice();
1✔
1764
   ASBlocks::ASIdentifierChoice inherit_rdi = ASBlocks::ASIdentifierChoice();
1✔
1765
   ASBlocks::ASIdentifiers inherit_ident = ASBlocks::ASIdentifiers(inherit_asnum, inherit_rdi);
2✔
1766
   std::unique_ptr<ASBlocks> inherit_blocks = std::make_unique<ASBlocks>(inherit_ident);
1✔
1767

1768
   // Dynamic cert
1769
   ASBlocks::ASIdOrRange dyn_asnum_id_or_range0 = ASBlocks::ASIdOrRange(100, 600);
1✔
1770
   ASBlocks::ASIdOrRange dyn_asnum_id_or_range1 = ASBlocks::ASIdOrRange(678);
1✔
1771
   ASBlocks::ASIdOrRange dyn_asnum_id_or_range2 = ASBlocks::ASIdOrRange(5042, 5101);
1✔
1772

1773
   ASBlocks::ASIdOrRange dyn_rdi_id_or_range0 = ASBlocks::ASIdOrRange(1500, 5000);
1✔
1774
   ASBlocks::ASIdOrRange dyn_rdi_id_or_range1 = ASBlocks::ASIdOrRange(33000, 60000);
1✔
1775

1776
   std::vector<ASBlocks::ASIdOrRange> dyn_as_ranges;
1✔
1777
   dyn_as_ranges.push_back(dyn_asnum_id_or_range0);
1✔
1778
   dyn_as_ranges.push_back(dyn_asnum_id_or_range1);
1✔
1779
   dyn_as_ranges.push_back(dyn_asnum_id_or_range2);
1✔
1780

1781
   std::vector<ASBlocks::ASIdOrRange> dyn_rdi_ranges;
1✔
1782
   dyn_rdi_ranges.push_back(dyn_rdi_id_or_range0);
1✔
1783
   dyn_rdi_ranges.push_back(dyn_rdi_id_or_range1);
1✔
1784

1785
   // Subject cert
1786
   ASBlocks::ASIdOrRange sub_asnum_id_or_range0 = ASBlocks::ASIdOrRange(120, 180);
1✔
1787
   ASBlocks::ASIdOrRange sub_asnum_id_or_range1 = ASBlocks::ASIdOrRange(220, 240);
1✔
1788
   ASBlocks::ASIdOrRange sub_asnum_id_or_range2 = ASBlocks::ASIdOrRange(260, 511);
1✔
1789
   ASBlocks::ASIdOrRange sub_asnum_id_or_range3 = ASBlocks::ASIdOrRange(678);
1✔
1790
   ASBlocks::ASIdOrRange sub_asnum_id_or_range4 = ASBlocks::ASIdOrRange(5043, 5100);
1✔
1791

1792
   ASBlocks::ASIdOrRange sub_rdi_id_or_range0 = ASBlocks::ASIdOrRange(1500, 2300);
1✔
1793
   ASBlocks::ASIdOrRange sub_rdi_id_or_range1 = ASBlocks::ASIdOrRange(2500, 4000);
1✔
1794
   ASBlocks::ASIdOrRange sub_rdi_id_or_range2 = ASBlocks::ASIdOrRange(1567);
1✔
1795
   ASBlocks::ASIdOrRange sub_rdi_id_or_range3 = ASBlocks::ASIdOrRange(33100, 40000);
1✔
1796

1797
   std::vector<ASBlocks::ASIdOrRange> sub_as_ranges;
1✔
1798
   sub_as_ranges.push_back(sub_asnum_id_or_range0);
1✔
1799
   sub_as_ranges.push_back(sub_asnum_id_or_range1);
1✔
1800
   sub_as_ranges.push_back(sub_asnum_id_or_range2);
1✔
1801
   sub_as_ranges.push_back(sub_asnum_id_or_range3);
1✔
1802
   sub_as_ranges.push_back(sub_asnum_id_or_range4);
1✔
1803

1804
   std::vector<ASBlocks::ASIdOrRange> sub_rdi_ranges;
1✔
1805
   sub_rdi_ranges.push_back(sub_rdi_id_or_range0);
1✔
1806
   sub_rdi_ranges.push_back(sub_rdi_id_or_range1);
1✔
1807
   sub_rdi_ranges.push_back(sub_rdi_id_or_range2);
1✔
1808
   sub_rdi_ranges.push_back(sub_rdi_id_or_range3);
1✔
1809

1810
   ASBlocks::ASIdentifierChoice sub_asnum = ASBlocks::ASIdentifierChoice(sub_as_ranges);
1✔
1811
   ASBlocks::ASIdentifierChoice sub_rdi = ASBlocks::ASIdentifierChoice(sub_rdi_ranges);
1✔
1812
   ASBlocks::ASIdentifiers sub_ident = ASBlocks::ASIdentifiers(sub_asnum, sub_rdi);
4✔
1813
   std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>(sub_ident);
1✔
1814

1815
   auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
1✔
1816
      make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
2✔
1817
   auto [inherit_cert, inherit_ca] = make_and_sign_ca(std::move(inherit_blocks), root_ca, *rng);
2✔
1818

1819
   Botan::Certificate_Store_In_Memory trusted;
1✔
1820
   trusted.add_certificate(root_cert);
1✔
1821

1822
   for(size_t i = 0; i < 4; i++) {
5✔
1823
      bool include_asnum = i & 1;
4✔
1824
      bool include_rdi = (i >> 1) & 1;
4✔
1825

1826
      ASBlocks::ASIdentifierChoice dyn_asnum =
4✔
1827
         ASBlocks::ASIdentifierChoice(include_asnum ? std::optional(dyn_as_ranges) : std::nullopt);
6✔
1828
      ASBlocks::ASIdentifierChoice dyn_rdi =
4✔
1829
         ASBlocks::ASIdentifierChoice(include_rdi ? std::optional(dyn_rdi_ranges) : std::nullopt);
6✔
1830
      ASBlocks::ASIdentifiers dyn_ident = ASBlocks::ASIdentifiers(dyn_asnum, dyn_rdi);
12✔
1831
      std::unique_ptr<ASBlocks> dyn_blocks = std::make_unique<ASBlocks>(dyn_ident);
4✔
1832

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

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

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

1842
      Botan::Path_Validation_Result path_result = Botan::x509_path_validate(certs, restrictions, trusted);
4✔
1843
      result.require("path validation succeeds", path_result.successful_validation());
4✔
1844
   }
12✔
1845

1846
   result.end_timer();
1✔
1847
   return result;
2✔
1848
}
12✔
1849

1850
Test::Result test_x509_as_blocks_path_validation_extension_not_present_builder() {
1✔
1851
   Test::Result result("X509 AS Block path validation extension not present (builder)");
1✔
1852
   result.start_timer();
1✔
1853

1854
   using Botan::Cert_Extension::ASBlocks;
1✔
1855
   auto rng = Test::new_rng(__func__);
1✔
1856

1857
   std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>();
1✔
1858
   sub_blocks->add_asnum(120, 180);
1✔
1859
   sub_blocks->add_asnum(220, 224);
1✔
1860
   sub_blocks->add_asnum(260, 511);
1✔
1861
   sub_blocks->add_asnum(678);
1✔
1862
   sub_blocks->add_asnum(5043, 5100);
1✔
1863

1864
   sub_blocks->add_rdi(1500, 2300);
1✔
1865
   sub_blocks->add_rdi(2500, 4000);
1✔
1866
   sub_blocks->add_rdi(1567);
1✔
1867
   sub_blocks->add_rdi(33100, 40000);
1✔
1868

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

1874
   Botan::Certificate_Store_In_Memory trusted;
1✔
1875
   trusted.add_certificate(root_cert);
1✔
1876

1877
   const Botan::Path_Validation_Restrictions restrictions(false, 80);
2✔
1878
   const std::vector<Botan::X509_Certificate> certs = {sub_cert};
2✔
1879

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

1883
   result.end_timer();
1✔
1884
   return result;
2✔
1885
}
3✔
1886

1887
Test::Result test_x509_as_blocks_path_validation_extension_not_present_ctor() {
1✔
1888
   Test::Result result("X509 AS Block path validation extension not present (ctor)");
1✔
1889
   result.start_timer();
1✔
1890

1891
   using Botan::Cert_Extension::ASBlocks;
1✔
1892
   auto rng = Test::new_rng(__func__);
1✔
1893

1894
   // Subject cert
1895
   ASBlocks::ASIdOrRange sub_asnum_id_or_range0 = ASBlocks::ASIdOrRange(120, 180);
1✔
1896
   ASBlocks::ASIdOrRange sub_asnum_id_or_range1 = ASBlocks::ASIdOrRange(220, 240);
1✔
1897
   ASBlocks::ASIdOrRange sub_asnum_id_or_range2 = ASBlocks::ASIdOrRange(260, 511);
1✔
1898
   ASBlocks::ASIdOrRange sub_asnum_id_or_range3 = ASBlocks::ASIdOrRange(678);
1✔
1899
   ASBlocks::ASIdOrRange sub_asnum_id_or_range4 = ASBlocks::ASIdOrRange(5043, 5100);
1✔
1900

1901
   ASBlocks::ASIdOrRange sub_rdi_id_or_range0 = ASBlocks::ASIdOrRange(1500, 2300);
1✔
1902
   ASBlocks::ASIdOrRange sub_rdi_id_or_range1 = ASBlocks::ASIdOrRange(2500, 4000);
1✔
1903
   ASBlocks::ASIdOrRange sub_rdi_id_or_range2 = ASBlocks::ASIdOrRange(1567);
1✔
1904
   ASBlocks::ASIdOrRange sub_rdi_id_or_range3 = ASBlocks::ASIdOrRange(33100, 40000);
1✔
1905

1906
   std::vector<ASBlocks::ASIdOrRange> sub_as_ranges;
1✔
1907
   sub_as_ranges.push_back(sub_asnum_id_or_range0);
1✔
1908
   sub_as_ranges.push_back(sub_asnum_id_or_range1);
1✔
1909
   sub_as_ranges.push_back(sub_asnum_id_or_range2);
1✔
1910
   sub_as_ranges.push_back(sub_asnum_id_or_range3);
1✔
1911
   sub_as_ranges.push_back(sub_asnum_id_or_range4);
1✔
1912

1913
   std::vector<ASBlocks::ASIdOrRange> sub_rdi_ranges;
1✔
1914
   sub_rdi_ranges.push_back(sub_rdi_id_or_range0);
1✔
1915
   sub_rdi_ranges.push_back(sub_rdi_id_or_range1);
1✔
1916
   sub_rdi_ranges.push_back(sub_rdi_id_or_range2);
1✔
1917
   sub_rdi_ranges.push_back(sub_rdi_id_or_range3);
1✔
1918

1919
   ASBlocks::ASIdentifierChoice sub_asnum = ASBlocks::ASIdentifierChoice(sub_as_ranges);
1✔
1920
   ASBlocks::ASIdentifierChoice sub_rdi = ASBlocks::ASIdentifierChoice(sub_rdi_ranges);
1✔
1921
   ASBlocks::ASIdentifiers sub_ident = ASBlocks::ASIdentifiers(sub_asnum, sub_rdi);
4✔
1922
   std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>(sub_ident);
1✔
1923

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

1929
   Botan::Certificate_Store_In_Memory trusted;
1✔
1930
   trusted.add_certificate(root_cert);
1✔
1931

1932
   const Botan::Path_Validation_Restrictions restrictions(false, 80);
2✔
1933
   const std::vector<Botan::X509_Certificate> certs = {sub_cert};
2✔
1934

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

1938
   result.end_timer();
1✔
1939
   return result;
2✔
1940
}
5✔
1941

1942
Test::Result test_x509_as_blocks_path_validation_failure_builder() {
1✔
1943
   Test::Result result("X509 AS Block path validation failure (builder)");
1✔
1944
   result.start_timer();
1✔
1945

1946
   using Botan::Cert_Extension::ASBlocks;
1✔
1947
   auto rng = Test::new_rng(__func__);
1✔
1948

1949
   /*
1950
   This executes a few permutations, messing around with edge cases when it comes to constructing ranges.
1951

1952
   Each test is expected to fail and creates the following certificate chain:
1953
   Root -> Issuer -> Subject
1954

1955
   00: set all the asnum choices to 'inherit' for each cert
1956
   01: 00 but for rdis
1957
   02: make smallest min asnum of the subject smaller than the smallest min asnum of the issuer
1958
   03: 02 but for rdis
1959
   04: both 02 and 03
1960
   05: make largest max asnum of the subject larger than the largest max asnum of the issuer
1961
   06: 05 but for rdis
1962
   07: both 05 and 06
1963
   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
1964
   09: 08 but for rdis
1965
   10: both 08 and 09
1966
   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)
1967
   12: 11 but for rdis
1968
   13: both 11 and 12
1969
   14: 08 but using the minimum instead of the maximum
1970
   15: 14 but for rdis
1971
   16: both 14 and 15
1972
   17: same as 11 but using the minimum instead of the maximum
1973
   18: 17 but for rdis
1974
   19: both 18 and 19
1975
   20: make the issuer ranges empty but have an entry in the subject ranges
1976
   */
1977
   for(size_t i = 0; i < 21; i++) {
22✔
1978
      // enable / disable all the different edge cases
1979
      bool inherit_all_asnums = (i == 0);
21✔
1980
      bool inherit_all_rdis = (i == 1);
21✔
1981
      bool push_asnum_min_edge_ranges = (i == 2) || (i == 4);
21✔
1982
      bool push_rdi_min_edge_ranges = (i == 3) || (i == 4);
21✔
1983
      bool push_asnum_max_edge_ranges = (i == 5) || (i == 7);
21✔
1984
      bool push_rdi_max_edge_ranges = (i == 6) || (i == 7);
21✔
1985
      bool push_asnum_max_middle_ranges = (i == 8) || (i == 10);
21✔
1986
      bool push_rdi_max_middle_ranges = (i == 9) || (i == 10);
21✔
1987
      bool push_asnum_max_split_ranges = (i == 11) || (i == 13);
21✔
1988
      bool push_rdi_max_split_ranges = (i == 12) || (i == 13);
21✔
1989
      bool push_asnum_min_middle_ranges = (i == 14) || (i == 16);
21✔
1990
      bool push_rdi_min_middle_ranges = (i == 15) || (i == 16);
21✔
1991
      bool push_asnum_min_split_ranges = (i == 17) || (i == 19);
21✔
1992
      bool push_rdi_min_split_ranges = (i == 18) || (i == 19);
21✔
1993
      bool empty_issuer_non_empty_subject = (i == 20);
21✔
1994

1995
      // Root cert
1996
      std::unique_ptr<ASBlocks> root_blocks = std::make_unique<ASBlocks>();
21✔
1997

1998
      if(!inherit_all_asnums) {
21✔
1999
         if(push_asnum_min_edge_ranges || push_asnum_max_edge_ranges) {
20✔
2000
            // 100-200 for 02,03,04
2001
            root_blocks->add_asnum(100, 200);
4✔
2002
         } else if(push_asnum_max_middle_ranges || push_asnum_min_middle_ranges) {
16✔
2003
            // 10-20,30-40,50-60 for 08,09,10
2004
            root_blocks->add_asnum(10, 20);
4✔
2005
            root_blocks->add_asnum(30, 40);
4✔
2006
            root_blocks->add_asnum(50, 60);
4✔
2007
         } else if(push_asnum_max_split_ranges || push_asnum_min_split_ranges) {
12✔
2008
            // 10-20,30-50,60-70 for 11,12,13
2009
            root_blocks->add_asnum(10, 20);
4✔
2010
            root_blocks->add_asnum(30, 50);
4✔
2011
            root_blocks->add_asnum(60, 70);
4✔
2012
         }
2013
      } else {
2014
         root_blocks->inherit_asnum();
1✔
2015
      }
2016

2017
      // same values but for rdis
2018
      if(!inherit_all_rdis) {
21✔
2019
         if(push_rdi_min_edge_ranges || push_rdi_max_edge_ranges) {
2020
            root_blocks->add_rdi(100, 200);
4✔
2021
         } else if(push_rdi_max_middle_ranges || push_rdi_min_middle_ranges) {
2022
            root_blocks->add_rdi(10, 20);
4✔
2023
            root_blocks->add_rdi(30, 40);
4✔
2024
            root_blocks->add_rdi(50, 60);
4✔
2025
         } else if(push_rdi_max_split_ranges || push_rdi_min_split_ranges) {
2026
            root_blocks->add_rdi(10, 20);
4✔
2027
            root_blocks->add_rdi(30, 50);
4✔
2028
            root_blocks->add_rdi(60, 70);
4✔
2029
         }
2030
      } else {
2031
         root_blocks->inherit_rdi();
1✔
2032
      }
2033

2034
      if(empty_issuer_non_empty_subject) {
21✔
2035
         root_blocks->restrict_asnum();
1✔
2036
         root_blocks->restrict_rdi();
1✔
2037
      }
2038

2039
      // Issuer cert
2040
      // the issuer cert has the same ranges as the root cert
2041
      // it is used to check that the 'inherit' check is bubbled up until the root cert is hit
2042
      auto issu_blocks = root_blocks->copy();
21✔
2043

2044
      // Subject cert
2045
      std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>();
21✔
2046

2047
      std::vector<ASBlocks::ASIdOrRange> sub_as_ranges;
21✔
2048
      std::vector<ASBlocks::ASIdOrRange> sub_rdi_ranges;
21✔
2049

2050
      if(!inherit_all_asnums) {
21✔
2051
         // assign the subject asnum ranges
2052
         if(push_asnum_min_edge_ranges) {
2053
            // 99-200 for 02 (so overlapping to the left)
2054
            sub_blocks->add_asnum(99, 200);
2✔
2055
         } else if(push_asnum_max_edge_ranges) {
2056
            // 100-201 for 03 (so overlapping to the right)
2057
            sub_blocks->add_asnum(100, 201);
2✔
2058
         } else if(push_asnum_max_middle_ranges) {
2059
            // same as root, but change the range in the middle to overlap to the right for 08
2060
            sub_blocks->add_asnum(10, 20);
2✔
2061
            sub_blocks->add_asnum(30, 41);
2✔
2062
            sub_blocks->add_asnum(50, 60);
2✔
2063
         } else if(push_asnum_max_split_ranges) {
2064
            // change the range in the middle to be cut at 45 for case 11
2065
            // the left range is 30-44
2066
            // the right range is 46-51 (overlapping the issuer range to the right)
2067
            sub_blocks->add_asnum(10, 20);
2✔
2068
            sub_blocks->add_asnum(30, 44);
2✔
2069
            sub_blocks->add_asnum(46, 51);
2✔
2070
            sub_blocks->add_asnum(60, 70);
2✔
2071
         } else if(push_asnum_min_middle_ranges) {
2072
            // just change the test in the middle to overlap to the left for case 14
2073
            sub_blocks->add_asnum(10, 20);
2✔
2074
            sub_blocks->add_asnum(29, 40);
2✔
2075
            sub_blocks->add_asnum(50, 60);
2✔
2076
         } else if(push_asnum_min_split_ranges) {
2077
            // again split the range in the middle at 45 for case 17
2078
            // creating two ranges 29-44 and 46-50 (so overlapping to the left)
2079
            sub_blocks->add_asnum(10, 20);
2✔
2080
            sub_blocks->add_asnum(29, 44);
2✔
2081
            sub_blocks->add_asnum(46, 50);
2✔
2082
            sub_blocks->add_asnum(60, 70);
2✔
2083
         } else if(empty_issuer_non_empty_subject) {
2084
            sub_blocks->add_asnum(50);
1✔
2085
         }
2086
      } else {
2087
         sub_blocks->inherit_asnum();
1✔
2088
      }
2089

2090
      if(!inherit_all_rdis) {
21✔
2091
         // same values but for rdis
2092
         if(push_rdi_min_edge_ranges) {
2093
            sub_blocks->add_rdi(99, 200);
2✔
2094
         } else if(push_rdi_max_edge_ranges) {
2095
            sub_blocks->add_rdi(100, 201);
2✔
2096
         } else if(push_rdi_max_middle_ranges) {
2097
            sub_blocks->add_rdi(10, 20);
2✔
2098
            sub_blocks->add_rdi(30, 41);
2✔
2099
            sub_blocks->add_rdi(50, 60);
2✔
2100
         } else if(push_rdi_max_split_ranges) {
2101
            sub_blocks->add_rdi(10, 20);
2✔
2102
            sub_blocks->add_rdi(30, 44);
2✔
2103
            sub_blocks->add_rdi(46, 51);
2✔
2104
            sub_blocks->add_rdi(60, 70);
2✔
2105
         } else if(push_rdi_min_middle_ranges) {
2106
            sub_blocks->add_rdi(10, 20);
2✔
2107
            sub_blocks->add_rdi(29, 40);
2✔
2108
            sub_blocks->add_rdi(50, 60);
2✔
2109
         } else if(push_rdi_min_split_ranges) {
2110
            sub_blocks->add_rdi(10, 20);
2✔
2111
            sub_blocks->add_rdi(29, 44);
2✔
2112
            sub_blocks->add_rdi(46, 50);
2✔
2113
            sub_blocks->add_rdi(60, 70);
2✔
2114
         }
2115
      } else {
2116
         sub_blocks->inherit_rdi();
1✔
2117
      }
2118

2119
      auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
21✔
2120
         make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
42✔
2121
      auto [issu_cert, issu_ca] = make_and_sign_ca(std::move(issu_blocks), root_ca, *rng);
42✔
2122

2123
      const auto sub_req =
21✔
2124
         user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
21✔
2125
      Botan::X509_Certificate sub_cert =
21✔
2126
         issu_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
21✔
2127

2128
      Botan::Certificate_Store_In_Memory trusted;
21✔
2129
      trusted.add_certificate(root_cert);
21✔
2130

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

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

2139
   result.end_timer();
1✔
2140
   return result;
1✔
2141
}
22✔
2142

2143
Test::Result test_x509_as_blocks_path_validation_failure_ctor() {
1✔
2144
   Test::Result result("X509 AS Block path validation failure (ctor)");
1✔
2145
   result.start_timer();
1✔
2146

2147
   using Botan::Cert_Extension::ASBlocks;
1✔
2148
   auto rng = Test::new_rng(__func__);
1✔
2149

2150
   /*
2151
   This executes a few permutations, messing around with edge cases when it comes to constructing ranges.
2152

2153
   Each test is expected to fail and creates the following certificate chain:
2154
   Root -> Issuer -> Subject
2155

2156
   00: set all the asnum choices to 'inherit' for each cert
2157
   01: 00 but for rdis
2158
   02: make smallest min asnum of the subject smaller than the smallest min asnum of the issuer
2159
   03: 02 but for rdis
2160
   04: both 02 and 03
2161
   05: make largest max asnum of the subject larger than the largest max asnum of the issuer
2162
   06: 05 but for rdis
2163
   07: both 05 and 06
2164
   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
2165
   09: 08 but for rdis
2166
   10: both 08 and 09
2167
   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)
2168
   12: 11 but for rdis
2169
   13: both 11 and 12
2170
   14: 08 but using the minimum instead of the maximum
2171
   15: 14 but for rdis
2172
   16: both 14 and 15
2173
   17: same as 11 but using the minimum instead of the maximum
2174
   18: 17 but for rdis
2175
   19: both 18 and 19
2176
   20: make the issuer ranges empty but have an entry in the subject ranges
2177
   */
2178
   for(size_t i = 0; i < 21; i++) {
22✔
2179
      // enable / disable all the different edge cases
2180
      bool inherit_all_asnums = (i == 0);
21✔
2181
      bool inherit_all_rdis = (i == 1);
21✔
2182
      bool push_asnum_min_edge_ranges = (i == 2) || (i == 4);
21✔
2183
      bool push_rdi_min_edge_ranges = (i == 3) || (i == 4);
21✔
2184
      bool push_asnum_max_edge_ranges = (i == 5) || (i == 7);
21✔
2185
      bool push_rdi_max_edge_ranges = (i == 6) || (i == 7);
21✔
2186
      bool push_asnum_max_middle_ranges = (i == 8) || (i == 10);
21✔
2187
      bool push_rdi_max_middle_ranges = (i == 9) || (i == 10);
21✔
2188
      bool push_asnum_max_split_ranges = (i == 11) || (i == 13);
21✔
2189
      bool push_rdi_max_split_ranges = (i == 12) || (i == 13);
21✔
2190
      bool push_asnum_min_middle_ranges = (i == 14) || (i == 16);
21✔
2191
      bool push_rdi_min_middle_ranges = (i == 15) || (i == 16);
21✔
2192
      bool push_asnum_min_split_ranges = (i == 17) || (i == 19);
21✔
2193
      bool push_rdi_min_split_ranges = (i == 18) || (i == 19);
21✔
2194
      bool empty_issuer_non_empty_subject = (i == 20);
21✔
2195

2196
      // Root cert
2197
      std::vector<ASBlocks::ASIdOrRange> root_as_ranges;
21✔
2198
      std::vector<ASBlocks::ASIdOrRange> root_rdi_ranges;
21✔
2199

2200
      // assign the root ranges
2201
      if(push_asnum_min_edge_ranges || push_asnum_max_edge_ranges) {
21✔
2202
         // 100-200 for 02,03,04
2203
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(100, 200));
8✔
2204
      } else if(push_asnum_max_middle_ranges || push_asnum_min_middle_ranges) {
17✔
2205
         // 10-20,30-40,50-60 for 08,09,10
2206
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(10, 20));
8✔
2207
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(30, 40));
8✔
2208
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(50, 60));
8✔
2209
      } else if(push_asnum_max_split_ranges || push_asnum_min_split_ranges) {
13✔
2210
         // 10-20,30-50,60-70 for 11,12,13
2211
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(10, 20));
8✔
2212
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(30, 50));
8✔
2213
         root_as_ranges.push_back(ASBlocks::ASIdOrRange(60, 70));
8✔
2214
      }
2215

2216
      // same values but for rdis
2217
      if(push_rdi_min_edge_ranges || push_rdi_max_edge_ranges) {
21✔
2218
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(100, 200));
8✔
2219
      } else if(push_rdi_max_middle_ranges || push_rdi_min_middle_ranges) {
2220
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(10, 20));
8✔
2221
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(30, 40));
8✔
2222
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(50, 60));
8✔
2223
      } else if(push_rdi_max_split_ranges || push_rdi_min_split_ranges) {
2224
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(10, 20));
8✔
2225
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(30, 50));
8✔
2226
         root_rdi_ranges.push_back(ASBlocks::ASIdOrRange(60, 70));
8✔
2227
      }
2228

2229
      // Issuer cert
2230
      // the issuer cert has the same ranges as the root cert
2231
      // it is used to check that the 'inherit' check is bubbled up until the root cert is hit
2232
      std::vector<ASBlocks::ASIdOrRange> issu_as_ranges;
21✔
2233
      std::vector<ASBlocks::ASIdOrRange> issu_rdi_ranges;
21✔
2234

2235
      // Subject cert
2236
      std::vector<ASBlocks::ASIdOrRange> sub_as_ranges;
21✔
2237
      std::vector<ASBlocks::ASIdOrRange> sub_rdi_ranges;
21✔
2238

2239
      // assign the subject asnum ranges
2240
      if(push_asnum_min_edge_ranges) {
21✔
2241
         // 99-200 for 02 (so overlapping to the left)
2242
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(99, 200));
4✔
2243
      } else if(push_asnum_max_edge_ranges) {
2244
         // 100-201 for 03 (so overlapping to the right)
2245
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(100, 201));
4✔
2246
      } else if(push_asnum_max_middle_ranges) {
2247
         // just change the range in the middle to overlap to the right for 08
2248
         sub_as_ranges = root_as_ranges;
2✔
2249
         sub_as_ranges[1] = ASBlocks::ASIdOrRange(30, 41);
2✔
2250
      } else if(push_asnum_max_split_ranges) {
2251
         // change the range in the middle to be cut at 45 for case 11
2252
         // the left range is 30-44
2253
         // the right range is 46-51 (overlapping the issuer range to the right)
2254
         sub_as_ranges = root_as_ranges;
2✔
2255
         sub_as_ranges[1] = ASBlocks::ASIdOrRange(30, 44);
2✔
2256
         // pushing the new range created by splitting to the back since they will be sorted anyway
2257
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(46, 51));
4✔
2258
      } else if(push_asnum_min_middle_ranges) {
2259
         // just change the test in the middle to overlap to the left for case 14
2260
         sub_as_ranges = root_as_ranges;
2✔
2261
         sub_as_ranges[1] = ASBlocks::ASIdOrRange(29, 40);
2✔
2262
      } else if(push_asnum_min_split_ranges) {
2263
         // again split the range in the middle at 45 for case 17
2264
         // creating two ranges 29-44 and 46-50 (so overlapping to the left)
2265
         sub_as_ranges = root_as_ranges;
2✔
2266
         sub_as_ranges[1] = ASBlocks::ASIdOrRange(29, 44);
2✔
2267
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(46, 50));
4✔
2268
      } else if(empty_issuer_non_empty_subject) {
2269
         sub_as_ranges.push_back(ASBlocks::ASIdOrRange(50));
1✔
2270
      }
2271

2272
      // same values but for rdis
2273
      if(push_rdi_min_edge_ranges) {
21✔
2274
         sub_rdi_ranges.push_back(ASBlocks::ASIdOrRange(99, 200));
4✔
2275
      } else if(push_rdi_max_edge_ranges) {
2276
         sub_rdi_ranges.push_back(ASBlocks::ASIdOrRange(100, 201));
4✔
2277
      } else if(push_rdi_max_middle_ranges) {
2278
         sub_rdi_ranges = root_rdi_ranges;
2✔
2279
         sub_rdi_ranges[1] = ASBlocks::ASIdOrRange(30, 41);
2✔
2280
      } else if(push_rdi_max_split_ranges) {
2281
         sub_rdi_ranges = root_rdi_ranges;
2✔
2282
         sub_rdi_ranges[1] = ASBlocks::ASIdOrRange(30, 44);
2✔
2283
         sub_rdi_ranges.push_back(ASBlocks::ASIdOrRange(46, 51));
4✔
2284
      } else if(push_rdi_min_middle_ranges) {
2285
         sub_rdi_ranges = root_rdi_ranges;
2✔
2286
         sub_rdi_ranges[1] = ASBlocks::ASIdOrRange(29, 40);
2✔
2287
      } else if(push_rdi_min_split_ranges) {
2288
         sub_rdi_ranges = root_rdi_ranges;
2✔
2289
         sub_rdi_ranges[1] = ASBlocks::ASIdOrRange(29, 44);
2✔
2290
         sub_rdi_ranges.push_back(ASBlocks::ASIdOrRange(46, 50));
4✔
2291
      }
2292

2293
      // for cases 00 and 01, set all certs to inherit (so std::nullopt)
2294
      // in all other cases use the ranges created beforehand
2295
      ASBlocks::ASIdentifierChoice root_asnum =
21✔
2296
         ASBlocks::ASIdentifierChoice(inherit_all_asnums ? std::nullopt : std::optional(root_as_ranges));
41✔
2297
      ASBlocks::ASIdentifierChoice root_rdi =
21✔
2298
         ASBlocks::ASIdentifierChoice(inherit_all_rdis ? std::nullopt : std::optional(root_rdi_ranges));
41✔
2299
      ASBlocks::ASIdentifiers root_ident = ASBlocks::ASIdentifiers(root_asnum, root_rdi);
82✔
2300
      std::unique_ptr<ASBlocks> root_blocks = std::make_unique<ASBlocks>(root_ident);
21✔
2301

2302
      ASBlocks::ASIdentifiers issu_ident = root_ident;
21✔
2303
      std::unique_ptr<ASBlocks> issu_blocks = std::make_unique<ASBlocks>(issu_ident);
21✔
2304

2305
      ASBlocks::ASIdentifierChoice sub_asnum =
21✔
2306
         ASBlocks::ASIdentifierChoice(inherit_all_asnums ? std::nullopt : std::optional(sub_as_ranges));
41✔
2307
      ASBlocks::ASIdentifierChoice sub_rdi =
21✔
2308
         ASBlocks::ASIdentifierChoice(inherit_all_rdis ? std::nullopt : std::optional(sub_rdi_ranges));
41✔
2309
      ASBlocks::ASIdentifiers sub_ident = ASBlocks::ASIdentifiers(sub_asnum, sub_rdi);
82✔
2310
      std::unique_ptr<ASBlocks> sub_blocks = std::make_unique<ASBlocks>(sub_ident);
21✔
2311

2312
      auto [root_cert, root_ca, sub_key, sig_algo, hash_fn] =
21✔
2313
         make_ca(*rng, ca_params().add_extension(std::move(root_blocks)));
42✔
2314
      auto [issu_cert, issu_ca] = make_and_sign_ca(std::move(issu_blocks), root_ca, *rng);
42✔
2315

2316
      const auto sub_req =
21✔
2317
         user_params().add_extension(std::move(sub_blocks)).into_pkcs10_request(*sub_key, *rng, hash_fn);
21✔
2318
      Botan::X509_Certificate sub_cert =
21✔
2319
         issu_ca.sign_request(sub_req, *rng, from_date(-1, 01, 01), from_date(2, 01, 01));
21✔
2320

2321
      Botan::Certificate_Store_In_Memory trusted;
21✔
2322
      trusted.add_certificate(root_cert);
21✔
2323

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

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

2332
   result.end_timer();
1✔
2333
   return result;
1✔
2334
}
22✔
2335

2336
class X509_RPKI_Tests final : public Test {
×
2337
   public:
2338
      std::vector<Test::Result> run() override {
1✔
2339
         std::vector<Test::Result> results;
1✔
2340

2341
   #if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
2342
         results.push_back(test_x509_ip_addr_blocks_extension_decode());
2✔
2343
         results.push_back(test_x509_as_blocks_extension_decode());
2✔
2344
   #endif
2345
         results.push_back(test_x509_ip_addr_blocks_rfc3779_example());
2✔
2346
         results.push_back(test_x509_ip_addr_blocks_encode_builder());
2✔
2347
         results.push_back(test_x509_ip_addr_blocks_extension_encode_ctor());
2✔
2348
         results.push_back(test_x509_ip_addr_blocks_extension_encode_edge_cases_ctor());
2✔
2349
         results.push_back(test_x509_ip_addr_blocks_range_merge());
2✔
2350
         results.push_back(test_x509_ip_addr_blocks_family_merge());
2✔
2351
         results.push_back(test_x509_ip_addr_blocks_path_validation_success_builder());
2✔
2352
         results.push_back(test_x509_ip_addr_blocks_path_validation_success_ctor());
2✔
2353
         results.push_back(test_x509_ip_addr_blocks_path_validation_failure_builder());
2✔
2354
         results.push_back(test_x509_ip_addr_blocks_path_validation_failure_ctor());
2✔
2355
         results.push_back(test_x509_as_blocks_rfc3779_example());
2✔
2356
         results.push_back(test_x509_as_blocks_encode_builder());
2✔
2357
         results.push_back(test_x509_as_blocks_extension_encode_ctor());
2✔
2358
         results.push_back(test_x509_as_blocks_range_merge());
2✔
2359
         results.push_back(test_x509_as_blocks_path_validation_success_builder());
2✔
2360
         results.push_back(test_x509_as_blocks_path_validation_success_ctor());
2✔
2361
         results.push_back(test_x509_as_blocks_path_validation_extension_not_present_builder());
2✔
2362
         results.push_back(test_x509_as_blocks_path_validation_extension_not_present_ctor());
2✔
2363
         results.push_back(test_x509_as_blocks_path_validation_failure_builder());
2✔
2364
         results.push_back(test_x509_as_blocks_path_validation_failure_ctor());
2✔
2365
         return results;
1✔
2366
      }
×
2367
};
2368

2369
BOTAN_REGISTER_TEST("x509", "x509_rpki", X509_RPKI_Tests);
2370

2371
#endif
2372

2373
}  // namespace
2374

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