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

randombit / botan / 25457312714

06 May 2026 07:43PM UTC coverage: 89.331% (-2.3%) from 91.667%
25457312714

push

github

randombit
In TLS 1.3 verification of client certs, check the correct extension for OCSP

This was checking if the client asked us (the server) for OCSP, instead of
checking if we asked the client for OCSP when we sent the CertificateRequest.

107574 of 120422 relevant lines covered (89.33%)

11482758.98 hits per line

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

93.91
/src/tests/test_ec_group.cpp
1
/*
2
* (C) 2007 Falko Strenzke
3
*     2007 Manuel Hartl
4
*     2009,2015,2018,2021 Jack Lloyd
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include "tests.h"
10

11
#if defined(BOTAN_HAS_ECC_GROUP)
12
   #include <botan/bigint.h>
13
   #include <botan/data_src.h>
14
   #include <botan/ec_group.h>
15
   #include <botan/hex.h>
16
   #include <botan/numthry.h>
17
   #include <botan/pk_keys.h>
18
   #include <botan/rng.h>
19
   #include <botan/x509_key.h>
20
   #include <botan/internal/barrett.h>
21
   #include <botan/internal/ec_inner_data.h>
22
   #if defined(BOTAN_HAS_ECDSA)
23
      #include <botan/pk_algs.h>
24
   #endif
25
#endif
26

27
namespace Botan_Tests {
28

29
namespace {
30

31
#if defined(BOTAN_HAS_ECC_GROUP)
32

33
   #if defined(BOTAN_HAS_LEGACY_EC_POINT)
34

35
Botan::BigInt test_integer(Botan::RandomNumberGenerator& rng, size_t bits, const BigInt& max) {
560✔
36
   /*
37
   Produces integers with long runs of ones and zeros, for testing for
38
   carry handling problems.
39
   */
40
   Botan::BigInt x = 0;
560✔
41

42
   auto flip_prob = [](size_t i) -> double {
154,040✔
43
      if(i % 64 == 0) {
153,480✔
44
         return .5;
45
      }
46
      if(i % 32 == 0) {
150,980✔
47
         return .4;
48
      }
49
      if(i % 8 == 0) {
148,560✔
50
         return .05;
14,360✔
51
      }
52
      return .01;
53
   };
54

55
   bool active = (rng.next_byte() > 128) ? true : false;
560✔
56
   for(size_t i = 0; i != bits; ++i) {
154,040✔
57
      x <<= 1;
153,480✔
58
      x += static_cast<int>(active);
153,480✔
59

60
      const double prob = flip_prob(i);
153,480✔
61
      const double sample = double(rng.next_byte() % 100) / 100.0;  // biased
153,480✔
62

63
      if(sample < prob) {
153,480✔
64
         active = !active;
5,088✔
65
      }
66
   }
67

68
   if(x == 0) {
560✔
69
      // EC_Scalar rejects zero as an input, if we hit this case instead
70
      // test with a completely randomized scalar
71
      return BigInt::random_integer(rng, 1, max);
×
72
   }
73

74
   if(max > 0) {
560✔
75
      while(x >= max) {
634✔
76
         const size_t b = x.bits() - 1;
74✔
77
         BOTAN_ASSERT(x.get_bit(b) == true, "Set");
148✔
78
         x.clear_bit(b);
74✔
79
      }
80
   }
81

82
   return x;
560✔
83
}
560✔
84

85
Botan::EC_Point create_random_point(Botan::RandomNumberGenerator& rng, const Botan::EC_Group& group) {
112✔
86
   const Botan::BigInt& p = group.get_p();
112✔
87
   auto mod_p = Botan::Barrett_Reduction::for_public_modulus(p);
112✔
88

89
   for(;;) {
156✔
90
      const Botan::BigInt x = Botan::BigInt::random_integer(rng, 1, p);
268✔
91
      const Botan::BigInt x3 = mod_p.multiply(x, mod_p.square(x));
268✔
92
      const Botan::BigInt ax = mod_p.multiply(group.get_a(), x);
268✔
93
      const Botan::BigInt y = mod_p.reduce(x3 + ax + group.get_b());
268✔
94
      const Botan::BigInt sqrt_y = Botan::sqrt_modulo_prime(y, p);
268✔
95

96
      if(sqrt_y > 1) {
268✔
97
         BOTAN_ASSERT_EQUAL(mod_p.square(sqrt_y), y, "Square root is correct");
224✔
98
         return group.point(x, sqrt_y);
112✔
99
      }
100
   }
268✔
101
}
112✔
102

103
class ECC_Randomized_Tests final : public Test {
1✔
104
   public:
105
      std::vector<Test::Result> run() override;
106
};
107

108
std::vector<Test::Result> ECC_Randomized_Tests::run() {
1✔
109
   std::vector<Test::Result> results;
1✔
110
   for(const std::string& group_name : Botan::EC_Group::known_named_groups()) {
29✔
111
      Test::Result result("ECC randomized " + group_name);
28✔
112

113
      result.start_timer();
28✔
114

115
      auto group = Botan::EC_Group::from_name(group_name);
28✔
116

117
      const Botan::EC_Point pt = create_random_point(this->rng(), group);
28✔
118

119
      try {
28✔
120
         std::vector<Botan::BigInt> blind_ws;
28✔
121
         const size_t trials = (Test::run_long_tests() ? 10 : 3);
28✔
122
         for(size_t i = 0; i < trials; ++i) {
308✔
123
            const Botan::BigInt a = test_integer(rng(), group.get_order_bits(), group.get_order());
280✔
124
            const Botan::BigInt b = test_integer(rng(), group.get_order_bits(), group.get_order());
280✔
125
            const Botan::BigInt c = group.mod_order(a + b);
280✔
126

127
            const Botan::EC_Point P = pt * a;
280✔
128
            const Botan::EC_Point Q = pt * b;
280✔
129
            const Botan::EC_Point R = pt * c;
280✔
130

131
            Botan::EC_Point P1 = group.blinded_var_point_multiply(pt, a, this->rng(), blind_ws);
280✔
132
            Botan::EC_Point Q1 = group.blinded_var_point_multiply(pt, b, this->rng(), blind_ws);
280✔
133
            Botan::EC_Point R1 = group.blinded_var_point_multiply(pt, c, this->rng(), blind_ws);
280✔
134

135
            Botan::EC_Point A1 = P + Q;
280✔
136
            Botan::EC_Point A2 = Q + P;
280✔
137

138
            result.test_bin_eq("p + q", A1.xy_bytes(), R.xy_bytes());
560✔
139
            result.test_bin_eq("q + p", A2.xy_bytes(), R.xy_bytes());
560✔
140

141
            A1.force_affine();
280✔
142
            A2.force_affine();
280✔
143
            result.test_bin_eq("p + q", A1.xy_bytes(), R.xy_bytes());
560✔
144
            result.test_bin_eq("q + p", A2.xy_bytes(), R.xy_bytes());
560✔
145

146
            result.test_is_true("p on the curve", P.on_the_curve());
280✔
147
            result.test_is_true("q on the curve", Q.on_the_curve());
280✔
148
            result.test_is_true("r on the curve", R.on_the_curve());
280✔
149

150
            result.test_bin_eq("P1", P1.xy_bytes(), P.xy_bytes());
560✔
151
            result.test_bin_eq("Q1", Q1.xy_bytes(), Q.xy_bytes());
560✔
152
            result.test_bin_eq("R1", R1.xy_bytes(), R.xy_bytes());
560✔
153

154
            P1.force_affine();
280✔
155
            Q1.force_affine();
280✔
156
            R1.force_affine();
280✔
157
            result.test_bin_eq("P1", P1.xy_bytes(), P.xy_bytes());
560✔
158
            result.test_bin_eq("Q1", Q1.xy_bytes(), Q.xy_bytes());
560✔
159
            result.test_bin_eq("R1", R1.xy_bytes(), R.xy_bytes());
560✔
160
         }
280✔
161
      } catch(std::exception& e) {
28✔
162
         result.test_failure(group_name, e.what());
×
163
      }
×
164
      result.end_timer();
28✔
165
      results.push_back(result);
28✔
166
   }
28✔
167

168
   return results;
1✔
169
}
×
170

171
BOTAN_REGISTER_TEST("pubkey", "ecc_randomized", ECC_Randomized_Tests);
172

173
   #endif
174

175
class EC_Group_Tests : public Test {
1✔
176
   public:
177
      std::vector<Test::Result> run() override {
1✔
178
         std::vector<Test::Result> results;
1✔
179

180
         for(const std::string& group_name : Botan::EC_Group::known_named_groups()) {
29✔
181
            Test::Result result("EC_Group " + group_name);
28✔
182

183
            result.start_timer();
28✔
184

185
            const auto group = Botan::EC_Group::from_name(group_name);
28✔
186

187
            result.test_is_true("EC_Group is known", group.get_curve_oid().has_value());
28✔
188
            result.test_is_true("EC_Group is considered valid", group.verify_group(this->rng(), true));
28✔
189
            result.test_is_true("EC_Group is not considered explicit encoding", !group.used_explicit_encoding());
28✔
190

191
            result.test_sz_eq("EC_Group has correct bit size", group.get_p().bits(), group.get_p_bits());
28✔
192
            result.test_sz_eq("EC_Group has byte size", group.get_p().bytes(), group.get_p_bytes());
28✔
193

194
            result.test_bn_eq("EC_Group has cofactor == 1", group.get_cofactor(), 1);
28✔
195

196
            const Botan::OID from_order = Botan::EC_Group::EC_group_identity_from_order(group.get_order());
28✔
197

198
            result.test_str_eq(
28✔
199
               "EC_group_identity_from_order works", from_order.to_string(), group.get_curve_oid().to_string());
56✔
200

201
            result.test_is_true("Same group is same", group == Botan::EC_Group::from_name(group_name));
28✔
202

203
            try {
28✔
204
               const Botan::EC_Group copy(group.get_curve_oid(),
28✔
205
                                          group.get_p(),
206
                                          group.get_a(),
207
                                          group.get_b(),
208
                                          group.get_g_x(),
209
                                          group.get_g_y(),
210
                                          group.get_order());
28✔
211

212
               result.test_is_true("Same group is same even with copy", group == copy);
20✔
213
            } catch(Botan::Invalid_Argument&) {}
28✔
214

215
            const auto group_der_oid = group.DER_encode();
28✔
216
            const Botan::EC_Group group_via_oid(group_der_oid);
28✔
217
            result.test_is_true("EC_Group via OID is not considered explicit encoding",
28✔
218
                                !group_via_oid.used_explicit_encoding());
28✔
219

220
            const auto group_der_explicit = group.DER_encode(Botan::EC_Group_Encoding::Explicit);
28✔
221
            const Botan::EC_Group group_via_explicit(group_der_explicit);
28✔
222
            result.test_is_true("EC_Group via explicit DER is considered explicit encoding",
28✔
223
                                group_via_explicit.used_explicit_encoding());
28✔
224

225
            if(group.a_is_minus_3()) {
28✔
226
               result.test_bn_eq("Group A equals -3", group.get_a(), group.get_p() - 3);
17✔
227
            } else {
228
               result.test_bn_ne("Group " + group_name + " A does not equal -3", group.get_a(), group.get_p() - 3);
33✔
229
            }
230

231
            if(group.a_is_zero()) {
28✔
232
               result.test_bn_eq("Group A is zero", group.get_a(), BigInt(0));
4✔
233
            } else {
234
               result.test_bn_ne("Group " + group_name + " A does not equal zero", group.get_a(), BigInt(0));
72✔
235
            }
236

237
   #if defined(BOTAN_HAS_LEGACY_EC_POINT)
238
            const auto pt_mult_by_order = group.get_base_point() * group.get_order();
28✔
239
            result.test_is_true("Multiplying point by the order results in zero point", pt_mult_by_order.is_zero());
28✔
240

241
            // get a valid point
242
            Botan::EC_Point p = group.get_base_point() * this->rng().next_nonzero_byte();
28✔
243

244
            // get a copy
245
            Botan::EC_Point q = p;
28✔
246

247
            p.randomize_repr(this->rng());
28✔
248
            q.randomize_repr(this->rng());
28✔
249

250
            result.test_bn_eq("affine x after copy", p.get_affine_x(), q.get_affine_x());
28✔
251
            result.test_bn_eq("affine y after copy", p.get_affine_y(), q.get_affine_y());
28✔
252

253
            q.force_affine();
28✔
254

255
            result.test_bn_eq("affine x after copy", p.get_affine_x(), q.get_affine_x());
28✔
256
            result.test_bn_eq("affine y after copy", p.get_affine_y(), q.get_affine_y());
28✔
257

258
            test_ser_der(result, group);
28✔
259
            test_basic_math(result, group);
28✔
260
            test_point_swap(result, group);
28✔
261
            test_zeropoint(result, group);
28✔
262
   #endif
263

264
            result.end_timer();
28✔
265

266
            results.push_back(result);
28✔
267
         }
84✔
268

269
         return results;
1✔
270
      }
×
271

272
   private:
273
   #if defined(BOTAN_HAS_LEGACY_EC_POINT)
274

275
      void test_ser_der(Test::Result& result, const Botan::EC_Group& group) {
28✔
276
         // generate point
277
         const Botan::EC_Point pt = create_random_point(this->rng(), group);
28✔
278
         const Botan::EC_Point zero = group.zero_point();
28✔
279

280
         for(auto scheme : {Botan::EC_Point_Format::Uncompressed,
84✔
281
                            Botan::EC_Point_Format::Compressed,
282
                            Botan::EC_Point_Format::Hybrid}) {
112✔
283
            try {
84✔
284
               result.test_bin_eq("encoded/decode rt works", group.OS2ECP(pt.encode(scheme)).xy_bytes(), pt.xy_bytes());
336✔
285
            } catch(Botan::Exception& e) {
×
286
               result.test_failure("Failed to round trip encode a random point", e.what());
×
287
            }
×
288

289
            try {
84✔
290
               result.test_is_true("encoded/decode rt works", group.OS2ECP(zero.encode(scheme)).is_zero());
252✔
291
            } catch(Botan::Exception& e) {
×
292
               result.test_failure("Failed to round trip encode the identity element", e.what());
×
293
            }
×
294
         }
295
      }
28✔
296

297
      static void test_basic_math(Test::Result& result, const Botan::EC_Group& group) {
28✔
298
         const Botan::EC_Point& G = group.get_base_point();
28✔
299

300
         const auto G2 = G * 2;
56✔
301
         const auto G3 = G * 3;
56✔
302

303
         Botan::EC_Point p1 = G2;
28✔
304
         p1 += G;
28✔
305

306
         result.test_bin_eq("point addition", p1.xy_bytes(), G3.xy_bytes());
56✔
307

308
         p1 -= G2;
28✔
309

310
         result.test_bin_eq("point subtraction", p1.xy_bytes(), G.xy_bytes());
56✔
311

312
         // The scalar multiplication algorithm relies on this being true:
313
         try {
28✔
314
            const Botan::EC_Point zero_coords = group.point(0, 0);
56✔
315
            result.test_is_true("point (0,0) is not on the curve", !zero_coords.on_the_curve());
×
316
         } catch(Botan::Exception&) {
28✔
317
            result.test_success("point (0,0) is rejected");
28✔
318
         }
28✔
319
      }
28✔
320

321
      void test_point_swap(Test::Result& result, const Botan::EC_Group& group) {
28✔
322
         const Botan::EC_Point a(create_random_point(this->rng(), group));
28✔
323
         Botan::EC_Point b(create_random_point(this->rng(), group));
28✔
324
         b *= Botan::BigInt(this->rng(), 20);
28✔
325

326
         Botan::EC_Point c(a);
28✔
327
         Botan::EC_Point d(b);
28✔
328

329
         d.swap(c);
28✔
330
         result.test_bin_eq("swap correct", a.xy_bytes(), d.xy_bytes());
56✔
331
         result.test_bin_eq("swap correct", b.xy_bytes(), c.xy_bytes());
56✔
332
      }
28✔
333

334
      static void test_zeropoint(Test::Result& result, const Botan::EC_Group& group) {
28✔
335
         Botan::EC_Point zero = group.zero_point();
28✔
336

337
         result.test_throws("Zero point throws", "Cannot convert zero point to affine", [&]() { zero.get_affine_x(); });
56✔
338
         result.test_throws("Zero point throws", "Cannot convert zero point to affine", [&]() { zero.get_affine_y(); });
56✔
339

340
         const Botan::EC_Point p1 = group.get_base_point() * 2;
28✔
341

342
         result.test_is_true("point is on the curve", p1.on_the_curve());
28✔
343
         result.test_is_true("point is not zero", !p1.is_zero());
28✔
344

345
         Botan::EC_Point p2 = p1;
28✔
346
         p2 -= p1;
28✔
347

348
         result.test_is_true("p - q with q = p results in zero", p2.is_zero());
28✔
349

350
         const Botan::EC_Point minus_p1 = -p1;
28✔
351
         result.test_is_true("point is on the curve", minus_p1.on_the_curve());
28✔
352
         const Botan::EC_Point shouldBeZero = p1 + minus_p1;
28✔
353
         result.test_is_true("point is on the curve", shouldBeZero.on_the_curve());
28✔
354
         result.test_is_true("point is zero", shouldBeZero.is_zero());
28✔
355

356
         result.test_bn_eq("minus point x", minus_p1.get_affine_x(), p1.get_affine_x());
28✔
357
         result.test_bn_eq("minus point y", minus_p1.get_affine_y(), group.get_p() - p1.get_affine_y());
28✔
358

359
         result.test_is_true("zero point is zero", zero.is_zero());
28✔
360
         result.test_is_true("zero point is on the curve", zero.on_the_curve());
28✔
361
         result.test_bin_eq("addition of zero does nothing", p1.xy_bytes(), (p1 + zero).xy_bytes());
84✔
362
         result.test_bin_eq("addition of zero does nothing", p1.xy_bytes(), (zero + p1).xy_bytes());
84✔
363
         result.test_bin_eq("addition of zero does nothing", p1.xy_bytes(), (p1 - zero).xy_bytes());
84✔
364
         result.test_is_true("zero times anything is the zero point", (zero * 39193).is_zero());
56✔
365

366
         for(auto scheme : {Botan::EC_Point_Format::Uncompressed,
196✔
367
                            Botan::EC_Point_Format::Compressed,
368
                            Botan::EC_Point_Format::Hybrid}) {
112✔
369
            const std::vector<uint8_t> v = zero.encode(scheme);
84✔
370
            result.test_is_true("encoded/decode rt works", group.OS2ECP(v).is_zero());
168✔
371
         }
84✔
372
      }
28✔
373
   #endif
374
};
375

376
BOTAN_REGISTER_TEST("pubkey", "ec_group", EC_Group_Tests);
377

378
Test::Result test_decoding_with_seed() {
1✔
379
   Test::Result result("Decode EC_Group with seed");
1✔
380

381
   try {
1✔
382
      if(Botan::EC_Group::supports_named_group("secp384r1")) {
1✔
383
         const auto secp384r1 = Botan::EC_Group::from_name("secp384r1");
1✔
384
         const auto secp384r1_with_seed =
1✔
385
            Botan::EC_Group::from_PEM(Test::read_data_file("x509/ecc/secp384r1_seed.pem"));
2✔
386
         result.test_is_true("decoding worked", secp384r1_with_seed.initialized());
1✔
387
         result.test_bn_eq("P-384 prime", secp384r1_with_seed.get_p(), secp384r1.get_p());
1✔
388
      }
1✔
389
   } catch(Botan::Exception& e) {
×
390
      result.test_failure(e.what());
×
391
   }
×
392

393
   return result;
1✔
394
}
×
395

396
Test::Result test_mixed_points() {
1✔
397
   Test::Result result("Mixed Point Arithmetic");
1✔
398

399
   if(Botan::EC_Group::supports_named_group("secp256r1") && Botan::EC_Group::supports_named_group("secp384r1")) {
1✔
400
      const auto secp256r1 = Botan::EC_Group::from_name("secp256r1");
1✔
401
      const auto secp384r1 = Botan::EC_Group::from_name("secp384r1");
1✔
402

403
   #if defined(BOTAN_HAS_LEGACY_EC_POINT)
404
      const Botan::EC_Point& G256 = secp256r1.get_base_point();
1✔
405
      const Botan::EC_Point& G384 = secp384r1.get_base_point();
1✔
406

407
      result.test_throws("Mixing points from different groups", [&] { const Botan::EC_Point p = G256 + G384; });
2✔
408
   #endif
409

410
      const auto p1 = Botan::EC_AffinePoint::generator(secp256r1);
1✔
411
      const auto p2 = Botan::EC_AffinePoint::generator(secp384r1);
1✔
412
      result.test_throws("Mixing points from different groups", [&] { auto p3 = p1.add(p2); });
2✔
413
   }
1✔
414

415
   return result;
1✔
416
}
×
417

418
class ECC_Unit_Tests final : public Test {
1✔
419
   public:
420
      std::vector<Test::Result> run() override {
1✔
421
         std::vector<Test::Result> results;
1✔
422

423
         results.push_back(test_decoding_with_seed());
2✔
424
         results.push_back(test_mixed_points());
2✔
425

426
         return results;
1✔
427
      }
×
428
};
429

430
BOTAN_REGISTER_TEST("pubkey", "ecc_unit", ECC_Unit_Tests);
431

432
class EC_Group_Registration_Tests final : public Test {
1✔
433
   public:
434
      std::vector<Test::Result> run() override {
1✔
435
         std::vector<Test::Result> results;
1✔
436

437
         if(Botan::EC_Group::supports_application_specific_group()) {
1✔
438
            results.push_back(test_ecc_registration());
2✔
439
            results.push_back(test_ec_group_from_params());
2✔
440
            results.push_back(test_ec_group_bad_registration());
2✔
441
            results.push_back(test_ec_group_duplicate_orders());
2✔
442
            results.push_back(test_ec_group_registration_with_custom_oid());
2✔
443
            results.push_back(test_ec_group_unregistration());
2✔
444
            results.push_back(test_supports_named_group_with_registration());
2✔
445
         }
446

447
         return results;
1✔
448
      }
×
449

450
   private:
451
      Test::Result test_ecc_registration() {
1✔
452
         Test::Result result("ECC registration");
1✔
453

454
         // numsp256d1
455
         const Botan::BigInt p("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43");
1✔
456
         const Botan::BigInt a("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40");
1✔
457
         const Botan::BigInt b("0x25581");
1✔
458
         const Botan::BigInt order("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE43C8275EA265C6020AB20294751A825");
1✔
459

460
         const Botan::BigInt g_x("0x01");
1✔
461
         const Botan::BigInt g_y("0x696F1853C1E466D7FC82C96CCEEEDD6BD02C2F9375894EC10BF46306C2B56C77");
1✔
462

463
         const Botan::OID oid("1.3.6.1.4.1.25258.4.1");
1✔
464

465
         // Creating this object implicitly registers the curve for future use ...
466
         const Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);
1✔
467

468
         auto group = Botan::EC_Group::from_OID(oid);
1✔
469

470
         result.test_bn_eq("Group registration worked", group.get_p(), p);
1✔
471

472
         // TODO(Botan4) this could change to == Generic
473
         result.test_is_true("Group is not pcurve", group.engine() != Botan::EC_Group_Engine::Optimized);
1✔
474

475
         return result;
1✔
476
      }
1✔
477

478
      Test::Result test_ec_group_from_params() {
1✔
479
         Test::Result result("EC_Group from params");
1✔
480

481
         Botan::EC_Group::clear_registered_curve_data();
1✔
482

483
         // secp256r1
484
         const Botan::BigInt p("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
1✔
485
         const Botan::BigInt a("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
1✔
486
         const Botan::BigInt b("0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
1✔
487

488
         const Botan::BigInt g_x("0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
1✔
489
         const Botan::BigInt g_y("0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
1✔
490
         const Botan::BigInt order("0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
1✔
491

492
         const Botan::OID oid("1.2.840.10045.3.1.7");
1✔
493

494
         // This uses the deprecated constructor to verify we dedup even without an OID
495
         // This whole test can be removed once explicit curve support is removed
496
         const Botan::EC_Group reg_group(p, a, b, g_x, g_y, order, 1);
1✔
497
         result.test_is_true("Group has correct OID", reg_group.get_curve_oid() == oid);
1✔
498

499
         return result;
1✔
500
      }
1✔
501

502
      Test::Result test_ec_group_bad_registration() {
1✔
503
         Test::Result result("EC_Group registering non-match");
1✔
504

505
         Botan::EC_Group::clear_registered_curve_data();
1✔
506

507
         // secp256r1 params except with a bad B param
508
         const Botan::BigInt p("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
1✔
509
         const Botan::BigInt a("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
1✔
510
         const Botan::BigInt b("0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604C");
1✔
511

512
         const Botan::BigInt g_x("0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
1✔
513
         const Botan::BigInt g_y("0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
1✔
514
         const Botan::BigInt order("0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
1✔
515

516
         const Botan::OID oid("1.2.840.10045.3.1.7");
1✔
517

518
         try {
1✔
519
            const Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);
1✔
520
            result.test_failure("Should have failed");
×
521
         } catch(Botan::Invalid_Argument&) {
1✔
522
            result.test_success("Got expected exception");
1✔
523
         }
1✔
524

525
         return result;
2✔
526
      }
1✔
527

528
      Test::Result test_ec_group_duplicate_orders() {
1✔
529
         Test::Result result("EC_Group with duplicate group order");
1✔
530

531
         Botan::EC_Group::clear_registered_curve_data();
1✔
532

533
         // secp256r1
534
         const Botan::BigInt p("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
1✔
535
         const Botan::BigInt a("0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
1✔
536
         const Botan::BigInt b("0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
1✔
537

538
         const Botan::BigInt g_x("0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
1✔
539
         const Botan::BigInt g_y("0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
1✔
540
         const Botan::BigInt order("0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
1✔
541

542
         const Botan::OID oid("1.3.6.1.4.1.25258.100.0");  // some other random OID
1✔
543

544
         const Botan::EC_Group reg_group(oid, p, a, b, g_x, g_y, order);
1✔
545
         result.test_success("Registration success");
1✔
546
         result.test_is_true("Group has correct OID", reg_group.get_curve_oid() == oid);
1✔
547

548
         // We can now get it by OID:
549
         const auto hc_group = Botan::EC_Group::from_OID(oid);
1✔
550
         result.test_is_true("Group has correct OID", hc_group.get_curve_oid() == oid);
1✔
551

552
         // Existing secp256r1 unmodified:
553
         const Botan::OID secp160r1("1.2.840.10045.3.1.7");
1✔
554
         const auto other_group = Botan::EC_Group::from_OID(secp160r1);
1✔
555
         result.test_is_true("Group has correct OID", other_group.get_curve_oid() == secp160r1);
1✔
556

557
         return result;
1✔
558
      }
1✔
559

560
      Test::Result test_ec_group_registration_with_custom_oid() {
1✔
561
         Test::Result result("EC_Group registration of standard group with custom OID");
1✔
562

563
         Botan::EC_Group::clear_registered_curve_data();
1✔
564

565
         const Botan::OID secp256r1_oid("1.2.840.10045.3.1.7");
1✔
566
         const auto secp256r1 = Botan::EC_Group::from_OID(secp256r1_oid);
1✔
567
         result.test_is_true("Group has correct OID", secp256r1.get_curve_oid() == secp256r1_oid);
1✔
568

569
         const Botan::OID custom_oid("1.3.6.1.4.1.25258.100.99");  // some other random OID
1✔
570

571
         Botan::OID::register_oid(custom_oid, "secp256r1");
1✔
572

573
         const Botan::EC_Group reg_group(custom_oid,
1✔
574
                                         secp256r1.get_p(),
575
                                         secp256r1.get_a(),
576
                                         secp256r1.get_b(),
577
                                         secp256r1.get_g_x(),
578
                                         secp256r1.get_g_y(),
579
                                         secp256r1.get_order());
1✔
580

581
         result.test_success("Registration success");
1✔
582
         result.test_is_true("Group has correct OID", reg_group.get_curve_oid() == custom_oid);
1✔
583

584
         // We can now get it by OID:
585
         result.test_is_true("Group has correct OID",
1✔
586
                             Botan::EC_Group::from_OID(custom_oid).get_curve_oid() == custom_oid);
1✔
587

588
         // In the current data model of EC_Group there is a 1:1 OID:group, so these
589
         // have distinct underlying data
590
         result.test_is_true("Groups have different inner data pointers", reg_group._data() != secp256r1._data());
1✔
591

592
   #if defined(BOTAN_HAS_PCURVES_SECP256R1)
593
         // However we should have gotten a pcurves out of the deal *and* it
594
         // should be the exact same shared_ptr as the official curve
595

596
         result.test_enum_eq("Group is pcurves based", reg_group.engine(), Botan::EC_Group_Engine::Optimized);
1✔
597

598
         try {
1✔
599
            const auto& pcurve = reg_group._data()->pcurve();
1✔
600
            result.test_is_true("Group with custom OID got the same pcurve pointer",
1✔
601
                                &pcurve == &secp256r1._data()->pcurve());
1✔
602
         } catch(...) {
×
603
            result.test_failure("Group with custom OID did not get a pcurve pointer");
×
604
         }
×
605
   #endif
606

607
         return result;
2✔
608
      }
1✔
609

610
      Test::Result test_supports_named_group_with_registration() {
1✔
611
         Test::Result result("EC_Group::supports_named_group with custom registration");
1✔
612

613
         Botan::EC_Group::clear_registered_curve_data();
1✔
614

615
         result.test_is_false("Unknown name is not supported",
1✔
616
                              Botan::EC_Group::supports_named_group("not_a_real_curve_name_xyz"));
1✔
617

618
         const Botan::OID custom_oid("1.3.6.1.4.1.25258.4.9000");
1✔
619
         const std::string custom_name = "goku-curve";  // very strong
1✔
620

621
         Botan::OID::register_oid(custom_oid, custom_name);
1✔
622

623
         result.test_is_false("Mapped OID without registered EC_Group is not supported",
1✔
624
                              Botan::EC_Group::supports_named_group(custom_name));
1✔
625

626
         const Botan::BigInt p("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF43");
1✔
627
         const Botan::BigInt a("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40");
1✔
628
         const Botan::BigInt b("0x25581");
1✔
629
         const Botan::BigInt order("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE43C8275EA265C6020AB20294751A825");
1✔
630
         const Botan::BigInt g_x("0x01");
1✔
631
         const Botan::BigInt g_y("0x696F1853C1E466D7FC82C96CCEEEDD6BD02C2F9375894EC10BF46306C2B56C77");
1✔
632

633
         const Botan::EC_Group reg_group(custom_oid, p, a, b, g_x, g_y, order);
1✔
634

635
         result.test_is_true("After registration the custom name is supported",
1✔
636
                             Botan::EC_Group::supports_named_group(custom_name));
1✔
637

638
         const auto resolved = Botan::EC_Group::from_name(custom_name);
1✔
639
         result.test_is_true("from_name resolves to the registered OID", resolved.get_curve_oid() == custom_oid);
1✔
640

641
         result.test_is_false("known_named_groups still does not include custom name",
1✔
642
                              Botan::EC_Group::known_named_groups().contains(custom_name));
1✔
643

644
         result.test_is_true("Unregistering removes support for the custom name",
1✔
645
                             Botan::EC_Group::unregister(custom_oid));
1✔
646
         result.test_is_false("After unregister the custom name is not supported",
1✔
647
                              Botan::EC_Group::supports_named_group(custom_name));
1✔
648

649
         return result;
2✔
650
      }
1✔
651

652
      Test::Result test_ec_group_unregistration() {
1✔
653
         Test::Result result("EC_Group unregistration of group");
1✔
654

655
         Botan::EC_Group::clear_registered_curve_data();
1✔
656

657
         const Botan::OID secp256r1_oid("1.2.840.10045.3.1.7");
1✔
658
         const auto secp256r1 = Botan::EC_Group::from_OID(secp256r1_oid);
1✔
659
         const Botan::OID custom_oid("1.3.6.1.4.1.25258.100.99");
1✔
660
         Botan::OID::register_oid(custom_oid, "secp256r1");
1✔
661

662
         const Botan::EC_Group reg_group(custom_oid,
1✔
663
                                         secp256r1.get_p(),
664
                                         secp256r1.get_a(),
665
                                         secp256r1.get_b(),
666
                                         secp256r1.get_g_x(),
667
                                         secp256r1.get_g_y(),
668
                                         secp256r1.get_order());
1✔
669

670
         const Botan::EC_Group group_from_oid = Botan::EC_Group::from_OID(custom_oid);
1✔
671

672
         result.test_is_true("Internal group is unregistered", Botan::EC_Group::unregister(secp256r1_oid));
1✔
673
         result.test_is_false("Unregistering internal group again does nothing",
1✔
674
                              Botan::EC_Group::unregister(secp256r1_oid));
1✔
675
         result.test_is_true("User defined group is unregistered", Botan::EC_Group::unregister(custom_oid));
1✔
676
         result.test_is_false("Unregistering user defined group again does nothing",
1✔
677
                              Botan::EC_Group::unregister(custom_oid));
1✔
678

679
         try {
1✔
680
            Botan::EC_Group::from_OID(custom_oid);
1✔
681
            result.test_failure("Should have failed");
×
682
         } catch(Botan::Invalid_Argument&) {
1✔
683
            result.test_success("Got expected exception");
1✔
684
         }
1✔
685

686
         result.test_is_true("Group can still be accessed", reg_group.get_curve_oid() == custom_oid);
1✔
687
         result.test_is_true("Group has correct p parameter", reg_group.get_p() == secp256r1.get_p());
1✔
688
         result.test_is_true("Group has correct a parameter", reg_group.get_a() == secp256r1.get_a());
1✔
689
         result.test_is_true("Group has correct b parameter", reg_group.get_b() == secp256r1.get_b());
1✔
690
         result.test_is_true("Group has correct g_x parameter", reg_group.get_g_x() == secp256r1.get_g_x());
1✔
691
         result.test_is_true("Group has correct g_y parameter", reg_group.get_g_y() == secp256r1.get_g_y());
1✔
692
         result.test_is_true("Group has correct order parameter", reg_group.get_order() == secp256r1.get_order());
1✔
693

694
   #if defined(BOTAN_HAS_ECDSA)
695
         std::unique_ptr<Botan::RandomNumberGenerator> rng = Test::new_rng("test_ec_group_unregistration");
1✔
696
         std::unique_ptr<Botan::Private_Key> key = Botan::create_ec_private_key("ECDSA", group_from_oid, *rng);
1✔
697
         result.test_success("Can still use group to create a key");
1✔
698
         result.test_is_true("Key was created correctly", key->check_key(*rng, true));
1✔
699
   #endif
700

701
         // TODO(Botan4) remove this when OIDs lose internal nullability
702
         try {
1✔
703
            const Botan::OID empty_oid("");
1✔
704
            Botan::EC_Group::unregister(empty_oid);
1✔
705
            result.test_failure("Should have failed");
×
706
         } catch(Botan::Invalid_Argument&) {
1✔
707
            result.test_success("Got expected exception");
1✔
708
         }
1✔
709

710
         return result;
1✔
711
      }
2✔
712
};
713

714
BOTAN_REGISTER_SERIALIZED_TEST("pubkey", "ec_group_registration", EC_Group_Registration_Tests);
715

716
class EC_PointEnc_Tests final : public Test {
1✔
717
   public:
718
      std::vector<Test::Result> run() override {
1✔
719
         std::vector<Test::Result> results;
1✔
720

721
         auto& rng = Test::rng();
1✔
722

723
         for(const auto& group_id : Botan::EC_Group::known_named_groups()) {
29✔
724
            const auto group = Botan::EC_Group::from_name(group_id);
28✔
725

726
            Result result("EC_AffinePoint encoding " + group_id);
28✔
727

728
            result.start_timer();
28✔
729

730
            for(size_t trial = 0; trial != 100; ++trial) {
2,828✔
731
               const auto scalar = Botan::EC_Scalar::random(group, rng);
2,800✔
732
               const auto pt = Botan::EC_AffinePoint::g_mul(scalar, rng);
2,800✔
733

734
               const auto pt_u = pt.serialize_uncompressed();
2,800✔
735
               result.test_u8_eq("Expected uncompressed header", pt_u[0], 0x04);
2,800✔
736
               const size_t fe_bytes = (pt_u.size() - 1) / 2;
2,800✔
737
               const auto pt_c = pt.serialize_compressed();
2,800✔
738

739
               result.test_sz_eq("Expected compressed size", pt_c.size(), 1 + fe_bytes);
2,800✔
740
               const uint8_t expected_c_header = (pt_u[pt_u.size() - 1] % 2 == 0) ? 0x02 : 0x03;
2,800✔
741
               result.test_u8_eq("Expected compressed header", pt_c[0], expected_c_header);
2,800✔
742

743
               result.test_bin_eq(
2,800✔
744
                  "Expected compressed x", std::span{pt_c}.subspan(1), std::span{pt_u}.subspan(1, fe_bytes));
745

746
               if(auto d_pt_u = Botan::EC_AffinePoint::deserialize(group, pt_u)) {
2,800✔
747
                  result.test_bin_eq(
2,800✔
748
                     "Deserializing uncompressed returned correct point", d_pt_u->serialize_uncompressed(), pt_u);
5,600✔
749
               } else {
750
                  result.test_failure("Failed to deserialize uncompressed point");
×
751
               }
×
752

753
               if(auto d_pt_c = Botan::EC_AffinePoint::deserialize(group, pt_c)) {
2,800✔
754
                  result.test_bin_eq(
2,800✔
755
                     "Deserializing compressed returned correct point", d_pt_c->serialize_uncompressed(), pt_u);
5,600✔
756
               } else {
757
                  result.test_failure("Failed to deserialize compressed point");
×
758
               }
×
759

760
               const auto neg_pt_c = [&]() {
2,800✔
761
                  auto x = pt_c;
2,800✔
762
                  x[0] ^= 0x01;
2,800✔
763
                  return x;
2,800✔
764
               }();
2,800✔
765

766
               if(auto d_neg_pt_c = Botan::EC_AffinePoint::deserialize(group, neg_pt_c)) {
2,800✔
767
                  result.test_bin_eq("Deserializing compressed with inverted header returned negated point",
2,800✔
768
                                     d_neg_pt_c->serialize_uncompressed(),
5,600✔
769
                                     pt.negate().serialize_uncompressed());
5,600✔
770
               } else {
771
                  result.test_failure("Failed to deserialize compressed point");
×
772
               }
2,800✔
773
            }
2,800✔
774

775
            result.end_timer();
28✔
776

777
            results.push_back(result);
28✔
778
         }
28✔
779

780
         return results;
1✔
781
      }
2,800✔
782
};
783

784
BOTAN_REGISTER_TEST("pubkey", "ec_point_enc", EC_PointEnc_Tests);
785

786
class EC_Point_Arithmetic_Tests final : public Test {
1✔
787
   public:
788
      std::vector<Test::Result> run() override {
1✔
789
         std::vector<Test::Result> results;
1✔
790

791
         auto& rng = Test::rng();
1✔
792

793
         for(const auto& group_id : Botan::EC_Group::known_named_groups()) {
29✔
794
            const auto group = Botan::EC_Group::from_name(group_id);
28✔
795

796
            Result result("EC_AffinePoint arithmetic " + group_id);
28✔
797

798
            result.start_timer();
28✔
799

800
            const auto one = Botan::EC_Scalar::one(group);
28✔
801
            const auto zero = one - one;  // NOLINT(*-redundant-expression)
28✔
802
            const auto g = Botan::EC_AffinePoint::generator(group);
28✔
803
            const auto g_bytes = g.serialize_uncompressed();
28✔
804

805
            const auto id = Botan::EC_AffinePoint::g_mul(zero, rng);
28✔
806
            result.test_is_true("g*zero is point at identity", id.is_identity());
28✔
807

808
            const auto id2 = id.add(id);
28✔
809
            result.test_is_true("identity plus itself is identity", id2.is_identity());
28✔
810

811
            const auto g_one = Botan::EC_AffinePoint::g_mul(one, rng);
28✔
812
            result.test_bin_eq("g*one == generator", g_one.serialize_uncompressed(), g_bytes);
28✔
813

814
            const auto g_plus_id = g_one.add(id);
28✔
815
            result.test_bin_eq("g + id == g", g_plus_id.serialize_uncompressed(), g_bytes);
28✔
816

817
            const auto id_plus_g = id.add(g_one);
28✔
818
            result.test_bin_eq("id + g == g", id_plus_g.serialize_uncompressed(), g_bytes);
28✔
819

820
            const auto g_neg_one = Botan::EC_AffinePoint::g_mul(one.negate(), rng);
28✔
821

822
            const auto id_from_g = g_one.add(g_neg_one);
28✔
823
            result.test_is_true("g - g is identity", id_from_g.is_identity());
28✔
824

825
            const auto g_two = Botan::EC_AffinePoint::g_mul(one + one, rng);
28✔
826
            const auto g_plus_g = g_one.add(g_one);
28✔
827
            result.test_bin_eq("2*g == g+g", g_two.serialize_uncompressed(), g_plus_g.serialize_uncompressed());
56✔
828

829
            result.test_is_true("Scalar::zero is zero", zero.is_zero());
28✔
830
            result.test_is_true("(zero+zero) is zero", (zero + zero).is_zero());
28✔
831
            result.test_is_true("(zero*zero) is zero", (zero * zero).is_zero());
28✔
832
            result.test_is_true("(zero-zero) is zero", (zero - zero).is_zero());  // NOLINT(*-redundant-expression)
28✔
833

834
            const auto neg_zero = zero.negate();
28✔
835
            result.test_is_true("zero.negate() is zero", neg_zero.is_zero());
28✔
836

837
            result.test_is_true("(zero+nz) is zero", (zero + neg_zero).is_zero());
28✔
838
            result.test_is_true("(nz+nz) is zero", (neg_zero + neg_zero).is_zero());
28✔
839
            result.test_is_true("(nz+zero) is zero", (neg_zero + zero).is_zero());
28✔
840

841
            result.test_is_true("Scalar::one is not zero", !one.is_zero());
28✔
842
            result.test_is_true("(one-one) is zero", (one - one).is_zero());  // NOLINT(*-redundant-expression)
28✔
843
            result.test_is_true("(one+one.negate()) is zero", (one + one.negate()).is_zero());
56✔
844
            result.test_is_true("(one.negate()+one) is zero", (one.negate() + one).is_zero());
56✔
845

846
            for(size_t i = 0; i != 16; ++i) {
476✔
847
               const auto pt = Botan::EC_AffinePoint::g_mul(Botan::EC_Scalar::random(group, rng), rng);
448✔
848

849
               const auto a = Botan::EC_Scalar::random(group, rng);
448✔
850
               const auto b = Botan::EC_Scalar::random(group, rng);
448✔
851
               const auto c = a + b;
448✔
852

853
               const auto Pa = pt.mul(a, rng);
448✔
854
               const auto Pb = pt.mul(b, rng);
448✔
855
               const auto Pc = pt.mul(c, rng);
448✔
856

857
               const auto Pc_bytes = Pc.serialize_uncompressed();
448✔
858

859
               const auto Pab = Pa.add(Pb);
448✔
860
               result.test_bin_eq("Pa + Pb == Pc", Pab.serialize_uncompressed(), Pc_bytes);
448✔
861

862
               const auto Pba = Pb.add(Pa);
448✔
863
               result.test_bin_eq("Pb + Pa == Pc", Pba.serialize_uncompressed(), Pc_bytes);
448✔
864
            }
896✔
865

866
            for(size_t i = 0; i != 64; ++i) {
1,820✔
867
               auto h = [&]() {
5,376✔
868
                  const auto s = [&]() {
5,376✔
869
                     if(i == 0) {
1,792✔
870
                        // Test the identity case
871
                        return Botan::EC_Scalar(zero);
28✔
872
                     } else if(i <= 32) {
1,764✔
873
                        // Test cases where the two points have a linear relation
874
                        std::vector<uint8_t> sbytes(group.get_order_bytes());
896✔
875
                        sbytes[sbytes.size() - 1] = static_cast<uint8_t>((i + 1) / 2);
896✔
876
                        auto si = Botan::EC_Scalar::deserialize(group, sbytes).value();
1,792✔
877
                        if(i % 2 == 0) {
896✔
878
                           return si;
448✔
879
                        } else {
880
                           return si.negate();
448✔
881
                        }
882
                     } else {
1,792✔
883
                        return Botan::EC_Scalar::random(group, rng);
868✔
884
                     }
885
                  }();
1,792✔
886
                  auto x = Botan::EC_AffinePoint::g_mul(s, rng);
1,792✔
887
                  return x;
1,792✔
888
               }();
3,584✔
889

890
               const auto s1 = Botan::EC_Scalar::random(group, rng);
1,792✔
891
               const auto s2 = Botan::EC_Scalar::random(group, rng);
1,792✔
892

893
               const Botan::EC_Group::Mul2Table mul2_table(h);
1,792✔
894

895
               const auto ref = Botan::EC_AffinePoint::g_mul(s1, rng).add(h.mul(s2, rng));
1,792✔
896

897
               if(auto mul2pt = mul2_table.mul2_vartime(s1, s2)) {
1,792✔
898
                  result.test_bin_eq("ref == mul2t", ref.serialize_uncompressed(), mul2pt->serialize_uncompressed());
5,376✔
899
               } else {
900
                  result.test_is_true("ref is identity", ref.is_identity());
×
901
               }
×
902
            }
1,792✔
903

904
            result.end_timer();
28✔
905

906
            results.push_back(result);
28✔
907
         }
56✔
908

909
         return results;
1✔
910
      }
×
911
};
912

913
BOTAN_REGISTER_TEST("pubkey", "ec_point_arith", EC_Point_Arithmetic_Tests);
914

915
   #if defined(BOTAN_HAS_ECDSA)
916

917
class ECC_Invalid_Key_Tests final : public Text_Based_Test {
×
918
   public:
919
      ECC_Invalid_Key_Tests() : Text_Based_Test("pubkey/ecc_invalid.vec", "SubjectPublicKey") {}
2✔
920

921
      bool clear_between_callbacks() const override { return false; }
5✔
922

923
      Test::Result run_one_test(const std::string& /*header*/, const VarMap& vars) override {
5✔
924
         Test::Result result("ECC invalid keys");
5✔
925

926
         const std::string encoded = vars.get_req_str("SubjectPublicKey");
5✔
927
         Botan::DataSource_Memory key_data(Botan::hex_decode(encoded));
10✔
928

929
         try {
5✔
930
            auto key = Botan::X509::load_key(key_data);
5✔
931
            result.test_is_false("public key fails check", key->check_key(this->rng(), false));
×
932
         } catch(Botan::Decoding_Error&) {
5✔
933
            result.test_success("Decoding invalid ECC key results in decoding error exception");
5✔
934
         }
5✔
935

936
         return result;
5✔
937
      }
5✔
938
};
939

940
BOTAN_REGISTER_TEST("pubkey", "ecc_invalid", ECC_Invalid_Key_Tests);
941

942
   #endif
943

944
#endif
945

946
}  // namespace
947

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