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

randombit / botan / 29801022385

21 Jul 2026 02:12AM UTC coverage: 89.404% (-0.02%) from 89.419%
29801022385

push

github

web-flow
Merge pull request #5747 from randombit/jack/zfec-avx512-gfni

ZFEC optimizations and improvements

114453 of 128018 relevant lines covered (89.4%)

10848451.21 hits per line

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

98.44
/src/tests/test_ffi.cpp
1
/*
2
* (C) 2015 Jack Lloyd
3
* (C) 2016 René Korthaus
4
* (C) 2018 Ribose Inc, Krzysztof Kwiatkowski
5
* (C) 2018 Ribose Inc
6
*
7
* Botan is released under the Simplified BSD License (see license.txt)
8
*/
9

10
#include "tests.h"
11
#include <botan/version.h>
12

13
#if defined(BOTAN_HAS_FFI)
14
   #include <botan/ber_dec.h>
15
   #include <botan/ec_group.h>
16
   #include <botan/ffi.h>
17
   #include <botan/hex.h>
18
   #include <botan/mem_ops.h>
19
   #include <botan/internal/calendar.h>
20
   #include <botan/internal/concat_util.h>
21
   #include <botan/internal/fmt.h>
22
   #include <botan/internal/loadstor.h>
23
   #include <botan/internal/stl_util.h>
24
   #include <botan/internal/target_info.h>
25
   #include <set>
26
#endif
27

28
#if defined(BOTAN_HAS_X509)
29
   #include <botan/pkix_enums.h>
30
   #include <botan/pkix_types.h>
31
#endif
32

33
#if defined(BOTAN_HAS_TPM2)
34
   #include <tss2/tss2_esys.h>
35
   #include <tss2/tss2_tctildr.h>
36
#endif
37

38
namespace Botan_Tests {
39

40
namespace {
41

42
#if defined(BOTAN_HAS_FFI)
43

44
// NOLINTBEGIN(*-macro-usage)
45

46
   #define _TEST_FFI_STR_HELPER(x) #x
47

48
   #define _TEST_FFI_STR(x) _TEST_FFI_STR_HELPER(x)
49

50
   #define _TEST_FFI_SOURCE_LOCATION(func, file, line) (func " invoked at " file ":" _TEST_FFI_STR(line))
51

52
   #define TEST_FFI_OK(func, args) result.test_rc_ok(_TEST_FFI_SOURCE_LOCATION(#func, __FILE__, __LINE__), func args)
53

54
   #define TEST_FFI_INIT(func, args) \
55
      result.test_rc_init(_TEST_FFI_SOURCE_LOCATION(#func, __FILE__, __LINE__), func args)
56

57
   #define TEST_FFI_FAIL(msg, func, args) \
58
      result.test_rc_fail(_TEST_FFI_SOURCE_LOCATION(#func, __FILE__, __LINE__), msg, func args)
59

60
   #define TEST_FFI_RC(rc, func, args) \
61
      result.test_rc(_TEST_FFI_SOURCE_LOCATION(#func, __FILE__, __LINE__), func args, rc)
62

63
   #define REQUIRE_FFI_OK(func, args)                           \
64
      if(!TEST_FFI_OK(func, args)) {                            \
65
         result.test_note("Exiting test early due to failure"); \
66
         return;                                                \
67
      }
68

69
// NOLINTEND(*-macro-usage)
70

71
/**
72
 * Helper class for testing "view"-style API functions that take a callback
73
 * that gets passed a variable-length buffer of bytes.
74
 *
75
 * Example:
76
 *   botan_privkey_t priv;
77
 *   ViewBytesSink sink;
78
 *   botan_privkey_view_raw(priv, sink.delegate(), sink.callback());
79
 *   std::cout << hex_encode(sink.get()) << std::endl;
80
 */
81
class ViewBytesSink final {
×
82
   public:
83
      void* delegate() { return this; }
84

85
      botan_view_bin_fn callback() { return &write_fn; }
262✔
86

87
      std::span<const uint8_t> get() const { return m_buf; }
17✔
88

89
      const uint8_t* data() const { return m_buf.data(); }
7✔
90

91
      size_t size() const { return m_buf.size(); }
7✔
92

93
   private:
94
      static int write_fn(void* ctx, const uint8_t buf[], size_t len) {
253✔
95
         if(ctx == nullptr || buf == nullptr) {
253✔
96
            return BOTAN_FFI_ERROR_NULL_POINTER;
97
         }
98

99
         auto* sink = static_cast<ViewBytesSink*>(ctx);
253✔
100
         sink->m_buf.assign(buf, buf + len);
253✔
101

102
         return BOTAN_FFI_SUCCESS;
253✔
103
      }
104

105
   private:
106
      std::vector<uint8_t> m_buf;
107
};
108

109
/**
110
 * See ViewBytesSink for how to use this. Works for `botan_view_str_fn` instead.
111
*/
112
class ViewStringSink final {
28✔
113
   public:
114
      void* delegate() { return this; }
115

116
      botan_view_str_fn callback() { return &write_fn; }
74✔
117

118
      const std::string& get() { return m_str; }
63✔
119

120
   private:
121
      static int write_fn(void* ctx, const char* str, size_t len) {
73✔
122
         if(ctx == nullptr || str == nullptr) {
73✔
123
            return BOTAN_FFI_ERROR_NULL_POINTER;
124
         }
125

126
         auto* sink = static_cast<ViewStringSink*>(ctx);
73✔
127
         // discard the null terminator
128
         sink->m_str = std::string(str, len - 1);
73✔
129

130
         return BOTAN_FFI_SUCCESS;
73✔
131
      }
132

133
   private:
134
      std::string m_str;
135
};
136

137
// NOLINTBEGIN(*-init-variables)
138

139
class FFI_Test : public Test {
58✔
140
   public:
141
      std::vector<Test::Result> run() override {
58✔
142
         Test::Result result(this->name());
58✔
143

144
         if(!skip_this_test()) {
58✔
145
            botan_rng_t rng;
58✔
146
            if(botan_rng_init(&rng, "system") != 0) {
58✔
147
               result.test_failure("Failed to init RNG");
×
148
               return {result};
×
149
            }
150

151
            result.start_timer();
58✔
152
            ffi_test(result, rng);
58✔
153
            result.end_timer();
58✔
154

155
            botan_rng_destroy(rng);
58✔
156
         } else {
157
            result.test_note("FFI test asked to be skipped");
×
158
         }
159

160
         return {result};
116✔
161
      }
116✔
162

163
   private:
164
      virtual std::string name() const = 0;
165
      virtual void ffi_test(Test::Result& result, botan_rng_t rng) = 0;
166

167
      virtual bool skip_this_test() const { return false; }
56✔
168
};
169

170
void ffi_test_pubkey_export(Test::Result& result, botan_pubkey_t pub, botan_privkey_t priv, botan_rng_t rng) {
12✔
171
   // export public key
172
   size_t pubkey_len = 0;
12✔
173
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
12✔
174
               botan_pubkey_export,
175
               (pub, nullptr, &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
176

177
   std::vector<uint8_t> pubkey(pubkey_len);
12✔
178
   TEST_FFI_OK(botan_pubkey_export, (pub, pubkey.data(), &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
12✔
179

180
   pubkey_len = 0;
12✔
181
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
12✔
182
               botan_pubkey_export,
183
               (pub, nullptr, &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
184

185
   pubkey.resize(pubkey_len);
12✔
186
   TEST_FFI_OK(botan_pubkey_export, (pub, pubkey.data(), &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
12✔
187

188
   // reimport exported public key
189
   botan_pubkey_t pub_copy;
12✔
190
   TEST_FFI_OK(botan_pubkey_load, (&pub_copy, pubkey.data(), pubkey_len));
12✔
191
   TEST_FFI_OK(botan_pubkey_check_key, (pub_copy, rng, 0));
12✔
192
   TEST_FFI_OK(botan_pubkey_destroy, (pub_copy));
12✔
193

194
   // export private key
195
   std::vector<uint8_t> privkey;
12✔
196
   size_t privkey_len = 0;
12✔
197

198
   // call with nullptr to query the length
199
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
12✔
200
               botan_privkey_export,
201
               (priv, nullptr, &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
202

203
   privkey.resize(privkey_len);
12✔
204
   privkey_len = privkey.size();  // set buffer size
12✔
205

206
   TEST_FFI_OK(botan_privkey_export, (priv, privkey.data(), &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
12✔
207

208
   privkey.resize(privkey_len);
12✔
209

210
   result.test_sz_gte("Reasonable size", privkey.size(), 32);
12✔
211

212
   // reimport exported private key
213
   botan_privkey_t copy;
12✔
214
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), nullptr));
12✔
215
   botan_privkey_destroy(copy);
12✔
216

217
   // Now again for PEM
218
   privkey_len = 0;
12✔
219

220
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
12✔
221
               botan_privkey_export,
222
               (priv, nullptr, &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
223

224
   privkey.resize(privkey_len);
12✔
225
   TEST_FFI_OK(botan_privkey_export, (priv, privkey.data(), &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
12✔
226

227
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), nullptr));
12✔
228
   botan_privkey_destroy(copy);
12✔
229

230
   #if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_PKCS5_PBES2)
231
   const size_t pbkdf_iter = 1000;
12✔
232

233
   // export private key encrypted
234
   privkey_len = 0;
12✔
235
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
12✔
236
               botan_privkey_export_encrypted_pbkdf_iter,
237
               (priv, nullptr, &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_DER));
238

239
   privkey.resize(privkey_len);
12✔
240
   privkey_len = privkey.size();
12✔
241

242
   TEST_FFI_OK(
12✔
243
      botan_privkey_export_encrypted_pbkdf_iter,
244
      (priv, privkey.data(), &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_DER));
245

246
   // reimport encrypted private key
247
   botan_privkey_load(&copy, rng, privkey.data(), privkey.size(), "password");
12✔
248
   botan_privkey_destroy(copy);
12✔
249

250
   privkey_len = 0;
12✔
251
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
12✔
252
               botan_privkey_export_encrypted_pbkdf_iter,
253
               (priv, nullptr, &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
254

255
   privkey.resize(privkey_len);
12✔
256
   TEST_FFI_OK(
12✔
257
      botan_privkey_export_encrypted_pbkdf_iter,
258
      (priv, privkey.data(), &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
259

260
   privkey.resize(privkey_len * 2);
12✔
261
   privkey_len = privkey.size();
12✔
262
   const uint32_t pbkdf_msec = 100;
12✔
263
   size_t pbkdf_iters_out = 0;
12✔
264

265
      #if defined(BOTAN_HAS_SCRYPT)
266
   const std::string pbe_hash = "Scrypt";
12✔
267
      #else
268
   const std::string pbe_hash = "SHA-512";
269
      #endif
270

271
      #if defined(BOTAN_HAS_AEAD_GCM)
272
   const std::string pbe_cipher = "AES-256/GCM";
12✔
273
      #else
274
   const std::string pbe_cipher = "AES-256/CBC";
275
      #endif
276

277
   TEST_FFI_OK(botan_privkey_export_encrypted_pbkdf_msec,
12✔
278
               (priv,
279
                privkey.data(),
280
                &privkey_len,
281
                rng,
282
                "password",
283
                pbkdf_msec,
284
                &pbkdf_iters_out,
285
                pbe_cipher.c_str(),
286
                pbe_hash.c_str(),
287
                0));
288

289
   if(pbe_hash == "Scrypt") {
12✔
290
      result.test_sz_eq("Scrypt iters set to zero in this API", pbkdf_iters_out, 0);
12✔
291
   } else {
292
      // PBKDF2 currently always rounds to multiple of 2000
293
      result.test_sz_eq("Expected PBKDF2 iters", pbkdf_iters_out % 2000, 0);
×
294
   }
295

296
   privkey.resize(privkey_len);
12✔
297

298
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), "password"));
12✔
299
   botan_privkey_destroy(copy);
12✔
300
   #endif
301

302
   // calculate fingerprint
303
   size_t strength = 0;
12✔
304
   TEST_FFI_OK(botan_pubkey_estimated_strength, (pub, &strength));
12✔
305
   result.test_sz_gte("estimated strength", strength, 1);
12✔
306

307
   size_t fingerprint_len = 0;
12✔
308
   TEST_FFI_RC(
12✔
309
      BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_pubkey_fingerprint, (pub, "SHA-256", nullptr, &fingerprint_len));
310

311
   std::vector<uint8_t> fingerprint(fingerprint_len);
12✔
312
   TEST_FFI_OK(botan_pubkey_fingerprint, (pub, "SHA-256", fingerprint.data(), &fingerprint_len));
12✔
313
}
12✔
314

315
class FFI_Utils_Test final : public FFI_Test {
1✔
316
   public:
317
      std::string name() const override { return "FFI Utils"; }
1✔
318

319
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
320
         result.test_u32_eq("FFI API version macro", uint32_t(BOTAN_FFI_API_VERSION), uint32_t(BOTAN_HAS_FFI));
1✔
321
         result.test_u32_eq("FFI API version function", botan_ffi_api_version(), uint32_t(BOTAN_HAS_FFI));
1✔
322
         result.test_u32_eq("Major version", botan_version_major(), Botan::version_major());
1✔
323
         result.test_u32_eq("Minor version", botan_version_minor(), Botan::version_minor());
1✔
324
         result.test_u32_eq("Patch version", botan_version_patch(), Botan::version_patch());
1✔
325
         result.test_str_eq("Botan version", botan_version_string(), Botan::version_cstr());
1✔
326
         result.test_u32_eq("Botan version datestamp", botan_version_datestamp(), Botan::version_datestamp());
1✔
327
         result.test_rc_ok("FFI supports its own version", botan_ffi_supports_api(botan_ffi_api_version()));
1✔
328

329
         result.test_u32_eq("FFI compile time time var matches botan_ffi_api_version",
1✔
330
                            botan_ffi_api_version(),
331
                            uint32_t(BOTAN_FFI_API_VERSION));
332

333
         result.test_rc_ok("FFI supports 2.0 version", botan_ffi_supports_api(20150515));
1✔
334
         result.test_rc_ok("FFI supports 2.1 version", botan_ffi_supports_api(20170327));
1✔
335
         result.test_rc_ok("FFI supports 2.3 version", botan_ffi_supports_api(20170815));
1✔
336
         result.test_rc_ok("FFI supports 2.8 version", botan_ffi_supports_api(20180713));
1✔
337

338
         result.test_rc("FFI doesn't support bogus version", botan_ffi_supports_api(20160229), -1);
1✔
339

340
         const std::vector<uint8_t> mem1 = {0xFF, 0xAA, 0xFF};
1✔
341
         const std::vector<uint8_t> mem2 = {0xFF, 0xA9, 0xFF};
1✔
342

343
         TEST_FFI_RC(0, botan_constant_time_compare, (mem1.data(), mem1.data(), mem1.size()));
1✔
344
         TEST_FFI_RC(-1, botan_constant_time_compare, (mem1.data(), mem2.data(), mem1.size()));
1✔
345

346
         std::vector<uint8_t> to_zero = {0xFF, 0xA0};
1✔
347
         TEST_FFI_OK(botan_scrub_mem, (to_zero.data(), to_zero.size()));
1✔
348
         result.test_is_true("scrub_memory zeros", to_zero[0] == 0 && to_zero[1] == 0);
1✔
349

350
         const std::vector<uint8_t> bin = {0xAA, 0xDE, 0x01};
1✔
351

352
         std::string outstr;
1✔
353
         outstr.resize(2 * bin.size());
1✔
354
         TEST_FFI_OK(botan_hex_encode, (bin.data(), bin.size(), outstr.data(), 0));
1✔
355
         result.test_str_eq("uppercase hex", outstr, "AADE01");
1✔
356

357
         TEST_FFI_OK(botan_hex_encode, (bin.data(), bin.size(), outstr.data(), BOTAN_FFI_HEX_LOWER_CASE));
1✔
358
         result.test_str_eq("lowercase hex", outstr, "aade01");
1✔
359
      }
1✔
360
};
361

362
class FFI_RNG_Test final : public FFI_Test {
1✔
363
   public:
364
      std::string name() const override { return "FFI RNG"; }
1✔
365

366
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
367
         // RNG test and initialization
368
         botan_rng_t rng;
1✔
369
         botan_rng_t system_rng;
1✔
370
         botan_rng_t hwrng_rng = nullptr;
1✔
371
         botan_rng_t null_rng;
1✔
372
         botan_rng_t custom_rng;
1✔
373
         botan_rng_t tpm2_rng = nullptr;
1✔
374

375
         botan_tpm2_ctx_t tpm2_ctx = nullptr;
1✔
376
         botan_tpm2_session_t tpm2_session = nullptr;
1✔
377

378
         TEST_FFI_FAIL("invalid rng type", botan_rng_init, (&rng, "invalid_type"));
1✔
379

380
         REQUIRE_FFI_OK(botan_rng_init, (&system_rng, "system"));
1✔
381
         REQUIRE_FFI_OK(botan_rng_init, (&null_rng, "null"));
1✔
382

383
         int rc = botan_rng_init(&hwrng_rng, "hwrng");
1✔
384
         result.test_is_true("Either success or not implemented", rc == 0 || rc == BOTAN_FFI_ERROR_NOT_IMPLEMENTED);
1✔
385

386
         std::vector<uint8_t> outbuf(512);
1✔
387

388
         rc = botan_rng_init(&rng, "user-threadsafe");
1✔
389
         result.test_is_true("Either success or not implemented", rc == 0 || rc == BOTAN_FFI_ERROR_NOT_IMPLEMENTED);
1✔
390

391
         if(rc != 0) {
1✔
392
            REQUIRE_FFI_OK(botan_rng_init, (&rng, "user"));
×
393
            REQUIRE_FFI_OK(botan_rng_destroy, (rng));
×
394
         }
395

396
         if(rc == 0) {
1✔
397
            TEST_FFI_OK(botan_rng_get, (rng, outbuf.data(), outbuf.size()));
1✔
398
            TEST_FFI_OK(botan_rng_reseed, (rng, 256));
1✔
399

400
            TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, botan_rng_reseed_from_rng, (rng, null_rng, 256));
1✔
401
            if(hwrng_rng != nullptr) {
1✔
402
               TEST_FFI_OK(botan_rng_reseed_from_rng, (rng, hwrng_rng, 256));
1✔
403
            }
404
            TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, botan_rng_get, (null_rng, outbuf.data(), outbuf.size()));
1✔
405

406
            TEST_FFI_OK(botan_rng_destroy, (rng));
1✔
407
         }
408

409
         if(TEST_FFI_OK(botan_rng_init, (&rng, "user"))) {
1✔
410
            TEST_FFI_OK(botan_rng_get, (rng, outbuf.data(), outbuf.size()));
1✔
411
            TEST_FFI_OK(botan_rng_reseed, (rng, 256));
1✔
412

413
            TEST_FFI_OK(botan_rng_reseed_from_rng, (rng, system_rng, 256));
1✔
414

415
            uint8_t not_really_entropy[32] = {0};
1✔
416
            TEST_FFI_OK(botan_rng_add_entropy, (rng, not_really_entropy, 32));
1✔
417
         }
418

419
         uint8_t system_rng_buf[4096];
1✔
420
         TEST_FFI_OK(botan_system_rng_get, (system_rng_buf, sizeof(system_rng_buf)));
1✔
421

422
         size_t cb_counter = 0;
1✔
423

424
         auto custom_get_cb = +[](void* context, uint8_t* out, size_t out_len) -> int {
1✔
425
            for(size_t i = 0; i != out_len; ++i) {
426
               out[i] = 0x12;
427
            }
428
            (*(static_cast<size_t*>(context)))++;
429
            return 0;
430
         };
431

432
         auto custom_add_entropy_cb = +[](void* context, const uint8_t input[], size_t length) -> int {
1✔
433
            BOTAN_UNUSED(input, length);
434
            (*(static_cast<size_t*>(context)))++;
435
            return 0;
436
         };
437

438
         auto custom_destroy_cb = +[](void* context) -> void { (*(static_cast<size_t*>(context)))++; };
1✔
439

440
         if(TEST_FFI_OK(
1✔
441
               botan_rng_init_custom,
442
               (&custom_rng, "custom rng", &cb_counter, custom_get_cb, custom_add_entropy_cb, custom_destroy_cb))) {
443
            Botan::clear_mem(outbuf.data(), outbuf.size());
1✔
444
            TEST_FFI_OK(botan_rng_get, (custom_rng, outbuf.data(), outbuf.size()));
1✔
445
            result.test_sz_eq("custom_get_cb called", cb_counter, 1);
1✔
446
            std::vector<uint8_t> pattern(outbuf.size(), 0x12);
1✔
447
            result.test_bin_eq("custom_get_cb returned bytes", pattern, outbuf);
1✔
448

449
            TEST_FFI_OK(botan_rng_reseed, (custom_rng, 256));
1✔
450
            result.test_sz_eq("custom_add_entropy_cb called", cb_counter, 2);
1✔
451

452
            TEST_FFI_OK(botan_rng_reseed_from_rng, (custom_rng, system_rng, 256));
1✔
453
            result.test_sz_eq("custom_add_entropy_cb called", cb_counter, 3);
1✔
454

455
            uint8_t not_really_entropy[32] = {0};
1✔
456
            TEST_FFI_OK(botan_rng_add_entropy, (custom_rng, not_really_entropy, 32));
1✔
457
            result.test_sz_eq("custom_add_entropy_cb called", cb_counter, 4);
1✔
458

459
            TEST_FFI_OK(botan_rng_destroy, (custom_rng));
1✔
460
            result.test_sz_eq("custom_destroy_cb called", cb_counter, 5);
1✔
461
         }
1✔
462

463
   #ifdef BOTAN_HAS_JITTER_RNG
464
         botan_rng_t jitter_rng;
1✔
465
         if(TEST_FFI_OK(botan_rng_init, (&jitter_rng, "jitter"))) {
1✔
466
            const std::vector<uint8_t> buf(256);
1✔
467
            TEST_FFI_OK(botan_rng_get, (jitter_rng, outbuf.data(), buf.size()));
1✔
468
            TEST_FFI_OK(botan_rng_destroy, (jitter_rng));
1✔
469
         }
1✔
470
   #endif
471

472
         const auto tcti_name = Test::options().tpm2_tcti_name().value_or("");
1✔
473
         const auto tcti_conf = Test::options().tpm2_tcti_conf().value_or("");
1✔
474
         if(tcti_name.empty() || tcti_name == "disabled") {
1✔
475
            result.test_note("TPM2 tests are disabled.");
×
476
         } else {
477
            auto tpm2_test_rng = [&](botan_tpm2_ctx_t tpm2_context) {
3✔
478
               // Create and use an RNG without a TPM2 session
479
               // (communication between application and TPM won't be encrypted)
480
               if(TEST_FFI_INIT(botan_tpm2_rng_init, (&tpm2_rng, tpm2_context, nullptr, nullptr, nullptr))) {
2✔
481
                  Botan::clear_mem(outbuf.data(), outbuf.size());
2✔
482

483
                  TEST_FFI_OK(botan_rng_get, (tpm2_rng, outbuf.data(), outbuf.size()));
2✔
484
                  TEST_FFI_OK(botan_rng_reseed, (tpm2_rng, 256));
2✔
485

486
                  TEST_FFI_OK(botan_rng_reseed_from_rng, (tpm2_rng, system_rng, 256));
2✔
487

488
                  uint8_t not_really_entropy[32] = {0};
2✔
489
                  TEST_FFI_OK(botan_rng_add_entropy, (tpm2_rng, not_really_entropy, 32));
2✔
490
                  TEST_FFI_OK(botan_rng_destroy, (tpm2_rng));
2✔
491
               }
492

493
               // Create an anonymous TPM2 session
494
               if(TEST_FFI_INIT(botan_tpm2_unauthenticated_session_init, (&tpm2_session, tpm2_context))) {
2✔
495
                  // Create and use an RNG with an anonymous TPM2 session
496
                  // (communication between application and TPM will be encrypted)
497
                  if(TEST_FFI_INIT(botan_tpm2_rng_init, (&tpm2_rng, tpm2_context, tpm2_session, nullptr, nullptr))) {
2✔
498
                     Botan::clear_mem(outbuf.data(), outbuf.size());
2✔
499

500
                     TEST_FFI_OK(botan_rng_get, (tpm2_rng, outbuf.data(), outbuf.size()));
2✔
501
                     TEST_FFI_OK(botan_rng_reseed, (tpm2_rng, 256));
2✔
502

503
                     TEST_FFI_OK(botan_rng_reseed_from_rng, (tpm2_rng, system_rng, 256));
2✔
504

505
                     uint8_t not_really_entropy[32] = {0};
2✔
506
                     TEST_FFI_OK(botan_rng_add_entropy, (tpm2_rng, not_really_entropy, 32));
2✔
507
                     TEST_FFI_OK(botan_rng_destroy, (tpm2_rng));
2✔
508
                  }
509

510
                  TEST_FFI_OK(botan_tpm2_session_destroy, (tpm2_session));
2✔
511
               }
512
            };
3✔
513

514
            if(TEST_FFI_INIT(botan_tpm2_ctx_init_ex, (&tpm2_ctx, tcti_name.c_str(), tcti_conf.c_str()))) {
1✔
515
               if(botan_tpm2_supports_crypto_backend() == 1) {
1✔
516
                  TEST_FFI_OK(botan_tpm2_ctx_enable_crypto_backend, (tpm2_ctx, system_rng));
1✔
517
                  result.test_note("TPM2 crypto backend enabled");
1✔
518
               } else {
519
                  result.test_note("TPM2 crypto backend not supported");
×
520
               }
521

522
               tpm2_test_rng(tpm2_ctx);
1✔
523
               TEST_FFI_OK(botan_tpm2_ctx_destroy, (tpm2_ctx));
1✔
524
            }
525

526
   #if defined(BOTAN_HAS_TPM2)
527
            TSS2_TCTI_CONTEXT* tcti_ctx;
1✔
528
            ESYS_CONTEXT* esys_ctx;
1✔
529

530
            if(TEST_FFI_INIT(Tss2_TctiLdr_Initialize_Ex, (tcti_name.c_str(), tcti_conf.c_str(), &tcti_ctx))) {
1✔
531
               if(TEST_FFI_INIT(Esys_Initialize, (&esys_ctx, tcti_ctx, nullptr /* ABI version */))) {
1✔
532
                  botan_tpm2_crypto_backend_state_t cbs = nullptr;
1✔
533

534
                  // enable the botan-based TSS2 crypto backend on a bare ESYS_CONTEXT
535
                  if(botan_tpm2_supports_crypto_backend() == 1) {
1✔
536
                     TEST_FFI_OK(botan_tpm2_enable_crypto_backend, (&cbs, esys_ctx, system_rng));
1✔
537
                     result.test_note("TPM2 crypto backend enabled");
1✔
538
                  } else {
539
                     result.test_note("TPM2 crypto backend not supported");
×
540
                  }
541

542
                  // initialize the Botan TPM2 FFI wrapper from the bare ESYS_CONTEXT
543
                  if(TEST_FFI_INIT(botan_tpm2_ctx_from_esys, (&tpm2_ctx, esys_ctx))) {
1✔
544
                     tpm2_test_rng(tpm2_ctx);
1✔
545
                     TEST_FFI_OK(botan_tpm2_ctx_destroy, (tpm2_ctx));
1✔
546
                  }
547

548
                  if(cbs != nullptr) {
1✔
549
                     TEST_FFI_OK(botan_tpm2_crypto_backend_state_destroy, (cbs));
1✔
550
                  }
551

552
                  Esys_Finalize(&esys_ctx);
1✔
553
               }
554
               Tss2_TctiLdr_Finalize(&tcti_ctx);
1✔
555
            }
556
   #endif
557
         }
558

559
         TEST_FFI_OK(botan_rng_destroy, (rng));
1✔
560
         TEST_FFI_OK(botan_rng_destroy, (null_rng));
1✔
561
         TEST_FFI_OK(botan_rng_destroy, (system_rng));
1✔
562
         TEST_FFI_OK(botan_rng_destroy, (hwrng_rng));
1✔
563
      }
1✔
564
};
565

566
class FFI_RSA_Cert_Test final : public FFI_Test {
1✔
567
   public:
568
      std::string name() const override { return "FFI RSA cert"; }
1✔
569

570
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
571
         botan_x509_cert_t cert;
1✔
572
         if(TEST_FFI_INIT(botan_x509_cert_load_file, (&cert, Test::data_file("x509/ocsp/randombit.pem").c_str()))) {
1✔
573
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (cert, "randombit.net"));
1✔
574
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (cert, "www.randombit.net"));
1✔
575
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "*.randombit.net"));
1✔
576
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "flub.randombit.net"));
1✔
577
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "randombit.net.com"));
1✔
578

579
            botan_x509_cert_t copy;
1✔
580
            TEST_FFI_OK(botan_x509_cert_dup, (&copy, cert));
1✔
581
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (copy, "randombit.net"));
1✔
582

583
            TEST_FFI_OK(botan_x509_cert_destroy, (copy));
1✔
584
            TEST_FFI_OK(botan_x509_cert_destroy, (cert));
1✔
585
         }
586
      }
1✔
587
};
588

589
class FFI_ZFEC_Test final : public FFI_Test {
1✔
590
   public:
591
      std::string name() const override { return "FFI ZFEC"; }
1✔
592

593
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
594
         /* exercise a simple success case
595
          */
596

597
         // Select some arbitrary, valid encoding parameters.  There is
598
         // nothing special about them but some relationships between these
599
         // values and other inputs must hold.
600
         const size_t K = 3;
1✔
601
         const size_t N = 11;
1✔
602

603
         // The decoder needs to know the indexes of the blocks being passed
604
         // in to it.  This array must equal [0..N) for the logic in the
605
         // decoding loop below to hold.
606
         const std::vector<size_t> indexes = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1✔
607

608
         // This will be the size of each encoded (or decoded) block.  This is
609
         // an arbitrary value but it must match up with the length of the
610
         // test data given in `input`.
611
         const size_t blockSize = 15;
1✔
612

613
         // K of the blocks are required so the total information represented
614
         // can be this multiple.  totalSize must be a multiple of K and it
615
         // always will be using this construction.
616
         const size_t totalSize = blockSize * K;
1✔
617

618
         // Here's the complete original input (plus a trailing NUL that we
619
         // won't pass through ZFEC).  These are arbitrary bytes.
620
         const uint8_t input[totalSize + 1] = "Does this work?AAAAAAAAAAAAAAAzzzzzzzzzzzzzzz";
1✔
621

622
         // Allocate memory for the encoding and decoding output parameters.
623
         std::vector<uint8_t> encoded_buf(N * blockSize);
1✔
624
         std::vector<uint8_t> decoded_buf(K * blockSize);
1✔
625

626
         std::vector<uint8_t*> encoded(N);
1✔
627
         for(size_t i = 0; i < N; ++i) {
12✔
628
            encoded[i] = &encoded_buf[i * blockSize];
11✔
629
         }
630
         std::vector<uint8_t*> decoded(K);
1✔
631
         for(size_t i = 0; i < K; ++i) {
4✔
632
            decoded[i] = &decoded_buf[i * blockSize];
3✔
633
         }
634

635
         // First encode the complete input string into N blocks where K are
636
         // required for reconstruction.  The N encoded blocks will end up in
637
         // `encoded`.
638
         if(!TEST_FFI_INIT(botan_zfec_encode, (K, N, input, totalSize, encoded.data()))) {
1✔
639
            return;
640
         }
641

642
         // Any K blocks can be decoded to reproduce the original input (split
643
         // across an array of K strings of blockSize bytes each).  This loop
644
         // only exercises decoding with consecutive blocks because it's
645
         // harder to pick non-consecutive blocks out for a test.
646
         for(size_t offset = 0; offset < N - K; ++offset) {
9✔
647
            result.test_note("About to decode with offset " + std::to_string(offset));
24✔
648
            // Pass in the K shares starting from `offset` (and their indexes)
649
            // so that we can try decoding a certain group of blocks here.  Any
650
            // K shares *should* work.
651
            REQUIRE_FFI_OK(botan_zfec_decode,
8✔
652
                           (K, N, indexes.data() + offset, encoded.data() + offset, blockSize, decoded.data()));
653

654
            // Check that the original input bytes have been written to the
655
            // output parameter.
656
            for(size_t k = 0, pos = 0; k < K; ++k, pos += blockSize) {
32✔
657
               TEST_FFI_RC(0, botan_constant_time_compare, (input + pos, decoded[k], blockSize));
24✔
658
            }
659
         }
660

661
         /* Exercise a couple basic failure cases, such as you encounter if
662
          * the caller supplies invalid parameters.  We don't try to
663
          * exhaustively prove invalid parameters are handled through this
664
          * interface since the implementation only passes them through to
665
          * ZFEC::{encode,decode} where the real checking is.  We just want to
666
          * see that errors can propagate.
667
          */
668
         TEST_FFI_FAIL("encode with out-of-bounds encoding parameters should have failed",
1✔
669
                       botan_zfec_encode,
670
                       (0, 0, nullptr, 0, nullptr));
671
         TEST_FFI_FAIL("decode with out-of-bounds encoding parameters should have failed",
1✔
672
                       botan_zfec_decode,
673
                       (0, 0, nullptr, nullptr, 0, nullptr));
674
      }
1✔
675
};
676

677
class FFI_CRL_Test final : public FFI_Test {
1✔
678
   public:
679
      std::string name() const override { return "FFI CRL"; }
1✔
680

681
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
682
         const char* crl_string =
1✔
683
            "-----BEGIN X509 CRL-----\n"
684
            "MIICoTCCAQkCAQEwDQYJKoZIhvcNAQELBQAwgZQxLTArBgNVBAMTJFVzYWJsZSBj\n"
685
            "ZXJ0IHZhbGlkYXRpb246IFRlbXBvcmFyeSBDQTE5MDcGA1UECxMwQ2VudHJlIGZv\n"
686
            "ciBSZXNlYXJjaCBvbiBDcnlwdG9ncmFwaHkgYW5kIFNlY3VyaXR5MRswGQYDVQQK\n"
687
            "ExJNYXNhcnlrIFVuaXZlcnNpdHkxCzAJBgNVBAYTAkNaGA8yMDUwMDIyNTE1MjE0\n"
688
            "MloYDzIwNTAwMjI1MTUyNDQxWjAAoDowODAfBgNVHSMEGDAWgBRKzxAvI4+rVVo/\n"
689
            "JzLigRznREyB+TAVBgNVHRQEDgIMXcr16yNys/gjeuCFMA0GCSqGSIb3DQEBCwUA\n"
690
            "A4IBgQCfxv/5REM/KUnzeVycph3dJr1Yrtxhc6pZmQ9pMzSW/nawLN3rUHm5oG44\n"
691
            "ZuQgjvzE4PnbU0/DNRu/4w3H58kgrctJHHXbbvkU3lf2ZZLh2wBl+EUh92+/COow\n"
692
            "ZyGB+jqj/XwB99hYUhrY6NLEWRz08kpgG6dnNMEU0uFqdQKWk0CQPnmgPRgDb8BW\n"
693
            "IuMBcjY7aF9XoCZFOqPYdEvUKzAo4QGCf7uJ7fNGS3LqvjaLjAHJseSr5/yR7Q9r\n"
694
            "nEdI38yKPbRj0tNHe7j+BbYg31C+X+AZZKJtlTg8GxYR3qfQio1kDgpZ3rQLzHY3\n"
695
            "ea2MLX/Kdx9cPSwh4KwlcDxQmQKoELb4EnZW1CScSBHi9HQyCBNyCkgkOBMGcJqz\n"
696
            "Ihq1dGeSf8eca9+Avk5kAQ3yjXK1TI2CDEi0msrXLr9XbgowXiOLLzR+rYkhQz+V\n"
697
            "RnIoBwjnrGoJoz636KS170SZCB9ARNs17WE4IvbJdZrTXNOGaVZCQUUpiLRj4ZSO\n"
698
            "Na/nobI=\n"
699
            "-----END X509 CRL-----";
700

701
         botan_x509_crl_t bytecrl;
1✔
702
         if(!TEST_FFI_INIT(botan_x509_crl_load, (&bytecrl, reinterpret_cast<const uint8_t*>(crl_string), 966))) {
1✔
703
            return;
×
704
         }
705

706
         botan_x509_crl_t crl_without_next_update;
1✔
707
         if(!TEST_FFI_INIT(botan_x509_crl_load_file,
1✔
708
                           (&crl_without_next_update,
709
                            Test::data_file("x509/misc/crl_without_nextupdate/valid_forever.crl").c_str()))) {
710
            return;
711
         }
712

713
         uint64_t this_update;
1✔
714
         uint64_t next_update;
1✔
715
         TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE, botan_x509_crl_next_update, (crl_without_next_update, &next_update));
1✔
716
         TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE, botan_x509_crl_next_update, (crl_without_next_update, nullptr));
1✔
717
         TEST_FFI_OK(botan_x509_crl_this_update, (bytecrl, &this_update));
1✔
718
         TEST_FFI_OK(botan_x509_crl_next_update, (bytecrl, &next_update));
1✔
719
         result.test_u64_eq(
1✔
720
            "this update", this_update, Botan::calendar_point(2050, 2, 25, 15, 21, 42).seconds_since_epoch());
1✔
721
         result.test_u64_eq(
1✔
722
            "next update", next_update, Botan::calendar_point(2050, 2, 25, 15, 24, 41).seconds_since_epoch());
1✔
723

724
         TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_x509_crl_this_update, (bytecrl, nullptr));
1✔
725
         TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_x509_crl_next_update, (bytecrl, nullptr));
1✔
726

727
         ViewBytesSink akid;
1✔
728
         TEST_FFI_OK(botan_x509_crl_view_binary_values,
1✔
729
                     (bytecrl, BOTAN_X509_AUTHORITY_KEY_IDENTIFIER, 0, akid.delegate(), akid.callback()));
730
         result.test_bin_eq("authority key ID", akid.get(), "4ACF102F238FAB555A3F2732E2811CE7444C81F9");
1✔
731

732
         TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE,
1✔
733
                     botan_x509_crl_view_binary_values,
734
                     (bytecrl, BOTAN_X509_SUBJECT_KEY_IDENTIFIER, 0, akid.delegate(), akid.callback()));
735
         size_t akid_count;
1✔
736
         TEST_FFI_OK(botan_x509_crl_view_binary_values_count,
1✔
737
                     (bytecrl, BOTAN_X509_SUBJECT_KEY_IDENTIFIER, &akid_count));
738
         result.test_sz_eq("no subject key ID entries", akid_count, 0);
1✔
739

740
         botan_x509_crl_t crl;
1✔
741
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&crl, Test::data_file("x509/nist/root.crl").c_str()));
1✔
742

743
         botan_x509_cert_t cert1;
1✔
744
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&cert1, Test::data_file("x509/nist/test01/end.crt").c_str()));
1✔
745
         TEST_FFI_RC(-1, botan_x509_is_revoked, (crl, cert1));
1✔
746
         TEST_FFI_OK(botan_x509_cert_destroy, (cert1));
1✔
747

748
         botan_x509_cert_t cert2;
1✔
749
         std::vector<uint8_t> cert2_serial;
1✔
750
         botan_mp_t cert2_serial_bn;
1✔
751
         size_t cert2_serial_len = 0;
1✔
752
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&cert2, Test::data_file("x509/nist/test20/int.crt").c_str()));
1✔
753
         TEST_FFI_RC(0, botan_x509_is_revoked, (crl, cert2));
1✔
754
         TEST_FFI_RC(-1, botan_x509_is_revoked, (bytecrl, cert2));
1✔
755
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
756
                     botan_x509_cert_get_serial_number,
757
                     (cert2, nullptr, &cert2_serial_len));
758
         cert2_serial.resize(cert2_serial_len);
1✔
759
         TEST_FFI_OK(botan_x509_cert_get_serial_number, (cert2, cert2_serial.data(), &cert2_serial_len));
1✔
760
         TEST_FFI_OK(botan_x509_cert_serial_number, (cert2, &cert2_serial_bn));
1✔
761
         TEST_FFI_OK(botan_x509_cert_destroy, (cert2));
1✔
762

763
         size_t entries;
1✔
764
         TEST_FFI_OK(botan_x509_crl_entries_count, (crl, &entries));
1✔
765
         result.test_sz_eq("one revoked cert", entries, 1);
1✔
766
         TEST_FFI_OK(botan_x509_crl_entries_count, (bytecrl, &entries));
1✔
767
         result.test_sz_eq("no revoked cert", entries, 0);
1✔
768

769
         ViewBytesSink serial;
1✔
770
         TEST_FFI_OK(botan_mp_view_bin, (cert2_serial_bn, serial.delegate(), serial.callback()));
1✔
771
         result.test_bin_eq("serial == serial_bn", serial.get(), cert2_serial);
1✔
772
         TEST_FFI_OK(botan_mp_destroy, (cert2_serial_bn));
1✔
773

774
         botan_x509_crl_entry_t entry;
1✔
775
         TEST_FFI_OK(botan_x509_crl_entries, (crl, 0, &entry));
1✔
776

777
         uint64_t ts;
1✔
778
         int reason;
1✔
779
         botan_mp_t entry_serial_bn;
1✔
780

781
         TEST_FFI_OK(botan_x509_crl_entry_view_serial_number, (entry, serial.delegate(), serial.callback()));
1✔
782
         TEST_FFI_OK(botan_x509_crl_entry_serial_number, (entry, &entry_serial_bn));
1✔
783
         TEST_FFI_OK(botan_x509_crl_entry_revocation_date, (entry, &ts));
1✔
784
         TEST_FFI_OK(botan_x509_crl_entry_reason, (entry, &reason));
1✔
785
         TEST_FFI_OK(botan_x509_crl_entry_destroy, (entry));
1✔
786

787
   #if defined(BOTAN_HAS_X509)
788
         result.test_u8_eq(
1✔
789
            "Reason", static_cast<uint8_t>(reason), Botan::to_underlying(Botan::CRL_Code::KeyCompromise));
790
   #endif
791
         result.test_u64_eq("Revocation time", ts, Botan::calendar_point(1999, 1, 1, 12, 0, 0).seconds_since_epoch());
1✔
792
         result.test_bin_eq("Revoked cert serial", serial.get(), cert2_serial);
1✔
793

794
         TEST_FFI_OK(botan_mp_view_bin, (entry_serial_bn, serial.delegate(), serial.callback()));
1✔
795
         result.test_bin_eq("Revoked cert serial_bn", serial.get(), cert2_serial);
1✔
796
         TEST_FFI_OK(botan_mp_destroy, (entry_serial_bn));
1✔
797

798
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE, botan_x509_crl_entries, (crl, 1, &entry));
1✔
799
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE, botan_x509_crl_entries, (bytecrl, 0, &entry));
1✔
800

801
         ViewStringSink crl_pem;
1✔
802
         TEST_FFI_OK(botan_x509_crl_view_string_values,
1✔
803
                     (bytecrl, BOTAN_X509_PEM_ENCODING, 0, crl_pem.delegate(), crl_pem.callback()));
804
         size_t pem_count;
1✔
805
         TEST_FFI_OK(botan_x509_crl_view_string_values_count, (bytecrl, BOTAN_X509_PEM_ENCODING, &pem_count));
1✔
806
         result.test_sz_eq("one PEM encoding", pem_count, 1);
1✔
807

808
         auto remove_newlines = [](std::string_view str) {
3✔
809
            auto out = std::string(str);
2✔
810
            std::erase(out, '\n');
2✔
811
            std::erase(out, '\r');
2✔
812
            return out;
2✔
813
         };
814

815
         result.test_str_eq("CRL PEM", remove_newlines(crl_pem.get()), remove_newlines(crl_string));
1✔
816

817
         TEST_FFI_OK(botan_x509_crl_destroy, (crl));
1✔
818
         TEST_FFI_OK(botan_x509_crl_destroy, (bytecrl));
1✔
819
         TEST_FFI_OK(botan_x509_crl_destroy, (crl_without_next_update));
1✔
820

821
         const uint64_t now =
1✔
822
            std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
1✔
823
               .count();
1✔
824

825
         const char* priv_string =
1✔
826
            "-----BEGIN PRIVATE KEY-----\n"
827
            "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgoVEKnWZw2Bfrf3MM\n"
828
            "WLrfvRcAqq/sOf58jny37NLGQHShRANCAARageRLkKQEh1M86zvqeeesx2u9duLP\n"
829
            "iWtHjIcunpiq6+IiB8IVu7Ncu6uPKoFS/mWzTvjgdNusmgNle9p3OAbE\n"
830
            "-----END PRIVATE KEY-----";
831

832
         botan_privkey_t ca_key;
1✔
833
         botan_x509_cert_t ca_cert;
1✔
834
         botan_x509_cert_t sub1_cert;
1✔
835
         botan_x509_cert_t sub2_cert;
1✔
836

837
         REQUIRE_FFI_OK(botan_privkey_load,
1✔
838
                        (&ca_key, nullptr, reinterpret_cast<const uint8_t*>(priv_string), 240, nullptr));
1✔
839
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&ca_cert, Test::data_file("x509/crl/ca.crt").c_str()));
1✔
840
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub1_cert, Test::data_file("x509/crl/sub1.crt").c_str()));
1✔
841
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub2_cert, Test::data_file("x509/crl/sub2.crt").c_str()));
1✔
842

843
         botan_pubkey_t ca_pubkey;
1✔
844
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&ca_pubkey, ca_key));
1✔
845

846
         botan_x509_crl_t empty_crl;
1✔
847
         TEST_FFI_OK(botan_x509_crl_create, (&empty_crl, rng, ca_cert, ca_key, now, 86400, nullptr, nullptr));
1✔
848

849
         int rc;
1✔
850
         // both validate, because the crl is empty
851
         TEST_FFI_RC(0,
1✔
852
                     botan_x509_cert_verify_with_crl,
853
                     (&rc, sub1_cert, nullptr, 0, &ca_cert, 1, &empty_crl, 1, nullptr, 0, nullptr, 0));
854
         TEST_FFI_RC(0,
1✔
855
                     botan_x509_cert_verify_with_crl,
856
                     (&rc, sub2_cert, nullptr, 0, &ca_cert, 1, &empty_crl, 1, nullptr, 0, nullptr, 0));
857

858
         botan_x509_crl_entry_t crl_entry;
1✔
859
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE, botan_x509_crl_entries, (empty_crl, 0, &crl_entry));
1✔
860
         TEST_FFI_OK(botan_x509_crl_entry_create, (&crl_entry, sub2_cert, BOTAN_CRL_ENTRY_KEY_COMPROMISE));
1✔
861

862
         botan_x509_crl_t new_crl;
1✔
863
         const botan_x509_crl_entry_t crl_entries[1] = {crl_entry};
1✔
864

865
         TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER,
1✔
866
                     botan_x509_crl_update,
867
                     (&new_crl, empty_crl, rng, ca_cert, ca_key, now, 86400, nullptr, 1, nullptr, nullptr));
868
         TEST_FFI_OK(botan_x509_crl_update,
1✔
869
                     (&new_crl, empty_crl, rng, ca_cert, ca_key, now, 86400, crl_entries, 1, nullptr, nullptr));
870
         // sub 1 still validates
871
         TEST_FFI_RC(0,
1✔
872
                     botan_x509_cert_verify_with_crl,
873
                     (&rc, sub1_cert, nullptr, 0, &ca_cert, 1, &new_crl, 1, nullptr, 0, nullptr, 0));
874
         // but sub 2 is revoked
875
         TEST_FFI_RC(1,
1✔
876
                     botan_x509_cert_verify_with_crl,
877
                     (&rc, sub2_cert, nullptr, 0, &ca_cert, 1, &new_crl, 1, nullptr, 0, nullptr, 0));
878

879
         botan_x509_crl_entry_t crl_entry_2;
1✔
880
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE, botan_x509_crl_entries, (new_crl, 1, &crl_entry_2));
1✔
881
         TEST_FFI_OK(botan_x509_crl_entries, (new_crl, 0, &crl_entry_2));
1✔
882

883
         botan_mp_t serial_from_str;
1✔
884
         TEST_FFI_OK(botan_mp_init, (&serial_from_str));
1✔
885
         TEST_FFI_OK(botan_mp_set_from_str, (serial_from_str, "270431672985589325219914342203841486494"));
1✔
886

887
         uint64_t expire_time;
1✔
888
         TEST_FFI_OK(botan_x509_crl_entry_revocation_date, (crl_entry_2, &expire_time));
1✔
889
         TEST_FFI_OK(botan_x509_crl_entry_reason, (crl_entry_2, &reason));
1✔
890

891
         botan_mp_t serial_from_crl;
1✔
892
         TEST_FFI_OK(botan_x509_crl_entry_serial_number, (crl_entry_2, &serial_from_crl));
1✔
893
         TEST_FFI_RC(1, botan_mp_equal, (serial_from_str, serial_from_crl));
1✔
894
         result.test_is_true("expire time is correct", now - 20 <= expire_time && expire_time <= now + 20);
1✔
895
         result.test_is_true("reason is correct", reason == BOTAN_CRL_ENTRY_KEY_COMPROMISE);
1✔
896

897
         TEST_FFI_RC(1, botan_x509_crl_verify_signature, (new_crl, ca_pubkey));
1✔
898

899
         botan_x509_crl_t even_newer_crl;
1✔
900
         TEST_FFI_OK(botan_x509_crl_update,
1✔
901
                     (&even_newer_crl, new_crl, rng, ca_cert, ca_key, now, 456, nullptr, 0, nullptr, nullptr));
902

903
         TEST_FFI_OK(botan_x509_crl_next_update, (even_newer_crl, &expire_time));
1✔
904
         result.test_is_true("expire time is correct", expire_time == now + 456);
1✔
905

906
         TEST_FFI_OK(botan_x509_crl_entry_destroy, (crl_entry));
1✔
907
         TEST_FFI_OK(botan_x509_crl_entry_destroy, (crl_entry_2));
1✔
908
         TEST_FFI_OK(botan_mp_destroy, (serial_from_str));
1✔
909
         TEST_FFI_OK(botan_mp_destroy, (serial_from_crl));
1✔
910
         TEST_FFI_OK(botan_x509_crl_destroy, (empty_crl));
1✔
911
         TEST_FFI_OK(botan_x509_crl_destroy, (new_crl));
1✔
912
         TEST_FFI_OK(botan_x509_crl_destroy, (even_newer_crl));
1✔
913
         TEST_FFI_OK(botan_x509_cert_destroy, (ca_cert));
1✔
914
         TEST_FFI_OK(botan_x509_cert_destroy, (sub1_cert));
1✔
915
         TEST_FFI_OK(botan_x509_cert_destroy, (sub2_cert));
1✔
916
         TEST_FFI_OK(botan_pubkey_destroy, (ca_pubkey));
1✔
917
         TEST_FFI_OK(botan_privkey_destroy, (ca_key));
1✔
918
      }
1✔
919
};
920

921
class FFI_Cert_Validation_Test final : public FFI_Test {
1✔
922
   public:
923
      std::string name() const override { return "FFI Cert Validation"; }
1✔
924

925
      bool skip_this_test() const override {
1✔
926
   #if !defined(BOTAN_HAS_PKCSV15_SIGNATURE_PADDING)
927
         return true;
928
   #else
929
         return false;
1✔
930
   #endif
931
      }
932

933
      void verify_bare_pkcs1_rsa_signature(Test::Result& result, botan_x509_cert_t ee, botan_x509_cert_t ca) {
1✔
934
         ViewBytesSink tbs_data;
1✔
935
         ViewBytesSink sig_scheme;
1✔
936
         ViewBytesSink signature;
1✔
937
         ViewBytesSink public_key;
1✔
938

939
         TEST_FFI_OK(botan_x509_cert_view_binary_values,
1✔
940
                     (ee, BOTAN_X509_TBS_DATA_BITS, 0, tbs_data.delegate(), tbs_data.callback()));
941
         TEST_FFI_OK(botan_x509_cert_view_binary_values,
1✔
942
                     (ee, BOTAN_X509_SIGNATURE_SCHEME_BITS, 0, sig_scheme.delegate(), sig_scheme.callback()));
943
         TEST_FFI_OK(botan_x509_cert_view_binary_values,
1✔
944
                     (ee, BOTAN_X509_SIGNATURE_BITS, 0, signature.delegate(), signature.callback()));
945
         TEST_FFI_OK(botan_x509_cert_view_binary_values,
1✔
946
                     (ca, BOTAN_X509_PUBLIC_KEY_PKCS8_BITS, 0, public_key.delegate(), public_key.callback()));
947

948
         // These values exist exactly once in a certificate
949
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE,
1✔
950
                     botan_x509_cert_view_binary_values,
951
                     (ee, BOTAN_X509_TBS_DATA_BITS, 1, tbs_data.delegate(), tbs_data.callback()));
952
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE,
1✔
953
                     botan_x509_cert_view_binary_values,
954
                     (ee, BOTAN_X509_SIGNATURE_SCHEME_BITS, 1, sig_scheme.delegate(), sig_scheme.callback()));
955
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE,
1✔
956
                     botan_x509_cert_view_binary_values,
957
                     (ee, BOTAN_X509_SIGNATURE_BITS, 1, signature.delegate(), signature.callback()));
958
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE,
1✔
959
                     botan_x509_cert_view_binary_values,
960
                     (ca, BOTAN_X509_PUBLIC_KEY_PKCS8_BITS, 1, public_key.delegate(), public_key.callback()));
961

962
         size_t count;
1✔
963
         TEST_FFI_OK(botan_x509_cert_view_binary_values_count, (ee, BOTAN_X509_TBS_DATA_BITS, &count));
1✔
964
         result.test_sz_eq("TBS data count", count, 1);
1✔
965
         TEST_FFI_OK(botan_x509_cert_view_binary_values_count, (ee, BOTAN_X509_SIGNATURE_SCHEME_BITS, &count));
1✔
966
         result.test_sz_eq("Signature scheme count", count, 1);
1✔
967
         TEST_FFI_OK(botan_x509_cert_view_binary_values_count, (ee, BOTAN_X509_SIGNATURE_BITS, &count));
1✔
968
         result.test_sz_eq("Signature count", count, 1);
1✔
969
         TEST_FFI_OK(botan_x509_cert_view_binary_values_count, (ca, BOTAN_X509_PUBLIC_KEY_PKCS8_BITS, &count));
1✔
970
         result.test_sz_eq("Public key count", count, 1);
1✔
971

972
         // At the moment there's no way to directly instantiate a signature
973
         // verifier object with an encoded signature algorithm scheme. Hence,
974
         // we just check that the hard-coded expectation is fulfilled.
975
         //
976
         // TODO: improve this if we ever have a pk_op_verify_t constructor that
977
         //       takes an encoded AlgorithmIdentifier.
978
         const auto expected_sig_scheme =
1✔
979
            Botan::AlgorithmIdentifier("RSA/PKCS1v15(SHA-1)", Botan::AlgorithmIdentifier::USE_NULL_PARAM).BER_encode();
1✔
980
         result.test_bin_eq("AlgorithmIdentifier", sig_scheme.get(), expected_sig_scheme);
1✔
981

982
         botan_pubkey_t pubkey;
1✔
983
         TEST_FFI_INIT(botan_pubkey_load, (&pubkey, public_key.data(), public_key.size()));
1✔
984

985
         botan_pk_op_verify_t verifier;
1✔
986
         TEST_FFI_INIT(botan_pk_op_verify_create, (&verifier, pubkey, "PKCS1v15(SHA-1)", 0));
1✔
987
         TEST_FFI_OK(botan_pk_op_verify_update, (verifier, tbs_data.data(), tbs_data.size()));
1✔
988
         TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
989

990
         TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
1✔
991
         TEST_FFI_OK(botan_pubkey_destroy, (pubkey));
1✔
992
      }
1✔
993

994
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
995
         botan_x509_cert_t root;
1✔
996
         int rc;
1✔
997

998
         if(!TEST_FFI_INIT(botan_x509_cert_load_file, (&root, Test::data_file("x509/nist/root.crt").c_str()))) {
1✔
999
            return;
×
1000
         }
1001
         TEST_FFI_RC(1, botan_x509_cert_is_ca, (root));
1✔
1002

1003
         botan_x509_cert_t end2;
1✔
1004
         botan_x509_cert_t sub2;
1✔
1005
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end2, Test::data_file("x509/nist/test02/end.crt").c_str()));
1✔
1006
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub2, Test::data_file("x509/nist/test02/int.crt").c_str()));
1✔
1007
         TEST_FFI_RC(0, botan_x509_cert_is_ca, (end2));
1✔
1008

1009
         size_t path_limit;
1✔
1010
         TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE, botan_x509_cert_get_path_length_constraint, (root, &path_limit));
1✔
1011

1012
         botan_x509_cert_t root_with_pathlen;
1✔
1013
         REQUIRE_FFI_OK(botan_x509_cert_load_file,
1✔
1014
                        (&root_with_pathlen, Test::data_file("x509/extended/02/root.crt").c_str()));
1✔
1015
         TEST_FFI_OK(botan_x509_cert_get_path_length_constraint, (root_with_pathlen, &path_limit));
1✔
1016
         result.test_sz_eq("Path length constraint", path_limit, 1);
1✔
1017

1018
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end2, &sub2, 1, &root, 1, nullptr, 0, nullptr, 0));
1✔
1019
         result.test_is_true("Validation test02 failed", rc == 5002);
1✔
1020
         result.test_str_eq(
1✔
1021
            "Validation test02 status string", botan_x509_cert_validation_status(rc), "Signature error");
1022

1023
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end2, nullptr, 0, &root, 1, nullptr, 0, nullptr, 0));
1✔
1024
         result.test_is_true("Validation test02 failed (missing int)", rc == 3000);
1✔
1025
         result.test_str_eq(
1✔
1026
            "Validation test02 status string", botan_x509_cert_validation_status(rc), "Certificate issuer not found");
1027

1028
         botan_x509_cert_t end7;
1✔
1029
         botan_x509_cert_t sub7;
1✔
1030
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end7, Test::data_file("x509/nist/test07/end.crt").c_str()));
1✔
1031
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub7, Test::data_file("x509/nist/test07/int.crt").c_str()));
1✔
1032

1033
         const botan_x509_cert_t subs[2] = {sub2, sub7};
1✔
1034
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end7, subs, 2, &root, 1, nullptr, 0, nullptr, 0));
1✔
1035
         result.test_is_true("Validation test07 failed with expected error", rc == 1001);
1✔
1036
         result.test_str_eq("Validation test07 status string",
1✔
1037
                            botan_x509_cert_validation_status(rc),
1038
                            "Hash function used is considered too weak for security");
1039

1040
         TEST_FFI_RC(0, botan_x509_cert_verify, (&rc, end7, subs, 2, &root, 1, nullptr, 80, nullptr, 0));
1✔
1041
         result.test_is_true("Validation test07 passed", rc == 0);
1✔
1042
         result.test_str_eq("Validation test07 status string", botan_x509_cert_validation_status(rc), "Verified");
1✔
1043

1044
         verify_bare_pkcs1_rsa_signature(result, end7, sub7);
1✔
1045

1046
         TEST_FFI_RC(1,
1✔
1047
                     botan_x509_cert_verify_with_crl,
1048
                     (&rc, end7, subs, 2, nullptr, 0, nullptr, 0, "x509/farce", 0, nullptr, 0));
1049
         result.test_is_true("Validation test07 failed with expected error", rc == 3000);
1✔
1050
         result.test_str_eq(
1✔
1051
            "Validation test07 status string", botan_x509_cert_validation_status(rc), "Certificate issuer not found");
1052

1053
         botan_x509_crl_t rootcrl;
1✔
1054

1055
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&rootcrl, Test::data_file("x509/nist/root.crl").c_str()));
1✔
1056
         TEST_FFI_RC(
1✔
1057
            0, botan_x509_cert_verify_with_crl, (&rc, end7, subs, 2, &root, 1, &rootcrl, 1, nullptr, 80, nullptr, 0));
1058
         result.test_is_true("Validation test07 with CRL passed", rc == 0);
1✔
1059
         result.test_str_eq(
1✔
1060
            "Validation test07 with CRL status string", botan_x509_cert_validation_status(rc), "Verified");
1061

1062
         botan_x509_cert_t end20;
1✔
1063
         botan_x509_cert_t sub20;
1✔
1064
         botan_x509_crl_t sub20crl;
1✔
1065
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end20, Test::data_file("x509/nist/test20/end.crt").c_str()));
1✔
1066
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub20, Test::data_file("x509/nist/test20/int.crt").c_str()));
1✔
1067
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&sub20crl, Test::data_file("x509/nist/test20/int.crl").c_str()));
1✔
1068
         const botan_x509_crl_t crls[2] = {sub20crl, rootcrl};
1✔
1069
         TEST_FFI_RC(
1✔
1070
            1, botan_x509_cert_verify_with_crl, (&rc, end20, &sub20, 1, &root, 1, crls, 2, nullptr, 80, nullptr, 0));
1071
         result.test_is_true("Validation test20 failed with expected error", rc == 5000);
1✔
1072
         result.test_str_eq(
1✔
1073
            "Validation test20 status string", botan_x509_cert_validation_status(rc), "Certificate is revoked");
1074

1075
         TEST_FFI_OK(botan_x509_cert_destroy, (root_with_pathlen));
1✔
1076
         TEST_FFI_OK(botan_x509_cert_destroy, (end2));
1✔
1077
         TEST_FFI_OK(botan_x509_cert_destroy, (sub2));
1✔
1078
         TEST_FFI_OK(botan_x509_cert_destroy, (end7));
1✔
1079
         TEST_FFI_OK(botan_x509_cert_destroy, (sub7));
1✔
1080
         TEST_FFI_OK(botan_x509_cert_destroy, (end20));
1✔
1081
         TEST_FFI_OK(botan_x509_cert_destroy, (sub20));
1✔
1082
         TEST_FFI_OK(botan_x509_crl_destroy, (sub20crl));
1✔
1083
         TEST_FFI_OK(botan_x509_cert_destroy, (root));
1✔
1084
         TEST_FFI_OK(botan_x509_crl_destroy, (rootcrl));
1✔
1085
      }
1086
};
1087

1088
class FFI_ECDSA_Certificate_Test final : public FFI_Test {
1✔
1089
   public:
1090
      std::string name() const override { return "FFI ECDSA cert"; }
1✔
1091

1092
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1093
         botan_x509_cert_t cert;
1✔
1094
         if(TEST_FFI_INIT(botan_x509_cert_load_file, (&cert, Test::data_file("x509/ecc/isrg-root-x2.pem").c_str()))) {
1✔
1095
            size_t date_len = 0;
1✔
1096
            TEST_FFI_RC(
1✔
1097
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_starts, (cert, nullptr, &date_len));
1098

1099
            date_len = 8;
1✔
1100
            TEST_FFI_RC(
1✔
1101
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_starts, (cert, nullptr, &date_len));
1102

1103
            std::string date(date_len - 1, '0');
1✔
1104
            TEST_FFI_OK(botan_x509_cert_get_time_starts, (cert, date.data(), &date_len));
1✔
1105
            result.test_str_eq("cert valid from", date, "200904000000Z");
1✔
1106

1107
            date_len = 0;
1✔
1108
            TEST_FFI_RC(
1✔
1109
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_expires, (cert, nullptr, &date_len));
1110

1111
            date.resize(date_len - 1);
1✔
1112
            TEST_FFI_OK(botan_x509_cert_get_time_expires, (cert, date.data(), &date_len));
1✔
1113
            result.test_str_eq("cert valid until", date, "400917160000Z");
1✔
1114

1115
            uint64_t not_before = 0;
1✔
1116
            TEST_FFI_OK(botan_x509_cert_not_before, (cert, &not_before));
1✔
1117
            result.test_is_true("cert not before", not_before == 1599177600);
1✔
1118

1119
            uint64_t not_after = 0;
1✔
1120
            TEST_FFI_OK(botan_x509_cert_not_after, (cert, &not_after));
1✔
1121
            result.test_is_true("cert not after", not_after == 2231510400);
1✔
1122

1123
            size_t serial_len = 0;
1✔
1124
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1125
                        botan_x509_cert_get_serial_number,
1126
                        (cert, nullptr, &serial_len));
1127

1128
            std::vector<uint8_t> serial(serial_len);
1✔
1129
            TEST_FFI_OK(botan_x509_cert_get_serial_number, (cert, serial.data(), &serial_len));
1✔
1130
            result.test_sz_eq("cert serial length", serial.size(), 16);
1✔
1131
            result.test_bin_eq("cert serial", serial, "41D29DD172EAEEA780C12C6CE92F8752");
1✔
1132

1133
            ViewBytesSink serial_sink;
1✔
1134
            TEST_FFI_OK(botan_x509_cert_view_binary_values,
1✔
1135
                        (cert, BOTAN_X509_SERIAL_NUMBER, 0, serial_sink.delegate(), serial_sink.callback()));
1136
            result.test_bin_eq("cert serial (2)", serial_sink.get(), "41D29DD172EAEEA780C12C6CE92F8752");
1✔
1137

1138
            size_t fingerprint_len = 0;
1✔
1139
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1140
                        botan_x509_cert_get_fingerprint,
1141
                        (cert, "SHA-256", nullptr, &fingerprint_len));
1142

1143
            std::vector<uint8_t> fingerprint(fingerprint_len);
1✔
1144
            TEST_FFI_OK(botan_x509_cert_get_fingerprint, (cert, "SHA-256", fingerprint.data(), &fingerprint_len));
1✔
1145
            result.test_str_eq(
1✔
1146
               "cert fingerprint",
1147
               reinterpret_cast<const char*>(fingerprint.data()),
1✔
1148
               "69:72:9B:8E:15:A8:6E:FC:17:7A:57:AF:B7:17:1D:FC:64:AD:D2:8C:2F:CA:8C:F1:50:7E:34:45:3C:CB:14:70");
1149

1150
            size_t key_id_len = 0;
1✔
1151
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1152
                        botan_x509_cert_get_authority_key_id,
1153
                        (cert, nullptr, &key_id_len));
1154

1155
            result.test_sz_eq("No AKID", key_id_len, 0);
1✔
1156

1157
            // "No AKID" is explicitly communicated with an error code
1158
            ViewBytesSink key_id_sink;
1✔
1159
            TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE,
1✔
1160
                        botan_x509_cert_view_binary_values,
1161
                        (cert, BOTAN_X509_AUTHORITY_KEY_IDENTIFIER, 0, key_id_sink.delegate(), key_id_sink.callback()));
1162

1163
            key_id_len = 0;
1✔
1164
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1165
                        botan_x509_cert_get_subject_key_id,
1166
                        (cert, nullptr, &key_id_len));
1167

1168
            std::vector<uint8_t> key_id(key_id_len);
1✔
1169
            TEST_FFI_OK(botan_x509_cert_get_subject_key_id, (cert, key_id.data(), &key_id_len));
1✔
1170
            result.test_str_eq("cert subject key id",
1✔
1171
                               Botan::hex_encode(key_id.data(), key_id.size(), true),
1✔
1172
                               "7C4296AEDE4B483BFA92F89E8CCF6D8BA9723795");
1173

1174
            TEST_FFI_OK(botan_x509_cert_view_binary_values,
1✔
1175
                        (cert, BOTAN_X509_SUBJECT_KEY_IDENTIFIER, 0, key_id_sink.delegate(), key_id_sink.callback()));
1176
            result.test_bin_eq("cert subject key id", key_id_sink.get(), "7C4296AEDE4B483BFA92F89E8CCF6D8BA9723795");
1✔
1177

1178
            size_t pubkey_len = 0;
1✔
1179
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1180
                        botan_x509_cert_get_public_key_bits,
1181
                        (cert, nullptr, &pubkey_len));
1182

1183
            std::vector<uint8_t> pubkey(pubkey_len);
1✔
1184
            TEST_FFI_OK(botan_x509_cert_get_public_key_bits, (cert, pubkey.data(), &pubkey_len));
1✔
1185

1186
   #if defined(BOTAN_HAS_ECDSA)
1187
            botan_pubkey_t pub;
1✔
1188
            if(TEST_FFI_OK(botan_x509_cert_get_public_key, (cert, &pub))) {
1✔
1189
               TEST_FFI_RC(0, botan_pubkey_ecc_key_used_explicit_encoding, (pub));
1✔
1190
               TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
1191
            }
1192
   #endif
1193

1194
            size_t rdn_count;
1✔
1195
            TEST_FFI_OK(botan_x509_cert_get_issuer_dn_count, (cert, "Name", &rdn_count));
1✔
1196
            result.test_sz_eq("issuer DN 'name' count", rdn_count, 1);
1✔
1197
            TEST_FFI_OK(botan_x509_cert_get_issuer_dn_count, (cert, "Organizational Unit", &rdn_count));
1✔
1198
            result.test_sz_eq("issuer DN 'organizational unit' count", rdn_count, 0);
1✔
1199

1200
            size_t dn_len = 0;
1✔
1201
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1202
                        botan_x509_cert_get_issuer_dn,
1203
                        (cert, "Name", 0, nullptr, &dn_len));
1204

1205
            std::vector<uint8_t> dn(dn_len);
1✔
1206
            TEST_FFI_OK(botan_x509_cert_get_issuer_dn, (cert, "Name", 0, dn.data(), &dn_len));
1✔
1207
            result.test_str_eq("issuer dn", reinterpret_cast<const char*>(dn.data()), "ISRG Root X2");
1✔
1208

1209
            TEST_FFI_OK(botan_x509_cert_get_subject_dn_count, (cert, "Name", &rdn_count));
1✔
1210
            result.test_sz_eq("subject DN 'name' count", rdn_count, 1);
1✔
1211
            TEST_FFI_OK(botan_x509_cert_get_subject_dn_count, (cert, "Organizational Unit", &rdn_count));
1✔
1212
            result.test_sz_eq("subject DN 'organizational unit' count", rdn_count, 0);
1✔
1213

1214
            dn_len = 0;
1✔
1215
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1216
                        botan_x509_cert_get_subject_dn,
1217
                        (cert, "Name", 0, nullptr, &dn_len));
1218

1219
            dn.resize(dn_len);
1✔
1220
            TEST_FFI_OK(botan_x509_cert_get_subject_dn, (cert, "Name", 0, dn.data(), &dn_len));
1✔
1221
            result.test_str_eq("subject dn", reinterpret_cast<const char*>(dn.data()), "ISRG Root X2");
1✔
1222

1223
            size_t printable_len = 0;
1✔
1224
            TEST_FFI_RC(
1✔
1225
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_to_string, (cert, nullptr, &printable_len));
1226

1227
            std::string printable(printable_len - 1, '0');
1✔
1228
            TEST_FFI_OK(botan_x509_cert_to_string, (cert, printable.data(), &printable_len));
1✔
1229

1230
            size_t count;
1✔
1231
            TEST_FFI_OK(botan_x509_cert_view_string_values_count, (cert, BOTAN_X509_PEM_ENCODING, &count));
1✔
1232
            result.test_sz_eq("one PEM encoding", count, 1);
1✔
1233
            TEST_FFI_OK(botan_x509_cert_view_binary_values_count, (cert, BOTAN_X509_DER_ENCODING, &count));
1✔
1234
            result.test_sz_eq("one DER encoding", count, 1);
1✔
1235

1236
            ViewBytesSink der;
1✔
1237
            ViewStringSink pem;
1✔
1238
            TEST_FFI_OK(botan_x509_cert_view_binary_values,
1✔
1239
                        (cert, BOTAN_X509_DER_ENCODING, 0, der.delegate(), der.callback()));
1240
            result.test_is_true("DER encoding produced something", !der.get().empty());
1✔
1241
            TEST_FFI_OK(botan_x509_cert_view_string_values,
1✔
1242
                        (cert, BOTAN_X509_PEM_ENCODING, 0, pem.delegate(), pem.callback()));
1243
            result.test_is_true("PEM encoding produced something", !pem.get().empty());
1✔
1244

1245
            TEST_FFI_RC(0, botan_x509_cert_allowed_usage, (cert, KEY_CERT_SIGN));
1✔
1246
            TEST_FFI_RC(0, botan_x509_cert_allowed_usage, (cert, CRL_SIGN));
1✔
1247
            TEST_FFI_RC(1, botan_x509_cert_allowed_usage, (cert, DIGITAL_SIGNATURE));
1✔
1248

1249
            TEST_FFI_OK(botan_x509_cert_destroy, (cert));
1✔
1250
         }
1✔
1251
      }
1✔
1252
};
1253

1254
class FFI_Cert_ExtKeyUsages_Test final : public FFI_Test {
1✔
1255
   public:
1256
      std::string name() const override { return "FFI X509 Extended Key Usage"; }
1✔
1257

1258
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1259
         botan_x509_cert_t cert_with_eku;
1✔
1260
         if(!TEST_FFI_INIT(botan_x509_cert_load_file,
1✔
1261
                           (&cert_with_eku, Test::data_file("x509/pss_certs/03/end.crt").c_str()))) {
1262
            return;
×
1263
         }
1264

1265
         // Prepare some OID objects for OID-based EKU queries
1266
         botan_asn1_oid_t oid_srv_auth1;
1✔
1267
         botan_asn1_oid_t oid_srv_auth2;
1✔
1268
         botan_asn1_oid_t oid_ocsp_signing;
1✔
1269
         TEST_FFI_OK(botan_oid_from_string, (&oid_srv_auth1, "1.3.6.1.5.5.7.3.1"));
1✔
1270
         TEST_FFI_OK(botan_oid_from_string, (&oid_srv_auth2, "PKIX.ServerAuth"));
1✔
1271
         TEST_FFI_OK(botan_oid_from_string, (&oid_ocsp_signing, "PKIX.OCSPSigning"));
1✔
1272

1273
         // Make sure the OID object is checked for nullptr
1274
         TEST_FFI_RC(
1✔
1275
            BOTAN_FFI_ERROR_NULL_POINTER, botan_x509_cert_allowed_extended_usage_oid, (cert_with_eku, nullptr));
1276

1277
         // Should have serverAuth (TLS Web Server Authentication)
1278
         TEST_FFI_RC(1, botan_x509_cert_allowed_extended_usage_str, (cert_with_eku, "1.3.6.1.5.5.7.3.1"));
1✔
1279
         TEST_FFI_RC(1, botan_x509_cert_allowed_extended_usage_str, (cert_with_eku, "PKIX.ServerAuth"));
1✔
1280
         TEST_FFI_RC(1, botan_x509_cert_allowed_extended_usage_oid, (cert_with_eku, oid_srv_auth1));
1✔
1281
         TEST_FFI_RC(1, botan_x509_cert_allowed_extended_usage_oid, (cert_with_eku, oid_srv_auth2));
1✔
1282

1283
         // Should have clientAuth (TLS Web Client Authentication)
1284
         TEST_FFI_RC(1, botan_x509_cert_allowed_extended_usage_str, (cert_with_eku, "1.3.6.1.5.5.7.3.2"));
1✔
1285
         TEST_FFI_RC(1, botan_x509_cert_allowed_extended_usage_str, (cert_with_eku, "PKIX.ClientAuth"));
1✔
1286

1287
         // Should NOT have OCSPSigning
1288
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_str, (cert_with_eku, "1.3.6.1.5.5.7.3.9"));
1✔
1289
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_str, (cert_with_eku, "PKIX.OCSPSigning"));
1✔
1290

1291
         // Should NOT have codeSigning
1292
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_str, (cert_with_eku, "1.3.6.1.5.5.7.3.3"));
1✔
1293
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_str, (cert_with_eku, "PKIX.CodeSigning"));
1✔
1294
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_oid, (cert_with_eku, oid_ocsp_signing));
1✔
1295

1296
         TEST_FFI_OK(botan_x509_cert_destroy, (cert_with_eku));
1✔
1297

1298
         botan_x509_cert_t cert_without_eku;
1✔
1299
         if(!TEST_FFI_INIT(botan_x509_cert_load_file,
1✔
1300
                           (&cert_without_eku, Test::data_file("x509/nist/root.crt").c_str()))) {
1301
            return;
1302
         }
1303

1304
         // Should return zero for any EKU query (no EKU extension present)
1305
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_str, (cert_without_eku, "1.3.6.1.5.5.7.3.1"));
1✔
1306
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_str, (cert_without_eku, "1.3.6.1.5.5.7.3.2"));
1✔
1307
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_str, (cert_without_eku, "PKIX.OCSPSigning"));
1✔
1308
         TEST_FFI_RC(0, botan_x509_cert_allowed_extended_usage_str, (cert_without_eku, "PKIX.CodeSigning"));
1✔
1309

1310
         TEST_FFI_OK(botan_oid_destroy, (oid_srv_auth1));
1✔
1311
         TEST_FFI_OK(botan_oid_destroy, (oid_srv_auth2));
1✔
1312
         TEST_FFI_OK(botan_oid_destroy, (oid_ocsp_signing));
1✔
1313
         TEST_FFI_OK(botan_x509_cert_destroy, (cert_without_eku));
1✔
1314
      }
1315
};
1316

1317
   #if defined(BOTAN_HAS_X509)
1318

1319
auto read_distinguished_name(std::span<const uint8_t> bytes) {
32✔
1320
   auto dec = Botan::BER_Decoder(bytes, Botan::BER_Decoder::Limits::DER());
32✔
1321
   Botan::X509_DN dn;
32✔
1322
   dn.decode_from(dec);
32✔
1323
   return dn;
32✔
1324
}
32✔
1325

1326
class FFI_Cert_AlternativeNames_Test final : public FFI_Test {
1✔
1327
   private:
1328
      template <std::invocable<botan_x509_cert_t, size_t, botan_x509_general_name_t*> EnumeratorT,
1329
                std::invocable<botan_x509_cert_t, size_t*> CountFnT,
1330
                std::invocable<botan_x509_general_name_t> VisitorT>
1331
      static void visit_general_names(Test::Result& result,
12✔
1332
                                      botan_x509_cert_t cert,
1333
                                      EnumeratorT enumerator_fn,
1334
                                      CountFnT count_fn,
1335
                                      VisitorT visitor_fn) {
1336
         int rc = BOTAN_FFI_SUCCESS;
12✔
1337
         for(size_t i = 0; rc == BOTAN_FFI_SUCCESS; ++i) {
144✔
1338
            botan_x509_general_name_t gn;
1339
            rc = enumerator_fn(cert, i, &gn);
132✔
1340
            if(rc == BOTAN_FFI_SUCCESS) {
132✔
1341
               visitor_fn(gn);
120✔
1342
               TEST_FFI_OK(botan_x509_general_name_destroy, (gn));
120✔
1343
            } else if(rc == BOTAN_FFI_ERROR_OUT_OF_RANGE) {
12✔
1344
               // Now check we are at the expected index
1345
               size_t count;
1346
               TEST_FFI_OK(count_fn, (cert, &count));
12✔
1347
               result.test_sz_eq("enumerator reached end at expected index", i, count);
12✔
1348
            } else {
1349
               result.test_note(
×
1350
                  Botan::fmt("enumerator produced unexpected return code: {}", botan_error_description(rc)));
×
1351
            }
1352
         }
1353
      }
12✔
1354

1355
      template <typename EnumeratorT, typename CountFnT>
1356
      static auto read_string_alternative_names(Test::Result& result,
8✔
1357
                                                botan_x509_cert_t cert,
1358
                                                EnumeratorT enumerator_fn,
1359
                                                CountFnT count_fn,
1360
                                                botan_x509_general_name_types type) {
1361
         std::vector<std::string> out;
8✔
1362

1363
         visit_general_names(result, cert, enumerator_fn, count_fn, [&](botan_x509_general_name_t gn) {
88✔
1364
            unsigned int gn_type;
1365
            TEST_FFI_OK(botan_x509_general_name_get_type, (gn, &gn_type));
80✔
1366
            if(static_cast<botan_x509_general_name_types>(gn_type) == type) {
80✔
1367
               ViewStringSink str;
14✔
1368
               TEST_FFI_OK(botan_x509_general_name_view_string_value, (gn, str.delegate(), str.callback()));
14✔
1369
               out.push_back(str.get());
14✔
1370
            }
14✔
1371
         });
1372

1373
         return out;
8✔
1374
      }
×
1375

1376
      template <typename EnumeratorT, typename CountFnT>
1377
      static auto read_binary_alternative_names(Test::Result& result,
4✔
1378
                                                botan_x509_cert_t cert,
1379
                                                EnumeratorT enumerator_fn,
1380
                                                CountFnT count_fn,
1381
                                                botan_x509_general_name_types type) {
1382
         std::vector<std::vector<uint8_t>> out;
4✔
1383

1384
         visit_general_names(result, cert, enumerator_fn, count_fn, [&](botan_x509_general_name_t gn) {
44✔
1385
            unsigned int gn_type;
1386
            TEST_FFI_OK(botan_x509_general_name_get_type, (gn, &gn_type));
40✔
1387
            if(static_cast<botan_x509_general_name_types>(gn_type) == type) {
40✔
1388
               ViewBytesSink data;
8✔
1389
               TEST_FFI_OK(botan_x509_general_name_view_binary_value, (gn, data.delegate(), data.callback()));
8✔
1390
               out.emplace_back(data.get().begin(), data.get().end());
8✔
1391
            }
8✔
1392
         });
1393

1394
         return out;
4✔
1395
      }
×
1396

1397
      static auto read_common_names(std::span<const std::vector<uint8_t>> bytes) {
2✔
1398
         std::vector<std::string> result;
2✔
1399
         for(const auto& dn_bytes : bytes) {
8✔
1400
            const auto dn = read_distinguished_name(dn_bytes);
6✔
1401
            result.push_back(dn.get_first_attribute("X520.CommonName"));
12✔
1402
         }
6✔
1403
         return result;
2✔
1404
      }
×
1405

1406
   public:
1407
      std::string name() const override { return "FFI X509 Alternative Names"; }
1✔
1408

1409
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1410
         botan_x509_cert_t cert_none;
1✔
1411
         if(!TEST_FFI_INIT(botan_x509_cert_load_file,
1✔
1412
                           (&cert_none, Test::data_file("x509/misc/no_alternative_names.pem").c_str()))) {
1413
            return;
×
1414
         }
1415

1416
         botan_x509_general_name_t nil = nullptr;
1✔
1417
         TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE, botan_x509_cert_subject_alternative_names, (cert_none, 0, &nil));
1✔
1418
         TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE, botan_x509_cert_issuer_alternative_names, (cert_none, 0, &nil));
1✔
1419
         result.test_is_true("no general name created", nil == nullptr);
1✔
1420

1421
         botan_x509_cert_t cert;
1✔
1422
         if(!TEST_FFI_INIT(botan_x509_cert_load_file,
1✔
1423
                           (&cert, Test::data_file("x509/misc/multiple_alternative_names.pem").c_str()))) {
1424
            return;
1425
         }
1426

1427
         const auto get_san = botan_x509_cert_subject_alternative_names;
1✔
1428
         const auto count_san = botan_x509_cert_subject_alternative_names_count;
1✔
1429

1430
         const auto san_email =
1✔
1431
            read_string_alternative_names(result, cert, get_san, count_san, BOTAN_X509_EMAIL_ADDRESS);
1✔
1432
         result.test_sz_eq("expected number of emails in SAN", san_email.size(), 2);
1✔
1433
         result.test_is_true("testing@x509-labs.com", Botan::value_exists(san_email, "testing@x509-labs.com"));
2✔
1434
         result.test_is_true("info@x509-labs.com", Botan::value_exists(san_email, "info@x509-labs.com"));
2✔
1435

1436
         const auto san_dns = read_string_alternative_names(result, cert, get_san, count_san, BOTAN_X509_DNS_NAME);
1✔
1437
         result.test_sz_eq("expected number of hostnames in SAN", san_dns.size(), 3);
1✔
1438
         result.test_is_true("test.x509-labs.com", Botan::value_exists(san_dns, "test.x509-labs.com"));
2✔
1439
         result.test_is_true("versuch.x509-labs.com", Botan::value_exists(san_dns, "versuch.x509-labs.com"));
2✔
1440
         result.test_is_true("trail.x509-labs.com", Botan::value_exists(san_dns, "trail.x509-labs.com"));
2✔
1441

1442
         const auto san_uri = read_string_alternative_names(result, cert, get_san, count_san, BOTAN_X509_URI);
1✔
1443
         result.test_sz_eq("expected number of URIs in SAN", san_uri.size(), 2);
1✔
1444
         result.test_is_true("https://x509-labs.com", Botan::value_exists(san_uri, "https://x509-labs.com"));
2✔
1445
         result.test_is_true("http://x509-labs.com", Botan::value_exists(san_uri, "http://x509-labs.com"));
2✔
1446

1447
         const auto san_ip4 = read_string_alternative_names(result, cert, get_san, count_san, BOTAN_X509_IP_ADDRESS);
1✔
1448
         result.test_sz_eq("expected number of IPv4 addresses", san_ip4.size(), 1);
1✔
1449
         result.test_is_true("127.0.0.1", Botan::value_exists(san_ip4, "127.0.0.1"));
2✔
1450
         const auto san_ip4_bin =
1✔
1451
            read_binary_alternative_names(result, cert, get_san, count_san, BOTAN_X509_IP_ADDRESS);
1✔
1452
         result.test_sz_eq("expected number of IPv4 addresses (bin)", san_ip4_bin.size(), 1);
1✔
1453
         result.test_bin_eq("127.0.0.1 (bin)", san_ip4_bin.front(), Botan::store_be(uint32_t(0x7F000001)));
1✔
1454

1455
         const auto san_dn_bytes =
1✔
1456
            read_binary_alternative_names(result, cert, get_san, count_san, BOTAN_X509_DIRECTORY_NAME);
1✔
1457
         result.test_sz_eq("expected number of DNs in SAN", san_dn_bytes.size(), 3);
1✔
1458
         const auto san_dn_cns = read_common_names(san_dn_bytes);
1✔
1459
         result.test_is_true("First Name", Botan::value_exists(san_dn_cns, "First Name"));
2✔
1460
         result.test_is_true("Middle Name", Botan::value_exists(san_dn_cns, "Middle Name"));
2✔
1461
         result.test_is_true("Last Name", Botan::value_exists(san_dn_cns, "Last Name"));
2✔
1462

1463
         auto get_ian = botan_x509_cert_issuer_alternative_names;
1✔
1464
         auto count_ian = botan_x509_cert_issuer_alternative_names_count;
1✔
1465

1466
         const auto ian_email =
1✔
1467
            read_string_alternative_names(result, cert, get_ian, count_ian, BOTAN_X509_EMAIL_ADDRESS);
1✔
1468
         result.test_sz_eq("expected number of emails in IAN", ian_email.size(), 0);
1✔
1469

1470
         const auto ian_dns = read_string_alternative_names(result, cert, get_ian, count_ian, BOTAN_X509_DNS_NAME);
1✔
1471
         result.test_sz_eq("expected number of hostnames in IAN", ian_dns.size(), 3);
1✔
1472
         result.test_is_true("test.x509-labs-ca.com", Botan::value_exists(ian_dns, "test.x509-labs-ca.com"));
2✔
1473
         result.test_is_true("versuch.x509-labs-ca.com", Botan::value_exists(ian_dns, "versuch.x509-labs-ca.com"));
2✔
1474
         result.test_is_true("trail.x509-labs-ca.com", Botan::value_exists(ian_dns, "trail.x509-labs-ca.com"));
2✔
1475

1476
         const auto ian_uri = read_string_alternative_names(result, cert, get_ian, count_ian, BOTAN_X509_URI);
1✔
1477
         result.test_sz_eq("expected number of URIs in IAN", ian_uri.size(), 2);
1✔
1478
         result.test_is_true("https://x509-labs-ca.com", Botan::value_exists(ian_uri, "https://x509-labs-ca.com"));
2✔
1479
         result.test_is_true("http://x509-labs-ca.com", Botan::value_exists(ian_uri, "http://x509-labs-ca.com"));
2✔
1480

1481
         const auto ian_ip4 = read_string_alternative_names(result, cert, get_ian, count_ian, BOTAN_X509_IP_ADDRESS);
1✔
1482
         result.test_sz_eq("expected number of IPv4 addresses", ian_ip4.size(), 1);
1✔
1483
         result.test_is_true("192.168.1.1", Botan::value_exists(ian_ip4, "192.168.1.1"));
2✔
1484
         const auto ian_ip4_bin =
1✔
1485
            read_binary_alternative_names(result, cert, get_ian, count_ian, BOTAN_X509_IP_ADDRESS);
1✔
1486
         result.test_sz_eq("expected number of IPv4 addresses (bin)", ian_ip4_bin.size(), 1);
1✔
1487
         result.test_bin_eq("192.168.1.1 (bin)", ian_ip4_bin.front(), Botan::store_be(uint32_t(0xC0A80101)));
1✔
1488

1489
         const auto ian_dn_bytes =
1✔
1490
            read_binary_alternative_names(result, cert, get_ian, count_ian, BOTAN_X509_DIRECTORY_NAME);
1✔
1491
         result.test_sz_eq("expected number of DNs in IAN", ian_dn_bytes.size(), 3);
1✔
1492
         const auto ian_dn_cns = read_common_names(ian_dn_bytes);
1✔
1493
         result.test_is_true("First CA", Botan::value_exists(ian_dn_cns, "First CA"));
2✔
1494
         result.test_is_true("Middle CA", Botan::value_exists(ian_dn_cns, "Middle CA"));
2✔
1495
         result.test_is_true("Last CA", Botan::value_exists(ian_dn_cns, "Last CA"));
2✔
1496

1497
         TEST_FFI_OK(botan_x509_cert_destroy, (cert));
1✔
1498
         TEST_FFI_OK(botan_x509_cert_destroy, (cert_none));
1✔
1499
      }
1✔
1500
};
1501

1502
class FFI_Cert_NameConstraints_Test final : public FFI_Test {
1✔
1503
   private:
1504
      static auto read_constraints(Test::Result& result, botan_x509_cert_t cert, bool permitted) {
2✔
1505
         std::vector<std::pair<botan_x509_general_name_types, std::string>> out;
2✔
1506

1507
         int rc = BOTAN_FFI_SUCCESS;
2✔
1508
         for(size_t i = 0; rc == BOTAN_FFI_SUCCESS; ++i) {
78✔
1509
            botan_x509_general_name_t constraint;
76✔
1510
            if(permitted) {
76✔
1511
               rc = botan_x509_cert_permitted_name_constraints(cert, i, &constraint);
73✔
1512
            } else {
1513
               rc = botan_x509_cert_excluded_name_constraints(cert, i, &constraint);
3✔
1514
            }
1515

1516
            if(rc == BOTAN_FFI_SUCCESS) {
76✔
1517
               ViewBytesSink bytes;
74✔
1518
               ViewStringSink string;
74✔
1519

1520
               unsigned int type;
74✔
1521
               const auto rc2 = botan_x509_general_name_get_type(constraint, &type);
74✔
1522
               if(rc2 == BOTAN_FFI_SUCCESS) {
74✔
1523
                  const auto gn_type = static_cast<botan_x509_general_name_types>(type);
74✔
1524
                  switch(gn_type) {
74✔
1525
                     case BOTAN_X509_EMAIL_ADDRESS:
49✔
1526
                     case BOTAN_X509_DNS_NAME:
49✔
1527
                     case BOTAN_X509_URI:
49✔
1528
                     case BOTAN_X509_IP_ADDRESS:
49✔
1529
                        TEST_FFI_OK(botan_x509_general_name_view_string_value,
49✔
1530
                                    (constraint, string.delegate(), string.callback()));
1531
                        out.emplace_back(gn_type, string.get());
49✔
1532
                        break;
1533
                     case BOTAN_X509_DIRECTORY_NAME:
25✔
1534
                        TEST_FFI_OK(botan_x509_general_name_view_binary_value,
25✔
1535
                                    (constraint, bytes.delegate(), bytes.callback()));
1536
                        out.emplace_back(gn_type, read_distinguished_name(bytes.get()).to_string());
50✔
1537
                        break;
25✔
1538
                     case BOTAN_X509_OTHER_NAME:
×
1539
                        out.emplace_back(gn_type, "<not supported>");
×
1540
                        break;
1541
                  }
1542
               } else {
1543
                  result.test_note(
×
1544
                     Botan::fmt("botan_x509_general_name_get_type returned {}", botan_error_description(rc2)));
×
1545
               }
1546

1547
               TEST_FFI_OK(botan_x509_general_name_destroy, (constraint));
74✔
1548
            } else if(rc == BOTAN_FFI_ERROR_OUT_OF_RANGE) {
76✔
1549
               // Now check that we are at the expected index
1550
               size_t count;
2✔
1551
               if(permitted) {
2✔
1552
                  TEST_FFI_OK(botan_x509_cert_permitted_name_constraints_count, (cert, &count));
1✔
1553
               } else {
1554
                  TEST_FFI_OK(botan_x509_cert_excluded_name_constraints_count, (cert, &count));
1✔
1555
               }
1556
               result.test_sz_eq("expected length of name constraint list", i, count);
2✔
1557
            } else {
1558
               result.test_failure(Botan::fmt("unexpected error code: {}", botan_error_description(rc)));
×
1559
            }
1560
         }
1561

1562
         return out;
2✔
1563
      }
×
1564

1565
   public:
1566
      std::string name() const override { return "FFI X509 Name Constraints"; }
1✔
1567

1568
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1569
         botan_x509_cert_t cert;
1✔
1570
         if(!TEST_FFI_INIT(botan_x509_cert_load_file,
1✔
1571
                           (&cert, Test::data_file("x509/misc/name_constraint_ci/int.pem").c_str()))) {
1572
            return;
×
1573
         }
1574

1575
         const auto permitted = read_constraints(result, cert, true);
1✔
1576
         const auto excluded = read_constraints(result, cert, false);
1✔
1577

1578
         result.test_sz_eq("permissions", permitted.size(), 72);
1✔
1579
         result.test_sz_eq("exclusions", excluded.size(), 2);
1✔
1580

1581
         using V = decltype(permitted)::value_type;
1✔
1582
         result.test_is_true("email", Botan::value_exists(permitted, V{BOTAN_X509_EMAIL_ADDRESS, "pec.aruba.it"}));
1✔
1583
         result.test_is_true("DNS", Botan::value_exists(permitted, V{BOTAN_X509_DNS_NAME, "gov.it"}));
1✔
1584
         result.test_is_true(
1✔
1585
            "DN",
1586
            Botan::value_exists(
1✔
1587
               permitted,
1588
               V{BOTAN_X509_DIRECTORY_NAME, R"(C="IT",X520.State="Roma",X520.Locality="Roma",O="Sogei S.p.A.")"}));
1✔
1589
         result.test_is_true("IPv4", Botan::value_exists(excluded, V{BOTAN_X509_IP_ADDRESS, "0.0.0.0/0"}));
1✔
1590
         result.test_is_true("IPv6", Botan::value_exists(excluded, V{BOTAN_X509_IP_ADDRESS, "::/0"}));
1✔
1591

1592
         // below are more generic general_name_t tests
1593

1594
         botan_x509_general_name_t email;
1✔
1595
         botan_x509_general_name_t dns;
1✔
1596
         botan_x509_general_name_t dn;
1✔
1597
         botan_x509_general_name_t ip;
1✔
1598
         TEST_FFI_OK(botan_x509_cert_permitted_name_constraints, (cert, 0, &email));
1✔
1599
         TEST_FFI_OK(botan_x509_cert_permitted_name_constraints, (cert, 33, &dns));
1✔
1600
         TEST_FFI_OK(botan_x509_cert_permitted_name_constraints, (cert, 47, &dn));
1✔
1601
         TEST_FFI_OK(botan_x509_cert_excluded_name_constraints, (cert, 0, &ip));
1✔
1602

1603
         unsigned int type;
1✔
1604
         TEST_FFI_OK(botan_x509_general_name_get_type, (email, &type));
1✔
1605
         result.test_enum_eq("email", static_cast<botan_x509_general_name_types>(type), BOTAN_X509_EMAIL_ADDRESS);
1✔
1606
         TEST_FFI_OK(botan_x509_general_name_get_type, (dns, &type));
1✔
1607
         result.test_enum_eq("dns", static_cast<botan_x509_general_name_types>(type), BOTAN_X509_DNS_NAME);
1✔
1608
         TEST_FFI_OK(botan_x509_general_name_get_type, (dn, &type));
1✔
1609
         result.test_enum_eq("dn", static_cast<botan_x509_general_name_types>(type), BOTAN_X509_DIRECTORY_NAME);
1✔
1610
         TEST_FFI_OK(botan_x509_general_name_get_type, (ip, &type));
1✔
1611
         result.test_enum_eq("ip", static_cast<botan_x509_general_name_types>(type), BOTAN_X509_IP_ADDRESS);
1✔
1612

1613
         ViewBytesSink bin;
1✔
1614
         ViewStringSink str;
1✔
1615

1616
         TEST_FFI_OK(botan_x509_general_name_view_string_value, (email, str.delegate(), str.callback()));
1✔
1617
         result.test_str_eq("email as expected", str.get(), "agid.gov.it");
1✔
1618
         TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1619
                     botan_x509_general_name_view_binary_value,
1620
                     (email, bin.delegate(), bin.callback()));
1621

1622
         TEST_FFI_OK(botan_x509_general_name_view_string_value, (dns, str.delegate(), str.callback()));
1✔
1623
         result.test_str_eq("dns as expected", str.get(), "agendadigitale.it");
1✔
1624
         TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1625
                     botan_x509_general_name_view_binary_value,
1626
                     (dns, bin.delegate(), bin.callback()));
1627

1628
         TEST_FFI_OK(botan_x509_general_name_view_binary_value, (dn, bin.delegate(), bin.callback()));
1✔
1629
         const auto organization = read_distinguished_name(bin.get()).get_first_attribute("O");
1✔
1630
         result.test_str_eq("dn as expected", organization, "ACI Informatica S.p.A.");
1✔
1631
         TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1632
                     botan_x509_general_name_view_string_value,
1633
                     (dn, str.delegate(), str.callback()));
1634

1635
         TEST_FFI_OK(botan_x509_general_name_view_binary_value, (ip, bin.delegate(), bin.callback()));
1✔
1636
         result.test_sz_eq("ip has correct length", bin.get().size(), 8);
1✔
1637
         TEST_FFI_OK(botan_x509_general_name_view_string_value, (ip, str.delegate(), str.callback()));
1✔
1638
         result.test_str_eq("ip has correct length", str.get(), "0.0.0.0/0");
1✔
1639

1640
         TEST_FFI_OK(botan_x509_general_name_destroy, (email));
1✔
1641
         TEST_FFI_OK(botan_x509_general_name_destroy, (dns));
1✔
1642
         TEST_FFI_OK(botan_x509_general_name_destroy, (dn));
1✔
1643
         TEST_FFI_OK(botan_x509_general_name_destroy, (ip));
1✔
1644

1645
         TEST_FFI_OK(botan_x509_cert_destroy, (cert));
1✔
1646
      }
1✔
1647
};
1648

1649
class FFI_Cert_AuthorityInformationAccess_Test final : public FFI_Test {
1✔
1650
   private:
1651
      static auto read_aia_string_list(Test::Result& result, botan_x509_cert_t cert, botan_x509_value_type value_type) {
3✔
1652
         std::vector<std::string> out;
3✔
1653

1654
         size_t count = 0;
3✔
1655
         TEST_FFI_OK(botan_x509_cert_view_string_values_count, (cert, value_type, &count));
3✔
1656
         for(size_t i = 0; i < count; ++i) {
8✔
1657
            TEST_FFI_OK(botan_x509_cert_view_string_values,
5✔
1658
                        (cert, value_type, i, &out, [](botan_view_ctx ctx, const char* str, size_t) -> int {
1659
                           static_cast<std::vector<std::string>*>(ctx)->emplace_back(str);
1660
                           return BOTAN_FFI_SUCCESS;
1661
                        }));
1662
         }
1663

1664
         return out;
3✔
1665
      }
×
1666

1667
   public:
1668
      std::string name() const override { return "FFI X509 Authority Information Access"; }
1✔
1669

1670
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1671
         botan_x509_cert_t cert_with_aia;
1✔
1672
         botan_x509_cert_t cert_without_crl_dps;
1✔
1673
         if(!TEST_FFI_INIT(
1✔
1674
               botan_x509_cert_load_file,
1675
               (&cert_with_aia,
1676
                Test::data_file("x509/misc/contains_authority_info_access_with_two_ca_issuers.pem").c_str()))) {
1677
            return;
×
1678
         }
1679

1680
         if(!TEST_FFI_INIT(botan_x509_cert_load_file,
1✔
1681
                           (&cert_without_crl_dps, Test::data_file("x509/misc/no_alternative_names.pem").c_str()))) {
1682
            return;
1683
         }
1684

1685
         TEST_FFI_RC(
1✔
1686
            BOTAN_FFI_ERROR_OUT_OF_RANGE,
1687
            botan_x509_cert_view_string_values,
1688
            (cert_without_crl_dps, BOTAN_X509_CRL_DISTRIBUTION_URLS, 0, nullptr, [](auto, auto, auto) { return 0; }));
1689

1690
         const auto crl_dps = read_aia_string_list(result, cert_with_aia, BOTAN_X509_CRL_DISTRIBUTION_URLS);
1✔
1691
         result.test_sz_eq("has two CRL URI distribution points", crl_dps.size(), 2);
1✔
1692
         result.test_is_true("has expected CRL URI distribution point",
1✔
1693
                             Botan::value_exists(crl_dps, "http://crl.d-trust.net/crl/bdrive_test_ca_1-2_2017.crl"));
1✔
1694

1695
         const auto dummy_callback = [](auto, auto, auto) -> int { return BOTAN_FFI_SUCCESS; };
1✔
1696

1697
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE,
1✔
1698
                     botan_x509_cert_view_string_values,
1699
                     (cert_without_crl_dps, BOTAN_X509_OCSP_RESPONDER_URLS, 0, nullptr, dummy_callback));
1700
         TEST_FFI_RC(BOTAN_FFI_ERROR_OUT_OF_RANGE,
1✔
1701
                     botan_x509_cert_view_string_values,
1702
                     (cert_without_crl_dps, BOTAN_X509_CA_ISSUERS_URLS, 0, nullptr, dummy_callback));
1703

1704
         const auto ocsps = read_aia_string_list(result, cert_with_aia, BOTAN_X509_OCSP_RESPONDER_URLS);
1✔
1705
         result.test_is_true("OCSP responder found", Botan::value_exists(ocsps, "http://staging.ocsp.d-trust.net"));
2✔
1706

1707
         const auto cas = read_aia_string_list(result, cert_with_aia, BOTAN_X509_CA_ISSUERS_URLS);
1✔
1708
         result.test_is_true("CA issuer found",
1✔
1709
                             Botan::value_exists(cas, "http://www.d-trust.net/cgi-bin/Bdrive_Test_CA_1-2_2017.crt"));
1✔
1710

1711
         TEST_FFI_OK(botan_x509_cert_destroy, (cert_with_aia));
1✔
1712
         TEST_FFI_OK(botan_x509_cert_destroy, (cert_without_crl_dps));
1✔
1713
      }
1✔
1714
};
1715

1716
   #endif
1717

1718
class FFI_PKCS_Hashid_Test final : public FFI_Test {
1✔
1719
   public:
1720
      std::string name() const override { return "FFI PKCS hash id"; }
1✔
1721

1722
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1723
         std::vector<uint8_t> hash_id(64);
1✔
1724
         size_t hash_id_len = hash_id.size();
1✔
1725

1726
         if(TEST_FFI_INIT(botan_pkcs_hash_id, ("SHA-256", hash_id.data(), &hash_id_len))) {
1✔
1727
            result.test_sz_eq("Expected SHA-256 PKCS hash id len", hash_id_len, 19);
1✔
1728

1729
            hash_id.resize(hash_id_len);
1✔
1730
            result.test_bin_eq("Expected SHA_256 PKCS hash id", hash_id, "3031300D060960864801650304020105000420");
1✔
1731

1732
            hash_id_len = 3;  // too short
1✔
1733
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1734
                        botan_pkcs_hash_id,
1735
                        ("SHA-256", hash_id.data(), &hash_id_len));
1736
         }
1737
      }
1✔
1738
};
1739

1740
class FFI_CBC_Cipher_Test final : public FFI_Test {
1✔
1741
   public:
1742
      std::string name() const override { return "FFI CBC cipher"; }
1✔
1743

1744
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1745
         botan_cipher_t cipher_encrypt;
1✔
1746
         botan_cipher_t cipher_decrypt;
1✔
1747

1748
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/CBC/PKCS7", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
1749
            size_t min_keylen = 0;
1✔
1750
            size_t max_keylen = 0;
1✔
1751
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
1752
            result.test_sz_eq("Min key length", min_keylen, 16);
1✔
1753
            result.test_sz_eq("Max key length", max_keylen, 16);
1✔
1754

1755
            // from https://github.com/geertj/bluepass/blob/master/tests/vectors/aes-cbc-pkcs7.txt
1756
            const std::vector<uint8_t> plaintext =
1✔
1757
               Botan::hex_decode("0397f4f6820b1f9386f14403be5ac16e50213bd473b4874b9bcbf5f318ee686b1d");
1✔
1758
            const std::vector<uint8_t> symkey = Botan::hex_decode("898be9cc5004ed0fa6e117c9a3099d31");
1✔
1759
            const std::vector<uint8_t> nonce = Botan::hex_decode("9dea7621945988f96491083849b068df");
1✔
1760
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
1761
               "e232cd6ef50047801ee681ec30f61d53cfd6b0bca02fd03c1b234baa10ea82ac9dab8b960926433a19ce6dea08677e34");
1✔
1762

1763
            size_t output_written = 0;
1✔
1764
            size_t input_consumed = 0;
1✔
1765

1766
            // Test that after clear or final the object can be reused
1767
            for(size_t r = 0; r != 2; ++r) {
3✔
1768
               size_t ctext_len;
2✔
1769
               TEST_FFI_OK(botan_cipher_output_length, (cipher_encrypt, plaintext.size(), &ctext_len));
2✔
1770
               result.test_sz_eq("Expected size of padded message", ctext_len, plaintext.size() + 15);
2✔
1771
               std::vector<uint8_t> ciphertext(ctext_len);
2✔
1772

1773
               size_t update_granularity = 0;
2✔
1774
               size_t ideal_granularity = 0;
2✔
1775
               size_t taglen = 0;
2✔
1776

1777
               TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
2✔
1778
               TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
2✔
1779
               TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &taglen));
2✔
1780

1781
               result.test_sz_eq(
2✔
1782
                  "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
1783
               result.test_sz_eq("not an AEAD, hence no tag", taglen, 0);
2✔
1784

1785
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1786
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1787
               TEST_FFI_OK(botan_cipher_update,
2✔
1788
                           (cipher_encrypt,
1789
                            0,
1790
                            ciphertext.data(),
1791
                            ciphertext.size(),
1792
                            &output_written,
1793
                            plaintext.data(),
1794
                            plaintext.size(),
1795
                            &input_consumed));
1796
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
1797

1798
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1799
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1800
               TEST_FFI_OK(botan_cipher_update,
2✔
1801
                           (cipher_encrypt,
1802
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1803
                            ciphertext.data(),
1804
                            ciphertext.size(),
1805
                            &output_written,
1806
                            plaintext.data(),
1807
                            plaintext.size(),
1808
                            &input_consumed));
1809

1810
               ciphertext.resize(output_written);
2✔
1811
               result.test_bin_eq("AES/CBC ciphertext", ciphertext, exp_ciphertext);
2✔
1812

1813
               if(TEST_FFI_OK(botan_cipher_init, (&cipher_decrypt, "AES-128/CBC", BOTAN_CIPHER_INIT_FLAG_DECRYPT))) {
2✔
1814
                  size_t ptext_len;
2✔
1815
                  TEST_FFI_OK(botan_cipher_output_length, (cipher_decrypt, ciphertext.size(), &ptext_len));
2✔
1816
                  std::vector<uint8_t> decrypted(ptext_len);
2✔
1817

1818
                  TEST_FFI_RC(0, botan_cipher_is_authenticated, (cipher_encrypt));
2✔
1819

1820
                  TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
2✔
1821
                  TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
2✔
1822
                  TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_decrypt, &taglen));
2✔
1823

1824
                  result.test_sz_eq("ideal granularity is a multiple of update granularity (decrypt)",
2✔
1825
                                    ideal_granularity % update_granularity,
1826
                                    0);
1827
                  result.test_sz_eq("not an AEAD, hence no tag (decrypt)", taglen, 0);
2✔
1828

1829
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
1830
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
1831
                  TEST_FFI_OK(botan_cipher_update,
2✔
1832
                              (cipher_decrypt,
1833
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1834
                               decrypted.data(),
1835
                               decrypted.size(),
1836
                               &output_written,
1837
                               ciphertext.data(),
1838
                               ciphertext.size(),
1839
                               &input_consumed));
1840

1841
                  decrypted.resize(output_written);
2✔
1842

1843
                  result.test_bin_eq("AES/CBC plaintext", decrypted, plaintext);
2✔
1844

1845
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
2✔
1846
               }
2✔
1847
            }
2✔
1848

1849
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
1✔
1850
         }
1✔
1851
      }
1✔
1852
};
1853

1854
class FFI_GCM_Test final : public FFI_Test {
1✔
1855
   public:
1856
      std::string name() const override { return "FFI GCM"; }
1✔
1857

1858
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1859
         botan_cipher_t cipher_encrypt;
1✔
1860
         botan_cipher_t cipher_decrypt;
1✔
1861

1862
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/GCM", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
1863
            std::array<char, 18> namebuf{};
1✔
1864
            size_t name_len = 15;
1✔
1865
            TEST_FFI_FAIL("output buffer too short", botan_cipher_name, (cipher_encrypt, namebuf.data(), &name_len));
1✔
1866
            result.test_sz_eq("name len", name_len, 16);
1✔
1867

1868
            name_len = namebuf.size();
1✔
1869
            if(TEST_FFI_OK(botan_cipher_name, (cipher_encrypt, namebuf.data(), &name_len))) {
1✔
1870
               result.test_sz_eq("name len", name_len, 16);
1✔
1871
               result.test_str_eq("name", namebuf.data(), "AES-128/GCM(16)");
1✔
1872
            }
1873

1874
            size_t min_keylen = 0;
1✔
1875
            size_t max_keylen = 0;
1✔
1876
            size_t nonce_len = 0;
1✔
1877
            size_t tag_len = 0;
1✔
1878
            size_t update_granularity = 0;
1✔
1879
            size_t ideal_granularity = 0;
1✔
1880

1881
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
1✔
1882
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
1✔
1883

1884
            result.test_sz_eq(
1✔
1885
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
1886

1887
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
1888
            result.test_sz_eq("Min key length", min_keylen, 16);
1✔
1889
            result.test_sz_eq("Max key length", max_keylen, 16);
1✔
1890

1891
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &nonce_len));
1✔
1892
            result.test_sz_eq("Expected default GCM nonce length", nonce_len, 12);
1✔
1893

1894
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &tag_len));
1✔
1895
            result.test_sz_eq("Expected GCM tag length", tag_len, 16);
1✔
1896

1897
            TEST_FFI_RC(1, botan_cipher_is_authenticated, (cipher_encrypt));
1✔
1898

1899
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 12));
1✔
1900
            // GCM accepts any nonce size except zero
1901
            TEST_FFI_RC(0, botan_cipher_valid_nonce_length, (cipher_encrypt, 0));
1✔
1902
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 1));
1✔
1903
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 100009));
1✔
1904

1905
            // NIST test vector
1906
            const std::vector<uint8_t> plaintext = Botan::hex_decode(
1✔
1907
               "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39");
1✔
1908

1909
            const std::vector<uint8_t> symkey = Botan::hex_decode("FEFFE9928665731C6D6A8F9467308308");
1✔
1910
            const std::vector<uint8_t> nonce = Botan::hex_decode("CAFEBABEFACEDBADDECAF888");
1✔
1911
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
1912
               "42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E0915BC94FBC3221A5DB94FAE95AE7121A47");
1✔
1913
            const std::vector<uint8_t> aad = Botan::hex_decode("FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2");
1✔
1914

1915
            std::vector<uint8_t> ciphertext(tag_len + plaintext.size());
1✔
1916

1917
            size_t output_written = 0;
1✔
1918
            size_t input_consumed = 0;
1✔
1919

1920
            // Test that after clear or final the object can be reused
1921
            for(size_t r = 0; r != 2; ++r) {
3✔
1922
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1923

1924
               // First use a nonce of the AAD, and ensure reset works
1925
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, aad.data(), aad.size()));
2✔
1926
               TEST_FFI_OK(botan_cipher_reset, (cipher_encrypt));
2✔
1927

1928
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1929
               TEST_FFI_OK(botan_cipher_update,
2✔
1930
                           (cipher_encrypt,
1931
                            0,
1932
                            ciphertext.data(),
1933
                            ciphertext.size(),
1934
                            &output_written,
1935
                            plaintext.data(),
1936
                            plaintext.size(),
1937
                            &input_consumed));
1938
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
1939

1940
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1941
               TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_encrypt, aad.data(), aad.size()));
2✔
1942
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1943
               TEST_FFI_OK(botan_cipher_update,
2✔
1944
                           (cipher_encrypt,
1945
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1946
                            ciphertext.data(),
1947
                            ciphertext.size(),
1948
                            &output_written,
1949
                            plaintext.data(),
1950
                            plaintext.size(),
1951
                            &input_consumed));
1952

1953
               ciphertext.resize(output_written);
2✔
1954
               result.test_bin_eq("AES/GCM ciphertext", ciphertext, exp_ciphertext);
2✔
1955

1956
               if(TEST_FFI_OK(botan_cipher_init, (&cipher_decrypt, "AES-128/GCM", BOTAN_CIPHER_INIT_FLAG_DECRYPT))) {
2✔
1957
                  std::vector<uint8_t> decrypted(plaintext.size());
2✔
1958

1959
                  TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
2✔
1960
                  TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
2✔
1961

1962
                  result.test_sz_eq("ideal granularity is a multiple of update granularity (decrypt)",
2✔
1963
                                    ideal_granularity % update_granularity,
1964
                                    0);
1965

1966
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
1967
                  TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_decrypt, aad.data(), aad.size()));
2✔
1968
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
1969
                  TEST_FFI_OK(botan_cipher_update,
2✔
1970
                              (cipher_decrypt,
1971
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1972
                               decrypted.data(),
1973
                               decrypted.size(),
1974
                               &output_written,
1975
                               ciphertext.data(),
1976
                               ciphertext.size(),
1977
                               &input_consumed));
1978

1979
                  result.test_sz_eq("All input consumed", input_consumed, ciphertext.size());
2✔
1980
                  result.test_sz_eq("Expected output size produced", output_written, decrypted.size());
2✔
1981
                  result.test_bin_eq("AES/GCM plaintext", decrypted, plaintext);
2✔
1982

1983
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
2✔
1984
               }
2✔
1985
            }
1986

1987
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
1✔
1988
         }
1✔
1989
      }
1✔
1990
};
1991

1992
class FFI_ChaCha20Poly1305_Test final : public FFI_Test {
1✔
1993
   public:
1994
      std::string name() const override { return "FFI ChaCha20Poly1305"; }
1✔
1995

1996
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1997
         botan_cipher_t cipher_encrypt;
1✔
1998
         botan_cipher_t cipher_decrypt;
1✔
1999

2000
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "ChaCha20Poly1305", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
2001
            std::array<char, 17> namebuf{};
1✔
2002
            size_t name_len = 15;
1✔
2003
            TEST_FFI_FAIL("output buffer too short", botan_cipher_name, (cipher_encrypt, namebuf.data(), &name_len));
1✔
2004
            result.test_sz_eq("name len", name_len, 17);
1✔
2005

2006
            name_len = namebuf.size();
1✔
2007
            if(TEST_FFI_OK(botan_cipher_name, (cipher_encrypt, namebuf.data(), &name_len))) {
1✔
2008
               result.test_sz_eq("name len", name_len, 17);
1✔
2009
               result.test_str_eq("name", std::string(namebuf.data()), "ChaCha20Poly1305");
1✔
2010
            }
2011

2012
            size_t min_keylen = 0;
1✔
2013
            size_t max_keylen = 0;
1✔
2014
            size_t nonce_len = 0;
1✔
2015
            size_t tag_len = 0;
1✔
2016
            size_t update_granularity = 0;
1✔
2017
            size_t ideal_granularity = 0;
1✔
2018

2019
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
1✔
2020
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
1✔
2021

2022
            result.test_sz_eq(
1✔
2023
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
2024

2025
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
2026
            result.test_sz_eq("Min key length", min_keylen, 32);
1✔
2027
            result.test_sz_eq("Max key length", max_keylen, 32);
1✔
2028

2029
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &nonce_len));
1✔
2030
            result.test_sz_eq("Expected default ChaCha20Poly1305 nonce length", nonce_len, 12);
1✔
2031

2032
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &tag_len));
1✔
2033
            result.test_sz_eq("Expected Chacha20Poly1305 tag length", tag_len, 16);
1✔
2034

2035
            TEST_FFI_RC(1, botan_cipher_is_authenticated, (cipher_encrypt));
1✔
2036

2037
            // From RFC 7539
2038
            const std::vector<uint8_t> plaintext = Botan::hex_decode(
1✔
2039
               "4C616469657320616E642047656E746C656D656E206F662074686520636C617373206F66202739393A204966204920636F756C64206F6666657220796F75206F6E6C79206F6E652074697020666F7220746865206675747572652C2073756E73637265656E20776F756C642062652069742E");
1✔
2040
            const std::vector<uint8_t> symkey =
1✔
2041
               Botan::hex_decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F");
1✔
2042
            const std::vector<uint8_t> nonce = Botan::hex_decode("070000004041424344454647");
1✔
2043
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
2044
               "D31A8D34648E60DB7B86AFBC53EF7EC2A4ADED51296E08FEA9E2B5A736EE62D63DBEA45E8CA9671282FAFB69DA92728B1A71DE0A9E060B2905D6A5B67ECD3B3692DDBD7F2D778B8C9803AEE328091B58FAB324E4FAD675945585808B4831D7BC3FF4DEF08E4B7A9DE576D26586CEC64B61161AE10B594F09E26A7E902ECBD0600691");
1✔
2045
            const std::vector<uint8_t> aad = Botan::hex_decode("50515253C0C1C2C3C4C5C6C7");
1✔
2046

2047
            std::vector<uint8_t> ciphertext(tag_len + plaintext.size());
1✔
2048

2049
            size_t output_written = 0;
1✔
2050
            size_t input_consumed = 0;
1✔
2051

2052
            // Test that after clear or final the object can be reused
2053
            for(size_t r = 0; r != 2; ++r) {
3✔
2054
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
2055

2056
               // First use a nonce of the AAD, and ensure reset works
2057
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, aad.data(), aad.size()));
2✔
2058
               TEST_FFI_OK(botan_cipher_reset, (cipher_encrypt));
2✔
2059

2060
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
2061
               TEST_FFI_OK(botan_cipher_update,
2✔
2062
                           (cipher_encrypt,
2063
                            0,
2064
                            ciphertext.data(),
2065
                            ciphertext.size(),
2066
                            &output_written,
2067
                            plaintext.data(),
2068
                            plaintext.size(),
2069
                            &input_consumed));
2070
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
2071

2072
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
2073
               TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_encrypt, aad.data(), aad.size()));
2✔
2074
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
2075
               TEST_FFI_OK(botan_cipher_update,
2✔
2076
                           (cipher_encrypt,
2077
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2078
                            ciphertext.data(),
2079
                            ciphertext.size(),
2080
                            &output_written,
2081
                            plaintext.data(),
2082
                            plaintext.size(),
2083
                            &input_consumed));
2084

2085
               ciphertext.resize(output_written);
2✔
2086
               result.test_bin_eq("AES/GCM ciphertext", ciphertext, exp_ciphertext);
2✔
2087

2088
               if(TEST_FFI_OK(botan_cipher_init,
2✔
2089
                              (&cipher_decrypt, "ChaCha20Poly1305", BOTAN_CIPHER_INIT_FLAG_DECRYPT))) {
2090
                  std::vector<uint8_t> decrypted(plaintext.size());
2✔
2091

2092
                  TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
2✔
2093
                  TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
2✔
2094

2095
                  result.test_sz_eq("ideal granularity is a multiple of update granularity (decrypt)",
2✔
2096
                                    ideal_granularity % update_granularity,
2097
                                    0);
2098

2099
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
2100
                  TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_decrypt, aad.data(), aad.size()));
2✔
2101
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
2102
                  TEST_FFI_OK(botan_cipher_update,
2✔
2103
                              (cipher_decrypt,
2104
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2105
                               decrypted.data(),
2106
                               decrypted.size(),
2107
                               &output_written,
2108
                               ciphertext.data(),
2109
                               ciphertext.size(),
2110
                               &input_consumed));
2111

2112
                  result.test_sz_eq("All input consumed", input_consumed, ciphertext.size());
2✔
2113
                  result.test_sz_eq("Expected output size produced", output_written, decrypted.size());
2✔
2114
                  result.test_bin_eq("AES/GCM plaintext", decrypted, plaintext);
2✔
2115

2116
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
2✔
2117
               }
2✔
2118
            }
2119

2120
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
1✔
2121
         }
1✔
2122
      }
1✔
2123
};
2124

2125
class FFI_EAX_Test final : public FFI_Test {
1✔
2126
   public:
2127
      std::string name() const override { return "FFI EAX"; }
1✔
2128

2129
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2130
         botan_cipher_t cipher_encrypt;
1✔
2131
         botan_cipher_t cipher_decrypt;
1✔
2132

2133
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/EAX", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
2134
            size_t min_keylen = 0;
1✔
2135
            size_t max_keylen = 0;
1✔
2136
            size_t mod_keylen = 0;
1✔
2137
            size_t nonce_len = 0;
1✔
2138
            size_t tag_len = 0;
1✔
2139
            size_t update_granularity = 0;
1✔
2140
            size_t ideal_granularity = 0;
1✔
2141

2142
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
1✔
2143
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
1✔
2144

2145
            result.test_sz_eq(
1✔
2146
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
2147

2148
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
2149
            result.test_sz_eq("Min key length", min_keylen, 16);
1✔
2150
            result.test_sz_eq("Max key length", max_keylen, 16);
1✔
2151

2152
            TEST_FFI_OK(botan_cipher_get_keyspec, (cipher_encrypt, &min_keylen, &max_keylen, &mod_keylen));
1✔
2153
            result.test_sz_eq("Min key length", min_keylen, 16);
1✔
2154
            result.test_sz_eq("Max key length", max_keylen, 16);
1✔
2155
            result.test_sz_eq("Mod key length", mod_keylen, 1);
1✔
2156

2157
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &nonce_len));
1✔
2158
            result.test_sz_eq("Expected default EAX nonce length", nonce_len, 12);
1✔
2159

2160
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &tag_len));
1✔
2161
            result.test_sz_eq("Expected EAX tag length", tag_len, 16);
1✔
2162

2163
            TEST_FFI_RC(1, botan_cipher_is_authenticated, (cipher_encrypt));
1✔
2164

2165
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 12));
1✔
2166
            // EAX accepts any nonce size...
2167
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 0));
1✔
2168

2169
            const std::vector<uint8_t> plaintext =
1✔
2170
               Botan::hex_decode("0000000000000000000000000000000011111111111111111111111111111111");
1✔
2171
            const std::vector<uint8_t> symkey = Botan::hex_decode("000102030405060708090a0b0c0d0e0f");
1✔
2172
            const std::vector<uint8_t> nonce = Botan::hex_decode("3c8cc2970a008f75cc5beae2847258c2");
1✔
2173
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
2174
               "3c441f32ce07822364d7a2990e50bb13d7b02a26969e4a937e5e9073b0d9c968db90bdb3da3d00afd0fc6a83551da95e");
1✔
2175

2176
            std::vector<uint8_t> ciphertext(tag_len + plaintext.size());
1✔
2177

2178
            size_t output_written = 0;
1✔
2179
            size_t input_consumed = 0;
1✔
2180

2181
            // Test that after clear or final the object can be reused
2182
            for(size_t r = 0; r != 2; ++r) {
3✔
2183
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
2184
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
2185
               TEST_FFI_OK(botan_cipher_update,
2✔
2186
                           (cipher_encrypt,
2187
                            0,
2188
                            ciphertext.data(),
2189
                            ciphertext.size(),
2190
                            &output_written,
2191
                            plaintext.data(),
2192
                            plaintext.size(),
2193
                            &input_consumed));
2194
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
2195

2196
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
2197
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
2198
               TEST_FFI_OK(botan_cipher_update,
2✔
2199
                           (cipher_encrypt,
2200
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2201
                            ciphertext.data(),
2202
                            ciphertext.size(),
2203
                            &output_written,
2204
                            plaintext.data(),
2205
                            plaintext.size(),
2206
                            &input_consumed));
2207

2208
               ciphertext.resize(output_written);
2✔
2209
               result.test_bin_eq("AES/EAX ciphertext", ciphertext, exp_ciphertext);
2✔
2210

2211
               if(TEST_FFI_OK(botan_cipher_init, (&cipher_decrypt, "AES-128/EAX", BOTAN_CIPHER_INIT_FLAG_DECRYPT))) {
2✔
2212
                  std::vector<uint8_t> decrypted(plaintext.size());
2✔
2213

2214
                  TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
2✔
2215
                  TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
2✔
2216

2217
                  result.test_sz_eq("ideal granularity is a multiple of update granularity (decrypt)",
2✔
2218
                                    ideal_granularity % update_granularity,
2219
                                    0);
2220

2221
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
2222
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
2223
                  TEST_FFI_OK(botan_cipher_update,
2✔
2224
                              (cipher_decrypt,
2225
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2226
                               decrypted.data(),
2227
                               decrypted.size(),
2228
                               &output_written,
2229
                               ciphertext.data(),
2230
                               ciphertext.size(),
2231
                               &input_consumed));
2232

2233
                  result.test_sz_eq("All input consumed", input_consumed, ciphertext.size());
2✔
2234
                  result.test_sz_eq("Expected output size produced", output_written, decrypted.size());
2✔
2235
                  result.test_bin_eq("AES/EAX plaintext", decrypted, plaintext);
2✔
2236

2237
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
2✔
2238
               }
2✔
2239
            }
2240

2241
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
1✔
2242
         }
1✔
2243
      }
1✔
2244
};
2245

2246
class FFI_AEAD_Test final : public FFI_Test {
1✔
2247
   public:
2248
      std::string name() const override { return "FFI AEAD"; }
1✔
2249

2250
      void ffi_test(Test::Result& merged_result, botan_rng_t rng) override {
1✔
2251
         botan_cipher_t cipher_encrypt;
1✔
2252
         botan_cipher_t cipher_decrypt;
1✔
2253

2254
         const std::array<std::string, 5> aeads = {
1✔
2255
            "AES-128/GCM", "ChaCha20Poly1305", "AES-128/EAX", "AES-256/SIV", "AES-128/CCM"};
1✔
2256

2257
         for(const std::string& aead : aeads) {
6✔
2258
            Test::Result result(Botan::fmt("AEAD {}", aead));
5✔
2259

2260
            if(!TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, aead.c_str(), BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
5✔
2261
               continue;
×
2262
            }
2263

2264
            if(botan_cipher_is_authenticated(cipher_encrypt) == 0) {
5✔
2265
               result.test_failure("Cipher " + aead + " claims is not authenticated");
×
2266
               botan_cipher_destroy(cipher_encrypt);
×
2267
               continue;
×
2268
            }
2269

2270
            size_t min_keylen = 0;
5✔
2271
            size_t max_keylen = 0;
5✔
2272
            size_t update_granularity = 0;
5✔
2273
            size_t ideal_granularity = 0;
5✔
2274
            size_t noncelen = 0;
5✔
2275
            size_t taglen = 0;
5✔
2276
            constexpr size_t pt_multiplier = 5;
5✔
2277
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
5✔
2278
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
5✔
2279
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
5✔
2280
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &noncelen));
5✔
2281
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &taglen));
5✔
2282

2283
            result.test_sz_eq(
5✔
2284
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
2285

2286
            std::vector<uint8_t> key(max_keylen);
5✔
2287
            TEST_FFI_OK(botan_rng_get, (rng, key.data(), key.size()));
5✔
2288
            TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, key.data(), key.size()));
5✔
2289

2290
            std::vector<uint8_t> nonce(noncelen);
5✔
2291
            TEST_FFI_OK(botan_rng_get, (rng, nonce.data(), nonce.size()));
5✔
2292
            TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
5✔
2293

2294
            std::vector<uint8_t> plaintext(ideal_granularity * pt_multiplier);
5✔
2295
            std::vector<uint8_t> ciphertext(ideal_granularity * pt_multiplier + taglen);
5✔
2296
            TEST_FFI_OK(botan_rng_get, (rng, plaintext.data(), plaintext.size()));
5✔
2297

2298
            std::vector<uint8_t> dummy_buffer(1024);
5✔
2299
            TEST_FFI_OK(botan_rng_get, (rng, dummy_buffer.data(), dummy_buffer.size()));
5✔
2300
            std::vector<uint8_t> dummy_buffer_reference = dummy_buffer;
5✔
2301

2302
            const bool requires_entire_message = botan_cipher_requires_entire_message(cipher_encrypt) == 1;
5✔
2303
            result.test_bool_eq(
5✔
2304
               "requires entire message", requires_entire_message, (aead == "AES-256/SIV" || aead == "AES-128/CCM"));
5✔
2305

2306
            std::span<const uint8_t> pt_slicer(plaintext);
5✔
2307
            std::span<uint8_t> ct_stuffer(ciphertext);
5✔
2308

2309
            // Process data that is explicitly a multiple of the ideal
2310
            // granularity and therefore should be aligned with the cipher's
2311
            // internal block size.
2312
            for(size_t i = 0; i < pt_multiplier; ++i) {
30✔
2313
               size_t output_written = 0;
25✔
2314
               size_t input_consumed = 0;
25✔
2315

2316
               auto pt_chunk = pt_slicer.first(ideal_granularity);
25✔
2317

2318
               // The existing implementation won't consume any bytes from the
2319
               // input if there is no space in the output buffer. Even when
2320
               // the cipher is a mode that won't produce any output until the
2321
               // entire message is processed. Hence, give it some dummy buffer.
2322
               BOTAN_ASSERT_NOMSG(dummy_buffer.size() > ideal_granularity);
25✔
2323
               auto ct_chunk = (requires_entire_message) ? std::span(dummy_buffer).first(ideal_granularity)
25✔
2324
                                                         : ct_stuffer.first(ideal_granularity);
2325

2326
               TEST_FFI_OK(botan_cipher_update,
25✔
2327
                           (cipher_encrypt,
2328
                            0 /* don't finalize */,
2329
                            ct_chunk.data(),
2330
                            ct_chunk.size(),
2331
                            &output_written,
2332
                            pt_chunk.data(),
2333
                            pt_chunk.size(),
2334
                            &input_consumed));
2335

2336
               result.test_sz_gt("some input consumed", input_consumed, 0);
25✔
2337
               result.test_sz_lte("at most, all input consumed", input_consumed, pt_chunk.size());
25✔
2338
               pt_slicer = pt_slicer.subspan(input_consumed);
25✔
2339

2340
               if(requires_entire_message) {
25✔
2341
                  result.test_sz_eq("no output produced", output_written, 0);
10✔
2342
               } else {
2343
                  result.test_sz_eq("all bytes produced", output_written, input_consumed);
15✔
2344
                  ct_stuffer = ct_stuffer.subspan(output_written);
15✔
2345
               }
2346
            }
2347

2348
            // Trying to pull a part of the authentication tag should fail,
2349
            // as we must consume the entire tag in a single invocation to
2350
            // botan_cipher_update().
2351
            size_t final_output_written = 42;
5✔
2352
            size_t final_input_consumed = 1337;
5✔
2353
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
5✔
2354
                        botan_cipher_update,
2355
                        (cipher_encrypt,
2356
                         BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2357
                         dummy_buffer.data(),
2358
                         3, /* not enough to hold any reasonable auth'n tag */
2359
                         &final_output_written,
2360
                         pt_slicer.data(),  // remaining bytes (typically 0)
2361
                         pt_slicer.size(),
2362
                         &final_input_consumed));
2363

2364
            const size_t expected_final_size = requires_entire_message ? ciphertext.size() : taglen + pt_slicer.size();
5✔
2365

2366
            result.test_sz_eq("remaining bytes consumed in bogus final", final_input_consumed, pt_slicer.size());
5✔
2367
            result.test_sz_eq(
5✔
2368
               "required buffer size is written in bogus final", final_output_written, expected_final_size);
2369

2370
            auto final_ct_chunk = ct_stuffer.first(expected_final_size);
5✔
2371

2372
            TEST_FFI_OK(botan_cipher_update,
5✔
2373
                        (cipher_encrypt,
2374
                         BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2375
                         final_ct_chunk.data(),
2376
                         final_ct_chunk.size(),
2377
                         &final_output_written,
2378
                         nullptr,  // no more input
2379
                         0,
2380
                         &final_input_consumed));
2381

2382
            result.test_sz_eq("no bytes consumed in final", final_input_consumed, 0);
5✔
2383
            result.test_sz_eq("final bytes written", final_output_written, expected_final_size);
5✔
2384
            result.test_bin_eq("dummy buffer unchanged", dummy_buffer, dummy_buffer_reference);
5✔
2385

2386
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
5✔
2387

2388
            // ----------------------------------------------------------------
2389

2390
            TEST_FFI_INIT(botan_cipher_init, (&cipher_decrypt, aead.c_str(), BOTAN_CIPHER_INIT_FLAG_DECRYPT));
5✔
2391

2392
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
5✔
2393
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
5✔
2394

2395
            result.test_sz_eq("ideal granularity is a multiple of update granularity (decrypt)",
5✔
2396
                              ideal_granularity % update_granularity,
2397
                              0);
2398

2399
            TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, key.data(), key.size()));
5✔
2400
            TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
5✔
2401

2402
            std::vector<uint8_t> decrypted(plaintext.size());
5✔
2403

2404
            std::span<const uint8_t> ct_slicer(ciphertext);
5✔
2405
            std::span<uint8_t> pt_stuffer(decrypted);
5✔
2406

2407
            // Process data that is explicitly a multiple of the ideal
2408
            // granularity and therefore should be aligned with the cipher's
2409
            // internal block size.
2410
            for(size_t i = 0; i < pt_multiplier; ++i) {
30✔
2411
               size_t output_written = 42;
25✔
2412
               size_t input_consumed = 1337;
25✔
2413

2414
               auto ct_chunk = ct_slicer.first(ideal_granularity);
25✔
2415

2416
               // The existing implementation won't consume any bytes from the
2417
               // input if there is no space in the output buffer. Even when
2418
               // the cipher is a mode that won't produce any output until the
2419
               // entire message is processed. Hence, give it some dummy buffer.
2420
               auto pt_chunk = (requires_entire_message) ? std::span(dummy_buffer).first(ideal_granularity)
25✔
2421
                                                         : pt_stuffer.first(ideal_granularity);
2422

2423
               TEST_FFI_OK(botan_cipher_update,
25✔
2424
                           (cipher_decrypt,
2425
                            0 /* don't finalize */,
2426
                            pt_chunk.data(),
2427
                            pt_chunk.size(),
2428
                            &output_written,
2429
                            ct_chunk.data(),
2430
                            ct_chunk.size(),
2431
                            &input_consumed));
2432

2433
               result.test_sz_gt("some input consumed", input_consumed, 0);
25✔
2434
               result.test_sz_lte("at most, all input consumed", input_consumed, ct_chunk.size());
25✔
2435
               ct_slicer = ct_slicer.subspan(input_consumed);
25✔
2436

2437
               if(requires_entire_message) {
25✔
2438
                  result.test_sz_eq("no output produced", output_written, 0);
10✔
2439
               } else {
2440
                  result.test_sz_eq("all bytes produced", output_written, input_consumed);
15✔
2441
                  pt_stuffer = pt_stuffer.subspan(output_written);
15✔
2442
               }
2443
            }
2444

2445
            const size_t expected_final_size_dec = requires_entire_message ? plaintext.size() : pt_stuffer.size();
5✔
2446
            auto pt_chunk = pt_stuffer.first(expected_final_size_dec);
5✔
2447

2448
            size_t final_output_written_dec = 42;
5✔
2449
            size_t final_input_consumed_dec = 1337;
5✔
2450

2451
            TEST_FFI_OK(botan_cipher_update,
5✔
2452
                        (cipher_decrypt,
2453
                         BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2454
                         pt_chunk.data(),
2455
                         pt_chunk.size(),
2456
                         &final_output_written_dec,
2457
                         ct_slicer.data(),  // remaining bytes (typically 0)
2458
                         ct_slicer.size(),
2459
                         &final_input_consumed_dec));
2460

2461
            result.test_sz_eq(
5✔
2462
               "remaining bytes consumed in final (decrypt)", final_input_consumed_dec, ct_slicer.size());
2463
            result.test_sz_eq("bytes written in final (decrypt)", final_output_written_dec, expected_final_size_dec);
5✔
2464
            result.test_bin_eq("dummy buffer unchanged", dummy_buffer, dummy_buffer_reference);
5✔
2465

2466
            result.test_bin_eq("decrypted plaintext", decrypted, plaintext);
5✔
2467

2468
            TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
5✔
2469

2470
            merged_result.merge(result, true /* ignore names */);
5✔
2471
         }
5✔
2472
      }
1✔
2473
};
2474

2475
class FFI_StreamCipher_Test final : public FFI_Test {
1✔
2476
   public:
2477
      std::string name() const override { return "FFI stream ciphers"; }
1✔
2478

2479
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2480
         botan_cipher_t ctr;
1✔
2481

2482
         if(TEST_FFI_INIT(botan_cipher_init, (&ctr, "AES-128/CTR-BE", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
2483
            const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C");
1✔
2484
            const std::vector<uint8_t> nonce = Botan::hex_decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF");
1✔
2485
            const std::vector<uint8_t> pt = Botan::hex_decode(
1✔
2486
               "AE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710");
1✔
2487
            const std::vector<uint8_t> exp_ct = Botan::hex_decode(
1✔
2488
               "9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE");
1✔
2489

2490
            std::vector<uint8_t> ct(pt.size());
1✔
2491

2492
            size_t update_granularity = 0;
1✔
2493
            size_t ideal_granularity = 0;
1✔
2494

2495
            TEST_FFI_OK(botan_cipher_get_update_granularity, (ctr, &update_granularity));
1✔
2496
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (ctr, &ideal_granularity));
1✔
2497

2498
            result.test_sz_eq(
1✔
2499
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
2500

2501
            TEST_FFI_RC(0, botan_cipher_is_authenticated, (ctr));
1✔
2502

2503
            size_t input_consumed = 0;
1✔
2504
            size_t output_written = 0;
1✔
2505

2506
            TEST_FFI_OK(botan_cipher_set_key, (ctr, key.data(), key.size()));
1✔
2507
            TEST_FFI_OK(botan_cipher_start, (ctr, nonce.data(), nonce.size()));
1✔
2508

2509
            // Test partial updates...
2510
            TEST_FFI_OK(botan_cipher_update,
1✔
2511
                        (ctr, 0, ct.data(), ct.size(), &output_written, pt.data(), 5, &input_consumed));
2512

2513
            result.test_sz_eq("Expected output written", output_written, 5);
1✔
2514
            result.test_sz_eq("Expected input consumed", input_consumed, 5);
1✔
2515

2516
            TEST_FFI_OK(botan_cipher_update,
1✔
2517
                        (ctr, 0, &ct[5], ct.size() - 5, &output_written, &pt[5], pt.size() - 5, &input_consumed));
2518

2519
            result.test_sz_eq("Expected output written", output_written, ct.size() - 5);
1✔
2520
            result.test_sz_eq("Expected input consumed", input_consumed, pt.size() - 5);
1✔
2521
            result.test_bin_eq("AES-128/CTR ciphertext", ct, exp_ct);
1✔
2522

2523
            TEST_FFI_OK(botan_cipher_destroy, (ctr));
1✔
2524
         }
1✔
2525
      }
1✔
2526
};
2527

2528
class FFI_XOF_Test final : public FFI_Test {
1✔
2529
      std::string name() const override { return "FFI XOF"; }
1✔
2530

2531
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2532
         const char* input1 = "XOF input";
1✔
2533
         const char* input2 = "more XOF input";
1✔
2534
         const char* input3 = "additional XOF input";
1✔
2535
         const char* xof_name = "SHAKE-128";
1✔
2536

2537
         botan_xof_t xof1;
1✔
2538
         TEST_FFI_FAIL("unknown XOF", botan_xof_init, (&xof1, "SCHUETTEL-128", 0));
1✔
2539
         TEST_FFI_FAIL("invalid flags", botan_xof_init, (&xof1, "SHAKE-128", 42));
1✔
2540

2541
         if(!TEST_FFI_INIT(botan_xof_init, (&xof1, xof_name, 0))) {
1✔
2542
            return;
×
2543
         }
2544

2545
         std::array<char, 10> out_name{};
1✔
2546
         size_t out_name_len = 5;
1✔
2547
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_xof_name, (xof1, nullptr, &out_name_len));
1✔
2548
         result.test_sz_eq("valid XOF name length", out_name_len, out_name.size());
1✔
2549
         TEST_FFI_OK(botan_xof_name, (xof1, out_name.data(), &out_name_len));
1✔
2550

2551
         size_t out_block_size;
1✔
2552
         TEST_FFI_OK(botan_xof_block_size, (xof1, &out_block_size));
1✔
2553
         result.test_sz_eq("valid XOF block size", out_block_size, 168);
1✔
2554

2555
         result.test_rc("ready for input", botan_xof_accepts_input(xof1), 1);
1✔
2556
         TEST_FFI_OK(botan_xof_update, (xof1, reinterpret_cast<const uint8_t*>(input1), strlen(input1)));
1✔
2557
         result.test_rc("still ready for input", botan_xof_accepts_input(xof1), 1);
1✔
2558
         TEST_FFI_OK(botan_xof_update, (xof1, reinterpret_cast<const uint8_t*>(input2), strlen(input2)));
1✔
2559

2560
         botan_xof_t xof2;
1✔
2561
         TEST_FFI_OK(botan_xof_copy_state, (&xof2, xof1));
1✔
2562
         result.test_rc("copy still ready for input", botan_xof_accepts_input(xof2), 1);
1✔
2563

2564
         std::array<uint8_t, 16> out_bytes{};
1✔
2565
         TEST_FFI_OK(botan_xof_output, (xof1, nullptr, 0));
1✔
2566
         TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_xof_output, (xof1, nullptr, 1));
1✔
2567
         TEST_FFI_OK(botan_xof_output, (xof1, out_bytes.data(), out_bytes.size()));
1✔
2568

2569
         result.test_bin_eq("expected first output", out_bytes, "2E870A5FE35999A7B15F9F0BB5AC1689");
1✔
2570
         result.test_sz_ne("no more input", botan_xof_accepts_input(xof1), 1);
1✔
2571
         TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
2572
                     botan_xof_update,
2573
                     (xof1, reinterpret_cast<const uint8_t*>(input1), strlen(input1)));
2574

2575
         TEST_FFI_OK(botan_xof_output, (xof1, out_bytes.data(), out_bytes.size()));
1✔
2576
         result.test_bin_eq("expected second output", out_bytes, "E266E213DA0F2763AE29601AB8F9DEDC");
1✔
2577

2578
         TEST_FFI_OK(botan_xof_update, (xof2, reinterpret_cast<const uint8_t*>(input3), strlen(input3)));
1✔
2579
         TEST_FFI_OK(botan_xof_output, (xof2, out_bytes.data(), out_bytes.size()));
1✔
2580
         result.test_bin_eq(
1✔
2581
            "expected first output after additional input", out_bytes, "D9D5416188659DDC5C26FCF52E49A157");
2582

2583
         TEST_FFI_OK(botan_xof_clear, (xof1));
1✔
2584
         result.test_rc("again ready for input", botan_xof_accepts_input(xof1), 1);
1✔
2585
         TEST_FFI_OK(botan_xof_update, (xof1, reinterpret_cast<const uint8_t*>(input1), strlen(input1)));
1✔
2586
         TEST_FFI_OK(botan_xof_update, (xof1, reinterpret_cast<const uint8_t*>(input2), strlen(input2)));
1✔
2587
         TEST_FFI_OK(botan_xof_update, (xof1, reinterpret_cast<const uint8_t*>(input3), strlen(input3)));
1✔
2588
         TEST_FFI_OK(botan_xof_output, (xof1, out_bytes.data(), out_bytes.size()));
1✔
2589
         result.test_bin_eq("expected first output with full input", out_bytes, "D9D5416188659DDC5C26FCF52E49A157");
1✔
2590

2591
         TEST_FFI_OK(botan_xof_destroy, (xof1));
1✔
2592
         TEST_FFI_OK(botan_xof_destroy, (xof2));
1✔
2593
      }
2594
};
2595

2596
class FFI_HashFunction_Test final : public FFI_Test {
1✔
2597
   public:
2598
      std::string name() const override { return "FFI hash"; }
1✔
2599

2600
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2601
         const char* input_str = "ABC";
1✔
2602

2603
         botan_hash_t hash;
1✔
2604
         TEST_FFI_FAIL("invalid hash name", botan_hash_init, (&hash, "SHA-255", 0));
1✔
2605
         TEST_FFI_FAIL("invalid flags", botan_hash_init, (&hash, "SHA-256", 1));
1✔
2606

2607
         if(TEST_FFI_INIT(botan_hash_init, (&hash, "SHA-256", 0))) {
1✔
2608
            std::array<char, 10> namebuf{};
1✔
2609
            size_t name_len = 7;
1✔
2610
            TEST_FFI_FAIL("output buffer too short", botan_hash_name, (hash, namebuf.data(), &name_len));
1✔
2611
            result.test_sz_eq("name len", name_len, 8);
1✔
2612

2613
            name_len = namebuf.size();
1✔
2614
            if(TEST_FFI_OK(botan_hash_name, (hash, namebuf.data(), &name_len))) {
1✔
2615
               result.test_sz_eq("name len", name_len, 8);
1✔
2616
               result.test_str_eq("name", namebuf.data(), "SHA-256");
1✔
2617
            }
2618

2619
            size_t block_size;
1✔
2620
            if(TEST_FFI_OK(botan_hash_block_size, (hash, &block_size))) {
1✔
2621
               result.test_sz_eq("hash block size", block_size, 64);
1✔
2622
            }
2623

2624
            size_t security_level;
1✔
2625
            if(TEST_FFI_OK(botan_hash_security_level, (hash, &security_level))) {
1✔
2626
               result.test_sz_eq("hash security level", security_level, 128);
1✔
2627
            }
2628

2629
            size_t output_len;
1✔
2630
            if(TEST_FFI_OK(botan_hash_output_length, (hash, &output_len))) {
1✔
2631
               result.test_sz_eq("hash output length", output_len, 32);
1✔
2632

2633
               std::vector<uint8_t> outbuf(output_len);
1✔
2634

2635
               // Test that after clear or final the object can be reused
2636
               for(size_t r = 0; r != 2; ++r) {
3✔
2637
                  TEST_FFI_OK(botan_hash_update, (hash, reinterpret_cast<const uint8_t*>(input_str), 1));
2✔
2638
                  TEST_FFI_OK(botan_hash_clear, (hash));
2✔
2639

2640
                  TEST_FFI_OK(botan_hash_update,
2✔
2641
                              (hash, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
2642
                  TEST_FFI_OK(botan_hash_final, (hash, outbuf.data()));
2✔
2643

2644
                  result.test_bin_eq(
2✔
2645
                     "SHA-256 output", outbuf, "B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78");
2646
               }
2647

2648
               // Test botan_hash_copy_state
2649
               const char* msg = "message digest";
1✔
2650
               const char* expected = "F7846F55CF23E14EEBEAB5B4E1550CAD5B509E3348FBC4EFA3A1413D393CB650";
1✔
2651
               TEST_FFI_OK(botan_hash_clear, (hash));
1✔
2652
               TEST_FFI_OK(botan_hash_update, (hash, reinterpret_cast<const uint8_t*>(&msg[0]), 1));
1✔
2653
               botan_hash_t fork;
1✔
2654
               if(TEST_FFI_OK(botan_hash_copy_state, (&fork, hash))) {
1✔
2655
                  TEST_FFI_OK(botan_hash_update,
1✔
2656
                              (fork, reinterpret_cast<const uint8_t*>(&msg[1]), std::strlen(msg) - 2));
2657

2658
                  TEST_FFI_OK(botan_hash_update,
1✔
2659
                              (hash, reinterpret_cast<const uint8_t*>(&msg[1]), std::strlen(msg) - 1));
2660
                  TEST_FFI_OK(botan_hash_final, (hash, outbuf.data()));
1✔
2661
                  result.test_bin_eq("hashing split", outbuf, expected);
1✔
2662

2663
                  TEST_FFI_OK(botan_hash_update,
1✔
2664
                              (fork, reinterpret_cast<const uint8_t*>(&msg[std::strlen(msg) - 1]), 1));
2665
                  TEST_FFI_OK(botan_hash_final, (fork, outbuf.data()));
1✔
2666
                  result.test_bin_eq("hashing split", outbuf, expected);
1✔
2667

2668
                  TEST_FFI_OK(botan_hash_destroy, (fork));
1✔
2669
               }
2670
            }
1✔
2671

2672
            TEST_FFI_OK(botan_hash_destroy, (hash));
1✔
2673
         }
2674
      }
1✔
2675
};
2676

2677
class FFI_MAC_Test final : public FFI_Test {
1✔
2678
   public:
2679
      std::string name() const override { return "FFI MAC"; }
1✔
2680

2681
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2682
         const char* input_str = "ABC";
1✔
2683

2684
         // MAC test
2685
         botan_mac_t mac;
1✔
2686
         TEST_FFI_FAIL("bad flag", botan_mac_init, (&mac, "HMAC(SHA-256)", 1));
1✔
2687
         TEST_FFI_FAIL("bad name", botan_mac_init, (&mac, "HMAC(SHA-259)", 0));
1✔
2688

2689
         if(TEST_FFI_INIT(botan_mac_init, (&mac, "HMAC(SHA-256)", 0))) {
1✔
2690
            std::array<char, 16> namebuf{};
1✔
2691
            size_t name_len = 13;
1✔
2692
            TEST_FFI_FAIL("output buffer too short", botan_mac_name, (mac, namebuf.data(), &name_len));
1✔
2693
            result.test_sz_eq("name len", name_len, 14);
1✔
2694

2695
            name_len = namebuf.size();
1✔
2696
            if(TEST_FFI_OK(botan_mac_name, (mac, namebuf.data(), &name_len))) {
1✔
2697
               result.test_sz_eq("name len", name_len, 14);
1✔
2698
               result.test_str_eq("name", namebuf.data(), "HMAC(SHA-256)");
1✔
2699
            }
2700

2701
            size_t min_keylen = 0;
1✔
2702
            size_t max_keylen = 0;
1✔
2703
            size_t mod_keylen = 0;
1✔
2704
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, nullptr, nullptr));
1✔
2705
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, &min_keylen, nullptr, nullptr));
1✔
2706
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, &max_keylen, nullptr));
1✔
2707
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, nullptr, &mod_keylen));
1✔
2708

2709
            result.test_sz_eq("Expected min keylen", min_keylen, 0);
1✔
2710
            result.test_sz_eq("Expected max keylen", max_keylen, 8192);
1✔
2711
            result.test_sz_eq("Expected mod keylen", mod_keylen, 1);
1✔
2712

2713
            size_t output_len;
1✔
2714
            if(TEST_FFI_OK(botan_mac_output_length, (mac, &output_len))) {
1✔
2715
               result.test_sz_eq("MAC output length", output_len, 32);
1✔
2716

2717
               const uint8_t mac_key[] = {0xAA, 0xBB, 0xCC, 0xDD};
1✔
2718
               std::vector<uint8_t> outbuf(output_len);
1✔
2719

2720
               // Test that after clear or final the object can be reused
2721
               for(size_t r = 0; r != 2; ++r) {
3✔
2722
                  TEST_FFI_OK(botan_mac_set_key, (mac, mac_key, sizeof(mac_key)));
2✔
2723
                  TEST_FFI_OK(botan_mac_update,
2✔
2724
                              (mac, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
2725
                  TEST_FFI_OK(botan_mac_clear, (mac));
2✔
2726

2727
                  TEST_FFI_OK(botan_mac_set_key, (mac, mac_key, sizeof(mac_key)));
2✔
2728
                  TEST_FFI_OK(botan_mac_update,
2✔
2729
                              (mac, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
2730
                  TEST_FFI_OK(botan_mac_final, (mac, outbuf.data()));
2✔
2731

2732
                  result.test_bin_eq(
2✔
2733
                     "HMAC output", outbuf, "1A82EEA984BC4A7285617CC0D05F1FE1D6C96675924A81BC965EE8FF7B0697A7");
2734
               }
2735
            }
1✔
2736

2737
            TEST_FFI_OK(botan_mac_destroy, (mac));
1✔
2738
         }
2739
      }
1✔
2740
};
2741

2742
class FFI_Scrypt_Test final : public FFI_Test {
1✔
2743
   public:
2744
      std::string name() const override { return "FFI Scrypt"; }
1✔
2745

2746
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2747
         std::vector<uint8_t> output(24);
1✔
2748
         const uint8_t salt[8] = {0};
1✔
2749
         const char* pass = "password";
1✔
2750

2751
         if(TEST_FFI_INIT(botan_scrypt, (output.data(), output.size(), pass, salt, sizeof(salt), 8, 1, 1))) {
1✔
2752
            result.test_bin_eq("scrypt output", output, "4B9B888D695288E002CC4F9D90808A4D296A45CE4471AFBB");
1✔
2753

2754
            size_t N;
1✔
2755
            size_t r;
1✔
2756
            size_t p;
1✔
2757
            TEST_FFI_OK(botan_pwdhash_timed,
1✔
2758
                        ("Scrypt", 50, &r, &p, &N, output.data(), output.size(), "bunny", 5, salt, sizeof(salt)));
2759

2760
            std::vector<uint8_t> cmp(output.size());
1✔
2761

2762
            TEST_FFI_OK(botan_pwdhash, ("Scrypt", N, r, p, cmp.data(), cmp.size(), "bunny", 5, salt, sizeof(salt)));
1✔
2763
            result.test_bin_eq("recomputed scrypt", cmp, output);
1✔
2764
         }
1✔
2765
      }
1✔
2766
};
2767

2768
class FFI_KDF_Test final : public FFI_Test {
1✔
2769
   public:
2770
      std::string name() const override { return "FFI KDF"; }
1✔
2771

2772
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2773
         std::vector<uint8_t> outbuf;
1✔
2774

2775
         const std::string passphrase = "ltexmfeyylmlbrsyikaw";
1✔
2776

2777
         const std::vector<uint8_t> pbkdf_salt = Botan::hex_decode("ED1F39A0A7F3889AAF7E60743B3BC1CC2C738E60");
1✔
2778
         const size_t pbkdf_out_len = 10;
1✔
2779
         const size_t pbkdf_iterations = 1000;
1✔
2780

2781
         outbuf.resize(pbkdf_out_len);
1✔
2782

2783
         if(TEST_FFI_INIT(botan_pbkdf,
1✔
2784
                          ("PBKDF2(SHA-1)",
2785
                           outbuf.data(),
2786
                           outbuf.size(),
2787
                           passphrase.c_str(),
2788
                           pbkdf_salt.data(),
2789
                           pbkdf_salt.size(),
2790
                           pbkdf_iterations))) {
2791
            result.test_bin_eq("PBKDF output", outbuf, "027AFADD48F4BE8DCC4F");
1✔
2792

2793
            size_t iters_10ms;
1✔
2794
            size_t iters_100ms;
1✔
2795

2796
            TEST_FFI_OK(botan_pbkdf_timed,
1✔
2797
                        ("PBKDF2(SHA-1)",
2798
                         outbuf.data(),
2799
                         outbuf.size(),
2800
                         passphrase.c_str(),
2801
                         pbkdf_salt.data(),
2802
                         pbkdf_salt.size(),
2803
                         10,
2804
                         &iters_10ms));
2805
            TEST_FFI_OK(botan_pbkdf_timed,
1✔
2806
                        ("PBKDF2(SHA-1)",
2807
                         outbuf.data(),
2808
                         outbuf.size(),
2809
                         passphrase.c_str(),
2810
                         pbkdf_salt.data(),
2811
                         pbkdf_salt.size(),
2812
                         100,
2813
                         &iters_100ms));
2814

2815
            result.test_note("PBKDF timed 10 ms " + std::to_string(iters_10ms) + " iterations " + "100 ms " +
6✔
2816
                             std::to_string(iters_100ms) + " iterations");
4✔
2817
         }
2818

2819
         const std::vector<uint8_t> kdf_secret = Botan::hex_decode("92167440112E");
1✔
2820
         const std::vector<uint8_t> kdf_salt = Botan::hex_decode("45A9BEDED69163123D0348F5185F61ABFB1BF18D6AEA454F");
1✔
2821
         const size_t kdf_out_len = 18;
1✔
2822
         outbuf.resize(kdf_out_len);
1✔
2823

2824
         if(TEST_FFI_INIT(botan_kdf,
1✔
2825
                          ("KDF2(SHA-1)",
2826
                           outbuf.data(),
2827
                           outbuf.size(),
2828
                           kdf_secret.data(),
2829
                           kdf_secret.size(),
2830
                           kdf_salt.data(),
2831
                           kdf_salt.size(),
2832
                           nullptr,
2833
                           0))) {
2834
            result.test_bin_eq("KDF output", outbuf, "3A5DC9AA1C872B4744515AC2702D6396FC2A");
1✔
2835
         }
2836

2837
         size_t out_len = 64;
1✔
2838
         std::string outstr;
1✔
2839
         outstr.resize(out_len);
1✔
2840

2841
         const int rc =
1✔
2842
            botan_bcrypt_generate(reinterpret_cast<uint8_t*>(outstr.data()), &out_len, passphrase.c_str(), rng, 4, 0);
1✔
2843

2844
         if(rc == 0) {
1✔
2845
            result.test_sz_eq("bcrypt output size", out_len, 61);
1✔
2846

2847
            TEST_FFI_OK(botan_bcrypt_is_valid, (passphrase.c_str(), outstr.data()));
1✔
2848
            TEST_FFI_FAIL("bad password", botan_bcrypt_is_valid, ("nope", outstr.data()));
1✔
2849
         }
2850
      }
1✔
2851
};
2852

2853
class FFI_Blockcipher_Test final : public FFI_Test {
1✔
2854
   public:
2855
      std::string name() const override { return "FFI block ciphers"; }
1✔
2856

2857
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2858
         botan_block_cipher_t cipher;
1✔
2859

2860
         if(TEST_FFI_INIT(botan_block_cipher_init, (&cipher, "AES-128"))) {
1✔
2861
            std::array<char, 10> namebuf{};
1✔
2862
            size_t name_len = 7;
1✔
2863
            TEST_FFI_FAIL("output buffer too short", botan_block_cipher_name, (cipher, namebuf.data(), &name_len));
1✔
2864
            result.test_sz_eq("name len", name_len, 8);
1✔
2865

2866
            name_len = namebuf.size();
1✔
2867
            if(TEST_FFI_OK(botan_block_cipher_name, (cipher, namebuf.data(), &name_len))) {
1✔
2868
               result.test_sz_eq("name len", name_len, 8);
1✔
2869
               result.test_str_eq("name", namebuf.data(), "AES-128");
1✔
2870
            }
2871

2872
            const std::vector<uint8_t> zero16(16, 0);
1✔
2873
            std::vector<uint8_t> block(16, 0);
1✔
2874

2875
            TEST_FFI_OK(botan_block_cipher_clear, (cipher));
1✔
2876

2877
            TEST_FFI_RC(
1✔
2878
               BOTAN_FFI_ERROR_KEY_NOT_SET, botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
2879
            TEST_FFI_RC(
1✔
2880
               BOTAN_FFI_ERROR_KEY_NOT_SET, botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
2881

2882
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_block_cipher_encrypt_blocks, (cipher, nullptr, nullptr, 0));
1✔
2883
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_block_cipher_decrypt_blocks, (cipher, nullptr, nullptr, 0));
1✔
2884

2885
            TEST_FFI_RC(16, botan_block_cipher_block_size, (cipher));
1✔
2886

2887
            size_t min_keylen = 0;
1✔
2888
            size_t max_keylen = 0;
1✔
2889
            size_t mod_keylen = 0;
1✔
2890
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, nullptr, nullptr));
1✔
2891
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, &min_keylen, nullptr, nullptr));
1✔
2892
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, &max_keylen, nullptr));
1✔
2893
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, nullptr, &mod_keylen));
1✔
2894

2895
            result.test_sz_eq("Expected min keylen", min_keylen, 16);
1✔
2896
            result.test_sz_eq("Expected max keylen", max_keylen, 16);
1✔
2897
            result.test_sz_eq("Expected mod keylen", mod_keylen, 1);
1✔
2898

2899
            TEST_FFI_OK(botan_block_cipher_set_key, (cipher, zero16.data(), zero16.size()));
1✔
2900

2901
            TEST_FFI_OK(botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
2902
            result.test_bin_eq("AES-128 encryption works", block, "66E94BD4EF8A2C3B884CFA59CA342B2E");
1✔
2903

2904
            TEST_FFI_OK(botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
2905
            result.test_bin_eq("AES-128 encryption works", block, "F795BD4A52E29ED713D313FA20E98DBC");
1✔
2906

2907
            TEST_FFI_OK(botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
2908
            result.test_bin_eq("AES-128 decryption works", block, "66E94BD4EF8A2C3B884CFA59CA342B2E");
1✔
2909

2910
            TEST_FFI_OK(botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
2911
            result.test_bin_eq("AES-128 decryption works", block, "00000000000000000000000000000000");
1✔
2912

2913
            TEST_FFI_OK(botan_block_cipher_clear, (cipher));
1✔
2914
            botan_block_cipher_destroy(cipher);
1✔
2915
         }
1✔
2916
      }
1✔
2917
};
2918

2919
class FFI_ErrorHandling_Test final : public FFI_Test {
1✔
2920
   public:
2921
      std::string name() const override { return "FFI error handling"; }
1✔
2922

2923
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2924
         // delete of null is ok/ignored
2925
         TEST_FFI_RC(0, botan_hash_destroy, (nullptr));
1✔
2926

2927
   #if !defined(BOTAN_HAS_SANITIZER_UNDEFINED)
2928
         // Confirm that botan_x_destroy checks the argument type
2929
         botan_mp_t mp;
1✔
2930
         botan_mp_init(&mp);
1✔
2931
         TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT, botan_hash_destroy, (reinterpret_cast<botan_hash_t>(mp)));
1✔
2932
         TEST_FFI_RC(0, botan_mp_destroy, (mp));
1✔
2933
   #endif
2934

2935
         std::set<std::string> errors;
1✔
2936
         for(int i = -100; i != 50; ++i) {
151✔
2937
            const char* err = botan_error_description(i);
150✔
2938
            result.test_is_true("Never a null pointer", err != nullptr);
150✔
2939

2940
            if(err != nullptr) {
150✔
2941
               const std::string s(err);
150✔
2942

2943
               if(s != "Unknown error") {
150✔
2944
                  result.test_is_true("No duplicate messages", !errors.contains(s));
22✔
2945
                  errors.insert(s);
22✔
2946
               }
2947
            }
150✔
2948
         }
2949
      }
1✔
2950
};
2951

2952
class FFI_Base64_Test final : public FFI_Test {
1✔
2953
   public:
2954
      std::string name() const override { return "FFI base64"; }
1✔
2955

2956
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2957
         const uint8_t bin[9] = {0x16, 0x8a, 0x1f, 0x06, 0xe9, 0xe7, 0xcb, 0xdd, 0x34};
1✔
2958
         char out_buf[1024] = {0};
1✔
2959

2960
         size_t out_len = sizeof(out_buf);
1✔
2961
         TEST_FFI_OK(botan_base64_encode, (bin, sizeof(bin), out_buf, &out_len));
1✔
2962

2963
         result.test_str_eq("encoded string", out_buf, "FoofBunny900");
1✔
2964

2965
         out_len -= 1;
1✔
2966
         TEST_FFI_RC(
1✔
2967
            BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_base64_encode, (bin, sizeof(bin), out_buf, &out_len));
2968

2969
         const char* base64 = "U3VjaCBiYXNlNjQgd293IQ==";
1✔
2970
         uint8_t out_bin[1024] = {0};
1✔
2971

2972
         out_len = 3;
1✔
2973
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
2974
                     botan_base64_decode,
2975
                     (base64, strlen(base64), out_bin, &out_len));
2976

2977
         result.test_sz_eq("output length", out_len, 18);
1✔
2978

2979
         out_len = sizeof(out_bin);
1✔
2980
         TEST_FFI_OK(botan_base64_decode, (base64, strlen(base64), out_bin, &out_len));
1✔
2981

2982
         result.test_str_eq(
1✔
2983
            "decoded string", std::string(reinterpret_cast<const char*>(out_bin), out_len), "Such base64 wow!");
1✔
2984
      }
1✔
2985
};
2986

2987
class FFI_Hex_Test final : public FFI_Test {
1✔
2988
   public:
2989
      std::string name() const override { return "FFI hex"; }
1✔
2990

2991
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2992
         const uint8_t bin[4] = {0xDE, 0xAD, 0xBE, 0xEF};
1✔
2993
         char hex_buf[16] = {0};
1✔
2994

2995
         TEST_FFI_OK(botan_hex_encode, (bin, sizeof(bin), hex_buf, 0));
1✔
2996

2997
         result.test_str_eq("encoded string", hex_buf, "DEADBEEF");
1✔
2998

2999
         const char* hex = "67657420796572206A756D626F20736872696D70";
1✔
3000
         uint8_t out_bin[1024] = {0};
1✔
3001
         size_t out_len = 5;
1✔
3002

3003
         TEST_FFI_RC(
1✔
3004
            BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_hex_decode, (hex, strlen(hex), out_bin, &out_len));
3005

3006
         out_len = sizeof(out_bin);
1✔
3007
         TEST_FFI_OK(botan_hex_decode, (hex, strlen(hex), out_bin, &out_len));
1✔
3008

3009
         result.test_str_eq(
1✔
3010
            "decoded string", std::string(reinterpret_cast<const char*>(out_bin), out_len), "get yer jumbo shrimp");
1✔
3011
      }
1✔
3012
};
3013

3014
class FFI_MP_Test final : public FFI_Test {
1✔
3015
   public:
3016
      std::string name() const override { return "FFI MP"; }
1✔
3017

3018
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3019
         char str_buf[1024] = {0};
1✔
3020
         size_t str_len = 0;
1✔
3021

3022
         botan_mp_t x;
1✔
3023
         botan_mp_init(&x);
1✔
3024
         TEST_FFI_RC(0, botan_mp_is_odd, (x));
1✔
3025
         TEST_FFI_RC(1, botan_mp_is_even, (x));
1✔
3026
         TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
3027
         TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
3028
         TEST_FFI_RC(1, botan_mp_is_zero, (x));
1✔
3029
         botan_mp_destroy(x);
1✔
3030

3031
         botan_mp_init(&x);
1✔
3032
         size_t bn_bytes = 0;
1✔
3033
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
3034
         result.test_sz_eq("Expected size for MP 0", bn_bytes, 0);
1✔
3035

3036
         botan_mp_set_from_int(x, 5);
1✔
3037
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
3038
         result.test_sz_eq("Expected size for MP 5", bn_bytes, 1);
1✔
3039

3040
         botan_mp_add_u32(x, x, 75);
1✔
3041
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
3042
         result.test_sz_eq("Expected size for MP 80", bn_bytes, 1);
1✔
3043

3044
         str_len = sizeof(str_buf);
1✔
3045
         TEST_FFI_OK(botan_mp_to_str, (x, 10, str_buf, &str_len));
1✔
3046
         result.test_str_eq("botan_mp_add", std::string(str_buf), "80");
1✔
3047

3048
         botan_mp_sub_u32(x, x, 80);
1✔
3049
         TEST_FFI_RC(1, botan_mp_is_zero, (x));
1✔
3050
         botan_mp_add_u32(x, x, 259);
1✔
3051
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
3052
         result.test_sz_eq("Expected size for MP 259", bn_bytes, 2);
1✔
3053

3054
         str_len = sizeof(str_buf);
1✔
3055
         TEST_FFI_OK(botan_mp_to_str, (x, 10, str_buf, &str_len));
1✔
3056
         result.test_str_eq("botan_mp_add", std::string(str_buf), "259");
1✔
3057

3058
         TEST_FFI_RC(1, botan_mp_is_odd, (x));
1✔
3059
         TEST_FFI_RC(0, botan_mp_is_even, (x));
1✔
3060
         TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
3061
         TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
3062
         TEST_FFI_RC(0, botan_mp_is_zero, (x));
1✔
3063

3064
         {
1✔
3065
            botan_mp_t zero;
1✔
3066
            botan_mp_init(&zero);
1✔
3067
            int cmp;
1✔
3068
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, zero));
1✔
3069
            result.test_is_true("bigint_mp_cmp(+, 0)", cmp == 1);
1✔
3070

3071
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, x));
1✔
3072
            result.test_is_true("bigint_mp_cmp(0, +)", cmp == -1);
1✔
3073

3074
            TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
3075
            TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
3076
            TEST_FFI_OK(botan_mp_flip_sign, (x));
1✔
3077
            TEST_FFI_RC(1, botan_mp_is_negative, (x));
1✔
3078
            TEST_FFI_RC(0, botan_mp_is_positive, (x));
1✔
3079

3080
            // test no negative zero
3081
            TEST_FFI_RC(0, botan_mp_is_negative, (zero));
1✔
3082
            TEST_FFI_RC(1, botan_mp_is_positive, (zero));
1✔
3083
            TEST_FFI_OK(botan_mp_flip_sign, (zero));
1✔
3084
            TEST_FFI_RC(0, botan_mp_is_negative, (zero));
1✔
3085
            TEST_FFI_RC(1, botan_mp_is_positive, (zero));
1✔
3086

3087
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, zero));
1✔
3088
            result.test_is_true("bigint_mp_cmp(-, 0)", cmp == -1);
1✔
3089

3090
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, x));
1✔
3091
            result.test_is_true("bigint_mp_cmp(0, -)", cmp == 1);
1✔
3092

3093
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, zero));
1✔
3094
            result.test_is_true("bigint_mp_cmp(0, 0)", cmp == 0);
1✔
3095

3096
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, x));
1✔
3097
            result.test_is_true("bigint_mp_cmp(x, x)", cmp == 0);
1✔
3098

3099
            TEST_FFI_OK(botan_mp_flip_sign, (x));
1✔
3100

3101
            // Regression test for bug reported by @hgarrereyn
3102
            // See: GH #5128
3103
            botan_mp_t out_shift;
1✔
3104
            TEST_FFI_OK(botan_mp_init, (&out_shift));
1✔
3105
            TEST_FFI_OK(botan_mp_lshift, (out_shift, zero, 0));
1✔
3106

3107
            botan_mp_destroy(zero);
1✔
3108
            botan_mp_destroy(out_shift);
1✔
3109
         }
3110

3111
         size_t x_bits = 0;
1✔
3112
         TEST_FFI_OK(botan_mp_num_bits, (x, &x_bits));
1✔
3113
         result.test_sz_eq("botan_mp_num_bits", x_bits, 9);
1✔
3114

3115
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
3116
         result.test_str_eq("botan_mp_to_hex", std::string(str_buf), "0x0103");
1✔
3117

3118
         ViewStringSink hex_sink;
1✔
3119
         TEST_FFI_OK(botan_mp_view_hex, (x, hex_sink.delegate(), hex_sink.callback()));
1✔
3120
         result.test_str_eq("botan_mp_view_hex", hex_sink.get(), "0x0103");
1✔
3121

3122
         ViewStringSink str_sink;
1✔
3123
         TEST_FFI_OK(botan_mp_view_str, (x, 10, str_sink.delegate(), str_sink.callback()));
1✔
3124
         result.test_str_eq("botan_mp_view_str", str_sink.get(), "259");
1✔
3125

3126
         ViewBytesSink bin_sink;
1✔
3127
         TEST_FFI_OK(botan_mp_view_bin, (x, bin_sink.delegate(), bin_sink.callback()));
1✔
3128
         result.test_bin_eq("botan_mp_view_str", bin_sink.get(), "0103");
1✔
3129

3130
         uint32_t x_32;
1✔
3131
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
3132
         result.test_sz_eq("botan_mp_to_uint32", size_t(x_32), size_t(0x103));
1✔
3133

3134
         TEST_FFI_RC(1, botan_mp_get_bit, (x, 1));
1✔
3135
         TEST_FFI_RC(0, botan_mp_get_bit, (x, 87));
1✔
3136
         TEST_FFI_OK(botan_mp_set_bit, (x, 87));
1✔
3137
         TEST_FFI_RC(1, botan_mp_get_bit, (x, 87));
1✔
3138
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
3139
         result.test_str_eq("botan_mp_set_bit", std::string(str_buf), "0x8000000000000000000103");
1✔
3140

3141
         TEST_FFI_OK(botan_mp_clear_bit, (x, 87));
1✔
3142
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
3143
         result.test_str_eq("botan_mp_set_bit", std::string(str_buf), "0x0103");
1✔
3144

3145
         botan_mp_t y;
1✔
3146
         TEST_FFI_OK(botan_mp_init, (&y));
1✔
3147
         TEST_FFI_OK(botan_mp_set_from_int, (y, 0x1234567));
1✔
3148

3149
         botan_mp_t r;
1✔
3150
         botan_mp_init(&r);
1✔
3151

3152
         TEST_FFI_OK(botan_mp_add, (r, x, y));
1✔
3153
         str_len = sizeof(str_buf);
1✔
3154
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3155
         result.test_str_eq("botan_mp_add", std::string(str_buf), "19089002");
1✔
3156

3157
         TEST_FFI_OK(botan_mp_mul, (r, x, y));
1✔
3158
         str_len = sizeof(str_buf);
1✔
3159
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3160
         result.test_str_eq("botan_mp_mul", std::string(str_buf), "4943984437");
1✔
3161
         TEST_FFI_RC(0, botan_mp_is_negative, (r));
1✔
3162

3163
         botan_mp_t q;
1✔
3164
         botan_mp_init(&q);
1✔
3165
         TEST_FFI_OK(botan_mp_div, (q, r, y, x));
1✔
3166

3167
         str_len = sizeof(str_buf);
1✔
3168
         TEST_FFI_OK(botan_mp_to_str, (q, 10, str_buf, &str_len));
1✔
3169
         result.test_str_eq("botan_mp_div_q", std::string(str_buf), "73701");
1✔
3170

3171
         str_len = sizeof(str_buf);
1✔
3172
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3173
         result.test_str_eq("botan_mp_div_r", std::string(str_buf), "184");
1✔
3174

3175
         TEST_FFI_OK(botan_mp_set_from_str, (y, "4943984437"));
1✔
3176
         TEST_FFI_OK(botan_mp_sub, (r, x, y));
1✔
3177
         str_len = sizeof(str_buf);
1✔
3178
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3179
         result.test_str_eq("botan_mp_sub", std::string(str_buf), "-4943984178");
1✔
3180
         TEST_FFI_RC(1, botan_mp_is_negative, (r));
1✔
3181

3182
         TEST_FFI_OK(botan_mp_lshift, (r, x, 39));
1✔
3183
         str_len = sizeof(str_buf);
1✔
3184
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3185
         result.test_str_eq("botan_mp_lshift", std::string(str_buf), "142386755796992");
1✔
3186

3187
         TEST_FFI_OK(botan_mp_rshift, (r, r, 3));
1✔
3188
         str_len = sizeof(str_buf);
1✔
3189
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3190
         result.test_str_eq("botan_mp_rshift", std::string(str_buf), "17798344474624");
1✔
3191

3192
         TEST_FFI_OK(botan_mp_gcd, (r, x, y));
1✔
3193
         str_len = sizeof(str_buf);
1✔
3194
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3195
         result.test_str_eq("botan_mp_gcd", std::string(str_buf), "259");
1✔
3196

3197
         botan_mp_t p;
1✔
3198
         botan_mp_init(&p);
1✔
3199
         const uint8_t M127[] = {
1✔
3200
            0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
3201
         TEST_FFI_OK(botan_mp_from_bin, (p, M127, sizeof(M127)));
1✔
3202
         TEST_FFI_RC(1, botan_mp_is_prime, (p, rng, 64));
1✔
3203

3204
         size_t p_bits = 0;
1✔
3205
         TEST_FFI_OK(botan_mp_num_bits, (p, &p_bits));
1✔
3206
         result.test_sz_eq("botan_mp_num_bits", p_bits, 127);
1✔
3207

3208
         TEST_FFI_OK(botan_mp_mod_inverse, (r, x, p));
1✔
3209
         str_len = sizeof(str_buf);
1✔
3210
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3211
         result.test_str_eq("botan_mp_mod_inverse", std::string(str_buf), "40728777507911553541948312086427855425");
1✔
3212

3213
         TEST_FFI_OK(botan_mp_powmod, (r, x, r, p));
1✔
3214
         str_len = sizeof(str_buf);
1✔
3215
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3216
         result.test_str_eq("botan_mp_powmod", std::string(str_buf), "40550417419160441638948180641668117560");
1✔
3217

3218
         TEST_FFI_OK(botan_mp_num_bytes, (r, &bn_bytes));
1✔
3219
         result.test_sz_eq("botan_mp_num_bytes", bn_bytes, 16);
1✔
3220

3221
         std::vector<uint8_t> bn_buf;
1✔
3222
         bn_buf.resize(bn_bytes);
1✔
3223
         botan_mp_to_bin(r, bn_buf.data());
1✔
3224
         result.test_bin_eq("botan_mp_to_bin", bn_buf, "1E81B9EFE0BE1902F6D03F9F5E5FB438");
1✔
3225

3226
         TEST_FFI_OK(botan_mp_set_from_mp, (y, r));
1✔
3227
         TEST_FFI_OK(botan_mp_mod_mul, (r, x, y, p));
1✔
3228
         str_len = sizeof(str_buf);
1✔
3229
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3230
         result.test_str_eq("botan_mp_mod_mul", std::string(str_buf), "123945920473931248854653259523111998693");
1✔
3231

3232
         str_len = 0;
1✔
3233
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
3234

3235
         size_t x_bytes;
1✔
3236
         botan_mp_rand_bits(x, rng, 512);
1✔
3237
         TEST_FFI_OK(botan_mp_num_bytes, (x, &x_bytes));
1✔
3238
         result.test_sz_lte("botan_mp_num_bytes", x_bytes, 512 / 8);
1✔
3239

3240
         TEST_FFI_OK(botan_mp_set_from_radix_str, (x, "909A", 16));
1✔
3241
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
3242
         result.test_u32_eq("botan_mp_set_from_radix_str(16)", x_32, 0x909A);
1✔
3243

3244
         TEST_FFI_OK(botan_mp_set_from_radix_str, (x, "9098135", 10));
1✔
3245
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
3246
         result.test_u32_eq("botan_mp_set_from_radix_str(10)", x_32, 9098135);
1✔
3247

3248
         botan_mp_destroy(p);
1✔
3249
         botan_mp_destroy(x);
1✔
3250
         botan_mp_destroy(y);
1✔
3251
         botan_mp_destroy(r);
1✔
3252
         botan_mp_destroy(q);
1✔
3253
      }
1✔
3254
};
3255

3256
class FFI_FPE_Test final : public FFI_Test {
1✔
3257
   public:
3258
      std::string name() const override { return "FFI FPE"; }
1✔
3259

3260
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
3261
         const uint8_t key[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
1✔
3262

3263
         botan_mp_t n;
1✔
3264
         botan_mp_init(&n);
1✔
3265
         botan_mp_set_from_str(n, "1000000000");
1✔
3266

3267
         botan_fpe_t fpe;
1✔
3268
         if(!TEST_FFI_INIT(botan_fpe_fe1_init, (&fpe, n, key, sizeof(key), 5, 0))) {
1✔
3269
            botan_mp_destroy(n);
×
3270
            return;
×
3271
         }
3272

3273
         botan_mp_t x;
1✔
3274
         botan_mp_init(&x);
1✔
3275
         botan_mp_set_from_str(x, "178051120");
1✔
3276

3277
         TEST_FFI_OK(botan_fpe_encrypt, (fpe, x, nullptr, 0));
1✔
3278

3279
         uint32_t xval = 0;
1✔
3280
         TEST_FFI_OK(botan_mp_to_uint32, (x, &xval));
1✔
3281
         result.test_sz_eq("Expected FPE ciphertext", xval, size_t(605648666));
1✔
3282

3283
         TEST_FFI_OK(botan_fpe_encrypt, (fpe, x, nullptr, 0));
1✔
3284
         TEST_FFI_OK(botan_fpe_decrypt, (fpe, x, nullptr, 0));
1✔
3285
         TEST_FFI_OK(botan_fpe_decrypt, (fpe, x, nullptr, 0));
1✔
3286

3287
         TEST_FFI_OK(botan_mp_to_uint32, (x, &xval));
1✔
3288
         result.test_sz_eq("FPE round trip", xval, size_t(178051120));
1✔
3289

3290
         TEST_FFI_OK(botan_fpe_destroy, (fpe));
1✔
3291
         TEST_FFI_OK(botan_mp_destroy, (x));
1✔
3292
         TEST_FFI_OK(botan_mp_destroy, (n));
1✔
3293
      }
3294
};
3295

3296
class FFI_TOTP_Test final : public FFI_Test {
1✔
3297
   public:
3298
      std::string name() const override { return "FFI TOTP"; }
1✔
3299

3300
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
3301
         const std::vector<uint8_t> key = Botan::hex_decode("3132333435363738393031323334353637383930");
1✔
3302
         const size_t digits = 8;
1✔
3303
         const size_t timestep = 30;
1✔
3304
         botan_totp_t totp;
1✔
3305

3306
         if(!TEST_FFI_INIT(botan_totp_init, (&totp, key.data(), key.size(), "SHA-1", digits, timestep))) {
1✔
3307
            return;
×
3308
         }
3309

3310
         uint32_t code;
1✔
3311

3312
         const uint64_t timestamp = 1000216740;
1✔
3313
         TEST_FFI_OK(botan_totp_generate, (totp, &code, timestamp));
1✔
3314
         result.test_u32_eq("TOTP code", code, 34097298);
1✔
3315

3316
         TEST_FFI_OK(botan_totp_generate, (totp, &code, 1111111109));
1✔
3317
         result.test_u32_eq("TOTP code 2", code, 7081804);
1✔
3318

3319
         TEST_FFI_OK(botan_totp_check, (totp, 34097298, timestamp + 60, 2));
1✔
3320
         TEST_FFI_RC(1, botan_totp_check, (totp, 34097298, timestamp + 61, 1));
1✔
3321

3322
         TEST_FFI_OK(botan_totp_destroy, (totp));
1✔
3323
      }
1✔
3324
};
3325

3326
class FFI_HOTP_Test final : public FFI_Test {
1✔
3327
   public:
3328
      std::string name() const override { return "FFI HOTP"; }
1✔
3329

3330
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
3331
         const std::vector<uint8_t> key = Botan::hex_decode("3132333435363738393031323334353637383930");
1✔
3332
         const size_t digits = 6;
1✔
3333

3334
         botan_hotp_t hotp;
1✔
3335
         uint32_t hotp_val;
1✔
3336

3337
         if(!TEST_FFI_INIT(botan_hotp_init, (&hotp, key.data(), key.size(), "SHA-1", digits))) {
1✔
3338
            return;
×
3339
         }
3340

3341
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 0));
1✔
3342
         result.test_u32_eq("Valid value for counter 0", hotp_val, 755224);
1✔
3343
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 1));
1✔
3344
         result.test_u32_eq("Valid value for counter 0", hotp_val, 287082);
1✔
3345
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 2));
1✔
3346
         result.test_u32_eq("Valid value for counter 0", hotp_val, 359152);
1✔
3347
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 0));
1✔
3348
         result.test_u32_eq("Valid value for counter 0", hotp_val, 755224);
1✔
3349

3350
         uint64_t next_ctr = 0;
1✔
3351

3352
         TEST_FFI_OK(botan_hotp_check, (hotp, &next_ctr, 755224, 0, 0));
1✔
3353
         result.test_u64_eq("HOTP resync", next_ctr, 1);
1✔
3354
         TEST_FFI_OK(botan_hotp_check, (hotp, nullptr, 359152, 2, 0));
1✔
3355
         TEST_FFI_RC(1, botan_hotp_check, (hotp, nullptr, 359152, 1, 0));
1✔
3356
         TEST_FFI_OK(botan_hotp_check, (hotp, &next_ctr, 359152, 0, 2));
1✔
3357
         result.test_u64_eq("HOTP resync", next_ctr, 3);
1✔
3358

3359
         TEST_FFI_OK(botan_hotp_destroy, (hotp));
1✔
3360
      }
1✔
3361
};
3362

3363
class FFI_Keywrap_Test final : public FFI_Test {
1✔
3364
   public:
3365
      std::string name() const override { return "FFI Keywrap"; }
1✔
3366

3367
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
3368
         const uint8_t key[16] = {0};
1✔
3369
         const uint8_t kek[16] = {0xFF, 0};
1✔
3370

3371
         uint8_t wrapped[16 + 8] = {0};
1✔
3372
         size_t wrapped_keylen = sizeof(wrapped);
1✔
3373

3374
         if(TEST_FFI_INIT(botan_key_wrap3394, (key, sizeof(key), kek, sizeof(kek), wrapped, &wrapped_keylen))) {
1✔
3375
            const uint8_t expected_wrapped_key[16 + 8] = {0x04, 0x13, 0x37, 0x39, 0x82, 0xCF, 0xFA, 0x31,
1✔
3376
                                                          0x81, 0xCA, 0x4F, 0x59, 0x74, 0x4D, 0xED, 0x29,
3377
                                                          0x1F, 0x3F, 0xE5, 0x24, 0x00, 0x1B, 0x93, 0x20};
3378

3379
            result.test_sz_eq("Expected wrapped keylen size", wrapped_keylen, 16 + 8);
1✔
3380

3381
            result.test_bin_eq(
1✔
3382
               "Wrapped key", {wrapped, wrapped_keylen}, {expected_wrapped_key, sizeof(expected_wrapped_key)});
3383

3384
            uint8_t dec_key[16] = {0};
1✔
3385
            size_t dec_keylen = sizeof(dec_key);
1✔
3386
            TEST_FFI_OK(botan_key_unwrap3394, (wrapped, sizeof(wrapped), kek, sizeof(kek), dec_key, &dec_keylen));
1✔
3387

3388
            result.test_bin_eq("Unwrapped key", {dec_key, dec_keylen}, {key, sizeof(key)});
1✔
3389
         }
3390
      }
1✔
3391
};
3392

3393
class FFI_XMSS_Test final : public FFI_Test {
1✔
3394
   public:
3395
      std::string name() const override { return "FFI XMSS"; }
1✔
3396

3397
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3398
         botan_privkey_t priv;
1✔
3399
         if(TEST_FFI_INIT(botan_privkey_create, (&priv, "XMSS", "XMSS-SHA2_10_256", rng))) {
1✔
3400
            TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
1✔
3401

3402
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_privkey_stateful_operation, (priv, nullptr));
1✔
3403
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_privkey_remaining_operations, (priv, nullptr));
1✔
3404

3405
            int stateful;
1✔
3406
            TEST_FFI_OK(botan_privkey_stateful_operation, (priv, &stateful));
1✔
3407
            result.test_is_true("key is stateful", stateful == 1);
1✔
3408

3409
            uint64_t remaining;
1✔
3410
            TEST_FFI_OK(botan_privkey_remaining_operations, (priv, &remaining));
1✔
3411
            result.test_u64_eq("key has remaining operations", remaining, 1024);
1✔
3412

3413
            TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
3414
         }
3415
      }
1✔
3416
};
3417

3418
class FFI_RSA_Test final : public FFI_Test {
1✔
3419
   public:
3420
      std::string name() const override { return "FFI RSA"; }
1✔
3421

3422
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3423
         botan_privkey_t priv;
1✔
3424

3425
         if(TEST_FFI_INIT(botan_privkey_create_rsa, (&priv, rng, 1024))) {
1✔
3426
            TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
1✔
3427

3428
            int stateful;
1✔
3429
            TEST_FFI_OK(botan_privkey_stateful_operation, (priv, &stateful));
1✔
3430
            result.test_is_true("key is not stateful", stateful == 0);
1✔
3431

3432
            uint64_t remaining;
1✔
3433
            TEST_FFI_FAIL("key is not stateful", botan_privkey_remaining_operations, (priv, &remaining));
1✔
3434

3435
            botan_pubkey_t pub;
1✔
3436
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3437
            TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
1✔
3438

3439
            ffi_test_pubkey_export(result, pub, priv, rng);
1✔
3440

3441
            botan_mp_t p;
1✔
3442
            botan_mp_t q;
1✔
3443
            botan_mp_t d;
1✔
3444
            botan_mp_t n;
1✔
3445
            botan_mp_t e;
1✔
3446
            botan_mp_init(&p);
1✔
3447
            botan_mp_init(&q);
1✔
3448
            botan_mp_init(&d);
1✔
3449
            botan_mp_init(&n);
1✔
3450
            botan_mp_init(&e);
1✔
3451

3452
            TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (p, priv, "quux"));
1✔
3453
            TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_pubkey_get_field, (p, pub, "quux"));
1✔
3454

3455
            TEST_FFI_OK(botan_privkey_rsa_get_p, (p, priv));
1✔
3456
            TEST_FFI_OK(botan_privkey_rsa_get_q, (q, priv));
1✔
3457
            TEST_FFI_OK(botan_privkey_rsa_get_d, (d, priv));
1✔
3458
            TEST_FFI_OK(botan_privkey_rsa_get_e, (e, priv));
1✔
3459
            TEST_FFI_OK(botan_privkey_rsa_get_n, (n, priv));
1✔
3460

3461
            // Confirm same (e,n) values in public key
3462
            {
1✔
3463
               botan_mp_t pub_e;
1✔
3464
               botan_mp_t pub_n;
1✔
3465
               botan_mp_init(&pub_e);
1✔
3466
               botan_mp_init(&pub_n);
1✔
3467
               TEST_FFI_OK(botan_pubkey_rsa_get_e, (pub_e, pub));
1✔
3468
               TEST_FFI_OK(botan_pubkey_rsa_get_n, (pub_n, pub));
1✔
3469

3470
               TEST_FFI_RC(1, botan_mp_equal, (pub_e, e));
1✔
3471
               TEST_FFI_RC(1, botan_mp_equal, (pub_n, n));
1✔
3472
               botan_mp_destroy(pub_e);
1✔
3473
               botan_mp_destroy(pub_n);
1✔
3474
            }
3475

3476
            TEST_FFI_RC(1, botan_mp_is_prime, (p, rng, 64));
1✔
3477
            TEST_FFI_RC(1, botan_mp_is_prime, (q, rng, 64));
1✔
3478

3479
            // Test p != q
3480
            TEST_FFI_RC(0, botan_mp_equal, (p, q));
1✔
3481

3482
            // Test p * q == n
3483
            botan_mp_t x;
1✔
3484
            botan_mp_init(&x);
1✔
3485
            TEST_FFI_OK(botan_mp_mul, (x, p, q));
1✔
3486

3487
            TEST_FFI_RC(1, botan_mp_equal, (x, n));
1✔
3488
            botan_mp_destroy(x);
1✔
3489

3490
            botan_privkey_t loaded_privkey;
1✔
3491
            // First try loading a bogus key and verify it is rejected
3492
            TEST_FFI_RC(-1, botan_privkey_load_rsa, (&loaded_privkey, n, d, q));
1✔
3493

3494
            TEST_FFI_OK(botan_privkey_load_rsa, (&loaded_privkey, p, q, e));
1✔
3495
            TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3496

3497
            botan_pubkey_t loaded_pubkey;
1✔
3498
            TEST_FFI_OK(botan_pubkey_load_rsa, (&loaded_pubkey, n, e));
1✔
3499
            TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
3500

3501
            botan_mp_destroy(p);
1✔
3502
            botan_mp_destroy(q);
1✔
3503
            botan_mp_destroy(d);
1✔
3504
            botan_mp_destroy(e);
1✔
3505
            botan_mp_destroy(n);
1✔
3506

3507
            size_t pkcs1_len = 0;
1✔
3508
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
3509
                        botan_privkey_rsa_get_privkey,
3510
                        (loaded_privkey, nullptr, &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
3511

3512
            std::vector<uint8_t> pkcs1(pkcs1_len);
1✔
3513
            TEST_FFI_OK(botan_privkey_rsa_get_privkey,
1✔
3514
                        (loaded_privkey, pkcs1.data(), &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
3515

3516
            botan_privkey_t privkey_from_pkcs1;
1✔
3517
            TEST_FFI_OK(botan_privkey_load_rsa_pkcs1, (&privkey_from_pkcs1, pkcs1.data(), pkcs1_len));
1✔
3518
            TEST_FFI_OK(botan_privkey_destroy, (privkey_from_pkcs1));
1✔
3519

3520
            pkcs1_len = 0;
1✔
3521
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
3522
                        botan_privkey_rsa_get_privkey,
3523
                        (loaded_privkey, nullptr, &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
3524
            pkcs1.resize(pkcs1_len);
1✔
3525
            TEST_FFI_OK(botan_privkey_rsa_get_privkey,
1✔
3526
                        (loaded_privkey, pkcs1.data(), &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
3527

3528
            std::array<char, 32> namebuf{};
1✔
3529
            size_t name_len = namebuf.size();
1✔
3530
            if(TEST_FFI_OK(botan_pubkey_algo_name, (loaded_pubkey, namebuf.data(), &name_len))) {
1✔
3531
               result.test_str_eq("algo name", namebuf.data(), "RSA");
1✔
3532
            }
3533

3534
            name_len = namebuf.size();
1✔
3535
            if(TEST_FFI_OK(botan_privkey_algo_name, (loaded_privkey, namebuf.data(), &name_len))) {
1✔
3536
               result.test_str_eq("algo name", namebuf.data(), "RSA");
1✔
3537
            }
3538

3539
            botan_pk_op_encrypt_t encrypt;
1✔
3540
            if(TEST_FFI_INIT(botan_pk_op_encrypt_create, (&encrypt, loaded_pubkey, "OAEP(SHA-256)", 0))) {
1✔
3541
               std::vector<uint8_t> plaintext(32);
1✔
3542
               TEST_FFI_OK(botan_rng_get, (rng, plaintext.data(), plaintext.size()));
1✔
3543

3544
               size_t ctext_len;
1✔
3545
               TEST_FFI_OK(botan_pk_op_encrypt_output_length, (encrypt, plaintext.size(), &ctext_len));
1✔
3546
               std::vector<uint8_t> ciphertext(ctext_len);
1✔
3547

3548
               if(TEST_FFI_OK(botan_pk_op_encrypt,
1✔
3549
                              (encrypt, rng, ciphertext.data(), &ctext_len, plaintext.data(), plaintext.size()))) {
3550
                  ciphertext.resize(ctext_len);
1✔
3551

3552
                  botan_pk_op_decrypt_t decrypt;
1✔
3553
                  if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&decrypt, priv, "OAEP(SHA-256)", 0))) {
1✔
3554
                     size_t decrypted_len;
1✔
3555
                     TEST_FFI_OK(botan_pk_op_decrypt_output_length, (decrypt, ciphertext.size(), &decrypted_len));
1✔
3556
                     std::vector<uint8_t> decrypted(decrypted_len);
1✔
3557
                     TEST_FFI_OK(botan_pk_op_decrypt,
1✔
3558
                                 (decrypt, decrypted.data(), &decrypted_len, ciphertext.data(), ciphertext.size()));
3559
                     decrypted.resize(decrypted_len);
1✔
3560

3561
                     result.test_bin_eq("RSA plaintext", decrypted, plaintext);
1✔
3562
                  }
1✔
3563

3564
                  TEST_FFI_OK(botan_pk_op_decrypt_destroy, (decrypt));
1✔
3565
               }
3566

3567
               TEST_FFI_OK(botan_pk_op_encrypt_destroy, (encrypt));
1✔
3568
            }
1✔
3569

3570
            TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
1✔
3571
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3572
            TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
3573
            TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
3574
         }
1✔
3575
      }
1✔
3576
};
3577

3578
class FFI_DSA_Test final : public FFI_Test {
1✔
3579
   public:
3580
      std::string name() const override { return "FFI DSA"; }
1✔
3581

3582
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3583
         botan_privkey_t priv;
1✔
3584

3585
         if(TEST_FFI_INIT(botan_privkey_create, (&priv, "DSA", "dsa/jce/1024", rng))) {
1✔
3586
            do_dsa_test(priv, rng, result);
1✔
3587
         }
3588

3589
         if(TEST_FFI_INIT(botan_privkey_create_dsa, (&priv, rng, 1024, 160))) {
1✔
3590
            do_dsa_test(priv, rng, result);
1✔
3591
         }
3592
      }
1✔
3593

3594
   private:
3595
      static void do_dsa_test(botan_privkey_t priv, botan_rng_t rng, Test::Result& result) {
2✔
3596
         TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
2✔
3597

3598
         botan_pubkey_t pub;
2✔
3599
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
2✔
3600
         TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
2✔
3601

3602
         ffi_test_pubkey_export(result, pub, priv, rng);
2✔
3603

3604
         botan_mp_t p;
2✔
3605
         botan_mp_t q;
2✔
3606
         botan_mp_t g;
2✔
3607
         botan_mp_t x;
2✔
3608
         botan_mp_t y;
2✔
3609
         botan_mp_init(&p);
2✔
3610
         botan_mp_init(&q);
2✔
3611
         botan_mp_init(&g);
2✔
3612
         botan_mp_init(&x);
2✔
3613
         botan_mp_init(&y);
2✔
3614

3615
         TEST_FFI_OK(botan_privkey_dsa_get_x, (x, priv));
2✔
3616
         TEST_FFI_OK(botan_pubkey_dsa_get_g, (g, pub));
2✔
3617
         TEST_FFI_OK(botan_pubkey_dsa_get_p, (p, pub));
2✔
3618
         TEST_FFI_OK(botan_pubkey_dsa_get_q, (q, pub));
2✔
3619
         TEST_FFI_OK(botan_pubkey_dsa_get_y, (y, pub));
2✔
3620

3621
         botan_mp_t cmp;
2✔
3622
         botan_mp_init(&cmp);
2✔
3623
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (cmp, priv, "quux"));
2✔
3624

3625
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "x"));
2✔
3626
         TEST_FFI_RC(1, botan_mp_equal, (cmp, x));
2✔
3627

3628
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "y"));
2✔
3629
         TEST_FFI_RC(1, botan_mp_equal, (cmp, y));
2✔
3630

3631
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "p"));
2✔
3632
         TEST_FFI_RC(1, botan_mp_equal, (cmp, p));
2✔
3633
         botan_mp_destroy(cmp);
2✔
3634

3635
         botan_privkey_t loaded_privkey;
2✔
3636
         TEST_FFI_OK(botan_privkey_load_dsa, (&loaded_privkey, p, q, g, x));
2✔
3637
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
2✔
3638

3639
         botan_pubkey_t loaded_pubkey;
2✔
3640
         TEST_FFI_OK(botan_pubkey_load_dsa, (&loaded_pubkey, p, q, g, y));
2✔
3641
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
2✔
3642

3643
         botan_mp_destroy(p);
2✔
3644
         botan_mp_destroy(q);
2✔
3645
         botan_mp_destroy(g);
2✔
3646
         botan_mp_destroy(y);
2✔
3647
         botan_mp_destroy(x);
2✔
3648

3649
         botan_pk_op_sign_t signer;
2✔
3650

3651
         std::vector<uint8_t> message(6, 6);
2✔
3652
         std::vector<uint8_t> signature;
2✔
3653

3654
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, loaded_privkey, "SHA-256", 0))) {
2✔
3655
            // TODO: break input into multiple calls to update
3656
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
2✔
3657

3658
            size_t sig_len;
2✔
3659
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
2✔
3660
            signature.resize(sig_len);
2✔
3661

3662
            size_t output_sig_len = sig_len;
2✔
3663
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &output_sig_len));
2✔
3664
            result.test_sz_lte("Output length is upper bound", output_sig_len, sig_len);
2✔
3665
            signature.resize(output_sig_len);
2✔
3666

3667
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
2✔
3668
         }
3669

3670
         botan_pk_op_verify_t verifier = nullptr;
2✔
3671

3672
         if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-256", 0))) {
2✔
3673
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3674
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
3675

3676
            // TODO: randomize this
3677
            signature[0] ^= 1;
2✔
3678
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3679
            TEST_FFI_RC(
2✔
3680
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3681

3682
            message[0] ^= 1;
2✔
3683
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3684
            TEST_FFI_RC(
2✔
3685
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3686

3687
            signature[0] ^= 1;
2✔
3688
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3689
            TEST_FFI_RC(
2✔
3690
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3691

3692
            message[0] ^= 1;
2✔
3693
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3694
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
3695

3696
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
2✔
3697
         }
3698

3699
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
3700
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
2✔
3701
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
2✔
3702
         TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
3703
      }
2✔
3704
};
3705

3706
class FFI_ECDSA_Test final : public FFI_Test {
1✔
3707
   public:
3708
      std::string name() const override { return "FFI ECDSA"; }
1✔
3709

3710
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3711
         static const char* kCurve = "secp384r1";
1✔
3712
         botan_privkey_t priv;
1✔
3713
         botan_pubkey_t pub;
1✔
3714

3715
         if(!TEST_FFI_INIT(botan_privkey_create_ecdsa, (&priv, rng, kCurve))) {
1✔
3716
            return;
×
3717
         }
3718

3719
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3720
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
3721

3722
         // Check key load functions
3723
         botan_mp_t private_scalar;
1✔
3724
         botan_mp_t public_x;
1✔
3725
         botan_mp_t public_y;
1✔
3726
         ViewBytesSink sec1;
1✔
3727
         botan_mp_init(&private_scalar);
1✔
3728
         botan_mp_init(&public_x);
1✔
3729
         botan_mp_init(&public_y);
1✔
3730

3731
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (private_scalar, priv, "quux"));
1✔
3732
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_pubkey_get_field, (private_scalar, pub, "quux"));
1✔
3733

3734
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
3735
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
3736
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
3737
         TEST_FFI_OK(botan_pubkey_view_raw, (pub, sec1.delegate(), sec1.callback()));
1✔
3738

3739
         botan_privkey_t loaded_privkey;
1✔
3740
         botan_pubkey_t loaded_pubkey1;
1✔
3741
         botan_pubkey_t loaded_pubkey2;
1✔
3742
         TEST_FFI_OK(botan_privkey_load_ecdsa, (&loaded_privkey, private_scalar, kCurve));
1✔
3743
         TEST_FFI_OK(botan_pubkey_load_ecdsa, (&loaded_pubkey1, public_x, public_y, kCurve));
1✔
3744
         TEST_FFI_OK(botan_pubkey_load_ecdsa_sec1, (&loaded_pubkey2, sec1.data(), sec1.size(), kCurve));
1✔
3745
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3746
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
3747
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey2, rng, 0));
1✔
3748

3749
         std::array<char, 32> namebuf{};
1✔
3750
         size_t name_len = namebuf.size();
1✔
3751

3752
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf.data(), &name_len));
1✔
3753
         result.test_str_eq("Algo name is expected", namebuf.data(), "ECDSA");
1✔
3754

3755
         std::vector<uint8_t> message(1280);
1✔
3756
         std::vector<uint8_t> signature;
1✔
3757
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
3758

3759
         for(uint32_t flags = 0; flags <= 1; ++flags) {
3✔
3760
            botan_pk_op_sign_t signer;
2✔
3761
            if(TEST_FFI_INIT(botan_pk_op_sign_create, (&signer, loaded_privkey, "SHA-384", flags))) {
2✔
3762
               // TODO: break input into multiple calls to update
3763
               TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
2✔
3764

3765
               size_t sig_len;
2✔
3766
               TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
2✔
3767

3768
               signature.resize(sig_len);
2✔
3769

3770
               size_t output_sig_len = signature.size();
2✔
3771
               TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &output_sig_len));
2✔
3772
               signature.resize(output_sig_len);
2✔
3773

3774
               TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
2✔
3775
            }
3776

3777
            botan_pk_op_verify_t verifier = nullptr;
2✔
3778

3779
            if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-384", flags))) {
2✔
3780
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3781
               TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
3782

3783
               // TODO: randomize this
3784
               signature[0] ^= 1;
2✔
3785
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3786
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
3787
                           botan_pk_op_verify_finish,
3788
                           (verifier, signature.data(), signature.size()));
3789

3790
               message[0] ^= 1;
2✔
3791
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3792
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
3793
                           botan_pk_op_verify_finish,
3794
                           (verifier, signature.data(), signature.size()));
3795

3796
               signature[0] ^= 1;
2✔
3797
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3798
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
3799
                           botan_pk_op_verify_finish,
3800
                           (verifier, signature.data(), signature.size()));
3801

3802
               message[0] ^= 1;
2✔
3803
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3804
               TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
3805

3806
               TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
2✔
3807
            }
3808
         }
3809

3810
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
3811
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
3812
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
3813
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3814
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
3815
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
3816
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
1✔
3817
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey2));
1✔
3818
      }
1✔
3819
};
3820

3821
class FFI_SM2_Sig_Test final : public FFI_Test {
1✔
3822
   public:
3823
      std::string name() const override { return "FFI SM2 Sig"; }
1✔
3824

3825
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3826
         static const char* kCurve = "sm2p256v1";
1✔
3827
         const std::string sm2_ident = "SM2 Ident Field";
1✔
3828
         botan_privkey_t priv;
1✔
3829
         botan_pubkey_t pub;
1✔
3830
         botan_privkey_t loaded_privkey;
1✔
3831
         botan_pubkey_t loaded_pubkey1;
1✔
3832
         botan_pubkey_t loaded_pubkey2;
1✔
3833

3834
         if(!TEST_FFI_INIT(botan_privkey_create, (&priv, "SM2_Sig", kCurve, rng))) {
1✔
3835
            return;
3836
         }
3837

3838
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3839
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
3840

3841
         uint8_t za[32];
1✔
3842
         size_t sizeof_za = sizeof(za);
1✔
3843
         TEST_FFI_OK(botan_pubkey_sm2_compute_za, (za, &sizeof_za, "Ident", "SM3", pub));
1✔
3844

3845
         // Check key load functions
3846
         botan_mp_t private_scalar;
1✔
3847
         botan_mp_t public_x;
1✔
3848
         botan_mp_t public_y;
1✔
3849
         ViewBytesSink sec1;
1✔
3850
         botan_mp_init(&private_scalar);
1✔
3851
         botan_mp_init(&public_x);
1✔
3852
         botan_mp_init(&public_y);
1✔
3853

3854
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
3855
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
3856
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
3857
         TEST_FFI_OK(botan_pubkey_view_raw, (pub, sec1.delegate(), sec1.callback()));
1✔
3858
         REQUIRE_FFI_OK(botan_privkey_load_sm2, (&loaded_privkey, private_scalar, kCurve));
1✔
3859
         REQUIRE_FFI_OK(botan_pubkey_load_sm2, (&loaded_pubkey1, public_x, public_y, kCurve));
1✔
3860
         REQUIRE_FFI_OK(botan_pubkey_load_sm2_sec1, (&loaded_pubkey2, sec1.data(), sec1.size(), kCurve));
1✔
3861
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3862
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
3863
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey2, rng, 0));
1✔
3864

3865
         std::array<char, 32> namebuf{};
1✔
3866
         size_t name_len = namebuf.size();
1✔
3867

3868
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf.data(), &name_len));
1✔
3869
         result.test_str_eq("Algo name is expected", namebuf.data(), "SM2");
1✔
3870

3871
         std::vector<uint8_t> message(1280);
1✔
3872
         std::vector<uint8_t> signature;
1✔
3873
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
3874
         botan_pk_op_sign_t signer;
1✔
3875
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, loaded_privkey, sm2_ident.c_str(), 0))) {
1✔
3876
            // TODO: break input into multiple calls to update
3877
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
1✔
3878

3879
            size_t sig_len;
1✔
3880
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
1✔
3881

3882
            signature.resize(sig_len);
1✔
3883

3884
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_len));
1✔
3885
            signature.resize(sig_len);
1✔
3886

3887
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
1✔
3888
         }
3889

3890
         botan_pk_op_verify_t verifier = nullptr;
1✔
3891

3892
         if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, sm2_ident.c_str(), 0))) {
1✔
3893
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3894
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
3895

3896
            // TODO: randomize this
3897
            signature[0] ^= 1;
1✔
3898
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3899
            TEST_FFI_RC(
1✔
3900
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3901

3902
            message[0] ^= 1;
1✔
3903
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3904
            TEST_FFI_RC(
1✔
3905
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3906

3907
            signature[0] ^= 1;
1✔
3908
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3909
            TEST_FFI_RC(
1✔
3910
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3911

3912
            message[0] ^= 1;
1✔
3913
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3914
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
3915

3916
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
1✔
3917
         }
3918

3919
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
3920
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
3921
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
3922
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3923
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
3924
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
3925
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
1✔
3926
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey2));
1✔
3927
      }
1✔
3928
};
3929

3930
class FFI_SM2_Enc_Test final : public FFI_Test {
1✔
3931
   public:
3932
      std::string name() const override { return "FFI SM2 Enc"; }
1✔
3933

3934
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3935
         static const char* kCurve = "sm2p256v1";
1✔
3936
         botan_privkey_t priv;
1✔
3937
         botan_pubkey_t pub;
1✔
3938
         botan_privkey_t loaded_privkey;
1✔
3939
         botan_pubkey_t loaded_pubkey1;
1✔
3940
         botan_pubkey_t loaded_pubkey2;
1✔
3941

3942
         if(!TEST_FFI_INIT(botan_privkey_create, (&priv, "SM2_Enc", kCurve, rng))) {
1✔
3943
            return;
×
3944
         }
3945

3946
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3947
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
3948

3949
         uint8_t za[32];
1✔
3950
         size_t sizeof_za = sizeof(za);
1✔
3951
         TEST_FFI_OK(botan_pubkey_sm2_compute_za, (za, &sizeof_za, "Ident", "SM3", pub));
1✔
3952

3953
         // Check key load functions
3954
         botan_mp_t private_scalar;
1✔
3955
         botan_mp_t public_x;
1✔
3956
         botan_mp_t public_y;
1✔
3957
         ViewBytesSink sec1;
1✔
3958
         botan_mp_init(&private_scalar);
1✔
3959
         botan_mp_init(&public_x);
1✔
3960
         botan_mp_init(&public_y);
1✔
3961

3962
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
3963
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
3964
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
3965
         TEST_FFI_OK(botan_pubkey_view_raw, (pub, sec1.delegate(), sec1.callback()));
1✔
3966
         REQUIRE_FFI_OK(botan_privkey_load_sm2_enc, (&loaded_privkey, private_scalar, kCurve));
1✔
3967
         REQUIRE_FFI_OK(botan_pubkey_load_sm2_enc, (&loaded_pubkey1, public_x, public_y, kCurve));
1✔
3968
         REQUIRE_FFI_OK(botan_pubkey_load_sm2_sec1, (&loaded_pubkey2, sec1.data(), sec1.size(), kCurve));
1✔
3969
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3970
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
3971
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey2, rng, 0));
1✔
3972

3973
         std::array<char, 32> namebuf{};
1✔
3974
         size_t name_len = namebuf.size();
1✔
3975

3976
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf.data(), &name_len));
1✔
3977
         result.test_str_eq("Algo name is expected", namebuf.data(), "SM2");
1✔
3978

3979
         std::vector<uint8_t> message(32);
1✔
3980

3981
         std::vector<uint8_t> ciphertext;
1✔
3982
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
3983

3984
         botan_pk_op_encrypt_t enc;
1✔
3985
         if(TEST_FFI_OK(botan_pk_op_encrypt_create, (&enc, loaded_pubkey1, "", 0))) {
1✔
3986
            size_t ctext_len;
1✔
3987
            TEST_FFI_OK(botan_pk_op_encrypt_output_length, (enc, message.size(), &ctext_len));
1✔
3988

3989
            ciphertext.resize(ctext_len);
1✔
3990
            TEST_FFI_OK(botan_pk_op_encrypt, (enc, rng, ciphertext.data(), &ctext_len, message.data(), message.size()));
1✔
3991
            ciphertext.resize(ctext_len);
1✔
3992

3993
            botan_pk_op_decrypt_t dec;
1✔
3994
            TEST_FFI_OK(botan_pk_op_decrypt_create, (&dec, loaded_privkey, "", 0));
1✔
3995

3996
            std::vector<uint8_t> recovered(message.size());
1✔
3997
            size_t recovered_len = recovered.size();
1✔
3998

3999
            TEST_FFI_OK(botan_pk_op_decrypt,
1✔
4000
                        (dec, recovered.data(), &recovered_len, ciphertext.data(), ciphertext.size()));
4001

4002
            botan_pk_op_decrypt_destroy(dec);
1✔
4003
         }
1✔
4004
         botan_pk_op_encrypt_destroy(enc);
1✔
4005

4006
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
4007
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
4008
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
4009
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
4010
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
4011
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
4012
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
1✔
4013
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey2));
1✔
4014
      }
1✔
4015
};
4016

4017
class FFI_ECDH_Test final : public FFI_Test {
1✔
4018
   public:
4019
      std::string name() const override { return "FFI ECDH"; }
1✔
4020

4021
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4022
         botan_privkey_t priv1;
1✔
4023
         if(!TEST_FFI_INIT(botan_privkey_create_ecdh, (&priv1, rng, "secp256r1"))) {
1✔
4024
            return;
×
4025
         }
4026

4027
         botan_privkey_t priv2;
1✔
4028
         REQUIRE_FFI_OK(botan_privkey_create_ecdh, (&priv2, rng, "secp256r1"));
1✔
4029

4030
         botan_pubkey_t pub1;
1✔
4031
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub1, priv1));
1✔
4032

4033
         botan_pubkey_t pub2;
1✔
4034
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub2, priv2));
1✔
4035

4036
         /* Reload key-pair1 in order to test functions for key loading */
4037
         botan_mp_t private_scalar;
1✔
4038
         botan_mp_t public_x;
1✔
4039
         botan_mp_t public_y;
1✔
4040
         ViewBytesSink sec1;
1✔
4041
         botan_mp_init(&private_scalar);
1✔
4042
         botan_mp_init(&public_x);
1✔
4043
         botan_mp_init(&public_y);
1✔
4044

4045
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv1, "x"));
1✔
4046
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub1, "public_x"));
1✔
4047
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub1, "public_y"));
1✔
4048
         TEST_FFI_OK(botan_pubkey_view_raw, (pub1, sec1.delegate(), sec1.callback()));
1✔
4049

4050
         botan_privkey_t loaded_privkey1;
1✔
4051
         botan_pubkey_t loaded_pubkey1;
1✔
4052
         botan_pubkey_t loaded_pubkey2;
1✔
4053
         REQUIRE_FFI_OK(botan_privkey_load_ecdh, (&loaded_privkey1, private_scalar, "secp256r1"));
1✔
4054
         REQUIRE_FFI_OK(botan_pubkey_load_ecdh, (&loaded_pubkey1, public_x, public_y, "secp256r1"));
1✔
4055
         REQUIRE_FFI_OK(botan_pubkey_load_ecdh_sec1, (&loaded_pubkey2, sec1.data(), sec1.size(), "secp256r1"));
1✔
4056
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey1, rng, 0));
1✔
4057
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
4058
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey2, rng, 0));
1✔
4059

4060
         ffi_test_pubkey_export(result, loaded_pubkey1, priv1, rng);
1✔
4061
         ffi_test_pubkey_export(result, loaded_pubkey2, priv1, rng);
1✔
4062
         ffi_test_pubkey_export(result, pub2, priv2, rng);
1✔
4063

4064
   #if defined(BOTAN_HAS_KDF2) && defined(BOTAN_HAS_SHA_256)
4065
         constexpr bool has_kdf2_sha256 = true;
1✔
4066
   #else
4067
         constexpr bool has_kdf2_sha256 = false;
4068
   #endif
4069

4070
         const char* kdf = has_kdf2_sha256 ? "KDF2(SHA-256)" : "Raw";
1✔
4071
         constexpr size_t salt_len = has_kdf2_sha256 ? 32 : 0;
1✔
4072

4073
         botan_pk_op_ka_t ka1;
1✔
4074
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka1, loaded_privkey1, kdf, 0));
1✔
4075
         botan_pk_op_ka_t ka2;
1✔
4076
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka2, priv2, kdf, 0));
1✔
4077

4078
         size_t pubkey1_len = 0;
1✔
4079
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
4080
                     botan_pk_op_key_agreement_export_public,
4081
                     (priv1, nullptr, &pubkey1_len));
4082
         std::vector<uint8_t> pubkey1(pubkey1_len);
1✔
4083
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv1, pubkey1.data(), &pubkey1_len));
1✔
4084
         size_t pubkey2_len = 0;
1✔
4085
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
4086
                     botan_pk_op_key_agreement_export_public,
4087
                     (priv2, nullptr, &pubkey2_len));
4088
         std::vector<uint8_t> pubkey2(pubkey2_len);
1✔
4089
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv2, pubkey2.data(), &pubkey2_len));
1✔
4090

4091
         std::vector<uint8_t> salt(salt_len);
1✔
4092
         TEST_FFI_OK(botan_rng_get, (rng, salt.data(), salt.size()));
1✔
4093

4094
         const size_t shared_key_len = 32;
1✔
4095

4096
         std::vector<uint8_t> key1(shared_key_len);
1✔
4097
         size_t key1_len = key1.size();
1✔
4098
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
4099
                     (ka1, key1.data(), &key1_len, pubkey2.data(), pubkey2.size(), salt.data(), salt.size()));
4100

4101
         std::vector<uint8_t> key2(shared_key_len);
1✔
4102
         size_t key2_len = key2.size();
1✔
4103
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
4104
                     (ka2, key2.data(), &key2_len, pubkey1.data(), pubkey1.size(), salt.data(), salt.size()));
4105

4106
         result.test_bin_eq("shared ECDH key", key1, key2);
1✔
4107

4108
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
4109
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
4110
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
4111
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka1));
1✔
4112
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka2));
1✔
4113
         TEST_FFI_OK(botan_privkey_destroy, (priv1));
1✔
4114
         TEST_FFI_OK(botan_privkey_destroy, (priv2));
1✔
4115
         TEST_FFI_OK(botan_pubkey_destroy, (pub1));
1✔
4116
         TEST_FFI_OK(botan_pubkey_destroy, (pub2));
1✔
4117
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey1));
1✔
4118
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
1✔
4119
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey2));
1✔
4120
      }
1✔
4121
};
4122

4123
class FFI_McEliece_Test final : public FFI_Test {
1✔
4124
   public:
4125
      std::string name() const override { return "FFI McEliece"; }
1✔
4126

4127
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4128
         botan_privkey_t priv;
1✔
4129
         if(TEST_FFI_INIT(botan_privkey_create_mceliece, (&priv, rng, 1632, 33))) {
1✔
4130
            botan_pubkey_t pub;
1✔
4131
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
4132

4133
            ffi_test_pubkey_export(result, pub, priv, rng);
1✔
4134

4135
            std::array<char, 32> namebuf{};
1✔
4136
            size_t name_len = namebuf.size();
1✔
4137
            if(TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf.data(), &name_len))) {
1✔
4138
               result.test_str_eq("algo name", namebuf.data(), "McEliece");
1✔
4139
            }
4140

4141
            // TODO test KEM
4142

4143
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
4144
            TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
4145
         }
4146
      }
1✔
4147
};
4148

4149
class FFI_Ed25519_Test final : public FFI_Test {
1✔
4150
   public:
4151
      std::string name() const override { return "FFI Ed25519"; }
1✔
4152

4153
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4154
         botan_pubkey_t pub;
1✔
4155
         botan_privkey_t priv;
1✔
4156

4157
         // From draft-koch-eddsa-for-openpgp-04
4158
         const std::vector<uint8_t> seed =
1✔
4159
            Botan::hex_decode("1a8b1ff05ded48e18bf50166c664ab023ea70003d78d9e41f5758a91d850f8d2");
1✔
4160
         const std::vector<uint8_t> pubkey =
1✔
4161
            Botan::hex_decode("3f098994bdd916ed4053197934e4a87c80733a1280d62f8010992e43ee3b2406");
1✔
4162
         const std::vector<uint8_t> message = Botan::hex_decode("4f70656e504750040016080006050255f95f9504ff0000000c");
1✔
4163
         const std::vector<uint8_t> exp_sig = Botan::hex_decode(
1✔
4164
            "56f90cca98e2102637bd983fdb16c131dfd27ed82bf4dde5606e0d756aed3366"
4165
            "d09c4fa11527f038e0f57f2201d82f2ea2c9033265fa6ceb489e854bae61b404");
1✔
4166

4167
         if(!TEST_FFI_INIT(botan_privkey_load_ed25519, (&priv, seed.data()))) {
1✔
4168
            return;
×
4169
         }
4170

4171
         uint8_t retr_privkey[64];
1✔
4172
         TEST_FFI_OK(botan_privkey_ed25519_get_privkey, (priv, retr_privkey));
1✔
4173

4174
         result.test_bin_eq("Public key matches", {retr_privkey + 32, 32}, pubkey);
1✔
4175

4176
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
4177

4178
         uint8_t retr_pubkey[32];
1✔
4179
         TEST_FFI_OK(botan_pubkey_ed25519_get_pubkey, (pub, retr_pubkey));
1✔
4180
         result.test_bin_eq("Public key matches", {retr_pubkey, 32}, pubkey);
1✔
4181

4182
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
4183
         TEST_FFI_OK(botan_pubkey_load_ed25519, (&pub, pubkey.data()));
1✔
4184

4185
         botan_pk_op_sign_t signer;
1✔
4186
         std::vector<uint8_t> signature;
1✔
4187

4188
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv, "SHA-256", 0))) {
1✔
4189
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
1✔
4190

4191
            size_t sig_len;
1✔
4192
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
1✔
4193

4194
            signature.resize(sig_len);
1✔
4195

4196
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_len));
1✔
4197
            signature.resize(sig_len);
1✔
4198

4199
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
1✔
4200
         }
4201

4202
         result.test_bin_eq("Expected signature", signature, exp_sig);
1✔
4203

4204
         botan_pk_op_verify_t verifier;
1✔
4205

4206
         if(TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-256", 0))) {
1✔
4207
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
4208
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
4209

4210
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
1✔
4211
         }
4212

4213
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
4214
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
4215
      }
1✔
4216
};
4217

4218
class FFI_Ed448_Test final : public FFI_Test {
1✔
4219
   public:
4220
      std::string name() const override { return "FFI Ed448"; }
1✔
4221

4222
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4223
         botan_pubkey_t pub;
1✔
4224
         botan_privkey_t priv;
1✔
4225

4226
         // RFC 8032: Testvector Ed448, 1 octet
4227
         const auto sk = Botan::hex_decode(
1✔
4228
            "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e");
1✔
4229
         const auto pk_ref = Botan::hex_decode(
1✔
4230
            "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480");
1✔
4231
         const auto msg = Botan::hex_decode("03");
1✔
4232
         const auto sig_ref = Botan::hex_decode(
1✔
4233
            "26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f4352541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cbcee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0ff3348ab21aa4adafd1d234441cf807c03a00");
1✔
4234

4235
         if(!TEST_FFI_INIT(botan_privkey_load_ed448, (&priv, sk.data()))) {
1✔
4236
            return;
×
4237
         }
4238

4239
         std::vector<uint8_t> retr_privkey(57);
1✔
4240
         TEST_FFI_OK(botan_privkey_ed448_get_privkey, (priv, retr_privkey.data()));
1✔
4241
         result.test_bin_eq("Private key matches", retr_privkey, sk);
1✔
4242

4243
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
4244

4245
         std::vector<uint8_t> retr_pubkey(57);
1✔
4246
         TEST_FFI_OK(botan_pubkey_ed448_get_pubkey, (pub, retr_pubkey.data()));
1✔
4247
         result.test_bin_eq("Public key matches", retr_pubkey, pk_ref);
1✔
4248

4249
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
4250
         TEST_FFI_OK(botan_pubkey_load_ed448, (&pub, pk_ref.data()));
1✔
4251

4252
         botan_pk_op_sign_t signer;
1✔
4253
         std::vector<uint8_t> signature;
1✔
4254

4255
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv, "Pure", 0))) {
1✔
4256
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, msg.data(), msg.size()));
1✔
4257

4258
            size_t sig_len;
1✔
4259
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
1✔
4260

4261
            signature.resize(sig_len);
1✔
4262

4263
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_len));
1✔
4264
            signature.resize(sig_len);
1✔
4265

4266
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
1✔
4267
         }
4268

4269
         result.test_bin_eq("Expected signature", signature, sig_ref);
1✔
4270

4271
         botan_pk_op_verify_t verifier;
1✔
4272

4273
         if(TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "Pure", 0))) {
1✔
4274
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, msg.data(), msg.size()));
1✔
4275
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
4276

4277
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
1✔
4278
         }
4279

4280
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
4281
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
4282
      }
1✔
4283
};
4284

4285
class FFI_X25519_Test final : public FFI_Test {
1✔
4286
   public:
4287
      std::string name() const override { return "FFI X25519"; }
1✔
4288

4289
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
4290
         // From RFC 8037
4291

4292
         const std::vector<uint8_t> a_pub_bits =
1✔
4293
            Botan::hex_decode("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f");
1✔
4294
         const std::vector<uint8_t> b_priv_bits =
1✔
4295
            Botan::hex_decode("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a");
1✔
4296
         const std::vector<uint8_t> b_pub_bits =
1✔
4297
            Botan::hex_decode("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a");
1✔
4298
         const std::vector<uint8_t> shared_secret_bits =
1✔
4299
            Botan::hex_decode("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
1✔
4300

4301
         botan_privkey_t b_priv;
1✔
4302
         if(!TEST_FFI_INIT(botan_privkey_load_x25519, (&b_priv, b_priv_bits.data()))) {
1✔
4303
            return;
4304
         }
4305

4306
         std::vector<uint8_t> privkey_read(32);
1✔
4307
         TEST_FFI_OK(botan_privkey_x25519_get_privkey, (b_priv, privkey_read.data()));
1✔
4308
         result.test_bin_eq("X25519 private key", privkey_read, b_priv_bits);
1✔
4309

4310
         std::vector<uint8_t> pubkey_read(32);
1✔
4311

4312
         botan_pubkey_t b_pub;
1✔
4313
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
4314
         TEST_FFI_OK(botan_pubkey_x25519_get_pubkey, (b_pub, pubkey_read.data()));
1✔
4315
         result.test_bin_eq("X25519 public key b", pubkey_read, b_pub_bits);
1✔
4316

4317
         botan_pubkey_t a_pub;
1✔
4318
         TEST_FFI_OK(botan_pubkey_load_x25519, (&a_pub, a_pub_bits.data()));
1✔
4319
         TEST_FFI_OK(botan_pubkey_x25519_get_pubkey, (a_pub, pubkey_read.data()));
1✔
4320
         result.test_bin_eq("X25519 public key a", pubkey_read, a_pub_bits);
1✔
4321

4322
         botan_pk_op_ka_t ka;
1✔
4323
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka, b_priv, "Raw", 0));
1✔
4324

4325
         std::vector<uint8_t> shared_output(32);
1✔
4326
         size_t shared_len = shared_output.size();
1✔
4327
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
4328
                     (ka, shared_output.data(), &shared_len, a_pub_bits.data(), a_pub_bits.size(), nullptr, 0));
4329

4330
         result.test_bin_eq("Shared secret matches expected", shared_secret_bits, shared_output);
1✔
4331

4332
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
4333
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
4334
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
1✔
4335
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka));
1✔
4336
      }
1✔
4337
};
4338

4339
class FFI_X448_Test final : public FFI_Test {
1✔
4340
   public:
4341
      std::string name() const override { return "FFI X448"; }
1✔
4342

4343
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
4344
         // From RFC 7748 Section 6.2
4345
         const auto a_pub_ref = Botan::hex_decode(
1✔
4346
            "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0");
1✔
4347
         const auto b_priv_ref = Botan::hex_decode(
1✔
4348
            "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d");
1✔
4349
         const auto b_pub_ref = Botan::hex_decode(
1✔
4350
            "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609");
1✔
4351
         const auto shared_secret_ref = Botan::hex_decode(
1✔
4352
            "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d");
1✔
4353

4354
         botan_privkey_t b_priv;
1✔
4355
         if(!TEST_FFI_INIT(botan_privkey_load_x448, (&b_priv, b_priv_ref.data()))) {
1✔
4356
            return;
4357
         }
4358

4359
         std::vector<uint8_t> privkey_read(56);
1✔
4360
         TEST_FFI_OK(botan_privkey_x448_get_privkey, (b_priv, privkey_read.data()));
1✔
4361
         result.test_bin_eq("X448 private key", privkey_read, b_priv_ref);
1✔
4362

4363
         std::vector<uint8_t> pubkey_read(56);
1✔
4364

4365
         botan_pubkey_t b_pub;
1✔
4366
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
4367
         TEST_FFI_OK(botan_pubkey_x448_get_pubkey, (b_pub, pubkey_read.data()));
1✔
4368
         result.test_bin_eq("X448 public key b", pubkey_read, b_pub_ref);
1✔
4369

4370
         botan_pubkey_t a_pub;
1✔
4371
         TEST_FFI_OK(botan_pubkey_load_x448, (&a_pub, a_pub_ref.data()));
1✔
4372
         TEST_FFI_OK(botan_pubkey_x448_get_pubkey, (a_pub, pubkey_read.data()));
1✔
4373
         result.test_bin_eq("X448 public key a", pubkey_read, a_pub_ref);
1✔
4374

4375
         botan_pk_op_ka_t ka;
1✔
4376
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka, b_priv, "Raw", 0));
1✔
4377

4378
         std::vector<uint8_t> shared_output(56);
1✔
4379
         size_t shared_len = shared_output.size();
1✔
4380
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
4381
                     (ka, shared_output.data(), &shared_len, a_pub_ref.data(), a_pub_ref.size(), nullptr, 0));
4382

4383
         result.test_bin_eq("Shared secret matches expected", shared_secret_ref, shared_output);
1✔
4384

4385
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
4386
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
4387
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
1✔
4388
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka));
1✔
4389
      }
1✔
4390
};
4391

4392
/**
4393
 * Base class for roundtrip tests of FFI bindings for Key Encapsulation Mechanisms.
4394
 */
4395
class FFI_KEM_Roundtrip_Test : public FFI_Test {
6✔
4396
   protected:
4397
      using privkey_loader_fn_t = int (*)(botan_privkey_t*, const uint8_t[], size_t, const char*);
4398
      using pubkey_loader_fn_t = int (*)(botan_pubkey_t*, const uint8_t[], size_t, const char*);
4399

4400
   protected:
4401
      virtual const char* algo() const = 0;
4402
      virtual privkey_loader_fn_t private_key_load_function() const = 0;
4403
      virtual pubkey_loader_fn_t public_key_load_function() const = 0;
4404
      virtual std::vector<const char*> modes() const = 0;
4405

4406
   public:
4407
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
3✔
4408
         for(const auto* mode : modes()) {
34✔
4409
            // generate a key pair
4410
            botan_privkey_t priv;
31✔
4411
            botan_pubkey_t pub;
31✔
4412
            if(!TEST_FFI_INIT(botan_privkey_create, (&priv, algo(), mode, rng))) {
31✔
4413
               continue;
×
4414
            }
4415
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
31✔
4416

4417
            // raw-encode the key pair
4418
            ViewBytesSink priv_bytes;
31✔
4419
            ViewBytesSink pub_bytes;
31✔
4420
            TEST_FFI_OK(botan_privkey_view_raw, (priv, priv_bytes.delegate(), priv_bytes.callback()));
31✔
4421
            TEST_FFI_OK(botan_pubkey_view_raw, (pub, pub_bytes.delegate(), pub_bytes.callback()));
31✔
4422

4423
            // decode the key pair from raw encoding
4424
            botan_privkey_t priv_loaded;
31✔
4425
            botan_pubkey_t pub_loaded;
31✔
4426
            TEST_FFI_OK(private_key_load_function(),
31✔
4427
                        (&priv_loaded, priv_bytes.get().data(), priv_bytes.get().size(), mode));
4428
            TEST_FFI_OK(public_key_load_function(),
31✔
4429
                        (&pub_loaded, pub_bytes.get().data(), pub_bytes.get().size(), mode));
4430

4431
            // re-encode and compare to the first round
4432
            ViewBytesSink priv_bytes2;
31✔
4433
            ViewBytesSink pub_bytes2;
31✔
4434
            TEST_FFI_OK(botan_privkey_view_raw, (priv_loaded, priv_bytes2.delegate(), priv_bytes2.callback()));
31✔
4435
            TEST_FFI_OK(botan_pubkey_view_raw, (pub_loaded, pub_bytes2.delegate(), pub_bytes2.callback()));
31✔
4436
            result.test_bin_eq("private key encoding", priv_bytes.get(), priv_bytes2.get());
31✔
4437
            result.test_bin_eq("public key encoding", pub_bytes.get(), pub_bytes2.get());
31✔
4438

4439
            // KEM encryption (using the loaded public key)
4440
            botan_pk_op_kem_encrypt_t kem_enc;
31✔
4441
            TEST_FFI_OK(botan_pk_op_kem_encrypt_create, (&kem_enc, pub_loaded, "Raw"));
31✔
4442

4443
            // explicitly query output lengths
4444
            size_t shared_key_length = 0;
31✔
4445
            size_t ciphertext_length = 0;
31✔
4446
            TEST_FFI_OK(botan_pk_op_kem_encrypt_shared_key_length, (kem_enc, 0, &shared_key_length));
31✔
4447
            TEST_FFI_OK(botan_pk_op_kem_encrypt_encapsulated_key_length, (kem_enc, &ciphertext_length));
31✔
4448

4449
            // check that insufficient buffer space is handled correctly
4450
            size_t shared_key_length_out = 0;
31✔
4451
            size_t ciphertext_length_out = 0;
31✔
4452
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
31✔
4453
                        botan_pk_op_kem_encrypt_create_shared_key,
4454
                        (kem_enc,
4455
                         rng,
4456
                         nullptr /* no salt */,
4457
                         0,
4458
                         0 /* default key length */,
4459
                         nullptr,
4460
                         &shared_key_length_out,
4461
                         nullptr,
4462
                         &ciphertext_length_out));
4463

4464
            // TODO: should this report both lengths for usage convenience?
4465
            result.test_is_true(
31✔
4466
               "at least one buffer length is reported",
4467
               shared_key_length_out == shared_key_length || ciphertext_length_out == ciphertext_length);
31✔
4468

4469
            // allocate buffers (with additional space) and perform the actual encryption
4470
            shared_key_length_out = shared_key_length * 2;
31✔
4471
            ciphertext_length_out = ciphertext_length * 2;
31✔
4472
            Botan::secure_vector<uint8_t> shared_key(shared_key_length_out);
31✔
4473
            std::vector<uint8_t> ciphertext(ciphertext_length_out);
31✔
4474
            TEST_FFI_OK(botan_pk_op_kem_encrypt_create_shared_key,
31✔
4475
                        (kem_enc,
4476
                         rng,
4477
                         nullptr /* no salt */,
4478
                         0,
4479
                         0 /* default key length */,
4480
                         shared_key.data(),
4481
                         &shared_key_length_out,
4482
                         ciphertext.data(),
4483
                         &ciphertext_length_out));
4484
            result.test_sz_eq("shared key length", shared_key_length, shared_key_length_out);
31✔
4485
            result.test_sz_eq("ciphertext length", ciphertext_length, ciphertext_length_out);
31✔
4486
            shared_key.resize(shared_key_length_out);
31✔
4487
            ciphertext.resize(ciphertext_length_out);
31✔
4488
            TEST_FFI_OK(botan_pk_op_kem_encrypt_destroy, (kem_enc));
31✔
4489

4490
            // KEM decryption (using the generated private key)
4491
            botan_pk_op_kem_decrypt_t kem_dec;
31✔
4492
            TEST_FFI_OK(botan_pk_op_kem_decrypt_create, (&kem_dec, priv, "Raw"));
31✔
4493
            size_t shared_key_length2 = 0;
31✔
4494
            TEST_FFI_OK(botan_pk_op_kem_decrypt_shared_key_length, (kem_dec, shared_key_length, &shared_key_length2));
31✔
4495
            result.test_sz_eq("shared key lengths are consistent", shared_key_length, shared_key_length2);
31✔
4496

4497
            // check that insufficient buffer space is handled correctly
4498
            shared_key_length_out = 0;
31✔
4499
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
31✔
4500
                        botan_pk_op_kem_decrypt_shared_key,
4501
                        (kem_dec,
4502
                         nullptr /* no salt */,
4503
                         0,
4504
                         ciphertext.data(),
4505
                         ciphertext.size(),
4506
                         0 /* default length */,
4507
                         nullptr,
4508
                         &shared_key_length_out));
4509
            result.test_sz_eq("reported buffer length requirement", shared_key_length, shared_key_length_out);
31✔
4510

4511
            // allocate buffer (double the size) and perform the actual decryption
4512
            shared_key_length_out = shared_key_length * 2;
31✔
4513
            Botan::secure_vector<uint8_t> shared_key2(shared_key_length_out);
31✔
4514
            TEST_FFI_OK(botan_pk_op_kem_decrypt_shared_key,
31✔
4515
                        (kem_dec,
4516
                         nullptr /* no salt */,
4517
                         0,
4518
                         ciphertext.data(),
4519
                         ciphertext.size(),
4520
                         0 /* default length */,
4521
                         shared_key2.data(),
4522
                         &shared_key_length_out));
4523
            result.test_sz_eq("shared key output length", shared_key_length, shared_key_length_out);
31✔
4524
            shared_key2.resize(shared_key_length_out);
31✔
4525
            TEST_FFI_OK(botan_pk_op_kem_decrypt_destroy, (kem_dec));
31✔
4526

4527
            // final check and clean up
4528
            result.test_bin_eq("shared keys match", shared_key, shared_key2);
31✔
4529

4530
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
31✔
4531
            TEST_FFI_OK(botan_pubkey_destroy, (pub_loaded));
31✔
4532
            TEST_FFI_OK(botan_privkey_destroy, (priv));
31✔
4533
            TEST_FFI_OK(botan_privkey_destroy, (priv_loaded));
31✔
4534
         }
62✔
4535
      }
3✔
4536
};
4537

4538
/**
4539
 * Base class for roundtrip tests of FFI bindings for Signature Mechanisms.
4540
 */
4541
class FFI_Signature_Roundtrip_Test : public FFI_Test {
4✔
4542
   protected:
4543
      using privkey_loader_fn_t = int (*)(botan_privkey_t*, const uint8_t[], size_t, const char*);
4544
      using pubkey_loader_fn_t = int (*)(botan_pubkey_t*, const uint8_t[], size_t, const char*);
4545

4546
   protected:
4547
      virtual const char* algo() const = 0;
4548
      virtual privkey_loader_fn_t private_key_load_function() const = 0;
4549
      virtual pubkey_loader_fn_t public_key_load_function() const = 0;
4550
      virtual std::vector<const char*> modes() const = 0;
4551
      virtual const char* hash_algo_or_padding() const = 0;
4552

4553
   public:
4554
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
2✔
4555
         const std::vector<uint8_t> message1 = {'H', 'e', 'l', 'l', 'o', ' '};
2✔
4556
         const std::vector<uint8_t> message2 = {'W', 'o', 'r', 'l', 'd', '!'};
2✔
4557

4558
         for(const auto* mode : modes()) {
17✔
4559
            // generate a key pair
4560
            botan_privkey_t priv;
15✔
4561
            botan_pubkey_t pub;
15✔
4562
            if(!TEST_FFI_INIT(botan_privkey_create, (&priv, algo(), mode, rng))) {
15✔
4563
               continue;
×
4564
            }
4565
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
15✔
4566

4567
            // raw-encode the key pair
4568
            ViewBytesSink priv_bytes;
15✔
4569
            ViewBytesSink pub_bytes;
15✔
4570
            TEST_FFI_OK(botan_privkey_view_raw, (priv, priv_bytes.delegate(), priv_bytes.callback()));
15✔
4571
            TEST_FFI_OK(botan_pubkey_view_raw, (pub, pub_bytes.delegate(), pub_bytes.callback()));
15✔
4572

4573
            // decode the key pair from raw encoding
4574
            botan_privkey_t priv_loaded;
15✔
4575
            botan_pubkey_t pub_loaded;
15✔
4576
            TEST_FFI_OK(private_key_load_function(),
15✔
4577
                        (&priv_loaded, priv_bytes.get().data(), priv_bytes.get().size(), mode));
4578
            TEST_FFI_OK(public_key_load_function(),
15✔
4579
                        (&pub_loaded, pub_bytes.get().data(), pub_bytes.get().size(), mode));
4580

4581
            // re-encode and compare to the first round
4582
            ViewBytesSink priv_bytes2;
15✔
4583
            ViewBytesSink pub_bytes2;
15✔
4584
            TEST_FFI_OK(botan_privkey_view_raw, (priv_loaded, priv_bytes2.delegate(), priv_bytes2.callback()));
15✔
4585
            TEST_FFI_OK(botan_pubkey_view_raw, (pub_loaded, pub_bytes2.delegate(), pub_bytes2.callback()));
15✔
4586
            result.test_bin_eq("private key encoding", priv_bytes.get(), priv_bytes2.get());
15✔
4587
            result.test_bin_eq("public key encoding", pub_bytes.get(), pub_bytes2.get());
15✔
4588

4589
            // Signature Creation (using the loaded private key)
4590
            botan_pk_op_sign_t signer;
15✔
4591
            TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv_loaded, hash_algo_or_padding(), 0));
15✔
4592

4593
            // explicitly query the signature output length
4594
            size_t sig_output_length = 0;
15✔
4595
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_output_length));
15✔
4596

4597
            // pass a message to the signer
4598
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message1.data(), message1.size()));
15✔
4599
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message2.data(), message2.size()));
15✔
4600

4601
            // check that insufficient buffer space is handled correctly
4602
            size_t sig_output_length_out = 0;
15✔
4603
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
15✔
4604
                        botan_pk_op_sign_finish,
4605
                        (signer, rng, nullptr, &sig_output_length_out));
4606
            result.test_sz_eq("reported sig lengths are equal", sig_output_length, sig_output_length_out);
15✔
4607

4608
            // Recreate signer and try again
4609
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
15✔
4610
            TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv_loaded, hash_algo_or_padding(), 0));
15✔
4611
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message1.data(), message1.size()));
15✔
4612
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message2.data(), message2.size()));
15✔
4613

4614
            // allocate buffers (with additional space) and perform the actual signing
4615
            sig_output_length_out = sig_output_length * 2;
15✔
4616
            Botan::secure_vector<uint8_t> signature(sig_output_length_out);
15✔
4617
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_output_length_out));
15✔
4618
            result.test_sz_eq("signature length", sig_output_length, sig_output_length_out);
15✔
4619
            signature.resize(sig_output_length_out);
15✔
4620
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
15✔
4621

4622
            // Signature verification (using the generated public key)
4623
            botan_pk_op_verify_t verifier;
15✔
4624
            TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, hash_algo_or_padding(), 0));
15✔
4625
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message1.data(), message1.size()));
15✔
4626
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message2.data(), message2.size()));
15✔
4627

4628
            // Verify signature
4629
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
15✔
4630
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
15✔
4631

4632
            // Verify signature with wrong message (only first half)
4633
            TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, hash_algo_or_padding(), 0));
15✔
4634
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message1.data(), message1.size()));
15✔
4635
            TEST_FFI_RC(
15✔
4636
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
4637
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
15✔
4638

4639
            // Cleanup
4640
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
15✔
4641
            TEST_FFI_OK(botan_pubkey_destroy, (pub_loaded));
15✔
4642
            TEST_FFI_OK(botan_privkey_destroy, (priv));
15✔
4643
            TEST_FFI_OK(botan_privkey_destroy, (priv_loaded));
15✔
4644
         }
15✔
4645
      }
2✔
4646
};
4647

4648
class FFI_Kyber512_Test final : public FFI_Test {
1✔
4649
   public:
4650
      std::string name() const override { return "FFI Kyber512"; }
1✔
4651

4652
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
4653
         const std::vector<uint8_t> a_pub_bits = Botan::hex_decode(
1✔
4654
            "5fc44b99d7584f38cd28360cc5625a905b96af12930ed5b5fe2a82fc5aa7dc4b829fe37635f13f5af2a6d3081dad878785698a0aa914374c4e43b89f094a7892aa149a38b49c06a068d829a8d249e753a375d097a0f162e6c3a4dfe8c79761410c605ed3899a3fc44378e14f28879e8f148077e6bc3bb2ae56178c491611bf6aaf5f9a9cb9b5659223007940bcd6f8a23280a56015330e8577259587b12606f4c937ea13606cb3bb046066ad294261e2b22022bcc74678a5520570d88e4ceb42692631e7e3711c4b2fd5347f0328598340cb3c65c8f55ac02716831094cb6eb90f175b173d9c650329aaf513633633bb2ce6858e7447abc41b6fb06da8782572c332b09660366926bf529ed8caaa6243ccdb152b36ba6e47c714145c86f5b3b61de84ef1470d03fa0135e35194fa1fb3bc860fa500d1299aee88ce56054376c1199c553dd90a8d6f9cc763c811d0c66da6f851abf1056635a34a68aa7815868f153a3a5c77fcc8b1eb1807fbf62a6fb43b355700e78230943a2ba1e11b181345b11b4d46266e7b359f074a500c8857d79ba60f64262d662ccd9c8489a4c19df67437db193f95b9765181d9152262b1166f97be53497f001cb1be79024d6a2289bcc704e1b1d821015366a3cc8a484e6bc2e1f1b889f19323e3101aa09ad9ea62ba4005039bbfb5998055f93fbf77b14433116d5958422654dada1127213f02b78717a5a0454271d5b0c02517a6c27a3c3610101d753c09a25571775477dc13b2e404db4965b9a9350330c73a8a3642d39af8a23839ab85c6355b12f279f849813c280d54c5913e99b6946a0aaf012c8cab025396b255f002d837c761d42a4aeb38c5f456aaf79e162700c6b4048eca6f9a7367f90238d67bcf8e6a0d8a553c071522f9d2394e28483d2048be2a8f9c8c8e39991a41273c7eacaefc6a308be870b45b41176412954a1a0fd83d362a5ab288663dec5456b6286d0b2cecb01922fb3d473802ea2b86639bce02450339261cffb114e1e725e90677826a1688f686b29a78779c9822315dafc55753e98c8ed3221f2b3220805c8a28983355207da36fb72f9bc85c0a13b9d041586fd583feb12afd5a402dd33b43543f5fa4eb436c8d");
1✔
4655
         const std::vector<uint8_t> b_priv_bits = Botan::hex_decode(
1✔
4656
            "cf8c33fabbc3e6685f60779a456412e9060a792a3f67d90389815773e06dd2071e3906a1159921485b6221b73dfc723da9d45bbc99523c55b203f81856ba8d38f731c6594a0a9796f485c7cad02ee3a80a737cada2e40b580a1060a1364d365169539ce4d800eab9723153c5b266853b3a33112ccb03491e77f57aeb74c7670426c5bb02615b1907b353beda51f38a788774b1c9eb3c49f89df59ba00e196f180a37fd9acd6691b493d78f95a49906b26fa46125663a37b0b2614197473ba012956bc9348a9afc8907527bb7c2dcbd384b85630b3687096ffd9a93d603121706c06c05baca286bebea0ecdf391ba489d7ff6a7a1c7c3dd0c521c02bb3fa7c3e5b98f19509486ab33f1597346b03c7197865792896c1a553e8379c6f51729e9907d09b4fbc5b4279298f60195998225d95c2aef335c9e6a26f4988e0f19c307fc00f8aa0b21090daab0c540363f121044729322bebb97427227e8b01705826879ab4d42e30bf191068b705527a3ae9a5b3e30371c50b5b75d189903e60175f904c1488be7e872d3dc3be1bb31921027cb075f6bb051c28980c65b9959e8acf2d38671d27285d03419512008335492476e0c23ac6263425f8a65fbc1a38110b38db641f3a9872fa312d26b9c81f11de1d9378b629e9bdc7ca31496ac9511bff42a7a96b28f740a84c2904fe4056ca1989b28439222cee31c554e982d318366037070c4bb778b261e3479c605317922947e4340560732ca8fda63e2a7ac8cc67015e97d308c361e634f8cdb1e836b572367334c949011a9c52f391194baa91f08a71e847d3be202554ab1c4f871c9b26db5f4992db5b3688b1ea877925d02895d470b9659c51213b206b82de489455c6502856b841d000aab3c065ff6720f9222914b6421224d716684a7762fc98ba7f4655f4cfa82fc52472b01b1e22255fc990b20240b802034c99777b71b5c0d8a4c733b69d5f76ddfdb1128da3e194c1169a924f5d868d1dbc4ddcb30197c25005391c1fcc098010af1e9ab72bc8c3bd1c58b15583035bc2dd0898e148fb20b8c502a31489b00dd645ab24709bff5c37d1a7fee5c56d7490ae77a61b1c5951e359d2a89a946f200b1f647c0283de5d403282c693dfccca1c1b54804ab86f36e1f16550a77b75328916c770c225b142dfb750659ba6d532003f8b6d48825b122682051acda7c20f09117b3e5c93e8c1bd446672512947d964f0484a05b85af82f4401d323484d23373c0c6c8990a3fba70f8a2c13e7350ce945c8f4882b1929f10d18bb45a883c116d1ce06493a50580069743d26062da9171006405d27e2f7220a897024dca507b737a6c32ba3d925e15c9789589507a768ca075beb2fb17a17144c52810566a972dba60ad806a2ff15957a3bbd85a8f1ef34445d18cc668ca7a8ac5fc7545934221a4c92c60024069cc34d592ac30c88c3376bc133622e2b192e9b4b60a9a84e5304873e62d6f98103cc8c43f6024fb7739418cc2602b21416040220cb3ec588679c033d61a3c697c403463c17c13a63d7304044a9f024b907b440b39b7b6423723dda943447a900af0170144755d9a968f634e26f892ee19cd00a97b48d5041b4473ec8741e077126f85bbb8334b8b2cbd63429afa543a540740c1e56893f6b2f2f7c42a12bcd48c647726cca06841212656ff9b3d3e799e92c48414d653a61ca8dc2c49b7342469a868b7938db8d7844e6311134b2c30538ffa927ee3961a44e0a66438c5643aa1d13658fe8a7c2a84702a8211422831994ca1e801131ab88a25162d3cd988ebe09e6cb01ca7324256691635c536f576990664841b7c89b0dc325472271fdc2b0824a9514b5eb46a743f9734ee20648a407f5d505cc9614748f344a16950b5483e45516236d43afd1494d564c23e20b64a124593604404c879a776a5bd9399629600e86aa1a641be7a13418cda318bbc3af0c2a66c999841251a1c2868b05028f6a56a72c33d8a653c77f69af4247dc6f80d329921ce3355894605c35372ddf0c84cacb42d6ccbdf39a55b672a891749622a011747a01625764c788413f2c0fd877275c88fd5730fa9e87a3c783702223a4443525cc5b5381c976dd9cb08ac47490125ca5c70baac01ff9143bc40ceeb2a16c1529d70c07074a0013749656ff4b16d890868b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb3338e5d6352d5a5006d7cd901489e7f851711c08e00cd4162ccfc2564d5893d52b2c7300e2d894b0eaa40a6ab254506d8c1176a33c4a1b2879604b1b80df48d31dd");
1✔
4657
         const std::vector<uint8_t> b_pub_bits = Botan::hex_decode(
1✔
4658
            "ee5c56d7490ae77a61b1c5951e359d2a89a946f200b1f647c0283de5d403282c693dfccca1c1b54804ab86f36e1f16550a77b75328916c770c225b142dfb750659ba6d532003f8b6d48825b122682051acda7c20f09117b3e5c93e8c1bd446672512947d964f0484a05b85af82f4401d323484d23373c0c6c8990a3fba70f8a2c13e7350ce945c8f4882b1929f10d18bb45a883c116d1ce06493a50580069743d26062da9171006405d27e2f7220a897024dca507b737a6c32ba3d925e15c9789589507a768ca075beb2fb17a17144c52810566a972dba60ad806a2ff15957a3bbd85a8f1ef34445d18cc668ca7a8ac5fc7545934221a4c92c60024069cc34d592ac30c88c3376bc133622e2b192e9b4b60a9a84e5304873e62d6f98103cc8c43f6024fb7739418cc2602b21416040220cb3ec588679c033d61a3c697c403463c17c13a63d7304044a9f024b907b440b39b7b6423723dda943447a900af0170144755d9a968f634e26f892ee19cd00a97b48d5041b4473ec8741e077126f85bbb8334b8b2cbd63429afa543a540740c1e56893f6b2f2f7c42a12bcd48c647726cca06841212656ff9b3d3e799e92c48414d653a61ca8dc2c49b7342469a868b7938db8d7844e6311134b2c30538ffa927ee3961a44e0a66438c5643aa1d13658fe8a7c2a84702a8211422831994ca1e801131ab88a25162d3cd988ebe09e6cb01ca7324256691635c536f576990664841b7c89b0dc325472271fdc2b0824a9514b5eb46a743f9734ee20648a407f5d505cc9614748f344a16950b5483e45516236d43afd1494d564c23e20b64a124593604404c879a776a5bd9399629600e86aa1a641be7a13418cda318bbc3af0c2a66c999841251a1c2868b05028f6a56a72c33d8a653c77f69af4247dc6f80d329921ce3355894605c35372ddf0c84cacb42d6ccbdf39a55b672a891749622a011747a01625764c788413f2c0fd877275c88fd5730fa9e87a3c783702223a4443525cc5b5381c976dd9cb08ac47490125ca5c70baac01ff9143bc40ceeb2a16c1529d70c07074a0013749656ff4b16d890868b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb333");
1✔
4659

4660
         botan_privkey_t b_priv;
1✔
4661
         if(!TEST_FFI_INIT(botan_privkey_load_kyber, (&b_priv, b_priv_bits.data(), 1632))) {
1✔
4662
            return;
×
4663
         }
4664

4665
         ViewBytesSink privkey_read;
1✔
4666
         ViewBytesSink privkey_read_raw;
1✔
4667
         TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.delegate(), privkey_read.callback()));
1✔
4668
         TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.delegate(), privkey_read_raw.callback()));
1✔
4669
         result.test_bin_eq("kyber512 private key", privkey_read.get(), b_priv_bits);
1✔
4670
         result.test_bin_eq("kyber512 private key raw", privkey_read_raw.get(), b_priv_bits);
1✔
4671

4672
         ViewBytesSink pubkey_read;
1✔
4673
         ViewBytesSink pubkey_read_raw;
1✔
4674

4675
         botan_pubkey_t b_pub;
1✔
4676
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
4677
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4678
         TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.delegate(), pubkey_read_raw.callback()));
1✔
4679
         result.test_bin_eq("kyber512 public key b", pubkey_read.get(), b_pub_bits);
1✔
4680
         result.test_bin_eq("kyber512 raw public key b", pubkey_read_raw.get(), b_pub_bits);
1✔
4681

4682
         botan_pubkey_t a_pub;
1✔
4683
         TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 800));
1✔
4684
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (a_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4685
         result.test_bin_eq("kyber512 public key a", pubkey_read.get(), a_pub_bits);
1✔
4686

4687
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
4688
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
4689
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
1✔
4690
      }
1✔
4691
};
4692

4693
class FFI_Kyber768_Test final : public FFI_Test {
1✔
4694
   public:
4695
      std::string name() const override { return "FFI Kyber768"; }
1✔
4696

4697
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
4698
         const std::vector<uint8_t> a_pub_bits = Botan::hex_decode(
1✔
4699
            "38d4851e5c010da39a7470bc1c80916f78c7bd5891dcd3b1ea84b6f051b346b803c1b97c94604020b7279b27836c3049ea0b9a3758510b7559593237ade72587462206b709f365848c96559326a5fe6c6f4cf531fd1a18477267f66ba14af20163c41f1138a01995147f271ddfc2be5361b281e6029d210584b2859b7383667284f767bb32782baad10933da0138a3a0660a149531c03f9c8ffccb33e3c3a5a7984e21fab26aa72a8a6b942f265e52551a9c800e5a44805f0c0141a05554213387f105df56458496bd8f469051886da223cb9fe78e7b390bf94b0a937691af9550082b76d045cb4d29c23c67942608d078a1c80f24767a945d19f077d82c9b9b197073464abe69cf7c5626177308f384672d5263b0c4826db4470e1a70e4751e3918abe8fcbc3bc0531ae89e5512214b5cc94a16a014bcb3826c79fbf4add0825eeefbab88cb7cff37bb8d491f8de902578a1e961655565b7718782a23504fdc13c783f130e177925e305d1fbc63cc8c15c2c67f85500cca785de9f480490558ef71aaf0fb5b513914401269b309c4c59c64d2a757d8855f58465615925f1ea6812cb143fff383e1048e285118bf932944b86fbdf4b1b9e65685664a07775c46952aaada1168f54b47c7a231e7355c64637467b5a3c09cab67bb35f58640c2726283bb63530a15f66eca48a840c00ca8862e283c73bfbb413a2915b8d1159a043f12c59bfa828248249b76106faa61a127a0280c586350e7a42cb74ca49cabd606891ec7cb8e84affe4b2e14c71658332b755611bab7977fa76ce736b21ed34a17ac0ec3561ca9b282d4a2bc407697924b1cf918ba83d3a4fdc82564c95bd904bdeee91ed6ccb36baa88a05c80712901bf280aee6538ec2078c2a84ee5862fc137cd92e97968d69fc3453a1e1cb161c50c9f2473a0d09037b188a0fa01efc344c2ac8fe8592b0a58456662a95033659a158a2d90a6e50c253a87975785ce29c4570000a154d4b3b2c642205c8c7cf9ac6b1071fbb368ab950a744b88c95ba5243017831120a9048338d29847830d12a933a09abd21a46b828cb14e808cd35129c9dc6e5b931d4a126fefe07909618e2b4586e7b6b424963b7323ba505ba112bb9b834a7d1b78ad0df53d556a1c69369f09148b1dc9938df59223f087fd6833be5b2bc2651fe58911ac01467f9297dfdc22b41a0f1702718710b78cf35b1865813a896d45214d338155b6c043c532330c002d520739467a504a866637fb3451c849f8f83e6a94147f168da53acdf9d8affd968a84124a9abc09af960cd3b29f2344831bb41e67605eebf00df202857117399dd748b6514aed61bb2f6cb841d168d5f35e20054573a331cd4882a04b072c179158825bcf471266da0dcceab1a021c73254751d5a161c1a92062c220a217a69d9823314b4de996fe8d45f6db5af16c1561495a4c43090bc394c94e1b0ec738eb56267201c2ecd1c7b4993c0efc0284bdc9a091c294f95703a7178822c8a95b79b1e4591e0998d893875c1a879c08a073cc67df426bba792c18ae6c1feba879bec54812c2affa012973b700ad48e271078280864268600a7aa309eaa1098750a0f8a522eb929577b412f7855613688b72f9bc85c0a13b9d041586fd583feb12afd5a402dd33b43543f5fa4eb436c8d");
1✔
4700
         const std::vector<uint8_t> b_priv_bits = Botan::hex_decode(
1✔
4701
            "9bc4986eec853ac90896c7300f914216773baa687f57f81f94e6b5a26515c0a74c73b19dc6b9888755a1d1db6a1128b02c5144ed9ba75e874a68a14dee3a9bf770b767121fbbdb292e097444757fe2f324a875b0a07a4fbdcc8fd6137fce80c69f412be103b01f8b3bed392600f830d1b20d73ca0b386666d16c5d96db10e309041890bfd4ab7bdec27191979abe7637e76153918cc2af1545724abfd95ca496281a0cc6ca63a87819b75aa86452e5027d429cad64a9c029112a3a7b9fb993c6a6d0671f6c9e24986b83f67cf1236d94c051559616826a947eaa15074025d1ab810c80220e8a8c2c222d4e8594bf35811b444a57e9bf94fb2479d174d6b38c8c3b4730437c244b2513232ec798adec4a8e597bca83bca5948468f93c022ba65311a91e3d95c299c70c3f1a43cd0c83dd500bd2211b9b385b82f2c003b10d295765b3e367563a5f19033fc1231db9620f835c95f5a261190a5da1c24ed528316f0a1520d223e208a8c99b24d28598ade74fc88370e7f45102c5a6411891c661b356b9a32e1cc0fafaa085d7670e8bcb5e768eb255204f2445b5b73b04079881903a553c865744343a925c7899777b1c9dd5579a481512f8157061606a9a67c041d38bc179048be17dd9e19dc0a572bce595afa3b68ff21bf78a63a7560636b6bb01ec3362e2aaabc8965818b7f2417ca8f66a5a2a67f72a3931e125d638a872862a7b680a54aa1f25d90dbd567635ec6664919e29517325a5c5048cc8d1c31af5e4866e85025b9184a7b75ed7f2c9c8d88259fa2ec5b05ed3751584f88308c67ff1a72fa2453305160baf404db7d4be56f1547b20bb7dec23f02b10db584b28ca40d8b39c1c3ab9f3d7bbda0822604ca48f26694d69810aa888ae3c0983c5ba4cb74211f7a5361ccdee694f4202aebe13a75b1b2dda1b3232376be213582afc4fde3474766671fe865e2fd98384eb65b2f349f1e24269b91bd9d08c80849735a9951304afd130b5c2211314630aed4b6ac3b1252a0999ff5a3ec26a283342389d219fd243706128b389eb2334fb2a6184a4eab6735d7428df5633ce030b8f853ee47c4401fc5d06b43c9b66b7aeeb23b5f000a30a6f88f027ee3994fe8b63e51b83bc24bb733a3773a35cbe138f6d9c91a3a3898bca6776030d740ac355176547d624719656a9a44e91c63faf7699dc6c2c45575718d48828828b39043c2fda2af416837efc38d17c56d4b63c63a5ab43434647d029f7b236b288958f06910763610f8b2f027a8dcd780039ab34a6871427476ff6500240e83b87c95dcfa45ac5315ef34b343fb609eb296e915c849bb8c57f57c69b177eaa8456377403fe8c6627a3282d45308f675d67085a15f0b1b55aa2a8f21afd6c05c3c00e9eb8c32418cb41963ce427b43e7545c58325c7b9368db2333de424dbeb3430f007d18a68d73b7dc67960b28206a68a1be400a770b5cd9d45a72824ca00345ac56491c1414fe5287a2eb2ad61f3bdcd0c84c335b04a703425d79dbd02b0a0e90de5b331c3c29f6562969e04cdf7095b2a7646b3d006b0b83cb68580b5ccb71de1b4d9f131bac133d6088e10613a00599d81d4818403a4bea83905304cc45ca645a9b2c6484cf9490f1755c744d9988ed60475e6ae44355ed15c7b549366f29581ec2721fd6704e0ca3f878812805675141c0a15a7b7ac35a9e3f8b2a010bc184981c57852895b2695d56131e32326717f6b101df1bc82b3ba0222d52656d118538c4ca3416be1c76ba37a9901a36e4883be6c541f2bbb561818cd2f136b98f658250545c1fa5bcfdc04374016db1c5132447fd6d568866451c25412f72967de868eaeb9c546fb40ea88cd84a1a586ca51c74bc9c3e56e104323afb658d1ac003151bdc35879a4b6762648bff0caa682f1b3319805d2326d5a46af832aacefbaa1ea820568ea3925870e9b6577eb93898e1b0cfbd1c995cb4cd6cabb979813819749b40a9952f50e97c4365e777dcfe9084219294c205acb350e07db9c98f53444546460962e2bf5aa1cc12273d882fcc215a7397b3f9b307c56b9a0429b30f88453a2376669b28b4bc4b84b51714b6652b7a1a0b53e9ec61b55ca51cdb38243239ee5f18243e515f178768a888f475b3d9060136bb22ee355b3da02c16ad83bdbb4aaa13809cb4bcd5bb53710737d3883632f9254e3336af61621a376720572450e3937c0d930e349adbfa7642ff822b9135e18f943e0178617604d10e0c09ffb3e09783c09d12cbe93311757af9857b77d1488ed39321ca97c3745c5bc176ca81274c8321bcb2029938b32bbd01aec137032f9760849701649120050b50d8353c36b8bb7724a67e7660fc93324065d63912c35a86d8fe60683067bbd2685c552ad8c65c77c57c937676fd61595c453174bf996e9d3a9ccb837b25464115c1ba3343ac097b80735aed3225091167cd8f841ffe49c5e698ef542124253084623179394433a4b61547b9ee09c98c2736ea086bd69d1bc7ae68a6ae5ce682a215860006b4604dee45a3e212f97643acb77a79a880382e483537c5198d4483a176d25aac9c3670a3f30956f18ad441904776bcd48131c7d6465bce0c133010f3176c92ec962f5c6b84d4c3ae949619cf48172997ca3b1ccf5c8cc7a67923e1295801048a3d40ac4f2c6467c750fc71314a0c1fc22637dd52e7ea50907ea973d765a6a9bb2b11aa405b9187f72026696710e61af3e41c33da1a05eb65e6523704f078e74e32f10e00247967aee3a8c6546889ef67cd613ad7236583f2104122ac6c6a40a84dc96d81c569e76a952c0a25f396e48337a4fe029a4c91cc7406872706a55573b75f160a4facad7c85fab141c63454bf48990729096ce9965604c7cc1e60ae6868dcc41bc3df71c3e5593f0488b0c6a3063e817f9f4bacb17599c8666ff3591126b4891fb7f5d29660bab60cf5007043a4311d41ab3b29787184f3d3c9ab7cc247f635145b67e970505ba44ad0e06b11ec5cda4175295199d19d660204cbdc17947cc66442d3a2cd408a20fe98174f31ee4e5bb3fa8bcd102bedc26527e9bae836442978a6ccbe510f93ab77569ab1f09d0e6312dd0cc0bcaf095fa8a52a7212d14714a7bf852416c9b026301bd965c30a43d24d97298346a46b2c4bc814ba4059653358b03c9456c60bf0193932eaa2f24ea8e4b010a5a4425ce4540fbab90d8e55c97ac2687f15ff5299278824a08d4743e1a62e1c6619cd3278cd75a97a5b4e3a38668b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb3339ae9c9ce46d9da0e714c0bae8712a670d0e5dcfdd1dd0d045932c79c559b2ab3c7300e2d894b0eaa40a6ab254506d8c1176a33c4a1b2879604b1b80df48d31dd");
1✔
4702
         const std::vector<uint8_t> b_pub_bits = Botan::hex_decode(
1✔
4703
            "f9490f1755c744d9988ed60475e6ae44355ed15c7b549366f29581ec2721fd6704e0ca3f878812805675141c0a15a7b7ac35a9e3f8b2a010bc184981c57852895b2695d56131e32326717f6b101df1bc82b3ba0222d52656d118538c4ca3416be1c76ba37a9901a36e4883be6c541f2bbb561818cd2f136b98f658250545c1fa5bcfdc04374016db1c5132447fd6d568866451c25412f72967de868eaeb9c546fb40ea88cd84a1a586ca51c74bc9c3e56e104323afb658d1ac003151bdc35879a4b6762648bff0caa682f1b3319805d2326d5a46af832aacefbaa1ea820568ea3925870e9b6577eb93898e1b0cfbd1c995cb4cd6cabb979813819749b40a9952f50e97c4365e777dcfe9084219294c205acb350e07db9c98f53444546460962e2bf5aa1cc12273d882fcc215a7397b3f9b307c56b9a0429b30f88453a2376669b28b4bc4b84b51714b6652b7a1a0b53e9ec61b55ca51cdb38243239ee5f18243e515f178768a888f475b3d9060136bb22ee355b3da02c16ad83bdbb4aaa13809cb4bcd5bb53710737d3883632f9254e3336af61621a376720572450e3937c0d930e349adbfa7642ff822b9135e18f943e0178617604d10e0c09ffb3e09783c09d12cbe93311757af9857b77d1488ed39321ca97c3745c5bc176ca81274c8321bcb2029938b32bbd01aec137032f9760849701649120050b50d8353c36b8bb7724a67e7660fc93324065d63912c35a86d8fe60683067bbd2685c552ad8c65c77c57c937676fd61595c453174bf996e9d3a9ccb837b25464115c1ba3343ac097b80735aed3225091167cd8f841ffe49c5e698ef542124253084623179394433a4b61547b9ee09c98c2736ea086bd69d1bc7ae68a6ae5ce682a215860006b4604dee45a3e212f97643acb77a79a880382e483537c5198d4483a176d25aac9c3670a3f30956f18ad441904776bcd48131c7d6465bce0c133010f3176c92ec962f5c6b84d4c3ae949619cf48172997ca3b1ccf5c8cc7a67923e1295801048a3d40ac4f2c6467c750fc71314a0c1fc22637dd52e7ea50907ea973d765a6a9bb2b11aa405b9187f72026696710e61af3e41c33da1a05eb65e6523704f078e74e32f10e00247967aee3a8c6546889ef67cd613ad7236583f2104122ac6c6a40a84dc96d81c569e76a952c0a25f396e48337a4fe029a4c91cc7406872706a55573b75f160a4facad7c85fab141c63454bf48990729096ce9965604c7cc1e60ae6868dcc41bc3df71c3e5593f0488b0c6a3063e817f9f4bacb17599c8666ff3591126b4891fb7f5d29660bab60cf5007043a4311d41ab3b29787184f3d3c9ab7cc247f635145b67e970505ba44ad0e06b11ec5cda4175295199d19d660204cbdc17947cc66442d3a2cd408a20fe98174f31ee4e5bb3fa8bcd102bedc26527e9bae836442978a6ccbe510f93ab77569ab1f09d0e6312dd0cc0bcaf095fa8a52a7212d14714a7bf852416c9b026301bd965c30a43d24d97298346a46b2c4bc814ba4059653358b03c9456c60bf0193932eaa2f24ea8e4b010a5a4425ce4540fbab90d8e55c97ac2687f15ff5299278824a08d4743e1a62e1c6619cd3278cd75a97a5b4e3a38668b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb333");
1✔
4704

4705
         botan_privkey_t b_priv;
1✔
4706
         if(!TEST_FFI_INIT(botan_privkey_load_kyber, (&b_priv, b_priv_bits.data(), 2400))) {
1✔
4707
            return;
×
4708
         }
4709

4710
         ViewBytesSink privkey_read;
1✔
4711
         ViewBytesSink privkey_read_raw;
1✔
4712
         TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.delegate(), privkey_read.callback()));
1✔
4713
         TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.delegate(), privkey_read_raw.callback()));
1✔
4714
         result.test_bin_eq("kyber768 private key", privkey_read.get(), b_priv_bits);
1✔
4715
         result.test_bin_eq("kyber768 private key raw", privkey_read_raw.get(), b_priv_bits);
1✔
4716

4717
         ViewBytesSink pubkey_read;
1✔
4718
         ViewBytesSink pubkey_read_raw;
1✔
4719

4720
         botan_pubkey_t b_pub;
1✔
4721
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
4722
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4723
         TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.delegate(), pubkey_read_raw.callback()));
1✔
4724
         result.test_bin_eq("kyber768 public key b", pubkey_read.get(), b_pub_bits);
1✔
4725
         result.test_bin_eq("kyber768 public key raw b", pubkey_read_raw.get(), b_pub_bits);
1✔
4726

4727
         botan_pubkey_t a_pub;
1✔
4728
         TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 1184));
1✔
4729
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (a_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4730
         result.test_bin_eq("kyber768 public key a", pubkey_read.get(), a_pub_bits);
1✔
4731

4732
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
4733
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
4734
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
1✔
4735
      }
1✔
4736
};
4737

4738
class FFI_Kyber1024_Test final : public FFI_Test {
1✔
4739
   public:
4740
      std::string name() const override { return "FFI Kyber1024"; }
1✔
4741

4742
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
4743
         const std::vector<uint8_t> a_pub_bits = Botan::hex_decode(
1✔
4744
            "9779a4d1fc45ec261f048b9c9daa38c9ec228b6505e8905226b38486802059c2c5c89601560634cb1337b1315365144842bc405a292e683cafa4514526945c4dfb68ee2acdb8b79532836696d53125a045bdbb8a3bcc8123083d1e682c5bd7820c76c448351151474f69d601d7708dbb2c979d77527494b68520a8ff66c34162ca2aec8072a2a51ff259389648e75b95c16abe14604edbfabaf400b76a7a0f07db61dce19102f43b2d1060747b02c4425485341fd5d9bffaa7016061374963b985209c6b9a7db3f94958311d027900a3d8c44f8435b093a236a0509f1928df7719ce8c4e90228f4db87cb9e882f2712180238845d31eb906c60eb63e0ff55e84b867a91b79ae74a03ac00473c8c1b3e6aedcc37f1e69b8e136019bdb01c374a122e164c32584b2fbcf5e013a45127c893326b6860378cb5525a48b522b30132b7688214b69808dd19aa4ff033e16252016fc9479222424393e51db7115e38114e6893cdcc8ae1117a4316548010ab4629fb672148d031a6c601a6a4a661d872d8ef693750a115958716ab9263eb0516357102358cde5256464805ca8f59661751ad6a475a7ec78cb7319c3bbc544e1bb1185aaaeb751ba0b3923246e33f40a4ff4780b745362a218d169474d7208a9f7577228308af20f8d2403a27477cf53cff133a247d5c2b298bf21bac6dc44649e63afcef54ad3a07a74e447b36bacca295e053368ef7c146e1c28edb31b3777c941a7c27dc559437b0ff83c2910f827ef244d7726af2b9708654bcfb139a26844c6f4b79cd9e4747065a77596b927f96cbdbc7267ac9e32ac396f6c4ce739aa0aa60fccac178edab1e04688fe71a74201a99bc64b55f8cb89e11545e5275af48626ec667520ba8a7c88c2307e793455ef8780fae16412ea59e92406f595902dc21c612b142801cf31abc0475c7bde772d51c55a2dfc651bc5ab4143022813cc4c8cc6f52c8d27e3cd7851849a8c4343f0c7ed6c6cb9f765c5047e55bc48aad5b932128287f70939db753a61c0d7db1830c256288c1c85cc9bbce58366dac528c893d61b69850bcb82758e836936e1f8163861586482cad35b4db1437fad6980b66280b1652d72f52407a8015f85c29e75b2158933a4f5887db320b583cdcbca274eac21f8702879b8bc4afb62ba056d146512921554c765464d4c96bd3c9a9720187c3339d0593bc4bba59155469ff6b8688a5fc5fa6b46d4070668bd168c5f796492760940999927628236b2412968438d2cbc2a978abc097320291b0ed7e4631ec9bbe28ac63ab6860e976ac1552afc43897d6937a092432dc481a914c3a1273c43009e8ec523cb93ced9898f90905340ba6e01bc572d03a893fa21c4342d88dc3e77b33b1fc063dcdb689d8c4ffc840ce879cfb3471385512cc7c7591383b1fac89832bb1cb3324e6d2868918844cb20ca4df812b42824192a43380430a37a7f3ac41ed064cfe055157b91b5c0108fb7a613a0112af4d64e48f8a345328a99b7bf0c91cb037215b0177ad4c263e6d78f5958c848158e4fd2117c248e0cab3cf98c1e27868838f8428ba0562df6b61e8736e2b8b266607918e0ce2ce3af67c81fa5c2a4d2bc8e871825b702b3beca397b33a518dac8b1393d494a90900c01b55925857cbf8027051d36a4f141a4d2dc440341305e033cb50a074be459c76a339a9a52c447360dea2a5699ccea683a42430aa6fc9545c75c0492641af7a4e9267bcc384e55714cf49741eba3b69d6417a555475d3c021112b8b3588c63747b5ce2ccfee91297fa419f9c4298978fff0870d8a855b48899ca9bb47d836d62d2038cc3816f3a698bb3bbff78c7a015b0ea1960634292e1d50b03e1043a98ca9b27063e668b05e2c17d692d382b181365a818518ec747720337ca1868596af42a90fab1870373d74b8f6d42ac86b18bca3ab04764680cf2060c529abe5b8ef4474dc8cc47a8033ebd884d3e0a0f1a94420d8a3c9162b7af87a2c8a394647434f4a3bc2b477813ac82cf387185b587f7f68938eccddd6934d143ba17bb4a712566d2a55aaddb3323713667401b4a20b86c23bf1076439cb6b8c115389dba4e6f0c915be7602b9703b535070e4a5c5649a5d7080515026706b2604575cbd0687f2729a92a997d21ea7200c41ed8315275f4c7b72f9bc85c0a13b9d041586fd583feb12afd5a402dd33b43543f5fa4eb436c8d");
1✔
4745
         const std::vector<uint8_t> b_priv_bits = Botan::hex_decode(
1✔
4746
            "9bc4986eec853ac90896c7300f914216773baa687f57f81f94e6b5a26515c0a74c73b19dc6b9888755a1d1db6a1128b02c5144ed9ba75e874a68a14dee3a9bf770b767121fbbdb292e097444757fe2f324a875b0a07a4fbdcc8fd6137fce80c69f412be103b01f8b3bed392600f830d1b20d73ca0b386666d16c5d96db10e309041890bfd4ab7bdec27191979abe7637e76153918cc2af1545724abfd95ca496281a0cc6ca63a87819b75aa86452e5027d429cad64a9c029112a3a7b9fb993c6a6d0671f6c9e24986b83f67cf1236d94c051559616826a947eaa15074025d1ab810c80220e8a8c2c222d4e8594bf35811b444a57e9bf94fb2479d174d6b38c8c3b4730437c244b2513232ec798adec4a8e597bca83bca5948468f93c022ba65311a91e3d95c299c70c3f1a43cd0c83dd500bd2211b9b385b82f2c003b10d295765b3e367563a5f19033fc1231db9620f835c95f5a261190a5da1c24ed528316f0a1520d223e208a8c99b24d28598ade74fc88370e7f45102c5a6411891c661b356b9a32e1cc0fafaa085d7670e8bcb5e768eb255204f2445b5b73b04079881903a553c865744343a925c7899777b1c9dd5579a481512f8157061606a9a67c041d38bc179048be17dd9e19dc0a572bce595afa3b68ff21bf78a63a7560636b6bb01ec3362e2aaabc8965818b7f2417ca8f66a5a2a67f72a3931e125d638a872862a7b680a54aa1f25d90dbd567635ec6664919e29517325a5c5048cc8d1c31af5e4866e85025b9184a7b75ed7f2c9c8d88259fa2ec5b05ed3751584f88308c67ff1a72fa2453305160baf404db7d4be56f1547b20bb7dec23f02b10db584b28ca40d8b39c1c3ab9f3d7bbda0822604ca48f26694d69810aa888ae3c0983c5ba4cb74211f7a5361ccdee694f4202aebe13a75b1b2dda1b3232376be213582afc4fde3474766671fe865e2fd98384eb65b2f349f1e24269b91bd9d08c80849735a9951304afd130b5c2211314630aed4b6ac3b1252a0999ff5a3ec26a283342389d219fd243706128b389eb2334fb2a6184a4eab6735d7428df5633ce030b8f853ee47c4401fc5d06b43c9b66b7aeeb23b5f000a30a6f88f027ee3994fe8b63e51b83bc24bb733a3773a35cbe138f6d9c91a3a3898bca6776030d740ac355176547d624719656a9a44e91c63faf7699dc6c2c45575718d48828828b39043c2fda2af416837efc38d17c56d4b63c63a5ab43434647d029f7b236b288958f06910763610f8b2f027a8dcd780039ab34a6871427476ff6500240e83b87c95dcfa45ac5315ef34b343fb609eb296e915c849bb8c57f57c69b177eaa8456377403fe8c6627a3282d45308f675d67085a15f0b1b55aa2a8f21afd6c05c3c00e9eb8c32418cb41963ce427b43e7545c58325c7b9368db2333de424dbeb3430f007d18a68d73b7dc67960b28206a68a1be400a770b5cd9d45a72824ca00345ac56491c1414fe5287a2eb2ad61f3bdcd0c84c335b04a703425d79dbd02b0a0e90de5b331c3c29f6562969e04cdf7095b2a7646b3d006b0b83cb68580b5ccb71de1b4d9f131bac133d6088e10613a00599d81d4818403a4bea83905304cc45ca645a9b2c6484ce4f7bfbe3597f0c2c50784065abc214b5518ed8c7d427205392987d807cdfa571d09932e0a1217e7c5703dfc9be7c4a0f2f33338f316b8c203c6b84285a0957c363d3722145b592f9d6277b1b7446aa2005663b9898901da3b8978eaa8aee87a209c72bfd6cd10a2bedac527f26c419b4bb9a4ca13dba14cff5671461c4cff238d213988120c3cae3b15b607269420c14a9b23a6bb887ad048e6688528137dd5c071172bcaddd5ba4fb9acfb1712ca04aa267b0686a237414b16c4ac03525a45513a393605a29f3b4c07dc5cd082c67b770e69723c6425a23f573216c4cabd6c9c39533f16643bc6151672c466dea63fb8e2180fbcb453c5670b01c0fc7043d198b6c320bf0dfc5016d00f46dc0ba75c7369fc13b65733301b3a92c0cf8dcc1f01e33291a9974d5b5debfa3be5531c69a066a6f4230ba778502654b7e76191d3ba68b1488c848d8ef11bb9ac5a5374af6ccacd02432b247a963685127728825a162c43c1cc79a7b60f571481a3a635a18f0050cbe6f4af1a5a2224044622bb3893bc837be699d5279dac78c9d49818ebc91d4ff6cb54b294e4c378d8eb584f561d21ca87b7c77b1c551f52112ba72c4b6514bb286856e89b48b0a62bad093894474b246a515f849056c9aeb572060ee11b93e236204a8ff1784ede0c3f4c0cd0cdb2a50bd4bcb1225c0dd2caa8a129fdcb01f0e1a75da465b6b8742e4946dbe3ab21ca6c4e592d398a5700375b7b770c17e117663b51313824854585ece4a1520c59a513555f548afdc6748eb9b770b7af8adc9b3c1861efc00ebde93f91fa1539c3411ec9b154c93d1f508b9714cdd0aaabcb436951aa54978b84faa8bd838c29a12657a6389fa658237326bf80e44cff183d9c9107d30c7b4df83908a8badbc1bb5328ae61e6451291710408196261bb913b285c168fe5c7456cd74970377330139beb4c8b4c00c5954254a748308bc30f3a1ccabed83628422e5515b294e80bfed024902a81518c0e6827caa13230016b72aec10d31aab9f9b072652486c3b779c845804d001b223b4065667a5e318b4e0b27c41a099168ce763ac245c1c26354cfc8214cacf01dc8c99c5fc855639cb7486a7a6b71766d62369ee6349f521591344fb8026099fc055c3a0ca2002271c9361f52acaf4675a97b3593f3447b284ad69a9711501411e14e48f080e2a0bceba07a02f79dc15c3c971c1e671a66bf7144395a94d08c46603c4369b25b38d924693492f6500745cb1d2a037e2cd814fac70d8254aea4526e061648d227350dec1ba6305299a45bde4029a9f63e4f62acb5246ba8b54208a37b98fa77e4b720f02b18969635cc16cb6e236ff78111b621cab0339c60b529a9207c94a74925aa3d177636a6d205d72b429f614d452358b98582e42c2f3a32c94202a8625a760483807bbac74c083a7a786ae7b46aff3810a5318e3f479e67e83b4c94587d345ffda17273a55e0432281c670e36b76539263636445e4d110fa1c92b2e65b1ee993b26c41c8c66b181206ff559728993503e7611fa0ca24156642d29a52cbb6aeff88fa1bb790b4344472503ae77967d11a904550a95cc47c3435f1e44b4b890cf5dc4cbd7486a6cab60d1a6622e40c67e854ed0e6a0c4c2aa92a29731e69bc6b3ca9e83893df4bdb37338055bc16bc7cd875b0691d0212109b77236b10b0c72b7a76e9ce346061028be3271c480435e2482d3d2733ed619c2d3698d29a3225a7731a62db4f214a0b11569e91895fbccb8a92d18f94d307a542ff96d2ce8c2bbaa8fab948c83365162268124cabe934b3a5e6530b7f74397a980c243bdce2989747565dd9ba65a7498aa7c3ee711c3be239e93cb45134c082a900cc951756afa42e74a65001822cab95f41798fdef89ea8a751740842e2f7a271e98dbd5158d7455fe9b9cdcd0a0f68c91e59b00979673a1deabf8d213971f994c0bb08899a91e0b896319b9fc69651e3453b14d1cc94462341548fc81c643ab0b10303c7be2c3458b226d0e45f58b21658a853b84615ac5234da9bc5699646fc53c0df907f9a3c598dab6c409b7884a7a84e1a51c2caa80779cd86b77314dabae85caa28972bb6503273a82eb96ab24af6bb0ad0c9ba07ce24216696e265206abc9e147ceef1ad2e343d17aabbc4803496366c7afb53f604c92323c70be5c1e3f601c215c888f3ab239c72aba0634a2901a71891f5d072d41b524e410c7f276ff1109878d7196b5615f1f50c13976257600a821909cb36cf8d2857a2f801cf258913f56a5153234640b9e61bbd4e7b69f83a1eb8ac6b92cb841e808b700aa784a733451048211797563cccc748c9fbb54b3b65445cba676149c7ae9a9a2ecab6599b8505bc561ad85d8c052ed9669e50e684270c86f1cb4fd6708a6746c643392c8a088477dc8bf58ba4a54a8b79e523fc19a28bd47d7e5a334d8296ec86c7f52b7e73b475a0716422953cdd8a8aed0b3a84dc8425145c240c55870240a23977215b364c5596286bc496728717c329dd4b5d0b310980bc0b3f591a2d5cb2c9eaccfa1c7d3a096fc11091a4007a0f23a59782699c3171da53bc7b914f26c95391d6445073a1bd7a44691bafab9c9aceccc7ec389255c3a0ff24c71b30b6bf80c010803383485a7b295991d759cefbae257bbdee1806818565ebd09bf814c98686bbf44a0b14d28735f79ca2261bf9a31b2ca090c7667168b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb33357e74a31d3cd71513fb880e1e177438f29009bab0a131fec4cc24752015efe71c7300e2d894b0eaa40a6ab254506d8c1176a33c4a1b2879604b1b80df48d31dd");
1✔
4747
         const std::vector<uint8_t> b_pub_bits = Botan::hex_decode(
1✔
4748
            "93bc837be699d5279dac78c9d49818ebc91d4ff6cb54b294e4c378d8eb584f561d21ca87b7c77b1c551f52112ba72c4b6514bb286856e89b48b0a62bad093894474b246a515f849056c9aeb572060ee11b93e236204a8ff1784ede0c3f4c0cd0cdb2a50bd4bcb1225c0dd2caa8a129fdcb01f0e1a75da465b6b8742e4946dbe3ab21ca6c4e592d398a5700375b7b770c17e117663b51313824854585ece4a1520c59a513555f548afdc6748eb9b770b7af8adc9b3c1861efc00ebde93f91fa1539c3411ec9b154c93d1f508b9714cdd0aaabcb436951aa54978b84faa8bd838c29a12657a6389fa658237326bf80e44cff183d9c9107d30c7b4df83908a8badbc1bb5328ae61e6451291710408196261bb913b285c168fe5c7456cd74970377330139beb4c8b4c00c5954254a748308bc30f3a1ccabed83628422e5515b294e80bfed024902a81518c0e6827caa13230016b72aec10d31aab9f9b072652486c3b779c845804d001b223b4065667a5e318b4e0b27c41a099168ce763ac245c1c26354cfc8214cacf01dc8c99c5fc855639cb7486a7a6b71766d62369ee6349f521591344fb8026099fc055c3a0ca2002271c9361f52acaf4675a97b3593f3447b284ad69a9711501411e14e48f080e2a0bceba07a02f79dc15c3c971c1e671a66bf7144395a94d08c46603c4369b25b38d924693492f6500745cb1d2a037e2cd814fac70d8254aea4526e061648d227350dec1ba6305299a45bde4029a9f63e4f62acb5246ba8b54208a37b98fa77e4b720f02b18969635cc16cb6e236ff78111b621cab0339c60b529a9207c94a74925aa3d177636a6d205d72b429f614d452358b98582e42c2f3a32c94202a8625a760483807bbac74c083a7a786ae7b46aff3810a5318e3f479e67e83b4c94587d345ffda17273a55e0432281c670e36b76539263636445e4d110fa1c92b2e65b1ee993b26c41c8c66b181206ff559728993503e7611fa0ca24156642d29a52cbb6aeff88fa1bb790b4344472503ae77967d11a904550a95cc47c3435f1e44b4b890cf5dc4cbd7486a6cab60d1a6622e40c67e854ed0e6a0c4c2aa92a29731e69bc6b3ca9e83893df4bdb37338055bc16bc7cd875b0691d0212109b77236b10b0c72b7a76e9ce346061028be3271c480435e2482d3d2733ed619c2d3698d29a3225a7731a62db4f214a0b11569e91895fbccb8a92d18f94d307a542ff96d2ce8c2bbaa8fab948c83365162268124cabe934b3a5e6530b7f74397a980c243bdce2989747565dd9ba65a7498aa7c3ee711c3be239e93cb45134c082a900cc951756afa42e74a65001822cab95f41798fdef89ea8a751740842e2f7a271e98dbd5158d7455fe9b9cdcd0a0f68c91e59b00979673a1deabf8d213971f994c0bb08899a91e0b896319b9fc69651e3453b14d1cc94462341548fc81c643ab0b10303c7be2c3458b226d0e45f58b21658a853b84615ac5234da9bc5699646fc53c0df907f9a3c598dab6c409b7884a7a84e1a51c2caa80779cd86b77314dabae85caa28972bb6503273a82eb96ab24af6bb0ad0c9ba07ce24216696e265206abc9e147ceef1ad2e343d17aabbc4803496366c7afb53f604c92323c70be5c1e3f601c215c888f3ab239c72aba0634a2901a71891f5d072d41b524e410c7f276ff1109878d7196b5615f1f50c13976257600a821909cb36cf8d2857a2f801cf258913f56a5153234640b9e61bbd4e7b69f83a1eb8ac6b92cb841e808b700aa784a733451048211797563cccc748c9fbb54b3b65445cba676149c7ae9a9a2ecab6599b8505bc561ad85d8c052ed9669e50e684270c86f1cb4fd6708a6746c643392c8a088477dc8bf58ba4a54a8b79e523fc19a28bd47d7e5a334d8296ec86c7f52b7e73b475a0716422953cdd8a8aed0b3a84dc8425145c240c55870240a23977215b364c5596286bc496728717c329dd4b5d0b310980bc0b3f591a2d5cb2c9eaccfa1c7d3a096fc11091a4007a0f23a59782699c3171da53bc7b914f26c95391d6445073a1bd7a44691bafab9c9aceccc7ec389255c3a0ff24c71b30b6bf80c010803383485a7b295991d759cefbae257bbdee1806818565ebd09bf814c98686bbf44a0b14d28735f79ca2261bf9a31b2ca090c7667168b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb333");
1✔
4749

4750
         botan_privkey_t b_priv;
1✔
4751
         if(!TEST_FFI_INIT(botan_privkey_load_kyber, (&b_priv, b_priv_bits.data(), 3168))) {
1✔
4752
            return;
×
4753
         }
4754

4755
         ViewBytesSink privkey_read;
1✔
4756
         ViewBytesSink privkey_read_raw;
1✔
4757
         TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.delegate(), privkey_read.callback()));
1✔
4758
         TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.delegate(), privkey_read_raw.callback()));
1✔
4759
         result.test_bin_eq("kyber1024 private key", privkey_read.get(), b_priv_bits);
1✔
4760
         result.test_bin_eq("kyber1024 private key raw", privkey_read_raw.get(), b_priv_bits);
1✔
4761

4762
         ViewBytesSink pubkey_read;
1✔
4763
         ViewBytesSink pubkey_read_raw;
1✔
4764

4765
         botan_pubkey_t b_pub;
1✔
4766
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
4767
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4768
         TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.delegate(), pubkey_read_raw.callback()));
1✔
4769
         result.test_bin_eq("kyber1024 public key b", pubkey_read.get(), b_pub_bits);
1✔
4770
         result.test_bin_eq("kyber1024 public key raw b", pubkey_read_raw.get(), b_pub_bits);
1✔
4771

4772
         botan_pubkey_t a_pub;
1✔
4773
         TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 1568));
1✔
4774
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (a_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4775
         result.test_bin_eq("kyber1024 public key a", pubkey_read.get(), a_pub_bits);
1✔
4776

4777
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
4778
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
4779
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
1✔
4780
      }
1✔
4781
};
4782

4783
class FFI_ML_KEM_Test final : public FFI_KEM_Roundtrip_Test {
1✔
4784
   public:
4785
      std::string name() const override { return "FFI ML-KEM"; }
1✔
4786

4787
   private:
4788
      const char* algo() const override { return "ML-KEM"; }
3✔
4789

4790
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_ml_kem; }
3✔
4791

4792
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_ml_kem; }
3✔
4793

4794
      std::vector<const char*> modes() const override { return {"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"}; }
1✔
4795
};
4796

4797
class FFI_FrodoKEM_Test final : public FFI_KEM_Roundtrip_Test {
1✔
4798
   public:
4799
      std::string name() const override { return "FFI FrodoKEM"; }
1✔
4800

4801
   protected:
4802
      const char* algo() const override { return "FrodoKEM"; }
12✔
4803

4804
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_frodokem; }
12✔
4805

4806
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_frodokem; }
12✔
4807

4808
      std::vector<const char*> modes() const override {
1✔
4809
         return std::vector{
1✔
4810
            "FrodoKEM-640-SHAKE",
4811
            "FrodoKEM-976-SHAKE",
4812
            "FrodoKEM-1344-SHAKE",
4813
            "eFrodoKEM-640-SHAKE",
4814
            "eFrodoKEM-976-SHAKE",
4815
            "eFrodoKEM-1344-SHAKE",
4816
            "FrodoKEM-640-AES",
4817
            "FrodoKEM-976-AES",
4818
            "FrodoKEM-1344-AES",
4819
            "eFrodoKEM-640-AES",
4820
            "eFrodoKEM-976-AES",
4821
            "eFrodoKEM-1344-AES",
4822
         };
1✔
4823
      }
4824
};
4825

4826
class FFI_ML_DSA_Test final : public FFI_Signature_Roundtrip_Test {
1✔
4827
   public:
4828
      std::string name() const override { return "FFI ML-DSA"; }
1✔
4829

4830
   private:
4831
      const char* algo() const override { return "ML-DSA"; }
3✔
4832

4833
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_ml_dsa; }
3✔
4834

4835
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_ml_dsa; }
3✔
4836

4837
      std::vector<const char*> modes() const override {
1✔
4838
         return {
1✔
4839
            "ML-DSA-4x4",
4840
            "ML-DSA-6x5",
4841
            "ML-DSA-8x7",
4842
         };
1✔
4843
      }
4844

4845
      const char* hash_algo_or_padding() const override { return ""; }
12✔
4846
};
4847

4848
class FFI_SLH_DSA_Test final : public FFI_Signature_Roundtrip_Test {
1✔
4849
   public:
4850
      std::string name() const override { return "FFI SLH-DSA"; }
1✔
4851

4852
   private:
4853
      const char* algo() const override { return "SLH-DSA"; }
12✔
4854

4855
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_slh_dsa; }
12✔
4856

4857
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_slh_dsa; }
12✔
4858

4859
      std::vector<const char*> modes() const override {
1✔
4860
         auto modes = std::vector{
1✔
4861
            "SLH-DSA-SHA2-128f",
4862
            "SLH-DSA-SHAKE-128f",
4863
            "SLH-DSA-SHA2-192f",
4864
            "SLH-DSA-SHAKE-192f",
4865
            "SLH-DSA-SHA2-256f",
4866
            "SLH-DSA-SHAKE-256f",
4867
         };
1✔
4868

4869
         if(Test::run_long_tests()) {
1✔
4870
            modes = Botan::concat(modes,
3✔
4871
                                  std::vector{
1✔
4872
                                     "SLH-DSA-SHA2-128s",
4873
                                     "SLH-DSA-SHA2-192s",
4874
                                     "SLH-DSA-SHA2-256s",
4875
                                     "SLH-DSA-SHAKE-128s",
4876
                                     "SLH-DSA-SHAKE-192s",
4877
                                     "SLH-DSA-SHAKE-256s",
4878
                                  });
2✔
4879
         }
4880

4881
         return modes;
1✔
4882
      }
×
4883

4884
      const char* hash_algo_or_padding() const override { return ""; }
48✔
4885
};
4886

4887
class FFI_Classic_McEliece_Test final : public FFI_KEM_Roundtrip_Test {
1✔
4888
   public:
4889
      std::string name() const override { return "FFI Classic McEliece"; }
1✔
4890

4891
   protected:
4892
      const char* algo() const override { return "ClassicMcEliece"; }
16✔
4893

4894
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_classic_mceliece; }
16✔
4895

4896
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_classic_mceliece; }
16✔
4897

4898
      std::vector<const char*> modes() const override {
1✔
4899
         auto modes = std::vector{
1✔
4900
            "348864f",
4901
            "460896f",
4902
         };
1✔
4903
         if(Test::run_long_tests()) {
1✔
4904
            modes = Botan::concat(modes,
3✔
4905
                                  std::vector{
1✔
4906
                                     "348864",
4907
                                     "460896",
4908
                                     "6688128",
4909
                                     "6688128f",
4910
                                     "6688128pc",
4911
                                     "6688128pcf",
4912
                                     "6960119",
4913
                                     "6960119f",
4914
                                     "6960119pc",
4915
                                     "6960119pcf",
4916
                                     "8192128",
4917
                                     "8192128f",
4918
                                     "8192128pc",
4919
                                     "8192128pcf",
4920
                                  });
2✔
4921
         }
4922
         return modes;
1✔
4923
      }
×
4924
};
4925

4926
class FFI_ElGamal_Test final : public FFI_Test {
1✔
4927
   public:
4928
      std::string name() const override { return "FFI ElGamal"; }
1✔
4929

4930
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4931
         botan_privkey_t priv;
1✔
4932

4933
         if(TEST_FFI_INIT(botan_privkey_create, (&priv, "ElGamal", "modp/ietf/1024", rng))) {
1✔
4934
            do_elgamal_test(priv, rng, result);
1✔
4935
         }
4936

4937
         if(TEST_FFI_INIT(botan_privkey_create_elgamal, (&priv, rng, 1024, 160))) {
1✔
4938
            do_elgamal_test(priv, rng, result);
1✔
4939
         }
4940
      }
1✔
4941

4942
   private:
4943
      static void do_elgamal_test(botan_privkey_t priv, botan_rng_t rng, Test::Result& result) {
2✔
4944
         TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
2✔
4945

4946
         botan_pubkey_t pub = nullptr;
2✔
4947
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
2✔
4948
         TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
2✔
4949

4950
         ffi_test_pubkey_export(result, pub, priv, rng);
2✔
4951
         botan_mp_t p = nullptr;
2✔
4952
         botan_mp_t g = nullptr;
2✔
4953
         botan_mp_t x = nullptr;
2✔
4954
         botan_mp_t y = nullptr;
2✔
4955
         botan_mp_init(&p);
2✔
4956
         botan_mp_init(&g);
2✔
4957
         botan_mp_init(&x);
2✔
4958
         botan_mp_init(&y);
2✔
4959

4960
         TEST_FFI_OK(botan_pubkey_get_field, (p, pub, "p"));
2✔
4961
         TEST_FFI_OK(botan_pubkey_get_field, (g, pub, "g"));
2✔
4962
         TEST_FFI_OK(botan_pubkey_get_field, (y, pub, "y"));
2✔
4963
         TEST_FFI_OK(botan_privkey_get_field, (x, priv, "x"));
2✔
4964

4965
         size_t p_len = 0;
2✔
4966
         TEST_FFI_OK(botan_mp_num_bytes, (p, &p_len));
2✔
4967

4968
         botan_privkey_t loaded_privkey;
2✔
4969
         TEST_FFI_OK(botan_privkey_load_elgamal, (&loaded_privkey, p, g, x));
2✔
4970

4971
         botan_pubkey_t loaded_pubkey;
2✔
4972
         TEST_FFI_OK(botan_pubkey_load_elgamal, (&loaded_pubkey, p, g, y));
2✔
4973

4974
         botan_mp_destroy(p);
2✔
4975
         botan_mp_destroy(g);
2✔
4976
         botan_mp_destroy(y);
2✔
4977
         botan_mp_destroy(x);
2✔
4978

4979
         std::vector<uint8_t> plaintext(16, 0xFF);
2✔
4980
         std::vector<uint8_t> ciphertext;
2✔
4981
         std::vector<uint8_t> decryption;
2✔
4982

4983
   #if defined(BOTAN_HAS_OAEP) && defined(BOTAN_HAS_SHA2_32)
4984
         const std::string padding = "OAEP(SHA-256)";
2✔
4985
   #else
4986
         const std::string padding = "Raw";
4987
   #endif
4988

4989
         // Test encryption
4990
         botan_pk_op_encrypt_t op_enc;
2✔
4991
         if(TEST_FFI_OK(botan_pk_op_encrypt_create, (&op_enc, loaded_pubkey, padding.c_str(), 0))) {
2✔
4992
            size_t ctext_len;
2✔
4993
            TEST_FFI_OK(botan_pk_op_encrypt_output_length, (op_enc, plaintext.size(), &ctext_len));
2✔
4994
            ciphertext.resize(ctext_len);
2✔
4995
            TEST_FFI_OK(botan_pk_op_encrypt,
2✔
4996
                        (op_enc, rng, ciphertext.data(), &ctext_len, plaintext.data(), plaintext.size()));
4997
            ciphertext.resize(ctext_len);
2✔
4998
            TEST_FFI_OK(botan_pk_op_encrypt_destroy, (op_enc));
2✔
4999
         }
5000

5001
         // Test decryption
5002
         botan_pk_op_decrypt_t op_dec;
2✔
5003
         if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&op_dec, loaded_privkey, padding.c_str(), 0))) {
2✔
5004
            size_t ptext_len;
2✔
5005
            TEST_FFI_OK(botan_pk_op_decrypt_output_length, (op_dec, ciphertext.size(), &ptext_len));
2✔
5006
            decryption.resize(ptext_len);
2✔
5007
            TEST_FFI_OK(botan_pk_op_decrypt,
2✔
5008
                        (op_dec, decryption.data(), &ptext_len, ciphertext.data(), ciphertext.size()));
5009
            decryption.resize(ptext_len);
2✔
5010
            TEST_FFI_OK(botan_pk_op_decrypt_destroy, (op_dec));
2✔
5011
         }
5012

5013
         result.test_bin_eq("decryption worked", decryption, plaintext);
2✔
5014

5015
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
5016
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
2✔
5017
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
2✔
5018
         TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
5019
      }
2✔
5020
};
5021

5022
class FFI_DH_Test final : public FFI_Test {
1✔
5023
   public:
5024
      std::string name() const override { return "FFI DH"; }
1✔
5025

5026
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
5027
         botan_privkey_t priv1;
1✔
5028
         if(!TEST_FFI_INIT(botan_privkey_create_dh, (&priv1, rng, "modp/ietf/2048"))) {
1✔
5029
            return;
×
5030
         }
5031

5032
         botan_privkey_t priv2;
1✔
5033
         REQUIRE_FFI_OK(botan_privkey_create_dh, (&priv2, rng, "modp/ietf/2048"));
1✔
5034

5035
         botan_pubkey_t pub1;
1✔
5036
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub1, priv1));
1✔
5037

5038
         botan_pubkey_t pub2;
1✔
5039
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub2, priv2));
1✔
5040

5041
         // Reload key-pair1 in order to test functions for key loading
5042
         botan_mp_t private_x;
1✔
5043
         botan_mp_t public_g;
1✔
5044
         botan_mp_t public_p;
1✔
5045
         botan_mp_t public_y;
1✔
5046

5047
         botan_mp_init(&private_x);
1✔
5048
         botan_mp_init(&public_g);
1✔
5049
         botan_mp_init(&public_p);
1✔
5050
         botan_mp_init(&public_y);
1✔
5051

5052
         TEST_FFI_OK(botan_privkey_get_field, (private_x, priv1, "x"));
1✔
5053
         TEST_FFI_OK(botan_pubkey_get_field, (public_g, pub1, "g"));
1✔
5054
         TEST_FFI_OK(botan_pubkey_get_field, (public_p, pub1, "p"));
1✔
5055
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub1, "y"));
1✔
5056

5057
         botan_privkey_t loaded_privkey1;
1✔
5058
         botan_pubkey_t loaded_pubkey1;
1✔
5059
         TEST_FFI_OK(botan_privkey_load_dh, (&loaded_privkey1, public_p, public_g, private_x));
1✔
5060
         TEST_FFI_OK(botan_pubkey_load_dh, (&loaded_pubkey1, public_p, public_g, public_y));
1✔
5061

5062
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey1, rng, 0));
1✔
5063
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
5064

5065
         botan_mp_t loaded_public_g;
1✔
5066
         botan_mp_t loaded_public_p;
1✔
5067
         botan_mp_t loaded_public_y;
1✔
5068
         botan_mp_init(&loaded_public_g);
1✔
5069
         botan_mp_init(&loaded_public_p);
1✔
5070
         botan_mp_init(&loaded_public_y);
1✔
5071

5072
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_g, loaded_pubkey1, "g"));
1✔
5073
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_p, loaded_pubkey1, "p"));
1✔
5074
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_y, loaded_pubkey1, "y"));
1✔
5075

5076
         int cmp;
1✔
5077

5078
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_g, public_g));
1✔
5079
         result.test_is_true("bigint_mp_cmp(g, g)", cmp == 0);
1✔
5080

5081
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_p, public_p));
1✔
5082
         result.test_is_true("bigint_mp_cmp(p, p)", cmp == 0);
1✔
5083

5084
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_y, public_y));
1✔
5085
         result.test_is_true("bigint_mp_cmp(y, y)", cmp == 0);
1✔
5086

5087
         botan_pk_op_ka_t ka1;
1✔
5088
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka1, loaded_privkey1, "Raw", 0));
1✔
5089
         botan_pk_op_ka_t ka2;
1✔
5090
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka2, priv2, "Raw", 0));
1✔
5091

5092
         size_t pubkey1_len = 0;
1✔
5093
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
5094
                     botan_pk_op_key_agreement_export_public,
5095
                     (priv1, nullptr, &pubkey1_len));
5096
         std::vector<uint8_t> pubkey1(pubkey1_len);
1✔
5097
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv1, pubkey1.data(), &pubkey1_len));
1✔
5098
         size_t pubkey2_len = 0;
1✔
5099
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
5100
                     botan_pk_op_key_agreement_export_public,
5101
                     (priv2, nullptr, &pubkey2_len));
5102
         std::vector<uint8_t> pubkey2(pubkey2_len);
1✔
5103
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv2, pubkey2.data(), &pubkey2_len));
1✔
5104

5105
         const size_t shared_key_len = 256;
1✔
5106

5107
         std::vector<uint8_t> key1(shared_key_len);
1✔
5108
         size_t key1_len = key1.size();
1✔
5109

5110
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
5111
                     (ka1, key1.data(), &key1_len, pubkey2.data(), pubkey2.size(), nullptr, 0));
5112

5113
         std::vector<uint8_t> key2(shared_key_len);
1✔
5114
         size_t key2_len = key2.size();
1✔
5115

5116
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
5117
                     (ka2, key2.data(), &key2_len, pubkey1.data(), pubkey1.size(), nullptr, 0));
5118

5119
         result.test_bin_eq("shared DH key", key1, key2);
1✔
5120

5121
         TEST_FFI_OK(botan_mp_destroy, (private_x));
1✔
5122
         TEST_FFI_OK(botan_mp_destroy, (public_p));
1✔
5123
         TEST_FFI_OK(botan_mp_destroy, (public_g));
1✔
5124
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
5125

5126
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_p));
1✔
5127
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_g));
1✔
5128
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_y));
1✔
5129

5130
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka1));
1✔
5131
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka2));
1✔
5132
         TEST_FFI_OK(botan_privkey_destroy, (priv1));
1✔
5133
         TEST_FFI_OK(botan_privkey_destroy, (priv2));
1✔
5134
         TEST_FFI_OK(botan_pubkey_destroy, (pub1));
1✔
5135
         TEST_FFI_OK(botan_pubkey_destroy, (pub2));
1✔
5136
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey1));
1✔
5137
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
1✔
5138
      }
1✔
5139
};
5140

5141
class FFI_OID_Test final : public FFI_Test {
1✔
5142
   public:
5143
      std::string name() const override { return "FFI OID"; }
1✔
5144

5145
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
5146
         botan_asn1_oid_t oid;
1✔
5147
         botan_asn1_oid_t new_oid;
1✔
5148
         botan_asn1_oid_t new_oid_from_string;
1✔
5149
         botan_asn1_oid_t oid_a;
1✔
5150
         botan_asn1_oid_t oid_b;
1✔
5151
         botan_asn1_oid_t oid_c;
1✔
5152

5153
         TEST_FFI_FAIL("empty oid", botan_oid_from_string, (&oid, ""));
1✔
5154
         TEST_FFI_OK(botan_oid_from_string, (&oid, "1.2.3.4.5"));
1✔
5155

5156
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_oid_from_string, (&new_oid, "a.a.a"));
1✔
5157
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_oid_from_string, (&new_oid, "0.40"));
1✔
5158
         TEST_FFI_RC(
1✔
5159
            BOTAN_FFI_ERROR_BAD_PARAMETER, botan_oid_from_string, (&new_oid, "random-name-that-definitely-has-no-oid"));
5160

5161
         TEST_FFI_OK(botan_oid_from_string, (&new_oid, "1.2.3.4.5.6.7.8"));
1✔
5162
         TEST_FFI_OK(botan_oid_register, (new_oid, "random-name-that-definitely-has-no-oid"));
1✔
5163

5164
         TEST_FFI_OK(botan_oid_from_string, (&new_oid_from_string, "random-name-that-definitely-has-no-oid"));
1✔
5165
         TEST_FFI_RC(1, botan_oid_equal, (new_oid, new_oid_from_string));
1✔
5166

5167
         TEST_FFI_OK(botan_oid_from_string, (&oid_a, "1.2.3.4.5.6"));
1✔
5168
         TEST_FFI_OK(botan_oid_from_string, (&oid_b, "1.2.3.4.5.6"));
1✔
5169
         TEST_FFI_OK(botan_oid_from_string, (&oid_c, "1.2.3.4.4"));
1✔
5170

5171
         TEST_FFI_RC(1, botan_oid_equal, (oid_a, oid_b));
1✔
5172
         TEST_FFI_RC(0, botan_oid_equal, (oid_a, oid_c));
1✔
5173

5174
         int res;
1✔
5175

5176
         TEST_FFI_OK(botan_oid_cmp, (&res, oid_a, oid_b));
1✔
5177
         result.test_is_true("oid_a and oid_b are equal", res == 0);
1✔
5178

5179
         TEST_FFI_OK(botan_oid_cmp, (&res, oid_a, oid_c));
1✔
5180
         result.test_is_true("oid_a is bigger", res == 1);
1✔
5181

5182
         TEST_FFI_OK(botan_oid_cmp, (&res, oid_c, oid_a));
1✔
5183
         result.test_is_true("oid_c is smaller", res == -1);
1✔
5184

5185
         TEST_FFI_OK(botan_oid_destroy, (oid));
1✔
5186
         TEST_FFI_OK(botan_oid_destroy, (new_oid));
1✔
5187
         TEST_FFI_OK(botan_oid_destroy, (new_oid_from_string));
1✔
5188
         TEST_FFI_OK(botan_oid_destroy, (oid_a));
1✔
5189
         TEST_FFI_OK(botan_oid_destroy, (oid_b));
1✔
5190
         TEST_FFI_OK(botan_oid_destroy, (oid_c));
1✔
5191

5192
         botan_privkey_t priv;
1✔
5193
         if(TEST_FFI_INIT(botan_privkey_create_rsa, (&priv, rng, 1024))) {
1✔
5194
            TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
1✔
5195

5196
            const std::string oid_rsa_expected = "1.2.840.113549.1.1.1";
1✔
5197

5198
            botan_asn1_oid_t rsa_oid_priv;
1✔
5199
            botan_asn1_oid_t rsa_oid_pub;
1✔
5200
            botan_asn1_oid_t rsa_oid_expected;
1✔
5201
            botan_asn1_oid_t rsa_oid_from_name;
1✔
5202

5203
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_oid_from_string, (&rsa_oid_expected, nullptr));
1✔
5204
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_oid_from_string, (nullptr, "1.2.3.4.5"));
1✔
5205
            TEST_FFI_OK(botan_oid_from_string, (&rsa_oid_expected, oid_rsa_expected.c_str()));
1✔
5206
            TEST_FFI_OK(botan_privkey_oid, (&rsa_oid_priv, priv));
1✔
5207

5208
            TEST_FFI_RC(1, botan_oid_equal, (rsa_oid_priv, rsa_oid_expected));
1✔
5209

5210
            botan_pubkey_t pub;
1✔
5211
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
5212

5213
            TEST_FFI_OK(botan_pubkey_oid, (&rsa_oid_pub, pub));
1✔
5214
            TEST_FFI_RC(1, botan_oid_equal, (rsa_oid_pub, rsa_oid_expected));
1✔
5215

5216
            ViewStringSink oid_string;
1✔
5217
            TEST_FFI_OK(botan_oid_view_string, (rsa_oid_expected, oid_string.delegate(), oid_string.callback()));
1✔
5218
            const std::string oid_actual = {oid_string.get().begin(), oid_string.get().end()};
2✔
5219

5220
            result.test_str_eq("oid to string", oid_actual, oid_rsa_expected);
1✔
5221

5222
            TEST_FFI_OK(botan_oid_from_string, (&rsa_oid_from_name, "RSA"));
1✔
5223
            TEST_FFI_RC(1, botan_oid_equal, (rsa_oid_expected, rsa_oid_from_name));
1✔
5224

5225
            ViewStringSink rsa_name;
1✔
5226
            TEST_FFI_OK(botan_oid_view_name, (rsa_oid_from_name, rsa_name.delegate(), rsa_name.callback()));
1✔
5227
            const std::string rsa_name_string = {rsa_name.get().begin(), rsa_name.get().end()};
2✔
5228
            result.test_str_eq("oid to name", rsa_name_string, "RSA");
1✔
5229

5230
            TEST_FFI_OK(botan_oid_destroy, (rsa_oid_priv));
1✔
5231
            TEST_FFI_OK(botan_oid_destroy, (rsa_oid_pub));
1✔
5232
            TEST_FFI_OK(botan_oid_destroy, (rsa_oid_expected));
1✔
5233
            TEST_FFI_OK(botan_oid_destroy, (rsa_oid_from_name));
1✔
5234

5235
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
5236
            TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
5237
         }
1✔
5238
      }
1✔
5239
};
5240

5241
class FFI_EC_Group_Test final : public FFI_Test {
1✔
5242
   public:
5243
      std::string name() const override { return "FFI EC Group"; }
1✔
5244

5245
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
5246
         int appl_spec_groups;
1✔
5247
         int named_group;
1✔
5248
         TEST_FFI_OK(botan_ec_group_supports_application_specific_group, (&appl_spec_groups));
1✔
5249
         TEST_FFI_OK(botan_ec_group_supports_named_group, ("secp256r1", &named_group));
1✔
5250
         result.test_bool_eq("application specific groups support matches build",
1✔
5251
                             appl_spec_groups == 1,
5252
                             Botan::EC_Group::supports_application_specific_group());
1✔
5253
         result.test_bool_eq(
1✔
5254
            "named group support matches build", named_group == 1, Botan::EC_Group::supports_named_group("secp256r1"));
1✔
5255

5256
         if(named_group == 1) {
1✔
5257
            botan_ec_group_t group_from_name;
1✔
5258
            botan_asn1_oid_t oid_from_name;
1✔
5259
            botan_mp_t p_from_name;
1✔
5260
            botan_mp_t a_from_name;
1✔
5261
            botan_mp_t b_from_name;
1✔
5262
            botan_mp_t g_x_from_name;
1✔
5263
            botan_mp_t g_y_from_name;
1✔
5264
            botan_mp_t order_from_name;
1✔
5265

5266
            TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_ec_group_from_name, (&group_from_name, ""));
1✔
5267

5268
            TEST_FFI_OK(botan_ec_group_from_name, (&group_from_name, "secp256r1"));
1✔
5269

5270
            get_group_parameters(group_from_name,
1✔
5271
                                 &oid_from_name,
5272
                                 &p_from_name,
5273
                                 &a_from_name,
5274
                                 &b_from_name,
5275
                                 &g_x_from_name,
5276
                                 &g_y_from_name,
5277
                                 &order_from_name,
5278
                                 result);
5279

5280
            botan_asn1_oid_t group_oid;
1✔
5281
            botan_ec_group_t group_from_oid;
1✔
5282
            botan_asn1_oid_t oid_from_oid;
1✔
5283
            botan_mp_t p_from_oid;
1✔
5284
            botan_mp_t a_from_oid;
1✔
5285
            botan_mp_t b_from_oid;
1✔
5286
            botan_mp_t g_x_from_oid;
1✔
5287
            botan_mp_t g_y_from_oid;
1✔
5288
            botan_mp_t order_from_oid;
1✔
5289

5290
            TEST_FFI_OK(botan_oid_from_string, (&group_oid, "1.2.840.10045.3.1.7"));
1✔
5291

5292
            TEST_FFI_OK(botan_ec_group_from_oid, (&group_from_oid, group_oid));
1✔
5293

5294
            get_group_parameters(group_from_oid,
1✔
5295
                                 &oid_from_oid,
5296
                                 &p_from_oid,
5297
                                 &a_from_oid,
5298
                                 &b_from_oid,
5299
                                 &g_x_from_oid,
5300
                                 &g_y_from_oid,
5301
                                 &order_from_oid,
5302
                                 result);
5303

5304
            TEST_FFI_RC(1, botan_oid_equal, (group_oid, oid_from_oid));
1✔
5305
            TEST_FFI_RC(1, botan_oid_equal, (oid_from_name, oid_from_oid));
1✔
5306

5307
            if(appl_spec_groups == 1) {
1✔
5308
               botan_asn1_oid_t group_parameter_oid;
1✔
5309
               botan_mp_t p_parameter;
1✔
5310
               botan_mp_t a_parameter;
1✔
5311
               botan_mp_t b_parameter;
1✔
5312
               botan_mp_t g_x_parameter;
1✔
5313
               botan_mp_t g_y_parameter;
1✔
5314
               botan_mp_t order_parameter;
1✔
5315

5316
               botan_ec_group_t group_from_parameters;
1✔
5317
               botan_asn1_oid_t oid_from_parameters;
1✔
5318
               botan_mp_t p_from_parameters;
1✔
5319
               botan_mp_t a_from_parameters;
1✔
5320
               botan_mp_t b_from_parameters;
1✔
5321
               botan_mp_t g_x_from_parameters;
1✔
5322
               botan_mp_t g_y_from_parameters;
1✔
5323
               botan_mp_t order_from_parameters;
1✔
5324

5325
               TEST_FFI_OK(botan_oid_from_string, (&group_parameter_oid, "1.3.6.1.4.1.25258.100.0"));
1✔
5326
               botan_oid_register(group_parameter_oid, "secp256r1-but-manually-registered");
1✔
5327
               botan_mp_init(&p_parameter);
1✔
5328
               botan_mp_init(&a_parameter);
1✔
5329
               botan_mp_init(&b_parameter);
1✔
5330
               botan_mp_init(&g_x_parameter);
1✔
5331
               botan_mp_init(&g_y_parameter);
1✔
5332
               botan_mp_init(&order_parameter);
1✔
5333

5334
               botan_mp_set_from_str(p_parameter, "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
1✔
5335
               botan_mp_set_from_str(a_parameter, "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
1✔
5336
               botan_mp_set_from_str(b_parameter, "0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
1✔
5337
               botan_mp_set_from_str(g_x_parameter,
1✔
5338
                                     "0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
5339
               botan_mp_set_from_str(g_y_parameter,
1✔
5340
                                     "0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
5341
               botan_mp_set_from_str(order_parameter,
1✔
5342
                                     "0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
5343

5344
               TEST_FFI_OK(botan_ec_group_from_params,
1✔
5345
                           (&group_from_parameters,
5346
                            group_parameter_oid,
5347
                            p_parameter,
5348
                            a_parameter,
5349
                            b_parameter,
5350
                            g_x_parameter,
5351
                            g_y_parameter,
5352
                            order_parameter));
5353

5354
               get_group_parameters(group_from_parameters,
1✔
5355
                                    &oid_from_parameters,
5356
                                    &p_from_parameters,
5357
                                    &a_from_parameters,
5358
                                    &b_from_parameters,
5359
                                    &g_x_from_parameters,
5360
                                    &g_y_from_parameters,
5361
                                    &order_from_parameters,
5362
                                    result);
5363

5364
               botan_ec_group_t group_from_registered_oid;
1✔
5365

5366
               TEST_FFI_OK(botan_ec_group_from_name, (&group_from_registered_oid, "secp256r1-but-manually-registered"));
1✔
5367

5368
               // we registered this group under a different oid
5369
               TEST_FFI_RC(0, botan_oid_equal, (oid_from_oid, oid_from_parameters));
1✔
5370

5371
               TEST_FFI_RC(1, botan_ec_group_equal, (group_from_name, group_from_parameters));
1✔
5372
               TEST_FFI_RC(1, botan_ec_group_equal, (group_from_parameters, group_from_registered_oid));
1✔
5373

5374
               const std::vector<std::tuple<botan_mp_t, botan_mp_t>> parameters_inner = {
1✔
5375
                  {p_from_name, p_from_parameters},
5376
                  {a_from_name, a_from_parameters},
5377
                  {b_from_name, b_from_parameters},
5378
                  {g_x_from_name, g_x_from_parameters},
5379
                  {g_y_from_name, g_y_from_parameters},
5380
                  {order_from_name, order_from_parameters}};
1✔
5381

5382
               for(auto [x, y] : parameters_inner) {
7✔
5383
                  TEST_FFI_RC(1, botan_mp_equal, (x, y));
6✔
5384
                  botan_mp_destroy(y);
6✔
5385
               }
5386

5387
               botan_mp_destroy(p_parameter);
1✔
5388
               botan_mp_destroy(a_parameter);
1✔
5389
               botan_mp_destroy(b_parameter);
1✔
5390
               botan_mp_destroy(g_x_parameter);
1✔
5391
               botan_mp_destroy(g_y_parameter);
1✔
5392
               botan_mp_destroy(order_parameter);
1✔
5393

5394
               TEST_FFI_RC(1, botan_ec_group_unregister, (group_parameter_oid));
1✔
5395
               TEST_FFI_RC(0, botan_ec_group_unregister, (group_parameter_oid));
1✔
5396
               TEST_FFI_RC(1, botan_ec_group_unregister, (oid_from_name));
1✔
5397
               TEST_FFI_RC(0, botan_ec_group_unregister, (oid_from_name));
1✔
5398

5399
               botan_ec_group_t unregistered_group;
1✔
5400
               TEST_FFI_RC(
1✔
5401
                  BOTAN_FFI_ERROR_BAD_PARAMETER, botan_ec_group_from_oid, (&unregistered_group, group_parameter_oid));
5402

5403
               botan_oid_destroy(group_parameter_oid);
1✔
5404
               botan_oid_destroy(oid_from_parameters);
1✔
5405

5406
               TEST_FFI_OK(botan_ec_group_destroy, (group_from_parameters));
1✔
5407
               TEST_FFI_OK(botan_ec_group_destroy, (group_from_registered_oid));
1✔
5408
            }
1✔
5409

5410
            botan_oid_destroy(oid_from_name);
1✔
5411
            botan_oid_destroy(group_oid);
1✔
5412
            botan_oid_destroy(oid_from_oid);
1✔
5413

5414
            const std::vector<std::tuple<botan_mp_t, botan_mp_t>> parameters = {{p_from_name, p_from_oid},
1✔
5415
                                                                                {a_from_name, a_from_oid},
5416
                                                                                {b_from_name, b_from_oid},
5417
                                                                                {g_x_from_name, g_x_from_oid},
5418
                                                                                {g_y_from_name, g_y_from_oid},
5419
                                                                                {order_from_name, order_from_oid}};
1✔
5420

5421
            for(auto [x, y] : parameters) {
7✔
5422
               TEST_FFI_RC(1, botan_mp_equal, (x, y));
6✔
5423
               botan_mp_destroy(x);
6✔
5424
               botan_mp_destroy(y);
6✔
5425
            }
5426

5427
            botan_ec_group_t secp384r1;
1✔
5428
            botan_ec_group_t secp384r1_with_seed;
1✔
5429

5430
            TEST_FFI_OK(botan_ec_group_from_name, (&secp384r1, "secp384r1"));
1✔
5431
            TEST_FFI_OK(botan_ec_group_from_pem,
1✔
5432
                        (&secp384r1_with_seed, Test::read_data_file("x509/ecc/secp384r1_seed.pem").c_str()));
5433

5434
            botan_mp_t p;
1✔
5435
            botan_mp_t p_with_seed;
1✔
5436
            TEST_FFI_OK(botan_ec_group_get_p, (&p, secp384r1));
1✔
5437
            TEST_FFI_OK(botan_ec_group_get_p, (&p_with_seed, secp384r1_with_seed));
1✔
5438
            TEST_FFI_RC(1, botan_mp_equal, (p, p_with_seed));
1✔
5439
            botan_mp_destroy(p);
1✔
5440
            botan_mp_destroy(p_with_seed);
1✔
5441

5442
            TEST_FFI_RC(0, botan_ec_group_equal, (group_from_name, secp384r1));
1✔
5443
            TEST_FFI_RC(1, botan_ec_group_equal, (group_from_name, group_from_oid));
1✔
5444

5445
            ViewBytesSink der_bytes;
1✔
5446
            TEST_FFI_OK(botan_ec_group_view_der, (group_from_name, der_bytes.delegate(), der_bytes.callback()));
1✔
5447
            botan_ec_group_t group_from_ber;
1✔
5448
            TEST_FFI_OK(
1✔
5449
               botan_ec_group_from_ber,
5450
               (&group_from_ber, reinterpret_cast<const uint8_t*>(der_bytes.get().data()), der_bytes.get().size()));
5451

5452
            ViewStringSink pem_string;
1✔
5453
            TEST_FFI_OK(botan_ec_group_view_pem, (group_from_name, pem_string.delegate(), pem_string.callback()));
1✔
5454
            const std::string pem_actual = {pem_string.get().begin(), pem_string.get().end()};
2✔
5455

5456
            botan_ec_group_t group_from_pem;
1✔
5457
            TEST_FFI_OK(botan_ec_group_from_pem, (&group_from_pem, pem_actual.c_str()));
1✔
5458

5459
            TEST_FFI_RC(1, botan_ec_group_equal, (group_from_name, group_from_ber));
1✔
5460
            TEST_FFI_RC(1, botan_ec_group_equal, (group_from_name, group_from_pem));
1✔
5461

5462
            botan_privkey_t priv;
1✔
5463
            TEST_FFI_OK(botan_ec_privkey_create, (&priv, "ECDSA", secp384r1, rng));
1✔
5464
            std::array<char, 32> namebuf{};
1✔
5465
            size_t name_len = namebuf.size();
1✔
5466

5467
            TEST_FFI_OK(botan_privkey_algo_name, (priv, namebuf.data(), &name_len));
1✔
5468
            result.test_str_eq("Key name is expected value", namebuf.data(), "ECDSA");
1✔
5469

5470
            botan_ec_group_t group_from_key;
1✔
5471
            TEST_FFI_OK(botan_ec_privkey_get_group, (priv, &group_from_key));
1✔
5472
            TEST_FFI_RC(1, botan_ec_group_equal, (group_from_key, secp384r1));
1✔
5473

5474
            botan_ec_scalar_t private_value;
1✔
5475
            TEST_FFI_OK(botan_ec_privkey_get_private_key, (priv, &private_value));
1✔
5476

5477
            botan_ec_scalar_destroy(private_value);
1✔
5478
            botan_privkey_destroy(priv);
1✔
5479

5480
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_name));
1✔
5481
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_oid));
1✔
5482
            TEST_FFI_OK(botan_ec_group_destroy, (secp384r1));
1✔
5483
            TEST_FFI_OK(botan_ec_group_destroy, (secp384r1_with_seed));
1✔
5484
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_ber));
1✔
5485
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_pem));
1✔
5486
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_key));
1✔
5487
         }
2✔
5488
      }
1✔
5489

5490
   private:
5491
      static void get_group_parameters(botan_ec_group_t ec_group,
3✔
5492
                                       botan_asn1_oid_t* oid,
5493
                                       botan_mp_t* p,
5494
                                       botan_mp_t* a,
5495
                                       botan_mp_t* b,
5496
                                       botan_mp_t* g_x,
5497
                                       botan_mp_t* g_y,
5498
                                       botan_mp_t* order,
5499
                                       Test::Result& result) {
5500
         TEST_FFI_OK(botan_ec_group_get_curve_oid, (oid, ec_group));
3✔
5501
         TEST_FFI_OK(botan_ec_group_get_p, (p, ec_group));
3✔
5502
         TEST_FFI_OK(botan_ec_group_get_a, (a, ec_group));
3✔
5503
         TEST_FFI_OK(botan_ec_group_get_b, (b, ec_group));
3✔
5504
         TEST_FFI_OK(botan_ec_group_get_g_x, (g_x, ec_group));
3✔
5505
         TEST_FFI_OK(botan_ec_group_get_g_y, (g_y, ec_group));
3✔
5506
         TEST_FFI_OK(botan_ec_group_get_order, (order, ec_group));
3✔
5507
      }
3✔
5508
};
5509

5510
class FFI_EC_Point_Test final : public FFI_Test {
1✔
5511
   public:
5512
      std::string name() const override { return "FFI Points and Scalars"; }
1✔
5513

5514
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
5515
         botan_ec_group_t group;
1✔
5516

5517
         botan_ec_scalar_t random;
1✔
5518
         botan_mp_t to_scalar;
1✔
5519
         botan_ec_scalar_t from_mp;
1✔
5520
         botan_mp_t from_scalar;
1✔
5521

5522
         if(!Botan::EC_Group::supports_named_group("secp256r1")) {
1✔
5523
            result.test_note("Group needed for test not supported by this build configuration.");
×
5524
            return;
×
5525
         }
5526

5527
         TEST_FFI_OK(botan_mp_init, (&to_scalar));
1✔
5528
         TEST_FFI_OK(botan_mp_set_from_str, (to_scalar, "12345"));
1✔
5529

5530
         TEST_FFI_OK(botan_ec_group_from_name, (&group, "secp256r1"));
1✔
5531
         TEST_FFI_OK(botan_ec_scalar_random, (&random, group, rng));
1✔
5532
         TEST_FFI_OK(botan_ec_scalar_from_mp, (&from_mp, group, to_scalar));
1✔
5533
         TEST_FFI_OK(botan_ec_scalar_to_mp, (from_mp, &from_scalar));
1✔
5534
         TEST_FFI_RC(1, botan_mp_equal, (to_scalar, from_scalar));
1✔
5535

5536
         TEST_FFI_OK(botan_ec_scalar_destroy, (random));
1✔
5537
         TEST_FFI_OK(botan_ec_scalar_destroy, (from_mp));
1✔
5538
         TEST_FFI_OK(botan_mp_destroy, (to_scalar));
1✔
5539
         TEST_FFI_OK(botan_mp_destroy, (from_scalar));
1✔
5540

5541
         botan_ec_point_t identity;
1✔
5542
         botan_ec_point_t generator;
1✔
5543
         botan_ec_point_t generator_neg;
1✔
5544
         botan_ec_point_t out_add_ident;
1✔
5545
         botan_ec_point_t out_add_inverse;
1✔
5546

5547
         TEST_FFI_OK(botan_ec_point_identity, (&identity, group));
1✔
5548
         TEST_FFI_OK(botan_ec_point_generator, (&generator, group));
1✔
5549
         TEST_FFI_OK(botan_ec_point_negate, (&generator_neg, generator));
1✔
5550

5551
         TEST_FFI_OK(botan_ec_point_add, (&out_add_ident, generator, identity));
1✔
5552
         TEST_FFI_OK(botan_ec_point_add, (&out_add_inverse, generator, generator_neg));
1✔
5553

5554
         ViewBytesSink generator_bytes;
1✔
5555
         TEST_FFI_OK(botan_ec_point_view_xy_bytes, (generator, generator_bytes.delegate(), generator_bytes.callback()));
1✔
5556

5557
         ViewBytesSink gen_plus_ident_bytes;
1✔
5558
         TEST_FFI_OK(botan_ec_point_view_xy_bytes,
1✔
5559
                     (out_add_ident, gen_plus_ident_bytes.delegate(), gen_plus_ident_bytes.callback()));
5560

5561
         result.test_bin_eq("generator == out_add_ident", generator_bytes.get(), gen_plus_ident_bytes.get());
1✔
5562

5563
         TEST_FFI_RC(1, botan_ec_point_equal, (generator, out_add_ident));
1✔
5564
         TEST_FFI_RC(1, botan_ec_point_equal, (identity, out_add_inverse));
1✔
5565
         TEST_FFI_RC(1, botan_ec_point_is_identity, (out_add_inverse));
1✔
5566

5567
         ViewBytesSink identity_bytes;
1✔
5568
         TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
5569
                     botan_ec_point_view_xy_bytes,
5570
                     (identity, identity_bytes.delegate(), identity_bytes.callback()));
5571

5572
         botan_mp_t group_order;
1✔
5573
         TEST_FFI_OK(botan_ec_group_get_order, (&group_order, group));
1✔
5574
         botan_mp_t group_order_minus_1;
1✔
5575
         TEST_FFI_OK(botan_mp_init, (&group_order_minus_1));
1✔
5576

5577
         TEST_FFI_OK(botan_mp_sub_u32, (group_order_minus_1, group_order, 1));
1✔
5578
         botan_ec_scalar_t order;
1✔
5579
         TEST_FFI_OK(botan_ec_scalar_from_mp, (&order, group, group_order_minus_1));
1✔
5580

5581
         botan_ec_point_t out_mul_order_minus_one;
1✔
5582
         TEST_FFI_OK(botan_ec_point_mul, (&out_mul_order_minus_one, generator, order, rng));
1✔
5583

5584
         botan_ec_point_t out_add_gen_to_order;
1✔
5585
         TEST_FFI_OK(botan_ec_point_add, (&out_add_gen_to_order, out_mul_order_minus_one, generator));
1✔
5586

5587
         TEST_FFI_RC(1, botan_ec_point_is_identity, (out_add_gen_to_order));
1✔
5588

5589
         TEST_FFI_OK(botan_mp_destroy, (group_order));
1✔
5590
         TEST_FFI_OK(botan_mp_destroy, (group_order_minus_1));
1✔
5591
         TEST_FFI_OK(botan_ec_scalar_destroy, (order));
1✔
5592

5593
         TEST_FFI_OK(botan_ec_point_destroy, (identity));
1✔
5594
         TEST_FFI_OK(botan_ec_point_destroy, (generator));
1✔
5595
         TEST_FFI_OK(botan_ec_point_destroy, (generator_neg));
1✔
5596
         TEST_FFI_OK(botan_ec_point_destroy, (out_add_ident));
1✔
5597
         TEST_FFI_OK(botan_ec_point_destroy, (out_add_inverse));
1✔
5598
         TEST_FFI_OK(botan_ec_point_destroy, (out_mul_order_minus_one));
1✔
5599
         TEST_FFI_OK(botan_ec_point_destroy, (out_add_gen_to_order));
1✔
5600
         TEST_FFI_OK(botan_ec_group_destroy, (group));
1✔
5601
      }
1✔
5602
};
5603

5604
class FFI_SRP6_Test final : public FFI_Test {
1✔
5605
   public:
5606
      std::string name() const override { return "FFI SRP6"; }
1✔
5607

5608
      bool skip_this_test() const override {
1✔
5609
   #if !defined(BOTAN_HAS_SRP6)
5610
         return true;
5611
   #else
5612
         return false;
1✔
5613
   #endif
5614
      }
5615

5616
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
5617
         constexpr size_t group_bytes = 128;
1✔
5618
         const char* username = "alice";
1✔
5619
         const char* password = "secret";
1✔
5620
         const char* srp_group = "modp/srp/1024";
1✔
5621
         const char* srp_hash = "SHA-256";
1✔
5622
         const auto salt = Botan::hex_decode("beb25379d1a8581eb5a727673a2441ee");
1✔
5623

5624
         std::array<uint8_t, group_bytes> output{};
1✔
5625

5626
         size_t group_size = 0;
1✔
5627
         TEST_FFI_OK(botan_srp6_group_size, (srp_group, &group_size));
1✔
5628
         result.test_sz_eq("reported group size", group_size, group_bytes);
1✔
5629

5630
         size_t short_output_len = output.size() / 2;
1✔
5631
         TEST_FFI_RC(
1✔
5632
            BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
5633
            botan_srp6_generate_verifier,
5634
            (username, password, salt.data(), salt.size(), srp_group, srp_hash, output.data(), &short_output_len));
5635
         result.test_sz_eq("requested verifier length", short_output_len, group_bytes);
1✔
5636

5637
         size_t verifier_output_len = short_output_len;
1✔
5638
         TEST_FFI_OK(
1✔
5639
            botan_srp6_generate_verifier,
5640
            (username, password, salt.data(), salt.size(), srp_group, srp_hash, output.data(), &verifier_output_len));
5641
         const auto verifier = std::vector(output.data(), output.data() + verifier_output_len);
1✔
5642

5643
         botan_srp6_server_session_t srp_server;
1✔
5644
         TEST_FFI_OK(botan_srp6_server_session_init, (&srp_server));
1✔
5645

5646
         short_output_len = output.size() / 2;
1✔
5647
         TEST_FFI_RC(
1✔
5648
            BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
5649
            botan_srp6_server_session_step1,
5650
            (srp_server, verifier.data(), verifier.size(), srp_group, srp_hash, rng, output.data(), &short_output_len));
5651
         result.test_sz_eq("requested B_pub length", short_output_len, group_bytes);
1✔
5652

5653
         size_t pub_B_output_len = short_output_len;
1✔
5654
         TEST_FFI_OK(
1✔
5655
            botan_srp6_server_session_step1,
5656
            (srp_server, verifier.data(), verifier.size(), srp_group, srp_hash, rng, output.data(), &pub_B_output_len));
5657
         const auto pub_B = std::vector(output.data(), output.data() + pub_B_output_len);
1✔
5658

5659
         std::array<uint8_t, group_bytes> output2{};
1✔
5660
         size_t short_output_len2 = output2.size() / 2;
1✔
5661
         short_output_len = output.size() / 2;
1✔
5662
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
5663
                     botan_srp6_client_agree,
5664
                     (username,
5665
                      password,
5666
                      srp_group,
5667
                      srp_hash,
5668
                      salt.data(),
5669
                      salt.size(),
5670
                      pub_B.data(),
5671
                      pub_B.size(),
5672
                      rng,
5673
                      output.data(),
5674
                      &short_output_len,
5675
                      output2.data(),
5676
                      &short_output_len2));
5677
         result.test_sz_eq("requested pub_A length", short_output_len, group_bytes);
1✔
5678
         result.test_sz_eq("requested K1 length", short_output_len2, group_bytes);
1✔
5679

5680
         size_t pub_A_output_len = short_output_len;
1✔
5681
         size_t K1_output_len = short_output_len2;
1✔
5682
         TEST_FFI_OK(botan_srp6_client_agree,
1✔
5683
                     (username,
5684
                      password,
5685
                      srp_group,
5686
                      srp_hash,
5687
                      salt.data(),
5688
                      salt.size(),
5689
                      pub_B.data(),
5690
                      pub_B.size(),
5691
                      rng,
5692
                      output.data(),
5693
                      &pub_A_output_len,
5694
                      output2.data(),
5695
                      &K1_output_len));
5696
         const auto pub_A = std::vector(output.data(), output.data() + pub_A_output_len);
1✔
5697
         const auto K1 = std::vector(output2.data(), output2.data() + K1_output_len);
1✔
5698

5699
         short_output_len = output.size() / 2;
1✔
5700
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
5701
                     botan_srp6_server_session_step2,
5702
                     (srp_server, pub_A.data(), pub_A.size(), output.data(), &short_output_len));
5703
         result.test_sz_eq("requested K2 length", short_output_len, group_bytes);
1✔
5704

5705
         size_t K2_output_len = short_output_len;
1✔
5706
         TEST_FFI_OK(botan_srp6_server_session_step2,
1✔
5707
                     (srp_server, pub_A.data(), pub_A.size(), output.data(), &K2_output_len));
5708
         const auto K2 = std::vector(output.data(), output.data() + K2_output_len);
1✔
5709

5710
         result.test_bin_eq("K1 == K2", K1, K2);
1✔
5711

5712
         TEST_FFI_OK(botan_srp6_server_session_destroy, (srp_server));
1✔
5713
      }
1✔
5714
};
5715

5716
// NOLINTEND(*-init-variables)
5717

5718
BOTAN_REGISTER_TEST("ffi", "ffi_utils", FFI_Utils_Test);
5719
BOTAN_REGISTER_TEST("ffi", "ffi_rng", FFI_RNG_Test);
5720
BOTAN_REGISTER_TEST("ffi", "ffi_rsa_cert", FFI_RSA_Cert_Test);
5721
BOTAN_REGISTER_TEST("ffi", "ffi_zfec", FFI_ZFEC_Test);
5722
BOTAN_REGISTER_TEST("ffi", "ffi_crl", FFI_CRL_Test);
5723
BOTAN_REGISTER_TEST("ffi", "ffi_cert_validation", FFI_Cert_Validation_Test);
5724
BOTAN_REGISTER_TEST("ffi", "ffi_ecdsa_certificate", FFI_ECDSA_Certificate_Test);
5725
BOTAN_REGISTER_TEST("ffi", "ffi_cert_ext_keyusage", FFI_Cert_ExtKeyUsages_Test);
5726
BOTAN_REGISTER_TEST("ffi", "ffi_pkcs_hashid", FFI_PKCS_Hashid_Test);
5727
BOTAN_REGISTER_TEST("ffi", "ffi_cbc_cipher", FFI_CBC_Cipher_Test);
5728
BOTAN_REGISTER_TEST("ffi", "ffi_gcm", FFI_GCM_Test);
5729
BOTAN_REGISTER_TEST("ffi", "ffi_chacha", FFI_ChaCha20Poly1305_Test);
5730
BOTAN_REGISTER_TEST("ffi", "ffi_eax", FFI_EAX_Test);
5731
BOTAN_REGISTER_TEST("ffi", "ffi_aead", FFI_AEAD_Test);
5732
BOTAN_REGISTER_TEST("ffi", "ffi_streamcipher", FFI_StreamCipher_Test);
5733
BOTAN_REGISTER_TEST("ffi", "ffi_xof", FFI_XOF_Test);
5734
BOTAN_REGISTER_TEST("ffi", "ffi_hashfunction", FFI_HashFunction_Test);
5735
BOTAN_REGISTER_TEST("ffi", "ffi_mac", FFI_MAC_Test);
5736
BOTAN_REGISTER_TEST("ffi", "ffi_scrypt", FFI_Scrypt_Test);
5737
BOTAN_REGISTER_TEST("ffi", "ffi_kdf", FFI_KDF_Test);
5738
BOTAN_REGISTER_TEST("ffi", "ffi_blockcipher", FFI_Blockcipher_Test);
5739
BOTAN_REGISTER_TEST("ffi", "ffi_errorhandling", FFI_ErrorHandling_Test);
5740
BOTAN_REGISTER_TEST("ffi", "ffi_base64", FFI_Base64_Test);
5741
BOTAN_REGISTER_TEST("ffi", "ffi_hex", FFI_Hex_Test);
5742
BOTAN_REGISTER_TEST("ffi", "ffi_mp", FFI_MP_Test);
5743
BOTAN_REGISTER_TEST("ffi", "ffi_fpe", FFI_FPE_Test);
5744
BOTAN_REGISTER_TEST("ffi", "ffi_totp", FFI_TOTP_Test);
5745
BOTAN_REGISTER_TEST("ffi", "ffi_hotp", FFI_HOTP_Test);
5746
BOTAN_REGISTER_TEST("ffi", "ffi_keywrap", FFI_Keywrap_Test);
5747
BOTAN_REGISTER_TEST("ffi", "ffi_xmss", FFI_XMSS_Test);
5748
BOTAN_REGISTER_TEST("ffi", "ffi_rsa", FFI_RSA_Test);
5749
BOTAN_REGISTER_TEST("ffi", "ffi_dsa", FFI_DSA_Test);
5750
BOTAN_REGISTER_TEST("ffi", "ffi_ecdsa", FFI_ECDSA_Test);
5751
BOTAN_REGISTER_TEST("ffi", "ffi_sm2_sig", FFI_SM2_Sig_Test);
5752
BOTAN_REGISTER_TEST("ffi", "ffi_sm2_enc", FFI_SM2_Enc_Test);
5753
BOTAN_REGISTER_TEST("ffi", "ffi_ecdh", FFI_ECDH_Test);
5754
BOTAN_REGISTER_TEST("ffi", "ffi_mceliece", FFI_McEliece_Test);
5755
BOTAN_REGISTER_TEST("ffi", "ffi_ed25519", FFI_Ed25519_Test);
5756
BOTAN_REGISTER_TEST("ffi", "ffi_ed448", FFI_Ed448_Test);
5757
BOTAN_REGISTER_TEST("ffi", "ffi_x25519", FFI_X25519_Test);
5758
BOTAN_REGISTER_TEST("ffi", "ffi_x448", FFI_X448_Test);
5759
BOTAN_REGISTER_TEST("ffi", "ffi_kyber512", FFI_Kyber512_Test);
5760
BOTAN_REGISTER_TEST("ffi", "ffi_kyber768", FFI_Kyber768_Test);
5761
BOTAN_REGISTER_TEST("ffi", "ffi_kyber1024", FFI_Kyber1024_Test);
5762
BOTAN_REGISTER_TEST("ffi", "ffi_ml_kem", FFI_ML_KEM_Test);
5763
BOTAN_REGISTER_TEST("ffi", "ffi_ml_dsa", FFI_ML_DSA_Test);
5764
BOTAN_REGISTER_TEST("ffi", "ffi_slh_dsa", FFI_SLH_DSA_Test);
5765
BOTAN_REGISTER_TEST("ffi", "ffi_frodokem", FFI_FrodoKEM_Test);
5766
BOTAN_REGISTER_TEST("ffi", "ffi_cmce", FFI_Classic_McEliece_Test);
5767
BOTAN_REGISTER_TEST("ffi", "ffi_elgamal", FFI_ElGamal_Test);
5768
BOTAN_REGISTER_TEST("ffi", "ffi_dh", FFI_DH_Test);
5769
BOTAN_REGISTER_TEST("ffi", "ffi_oid", FFI_OID_Test);
5770
BOTAN_REGISTER_TEST("ffi", "ffi_ec_group", FFI_EC_Group_Test);
5771
BOTAN_REGISTER_TEST("ffi", "ffi_ec_points", FFI_EC_Point_Test);
5772
BOTAN_REGISTER_TEST("ffi", "ffi_srp6", FFI_SRP6_Test);
5773

5774
   #if defined(BOTAN_HAS_X509)
5775
BOTAN_REGISTER_TEST("ffi", "ffi_cert_alt_names", FFI_Cert_AlternativeNames_Test);
5776
BOTAN_REGISTER_TEST("ffi", "ffi_cert_name_constraints", FFI_Cert_NameConstraints_Test);
5777
BOTAN_REGISTER_TEST("ffi", "ffi_cert_aia", FFI_Cert_AuthorityInformationAccess_Test);
5778
   #endif
5779

5780
#endif
5781

5782
}  // namespace
5783

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

© 2026 Coveralls, Inc