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

randombit / botan / 16884363558

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

Pull #4877

github

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

100748 of 111123 relevant lines covered (90.66%)

12297786.9 hits per line

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

97.07
/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
#define BOTAN_NO_DEPRECATED_WARNINGS
11

12
#include "tests.h"
13
#include <botan/version.h>
14

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

26
#if defined(BOTAN_HAS_TPM2)
27
   #include <tss2/tss2_esys.h>
28
   #include <tss2/tss2_tctildr.h>
29
#endif
30

31
namespace Botan_Tests {
32

33
namespace {
34

35
#if defined(BOTAN_HAS_FFI)
36

37
// NOLINTBEGIN(*-macro-usage)
38

39
   #define _TEST_FFI_STR_HELPER(x) #x
40

41
   #define _TEST_FFI_STR(x) _TEST_FFI_STR_HELPER(x)
42

43
   #define _TEST_FFI_SOURCE_LOCATION(func, file, line) (func " invoked at " file ":" _TEST_FFI_STR(line))
44

45
   #define TEST_FFI_OK(func, args) result.test_rc_ok(_TEST_FFI_SOURCE_LOCATION(#func, __FILE__, __LINE__), func args)
46

47
   #define TEST_FFI_INIT(func, args) \
48
      result.test_rc_init(_TEST_FFI_SOURCE_LOCATION(#func, __FILE__, __LINE__), func args)
49

50
   #define TEST_FFI_FAIL(msg, func, args) \
51
      result.test_rc_fail(_TEST_FFI_SOURCE_LOCATION(#func, __FILE__, __LINE__), msg, func args)
52

53
   #define TEST_FFI_RC(rc, func, args) \
54
      result.test_rc(_TEST_FFI_SOURCE_LOCATION(#func, __FILE__, __LINE__), rc, func args)
55

56
   #define REQUIRE_FFI_OK(func, args)                           \
57
      if(!TEST_FFI_OK(func, args)) {                            \
58
         result.test_note("Exiting test early due to failure"); \
59
         return;                                                \
60
      }
61

62
// NOLINTEND(*-macro-usage)
63

64
// NOLINTBEGIN(*-init-variables)
65

66
class FFI_Test : public Test {
53✔
67
   public:
68
      std::vector<Test::Result> run() override {
53✔
69
         Test::Result result(this->name());
53✔
70

71
         botan_rng_t rng;
53✔
72
         if(botan_rng_init(&rng, "system") != 0) {
53✔
73
            result.test_failure("Failed to init RNG");
×
74
            return {result};
×
75
         }
76

77
         result.start_timer();
53✔
78
         ffi_test(result, rng);
53✔
79
         result.end_timer();
53✔
80

81
         botan_rng_destroy(rng);
53✔
82

83
         return {result};
106✔
84
      }
106✔
85

86
   private:
87
      virtual std::string name() const = 0;
88
      virtual void ffi_test(Test::Result& result, botan_rng_t rng) = 0;
89
};
90

91
/**
92
 * Helper class for testing "view"-style API functions that take a callback
93
 * that gets passed a variable-length buffer of bytes.
94
 *
95
 * Example:
96
 *   botan_privkey_t priv;
97
 *   ViewBytesSink sink;
98
 *   botan_privkey_view_raw(priv, sink.delegate(), sink.callback());
99
 *   std::cout << hex_encode(sink.get()) << std::endl;
100
 */
101
class ViewBytesSink final {
×
102
   public:
103
      void* delegate() { return this; }
104

105
      botan_view_bin_fn callback() { return &write_fn; }
200✔
106

107
      const std::vector<uint8_t>& get() { return m_buf; }
108

109
   private:
110
      static int write_fn(void* ctx, const uint8_t buf[], size_t len) {
200✔
111
         if(ctx == nullptr || buf == nullptr) {
200✔
112
            return BOTAN_FFI_ERROR_NULL_POINTER;
113
         }
114

115
         auto* sink = static_cast<ViewBytesSink*>(ctx);
200✔
116
         sink->m_buf.assign(buf, buf + len);
200✔
117

118
         return 0;
200✔
119
      }
120

121
   private:
122
      std::vector<uint8_t> m_buf;
123
};
124

125
/**
126
 * See ViewBytesSink for how to use this. Works for `botan_view_str_fn` instead.
127
*/
128
class ViewStringSink final {
12✔
129
   public:
130
      void* delegate() { return this; }
131

132
      botan_view_str_fn callback() { return &write_fn; }
4✔
133

134
      std::string_view get() { return m_str; }
4✔
135

136
   private:
137
      static int write_fn(void* ctx, const char* str, size_t len) {
4✔
138
         if(ctx == nullptr || str == nullptr) {
4✔
139
            return BOTAN_FFI_ERROR_NULL_POINTER;
140
         }
141

142
         auto* sink = static_cast<ViewStringSink*>(ctx);
4✔
143
         // discard the null terminator
144
         sink->m_str = std::string(str, len - 1);
4✔
145

146
         return 0;
4✔
147
      }
148

149
   private:
150
      std::string m_str;
151
};
152

153
void ffi_test_pubkey_export(Test::Result& result, botan_pubkey_t pub, botan_privkey_t priv, botan_rng_t rng) {
11✔
154
   // export public key
155
   size_t pubkey_len = 0;
11✔
156
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
157
               botan_pubkey_export,
158
               (pub, nullptr, &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
159

160
   std::vector<uint8_t> pubkey(pubkey_len);
11✔
161
   TEST_FFI_OK(botan_pubkey_export, (pub, pubkey.data(), &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
11✔
162

163
   pubkey_len = 0;
11✔
164
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
165
               botan_pubkey_export,
166
               (pub, nullptr, &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
167

168
   pubkey.resize(pubkey_len);
11✔
169
   TEST_FFI_OK(botan_pubkey_export, (pub, pubkey.data(), &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
11✔
170

171
   // reimport exported public key
172
   botan_pubkey_t pub_copy;
11✔
173
   TEST_FFI_OK(botan_pubkey_load, (&pub_copy, pubkey.data(), pubkey_len));
11✔
174
   TEST_FFI_OK(botan_pubkey_check_key, (pub_copy, rng, 0));
11✔
175
   TEST_FFI_OK(botan_pubkey_destroy, (pub_copy));
11✔
176

177
   // export private key
178
   std::vector<uint8_t> privkey;
11✔
179
   size_t privkey_len = 0;
11✔
180

181
   // call with nullptr to query the length
182
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
183
               botan_privkey_export,
184
               (priv, nullptr, &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
185

186
   privkey.resize(privkey_len);
11✔
187
   privkey_len = privkey.size();  // set buffer size
11✔
188

189
   TEST_FFI_OK(botan_privkey_export, (priv, privkey.data(), &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
11✔
190

191
   privkey.resize(privkey_len);
11✔
192

193
   result.test_gte("Reasonable size", privkey.size(), 32);
11✔
194

195
   // reimport exported private key
196
   botan_privkey_t copy;
11✔
197
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), nullptr));
11✔
198
   botan_privkey_destroy(copy);
11✔
199

200
   // Now again for PEM
201
   privkey_len = 0;
11✔
202

203
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
204
               botan_privkey_export,
205
               (priv, nullptr, &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
206

207
   privkey.resize(privkey_len);
11✔
208
   TEST_FFI_OK(botan_privkey_export, (priv, privkey.data(), &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
11✔
209

210
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), nullptr));
11✔
211
   botan_privkey_destroy(copy);
11✔
212

213
   #if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_PKCS5_PBES2)
214
   const size_t pbkdf_iter = 1000;
11✔
215

216
   // export private key encrypted
217
   privkey_len = 0;
11✔
218
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
219
               botan_privkey_export_encrypted_pbkdf_iter,
220
               (priv, nullptr, &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_DER));
221

222
   privkey.resize(privkey_len);
11✔
223
   privkey_len = privkey.size();
11✔
224

225
   TEST_FFI_OK(
11✔
226
      botan_privkey_export_encrypted_pbkdf_iter,
227
      (priv, privkey.data(), &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_DER));
228

229
   // reimport encrypted private key
230
   botan_privkey_load(&copy, rng, privkey.data(), privkey.size(), "password");
11✔
231
   botan_privkey_destroy(copy);
11✔
232

233
   privkey_len = 0;
11✔
234
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
235
               botan_privkey_export_encrypted_pbkdf_iter,
236
               (priv, nullptr, &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
237

238
   privkey.resize(privkey_len);
11✔
239
   TEST_FFI_OK(
11✔
240
      botan_privkey_export_encrypted_pbkdf_iter,
241
      (priv, privkey.data(), &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
242

243
   privkey.resize(privkey_len * 2);
11✔
244
   privkey_len = privkey.size();
11✔
245
   const uint32_t pbkdf_msec = 100;
11✔
246
   size_t pbkdf_iters_out = 0;
11✔
247

248
      #if defined(BOTAN_HAS_SCRYPT)
249
   const std::string pbe_hash = "Scrypt";
11✔
250
      #else
251
   const std::string pbe_hash = "SHA-512";
252
      #endif
253

254
      #if defined(BOTAN_HAS_AEAD_GCM)
255
   const std::string pbe_cipher = "AES-256/GCM";
11✔
256
      #else
257
   const std::string pbe_cipher = "AES-256/CBC";
258
      #endif
259

260
   TEST_FFI_OK(botan_privkey_export_encrypted_pbkdf_msec,
11✔
261
               (priv,
262
                privkey.data(),
263
                &privkey_len,
264
                rng,
265
                "password",
266
                pbkdf_msec,
267
                &pbkdf_iters_out,
268
                pbe_cipher.c_str(),
269
                pbe_hash.c_str(),
270
                0));
271

272
   if(pbe_hash == "Scrypt") {
11✔
273
      result.test_eq("Scrypt iters set to zero in this API", pbkdf_iters_out, 0);
22✔
274
   } else {
275
      // PBKDF2 currently always rounds to multiple of 2000
276
      result.test_eq("Expected PBKDF2 iters", pbkdf_iters_out % 2000, 0);
×
277
   }
278

279
   privkey.resize(privkey_len);
11✔
280

281
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), "password"));
11✔
282
   botan_privkey_destroy(copy);
11✔
283
   #endif
284

285
   // calculate fingerprint
286
   size_t strength = 0;
11✔
287
   TEST_FFI_OK(botan_pubkey_estimated_strength, (pub, &strength));
11✔
288
   result.test_gte("estimated strength", strength, 1);
11✔
289

290
   size_t fingerprint_len = 0;
11✔
291
   TEST_FFI_RC(
11✔
292
      BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_pubkey_fingerprint, (pub, "SHA-256", nullptr, &fingerprint_len));
293

294
   std::vector<uint8_t> fingerprint(fingerprint_len);
11✔
295
   TEST_FFI_OK(botan_pubkey_fingerprint, (pub, "SHA-256", fingerprint.data(), &fingerprint_len));
22✔
296
}
33✔
297

298
class FFI_Utils_Test final : public FFI_Test {
×
299
   public:
300
      std::string name() const override { return "FFI Utils"; }
1✔
301

302
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
303
         result.test_is_eq("FFI API version macro", uint32_t(BOTAN_FFI_API_VERSION), uint32_t(BOTAN_HAS_FFI));
1✔
304
         result.test_is_eq("FFI API version function", botan_ffi_api_version(), uint32_t(BOTAN_HAS_FFI));
1✔
305
         result.test_is_eq("Major version", botan_version_major(), Botan::version_major());
1✔
306
         result.test_is_eq("Minor version", botan_version_minor(), Botan::version_minor());
1✔
307
         result.test_is_eq("Patch version", botan_version_patch(), Botan::version_patch());
1✔
308
         result.test_is_eq("Botan version", botan_version_string(), Botan::version_cstr());
1✔
309
         result.test_is_eq("Botan version datestamp", botan_version_datestamp(), Botan::version_datestamp());
1✔
310
         result.test_is_eq("FFI supports its own version", botan_ffi_supports_api(botan_ffi_api_version()), 0);
1✔
311

312
         result.test_is_eq("FFI compile time time var matches botan_ffi_api_version",
1✔
313
                           botan_ffi_api_version(),
1✔
314
                           uint32_t(BOTAN_FFI_API_VERSION));
1✔
315

316
         result.test_is_eq("FFI supports 2.0 version", botan_ffi_supports_api(20150515), 0);
1✔
317
         result.test_is_eq("FFI supports 2.1 version", botan_ffi_supports_api(20170327), 0);
1✔
318
         result.test_is_eq("FFI supports 2.3 version", botan_ffi_supports_api(20170815), 0);
1✔
319
         result.test_is_eq("FFI supports 2.8 version", botan_ffi_supports_api(20180713), 0);
1✔
320

321
         result.test_is_eq("FFI doesn't support bogus version", botan_ffi_supports_api(20160229), -1);
1✔
322

323
         const std::vector<uint8_t> mem1 = {0xFF, 0xAA, 0xFF};
1✔
324
         const std::vector<uint8_t> mem2 = {0xFF, 0xA9, 0xFF};
1✔
325

326
         TEST_FFI_RC(0, botan_constant_time_compare, (mem1.data(), mem1.data(), mem1.size()));
1✔
327
         TEST_FFI_RC(-1, botan_constant_time_compare, (mem1.data(), mem2.data(), mem1.size()));
1✔
328

329
         std::vector<uint8_t> to_zero = {0xFF, 0xA0};
1✔
330
         TEST_FFI_OK(botan_scrub_mem, (to_zero.data(), to_zero.size()));
1✔
331
         result.confirm("scrub_memory zeros", to_zero[0] == 0 && to_zero[1] == 0);
2✔
332

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

335
         std::string outstr;
1✔
336
         std::vector<uint8_t> outbuf;
1✔
337

338
         outstr.resize(2 * bin.size());
1✔
339
         TEST_FFI_OK(botan_hex_encode, (bin.data(), bin.size(), outstr.data(), 0));
1✔
340
         result.test_eq("uppercase hex", outstr, "AADE01");
2✔
341

342
         TEST_FFI_OK(botan_hex_encode, (bin.data(), bin.size(), outstr.data(), BOTAN_FFI_HEX_LOWER_CASE));
1✔
343
         result.test_eq("lowercase hex", outstr, "aade01");
2✔
344
      }
4✔
345
};
346

347
class FFI_RNG_Test final : public FFI_Test {
×
348
   public:
349
      std::string name() const override { return "FFI RNG"; }
1✔
350

351
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
352
         // RNG test and initialization
353
         botan_rng_t rng;
1✔
354
         botan_rng_t system_rng;
1✔
355
         botan_rng_t hwrng_rng = nullptr;
1✔
356
         botan_rng_t null_rng;
1✔
357
         botan_rng_t custom_rng;
1✔
358
         botan_rng_t tpm2_rng = nullptr;
1✔
359

360
         botan_tpm2_ctx_t tpm2_ctx = nullptr;
1✔
361
         botan_tpm2_session_t tpm2_session = nullptr;
1✔
362

363
         TEST_FFI_FAIL("invalid rng type", botan_rng_init, (&rng, "invalid_type"));
2✔
364

365
         REQUIRE_FFI_OK(botan_rng_init, (&system_rng, "system"));
1✔
366
         REQUIRE_FFI_OK(botan_rng_init, (&null_rng, "null"));
1✔
367

368
         int rc = botan_rng_init(&hwrng_rng, "hwrng");
1✔
369
         result.confirm("Either success or not implemented", rc == 0 || rc == BOTAN_FFI_ERROR_NOT_IMPLEMENTED);
2✔
370

371
         std::vector<uint8_t> outbuf(512);
1✔
372

373
         rc = botan_rng_init(&rng, "user-threadsafe");
1✔
374
         result.confirm("Either success or not implemented", rc == 0 || rc == BOTAN_FFI_ERROR_NOT_IMPLEMENTED);
2✔
375

376
         if(rc != 0) {
1✔
377
            REQUIRE_FFI_OK(botan_rng_init, (&rng, "user"));
×
378
            REQUIRE_FFI_OK(botan_rng_destroy, (rng));
×
379
         }
380

381
         if(rc == 0) {
1✔
382
            TEST_FFI_OK(botan_rng_get, (rng, outbuf.data(), outbuf.size()));
1✔
383
            TEST_FFI_OK(botan_rng_reseed, (rng, 256));
1✔
384

385
            TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, botan_rng_reseed_from_rng, (rng, null_rng, 256));
1✔
386
            if(hwrng_rng != nullptr) {
1✔
387
               TEST_FFI_OK(botan_rng_reseed_from_rng, (rng, hwrng_rng, 256));
2✔
388
            }
389
            TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, botan_rng_get, (null_rng, outbuf.data(), outbuf.size()));
1✔
390

391
            TEST_FFI_OK(botan_rng_destroy, (rng));
2✔
392
         }
393

394
         if(TEST_FFI_OK(botan_rng_init, (&rng, "user"))) {
1✔
395
            TEST_FFI_OK(botan_rng_get, (rng, outbuf.data(), outbuf.size()));
1✔
396
            TEST_FFI_OK(botan_rng_reseed, (rng, 256));
1✔
397

398
            TEST_FFI_OK(botan_rng_reseed_from_rng, (rng, system_rng, 256));
1✔
399

400
            uint8_t not_really_entropy[32] = {0};
1✔
401
            TEST_FFI_OK(botan_rng_add_entropy, (rng, not_really_entropy, 32));
2✔
402
         }
403

404
         uint8_t system_rng_buf[4096];
1✔
405
         TEST_FFI_OK(botan_system_rng_get, (system_rng_buf, sizeof(system_rng_buf)));
1✔
406

407
         size_t cb_counter = 0;
1✔
408

409
         auto custom_get_cb = +[](void* context, uint8_t* out, size_t out_len) -> int {
1✔
410
            for(size_t i = 0; i != out_len; ++i) {
411
               out[i] = 0x12;
412
            }
413
            (*(static_cast<size_t*>(context)))++;
414
            return 0;
415
         };
416

417
         auto custom_add_entropy_cb = +[](void* context, const uint8_t input[], size_t length) -> int {
1✔
418
            BOTAN_UNUSED(input, length);
419
            (*(static_cast<size_t*>(context)))++;
420
            return 0;
421
         };
422

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

425
         if(TEST_FFI_OK(
1✔
426
               botan_rng_init_custom,
427
               (&custom_rng, "custom rng", &cb_counter, custom_get_cb, custom_add_entropy_cb, custom_destroy_cb))) {
428
            Botan::clear_mem(outbuf.data(), outbuf.size());
1✔
429
            TEST_FFI_OK(botan_rng_get, (custom_rng, outbuf.data(), outbuf.size()));
1✔
430
            result.test_eq("custom_get_cb called", cb_counter, 1);
1✔
431
            std::vector<uint8_t> pattern(outbuf.size(), 0x12);
1✔
432
            result.test_eq("custom_get_cb returned bytes", pattern, outbuf);
2✔
433

434
            TEST_FFI_OK(botan_rng_reseed, (custom_rng, 256));
1✔
435
            result.test_eq("custom_add_entropy_cb called", cb_counter, 2);
1✔
436

437
            TEST_FFI_OK(botan_rng_reseed_from_rng, (custom_rng, system_rng, 256));
1✔
438
            result.test_eq("custom_add_entropy_cb called", cb_counter, 3);
1✔
439

440
            uint8_t not_really_entropy[32] = {0};
1✔
441
            TEST_FFI_OK(botan_rng_add_entropy, (custom_rng, not_really_entropy, 32));
1✔
442
            result.test_eq("custom_add_entropy_cb called", cb_counter, 4);
1✔
443

444
            TEST_FFI_OK(botan_rng_destroy, (custom_rng));
1✔
445
            result.test_eq("custom_destroy_cb called", cb_counter, 5);
2✔
446
         }
1✔
447

448
   #ifdef BOTAN_HAS_JITTER_RNG
449
         botan_rng_t jitter_rng;
1✔
450
         if(TEST_FFI_OK(botan_rng_init, (&jitter_rng, "jitter"))) {
1✔
451
            std::vector<uint8_t> buf(256);
1✔
452
            TEST_FFI_OK(botan_rng_get, (jitter_rng, outbuf.data(), buf.size()));
1✔
453
            TEST_FFI_OK(botan_rng_destroy, (jitter_rng));
2✔
454
         }
1✔
455
   #endif
456

457
         const auto tcti_name = Test::options().tpm2_tcti_name().value_or("");
1✔
458
         const auto tcti_conf = Test::options().tpm2_tcti_conf().value_or("");
1✔
459
         if(tcti_name.empty() || tcti_name == "disabled") {
1✔
460
            result.test_note("TPM2 tests are disabled.");
×
461
         } else {
462
            auto tpm2_test_rng = [&](botan_tpm2_ctx_t tpm2_context) {
3✔
463
               // Create and use an RNG without a TPM2 session
464
               // (communication between application and TPM won't be encrypted)
465
               if(TEST_FFI_INIT(botan_tpm2_rng_init, (&tpm2_rng, tpm2_context, nullptr, nullptr, nullptr))) {
2✔
466
                  Botan::clear_mem(outbuf.data(), outbuf.size());
2✔
467

468
                  TEST_FFI_OK(botan_rng_get, (tpm2_rng, outbuf.data(), outbuf.size()));
2✔
469
                  TEST_FFI_OK(botan_rng_reseed, (tpm2_rng, 256));
2✔
470

471
                  TEST_FFI_OK(botan_rng_reseed_from_rng, (tpm2_rng, system_rng, 256));
2✔
472

473
                  uint8_t not_really_entropy[32] = {0};
2✔
474
                  TEST_FFI_OK(botan_rng_add_entropy, (tpm2_rng, not_really_entropy, 32));
2✔
475
                  TEST_FFI_OK(botan_rng_destroy, (tpm2_rng));
4✔
476
               }
477

478
               // Create an anonymous TPM2 session
479
               if(TEST_FFI_INIT(botan_tpm2_unauthenticated_session_init, (&tpm2_session, tpm2_context))) {
2✔
480
                  // Create and use an RNG with an anonymous TPM2 session
481
                  // (communication between application and TPM will be encrypted)
482
                  if(TEST_FFI_INIT(botan_tpm2_rng_init, (&tpm2_rng, tpm2_context, tpm2_session, nullptr, nullptr))) {
2✔
483
                     Botan::clear_mem(outbuf.data(), outbuf.size());
2✔
484

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

488
                     TEST_FFI_OK(botan_rng_reseed_from_rng, (tpm2_rng, system_rng, 256));
2✔
489

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

495
                  TEST_FFI_OK(botan_tpm2_session_destroy, (tpm2_session));
4✔
496
               }
497
            };
2✔
498

499
            if(TEST_FFI_INIT(botan_tpm2_ctx_init_ex, (&tpm2_ctx, tcti_name.c_str(), tcti_conf.c_str()))) {
1✔
500
               if(botan_tpm2_supports_crypto_backend() == 1) {
1✔
501
                  TEST_FFI_OK(botan_tpm2_ctx_enable_crypto_backend, (tpm2_ctx, system_rng));
1✔
502
                  result.test_note("TPM2 crypto backend enabled");
2✔
503
               } else {
504
                  result.test_note("TPM2 crypto backend not supported");
×
505
               }
506

507
               tpm2_test_rng(tpm2_ctx);
1✔
508
               TEST_FFI_OK(botan_tpm2_ctx_destroy, (tpm2_ctx));
2✔
509
            }
510

511
   #if defined(BOTAN_HAS_TPM2)
512
            TSS2_TCTI_CONTEXT* tcti_ctx;
1✔
513
            ESYS_CONTEXT* esys_ctx;
1✔
514

515
            if(TEST_FFI_INIT(Tss2_TctiLdr_Initialize_Ex, (tcti_name.c_str(), tcti_conf.c_str(), &tcti_ctx))) {
1✔
516
               if(TEST_FFI_INIT(Esys_Initialize, (&esys_ctx, tcti_ctx, nullptr /* ABI version */))) {
1✔
517
                  botan_tpm2_crypto_backend_state_t cbs = nullptr;
1✔
518

519
                  // enable the botan-based TSS2 crypto backend on a bare ESYS_CONTEXT
520
                  if(botan_tpm2_supports_crypto_backend() == 1) {
1✔
521
                     TEST_FFI_OK(botan_tpm2_enable_crypto_backend, (&cbs, esys_ctx, system_rng));
1✔
522
                     result.test_note("TPM2 crypto backend enabled");
2✔
523
                  } else {
524
                     result.test_note("TPM2 crypto backend not supported");
×
525
                  }
526

527
                  // initialize the Botan TPM2 FFI wrapper from the bare ESYS_CONTEXT
528
                  if(TEST_FFI_INIT(botan_tpm2_ctx_from_esys, (&tpm2_ctx, esys_ctx))) {
1✔
529
                     tpm2_test_rng(tpm2_ctx);
1✔
530
                     TEST_FFI_OK(botan_tpm2_ctx_destroy, (tpm2_ctx));
2✔
531
                  }
532

533
                  if(cbs != nullptr) {
1✔
534
                     TEST_FFI_OK(botan_tpm2_crypto_backend_state_destroy, (cbs));
2✔
535
                  }
536

537
                  Esys_Finalize(&esys_ctx);
1✔
538
               }
539
               Tss2_TctiLdr_Finalize(&tcti_ctx);
1✔
540
            }
541
   #endif
542
         }
543

544
         TEST_FFI_OK(botan_rng_destroy, (rng));
1✔
545
         TEST_FFI_OK(botan_rng_destroy, (null_rng));
1✔
546
         TEST_FFI_OK(botan_rng_destroy, (system_rng));
1✔
547
         TEST_FFI_OK(botan_rng_destroy, (hwrng_rng));
2✔
548
      }
2✔
549
};
550

551
class FFI_RSA_Cert_Test final : public FFI_Test {
×
552
   public:
553
      std::string name() const override { return "FFI RSA cert"; }
1✔
554

555
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
556
         botan_x509_cert_t cert;
1✔
557
         if(TEST_FFI_INIT(botan_x509_cert_load_file, (&cert, Test::data_file("x509/ocsp/randombit.pem").c_str()))) {
1✔
558
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (cert, "randombit.net"));
1✔
559
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (cert, "www.randombit.net"));
1✔
560
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "*.randombit.net"));
1✔
561
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "flub.randombit.net"));
1✔
562
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "randombit.net.com"));
1✔
563

564
            botan_x509_cert_t copy;
1✔
565
            TEST_FFI_OK(botan_x509_cert_dup, (&copy, cert));
1✔
566
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (copy, "randombit.net"));
1✔
567

568
            TEST_FFI_OK(botan_x509_cert_destroy, (copy));
1✔
569
            TEST_FFI_OK(botan_x509_cert_destroy, (cert));
2✔
570
         }
571
      }
1✔
572
};
573

574
class FFI_ZFEC_Test final : public FFI_Test {
×
575
   public:
576
      std::string name() const override { return "FFI ZFEC"; }
1✔
577

578
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
579
         /* exercise a simple success case
580
          */
581

582
         // Select some arbitrary, valid encoding parameters.  There is
583
         // nothing special about them but some relationships between these
584
         // values and other inputs must hold.
585
         const size_t K = 3;
1✔
586
         const size_t N = 11;
1✔
587

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

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

598
         // K of the blocks are required so the total information represented
599
         // can be this multiple.  totalSize must be a multiple of K and it
600
         // always will be using this construction.
601
         const size_t totalSize = blockSize * K;
1✔
602

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

607
         // Allocate memory for the encoding and decoding output parameters.
608
         std::vector<uint8_t> encoded_buf(N * blockSize);
1✔
609
         std::vector<uint8_t> decoded_buf(K * blockSize);
1✔
610

611
         std::vector<uint8_t*> encoded(N);
1✔
612
         for(size_t i = 0; i < N; ++i) {
12✔
613
            encoded[i] = &encoded_buf[i * blockSize];
11✔
614
         }
615
         std::vector<uint8_t*> decoded(K);
1✔
616
         for(size_t i = 0; i < K; ++i) {
4✔
617
            decoded[i] = &decoded_buf[i * blockSize];
3✔
618
         }
619

620
         // First encode the complete input string into N blocks where K are
621
         // required for reconstruction.  The N encoded blocks will end up in
622
         // `encoded`.
623
         if(!TEST_FFI_INIT(botan_zfec_encode, (K, N, input, totalSize, encoded.data()))) {
1✔
624
            return;
625
         }
626

627
         // Any K blocks can be decoded to reproduce the original input (split
628
         // across an array of K strings of blockSize bytes each).  This loop
629
         // only exercises decoding with consecutive blocks because it's
630
         // harder to pick non-consecutive blocks out for a test.
631
         for(size_t offset = 0; offset < N - K; ++offset) {
9✔
632
            result.test_note("About to decode with offset " + std::to_string(offset));
24✔
633
            // Pass in the K shares starting from `offset` (and their indexes)
634
            // so that we can try decoding a certain group of blocks here.  Any
635
            // K shares *should* work.
636
            REQUIRE_FFI_OK(botan_zfec_decode,
8✔
637
                           (K, N, indexes.data() + offset, encoded.data() + offset, blockSize, decoded.data()));
638

639
            // Check that the original input bytes have been written to the
640
            // output parameter.
641
            for(size_t k = 0, pos = 0; k < K; ++k, pos += blockSize) {
32✔
642
               TEST_FFI_RC(0, botan_constant_time_compare, (input + pos, decoded[k], blockSize));
48✔
643
            }
644
         }
645

646
         /* Exercise a couple basic failure cases, such as you encounter if
647
          * the caller supplies invalid parameters.  We don't try to
648
          * exhaustively prove invalid parameters are handled through this
649
          * interface since the implementation only passes them through to
650
          * ZFEC::{encode,decode} where the real checking is.  We just want to
651
          * see that errors can propagate.
652
          */
653
         TEST_FFI_FAIL("encode with out-of-bounds encoding parameters should have failed",
2✔
654
                       botan_zfec_encode,
655
                       (0, 0, nullptr, 0, nullptr));
656
         TEST_FFI_FAIL("decode with out-of-bounds encoding parameters should have failed",
2✔
657
                       botan_zfec_decode,
658
                       (0, 0, nullptr, nullptr, 0, nullptr));
659
      }
3✔
660
};
661

662
class FFI_CRL_Test final : public FFI_Test {
×
663
   public:
664
      std::string name() const override { return "FFI CRL"; }
1✔
665

666
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
667
         const char* crl_string =
1✔
668
            "-----BEGIN X509 CRL-----\n"
669
            "MIICoTCCAQkCAQEwDQYJKoZIhvcNAQELBQAwgZQxLTArBgNVBAMTJFVzYWJsZSBj\n"
670
            "ZXJ0IHZhbGlkYXRpb246IFRlbXBvcmFyeSBDQTE5MDcGA1UECxMwQ2VudHJlIGZv\n"
671
            "ciBSZXNlYXJjaCBvbiBDcnlwdG9ncmFwaHkgYW5kIFNlY3VyaXR5MRswGQYDVQQK\n"
672
            "ExJNYXNhcnlrIFVuaXZlcnNpdHkxCzAJBgNVBAYTAkNaGA8yMDUwMDIyNTE1MjE0\n"
673
            "MloYDzIwNTAwMjI1MTUyNDQxWjAAoDowODAfBgNVHSMEGDAWgBRKzxAvI4+rVVo/\n"
674
            "JzLigRznREyB+TAVBgNVHRQEDgIMXcr16yNys/gjeuCFMA0GCSqGSIb3DQEBCwUA\n"
675
            "A4IBgQCfxv/5REM/KUnzeVycph3dJr1Yrtxhc6pZmQ9pMzSW/nawLN3rUHm5oG44\n"
676
            "ZuQgjvzE4PnbU0/DNRu/4w3H58kgrctJHHXbbvkU3lf2ZZLh2wBl+EUh92+/COow\n"
677
            "ZyGB+jqj/XwB99hYUhrY6NLEWRz08kpgG6dnNMEU0uFqdQKWk0CQPnmgPRgDb8BW\n"
678
            "IuMBcjY7aF9XoCZFOqPYdEvUKzAo4QGCf7uJ7fNGS3LqvjaLjAHJseSr5/yR7Q9r\n"
679
            "nEdI38yKPbRj0tNHe7j+BbYg31C+X+AZZKJtlTg8GxYR3qfQio1kDgpZ3rQLzHY3\n"
680
            "ea2MLX/Kdx9cPSwh4KwlcDxQmQKoELb4EnZW1CScSBHi9HQyCBNyCkgkOBMGcJqz\n"
681
            "Ihq1dGeSf8eca9+Avk5kAQ3yjXK1TI2CDEi0msrXLr9XbgowXiOLLzR+rYkhQz+V\n"
682
            "RnIoBwjnrGoJoz636KS170SZCB9ARNs17WE4IvbJdZrTXNOGaVZCQUUpiLRj4ZSO\n"
683
            "Na/nobI=\n"
684
            "-----END X509 CRL-----";
685

686
         botan_x509_crl_t bytecrl;
1✔
687
         if(!TEST_FFI_INIT(botan_x509_crl_load, (&bytecrl, reinterpret_cast<const uint8_t*>(crl_string), 966))) {
1✔
688
            return;
×
689
         }
690

691
         botan_x509_crl_t crl;
1✔
692
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&crl, Test::data_file("x509/nist/root.crl").c_str()));
1✔
693

694
         botan_x509_cert_t cert1;
1✔
695
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&cert1, Test::data_file("x509/nist/test01/end.crt").c_str()));
1✔
696
         TEST_FFI_RC(-1, botan_x509_is_revoked, (crl, cert1));
1✔
697
         TEST_FFI_OK(botan_x509_cert_destroy, (cert1));
1✔
698

699
         botan_x509_cert_t cert2;
1✔
700
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&cert2, Test::data_file("x509/nist/test20/int.crt").c_str()));
1✔
701
         TEST_FFI_RC(0, botan_x509_is_revoked, (crl, cert2));
1✔
702
         TEST_FFI_RC(-1, botan_x509_is_revoked, (bytecrl, cert2));
1✔
703
         TEST_FFI_OK(botan_x509_cert_destroy, (cert2));
1✔
704

705
         TEST_FFI_OK(botan_x509_crl_destroy, (crl));
1✔
706
         TEST_FFI_OK(botan_x509_crl_destroy, (bytecrl));
2✔
707
      }
708
};
709

710
class FFI_Cert_Validation_Test final : public FFI_Test {
×
711
   public:
712
      std::string name() const override { return "FFI Cert Validation"; }
1✔
713

714
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
715
         botan_x509_cert_t root;
1✔
716
         int rc;
1✔
717

718
         if(!TEST_FFI_INIT(botan_x509_cert_load_file, (&root, Test::data_file("x509/nist/root.crt").c_str()))) {
1✔
719
            return;
×
720
         }
721

722
         botan_x509_cert_t end2;
1✔
723
         botan_x509_cert_t sub2;
1✔
724
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end2, Test::data_file("x509/nist/test02/end.crt").c_str()));
1✔
725
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub2, Test::data_file("x509/nist/test02/int.crt").c_str()));
1✔
726

727
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end2, &sub2, 1, &root, 1, nullptr, 0, nullptr, 0));
1✔
728
         result.confirm("Validation test02 failed", rc == 5002);
2✔
729
         result.test_eq("Validation test02 status string", botan_x509_cert_validation_status(rc), "Signature error");
1✔
730

731
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end2, nullptr, 0, &root, 1, nullptr, 0, nullptr, 0));
1✔
732
         result.confirm("Validation test02 failed (missing int)", rc == 3000);
2✔
733
         result.test_eq(
1✔
734
            "Validation test02 status string", botan_x509_cert_validation_status(rc), "Certificate issuer not found");
735

736
         botan_x509_cert_t end7;
1✔
737
         botan_x509_cert_t sub7;
1✔
738
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end7, Test::data_file("x509/nist/test07/end.crt").c_str()));
1✔
739
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub7, Test::data_file("x509/nist/test07/int.crt").c_str()));
1✔
740

741
         botan_x509_cert_t subs[2] = {sub2, sub7};
1✔
742
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end7, subs, 2, &root, 1, nullptr, 0, nullptr, 0));
1✔
743
         result.confirm("Validation test07 failed with expected error", rc == 1001);
2✔
744
         result.test_eq("Validation test07 status string",
1✔
745
                        botan_x509_cert_validation_status(rc),
746
                        "Hash function used is considered too weak for security");
747

748
         TEST_FFI_RC(0, botan_x509_cert_verify, (&rc, end7, subs, 2, &root, 1, nullptr, 80, nullptr, 0));
1✔
749
         result.confirm("Validation test07 passed", rc == 0);
2✔
750
         result.test_eq("Validation test07 status string", botan_x509_cert_validation_status(rc), "Verified");
1✔
751

752
         TEST_FFI_RC(1,
1✔
753
                     botan_x509_cert_verify_with_crl,
754
                     (&rc, end7, subs, 2, nullptr, 0, nullptr, 0, "x509/farce", 0, nullptr, 0));
755
         result.confirm("Validation test07 failed with expected error", rc == 3000);
2✔
756
         result.test_eq(
1✔
757
            "Validation test07 status string", botan_x509_cert_validation_status(rc), "Certificate issuer not found");
758

759
         botan_x509_crl_t rootcrl;
1✔
760

761
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&rootcrl, Test::data_file("x509/nist/root.crl").c_str()));
1✔
762
         TEST_FFI_RC(
1✔
763
            0, botan_x509_cert_verify_with_crl, (&rc, end7, subs, 2, &root, 1, &rootcrl, 1, nullptr, 80, nullptr, 0));
764
         result.confirm("Validation test07 with CRL passed", rc == 0);
2✔
765
         result.test_eq("Validation test07 with CRL status string", botan_x509_cert_validation_status(rc), "Verified");
1✔
766

767
         botan_x509_cert_t end20;
1✔
768
         botan_x509_cert_t sub20;
1✔
769
         botan_x509_crl_t sub20crl;
1✔
770
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end20, Test::data_file("x509/nist/test20/end.crt").c_str()));
1✔
771
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub20, Test::data_file("x509/nist/test20/int.crt").c_str()));
1✔
772
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&sub20crl, Test::data_file("x509/nist/test20/int.crl").c_str()));
1✔
773
         botan_x509_crl_t crls[2] = {sub20crl, rootcrl};
1✔
774
         TEST_FFI_RC(
1✔
775
            1, botan_x509_cert_verify_with_crl, (&rc, end20, &sub20, 1, &root, 1, crls, 2, nullptr, 80, nullptr, 0));
776
         result.confirm("Validation test20 failed with expected error", rc == 5000);
2✔
777
         result.test_eq(
1✔
778
            "Validation test20 status string", botan_x509_cert_validation_status(rc), "Certificate is revoked");
779

780
         TEST_FFI_OK(botan_x509_cert_destroy, (end2));
1✔
781
         TEST_FFI_OK(botan_x509_cert_destroy, (sub2));
1✔
782
         TEST_FFI_OK(botan_x509_cert_destroy, (end7));
1✔
783
         TEST_FFI_OK(botan_x509_cert_destroy, (sub7));
1✔
784
         TEST_FFI_OK(botan_x509_cert_destroy, (end20));
1✔
785
         TEST_FFI_OK(botan_x509_cert_destroy, (sub20));
1✔
786
         TEST_FFI_OK(botan_x509_crl_destroy, (sub20crl));
1✔
787
         TEST_FFI_OK(botan_x509_cert_destroy, (root));
1✔
788
         TEST_FFI_OK(botan_x509_crl_destroy, (rootcrl));
2✔
789
      }
790
};
791

792
class FFI_Cert_Creation_Test final : public FFI_Test {
×
793
   public:
794
      std::string name() const override { return "FFI Cert Creation"; }
1✔
795

796
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
797
         const std::string hash_fn{"SHA-256"};
1✔
798
         const std::string group{"secp256r1"};
1✔
799

800
         botan_privkey_t ca_key;
1✔
801
         botan_pubkey_t ca_key_pub;
1✔
802
         botan_privkey_t cert_key;
1✔
803
         botan_pubkey_t cert_key_pub;
1✔
804

805
         if(TEST_FFI_INIT(botan_privkey_create, (&ca_key, "ECDSA", group.c_str(), rng))) {
1✔
806
            TEST_FFI_OK(botan_privkey_create, (&cert_key, "ECDSA", group.c_str(), rng));
1✔
807

808
            TEST_FFI_OK(botan_privkey_export_pubkey, (&ca_key_pub, ca_key));
1✔
809
            TEST_FFI_OK(botan_privkey_export_pubkey, (&cert_key_pub, cert_key));
1✔
810

811
            uint64_t now =
1✔
812
               std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
1✔
813
                  .count();
1✔
814
            uint64_t not_before = now - 180;
1✔
815
            uint64_t not_after = now + 86400;
1✔
816

817
            botan_x509_cert_params_builder_t ca_builder;
1✔
818
            if(TEST_FFI_INIT(botan_x509_cert_params_builder_create, (&ca_builder))) {
1✔
819
               TEST_FFI_OK(botan_x509_cert_params_builder_add_common_name, (ca_builder, "Test CA"));
1✔
820
               TEST_FFI_OK(botan_x509_cert_params_builder_add_country, (ca_builder, "US"));
1✔
821
               TEST_FFI_OK(botan_x509_cert_params_builder_add_organization, (ca_builder, "Botan Project"));
1✔
822
               TEST_FFI_OK(botan_x509_cert_params_builder_add_organizational_unit, (ca_builder, "Testing"));
1✔
823
               TEST_FFI_OK(botan_x509_cert_params_builder_set_as_ca_certificate, (ca_builder, nullptr));
1✔
824
               TEST_FFI_OK(botan_x509_cert_params_builder_add_uri, (ca_builder, "https://botan.randombit.net"));
1✔
825
               for(const auto* dns : {"imaginary.botan.randombit.net", "botan.randombit.net", "randombit.net"}) {
4✔
826
                  TEST_FFI_OK(botan_x509_cert_params_builder_add_dns, (ca_builder, dns));
6✔
827
               }
828

829
               botan_x509_cert_t ca_cert;
1✔
830
               TEST_FFI_OK(botan_x509_cert_create_self_signed,
1✔
831
                           (&ca_cert, ca_key, ca_builder, rng, not_before, not_after, nullptr, hash_fn.c_str(), ""));
832

833
               botan_x509_cert_params_builder_t req_builder;
1✔
834
               TEST_FFI_OK(botan_x509_cert_params_builder_create, (&req_builder));
1✔
835
               TEST_FFI_OK(botan_x509_cert_params_builder_add_allowed_usage, (req_builder, 1 << 15));
1✔
836

837
               botan_x509_pkcs10_req_t req;
1✔
838
               TEST_FFI_OK(botan_x509_pkcs10_req_create,
1✔
839
                           (&req, cert_key, req_builder, rng, hash_fn.c_str(), nullptr, nullptr));
840

841
               int res;
1✔
842
               TEST_FFI_OK(botan_x509_pkcs10_req_verify_signature, (req, ca_key_pub, &res));
1✔
843
               result.confirm("signature is not valid", res == 0);
2✔
844
               TEST_FFI_OK(botan_x509_pkcs10_req_verify_signature, (req, cert_key_pub, &res));
1✔
845
               result.confirm("signature is valid", res == 1);
2✔
846

847
               uint32_t usage;
1✔
848
               TEST_FFI_OK(botan_x509_pkcs10_req_get_key_constraints, (req, &usage));
1✔
849
               result.confirm("usage is correct", usage == 1 << 15);
2✔
850

851
               int is_ca;
1✔
852
               size_t limit;
1✔
853
               TEST_FFI_OK(botan_x509_pkcs10_req_is_ca, (req, &is_ca, &limit));
1✔
854
               result.confirm("cert is not a CA", is_ca == 0);
2✔
855

856
               botan_pubkey_t pubkey_from_req;
1✔
857
               TEST_FFI_OK(botan_x509_pkcs10_req_get_public_key, (req, &pubkey_from_req));
1✔
858
               TEST_FFI_OK(botan_x509_pkcs10_req_verify_signature, (req, pubkey_from_req, &res));
1✔
859
               result.confirm("signature is valid", res == 1);
2✔
860

861
               ViewStringSink req_pem;
1✔
862
               TEST_FFI_OK(botan_x509_pkcs10_req_view_pem, (req, req_pem.delegate(), req_pem.callback()));
1✔
863
               std::string pem = {req_pem.get().begin(), req_pem.get().end()};
2✔
864

865
               botan_x509_pkcs10_req_t req_from_pem;
1✔
866
               TEST_FFI_OK(botan_x509_pkcs10_req_load,
1✔
867
                           (&req_from_pem, reinterpret_cast<const uint8_t*>(pem.c_str()), pem.size()));
868

869
               TEST_FFI_OK(botan_x509_pkcs10_req_verify_signature, (req_from_pem, cert_key_pub, &res));
1✔
870
               result.confirm("signature is valid", res == 1);
2✔
871

872
               botan_mp_t serial;
1✔
873
               TEST_FFI_OK(botan_mp_init, (&serial));
1✔
874
               TEST_FFI_OK(botan_mp_set_from_str, (serial, "12345"));
1✔
875

876
               botan_x509_cert_t cert;
1✔
877
               TEST_FFI_OK(botan_x509_pkcs10_req_sign,
1✔
878
                           (&cert, req, ca_cert, ca_key, rng, not_before, not_after, &serial, hash_fn.c_str(), ""));
879

880
               std::vector<uint8_t> serial_out(5);
1✔
881
               size_t out_len = 5;
1✔
882

883
               botan_mp_t serial_from_cert;
1✔
884
               TEST_FFI_OK(botan_mp_init, (&serial_from_cert));
1✔
885

886
               TEST_FFI_OK(botan_x509_cert_get_serial_number, (cert, serial_out.data(), &out_len));
1✔
887
               TEST_FFI_OK(botan_mp_from_bin, (serial_from_cert, serial_out.data(), out_len));
1✔
888
               TEST_FFI_RC(1, botan_mp_equal, (serial, serial_from_cert));
1✔
889

890
               int rc;
1✔
891
               TEST_FFI_RC(0, botan_x509_cert_verify, (&rc, cert, nullptr, 0, &ca_cert, 1, nullptr, 0, nullptr, 0));
1✔
892
               result.confirm("validation succeeds", rc == 0);
2✔
893

894
               botan_x509_crl_t crl;
1✔
895
               TEST_FFI_OK(botan_x509_crl_create,
1✔
896
                           (&crl, rng, ca_cert, ca_key, not_before, 86400, hash_fn.c_str(), nullptr));
897

898
               TEST_FFI_RC(0,
1✔
899
                           botan_x509_cert_verify_with_crl,
900
                           (&rc, cert, nullptr, 0, &ca_cert, 1, &crl, 1, nullptr, 0, nullptr, 0));
901
               botan_x509_crl_t new_crl;
1✔
902
               botan_x509_cert_t certs[1] = {cert};
1✔
903
               TEST_FFI_OK(
1✔
904
                  botan_x509_crl_update,
905
                  (&new_crl, crl, rng, ca_cert, ca_key, not_before, 86400, certs, 1, 1, hash_fn.c_str(), nullptr));
906

907
               TEST_FFI_RC(1,
1✔
908
                           botan_x509_cert_verify_with_crl,
909
                           (&rc, cert, nullptr, 0, &ca_cert, 1, &new_crl, 1, nullptr, 0, nullptr, 0));
910
               result.confirm("validation fails because cert is revoked", rc == 5000);
2✔
911

912
               size_t count;
1✔
913
               TEST_FFI_OK(botan_x509_crl_get_count, (new_crl, &count));
1✔
914
               result.confirm("crl has correct number of entires", count == 1);
2✔
915

916
               uint64_t expire_time;
1✔
917
               uint8_t reason;
1✔
918
               TEST_FFI_OK(botan_x509_crl_get_entry, (new_crl, 0, serial_out.data(), &out_len, &expire_time, &reason));
1✔
919
               botan_mp_t serial_from_crl;
1✔
920
               TEST_FFI_OK(botan_mp_init, (&serial_from_crl));
1✔
921
               TEST_FFI_OK(botan_mp_from_bin, (serial_from_crl, serial_out.data(), out_len));
1✔
922
               TEST_FFI_RC(1, botan_mp_equal, (serial, serial_from_crl));
1✔
923
               result.confirm("expire time is correct", now - 5 <= expire_time && expire_time <= now + 5);
2✔
924
               result.confirm("reason is correct", reason == 1);
2✔
925

926
               TEST_FFI_OK(botan_mp_destroy, (serial));
1✔
927
               TEST_FFI_OK(botan_mp_destroy, (serial_from_cert));
1✔
928
               TEST_FFI_OK(botan_x509_cert_params_builder_destroy, (ca_builder));
1✔
929
               TEST_FFI_OK(botan_x509_cert_params_builder_destroy, (req_builder));
1✔
930
               TEST_FFI_OK(botan_x509_pkcs10_req_destroy, (req));
1✔
931
               TEST_FFI_OK(botan_x509_cert_destroy, (ca_cert));
1✔
932
               TEST_FFI_OK(botan_x509_cert_destroy, (cert));
1✔
933
               TEST_FFI_OK(botan_pubkey_destroy, (ca_key_pub));
1✔
934
               TEST_FFI_OK(botan_pubkey_destroy, (cert_key_pub));
1✔
935
               TEST_FFI_OK(botan_pubkey_destroy, (pubkey_from_req));
1✔
936
               TEST_FFI_OK(botan_privkey_destroy, (ca_key));
1✔
937
               TEST_FFI_OK(botan_privkey_destroy, (cert_key));
2✔
938
            }
1✔
939
         }
940
      }
1✔
941
};
942

943
class FFI_X509_RPKI_Test final : public FFI_Test {
×
944
   public:
945
      std::string name() const override { return "FFI X509 RPKI"; }
1✔
946

947
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
948
         const std::string hash_fn{"SHA-256"};
1✔
949
         const std::string group{"secp256r1"};
1✔
950

951
         botan_privkey_t ca_key;
1✔
952
         botan_privkey_t cert_key;
1✔
953

954
         if(TEST_FFI_INIT(botan_privkey_create, (&ca_key, "ECDSA", group.c_str(), rng))) {
1✔
955
            TEST_FFI_OK(botan_privkey_create, (&cert_key, "ECDSA", group.c_str(), rng));
1✔
956

957
            uint64_t now =
1✔
958
               std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch())
1✔
959
                  .count();
1✔
960
            uint64_t not_before = now - 180;
1✔
961
            uint64_t not_after = now + 86400;
1✔
962

963
            botan_x509_cert_params_builder_t ca_builder;
1✔
964
            if(TEST_FFI_INIT(botan_x509_cert_params_builder_create, (&ca_builder))) {
1✔
965
               size_t limit = 1;
1✔
966
               TEST_FFI_OK(botan_x509_cert_params_builder_set_as_ca_certificate, (ca_builder, &limit));
1✔
967

968
               botan_x509_ext_ip_addr_blocks_t ca_ip_addr_blocks;
1✔
969
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_create, (&ca_ip_addr_blocks));
1✔
970
               std::vector<uint8_t> ip_addr = {192, 168, 2, 1};
1✔
971
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_add_ip_addr,
1✔
972
                           (ca_ip_addr_blocks, ip_addr.data(), ip_addr.data(), 0, nullptr));
973

974
               std::vector<uint8_t> min = {10, 0, 0, 1};
1✔
975
               std::vector<uint8_t> max = {10, 255, 255, 255};
1✔
976

977
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_add_ip_addr,
1✔
978
                           (ca_ip_addr_blocks, min.data(), max.data(), 0, nullptr));
979

980
               std::vector<uint8_t> ipv6_addr = {
1✔
981
                  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
1✔
982
               uint8_t ipv6_safi = 1;
1✔
983
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_add_ip_addr,
1✔
984
                           (ca_ip_addr_blocks, ipv6_addr.data(), ipv6_addr.data(), 1, &ipv6_safi));
985

986
               ipv6_safi = 2;
1✔
987
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_restrict, (ca_ip_addr_blocks, 1, &ipv6_safi));
1✔
988

989
               size_t v4_count;
1✔
990
               size_t v6_count;
1✔
991

992
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_counts, (ca_ip_addr_blocks, &v4_count, &v6_count));
1✔
993

994
               result.test_eq("ext has v4 addresses", v4_count, 1);
1✔
995
               result.test_eq("ext has v6 addresses", v6_count, 2);
1✔
996

997
               int has_safi;
1✔
998
               uint8_t safi;
1✔
999
               int present;
1✔
1000
               size_t count;
1✔
1001

1002
               TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER,
1✔
1003
                           botan_x509_ext_ip_addr_blocks_get_family,
1004
                           (ca_ip_addr_blocks, 0, 1, &has_safi, &safi, &present, &count));
1005

1006
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_family,
1✔
1007
                           (ca_ip_addr_blocks, 0, 0, &has_safi, &safi, &present, &count));
1008

1009
               result.confirm("index 0 does not have a safi", has_safi == 0);
2✔
1010
               result.confirm("index 0 has a value", present == 1);
2✔
1011
               result.confirm("index 0 has entries", count == 2);
2✔
1012

1013
               std::vector<uint8_t> min_out(4);
1✔
1014
               std::vector<uint8_t> max_out(4);
1✔
1015
               size_t out_len = 4;
1✔
1016

1017
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_address,
1✔
1018
                           (ca_ip_addr_blocks, 0, 0, 0, min_out.data(), max_out.data(), &out_len));
1019

1020
               result.confirm("data has correct size", out_len == 4);
2✔
1021
               result.test_eq("index 0 entry 0 has correct min", min_out, min);
2✔
1022
               result.test_eq("index 0 entry 0 has correct min", max_out, max);
2✔
1023

1024
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_address,
1✔
1025
                           (ca_ip_addr_blocks, 0, 0, 1, min_out.data(), max_out.data(), &out_len));
1026

1027
               result.test_eq("index 0 entry 1 has correct min", min_out, ip_addr);
2✔
1028
               result.test_eq("index 0 entry 1 has correct min", max_out, ip_addr);
2✔
1029

1030
               TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER,
1✔
1031
                           botan_x509_ext_ip_addr_blocks_get_address,
1032
                           (ca_ip_addr_blocks, 0, 0, 2, min_out.data(), max_out.data(), &out_len));
1033
               TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER,
1✔
1034
                           botan_x509_ext_ip_addr_blocks_get_address,
1035
                           (ca_ip_addr_blocks, 0, 1, 0, min_out.data(), max_out.data(), &out_len));
1036
               TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER,
1✔
1037
                           botan_x509_ext_ip_addr_blocks_get_address,
1038
                           (ca_ip_addr_blocks, 1, 0, 0, min_out.data(), max_out.data(), &out_len));
1039

1040
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_family,
1✔
1041
                           (ca_ip_addr_blocks, 1, 1, &has_safi, &safi, &present, &count));
1042

1043
               result.confirm("index 1 does have a safi", has_safi == 1);
2✔
1044
               result.confirm("index 1 safi is correct", safi == 1);
2✔
1045
               result.confirm("index 1 has a value", present == 1);
2✔
1046
               result.confirm("index 1 has entries", count == 1);
2✔
1047

1048
               min_out.resize(16);
1✔
1049
               max_out.resize(16);
1✔
1050
               out_len = 16;
1✔
1051

1052
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_address,
1✔
1053
                           (ca_ip_addr_blocks, 1, 1, 0, min_out.data(), max_out.data(), &out_len));
1054

1055
               result.confirm("data has correct size", out_len == 16);
2✔
1056
               result.test_eq("index 1 entry 0 has correct min", min_out, ipv6_addr);
2✔
1057
               result.test_eq("index 1 entry 0 has correct min", max_out, ipv6_addr);
2✔
1058

1059
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_family,
1✔
1060
                           (ca_ip_addr_blocks, 1, 2, &has_safi, &safi, &present, &count));
1061

1062
               result.confirm("index 1 does have a safi", has_safi == 1);
2✔
1063
               result.confirm("index 1 safi is correct", safi == 2);
2✔
1064
               result.confirm("index 1 has a value", present == 1);
2✔
1065
               result.confirm("index 1 has entries", count == 0);
2✔
1066

1067
               TEST_FFI_OK(botan_x509_cert_params_builder_add_ext_ip_addr_blocks, (ca_builder, ca_ip_addr_blocks, 1));
1✔
1068
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1069
                           botan_x509_cert_params_builder_add_ext_ip_addr_blocks,
1070
                           (ca_builder, ca_ip_addr_blocks, 1));
1071
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_destroy, (ca_ip_addr_blocks));
1✔
1072

1073
               botan_x509_ext_as_blocks_t ca_as_blocks;
1✔
1074
               TEST_FFI_OK(botan_x509_ext_as_blocks_create, (&ca_as_blocks));
1✔
1075

1076
               TEST_FFI_OK(botan_x509_ext_as_blocks_add_asnum, (ca_as_blocks, 0, 3000));
1✔
1077
               TEST_FFI_OK(botan_x509_ext_as_blocks_add_asnum, (ca_as_blocks, 4000, 5000));
1✔
1078
               TEST_FFI_OK(botan_x509_ext_as_blocks_restrict_rdi, (ca_as_blocks));
1✔
1079

1080
               TEST_FFI_OK(botan_x509_ext_as_blocks_get_asnum, (ca_as_blocks, &present, &count));
1✔
1081
               result.confirm("ext has asnum", present == 1);
2✔
1082
               result.confirm("ext has 2 asnums", count == 2);
2✔
1083

1084
               uint32_t min_out_ = 0;
1✔
1085
               uint32_t max_out_ = 0;
1✔
1086

1087
               TEST_FFI_OK(botan_x509_ext_as_blocks_get_asnum_at, (ca_as_blocks, 0, &min_out_, &max_out_));
1✔
1088
               result.confirm("asnum 0 min is correct", min_out_ == 0);
2✔
1089
               result.confirm("asnum 0 max is correct", max_out_ == 3000);
2✔
1090
               TEST_FFI_OK(botan_x509_ext_as_blocks_get_asnum_at, (ca_as_blocks, 1, &min_out_, &max_out_));
1✔
1091
               result.confirm("asnum 1 min is correct", min_out_ == 4000);
2✔
1092
               result.confirm("asnum 1 max is correct", max_out_ == 5000);
2✔
1093
               TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER,
1✔
1094
                           botan_x509_ext_as_blocks_get_asnum_at,
1095
                           (ca_as_blocks, 2, &min_out_, &max_out_));
1096

1097
               TEST_FFI_OK(botan_x509_ext_as_blocks_get_rdi, (ca_as_blocks, &present, &count));
1✔
1098
               result.confirm("ext has rdi", present == 1);
2✔
1099
               result.confirm("ext has 0 rdis", count == 0);
2✔
1100
               TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER,
1✔
1101
                           botan_x509_ext_as_blocks_get_rdi_at,
1102
                           (ca_as_blocks, 0, &min_out_, &max_out_));
1103

1104
               TEST_FFI_OK(botan_x509_cert_params_builder_add_ext_as_blocks, (ca_builder, ca_as_blocks, 1));
1✔
1105
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1106
                           botan_x509_cert_params_builder_add_ext_as_blocks,
1107
                           (ca_builder, ca_as_blocks, 1));
1108
               TEST_FFI_OK(botan_x509_ext_as_blocks_destroy, (ca_as_blocks));
1✔
1109

1110
               botan_x509_cert_t ca_cert;
1✔
1111
               TEST_FFI_OK(
1✔
1112
                  botan_x509_cert_create_self_signed,
1113
                  (&ca_cert, ca_key, ca_builder, rng, not_before, not_after, nullptr, hash_fn.c_str(), nullptr));
1114

1115
               botan_x509_cert_params_builder_t req_builder;
1✔
1116
               TEST_FFI_OK(botan_x509_cert_params_builder_create, (&req_builder));
1✔
1117

1118
               botan_x509_ext_ip_addr_blocks_t req_ip_addr_blocks;
1✔
1119
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_create, (&req_ip_addr_blocks));
1✔
1120
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_inherit, (req_ip_addr_blocks, 0, nullptr));
1✔
1121

1122
               TEST_FFI_OK(botan_x509_cert_params_builder_add_ext_ip_addr_blocks, (req_builder, req_ip_addr_blocks, 1));
1✔
1123
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_destroy, (req_ip_addr_blocks));
1✔
1124

1125
               botan_x509_ext_as_blocks_t req_as_blocks;
1✔
1126
               TEST_FFI_OK(botan_x509_ext_as_blocks_create, (&req_as_blocks));
1✔
1127
               TEST_FFI_OK(botan_x509_ext_as_blocks_inherit_asnum, (req_as_blocks));
1✔
1128

1129
               TEST_FFI_OK(botan_x509_cert_params_builder_add_ext_as_blocks, (req_builder, req_as_blocks, 1));
1✔
1130
               TEST_FFI_OK(botan_x509_ext_as_blocks_destroy, (req_as_blocks));
1✔
1131

1132
               botan_x509_pkcs10_req_t req;
1✔
1133
               TEST_FFI_OK(botan_x509_pkcs10_req_create,
1✔
1134
                           (&req, cert_key, req_builder, rng, hash_fn.c_str(), nullptr, nullptr));
1135

1136
               botan_x509_cert_t cert;
1✔
1137
               TEST_FFI_OK(
1✔
1138
                  botan_x509_pkcs10_req_sign,
1139
                  (&cert, req, ca_cert, ca_key, rng, not_before, not_after, nullptr, hash_fn.c_str(), nullptr));
1140

1141
               uint64_t test = 0;
1✔
1142
               TEST_FFI_OK(botan_x509_cert_not_after, (cert, &test));
1✔
1143

1144
               botan_x509_ext_ip_addr_blocks_t req_ip_addr_blocks_from_cert;
1✔
1145
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_create_from_cert, (&req_ip_addr_blocks_from_cert, cert));
1✔
1146

1147
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_counts,
1✔
1148
                           (req_ip_addr_blocks_from_cert, &v4_count, &v6_count));
1149

1150
               result.test_eq("ext has v4 addresses", v4_count, 1);
1✔
1151
               result.test_eq("ext has no v6 addresses", v6_count, 0);
1✔
1152

1153
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_get_family,
1✔
1154
                           (req_ip_addr_blocks_from_cert, 0, 0, &has_safi, &safi, &present, &count));
1155

1156
               result.confirm("index 0 does not have a safi", has_safi == 0);
2✔
1157
               result.confirm("index 0 has a value", present == 0);
2✔
1158

1159
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1160
                           botan_x509_ext_ip_addr_blocks_add_ip_addr,
1161
                           (req_ip_addr_blocks_from_cert, min.data(), min.data(), 0, &safi));
1162

1163
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1164
                           botan_x509_ext_ip_addr_blocks_restrict,
1165
                           (req_ip_addr_blocks_from_cert, 0, &safi));
1166

1167
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1168
                           botan_x509_ext_ip_addr_blocks_inherit,
1169
                           (req_ip_addr_blocks_from_cert, 0, &safi));
1170

1171
               TEST_FFI_OK(botan_x509_ext_ip_addr_blocks_destroy, (req_ip_addr_blocks_from_cert));
1✔
1172

1173
               botan_x509_ext_as_blocks_t req_as_blocks_from_cert;
1✔
1174
               TEST_FFI_OK(botan_x509_ext_as_blocks_create_from_cert, (&req_as_blocks_from_cert, cert));
1✔
1175

1176
               TEST_FFI_OK(botan_x509_ext_as_blocks_get_asnum, (req_as_blocks_from_cert, &present, &count));
1✔
1177
               result.confirm("ext inherits asnum", present == 0);
2✔
1178

1179
               TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE,
1✔
1180
                           botan_x509_ext_as_blocks_get_asnum_at,
1181
                           (req_as_blocks_from_cert, 0, &min_out_, &max_out_));
1182

1183
               TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE,
1✔
1184
                           botan_x509_ext_as_blocks_get_rdi,
1185
                           (req_as_blocks_from_cert, &present, &count));
1186

1187
               TEST_FFI_RC(BOTAN_FFI_ERROR_NO_VALUE,
1✔
1188
                           botan_x509_ext_as_blocks_get_rdi_at,
1189
                           (req_as_blocks_from_cert, 0, &min_out_, &max_out_));
1190

1191
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1192
                           botan_x509_ext_as_blocks_add_asnum,
1193
                           (req_as_blocks_from_cert, 0, 1));
1194

1195
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1196
                           botan_x509_ext_as_blocks_restrict_asnum,
1197
                           (req_as_blocks_from_cert));
1198

1199
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1200
                           botan_x509_ext_as_blocks_inherit_asnum,
1201
                           (req_as_blocks_from_cert));
1202

1203
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1204
                           botan_x509_ext_as_blocks_add_rdi,
1205
                           (req_as_blocks_from_cert, 0, 1));
1206

1207
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1208
                           botan_x509_ext_as_blocks_restrict_rdi,
1209
                           (req_as_blocks_from_cert));
1210

1211
               TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE,
1✔
1212
                           botan_x509_ext_as_blocks_inherit_rdi,
1213
                           (req_as_blocks_from_cert));
1214

1215
               TEST_FFI_OK(botan_x509_ext_as_blocks_destroy, (req_as_blocks_from_cert));
1✔
1216

1217
               int rc;
1✔
1218
               TEST_FFI_RC(0, botan_x509_cert_verify, (&rc, cert, nullptr, 0, &ca_cert, 1, nullptr, 0, nullptr, 0));
1✔
1219
               TEST_FFI_OK(botan_x509_cert_params_builder_destroy, (ca_builder));
1✔
1220
               TEST_FFI_OK(botan_x509_cert_params_builder_destroy, (req_builder));
1✔
1221
               TEST_FFI_OK(botan_x509_pkcs10_req_destroy, (req));
1✔
1222
               TEST_FFI_OK(botan_x509_cert_destroy, (ca_cert));
1✔
1223
               TEST_FFI_OK(botan_x509_cert_destroy, (cert));
2✔
1224
            }
6✔
1225

1226
            TEST_FFI_OK(botan_privkey_destroy, (ca_key));
1✔
1227
            TEST_FFI_OK(botan_privkey_destroy, (cert_key));
2✔
1228
         }
1229
      }
1✔
1230
};
1231

1232
class FFI_ECDSA_Certificate_Test final : public FFI_Test {
×
1233
   public:
1234
      std::string name() const override { return "FFI ECDSA cert"; }
1✔
1235

1236
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1237
         botan_x509_cert_t cert;
1✔
1238
         if(TEST_FFI_INIT(botan_x509_cert_load_file, (&cert, Test::data_file("x509/ecc/isrg-root-x2.pem").c_str()))) {
1✔
1239
            size_t date_len = 0;
1✔
1240
            TEST_FFI_RC(
1✔
1241
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_starts, (cert, nullptr, &date_len));
1242

1243
            date_len = 8;
1✔
1244
            TEST_FFI_RC(
1✔
1245
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_starts, (cert, nullptr, &date_len));
1246

1247
            std::string date(date_len - 1, '0');
1✔
1248
            TEST_FFI_OK(botan_x509_cert_get_time_starts, (cert, date.data(), &date_len));
1✔
1249
            result.test_eq("cert valid from", date, "200904000000Z");
2✔
1250

1251
            date_len = 0;
1✔
1252
            TEST_FFI_RC(
1✔
1253
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_expires, (cert, nullptr, &date_len));
1254

1255
            date.resize(date_len - 1);
1✔
1256
            TEST_FFI_OK(botan_x509_cert_get_time_expires, (cert, date.data(), &date_len));
1✔
1257
            result.test_eq("cert valid until", date, "400917160000Z");
2✔
1258

1259
            uint64_t not_before = 0;
1✔
1260
            TEST_FFI_OK(botan_x509_cert_not_before, (cert, &not_before));
1✔
1261
            result.confirm("cert not before", not_before == 1599177600);
2✔
1262

1263
            uint64_t not_after = 0;
1✔
1264
            TEST_FFI_OK(botan_x509_cert_not_after, (cert, &not_after));
1✔
1265
            result.confirm("cert not after", not_after == 2231510400);
2✔
1266

1267
            size_t serial_len = 0;
1✔
1268
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1269
                        botan_x509_cert_get_serial_number,
1270
                        (cert, nullptr, &serial_len));
1271

1272
            std::vector<uint8_t> serial(serial_len);
1✔
1273
            TEST_FFI_OK(botan_x509_cert_get_serial_number, (cert, serial.data(), &serial_len));
1✔
1274
            result.test_eq("cert serial length", serial.size(), 16);
1✔
1275
            result.test_eq("cert serial", Botan::hex_encode(serial), "41D29DD172EAEEA780C12C6CE92F8752");
2✔
1276

1277
            size_t fingerprint_len = 0;
1✔
1278
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1279
                        botan_x509_cert_get_fingerprint,
1280
                        (cert, "SHA-256", nullptr, &fingerprint_len));
1281

1282
            std::vector<uint8_t> fingerprint(fingerprint_len);
1✔
1283
            TEST_FFI_OK(botan_x509_cert_get_fingerprint, (cert, "SHA-256", fingerprint.data(), &fingerprint_len));
1✔
1284
            result.test_eq(
1✔
1285
               "cert fingerprint",
1286
               reinterpret_cast<const char*>(fingerprint.data()),
1✔
1287
               "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");
1288

1289
            size_t key_id_len = 0;
1✔
1290
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1291
                        botan_x509_cert_get_authority_key_id,
1292
                        (cert, nullptr, &key_id_len));
1293

1294
            result.test_eq("No AKID", key_id_len, 0);
1✔
1295

1296
            key_id_len = 0;
1✔
1297
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1298
                        botan_x509_cert_get_subject_key_id,
1299
                        (cert, nullptr, &key_id_len));
1300

1301
            std::vector<uint8_t> key_id(key_id_len);
1✔
1302
            TEST_FFI_OK(botan_x509_cert_get_subject_key_id, (cert, key_id.data(), &key_id_len));
1✔
1303
            result.test_eq("cert subject key id",
3✔
1304
                           Botan::hex_encode(key_id.data(), key_id.size(), true),
2✔
1305
                           "7C4296AEDE4B483BFA92F89E8CCF6D8BA9723795");
1306

1307
            size_t pubkey_len = 0;
1✔
1308
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1309
                        botan_x509_cert_get_public_key_bits,
1310
                        (cert, nullptr, &pubkey_len));
1311

1312
            std::vector<uint8_t> pubkey(pubkey_len);
1✔
1313
            TEST_FFI_OK(botan_x509_cert_get_public_key_bits, (cert, pubkey.data(), &pubkey_len));
1✔
1314

1315
   #if defined(BOTAN_HAS_ECDSA)
1316
            botan_pubkey_t pub;
1✔
1317
            if(TEST_FFI_OK(botan_x509_cert_get_public_key, (cert, &pub))) {
1✔
1318
               TEST_FFI_RC(0, botan_pubkey_ecc_key_used_explicit_encoding, (pub));
1✔
1319
               TEST_FFI_OK(botan_pubkey_destroy, (pub));
2✔
1320
            }
1321
   #endif
1322

1323
            size_t dn_len = 0;
1✔
1324
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1325
                        botan_x509_cert_get_issuer_dn,
1326
                        (cert, "Name", 0, nullptr, &dn_len));
1327

1328
            std::vector<uint8_t> dn(dn_len);
1✔
1329
            TEST_FFI_OK(botan_x509_cert_get_issuer_dn, (cert, "Name", 0, dn.data(), &dn_len));
1✔
1330
            result.test_eq("issuer dn", reinterpret_cast<const char*>(dn.data()), "ISRG Root X2");
1✔
1331

1332
            dn_len = 0;
1✔
1333
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1334
                        botan_x509_cert_get_subject_dn,
1335
                        (cert, "Name", 0, nullptr, &dn_len));
1336

1337
            dn.resize(dn_len);
1✔
1338
            TEST_FFI_OK(botan_x509_cert_get_subject_dn, (cert, "Name", 0, dn.data(), &dn_len));
1✔
1339
            result.test_eq("subject dn", reinterpret_cast<const char*>(dn.data()), "ISRG Root X2");
1✔
1340

1341
            size_t printable_len = 0;
1✔
1342
            TEST_FFI_RC(
1✔
1343
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_to_string, (cert, nullptr, &printable_len));
1344

1345
            std::string printable(printable_len - 1, '0');
1✔
1346
            TEST_FFI_OK(botan_x509_cert_to_string, (cert, printable.data(), &printable_len));
1✔
1347

1348
            TEST_FFI_RC(0, botan_x509_cert_allowed_usage, (cert, KEY_CERT_SIGN));
1✔
1349
            TEST_FFI_RC(0, botan_x509_cert_allowed_usage, (cert, CRL_SIGN));
1✔
1350
            TEST_FFI_RC(1, botan_x509_cert_allowed_usage, (cert, DIGITAL_SIGNATURE));
1✔
1351

1352
            TEST_FFI_OK(botan_x509_cert_destroy, (cert));
2✔
1353
         }
6✔
1354
      }
1✔
1355
};
1356

1357
class FFI_PKCS_Hashid_Test final : public FFI_Test {
×
1358
   public:
1359
      std::string name() const override { return "FFI PKCS hash id"; }
1✔
1360

1361
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1362
         std::vector<uint8_t> hash_id(64);
1✔
1363
         size_t hash_id_len = hash_id.size();
1✔
1364

1365
         if(TEST_FFI_INIT(botan_pkcs_hash_id, ("SHA-256", hash_id.data(), &hash_id_len))) {
1✔
1366
            result.test_eq("Expected SHA-256 PKCS hash id len", hash_id_len, 19);
1✔
1367

1368
            hash_id.resize(hash_id_len);
1✔
1369
            result.test_eq("Expected SHA_256 PKCS hash id", hash_id, "3031300D060960864801650304020105000420");
1✔
1370

1371
            hash_id_len = 3;  // too short
1✔
1372
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
2✔
1373
                        botan_pkcs_hash_id,
1374
                        ("SHA-256", hash_id.data(), &hash_id_len));
1375
         }
1376
      }
1✔
1377
};
1378

1379
class FFI_CBC_Cipher_Test final : public FFI_Test {
×
1380
   public:
1381
      std::string name() const override { return "FFI CBC cipher"; }
1✔
1382

1383
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1384
         botan_cipher_t cipher_encrypt;
1✔
1385
         botan_cipher_t cipher_decrypt;
1✔
1386

1387
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/CBC/PKCS7", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
1388
            size_t min_keylen = 0;
1✔
1389
            size_t max_keylen = 0;
1✔
1390
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
1391
            result.test_int_eq(min_keylen, 16, "Min key length");
1✔
1392
            result.test_int_eq(max_keylen, 16, "Max key length");
1✔
1393

1394
            // from https://github.com/geertj/bluepass/blob/master/tests/vectors/aes-cbc-pkcs7.txt
1395
            const std::vector<uint8_t> plaintext =
1✔
1396
               Botan::hex_decode("0397f4f6820b1f9386f14403be5ac16e50213bd473b4874b9bcbf5f318ee686b1d");
1✔
1397
            const std::vector<uint8_t> symkey = Botan::hex_decode("898be9cc5004ed0fa6e117c9a3099d31");
1✔
1398
            const std::vector<uint8_t> nonce = Botan::hex_decode("9dea7621945988f96491083849b068df");
1✔
1399
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
1400
               "e232cd6ef50047801ee681ec30f61d53cfd6b0bca02fd03c1b234baa10ea82ac9dab8b960926433a19ce6dea08677e34");
1✔
1401

1402
            size_t output_written = 0;
1✔
1403
            size_t input_consumed = 0;
1✔
1404

1405
            // Test that after clear or final the object can be reused
1406
            for(size_t r = 0; r != 2; ++r) {
3✔
1407
               size_t ctext_len;
2✔
1408
               TEST_FFI_OK(botan_cipher_output_length, (cipher_encrypt, plaintext.size(), &ctext_len));
2✔
1409
               result.test_eq("Expected size of padded message", ctext_len, plaintext.size() + 15);
2✔
1410
               std::vector<uint8_t> ciphertext(ctext_len);
2✔
1411

1412
               size_t update_granularity = 0;
2✔
1413
               size_t ideal_granularity = 0;
2✔
1414
               size_t taglen = 0;
2✔
1415

1416
               TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
2✔
1417
               TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
2✔
1418
               TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &taglen));
2✔
1419

1420
               result.test_eq(
2✔
1421
                  "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
1422
               result.test_eq("not an AEAD, hence no tag", taglen, 0);
2✔
1423

1424
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1425
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1426
               TEST_FFI_OK(botan_cipher_update,
2✔
1427
                           (cipher_encrypt,
1428
                            0,
1429
                            ciphertext.data(),
1430
                            ciphertext.size(),
1431
                            &output_written,
1432
                            plaintext.data(),
1433
                            plaintext.size(),
1434
                            &input_consumed));
1435
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
1436

1437
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1438
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1439
               TEST_FFI_OK(botan_cipher_update,
2✔
1440
                           (cipher_encrypt,
1441
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1442
                            ciphertext.data(),
1443
                            ciphertext.size(),
1444
                            &output_written,
1445
                            plaintext.data(),
1446
                            plaintext.size(),
1447
                            &input_consumed));
1448

1449
               ciphertext.resize(output_written);
2✔
1450
               result.test_eq("AES/CBC ciphertext", ciphertext, exp_ciphertext);
4✔
1451

1452
               if(TEST_FFI_OK(botan_cipher_init, (&cipher_decrypt, "AES-128/CBC", BOTAN_CIPHER_INIT_FLAG_DECRYPT))) {
2✔
1453
                  size_t ptext_len;
2✔
1454
                  TEST_FFI_OK(botan_cipher_output_length, (cipher_decrypt, ciphertext.size(), &ptext_len));
2✔
1455
                  std::vector<uint8_t> decrypted(ptext_len);
2✔
1456

1457
                  TEST_FFI_RC(0, botan_cipher_is_authenticated, (cipher_encrypt));
2✔
1458

1459
                  TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
2✔
1460
                  TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
2✔
1461
                  TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_decrypt, &taglen));
2✔
1462

1463
                  result.test_eq("ideal granularity is a multiple of update granularity (decrypt)",
2✔
1464
                                 ideal_granularity % update_granularity,
1465
                                 0);
1466
                  result.test_eq("not an AEAD, hence no tag (decrypt)", taglen, 0);
2✔
1467

1468
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
1469
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
1470
                  TEST_FFI_OK(botan_cipher_update,
2✔
1471
                              (cipher_decrypt,
1472
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1473
                               decrypted.data(),
1474
                               decrypted.size(),
1475
                               &output_written,
1476
                               ciphertext.data(),
1477
                               ciphertext.size(),
1478
                               &input_consumed));
1479

1480
                  decrypted.resize(output_written);
2✔
1481

1482
                  result.test_eq("AES/CBC plaintext", decrypted, plaintext);
4✔
1483

1484
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
4✔
1485
               }
2✔
1486
            }
2✔
1487

1488
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
2✔
1489
         }
4✔
1490
      }
1✔
1491
};
1492

1493
class FFI_GCM_Test final : public FFI_Test {
×
1494
   public:
1495
      std::string name() const override { return "FFI GCM"; }
1✔
1496

1497
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1498
         botan_cipher_t cipher_encrypt;
1✔
1499
         botan_cipher_t cipher_decrypt;
1✔
1500

1501
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/GCM", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
1502
            std::array<char, 18> namebuf{};
1✔
1503
            size_t name_len = 15;
1✔
1504
            TEST_FFI_FAIL("output buffer too short", botan_cipher_name, (cipher_encrypt, namebuf.data(), &name_len));
2✔
1505
            result.test_eq("name len", name_len, 16);
1✔
1506

1507
            name_len = namebuf.size();
1✔
1508
            if(TEST_FFI_OK(botan_cipher_name, (cipher_encrypt, namebuf.data(), &name_len))) {
1✔
1509
               result.test_eq("name len", name_len, 16);
1✔
1510
               result.test_eq("name", namebuf.data(), "AES-128/GCM(16)");
2✔
1511
            }
1512

1513
            size_t min_keylen = 0;
1✔
1514
            size_t max_keylen = 0;
1✔
1515
            size_t nonce_len = 0;
1✔
1516
            size_t tag_len = 0;
1✔
1517
            size_t update_granularity = 0;
1✔
1518
            size_t ideal_granularity = 0;
1✔
1519

1520
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
1✔
1521
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
1✔
1522

1523
            result.test_eq(
1✔
1524
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
1525

1526
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
1527
            result.test_int_eq(min_keylen, 16, "Min key length");
1✔
1528
            result.test_int_eq(max_keylen, 16, "Max key length");
1✔
1529

1530
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &nonce_len));
1✔
1531
            result.test_int_eq(nonce_len, 12, "Expected default GCM nonce length");
1✔
1532

1533
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &tag_len));
1✔
1534
            result.test_int_eq(tag_len, 16, "Expected GCM tag length");
1✔
1535

1536
            TEST_FFI_RC(1, botan_cipher_is_authenticated, (cipher_encrypt));
1✔
1537

1538
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 12));
1✔
1539
            // GCM accepts any nonce size except zero
1540
            TEST_FFI_RC(0, botan_cipher_valid_nonce_length, (cipher_encrypt, 0));
1✔
1541
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 1));
1✔
1542
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 100009));
1✔
1543

1544
            // NIST test vector
1545
            const std::vector<uint8_t> plaintext = Botan::hex_decode(
1✔
1546
               "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39");
1✔
1547

1548
            const std::vector<uint8_t> symkey = Botan::hex_decode("FEFFE9928665731C6D6A8F9467308308");
1✔
1549
            const std::vector<uint8_t> nonce = Botan::hex_decode("CAFEBABEFACEDBADDECAF888");
1✔
1550
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
1551
               "42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E0915BC94FBC3221A5DB94FAE95AE7121A47");
1✔
1552
            const std::vector<uint8_t> aad = Botan::hex_decode("FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2");
1✔
1553

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

1556
            size_t output_written = 0;
1✔
1557
            size_t input_consumed = 0;
1✔
1558

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

1563
               // First use a nonce of the AAD, and ensure reset works
1564
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, aad.data(), aad.size()));
2✔
1565
               TEST_FFI_OK(botan_cipher_reset, (cipher_encrypt));
2✔
1566

1567
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1568
               TEST_FFI_OK(botan_cipher_update,
2✔
1569
                           (cipher_encrypt,
1570
                            0,
1571
                            ciphertext.data(),
1572
                            ciphertext.size(),
1573
                            &output_written,
1574
                            plaintext.data(),
1575
                            plaintext.size(),
1576
                            &input_consumed));
1577
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
1578

1579
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1580
               TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_encrypt, aad.data(), aad.size()));
2✔
1581
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1582
               TEST_FFI_OK(botan_cipher_update,
2✔
1583
                           (cipher_encrypt,
1584
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1585
                            ciphertext.data(),
1586
                            ciphertext.size(),
1587
                            &output_written,
1588
                            plaintext.data(),
1589
                            plaintext.size(),
1590
                            &input_consumed));
1591

1592
               ciphertext.resize(output_written);
2✔
1593
               result.test_eq("AES/GCM ciphertext", ciphertext, exp_ciphertext);
4✔
1594

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

1598
                  TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
2✔
1599
                  TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
2✔
1600

1601
                  result.test_eq("ideal granularity is a multiple of update granularity (decrypt)",
2✔
1602
                                 ideal_granularity % update_granularity,
1603
                                 0);
1604

1605
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
1606
                  TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_decrypt, aad.data(), aad.size()));
2✔
1607
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
1608
                  TEST_FFI_OK(botan_cipher_update,
2✔
1609
                              (cipher_decrypt,
1610
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1611
                               decrypted.data(),
1612
                               decrypted.size(),
1613
                               &output_written,
1614
                               ciphertext.data(),
1615
                               ciphertext.size(),
1616
                               &input_consumed));
1617

1618
                  result.test_int_eq(input_consumed, ciphertext.size(), "All input consumed");
2✔
1619
                  result.test_int_eq(output_written, decrypted.size(), "Expected output size produced");
2✔
1620
                  result.test_eq("AES/GCM plaintext", decrypted, plaintext);
4✔
1621

1622
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
4✔
1623
               }
2✔
1624
            }
1625

1626
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
2✔
1627
         }
6✔
1628
      }
1✔
1629
};
1630

1631
class FFI_ChaCha20Poly1305_Test final : public FFI_Test {
×
1632
   public:
1633
      std::string name() const override { return "FFI ChaCha20Poly1305"; }
1✔
1634

1635
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1636
         botan_cipher_t cipher_encrypt;
1✔
1637
         botan_cipher_t cipher_decrypt;
1✔
1638

1639
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "ChaCha20Poly1305", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
1640
            std::array<char, 17> namebuf{};
1✔
1641
            size_t name_len = 15;
1✔
1642
            TEST_FFI_FAIL("output buffer too short", botan_cipher_name, (cipher_encrypt, namebuf.data(), &name_len));
2✔
1643
            result.test_eq("name len", name_len, 17);
1✔
1644

1645
            name_len = namebuf.size();
1✔
1646
            if(TEST_FFI_OK(botan_cipher_name, (cipher_encrypt, namebuf.data(), &name_len))) {
1✔
1647
               result.test_eq("name len", name_len, 17);
1✔
1648
               result.test_eq("name", std::string(namebuf.data()), "ChaCha20Poly1305");
2✔
1649
            }
1650

1651
            size_t min_keylen = 0;
1✔
1652
            size_t max_keylen = 0;
1✔
1653
            size_t nonce_len = 0;
1✔
1654
            size_t tag_len = 0;
1✔
1655
            size_t update_granularity = 0;
1✔
1656
            size_t ideal_granularity = 0;
1✔
1657

1658
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
1✔
1659
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
1✔
1660

1661
            result.test_eq(
1✔
1662
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
1663

1664
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
1665
            result.test_int_eq(min_keylen, 32, "Min key length");
1✔
1666
            result.test_int_eq(max_keylen, 32, "Max key length");
1✔
1667

1668
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &nonce_len));
1✔
1669
            result.test_int_eq(nonce_len, 12, "Expected default ChaCha20Poly1305 nonce length");
1✔
1670

1671
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &tag_len));
1✔
1672
            result.test_int_eq(tag_len, 16, "Expected Chacha20Poly1305 tag length");
1✔
1673

1674
            TEST_FFI_RC(1, botan_cipher_is_authenticated, (cipher_encrypt));
1✔
1675

1676
            // From RFC 7539
1677
            const std::vector<uint8_t> plaintext = Botan::hex_decode(
1✔
1678
               "4C616469657320616E642047656E746C656D656E206F662074686520636C617373206F66202739393A204966204920636F756C64206F6666657220796F75206F6E6C79206F6E652074697020666F7220746865206675747572652C2073756E73637265656E20776F756C642062652069742E");
1✔
1679
            const std::vector<uint8_t> symkey =
1✔
1680
               Botan::hex_decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F");
1✔
1681
            const std::vector<uint8_t> nonce = Botan::hex_decode("070000004041424344454647");
1✔
1682
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
1683
               "D31A8D34648E60DB7B86AFBC53EF7EC2A4ADED51296E08FEA9E2B5A736EE62D63DBEA45E8CA9671282FAFB69DA92728B1A71DE0A9E060B2905D6A5B67ECD3B3692DDBD7F2D778B8C9803AEE328091B58FAB324E4FAD675945585808B4831D7BC3FF4DEF08E4B7A9DE576D26586CEC64B61161AE10B594F09E26A7E902ECBD0600691");
1✔
1684
            const std::vector<uint8_t> aad = Botan::hex_decode("50515253C0C1C2C3C4C5C6C7");
1✔
1685

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

1688
            size_t output_written = 0;
1✔
1689
            size_t input_consumed = 0;
1✔
1690

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

1695
               // First use a nonce of the AAD, and ensure reset works
1696
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, aad.data(), aad.size()));
2✔
1697
               TEST_FFI_OK(botan_cipher_reset, (cipher_encrypt));
2✔
1698

1699
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1700
               TEST_FFI_OK(botan_cipher_update,
2✔
1701
                           (cipher_encrypt,
1702
                            0,
1703
                            ciphertext.data(),
1704
                            ciphertext.size(),
1705
                            &output_written,
1706
                            plaintext.data(),
1707
                            plaintext.size(),
1708
                            &input_consumed));
1709
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
1710

1711
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1712
               TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_encrypt, aad.data(), aad.size()));
2✔
1713
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1714
               TEST_FFI_OK(botan_cipher_update,
2✔
1715
                           (cipher_encrypt,
1716
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1717
                            ciphertext.data(),
1718
                            ciphertext.size(),
1719
                            &output_written,
1720
                            plaintext.data(),
1721
                            plaintext.size(),
1722
                            &input_consumed));
1723

1724
               ciphertext.resize(output_written);
2✔
1725
               result.test_eq("AES/GCM ciphertext", ciphertext, exp_ciphertext);
4✔
1726

1727
               if(TEST_FFI_OK(botan_cipher_init,
2✔
1728
                              (&cipher_decrypt, "ChaCha20Poly1305", BOTAN_CIPHER_INIT_FLAG_DECRYPT))) {
1729
                  std::vector<uint8_t> decrypted(plaintext.size());
2✔
1730

1731
                  TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
2✔
1732
                  TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
2✔
1733

1734
                  result.test_eq("ideal granularity is a multiple of update granularity (decrypt)",
2✔
1735
                                 ideal_granularity % update_granularity,
1736
                                 0);
1737

1738
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
1739
                  TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_decrypt, aad.data(), aad.size()));
2✔
1740
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
1741
                  TEST_FFI_OK(botan_cipher_update,
2✔
1742
                              (cipher_decrypt,
1743
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1744
                               decrypted.data(),
1745
                               decrypted.size(),
1746
                               &output_written,
1747
                               ciphertext.data(),
1748
                               ciphertext.size(),
1749
                               &input_consumed));
1750

1751
                  result.test_int_eq(input_consumed, ciphertext.size(), "All input consumed");
2✔
1752
                  result.test_int_eq(output_written, decrypted.size(), "Expected output size produced");
2✔
1753
                  result.test_eq("AES/GCM plaintext", decrypted, plaintext);
4✔
1754

1755
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
4✔
1756
               }
2✔
1757
            }
1758

1759
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
2✔
1760
         }
6✔
1761
      }
1✔
1762
};
1763

1764
class FFI_EAX_Test final : public FFI_Test {
×
1765
   public:
1766
      std::string name() const override { return "FFI EAX"; }
1✔
1767

1768
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1769
         botan_cipher_t cipher_encrypt;
1✔
1770
         botan_cipher_t cipher_decrypt;
1✔
1771

1772
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/EAX", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
1773
            size_t min_keylen = 0;
1✔
1774
            size_t max_keylen = 0;
1✔
1775
            size_t mod_keylen = 0;
1✔
1776
            size_t nonce_len = 0;
1✔
1777
            size_t tag_len = 0;
1✔
1778
            size_t update_granularity = 0;
1✔
1779
            size_t ideal_granularity = 0;
1✔
1780

1781
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
1✔
1782
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
1✔
1783

1784
            result.test_eq(
1✔
1785
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
1786

1787
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
1788
            result.test_int_eq(min_keylen, 16, "Min key length");
1✔
1789
            result.test_int_eq(max_keylen, 16, "Max key length");
1✔
1790

1791
            TEST_FFI_OK(botan_cipher_get_keyspec, (cipher_encrypt, &min_keylen, &max_keylen, &mod_keylen));
1✔
1792
            result.test_int_eq(min_keylen, 16, "Min key length");
1✔
1793
            result.test_int_eq(max_keylen, 16, "Max key length");
1✔
1794
            result.test_int_eq(mod_keylen, 1, "Mod key length");
1✔
1795

1796
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &nonce_len));
1✔
1797
            result.test_int_eq(nonce_len, 12, "Expected default EAX nonce length");
1✔
1798

1799
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &tag_len));
1✔
1800
            result.test_int_eq(tag_len, 16, "Expected EAX tag length");
1✔
1801

1802
            TEST_FFI_RC(1, botan_cipher_is_authenticated, (cipher_encrypt));
1✔
1803

1804
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 12));
1✔
1805
            // EAX accepts any nonce size...
1806
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 0));
1✔
1807

1808
            const std::vector<uint8_t> plaintext =
1✔
1809
               Botan::hex_decode("0000000000000000000000000000000011111111111111111111111111111111");
1✔
1810
            const std::vector<uint8_t> symkey = Botan::hex_decode("000102030405060708090a0b0c0d0e0f");
1✔
1811
            const std::vector<uint8_t> nonce = Botan::hex_decode("3c8cc2970a008f75cc5beae2847258c2");
1✔
1812
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
1813
               "3c441f32ce07822364d7a2990e50bb13d7b02a26969e4a937e5e9073b0d9c968db90bdb3da3d00afd0fc6a83551da95e");
1✔
1814

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

1817
            size_t output_written = 0;
1✔
1818
            size_t input_consumed = 0;
1✔
1819

1820
            // Test that after clear or final the object can be reused
1821
            for(size_t r = 0; r != 2; ++r) {
3✔
1822
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1823
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1824
               TEST_FFI_OK(botan_cipher_update,
2✔
1825
                           (cipher_encrypt,
1826
                            0,
1827
                            ciphertext.data(),
1828
                            ciphertext.size(),
1829
                            &output_written,
1830
                            plaintext.data(),
1831
                            plaintext.size(),
1832
                            &input_consumed));
1833
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
1834

1835
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1836
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1837
               TEST_FFI_OK(botan_cipher_update,
2✔
1838
                           (cipher_encrypt,
1839
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1840
                            ciphertext.data(),
1841
                            ciphertext.size(),
1842
                            &output_written,
1843
                            plaintext.data(),
1844
                            plaintext.size(),
1845
                            &input_consumed));
1846

1847
               ciphertext.resize(output_written);
2✔
1848
               result.test_eq("AES/EAX ciphertext", ciphertext, exp_ciphertext);
4✔
1849

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

1853
                  TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
2✔
1854
                  TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
2✔
1855

1856
                  result.test_eq("ideal granularity is a multiple of update granularity (decrypt)",
2✔
1857
                                 ideal_granularity % update_granularity,
1858
                                 0);
1859

1860
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
1861
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
1862
                  TEST_FFI_OK(botan_cipher_update,
2✔
1863
                              (cipher_decrypt,
1864
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1865
                               decrypted.data(),
1866
                               decrypted.size(),
1867
                               &output_written,
1868
                               ciphertext.data(),
1869
                               ciphertext.size(),
1870
                               &input_consumed));
1871

1872
                  result.test_int_eq(input_consumed, ciphertext.size(), "All input consumed");
2✔
1873
                  result.test_int_eq(output_written, decrypted.size(), "Expected output size produced");
2✔
1874
                  result.test_eq("AES/EAX plaintext", decrypted, plaintext);
4✔
1875

1876
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
4✔
1877
               }
2✔
1878
            }
1879

1880
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
2✔
1881
         }
5✔
1882
      }
1✔
1883
};
1884

1885
class FFI_AEAD_Test final : public FFI_Test {
×
1886
   public:
1887
      std::string name() const override { return "FFI AEAD"; }
1✔
1888

1889
      void ffi_test(Test::Result& merged_result, botan_rng_t rng) override {
1✔
1890
         botan_cipher_t cipher_encrypt;
1✔
1891
         botan_cipher_t cipher_decrypt;
1✔
1892

1893
         std::array<std::string, 5> aeads = {
1✔
1894
            "AES-128/GCM", "ChaCha20Poly1305", "AES-128/EAX", "AES-256/SIV", "AES-128/CCM"};
1✔
1895

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

1899
            if(!TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, aead.c_str(), BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
5✔
1900
               continue;
×
1901
            }
1902

1903
            if(botan_cipher_is_authenticated(cipher_encrypt) == 0) {
5✔
1904
               result.test_failure("Cipher " + aead + " claims is not authenticated");
×
1905
               botan_cipher_destroy(cipher_encrypt);
×
1906
               continue;
×
1907
            }
1908

1909
            size_t min_keylen = 0;
5✔
1910
            size_t max_keylen = 0;
5✔
1911
            size_t update_granularity = 0;
5✔
1912
            size_t ideal_granularity = 0;
5✔
1913
            size_t noncelen = 0;
5✔
1914
            size_t taglen = 0;
5✔
1915
            constexpr size_t pt_multiplier = 5;
5✔
1916
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
5✔
1917
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_encrypt, &update_granularity));
5✔
1918
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_encrypt, &ideal_granularity));
5✔
1919
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &noncelen));
5✔
1920
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &taglen));
5✔
1921

1922
            result.test_eq(
5✔
1923
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
1924

1925
            std::vector<uint8_t> key(max_keylen);
5✔
1926
            TEST_FFI_OK(botan_rng_get, (rng, key.data(), key.size()));
5✔
1927
            TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, key.data(), key.size()));
5✔
1928

1929
            std::vector<uint8_t> nonce(noncelen);
5✔
1930
            TEST_FFI_OK(botan_rng_get, (rng, nonce.data(), nonce.size()));
5✔
1931
            TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
5✔
1932

1933
            std::vector<uint8_t> plaintext(ideal_granularity * pt_multiplier);
5✔
1934
            std::vector<uint8_t> ciphertext(ideal_granularity * pt_multiplier + taglen);
5✔
1935
            TEST_FFI_OK(botan_rng_get, (rng, plaintext.data(), plaintext.size()));
5✔
1936

1937
            std::vector<uint8_t> dummy_buffer(1024);
5✔
1938
            TEST_FFI_OK(botan_rng_get, (rng, dummy_buffer.data(), dummy_buffer.size()));
5✔
1939
            std::vector<uint8_t> dummy_buffer_reference = dummy_buffer;
5✔
1940

1941
            const bool requires_entire_message = botan_cipher_requires_entire_message(cipher_encrypt) == 1;
5✔
1942
            result.test_eq(
5✔
1943
               "requires entire message", requires_entire_message, (aead == "AES-256/SIV" || aead == "AES-128/CCM"));
5✔
1944

1945
            std::span<const uint8_t> pt_slicer(plaintext);
5✔
1946
            std::span<uint8_t> ct_stuffer(ciphertext);
5✔
1947

1948
            // Process data that is explicitly a multiple of the ideal
1949
            // granularity and therefore should be aligned with the cipher's
1950
            // internal block size.
1951
            for(size_t i = 0; i < pt_multiplier; ++i) {
30✔
1952
               size_t output_written = 0;
25✔
1953
               size_t input_consumed = 0;
25✔
1954

1955
               auto pt_chunk = pt_slicer.first(ideal_granularity);
25✔
1956

1957
               // The existing implementation won't consume any bytes from the
1958
               // input if there is no space in the output buffer. Even when
1959
               // the cipher is a mode that won't produce any output until the
1960
               // entire message is processed. Hence, give it some dummy buffer.
1961
               BOTAN_ASSERT_NOMSG(dummy_buffer.size() > ideal_granularity);
25✔
1962
               auto ct_chunk = (requires_entire_message) ? std::span(dummy_buffer).first(ideal_granularity)
25✔
1963
                                                         : ct_stuffer.first(ideal_granularity);
1964

1965
               TEST_FFI_OK(botan_cipher_update,
25✔
1966
                           (cipher_encrypt,
1967
                            0 /* don't finalize */,
1968
                            ct_chunk.data(),
1969
                            ct_chunk.size(),
1970
                            &output_written,
1971
                            pt_chunk.data(),
1972
                            pt_chunk.size(),
1973
                            &input_consumed));
1974

1975
               result.test_gt("some input consumed", input_consumed, 0);
25✔
1976
               result.test_lte("at most, all input consumed", input_consumed, pt_chunk.size());
25✔
1977
               pt_slicer = pt_slicer.subspan(input_consumed);
25✔
1978

1979
               if(requires_entire_message) {
25✔
1980
                  result.test_eq("no output produced", output_written, 0);
20✔
1981
               } else {
1982
                  result.test_eq("all bytes produced", output_written, input_consumed);
15✔
1983
                  ct_stuffer = ct_stuffer.subspan(output_written);
15✔
1984
               }
1985
            }
1986

1987
            // Trying to pull a part of the authentication tag should fail,
1988
            // as we must consume the entire tag in a single invocation to
1989
            // botan_cipher_update().
1990
            size_t final_output_written = 42;
5✔
1991
            size_t final_input_consumed = 1337;
5✔
1992
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
5✔
1993
                        botan_cipher_update,
1994
                        (cipher_encrypt,
1995
                         BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1996
                         dummy_buffer.data(),
1997
                         3, /* not enough to hold any reasonable auth'n tag */
1998
                         &final_output_written,
1999
                         pt_slicer.data(),  // remaining bytes (typically 0)
2000
                         pt_slicer.size(),
2001
                         &final_input_consumed));
2002

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

2005
            result.test_eq("remaining bytes consumed in bogus final", final_input_consumed, pt_slicer.size());
5✔
2006
            result.test_eq("required buffer size is written in bogus final", final_output_written, expected_final_size);
5✔
2007

2008
            auto final_ct_chunk = ct_stuffer.first(expected_final_size);
5✔
2009

2010
            TEST_FFI_OK(botan_cipher_update,
5✔
2011
                        (cipher_encrypt,
2012
                         BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2013
                         final_ct_chunk.data(),
2014
                         final_ct_chunk.size(),
2015
                         &final_output_written,
2016
                         nullptr,  // no more input
2017
                         0,
2018
                         &final_input_consumed));
2019

2020
            result.test_eq("no bytes consumed in final", final_input_consumed, 0);
5✔
2021
            result.test_eq("final bytes written", final_output_written, expected_final_size);
5✔
2022
            result.test_eq("dummy buffer unchanged", dummy_buffer, dummy_buffer_reference);
10✔
2023

2024
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
5✔
2025

2026
            // ----------------------------------------------------------------
2027

2028
            TEST_FFI_INIT(botan_cipher_init, (&cipher_decrypt, aead.c_str(), BOTAN_CIPHER_INIT_FLAG_DECRYPT));
5✔
2029

2030
            TEST_FFI_OK(botan_cipher_get_update_granularity, (cipher_decrypt, &update_granularity));
5✔
2031
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (cipher_decrypt, &ideal_granularity));
5✔
2032

2033
            result.test_eq("ideal granularity is a multiple of update granularity (decrypt)",
5✔
2034
                           ideal_granularity % update_granularity,
2035
                           0);
2036

2037
            TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, key.data(), key.size()));
5✔
2038
            TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
5✔
2039

2040
            std::vector<uint8_t> decrypted(plaintext.size());
5✔
2041

2042
            std::span<const uint8_t> ct_slicer(ciphertext);
5✔
2043
            std::span<uint8_t> pt_stuffer(decrypted);
5✔
2044

2045
            // Process data that is explicitly a multiple of the ideal
2046
            // granularity and therefore should be aligned with the cipher's
2047
            // internal block size.
2048
            for(size_t i = 0; i < pt_multiplier; ++i) {
30✔
2049
               size_t output_written = 42;
25✔
2050
               size_t input_consumed = 1337;
25✔
2051

2052
               auto ct_chunk = ct_slicer.first(ideal_granularity);
25✔
2053

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

2061
               TEST_FFI_OK(botan_cipher_update,
25✔
2062
                           (cipher_decrypt,
2063
                            0 /* don't finalize */,
2064
                            pt_chunk.data(),
2065
                            pt_chunk.size(),
2066
                            &output_written,
2067
                            ct_chunk.data(),
2068
                            ct_chunk.size(),
2069
                            &input_consumed));
2070

2071
               result.test_gt("some input consumed", input_consumed, 0);
25✔
2072
               result.test_lte("at most, all input consumed", input_consumed, ct_chunk.size());
25✔
2073
               ct_slicer = ct_slicer.subspan(input_consumed);
25✔
2074

2075
               if(requires_entire_message) {
25✔
2076
                  result.test_eq("no output produced", output_written, 0);
20✔
2077
               } else {
2078
                  result.test_eq("all bytes produced", output_written, input_consumed);
15✔
2079
                  pt_stuffer = pt_stuffer.subspan(output_written);
15✔
2080
               }
2081
            }
2082

2083
            const size_t expected_final_size_dec = requires_entire_message ? plaintext.size() : pt_stuffer.size();
5✔
2084
            auto pt_chunk = pt_stuffer.first(expected_final_size_dec);
5✔
2085

2086
            size_t final_output_written_dec = 42;
5✔
2087
            size_t final_input_consumed_dec = 1337;
5✔
2088

2089
            TEST_FFI_OK(botan_cipher_update,
5✔
2090
                        (cipher_decrypt,
2091
                         BOTAN_CIPHER_UPDATE_FLAG_FINAL,
2092
                         pt_chunk.data(),
2093
                         pt_chunk.size(),
2094
                         &final_output_written_dec,
2095
                         ct_slicer.data(),  // remaining bytes (typically 0)
2096
                         ct_slicer.size(),
2097
                         &final_input_consumed_dec));
2098

2099
            result.test_eq("remaining bytes consumed in final (decrypt)", final_input_consumed_dec, ct_slicer.size());
5✔
2100
            result.test_eq("bytes written in final (decrypt)", final_output_written_dec, expected_final_size_dec);
5✔
2101
            result.test_eq("dummy buffer unchanged", dummy_buffer, dummy_buffer_reference);
10✔
2102

2103
            result.test_eq("decrypted plaintext", decrypted, plaintext);
10✔
2104

2105
            TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
5✔
2106

2107
            merged_result.merge(result, true /* ignore names */);
5✔
2108
         }
35✔
2109
      }
1✔
2110
};
2111

2112
class FFI_StreamCipher_Test final : public FFI_Test {
×
2113
   public:
2114
      std::string name() const override { return "FFI stream ciphers"; }
1✔
2115

2116
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2117
         botan_cipher_t ctr;
1✔
2118

2119
         if(TEST_FFI_INIT(botan_cipher_init, (&ctr, "AES-128/CTR-BE", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
1✔
2120
            const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C");
1✔
2121
            const std::vector<uint8_t> nonce = Botan::hex_decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF");
1✔
2122
            const std::vector<uint8_t> pt = Botan::hex_decode(
1✔
2123
               "AE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710");
1✔
2124
            const std::vector<uint8_t> exp_ct = Botan::hex_decode(
1✔
2125
               "9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE");
1✔
2126

2127
            std::vector<uint8_t> ct(pt.size());
1✔
2128

2129
            size_t update_granularity = 0;
1✔
2130
            size_t ideal_granularity = 0;
1✔
2131

2132
            TEST_FFI_OK(botan_cipher_get_update_granularity, (ctr, &update_granularity));
1✔
2133
            TEST_FFI_OK(botan_cipher_get_ideal_update_granularity, (ctr, &ideal_granularity));
1✔
2134

2135
            result.test_eq(
1✔
2136
               "ideal granularity is a multiple of update granularity", ideal_granularity % update_granularity, 0);
2137

2138
            TEST_FFI_RC(0, botan_cipher_is_authenticated, (ctr));
1✔
2139

2140
            size_t input_consumed = 0;
1✔
2141
            size_t output_written = 0;
1✔
2142

2143
            TEST_FFI_OK(botan_cipher_set_key, (ctr, key.data(), key.size()));
1✔
2144
            TEST_FFI_OK(botan_cipher_start, (ctr, nonce.data(), nonce.size()));
1✔
2145

2146
            // Test partial updates...
2147
            TEST_FFI_OK(botan_cipher_update,
1✔
2148
                        (ctr, 0, ct.data(), ct.size(), &output_written, pt.data(), 5, &input_consumed));
2149

2150
            result.test_int_eq(output_written, 5, "Expected output written");
1✔
2151
            result.test_int_eq(input_consumed, 5, "Expected input consumed");
1✔
2152

2153
            TEST_FFI_OK(botan_cipher_update,
1✔
2154
                        (ctr, 0, &ct[5], ct.size() - 5, &output_written, &pt[5], pt.size() - 5, &input_consumed));
2155

2156
            result.test_int_eq(output_written, ct.size() - 5, "Expected output written");
1✔
2157
            result.test_int_eq(input_consumed, pt.size() - 5, "Expected input consumed");
1✔
2158
            result.test_eq("AES-128/CTR ciphertext", ct, exp_ct);
2✔
2159

2160
            TEST_FFI_OK(botan_cipher_destroy, (ctr));
2✔
2161
         }
5✔
2162
      }
1✔
2163
};
2164

2165
class FFI_HashFunction_Test final : public FFI_Test {
×
2166
   public:
2167
      std::string name() const override { return "FFI hash"; }
1✔
2168

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

2172
         botan_hash_t hash;
1✔
2173
         TEST_FFI_FAIL("invalid hash name", botan_hash_init, (&hash, "SHA-255", 0));
2✔
2174
         TEST_FFI_FAIL("invalid flags", botan_hash_init, (&hash, "SHA-256", 1));
2✔
2175

2176
         if(TEST_FFI_INIT(botan_hash_init, (&hash, "SHA-256", 0))) {
1✔
2177
            std::array<char, 10> namebuf{};
1✔
2178
            size_t name_len = 7;
1✔
2179
            TEST_FFI_FAIL("output buffer too short", botan_hash_name, (hash, namebuf.data(), &name_len));
2✔
2180
            result.test_eq("name len", name_len, 8);
1✔
2181

2182
            name_len = namebuf.size();
1✔
2183
            if(TEST_FFI_OK(botan_hash_name, (hash, namebuf.data(), &name_len))) {
1✔
2184
               result.test_eq("name len", name_len, 8);
1✔
2185
               result.test_eq("name", namebuf.data(), "SHA-256");
2✔
2186
            }
2187

2188
            size_t block_size;
1✔
2189
            if(TEST_FFI_OK(botan_hash_block_size, (hash, &block_size))) {
1✔
2190
               result.test_eq("hash block size", block_size, 64);
2✔
2191
            }
2192

2193
            size_t output_len;
1✔
2194
            if(TEST_FFI_OK(botan_hash_output_length, (hash, &output_len))) {
1✔
2195
               result.test_eq("hash output length", output_len, 32);
1✔
2196

2197
               std::vector<uint8_t> outbuf(output_len);
1✔
2198

2199
               // Test that after clear or final the object can be reused
2200
               for(size_t r = 0; r != 2; ++r) {
3✔
2201
                  TEST_FFI_OK(botan_hash_update, (hash, reinterpret_cast<const uint8_t*>(input_str), 1));
2✔
2202
                  TEST_FFI_OK(botan_hash_clear, (hash));
2✔
2203

2204
                  TEST_FFI_OK(botan_hash_update,
2✔
2205
                              (hash, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
2206
                  TEST_FFI_OK(botan_hash_final, (hash, outbuf.data()));
2✔
2207

2208
                  result.test_eq(
4✔
2209
                     "SHA-256 output", outbuf, "B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78");
2210
               }
2211

2212
               // Test botan_hash_copy_state
2213
               const char* msg = "message digest";
1✔
2214
               const char* expected = "F7846F55CF23E14EEBEAB5B4E1550CAD5B509E3348FBC4EFA3A1413D393CB650";
1✔
2215
               TEST_FFI_OK(botan_hash_clear, (hash));
1✔
2216
               TEST_FFI_OK(botan_hash_update, (hash, reinterpret_cast<const uint8_t*>(&msg[0]), 1));
1✔
2217
               botan_hash_t fork;
1✔
2218
               if(TEST_FFI_OK(botan_hash_copy_state, (&fork, hash))) {
1✔
2219
                  TEST_FFI_OK(botan_hash_update,
1✔
2220
                              (fork, reinterpret_cast<const uint8_t*>(&msg[1]), std::strlen(msg) - 2));
2221

2222
                  TEST_FFI_OK(botan_hash_update,
1✔
2223
                              (hash, reinterpret_cast<const uint8_t*>(&msg[1]), std::strlen(msg) - 1));
2224
                  TEST_FFI_OK(botan_hash_final, (hash, outbuf.data()));
1✔
2225
                  result.test_eq("hashing split", outbuf, expected);
1✔
2226

2227
                  TEST_FFI_OK(botan_hash_update,
1✔
2228
                              (fork, reinterpret_cast<const uint8_t*>(&msg[std::strlen(msg) - 1]), 1));
2229
                  TEST_FFI_OK(botan_hash_final, (fork, outbuf.data()));
1✔
2230
                  result.test_eq("hashing split", outbuf, expected);
1✔
2231

2232
                  TEST_FFI_OK(botan_hash_destroy, (fork));
2✔
2233
               }
2234
            }
1✔
2235

2236
            TEST_FFI_OK(botan_hash_destroy, (hash));
2✔
2237
         }
2238
      }
1✔
2239
};
2240

2241
class FFI_MAC_Test final : public FFI_Test {
×
2242
   public:
2243
      std::string name() const override { return "FFI MAC"; }
1✔
2244

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

2248
         // MAC test
2249
         botan_mac_t mac;
1✔
2250
         TEST_FFI_FAIL("bad flag", botan_mac_init, (&mac, "HMAC(SHA-256)", 1));
2✔
2251
         TEST_FFI_FAIL("bad name", botan_mac_init, (&mac, "HMAC(SHA-259)", 0));
2✔
2252

2253
         if(TEST_FFI_INIT(botan_mac_init, (&mac, "HMAC(SHA-256)", 0))) {
1✔
2254
            std::array<char, 16> namebuf{};
1✔
2255
            size_t name_len = 13;
1✔
2256
            TEST_FFI_FAIL("output buffer too short", botan_mac_name, (mac, namebuf.data(), &name_len));
2✔
2257
            result.test_eq("name len", name_len, 14);
1✔
2258

2259
            name_len = namebuf.size();
1✔
2260
            if(TEST_FFI_OK(botan_mac_name, (mac, namebuf.data(), &name_len))) {
1✔
2261
               result.test_eq("name len", name_len, 14);
1✔
2262
               result.test_eq("name", namebuf.data(), "HMAC(SHA-256)");
2✔
2263
            }
2264

2265
            size_t min_keylen = 0;
1✔
2266
            size_t max_keylen = 0;
1✔
2267
            size_t mod_keylen = 0;
1✔
2268
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, nullptr, nullptr));
1✔
2269
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, &min_keylen, nullptr, nullptr));
1✔
2270
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, &max_keylen, nullptr));
1✔
2271
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, nullptr, &mod_keylen));
1✔
2272

2273
            result.test_eq("Expected min keylen", min_keylen, 0);
1✔
2274
            result.test_eq("Expected max keylen", max_keylen, 4096);
1✔
2275
            result.test_eq("Expected mod keylen", mod_keylen, 1);
1✔
2276

2277
            size_t output_len;
1✔
2278
            if(TEST_FFI_OK(botan_mac_output_length, (mac, &output_len))) {
1✔
2279
               result.test_eq("MAC output length", output_len, 32);
1✔
2280

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

2284
               // Test that after clear or final the object can be reused
2285
               for(size_t r = 0; r != 2; ++r) {
3✔
2286
                  TEST_FFI_OK(botan_mac_set_key, (mac, mac_key, sizeof(mac_key)));
2✔
2287
                  TEST_FFI_OK(botan_mac_update,
2✔
2288
                              (mac, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
2289
                  TEST_FFI_OK(botan_mac_clear, (mac));
2✔
2290

2291
                  TEST_FFI_OK(botan_mac_set_key, (mac, mac_key, sizeof(mac_key)));
2✔
2292
                  TEST_FFI_OK(botan_mac_update,
2✔
2293
                              (mac, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
2294
                  TEST_FFI_OK(botan_mac_final, (mac, outbuf.data()));
2✔
2295

2296
                  result.test_eq(
4✔
2297
                     "HMAC output", outbuf, "1A82EEA984BC4A7285617CC0D05F1FE1D6C96675924A81BC965EE8FF7B0697A7");
2298
               }
2299
            }
1✔
2300

2301
            TEST_FFI_OK(botan_mac_destroy, (mac));
2✔
2302
         }
2303
      }
1✔
2304
};
2305

2306
class FFI_Scrypt_Test final : public FFI_Test {
×
2307
   public:
2308
      std::string name() const override { return "FFI Scrypt"; }
1✔
2309

2310
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2311
         std::vector<uint8_t> output(24);
1✔
2312
         const uint8_t salt[8] = {0};
1✔
2313
         const char* pass = "password";
1✔
2314

2315
         if(TEST_FFI_INIT(botan_scrypt, (output.data(), output.size(), pass, salt, sizeof(salt), 8, 1, 1))) {
1✔
2316
            result.test_eq("scrypt output", output, "4B9B888D695288E002CC4F9D90808A4D296A45CE4471AFBB");
1✔
2317

2318
            size_t N;
1✔
2319
            size_t r;
1✔
2320
            size_t p;
1✔
2321
            TEST_FFI_OK(botan_pwdhash_timed,
1✔
2322
                        ("Scrypt", 50, &r, &p, &N, output.data(), output.size(), "bunny", 5, salt, sizeof(salt)));
2323

2324
            std::vector<uint8_t> cmp(output.size());
1✔
2325

2326
            TEST_FFI_OK(botan_pwdhash, ("Scrypt", N, r, p, cmp.data(), cmp.size(), "bunny", 5, salt, sizeof(salt)));
1✔
2327
            result.test_eq("recomputed scrypt", cmp, output);
2✔
2328
         }
1✔
2329
      }
1✔
2330
};
2331

2332
class FFI_KDF_Test final : public FFI_Test {
×
2333
   public:
2334
      std::string name() const override { return "FFI KDF"; }
1✔
2335

2336
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2337
         std::vector<uint8_t> outbuf;
1✔
2338

2339
         const std::string passphrase = "ltexmfeyylmlbrsyikaw";
1✔
2340

2341
         const std::vector<uint8_t> pbkdf_salt = Botan::hex_decode("ED1F39A0A7F3889AAF7E60743B3BC1CC2C738E60");
1✔
2342
         const size_t pbkdf_out_len = 10;
1✔
2343
         const size_t pbkdf_iterations = 1000;
1✔
2344

2345
         outbuf.resize(pbkdf_out_len);
1✔
2346

2347
         if(TEST_FFI_INIT(botan_pbkdf,
1✔
2348
                          ("PBKDF2(SHA-1)",
2349
                           outbuf.data(),
2350
                           outbuf.size(),
2351
                           passphrase.c_str(),
2352
                           pbkdf_salt.data(),
2353
                           pbkdf_salt.size(),
2354
                           pbkdf_iterations))) {
2355
            result.test_eq("PBKDF output", outbuf, "027AFADD48F4BE8DCC4F");
1✔
2356

2357
            size_t iters_10ms;
1✔
2358
            size_t iters_100ms;
1✔
2359

2360
            TEST_FFI_OK(botan_pbkdf_timed,
1✔
2361
                        ("PBKDF2(SHA-1)",
2362
                         outbuf.data(),
2363
                         outbuf.size(),
2364
                         passphrase.c_str(),
2365
                         pbkdf_salt.data(),
2366
                         pbkdf_salt.size(),
2367
                         10,
2368
                         &iters_10ms));
2369
            TEST_FFI_OK(botan_pbkdf_timed,
1✔
2370
                        ("PBKDF2(SHA-1)",
2371
                         outbuf.data(),
2372
                         outbuf.size(),
2373
                         passphrase.c_str(),
2374
                         pbkdf_salt.data(),
2375
                         pbkdf_salt.size(),
2376
                         100,
2377
                         &iters_100ms));
2378

2379
            result.test_note("PBKDF timed 10 ms " + std::to_string(iters_10ms) + " iterations " + "100 ms " +
5✔
2380
                             std::to_string(iters_100ms) + " iterations");
4✔
2381
         }
2382

2383
         const std::vector<uint8_t> kdf_secret = Botan::hex_decode("92167440112E");
1✔
2384
         const std::vector<uint8_t> kdf_salt = Botan::hex_decode("45A9BEDED69163123D0348F5185F61ABFB1BF18D6AEA454F");
1✔
2385
         const size_t kdf_out_len = 18;
1✔
2386
         outbuf.resize(kdf_out_len);
1✔
2387

2388
         if(TEST_FFI_INIT(botan_kdf,
1✔
2389
                          ("KDF2(SHA-1)",
2390
                           outbuf.data(),
2391
                           outbuf.size(),
2392
                           kdf_secret.data(),
2393
                           kdf_secret.size(),
2394
                           kdf_salt.data(),
2395
                           kdf_salt.size(),
2396
                           nullptr,
2397
                           0))) {
2398
            result.test_eq("KDF output", outbuf, "3A5DC9AA1C872B4744515AC2702D6396FC2A");
2✔
2399
         }
2400

2401
         size_t out_len = 64;
1✔
2402
         std::string outstr;
1✔
2403
         outstr.resize(out_len);
1✔
2404

2405
         int rc =
1✔
2406
            botan_bcrypt_generate(reinterpret_cast<uint8_t*>(outstr.data()), &out_len, passphrase.c_str(), rng, 4, 0);
1✔
2407

2408
         if(rc == 0) {
1✔
2409
            result.test_eq("bcrypt output size", out_len, 61);
1✔
2410

2411
            TEST_FFI_OK(botan_bcrypt_is_valid, (passphrase.c_str(), outstr.data()));
1✔
2412
            TEST_FFI_FAIL("bad password", botan_bcrypt_is_valid, ("nope", outstr.data()));
2✔
2413
         }
2414
      }
5✔
2415
};
2416

2417
class FFI_Blockcipher_Test final : public FFI_Test {
×
2418
   public:
2419
      std::string name() const override { return "FFI block ciphers"; }
1✔
2420

2421
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2422
         botan_block_cipher_t cipher;
1✔
2423

2424
         if(TEST_FFI_INIT(botan_block_cipher_init, (&cipher, "AES-128"))) {
1✔
2425
            std::array<char, 10> namebuf{};
1✔
2426
            size_t name_len = 7;
1✔
2427
            TEST_FFI_FAIL("output buffer too short", botan_block_cipher_name, (cipher, namebuf.data(), &name_len));
2✔
2428
            result.test_eq("name len", name_len, 8);
1✔
2429

2430
            name_len = namebuf.size();
1✔
2431
            if(TEST_FFI_OK(botan_block_cipher_name, (cipher, namebuf.data(), &name_len))) {
1✔
2432
               result.test_eq("name len", name_len, 8);
1✔
2433
               result.test_eq("name", namebuf.data(), "AES-128");
2✔
2434
            }
2435

2436
            const std::vector<uint8_t> zero16(16, 0);
1✔
2437
            std::vector<uint8_t> block(16, 0);
1✔
2438

2439
            TEST_FFI_OK(botan_block_cipher_clear, (cipher));
1✔
2440

2441
            TEST_FFI_RC(
1✔
2442
               BOTAN_FFI_ERROR_KEY_NOT_SET, botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
2443
            TEST_FFI_RC(
1✔
2444
               BOTAN_FFI_ERROR_KEY_NOT_SET, botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
2445

2446
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_block_cipher_encrypt_blocks, (cipher, nullptr, nullptr, 0));
1✔
2447
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_block_cipher_decrypt_blocks, (cipher, nullptr, nullptr, 0));
1✔
2448

2449
            TEST_FFI_RC(16, botan_block_cipher_block_size, (cipher));
1✔
2450

2451
            size_t min_keylen = 0;
1✔
2452
            size_t max_keylen = 0;
1✔
2453
            size_t mod_keylen = 0;
1✔
2454
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, nullptr, nullptr));
1✔
2455
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, &min_keylen, nullptr, nullptr));
1✔
2456
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, &max_keylen, nullptr));
1✔
2457
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, nullptr, &mod_keylen));
1✔
2458

2459
            result.test_eq("Expected min keylen", min_keylen, 16);
1✔
2460
            result.test_eq("Expected max keylen", max_keylen, 16);
1✔
2461
            result.test_eq("Expected mod keylen", mod_keylen, 1);
1✔
2462

2463
            TEST_FFI_OK(botan_block_cipher_set_key, (cipher, zero16.data(), zero16.size()));
1✔
2464

2465
            TEST_FFI_OK(botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
2466
            result.test_eq("AES-128 encryption works", block, "66E94BD4EF8A2C3B884CFA59CA342B2E");
1✔
2467

2468
            TEST_FFI_OK(botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
2469
            result.test_eq("AES-128 encryption works", block, "F795BD4A52E29ED713D313FA20E98DBC");
1✔
2470

2471
            TEST_FFI_OK(botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
2472
            result.test_eq("AES-128 decryption works", block, "66E94BD4EF8A2C3B884CFA59CA342B2E");
1✔
2473

2474
            TEST_FFI_OK(botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
2475
            result.test_eq("AES-128 decryption works", block, "00000000000000000000000000000000");
1✔
2476

2477
            TEST_FFI_OK(botan_block_cipher_clear, (cipher));
1✔
2478
            botan_block_cipher_destroy(cipher);
1✔
2479
         }
2✔
2480
      }
1✔
2481
};
2482

2483
class FFI_ErrorHandling_Test final : public FFI_Test {
×
2484
   public:
2485
      std::string name() const override { return "FFI error handling"; }
1✔
2486

2487
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2488
         // delete of null is ok/ignored
2489
         TEST_FFI_RC(0, botan_hash_destroy, (nullptr));
1✔
2490

2491
   #if !defined(BOTAN_HAS_SANITIZER_UNDEFINED)
2492
         // Confirm that botan_x_destroy checks the argument type
2493
         botan_mp_t mp;
1✔
2494
         botan_mp_init(&mp);
1✔
2495
         TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT, botan_hash_destroy, (reinterpret_cast<botan_hash_t>(mp)));
1✔
2496
         TEST_FFI_RC(0, botan_mp_destroy, (mp));
1✔
2497
   #endif
2498

2499
         std::set<std::string> errors;
1✔
2500
         for(int i = -100; i != 50; ++i) {
151✔
2501
            const char* err = botan_error_description(i);
150✔
2502
            result.confirm("Never a null pointer", err != nullptr);
300✔
2503

2504
            if(err != nullptr) {
150✔
2505
               std::string s(err);
150✔
2506

2507
               if(s != "Unknown error") {
150✔
2508
                  result.confirm("No duplicate messages", !errors.contains(s));
42✔
2509
                  errors.insert(s);
21✔
2510
               }
2511
            }
150✔
2512
         }
2513
      }
1✔
2514
};
2515

2516
class FFI_Base64_Test final : public FFI_Test {
×
2517
   public:
2518
      std::string name() const override { return "FFI base64"; }
1✔
2519

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

2524
         size_t out_len = sizeof(out_buf);
1✔
2525
         TEST_FFI_OK(botan_base64_encode, (bin, sizeof(bin), out_buf, &out_len));
1✔
2526

2527
         result.test_eq("encoded string", out_buf, "FoofBunny900");
1✔
2528

2529
         out_len -= 1;
1✔
2530
         TEST_FFI_RC(
1✔
2531
            BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_base64_encode, (bin, sizeof(bin), out_buf, &out_len));
2532

2533
         const char* base64 = "U3VjaCBiYXNlNjQgd293IQ==";
1✔
2534
         uint8_t out_bin[1024] = {0};
1✔
2535

2536
         out_len = 3;
1✔
2537
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
2538
                     botan_base64_decode,
2539
                     (base64, strlen(base64), out_bin, &out_len));
2540

2541
         result.test_eq("output length", out_len, 18);
1✔
2542

2543
         out_len = sizeof(out_bin);
1✔
2544
         TEST_FFI_OK(botan_base64_decode, (base64, strlen(base64), out_bin, &out_len));
1✔
2545

2546
         result.test_eq(
3✔
2547
            "decoded string", std::string(reinterpret_cast<const char*>(out_bin), out_len), "Such base64 wow!");
2✔
2548
      }
1✔
2549
};
2550

2551
class FFI_Hex_Test final : public FFI_Test {
×
2552
   public:
2553
      std::string name() const override { return "FFI hex"; }
1✔
2554

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

2559
         TEST_FFI_OK(botan_hex_encode, (bin, sizeof(bin), hex_buf, 0));
1✔
2560

2561
         result.test_eq("encoded string", hex_buf, "DEADBEEF");
1✔
2562

2563
         const char* hex = "67657420796572206A756D626F20736872696D70";
1✔
2564
         uint8_t out_bin[1024] = {0};
1✔
2565
         size_t out_len = 5;
1✔
2566

2567
         TEST_FFI_RC(
1✔
2568
            BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_hex_decode, (hex, strlen(hex), out_bin, &out_len));
2569

2570
         out_len = sizeof(out_bin);
1✔
2571
         TEST_FFI_OK(botan_hex_decode, (hex, strlen(hex), out_bin, &out_len));
1✔
2572

2573
         result.test_eq(
3✔
2574
            "decoded string", std::string(reinterpret_cast<const char*>(out_bin), out_len), "get yer jumbo shrimp");
2✔
2575
      }
1✔
2576
};
2577

2578
class FFI_MP_Test final : public FFI_Test {
×
2579
   public:
2580
      std::string name() const override { return "FFI MP"; }
1✔
2581

2582
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2583
         char str_buf[1024] = {0};
1✔
2584
         size_t str_len = 0;
1✔
2585

2586
         botan_mp_t x;
1✔
2587
         botan_mp_init(&x);
1✔
2588
         TEST_FFI_RC(0, botan_mp_is_odd, (x));
1✔
2589
         TEST_FFI_RC(1, botan_mp_is_even, (x));
1✔
2590
         TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
2591
         TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
2592
         TEST_FFI_RC(1, botan_mp_is_zero, (x));
1✔
2593
         botan_mp_destroy(x);
1✔
2594

2595
         botan_mp_init(&x);
1✔
2596
         size_t bn_bytes = 0;
1✔
2597
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
2598
         result.test_eq("Expected size for MP 0", bn_bytes, 0);
1✔
2599

2600
         botan_mp_set_from_int(x, 5);
1✔
2601
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
2602
         result.test_eq("Expected size for MP 5", bn_bytes, 1);
1✔
2603

2604
         botan_mp_add_u32(x, x, 75);
1✔
2605
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
2606
         result.test_eq("Expected size for MP 80", bn_bytes, 1);
1✔
2607

2608
         str_len = sizeof(str_buf);
1✔
2609
         TEST_FFI_OK(botan_mp_to_str, (x, 10, str_buf, &str_len));
1✔
2610
         result.test_eq("botan_mp_add", std::string(str_buf), "80");
2✔
2611

2612
         botan_mp_sub_u32(x, x, 80);
1✔
2613
         TEST_FFI_RC(1, botan_mp_is_zero, (x));
1✔
2614
         botan_mp_add_u32(x, x, 259);
1✔
2615
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
2616
         result.test_eq("Expected size for MP 259", bn_bytes, 2);
1✔
2617

2618
         str_len = sizeof(str_buf);
1✔
2619
         TEST_FFI_OK(botan_mp_to_str, (x, 10, str_buf, &str_len));
1✔
2620
         result.test_eq("botan_mp_add", std::string(str_buf), "259");
2✔
2621

2622
         TEST_FFI_RC(1, botan_mp_is_odd, (x));
1✔
2623
         TEST_FFI_RC(0, botan_mp_is_even, (x));
1✔
2624
         TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
2625
         TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
2626
         TEST_FFI_RC(0, botan_mp_is_zero, (x));
1✔
2627

2628
         {
1✔
2629
            botan_mp_t zero;
1✔
2630
            botan_mp_init(&zero);
1✔
2631
            int cmp;
1✔
2632
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, zero));
1✔
2633
            result.confirm("bigint_mp_cmp(+, 0)", cmp == 1);
2✔
2634

2635
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, x));
1✔
2636
            result.confirm("bigint_mp_cmp(0, +)", cmp == -1);
2✔
2637

2638
            TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
2639
            TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
2640
            TEST_FFI_OK(botan_mp_flip_sign, (x));
1✔
2641
            TEST_FFI_RC(1, botan_mp_is_negative, (x));
1✔
2642
            TEST_FFI_RC(0, botan_mp_is_positive, (x));
1✔
2643

2644
            // test no negative zero
2645
            TEST_FFI_RC(0, botan_mp_is_negative, (zero));
1✔
2646
            TEST_FFI_RC(1, botan_mp_is_positive, (zero));
1✔
2647
            TEST_FFI_OK(botan_mp_flip_sign, (zero));
1✔
2648
            TEST_FFI_RC(0, botan_mp_is_negative, (zero));
1✔
2649
            TEST_FFI_RC(1, botan_mp_is_positive, (zero));
1✔
2650

2651
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, zero));
1✔
2652
            result.confirm("bigint_mp_cmp(-, 0)", cmp == -1);
2✔
2653

2654
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, x));
1✔
2655
            result.confirm("bigint_mp_cmp(0, -)", cmp == 1);
2✔
2656

2657
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, zero));
1✔
2658
            result.confirm("bigint_mp_cmp(0, 0)", cmp == 0);
2✔
2659

2660
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, x));
1✔
2661
            result.confirm("bigint_mp_cmp(x, x)", cmp == 0);
2✔
2662

2663
            TEST_FFI_OK(botan_mp_flip_sign, (x));
1✔
2664

2665
            botan_mp_destroy(zero);
1✔
2666
         }
2667

2668
         size_t x_bits = 0;
1✔
2669
         TEST_FFI_OK(botan_mp_num_bits, (x, &x_bits));
1✔
2670
         result.test_eq("botan_mp_num_bits", x_bits, 9);
1✔
2671

2672
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
2673
         result.test_eq("botan_mp_to_hex", std::string(str_buf), "0x0103");
2✔
2674

2675
         uint32_t x_32;
1✔
2676
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
2677
         result.test_eq("botan_mp_to_uint32", size_t(x_32), size_t(0x103));
1✔
2678

2679
         TEST_FFI_RC(1, botan_mp_get_bit, (x, 1));
1✔
2680
         TEST_FFI_RC(0, botan_mp_get_bit, (x, 87));
1✔
2681
         TEST_FFI_OK(botan_mp_set_bit, (x, 87));
1✔
2682
         TEST_FFI_RC(1, botan_mp_get_bit, (x, 87));
1✔
2683
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
2684
         result.test_eq("botan_mp_set_bit", std::string(str_buf), "0x8000000000000000000103");
2✔
2685

2686
         TEST_FFI_OK(botan_mp_clear_bit, (x, 87));
1✔
2687
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
2688
         result.test_eq("botan_mp_set_bit", std::string(str_buf), "0x0103");
2✔
2689

2690
         botan_mp_t y;
1✔
2691
         TEST_FFI_OK(botan_mp_init, (&y));
1✔
2692
         TEST_FFI_OK(botan_mp_set_from_int, (y, 0x1234567));
1✔
2693

2694
         botan_mp_t r;
1✔
2695
         botan_mp_init(&r);
1✔
2696

2697
         TEST_FFI_OK(botan_mp_add, (r, x, y));
1✔
2698
         str_len = sizeof(str_buf);
1✔
2699
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2700
         result.test_eq("botan_mp_add", std::string(str_buf), "19089002");
2✔
2701

2702
         TEST_FFI_OK(botan_mp_mul, (r, x, y));
1✔
2703
         str_len = sizeof(str_buf);
1✔
2704
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2705
         result.test_eq("botan_mp_mul", std::string(str_buf), "4943984437");
2✔
2706
         TEST_FFI_RC(0, botan_mp_is_negative, (r));
1✔
2707

2708
         botan_mp_t q;
1✔
2709
         botan_mp_init(&q);
1✔
2710
         TEST_FFI_OK(botan_mp_div, (q, r, y, x));
1✔
2711

2712
         str_len = sizeof(str_buf);
1✔
2713
         TEST_FFI_OK(botan_mp_to_str, (q, 10, str_buf, &str_len));
1✔
2714
         result.test_eq("botan_mp_div_q", std::string(str_buf), "73701");
2✔
2715

2716
         str_len = sizeof(str_buf);
1✔
2717
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2718
         result.test_eq("botan_mp_div_r", std::string(str_buf), "184");
2✔
2719

2720
         TEST_FFI_OK(botan_mp_set_from_str, (y, "4943984437"));
1✔
2721
         TEST_FFI_OK(botan_mp_sub, (r, x, y));
1✔
2722
         str_len = sizeof(str_buf);
1✔
2723
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2724
         result.test_eq("botan_mp_sub", std::string(str_buf), "-4943984178");
2✔
2725
         TEST_FFI_RC(1, botan_mp_is_negative, (r));
1✔
2726

2727
         TEST_FFI_OK(botan_mp_lshift, (r, x, 39));
1✔
2728
         str_len = sizeof(str_buf);
1✔
2729
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2730
         result.test_eq("botan_mp_lshift", std::string(str_buf), "142386755796992");
2✔
2731

2732
         TEST_FFI_OK(botan_mp_rshift, (r, r, 3));
1✔
2733
         str_len = sizeof(str_buf);
1✔
2734
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2735
         result.test_eq("botan_mp_rshift", std::string(str_buf), "17798344474624");
2✔
2736

2737
         TEST_FFI_OK(botan_mp_gcd, (r, x, y));
1✔
2738
         str_len = sizeof(str_buf);
1✔
2739
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2740
         result.test_eq("botan_mp_gcd", std::string(str_buf), "259");
2✔
2741

2742
         botan_mp_t p;
1✔
2743
         botan_mp_init(&p);
1✔
2744
         const uint8_t M127[] = {
1✔
2745
            0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
2746
         TEST_FFI_OK(botan_mp_from_bin, (p, M127, sizeof(M127)));
1✔
2747
         TEST_FFI_RC(1, botan_mp_is_prime, (p, rng, 64));
1✔
2748

2749
         size_t p_bits = 0;
1✔
2750
         TEST_FFI_OK(botan_mp_num_bits, (p, &p_bits));
1✔
2751
         result.test_eq("botan_mp_num_bits", p_bits, 127);
1✔
2752

2753
         TEST_FFI_OK(botan_mp_mod_inverse, (r, x, p));
1✔
2754
         str_len = sizeof(str_buf);
1✔
2755
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2756
         result.test_eq("botan_mp_mod_inverse", std::string(str_buf), "40728777507911553541948312086427855425");
2✔
2757

2758
         TEST_FFI_OK(botan_mp_powmod, (r, x, r, p));
1✔
2759
         str_len = sizeof(str_buf);
1✔
2760
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2761
         result.test_eq("botan_mp_powmod", std::string(str_buf), "40550417419160441638948180641668117560");
2✔
2762

2763
         TEST_FFI_OK(botan_mp_num_bytes, (r, &bn_bytes));
1✔
2764
         result.test_eq("botan_mp_num_bytes", bn_bytes, 16);
1✔
2765

2766
         std::vector<uint8_t> bn_buf;
1✔
2767
         bn_buf.resize(bn_bytes);
1✔
2768
         botan_mp_to_bin(r, bn_buf.data());
1✔
2769
         result.test_eq("botan_mp_to_bin", bn_buf, "1E81B9EFE0BE1902F6D03F9F5E5FB438");
1✔
2770

2771
         TEST_FFI_OK(botan_mp_set_from_mp, (y, r));
1✔
2772
         TEST_FFI_OK(botan_mp_mod_mul, (r, x, y, p));
1✔
2773
         str_len = sizeof(str_buf);
1✔
2774
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2775
         result.test_eq("botan_mp_mod_mul", std::string(str_buf), "123945920473931248854653259523111998693");
2✔
2776

2777
         str_len = 0;
1✔
2778
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
2779

2780
         size_t x_bytes;
1✔
2781
         botan_mp_rand_bits(x, rng, 512);
1✔
2782
         TEST_FFI_OK(botan_mp_num_bytes, (x, &x_bytes));
1✔
2783
         result.test_lte("botan_mp_num_bytes", x_bytes, 512 / 8);
1✔
2784

2785
         TEST_FFI_OK(botan_mp_set_from_radix_str, (x, "909A", 16));
1✔
2786
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
2787
         result.test_eq("botan_mp_set_from_radix_str(16)", x_32, static_cast<size_t>(0x909A));
1✔
2788

2789
         TEST_FFI_OK(botan_mp_set_from_radix_str, (x, "9098135", 10));
1✔
2790
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
2791
         result.test_eq("botan_mp_set_from_radix_str(10)", x_32, static_cast<size_t>(9098135));
1✔
2792

2793
         botan_mp_destroy(p);
1✔
2794
         botan_mp_destroy(x);
1✔
2795
         botan_mp_destroy(y);
1✔
2796
         botan_mp_destroy(r);
1✔
2797
         botan_mp_destroy(q);
1✔
2798
      }
1✔
2799
};
2800

2801
class FFI_FPE_Test final : public FFI_Test {
×
2802
   public:
2803
      std::string name() const override { return "FFI FPE"; }
1✔
2804

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

2808
         botan_mp_t n;
1✔
2809
         botan_mp_init(&n);
1✔
2810
         botan_mp_set_from_str(n, "1000000000");
1✔
2811

2812
         botan_fpe_t fpe;
1✔
2813
         if(!TEST_FFI_INIT(botan_fpe_fe1_init, (&fpe, n, key, sizeof(key), 5, 0))) {
1✔
2814
            botan_mp_destroy(n);
×
2815
            return;
×
2816
         }
2817

2818
         botan_mp_t x;
1✔
2819
         botan_mp_init(&x);
1✔
2820
         botan_mp_set_from_str(x, "178051120");
1✔
2821

2822
         TEST_FFI_OK(botan_fpe_encrypt, (fpe, x, nullptr, 0));
1✔
2823

2824
         uint32_t xval = 0;
1✔
2825
         TEST_FFI_OK(botan_mp_to_uint32, (x, &xval));
1✔
2826
         result.test_eq("Expected FPE ciphertext", xval, size_t(605648666));
1✔
2827

2828
         TEST_FFI_OK(botan_fpe_encrypt, (fpe, x, nullptr, 0));
1✔
2829
         TEST_FFI_OK(botan_fpe_decrypt, (fpe, x, nullptr, 0));
1✔
2830
         TEST_FFI_OK(botan_fpe_decrypt, (fpe, x, nullptr, 0));
1✔
2831

2832
         TEST_FFI_OK(botan_mp_to_uint32, (x, &xval));
1✔
2833
         result.test_eq("FPE round trip", xval, size_t(178051120));
1✔
2834

2835
         TEST_FFI_OK(botan_fpe_destroy, (fpe));
1✔
2836
         TEST_FFI_OK(botan_mp_destroy, (x));
1✔
2837
         TEST_FFI_OK(botan_mp_destroy, (n));
2✔
2838
      }
2839
};
2840

2841
class FFI_TOTP_Test final : public FFI_Test {
×
2842
   public:
2843
      std::string name() const override { return "FFI TOTP"; }
1✔
2844

2845
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2846
         const std::vector<uint8_t> key = Botan::hex_decode("3132333435363738393031323334353637383930");
1✔
2847
         const size_t digits = 8;
1✔
2848
         const size_t timestep = 30;
1✔
2849
         botan_totp_t totp;
1✔
2850

2851
         if(!TEST_FFI_INIT(botan_totp_init, (&totp, key.data(), key.size(), "SHA-1", digits, timestep))) {
1✔
2852
            return;
×
2853
         }
2854

2855
         uint32_t code;
1✔
2856
         TEST_FFI_OK(botan_totp_generate, (totp, &code, 59));
1✔
2857
         result.confirm("TOTP code", code == 94287082);
2✔
2858

2859
         TEST_FFI_OK(botan_totp_generate, (totp, &code, 1111111109));
1✔
2860
         result.confirm("TOTP code 2", code == 7081804);
2✔
2861

2862
         TEST_FFI_OK(botan_totp_check, (totp, 94287082, 59 + 60, 60));
1✔
2863
         TEST_FFI_RC(1, botan_totp_check, (totp, 94287082, 59 + 31, 1));
1✔
2864
         TEST_FFI_RC(1, botan_totp_check, (totp, 94287082, 59 + 61, 1));
1✔
2865

2866
         TEST_FFI_OK(botan_totp_destroy, (totp));
2✔
2867
      }
1✔
2868
};
2869

2870
class FFI_HOTP_Test final : public FFI_Test {
×
2871
   public:
2872
      std::string name() const override { return "FFI HOTP"; }
1✔
2873

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

2878
         botan_hotp_t hotp;
1✔
2879
         uint32_t hotp_val;
1✔
2880

2881
         if(!TEST_FFI_INIT(botan_hotp_init, (&hotp, key.data(), key.size(), "SHA-1", digits))) {
1✔
2882
            return;
×
2883
         }
2884

2885
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 0));
1✔
2886
         result.confirm("Valid value for counter 0", hotp_val == 755224);
2✔
2887
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 1));
1✔
2888
         result.confirm("Valid value for counter 0", hotp_val == 287082);
2✔
2889
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 2));
1✔
2890
         result.confirm("Valid value for counter 0", hotp_val == 359152);
2✔
2891
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 0));
1✔
2892
         result.confirm("Valid value for counter 0", hotp_val == 755224);
2✔
2893

2894
         uint64_t next_ctr = 0;
1✔
2895

2896
         TEST_FFI_OK(botan_hotp_check, (hotp, &next_ctr, 755224, 0, 0));
1✔
2897
         result.confirm("HOTP resync", next_ctr == 1);
2✔
2898
         TEST_FFI_OK(botan_hotp_check, (hotp, nullptr, 359152, 2, 0));
1✔
2899
         TEST_FFI_RC(1, botan_hotp_check, (hotp, nullptr, 359152, 1, 0));
1✔
2900
         TEST_FFI_OK(botan_hotp_check, (hotp, &next_ctr, 359152, 0, 2));
1✔
2901
         result.confirm("HOTP resync", next_ctr == 3);
2✔
2902

2903
         TEST_FFI_OK(botan_hotp_destroy, (hotp));
2✔
2904
      }
1✔
2905
};
2906

2907
class FFI_Keywrap_Test final : public FFI_Test {
×
2908
   public:
2909
      std::string name() const override { return "FFI Keywrap"; }
1✔
2910

2911
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2912
         const uint8_t key[16] = {0};
1✔
2913
         const uint8_t kek[16] = {0xFF, 0};
1✔
2914

2915
         uint8_t wrapped[16 + 8] = {0};
1✔
2916
         size_t wrapped_keylen = sizeof(wrapped);
1✔
2917

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

2923
            result.test_eq("Expected wrapped keylen size", wrapped_keylen, 16 + 8);
1✔
2924

2925
            result.test_eq(
1✔
2926
               nullptr, "Wrapped key", wrapped, wrapped_keylen, expected_wrapped_key, sizeof(expected_wrapped_key));
2927

2928
            uint8_t dec_key[16] = {0};
1✔
2929
            size_t dec_keylen = sizeof(dec_key);
1✔
2930
            TEST_FFI_OK(botan_key_unwrap3394, (wrapped, sizeof(wrapped), kek, sizeof(kek), dec_key, &dec_keylen));
1✔
2931

2932
            result.test_eq(nullptr, "Unwrapped key", dec_key, dec_keylen, key, sizeof(key));
2✔
2933
         }
2934
      }
1✔
2935
};
2936

2937
class FFI_XMSS_Test final : public FFI_Test {
×
2938
   public:
2939
      std::string name() const override { return "FFI XMSS"; }
1✔
2940

2941
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2942
         botan_privkey_t priv;
1✔
2943
         if(TEST_FFI_INIT(botan_privkey_create, (&priv, "XMSS", "XMSS-SHA2_10_256", rng))) {
1✔
2944
            TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
1✔
2945

2946
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_privkey_stateful_operation, (priv, nullptr));
1✔
2947
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_privkey_remaining_operations, (priv, nullptr));
1✔
2948

2949
            int stateful;
1✔
2950
            TEST_FFI_OK(botan_privkey_stateful_operation, (priv, &stateful));
1✔
2951
            result.confirm("key is stateful", stateful == 1, true);
2✔
2952

2953
            uint64_t remaining;
1✔
2954
            TEST_FFI_OK(botan_privkey_remaining_operations, (priv, &remaining));
1✔
2955
            result.confirm("key has remaining operations", remaining == 1024, true);
2✔
2956

2957
            TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
2958
         }
2959
      }
1✔
2960
};
2961

2962
class FFI_RSA_Test final : public FFI_Test {
×
2963
   public:
2964
      std::string name() const override { return "FFI RSA"; }
1✔
2965

2966
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2967
         botan_privkey_t priv;
1✔
2968

2969
         if(TEST_FFI_INIT(botan_privkey_create_rsa, (&priv, rng, 1024))) {
1✔
2970
            TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
1✔
2971

2972
            int stateful;
1✔
2973
            TEST_FFI_OK(botan_privkey_stateful_operation, (priv, &stateful));
1✔
2974
            result.confirm("key is not stateful", stateful == 1, false);
2✔
2975

2976
            uint64_t remaining;
1✔
2977
            TEST_FFI_FAIL("key is not stateful", botan_privkey_remaining_operations, (priv, &remaining));
2✔
2978

2979
            botan_pubkey_t pub;
1✔
2980
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
2981
            TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
1✔
2982

2983
            ffi_test_pubkey_export(result, pub, priv, rng);
1✔
2984

2985
            botan_mp_t p;
1✔
2986
            botan_mp_t q;
1✔
2987
            botan_mp_t d;
1✔
2988
            botan_mp_t n;
1✔
2989
            botan_mp_t e;
1✔
2990
            botan_mp_init(&p);
1✔
2991
            botan_mp_init(&q);
1✔
2992
            botan_mp_init(&d);
1✔
2993
            botan_mp_init(&n);
1✔
2994
            botan_mp_init(&e);
1✔
2995

2996
            TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (p, priv, "quux"));
1✔
2997
            TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_pubkey_get_field, (p, pub, "quux"));
1✔
2998

2999
            TEST_FFI_OK(botan_privkey_rsa_get_p, (p, priv));
1✔
3000
            TEST_FFI_OK(botan_privkey_rsa_get_q, (q, priv));
1✔
3001
            TEST_FFI_OK(botan_privkey_rsa_get_d, (d, priv));
1✔
3002
            TEST_FFI_OK(botan_privkey_rsa_get_e, (e, priv));
1✔
3003
            TEST_FFI_OK(botan_privkey_rsa_get_n, (n, priv));
1✔
3004

3005
            // Confirm same (e,n) values in public key
3006
            {
1✔
3007
               botan_mp_t pub_e;
1✔
3008
               botan_mp_t pub_n;
1✔
3009
               botan_mp_init(&pub_e);
1✔
3010
               botan_mp_init(&pub_n);
1✔
3011
               TEST_FFI_OK(botan_pubkey_rsa_get_e, (pub_e, pub));
1✔
3012
               TEST_FFI_OK(botan_pubkey_rsa_get_n, (pub_n, pub));
1✔
3013

3014
               TEST_FFI_RC(1, botan_mp_equal, (pub_e, e));
1✔
3015
               TEST_FFI_RC(1, botan_mp_equal, (pub_n, n));
1✔
3016
               botan_mp_destroy(pub_e);
1✔
3017
               botan_mp_destroy(pub_n);
1✔
3018
            }
3019

3020
            TEST_FFI_RC(1, botan_mp_is_prime, (p, rng, 64));
1✔
3021
            TEST_FFI_RC(1, botan_mp_is_prime, (q, rng, 64));
1✔
3022

3023
            // Test p != q
3024
            TEST_FFI_RC(0, botan_mp_equal, (p, q));
1✔
3025

3026
            // Test p * q == n
3027
            botan_mp_t x;
1✔
3028
            botan_mp_init(&x);
1✔
3029
            TEST_FFI_OK(botan_mp_mul, (x, p, q));
1✔
3030

3031
            TEST_FFI_RC(1, botan_mp_equal, (x, n));
1✔
3032
            botan_mp_destroy(x);
1✔
3033

3034
            botan_privkey_t loaded_privkey;
1✔
3035
            // First try loading a bogus key and verify check_key fails
3036
            TEST_FFI_OK(botan_privkey_load_rsa, (&loaded_privkey, n, d, q));
1✔
3037
            TEST_FFI_RC(-1, botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3038
            botan_privkey_destroy(loaded_privkey);
1✔
3039

3040
            TEST_FFI_OK(botan_privkey_load_rsa, (&loaded_privkey, p, q, e));
1✔
3041
            TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3042

3043
            botan_pubkey_t loaded_pubkey;
1✔
3044
            TEST_FFI_OK(botan_pubkey_load_rsa, (&loaded_pubkey, n, e));
1✔
3045
            TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
3046

3047
            botan_mp_destroy(p);
1✔
3048
            botan_mp_destroy(q);
1✔
3049
            botan_mp_destroy(d);
1✔
3050
            botan_mp_destroy(e);
1✔
3051
            botan_mp_destroy(n);
1✔
3052

3053
            size_t pkcs1_len = 0;
1✔
3054
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
3055
                        botan_privkey_rsa_get_privkey,
3056
                        (loaded_privkey, nullptr, &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
3057

3058
            std::vector<uint8_t> pkcs1(pkcs1_len);
1✔
3059
            TEST_FFI_OK(botan_privkey_rsa_get_privkey,
1✔
3060
                        (loaded_privkey, pkcs1.data(), &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
3061

3062
            botan_privkey_t privkey_from_pkcs1;
1✔
3063
            TEST_FFI_OK(botan_privkey_load_rsa_pkcs1, (&privkey_from_pkcs1, pkcs1.data(), pkcs1_len));
1✔
3064
            TEST_FFI_OK(botan_privkey_destroy, (privkey_from_pkcs1));
1✔
3065

3066
            pkcs1_len = 0;
1✔
3067
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
3068
                        botan_privkey_rsa_get_privkey,
3069
                        (loaded_privkey, nullptr, &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
3070
            pkcs1.resize(pkcs1_len);
1✔
3071
            TEST_FFI_OK(botan_privkey_rsa_get_privkey,
1✔
3072
                        (loaded_privkey, pkcs1.data(), &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
3073

3074
            std::array<char, 32> namebuf{};
1✔
3075
            size_t name_len = namebuf.size();
1✔
3076
            if(TEST_FFI_OK(botan_pubkey_algo_name, (loaded_pubkey, namebuf.data(), &name_len))) {
1✔
3077
               result.test_eq("algo name", namebuf.data(), "RSA");
2✔
3078
            }
3079

3080
            name_len = namebuf.size();
1✔
3081
            if(TEST_FFI_OK(botan_privkey_algo_name, (loaded_privkey, namebuf.data(), &name_len))) {
1✔
3082
               result.test_eq("algo name", namebuf.data(), "RSA");
2✔
3083
            }
3084

3085
            botan_pk_op_encrypt_t encrypt;
1✔
3086
            if(TEST_FFI_INIT(botan_pk_op_encrypt_create, (&encrypt, loaded_pubkey, "OAEP(SHA-256)", 0))) {
1✔
3087
               std::vector<uint8_t> plaintext(32);
1✔
3088
               TEST_FFI_OK(botan_rng_get, (rng, plaintext.data(), plaintext.size()));
1✔
3089

3090
               size_t ctext_len;
1✔
3091
               TEST_FFI_OK(botan_pk_op_encrypt_output_length, (encrypt, plaintext.size(), &ctext_len));
1✔
3092
               std::vector<uint8_t> ciphertext(ctext_len);
1✔
3093

3094
               if(TEST_FFI_OK(botan_pk_op_encrypt,
1✔
3095
                              (encrypt, rng, ciphertext.data(), &ctext_len, plaintext.data(), plaintext.size()))) {
3096
                  ciphertext.resize(ctext_len);
1✔
3097

3098
                  botan_pk_op_decrypt_t decrypt;
1✔
3099
                  if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&decrypt, priv, "OAEP(SHA-256)", 0))) {
1✔
3100
                     size_t decrypted_len;
1✔
3101
                     TEST_FFI_OK(botan_pk_op_decrypt_output_length, (decrypt, ciphertext.size(), &decrypted_len));
1✔
3102
                     std::vector<uint8_t> decrypted(decrypted_len);
1✔
3103
                     TEST_FFI_OK(botan_pk_op_decrypt,
1✔
3104
                                 (decrypt, decrypted.data(), &decrypted_len, ciphertext.data(), ciphertext.size()));
3105
                     decrypted.resize(decrypted_len);
1✔
3106

3107
                     result.test_eq("RSA plaintext", decrypted, plaintext);
2✔
3108
                  }
1✔
3109

3110
                  TEST_FFI_OK(botan_pk_op_decrypt_destroy, (decrypt));
2✔
3111
               }
3112

3113
               TEST_FFI_OK(botan_pk_op_encrypt_destroy, (encrypt));
2✔
3114
            }
2✔
3115

3116
            TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
1✔
3117
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3118
            TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
3119
            TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
3120
         }
1✔
3121
      }
1✔
3122
};
3123

3124
class FFI_DSA_Test final : public FFI_Test {
×
3125
   public:
3126
      std::string name() const override { return "FFI DSA"; }
1✔
3127

3128
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3129
         botan_privkey_t priv;
1✔
3130

3131
         if(TEST_FFI_INIT(botan_privkey_create, (&priv, "DSA", "dsa/jce/1024", rng))) {
1✔
3132
            do_dsa_test(priv, rng, result);
1✔
3133
         }
3134

3135
         if(TEST_FFI_INIT(botan_privkey_create_dsa, (&priv, rng, 1024, 160))) {
1✔
3136
            do_dsa_test(priv, rng, result);
1✔
3137
         }
3138
      }
1✔
3139

3140
   private:
3141
      static void do_dsa_test(botan_privkey_t priv, botan_rng_t rng, Test::Result& result) {
2✔
3142
         TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
2✔
3143

3144
         botan_pubkey_t pub;
2✔
3145
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
2✔
3146
         TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
2✔
3147

3148
         ffi_test_pubkey_export(result, pub, priv, rng);
2✔
3149

3150
         botan_mp_t p;
2✔
3151
         botan_mp_t q;
2✔
3152
         botan_mp_t g;
2✔
3153
         botan_mp_t x;
2✔
3154
         botan_mp_t y;
2✔
3155
         botan_mp_init(&p);
2✔
3156
         botan_mp_init(&q);
2✔
3157
         botan_mp_init(&g);
2✔
3158
         botan_mp_init(&x);
2✔
3159
         botan_mp_init(&y);
2✔
3160

3161
         TEST_FFI_OK(botan_privkey_dsa_get_x, (x, priv));
2✔
3162
         TEST_FFI_OK(botan_pubkey_dsa_get_g, (g, pub));
2✔
3163
         TEST_FFI_OK(botan_pubkey_dsa_get_p, (p, pub));
2✔
3164
         TEST_FFI_OK(botan_pubkey_dsa_get_q, (q, pub));
2✔
3165
         TEST_FFI_OK(botan_pubkey_dsa_get_y, (y, pub));
2✔
3166

3167
         botan_mp_t cmp;
2✔
3168
         botan_mp_init(&cmp);
2✔
3169
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (cmp, priv, "quux"));
2✔
3170

3171
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "x"));
2✔
3172
         TEST_FFI_RC(1, botan_mp_equal, (cmp, x));
2✔
3173

3174
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "y"));
2✔
3175
         TEST_FFI_RC(1, botan_mp_equal, (cmp, y));
2✔
3176

3177
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "p"));
2✔
3178
         TEST_FFI_RC(1, botan_mp_equal, (cmp, p));
2✔
3179
         botan_mp_destroy(cmp);
2✔
3180

3181
         botan_privkey_t loaded_privkey;
2✔
3182
         TEST_FFI_OK(botan_privkey_load_dsa, (&loaded_privkey, p, q, g, x));
2✔
3183
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
2✔
3184

3185
         botan_pubkey_t loaded_pubkey;
2✔
3186
         TEST_FFI_OK(botan_pubkey_load_dsa, (&loaded_pubkey, p, q, g, y));
2✔
3187
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
2✔
3188

3189
         botan_mp_destroy(p);
2✔
3190
         botan_mp_destroy(q);
2✔
3191
         botan_mp_destroy(g);
2✔
3192
         botan_mp_destroy(y);
2✔
3193
         botan_mp_destroy(x);
2✔
3194

3195
         botan_pk_op_sign_t signer;
2✔
3196

3197
         std::vector<uint8_t> message(6, 6);
2✔
3198
         std::vector<uint8_t> signature;
2✔
3199

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

3204
            size_t sig_len;
2✔
3205
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
2✔
3206
            signature.resize(sig_len);
2✔
3207

3208
            size_t output_sig_len = sig_len;
2✔
3209
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &output_sig_len));
2✔
3210
            result.test_lte("Output length is upper bound", output_sig_len, sig_len);
2✔
3211
            signature.resize(output_sig_len);
2✔
3212

3213
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
4✔
3214
         }
3215

3216
         botan_pk_op_verify_t verifier = nullptr;
2✔
3217

3218
         if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-256", 0))) {
4✔
3219
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3220
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
3221

3222
            // TODO: randomize this
3223
            signature[0] ^= 1;
2✔
3224
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3225
            TEST_FFI_RC(
2✔
3226
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3227

3228
            message[0] ^= 1;
2✔
3229
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3230
            TEST_FFI_RC(
2✔
3231
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3232

3233
            signature[0] ^= 1;
2✔
3234
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3235
            TEST_FFI_RC(
2✔
3236
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3237

3238
            message[0] ^= 1;
2✔
3239
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3240
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
3241

3242
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
4✔
3243
         }
3244

3245
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
3246
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
2✔
3247
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
2✔
3248
         TEST_FFI_OK(botan_privkey_destroy, (priv));
4✔
3249
      }
4✔
3250
};
3251

3252
class FFI_ECDSA_Test final : public FFI_Test {
×
3253
   public:
3254
      std::string name() const override { return "FFI ECDSA"; }
1✔
3255

3256
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3257
         static const char* kCurve = "secp384r1";
1✔
3258
         botan_privkey_t priv;
1✔
3259
         botan_pubkey_t pub;
1✔
3260

3261
         if(!TEST_FFI_INIT(botan_privkey_create_ecdsa, (&priv, rng, kCurve))) {
1✔
3262
            return;
×
3263
         }
3264

3265
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3266
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
3267

3268
         // Check key load functions
3269
         botan_mp_t private_scalar;
1✔
3270
         botan_mp_t public_x;
1✔
3271
         botan_mp_t public_y;
1✔
3272
         botan_mp_init(&private_scalar);
1✔
3273
         botan_mp_init(&public_x);
1✔
3274
         botan_mp_init(&public_y);
1✔
3275

3276
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (private_scalar, priv, "quux"));
1✔
3277
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_pubkey_get_field, (private_scalar, pub, "quux"));
1✔
3278

3279
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
3280
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
3281
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
3282

3283
         botan_privkey_t loaded_privkey;
1✔
3284
         botan_pubkey_t loaded_pubkey;
1✔
3285
         TEST_FFI_OK(botan_privkey_load_ecdsa, (&loaded_privkey, private_scalar, kCurve));
1✔
3286
         TEST_FFI_OK(botan_pubkey_load_ecdsa, (&loaded_pubkey, public_x, public_y, kCurve));
1✔
3287
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3288
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
3289

3290
         std::array<char, 32> namebuf{};
1✔
3291
         size_t name_len = namebuf.size();
1✔
3292

3293
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf.data(), &name_len));
1✔
3294
         result.test_eq("Algo name is expected", namebuf.data(), "ECDSA");
1✔
3295

3296
         std::vector<uint8_t> message(1280);
1✔
3297
         std::vector<uint8_t> signature;
1✔
3298
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
3299

3300
         for(uint32_t flags = 0; flags <= 1; ++flags) {
3✔
3301
            botan_pk_op_sign_t signer;
2✔
3302
            if(TEST_FFI_INIT(botan_pk_op_sign_create, (&signer, loaded_privkey, "SHA-384", flags))) {
2✔
3303
               // TODO: break input into multiple calls to update
3304
               TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
2✔
3305

3306
               size_t sig_len;
2✔
3307
               TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
2✔
3308

3309
               signature.resize(sig_len);
2✔
3310

3311
               size_t output_sig_len = signature.size();
2✔
3312
               TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &output_sig_len));
2✔
3313
               signature.resize(output_sig_len);
2✔
3314

3315
               TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
4✔
3316
            }
3317

3318
            botan_pk_op_verify_t verifier = nullptr;
2✔
3319

3320
            if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-384", flags))) {
4✔
3321
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3322
               TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
3323

3324
               // TODO: randomize this
3325
               signature[0] ^= 1;
2✔
3326
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3327
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
3328
                           botan_pk_op_verify_finish,
3329
                           (verifier, signature.data(), signature.size()));
3330

3331
               message[0] ^= 1;
2✔
3332
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3333
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
3334
                           botan_pk_op_verify_finish,
3335
                           (verifier, signature.data(), signature.size()));
3336

3337
               signature[0] ^= 1;
2✔
3338
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3339
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
3340
                           botan_pk_op_verify_finish,
3341
                           (verifier, signature.data(), signature.size()));
3342

3343
               message[0] ^= 1;
2✔
3344
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
3345
               TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
3346

3347
               TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
4✔
3348
            }
3349
         }
3350

3351
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
3352
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
3353
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
3354
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3355
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
3356
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
3357
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
3358
      }
2✔
3359
};
3360

3361
class FFI_SM2_Sig_Test final : public FFI_Test {
×
3362
   public:
3363
      std::string name() const override { return "FFI SM2 Sig"; }
1✔
3364

3365
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3366
         static const char* kCurve = "sm2p256v1";
1✔
3367
         const std::string sm2_ident = "SM2 Ident Field";
1✔
3368
         botan_privkey_t priv;
1✔
3369
         botan_pubkey_t pub;
1✔
3370
         botan_privkey_t loaded_privkey;
1✔
3371
         botan_pubkey_t loaded_pubkey;
1✔
3372

3373
         if(!TEST_FFI_INIT(botan_privkey_create, (&priv, "SM2_Sig", kCurve, rng))) {
1✔
3374
            return;
3375
         }
3376

3377
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3378
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
3379

3380
         uint8_t za[32];
1✔
3381
         size_t sizeof_za = sizeof(za);
1✔
3382
         TEST_FFI_OK(botan_pubkey_sm2_compute_za, (za, &sizeof_za, "Ident", "SM3", pub));
1✔
3383

3384
         // Check key load functions
3385
         botan_mp_t private_scalar;
1✔
3386
         botan_mp_t public_x;
1✔
3387
         botan_mp_t public_y;
1✔
3388
         botan_mp_init(&private_scalar);
1✔
3389
         botan_mp_init(&public_x);
1✔
3390
         botan_mp_init(&public_y);
1✔
3391

3392
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
3393
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
3394
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
3395
         REQUIRE_FFI_OK(botan_privkey_load_sm2, (&loaded_privkey, private_scalar, kCurve));
1✔
3396
         REQUIRE_FFI_OK(botan_pubkey_load_sm2, (&loaded_pubkey, public_x, public_y, kCurve));
1✔
3397
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3398
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
3399

3400
         std::array<char, 32> namebuf{};
1✔
3401
         size_t name_len = namebuf.size();
1✔
3402

3403
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf.data(), &name_len));
1✔
3404
         result.test_eq("Algo name is expected", namebuf.data(), "SM2");
1✔
3405

3406
         std::vector<uint8_t> message(1280);
1✔
3407
         std::vector<uint8_t> signature;
1✔
3408
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
3409
         botan_pk_op_sign_t signer;
1✔
3410
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, loaded_privkey, sm2_ident.c_str(), 0))) {
1✔
3411
            // TODO: break input into multiple calls to update
3412
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
1✔
3413

3414
            size_t sig_len;
1✔
3415
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
1✔
3416

3417
            signature.resize(sig_len);
1✔
3418

3419
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_len));
1✔
3420
            signature.resize(sig_len);
1✔
3421

3422
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
2✔
3423
         }
3424

3425
         botan_pk_op_verify_t verifier = nullptr;
1✔
3426

3427
         if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, sm2_ident.c_str(), 0))) {
2✔
3428
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3429
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
3430

3431
            // TODO: randomize this
3432
            signature[0] ^= 1;
1✔
3433
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3434
            TEST_FFI_RC(
1✔
3435
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3436

3437
            message[0] ^= 1;
1✔
3438
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3439
            TEST_FFI_RC(
1✔
3440
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3441

3442
            signature[0] ^= 1;
1✔
3443
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3444
            TEST_FFI_RC(
1✔
3445
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
3446

3447
            message[0] ^= 1;
1✔
3448
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3449
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
3450

3451
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
2✔
3452
         }
3453

3454
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
3455
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
3456
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
3457
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3458
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
3459
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
3460
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
3461
      }
2✔
3462
};
3463

3464
class FFI_SM2_Enc_Test final : public FFI_Test {
×
3465
   public:
3466
      std::string name() const override { return "FFI SM2 Enc"; }
1✔
3467

3468
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3469
         static const char* kCurve = "sm2p256v1";
1✔
3470
         botan_privkey_t priv;
1✔
3471
         botan_pubkey_t pub;
1✔
3472
         botan_privkey_t loaded_privkey;
1✔
3473
         botan_pubkey_t loaded_pubkey;
1✔
3474

3475
         if(!TEST_FFI_INIT(botan_privkey_create, (&priv, "SM2_Enc", kCurve, rng))) {
1✔
3476
            return;
×
3477
         }
3478

3479
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3480
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
3481

3482
         uint8_t za[32];
1✔
3483
         size_t sizeof_za = sizeof(za);
1✔
3484
         TEST_FFI_OK(botan_pubkey_sm2_compute_za, (za, &sizeof_za, "Ident", "SM3", pub));
1✔
3485

3486
         // Check key load functions
3487
         botan_mp_t private_scalar;
1✔
3488
         botan_mp_t public_x;
1✔
3489
         botan_mp_t public_y;
1✔
3490
         botan_mp_init(&private_scalar);
1✔
3491
         botan_mp_init(&public_x);
1✔
3492
         botan_mp_init(&public_y);
1✔
3493

3494
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
3495
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
3496
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
3497
         REQUIRE_FFI_OK(botan_privkey_load_sm2_enc, (&loaded_privkey, private_scalar, kCurve));
1✔
3498
         REQUIRE_FFI_OK(botan_pubkey_load_sm2_enc, (&loaded_pubkey, public_x, public_y, kCurve));
1✔
3499
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
3500
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
3501

3502
         std::array<char, 32> namebuf{};
1✔
3503
         size_t name_len = namebuf.size();
1✔
3504

3505
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf.data(), &name_len));
1✔
3506
         result.test_eq("Algo name is expected", namebuf.data(), "SM2");
1✔
3507

3508
         std::vector<uint8_t> message(32);
1✔
3509

3510
         std::vector<uint8_t> ciphertext;
1✔
3511
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
3512

3513
         botan_pk_op_encrypt_t enc;
1✔
3514
         if(TEST_FFI_OK(botan_pk_op_encrypt_create, (&enc, loaded_pubkey, "", 0))) {
1✔
3515
            size_t ctext_len;
1✔
3516
            TEST_FFI_OK(botan_pk_op_encrypt_output_length, (enc, message.size(), &ctext_len));
1✔
3517

3518
            ciphertext.resize(ctext_len);
1✔
3519
            TEST_FFI_OK(botan_pk_op_encrypt, (enc, rng, ciphertext.data(), &ctext_len, message.data(), message.size()));
1✔
3520
            ciphertext.resize(ctext_len);
1✔
3521

3522
            botan_pk_op_decrypt_t dec;
1✔
3523
            TEST_FFI_OK(botan_pk_op_decrypt_create, (&dec, loaded_privkey, "", 0));
1✔
3524

3525
            std::vector<uint8_t> recovered(message.size());
1✔
3526
            size_t recovered_len = recovered.size();
1✔
3527

3528
            TEST_FFI_OK(botan_pk_op_decrypt,
1✔
3529
                        (dec, recovered.data(), &recovered_len, ciphertext.data(), ciphertext.size()));
3530

3531
            botan_pk_op_decrypt_destroy(dec);
1✔
3532
         }
1✔
3533
         botan_pk_op_encrypt_destroy(enc);
1✔
3534

3535
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
3536
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
3537
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
3538
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3539
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
3540
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
3541
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
3542
      }
2✔
3543
};
3544

3545
class FFI_ECDH_Test final : public FFI_Test {
×
3546
   public:
3547
      std::string name() const override { return "FFI ECDH"; }
1✔
3548

3549
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3550
         botan_privkey_t priv1;
1✔
3551
         if(!TEST_FFI_INIT(botan_privkey_create_ecdh, (&priv1, rng, "secp256r1"))) {
1✔
3552
            return;
×
3553
         }
3554

3555
         botan_privkey_t priv2;
1✔
3556
         REQUIRE_FFI_OK(botan_privkey_create_ecdh, (&priv2, rng, "secp256r1"));
1✔
3557

3558
         botan_pubkey_t pub1;
1✔
3559
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub1, priv1));
1✔
3560

3561
         botan_pubkey_t pub2;
1✔
3562
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub2, priv2));
1✔
3563

3564
         /* Reload key-pair1 in order to test functions for key loading */
3565
         botan_mp_t private_scalar;
1✔
3566
         botan_mp_t public_x;
1✔
3567
         botan_mp_t public_y;
1✔
3568
         botan_mp_init(&private_scalar);
1✔
3569
         botan_mp_init(&public_x);
1✔
3570
         botan_mp_init(&public_y);
1✔
3571

3572
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv1, "x"));
1✔
3573
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub1, "public_x"));
1✔
3574
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub1, "public_y"));
1✔
3575

3576
         botan_privkey_t loaded_privkey1;
1✔
3577
         botan_pubkey_t loaded_pubkey1;
1✔
3578
         REQUIRE_FFI_OK(botan_privkey_load_ecdh, (&loaded_privkey1, private_scalar, "secp256r1"));
1✔
3579
         REQUIRE_FFI_OK(botan_pubkey_load_ecdh, (&loaded_pubkey1, public_x, public_y, "secp256r1"));
1✔
3580
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey1, rng, 0));
1✔
3581
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
3582

3583
         ffi_test_pubkey_export(result, loaded_pubkey1, priv1, rng);
1✔
3584
         ffi_test_pubkey_export(result, pub2, priv2, rng);
1✔
3585

3586
   #if defined(BOTAN_HAS_KDF2) && defined(BOTAN_HAS_SHA_256)
3587
         constexpr bool has_kdf2_sha256 = true;
1✔
3588
   #else
3589
         constexpr bool has_kdf2_sha256 = false;
3590
   #endif
3591

3592
         const char* kdf = has_kdf2_sha256 ? "KDF2(SHA-256)" : "Raw";
1✔
3593
         constexpr size_t salt_len = has_kdf2_sha256 ? 32 : 0;
1✔
3594

3595
         botan_pk_op_ka_t ka1;
1✔
3596
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka1, loaded_privkey1, kdf, 0));
1✔
3597
         botan_pk_op_ka_t ka2;
1✔
3598
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka2, priv2, kdf, 0));
1✔
3599

3600
         size_t pubkey1_len = 0;
1✔
3601
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
3602
                     botan_pk_op_key_agreement_export_public,
3603
                     (priv1, nullptr, &pubkey1_len));
3604
         std::vector<uint8_t> pubkey1(pubkey1_len);
1✔
3605
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv1, pubkey1.data(), &pubkey1_len));
1✔
3606
         size_t pubkey2_len = 0;
1✔
3607
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
3608
                     botan_pk_op_key_agreement_export_public,
3609
                     (priv2, nullptr, &pubkey2_len));
3610
         std::vector<uint8_t> pubkey2(pubkey2_len);
1✔
3611
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv2, pubkey2.data(), &pubkey2_len));
1✔
3612

3613
         std::vector<uint8_t> salt(salt_len);
1✔
3614
         TEST_FFI_OK(botan_rng_get, (rng, salt.data(), salt.size()));
1✔
3615

3616
         const size_t shared_key_len = 32;
1✔
3617

3618
         std::vector<uint8_t> key1(shared_key_len);
1✔
3619
         size_t key1_len = key1.size();
1✔
3620
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
3621
                     (ka1, key1.data(), &key1_len, pubkey2.data(), pubkey2.size(), salt.data(), salt.size()));
3622

3623
         std::vector<uint8_t> key2(shared_key_len);
1✔
3624
         size_t key2_len = key2.size();
1✔
3625
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
3626
                     (ka2, key2.data(), &key2_len, pubkey1.data(), pubkey1.size(), salt.data(), salt.size()));
3627

3628
         result.test_eq("shared ECDH key", key1, key2);
2✔
3629

3630
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
3631
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
3632
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
3633
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka1));
1✔
3634
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka2));
1✔
3635
         TEST_FFI_OK(botan_privkey_destroy, (priv1));
1✔
3636
         TEST_FFI_OK(botan_privkey_destroy, (priv2));
1✔
3637
         TEST_FFI_OK(botan_pubkey_destroy, (pub1));
1✔
3638
         TEST_FFI_OK(botan_pubkey_destroy, (pub2));
1✔
3639
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey1));
1✔
3640
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
2✔
3641
      }
5✔
3642
};
3643

3644
class FFI_McEliece_Test final : public FFI_Test {
×
3645
   public:
3646
      std::string name() const override { return "FFI McEliece"; }
1✔
3647

3648
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3649
         botan_privkey_t priv;
1✔
3650
         if(TEST_FFI_INIT(botan_privkey_create_mceliece, (&priv, rng, 2048, 50))) {
1✔
3651
            botan_pubkey_t pub;
1✔
3652
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3653

3654
            ffi_test_pubkey_export(result, pub, priv, rng);
1✔
3655

3656
            std::array<char, 32> namebuf{};
1✔
3657
            size_t name_len = namebuf.size();
1✔
3658
            if(TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf.data(), &name_len))) {
1✔
3659
               result.test_eq("algo name", namebuf.data(), "McEliece");
2✔
3660
            }
3661

3662
            // TODO test KEM
3663

3664
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3665
            TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
3666
         }
3667
      }
1✔
3668
};
3669

3670
class FFI_Ed25519_Test final : public FFI_Test {
×
3671
   public:
3672
      std::string name() const override { return "FFI Ed25519"; }
1✔
3673

3674
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3675
         botan_pubkey_t pub;
1✔
3676
         botan_privkey_t priv;
1✔
3677

3678
         // From draft-koch-eddsa-for-openpgp-04
3679
         const std::vector<uint8_t> seed =
1✔
3680
            Botan::hex_decode("1a8b1ff05ded48e18bf50166c664ab023ea70003d78d9e41f5758a91d850f8d2");
1✔
3681
         const std::vector<uint8_t> pubkey =
1✔
3682
            Botan::hex_decode("3f098994bdd916ed4053197934e4a87c80733a1280d62f8010992e43ee3b2406");
1✔
3683
         const std::vector<uint8_t> message = Botan::hex_decode("4f70656e504750040016080006050255f95f9504ff0000000c");
1✔
3684
         const std::vector<uint8_t> exp_sig = Botan::hex_decode(
1✔
3685
            "56f90cca98e2102637bd983fdb16c131dfd27ed82bf4dde5606e0d756aed3366"
3686
            "d09c4fa11527f038e0f57f2201d82f2ea2c9033265fa6ceb489e854bae61b404");
1✔
3687

3688
         if(!TEST_FFI_INIT(botan_privkey_load_ed25519, (&priv, seed.data()))) {
1✔
3689
            return;
×
3690
         }
3691

3692
         uint8_t retr_privkey[64];
1✔
3693
         TEST_FFI_OK(botan_privkey_ed25519_get_privkey, (priv, retr_privkey));
1✔
3694

3695
         result.test_eq(nullptr, "Public key matches", retr_privkey + 32, 32, pubkey.data(), pubkey.size());
1✔
3696

3697
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3698

3699
         uint8_t retr_pubkey[32];
1✔
3700
         TEST_FFI_OK(botan_pubkey_ed25519_get_pubkey, (pub, retr_pubkey));
1✔
3701
         result.test_eq(nullptr, "Public key matches", retr_pubkey, 32, pubkey.data(), pubkey.size());
1✔
3702

3703
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3704
         TEST_FFI_OK(botan_pubkey_load_ed25519, (&pub, pubkey.data()));
1✔
3705

3706
         botan_pk_op_sign_t signer;
1✔
3707
         std::vector<uint8_t> signature;
1✔
3708

3709
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv, "SHA-256", 0))) {
1✔
3710
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
1✔
3711

3712
            size_t sig_len;
1✔
3713
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
1✔
3714

3715
            signature.resize(sig_len);
1✔
3716

3717
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_len));
1✔
3718
            signature.resize(sig_len);
1✔
3719

3720
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
2✔
3721
         }
3722

3723
         result.test_eq("Expected signature", signature, exp_sig);
2✔
3724

3725
         botan_pk_op_verify_t verifier;
1✔
3726

3727
         if(TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-256", 0))) {
1✔
3728
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
3729
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
3730

3731
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
2✔
3732
         }
3733

3734
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3735
         TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
3736
      }
5✔
3737
};
3738

3739
class FFI_Ed448_Test final : public FFI_Test {
×
3740
   public:
3741
      std::string name() const override { return "FFI Ed448"; }
1✔
3742

3743
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
3744
         botan_pubkey_t pub;
1✔
3745
         botan_privkey_t priv;
1✔
3746

3747
         // RFC 8032: Testvector Ed448, 1 octet
3748
         const auto sk = Botan::hex_decode(
1✔
3749
            "c4eab05d357007c632f3dbb48489924d552b08fe0c353a0d4a1f00acda2c463afbea67c5e8d2877c5e3bc397a659949ef8021e954e0a12274e");
1✔
3750
         const auto pk_ref = Botan::hex_decode(
1✔
3751
            "43ba28f430cdff456ae531545f7ecd0ac834a55d9358c0372bfa0c6c6798c0866aea01eb00742802b8438ea4cb82169c235160627b4c3a9480");
1✔
3752
         const auto msg = Botan::hex_decode("03");
1✔
3753
         const auto sig_ref = Botan::hex_decode(
1✔
3754
            "26b8f91727bd62897af15e41eb43c377efb9c610d48f2335cb0bd0087810f4352541b143c4b981b7e18f62de8ccdf633fc1bf037ab7cd779805e0dbcc0aae1cbcee1afb2e027df36bc04dcecbf154336c19f0af7e0a6472905e799f1953d2a0ff3348ab21aa4adafd1d234441cf807c03a00");
1✔
3755

3756
         if(!TEST_FFI_INIT(botan_privkey_load_ed448, (&priv, sk.data()))) {
1✔
3757
            return;
×
3758
         }
3759

3760
         std::vector<uint8_t> retr_privkey(57);
1✔
3761
         TEST_FFI_OK(botan_privkey_ed448_get_privkey, (priv, retr_privkey.data()));
1✔
3762
         result.test_is_eq("Private key matches", retr_privkey, sk);
1✔
3763

3764
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
3765

3766
         std::vector<uint8_t> retr_pubkey(57);
1✔
3767
         TEST_FFI_OK(botan_pubkey_ed448_get_pubkey, (pub, retr_pubkey.data()));
1✔
3768
         result.test_is_eq("Public key matches", retr_pubkey, pk_ref);
1✔
3769

3770
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3771
         TEST_FFI_OK(botan_pubkey_load_ed448, (&pub, pk_ref.data()));
1✔
3772

3773
         botan_pk_op_sign_t signer;
1✔
3774
         std::vector<uint8_t> signature;
1✔
3775

3776
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv, "Pure", 0))) {
1✔
3777
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, msg.data(), msg.size()));
1✔
3778

3779
            size_t sig_len;
1✔
3780
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
1✔
3781

3782
            signature.resize(sig_len);
1✔
3783

3784
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_len));
1✔
3785
            signature.resize(sig_len);
1✔
3786

3787
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
2✔
3788
         }
3789

3790
         result.test_eq("Expected signature", signature, sig_ref);
2✔
3791

3792
         botan_pk_op_verify_t verifier;
1✔
3793

3794
         if(TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "Pure", 0))) {
1✔
3795
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, msg.data(), msg.size()));
1✔
3796
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
3797

3798
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
2✔
3799
         }
3800

3801
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
3802
         TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
3803
      }
7✔
3804
};
3805

3806
class FFI_X25519_Test final : public FFI_Test {
×
3807
   public:
3808
      std::string name() const override { return "FFI X25519"; }
1✔
3809

3810
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
3811
         // From RFC 8037
3812

3813
         const std::vector<uint8_t> a_pub_bits =
1✔
3814
            Botan::hex_decode("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f");
1✔
3815
         const std::vector<uint8_t> b_priv_bits =
1✔
3816
            Botan::hex_decode("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a");
1✔
3817
         const std::vector<uint8_t> b_pub_bits =
1✔
3818
            Botan::hex_decode("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a");
1✔
3819
         const std::vector<uint8_t> shared_secret_bits =
1✔
3820
            Botan::hex_decode("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
1✔
3821

3822
         botan_privkey_t b_priv;
1✔
3823
         if(!TEST_FFI_INIT(botan_privkey_load_x25519, (&b_priv, b_priv_bits.data()))) {
1✔
3824
            return;
3825
         }
3826

3827
         std::vector<uint8_t> privkey_read(32);
1✔
3828
         TEST_FFI_OK(botan_privkey_x25519_get_privkey, (b_priv, privkey_read.data()));
1✔
3829
         result.test_eq("X25519 private key", privkey_read, b_priv_bits);
2✔
3830

3831
         std::vector<uint8_t> pubkey_read(32);
1✔
3832

3833
         botan_pubkey_t b_pub;
1✔
3834
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
3835
         TEST_FFI_OK(botan_pubkey_x25519_get_pubkey, (b_pub, pubkey_read.data()));
1✔
3836
         result.test_eq("X25519 public key b", pubkey_read, b_pub_bits);
2✔
3837

3838
         botan_pubkey_t a_pub;
1✔
3839
         TEST_FFI_OK(botan_pubkey_load_x25519, (&a_pub, a_pub_bits.data()));
1✔
3840
         TEST_FFI_OK(botan_pubkey_x25519_get_pubkey, (a_pub, pubkey_read.data()));
1✔
3841
         result.test_eq("X25519 public key a", pubkey_read, a_pub_bits);
2✔
3842

3843
         botan_pk_op_ka_t ka;
1✔
3844
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka, b_priv, "Raw", 0));
1✔
3845

3846
         std::vector<uint8_t> shared_output(32);
1✔
3847
         size_t shared_len = shared_output.size();
1✔
3848
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
3849
                     (ka, shared_output.data(), &shared_len, a_pub_bits.data(), a_pub_bits.size(), nullptr, 0));
3850

3851
         result.test_eq("Shared secret matches expected", shared_secret_bits, shared_output);
2✔
3852

3853
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
3854
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
3855
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
1✔
3856
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka));
2✔
3857
      }
7✔
3858
};
3859

3860
class FFI_X448_Test final : public FFI_Test {
×
3861
   public:
3862
      std::string name() const override { return "FFI X448"; }
1✔
3863

3864
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
3865
         // From RFC 7748 Section 6.2
3866
         const auto a_pub_ref = Botan::hex_decode(
1✔
3867
            "9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0");
1✔
3868
         const auto b_priv_ref = Botan::hex_decode(
1✔
3869
            "1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d");
1✔
3870
         const auto b_pub_ref = Botan::hex_decode(
1✔
3871
            "3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609");
1✔
3872
         const auto shared_secret_ref = Botan::hex_decode(
1✔
3873
            "07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d");
1✔
3874

3875
         botan_privkey_t b_priv;
1✔
3876
         if(!TEST_FFI_INIT(botan_privkey_load_x448, (&b_priv, b_priv_ref.data()))) {
1✔
3877
            return;
3878
         }
3879

3880
         std::vector<uint8_t> privkey_read(56);
1✔
3881
         TEST_FFI_OK(botan_privkey_x448_get_privkey, (b_priv, privkey_read.data()));
1✔
3882
         result.test_eq("X448 private key", privkey_read, b_priv_ref);
2✔
3883

3884
         std::vector<uint8_t> pubkey_read(56);
1✔
3885

3886
         botan_pubkey_t b_pub;
1✔
3887
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
3888
         TEST_FFI_OK(botan_pubkey_x448_get_pubkey, (b_pub, pubkey_read.data()));
1✔
3889
         result.test_eq("X448 public key b", pubkey_read, b_pub_ref);
2✔
3890

3891
         botan_pubkey_t a_pub;
1✔
3892
         TEST_FFI_OK(botan_pubkey_load_x448, (&a_pub, a_pub_ref.data()));
1✔
3893
         TEST_FFI_OK(botan_pubkey_x448_get_pubkey, (a_pub, pubkey_read.data()));
1✔
3894
         result.test_eq("X448 public key a", pubkey_read, a_pub_ref);
2✔
3895

3896
         botan_pk_op_ka_t ka;
1✔
3897
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka, b_priv, "Raw", 0));
1✔
3898

3899
         std::vector<uint8_t> shared_output(56);
1✔
3900
         size_t shared_len = shared_output.size();
1✔
3901
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
3902
                     (ka, shared_output.data(), &shared_len, a_pub_ref.data(), a_pub_ref.size(), nullptr, 0));
3903

3904
         result.test_eq("Shared secret matches expected", shared_secret_ref, shared_output);
2✔
3905

3906
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
3907
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
3908
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
1✔
3909
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka));
2✔
3910
      }
7✔
3911
};
3912

3913
/**
3914
 * Base class for roundtrip tests of FFI bindings for Key Encapsulation Mechanisms.
3915
 */
3916
class FFI_KEM_Roundtrip_Test : public FFI_Test {
3✔
3917
   protected:
3918
      using privkey_loader_fn_t = int (*)(botan_privkey_t*, const uint8_t[], size_t, const char*);
3919
      using pubkey_loader_fn_t = int (*)(botan_pubkey_t*, const uint8_t[], size_t, const char*);
3920

3921
   protected:
3922
      virtual const char* algo() const = 0;
3923
      virtual privkey_loader_fn_t private_key_load_function() const = 0;
3924
      virtual pubkey_loader_fn_t public_key_load_function() const = 0;
3925
      virtual std::vector<const char*> modes() const = 0;
3926

3927
   public:
3928
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
3✔
3929
         for(const auto* mode : modes()) {
34✔
3930
            // generate a key pair
3931
            botan_privkey_t priv;
31✔
3932
            botan_pubkey_t pub;
31✔
3933
            if(!TEST_FFI_INIT(botan_privkey_create, (&priv, algo(), mode, rng))) {
31✔
3934
               continue;
×
3935
            }
3936
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
31✔
3937

3938
            // raw-encode the key pair
3939
            ViewBytesSink priv_bytes;
31✔
3940
            ViewBytesSink pub_bytes;
31✔
3941
            TEST_FFI_OK(botan_privkey_view_raw, (priv, priv_bytes.delegate(), priv_bytes.callback()));
31✔
3942
            TEST_FFI_OK(botan_pubkey_view_raw, (pub, pub_bytes.delegate(), pub_bytes.callback()));
31✔
3943

3944
            // decode the key pair from raw encoding
3945
            botan_privkey_t priv_loaded;
31✔
3946
            botan_pubkey_t pub_loaded;
31✔
3947
            TEST_FFI_OK(private_key_load_function(),
31✔
3948
                        (&priv_loaded, priv_bytes.get().data(), priv_bytes.get().size(), mode));
3949
            TEST_FFI_OK(public_key_load_function(),
31✔
3950
                        (&pub_loaded, pub_bytes.get().data(), pub_bytes.get().size(), mode));
3951

3952
            // re-encode and compare to the first round
3953
            ViewBytesSink priv_bytes2;
31✔
3954
            ViewBytesSink pub_bytes2;
31✔
3955
            TEST_FFI_OK(botan_privkey_view_raw, (priv_loaded, priv_bytes2.delegate(), priv_bytes2.callback()));
31✔
3956
            TEST_FFI_OK(botan_pubkey_view_raw, (pub_loaded, pub_bytes2.delegate(), pub_bytes2.callback()));
31✔
3957
            result.test_eq("private key encoding", priv_bytes.get(), priv_bytes2.get());
62✔
3958
            result.test_eq("public key encoding", pub_bytes.get(), pub_bytes2.get());
62✔
3959

3960
            // KEM encryption (using the loaded public key)
3961
            botan_pk_op_kem_encrypt_t kem_enc;
31✔
3962
            TEST_FFI_OK(botan_pk_op_kem_encrypt_create, (&kem_enc, pub_loaded, "Raw"));
31✔
3963

3964
            // explicitly query output lengths
3965
            size_t shared_key_length = 0;
31✔
3966
            size_t ciphertext_length = 0;
31✔
3967
            TEST_FFI_OK(botan_pk_op_kem_encrypt_shared_key_length, (kem_enc, 0, &shared_key_length));
31✔
3968
            TEST_FFI_OK(botan_pk_op_kem_encrypt_encapsulated_key_length, (kem_enc, &ciphertext_length));
31✔
3969

3970
            // check that insufficient buffer space is handled correctly
3971
            size_t shared_key_length_out = 0;
31✔
3972
            size_t ciphertext_length_out = 0;
31✔
3973
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
31✔
3974
                        botan_pk_op_kem_encrypt_create_shared_key,
3975
                        (kem_enc,
3976
                         rng,
3977
                         nullptr /* no salt */,
3978
                         0,
3979
                         0 /* default key length */,
3980
                         nullptr,
3981
                         &shared_key_length_out,
3982
                         nullptr,
3983
                         &ciphertext_length_out));
3984

3985
            // TODO: should this report both lengths for usage convenience?
3986
            result.confirm("at least one buffer length is reported",
62✔
3987
                           shared_key_length_out == shared_key_length || ciphertext_length_out == ciphertext_length);
31✔
3988

3989
            // allocate buffers (with additional space) and perform the actual encryption
3990
            shared_key_length_out = shared_key_length * 2;
31✔
3991
            ciphertext_length_out = ciphertext_length * 2;
31✔
3992
            Botan::secure_vector<uint8_t> shared_key(shared_key_length_out);
31✔
3993
            std::vector<uint8_t> ciphertext(ciphertext_length_out);
31✔
3994
            TEST_FFI_OK(botan_pk_op_kem_encrypt_create_shared_key,
31✔
3995
                        (kem_enc,
3996
                         rng,
3997
                         nullptr /* no salt */,
3998
                         0,
3999
                         0 /* default key length */,
4000
                         shared_key.data(),
4001
                         &shared_key_length_out,
4002
                         ciphertext.data(),
4003
                         &ciphertext_length_out));
4004
            result.test_eq("shared key length", shared_key_length, shared_key_length_out);
31✔
4005
            result.test_eq("ciphertext length", ciphertext_length, ciphertext_length_out);
31✔
4006
            shared_key.resize(shared_key_length_out);
31✔
4007
            ciphertext.resize(ciphertext_length_out);
31✔
4008
            TEST_FFI_OK(botan_pk_op_kem_encrypt_destroy, (kem_enc));
31✔
4009

4010
            // KEM decryption (using the generated private key)
4011
            botan_pk_op_kem_decrypt_t kem_dec;
31✔
4012
            TEST_FFI_OK(botan_pk_op_kem_decrypt_create, (&kem_dec, priv, "Raw"));
31✔
4013
            size_t shared_key_length2 = 0;
31✔
4014
            TEST_FFI_OK(botan_pk_op_kem_decrypt_shared_key_length, (kem_dec, shared_key_length, &shared_key_length2));
31✔
4015
            result.test_eq("shared key lengths are consistent", shared_key_length, shared_key_length2);
31✔
4016

4017
            // check that insufficient buffer space is handled correctly
4018
            shared_key_length_out = 0;
31✔
4019
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
31✔
4020
                        botan_pk_op_kem_decrypt_shared_key,
4021
                        (kem_dec,
4022
                         nullptr /* no salt */,
4023
                         0,
4024
                         ciphertext.data(),
4025
                         ciphertext.size(),
4026
                         0 /* default length */,
4027
                         nullptr,
4028
                         &shared_key_length_out));
4029
            result.test_eq("reported buffer length requirement", shared_key_length, shared_key_length_out);
31✔
4030

4031
            // allocate buffer (double the size) and perform the actual decryption
4032
            shared_key_length_out = shared_key_length * 2;
31✔
4033
            Botan::secure_vector<uint8_t> shared_key2(shared_key_length_out);
31✔
4034
            TEST_FFI_OK(botan_pk_op_kem_decrypt_shared_key,
31✔
4035
                        (kem_dec,
4036
                         nullptr /* no salt */,
4037
                         0,
4038
                         ciphertext.data(),
4039
                         ciphertext.size(),
4040
                         0 /* default length */,
4041
                         shared_key2.data(),
4042
                         &shared_key_length_out));
4043
            result.test_eq("shared key output length", shared_key_length, shared_key_length_out);
31✔
4044
            shared_key2.resize(shared_key_length_out);
31✔
4045
            TEST_FFI_OK(botan_pk_op_kem_decrypt_destroy, (kem_dec));
31✔
4046

4047
            // final check and clean up
4048
            result.test_eq("shared keys match", shared_key, shared_key2);
62✔
4049

4050
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
31✔
4051
            TEST_FFI_OK(botan_pubkey_destroy, (pub_loaded));
31✔
4052
            TEST_FFI_OK(botan_privkey_destroy, (priv));
31✔
4053
            TEST_FFI_OK(botan_privkey_destroy, (priv_loaded));
62✔
4054
         }
217✔
4055
      }
3✔
4056
};
4057

4058
/**
4059
 * Base class for roundtrip tests of FFI bindings for Signature Mechanisms.
4060
 */
4061
class FFI_Signature_Roundtrip_Test : public FFI_Test {
2✔
4062
   protected:
4063
      using privkey_loader_fn_t = int (*)(botan_privkey_t*, const uint8_t[], size_t, const char*);
4064
      using pubkey_loader_fn_t = int (*)(botan_pubkey_t*, const uint8_t[], size_t, const char*);
4065

4066
   protected:
4067
      virtual const char* algo() const = 0;
4068
      virtual privkey_loader_fn_t private_key_load_function() const = 0;
4069
      virtual pubkey_loader_fn_t public_key_load_function() const = 0;
4070
      virtual std::vector<const char*> modes() const = 0;
4071
      virtual const char* hash_algo_or_padding() const = 0;
4072

4073
   public:
4074
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
2✔
4075
         const std::vector<uint8_t> message1 = {'H', 'e', 'l', 'l', 'o', ' '};
2✔
4076
         const std::vector<uint8_t> message2 = {'W', 'o', 'r', 'l', 'd', '!'};
2✔
4077

4078
         for(const auto* mode : modes()) {
17✔
4079
            // generate a key pair
4080
            botan_privkey_t priv;
15✔
4081
            botan_pubkey_t pub;
15✔
4082
            if(!TEST_FFI_INIT(botan_privkey_create, (&priv, algo(), mode, rng))) {
15✔
4083
               continue;
×
4084
            }
4085
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
15✔
4086

4087
            // raw-encode the key pair
4088
            ViewBytesSink priv_bytes;
15✔
4089
            ViewBytesSink pub_bytes;
15✔
4090
            TEST_FFI_OK(botan_privkey_view_raw, (priv, priv_bytes.delegate(), priv_bytes.callback()));
15✔
4091
            TEST_FFI_OK(botan_pubkey_view_raw, (pub, pub_bytes.delegate(), pub_bytes.callback()));
15✔
4092

4093
            // decode the key pair from raw encoding
4094
            botan_privkey_t priv_loaded;
15✔
4095
            botan_pubkey_t pub_loaded;
15✔
4096
            TEST_FFI_OK(private_key_load_function(),
15✔
4097
                        (&priv_loaded, priv_bytes.get().data(), priv_bytes.get().size(), mode));
4098
            TEST_FFI_OK(public_key_load_function(),
15✔
4099
                        (&pub_loaded, pub_bytes.get().data(), pub_bytes.get().size(), mode));
4100

4101
            // re-encode and compare to the first round
4102
            ViewBytesSink priv_bytes2;
15✔
4103
            ViewBytesSink pub_bytes2;
15✔
4104
            TEST_FFI_OK(botan_privkey_view_raw, (priv_loaded, priv_bytes2.delegate(), priv_bytes2.callback()));
15✔
4105
            TEST_FFI_OK(botan_pubkey_view_raw, (pub_loaded, pub_bytes2.delegate(), pub_bytes2.callback()));
15✔
4106
            result.test_eq("private key encoding", priv_bytes.get(), priv_bytes2.get());
30✔
4107
            result.test_eq("public key encoding", pub_bytes.get(), pub_bytes2.get());
30✔
4108

4109
            // Signature Creation (using the loaded private key)
4110
            botan_pk_op_sign_t signer;
15✔
4111
            TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv_loaded, hash_algo_or_padding(), 0));
15✔
4112

4113
            // explicitly query the signature output length
4114
            size_t sig_output_length = 0;
15✔
4115
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_output_length));
15✔
4116

4117
            // pass a message to the signer
4118
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message1.data(), message1.size()));
15✔
4119
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message2.data(), message2.size()));
15✔
4120

4121
            // check that insufficient buffer space is handled correctly
4122
            size_t sig_output_length_out = 0;
15✔
4123
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
15✔
4124
                        botan_pk_op_sign_finish,
4125
                        (signer, rng, nullptr, &sig_output_length_out));
4126
            result.test_eq("reported sig lengths are equal", sig_output_length, sig_output_length_out);
15✔
4127

4128
            // Recreate signer and try again
4129
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
15✔
4130
            TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv_loaded, hash_algo_or_padding(), 0));
15✔
4131
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message1.data(), message1.size()));
15✔
4132
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message2.data(), message2.size()));
15✔
4133

4134
            // allocate buffers (with additional space) and perform the actual signing
4135
            sig_output_length_out = sig_output_length * 2;
15✔
4136
            Botan::secure_vector<uint8_t> signature(sig_output_length_out);
15✔
4137
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_output_length_out));
15✔
4138
            result.test_eq("signature length", sig_output_length, sig_output_length_out);
15✔
4139
            signature.resize(sig_output_length_out);
15✔
4140
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
15✔
4141

4142
            // Signature verification (using the generated public key)
4143
            botan_pk_op_verify_t verifier;
15✔
4144
            TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, hash_algo_or_padding(), 0));
15✔
4145
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message1.data(), message1.size()));
15✔
4146
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message2.data(), message2.size()));
15✔
4147

4148
            // Verify signature
4149
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
15✔
4150
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
15✔
4151

4152
            // Verify signature with wrong message (only first half)
4153
            TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, hash_algo_or_padding(), 0));
15✔
4154
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message1.data(), message1.size()));
15✔
4155
            TEST_FFI_RC(
15✔
4156
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
4157
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
15✔
4158

4159
            // Cleanup
4160
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
15✔
4161
            TEST_FFI_OK(botan_pubkey_destroy, (pub_loaded));
15✔
4162
            TEST_FFI_OK(botan_privkey_destroy, (priv));
15✔
4163
            TEST_FFI_OK(botan_privkey_destroy, (priv_loaded));
30✔
4164
         }
77✔
4165
      }
4✔
4166
};
4167

4168
class FFI_Kyber512_Test final : public FFI_Test {
×
4169
   public:
4170
      std::string name() const override { return "FFI Kyber512"; }
1✔
4171

4172
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
4173
         const std::vector<uint8_t> a_pub_bits = Botan::hex_decode(
1✔
4174
            "5fc44b99d7584f38cd28360cc5625a905b96af12930ed5b5fe2a82fc5aa7dc4b829fe37635f13f5af2a6d3081dad878785698a0aa914374c4e43b89f094a7892aa149a38b49c06a068d829a8d249e753a375d097a0f162e6c3a4dfe8c79761410c605ed3899a3fc44378e14f28879e8f148077e6bc3bb2ae56178c491611bf6aaf5f9a9cb9b5659223007940bcd6f8a23280a56015330e8577259587b12606f4c937ea13606cb3bb046066ad294261e2b22022bcc74678a5520570d88e4ceb42692631e7e3711c4b2fd5347f0328598340cb3c65c8f55ac02716831094cb6eb90f175b173d9c650329aaf513633633bb2ce6858e7447abc41b6fb06da8782572c332b09660366926bf529ed8caaa6243ccdb152b36ba6e47c714145c86f5b3b61de84ef1470d03fa0135e35194fa1fb3bc860fa500d1299aee88ce56054376c1199c553dd90a8d6f9cc763c811d0c66da6f851abf1056635a34a68aa7815868f153a3a5c77fcc8b1eb1807fbf62a6fb43b355700e78230943a2ba1e11b181345b11b4d46266e7b359f074a500c8857d79ba60f64262d662ccd9c8489a4c19df67437db193f95b9765181d9152262b1166f97be53497f001cb1be79024d6a2289bcc704e1b1d821015366a3cc8a484e6bc2e1f1b889f19323e3101aa09ad9ea62ba4005039bbfb5998055f93fbf77b14433116d5958422654dada1127213f02b78717a5a0454271d5b0c02517a6c27a3c3610101d753c09a25571775477dc13b2e404db4965b9a9350330c73a8a3642d39af8a23839ab85c6355b12f279f849813c280d54c5913e99b6946a0aaf012c8cab025396b255f002d837c761d42a4aeb38c5f456aaf79e162700c6b4048eca6f9a7367f90238d67bcf8e6a0d8a553c071522f9d2394e28483d2048be2a8f9c8c8e39991a41273c7eacaefc6a308be870b45b41176412954a1a0fd83d362a5ab288663dec5456b6286d0b2cecb01922fb3d473802ea2b86639bce02450339261cffb114e1e725e90677826a1688f686b29a78779c9822315dafc55753e98c8ed3221f2b3220805c8a28983355207da36fb72f9bc85c0a13b9d041586fd583feb12afd5a402dd33b43543f5fa4eb436c8d");
1✔
4175
         const std::vector<uint8_t> b_priv_bits = Botan::hex_decode(
1✔
4176
            "cf8c33fabbc3e6685f60779a456412e9060a792a3f67d90389815773e06dd2071e3906a1159921485b6221b73dfc723da9d45bbc99523c55b203f81856ba8d38f731c6594a0a9796f485c7cad02ee3a80a737cada2e40b580a1060a1364d365169539ce4d800eab9723153c5b266853b3a33112ccb03491e77f57aeb74c7670426c5bb02615b1907b353beda51f38a788774b1c9eb3c49f89df59ba00e196f180a37fd9acd6691b493d78f95a49906b26fa46125663a37b0b2614197473ba012956bc9348a9afc8907527bb7c2dcbd384b85630b3687096ffd9a93d603121706c06c05baca286bebea0ecdf391ba489d7ff6a7a1c7c3dd0c521c02bb3fa7c3e5b98f19509486ab33f1597346b03c7197865792896c1a553e8379c6f51729e9907d09b4fbc5b4279298f60195998225d95c2aef335c9e6a26f4988e0f19c307fc00f8aa0b21090daab0c540363f121044729322bebb97427227e8b01705826879ab4d42e30bf191068b705527a3ae9a5b3e30371c50b5b75d189903e60175f904c1488be7e872d3dc3be1bb31921027cb075f6bb051c28980c65b9959e8acf2d38671d27285d03419512008335492476e0c23ac6263425f8a65fbc1a38110b38db641f3a9872fa312d26b9c81f11de1d9378b629e9bdc7ca31496ac9511bff42a7a96b28f740a84c2904fe4056ca1989b28439222cee31c554e982d318366037070c4bb778b261e3479c605317922947e4340560732ca8fda63e2a7ac8cc67015e97d308c361e634f8cdb1e836b572367334c949011a9c52f391194baa91f08a71e847d3be202554ab1c4f871c9b26db5f4992db5b3688b1ea877925d02895d470b9659c51213b206b82de489455c6502856b841d000aab3c065ff6720f9222914b6421224d716684a7762fc98ba7f4655f4cfa82fc52472b01b1e22255fc990b20240b802034c99777b71b5c0d8a4c733b69d5f76ddfdb1128da3e194c1169a924f5d868d1dbc4ddcb30197c25005391c1fcc098010af1e9ab72bc8c3bd1c58b15583035bc2dd0898e148fb20b8c502a31489b00dd645ab24709bff5c37d1a7fee5c56d7490ae77a61b1c5951e359d2a89a946f200b1f647c0283de5d403282c693dfccca1c1b54804ab86f36e1f16550a77b75328916c770c225b142dfb750659ba6d532003f8b6d48825b122682051acda7c20f09117b3e5c93e8c1bd446672512947d964f0484a05b85af82f4401d323484d23373c0c6c8990a3fba70f8a2c13e7350ce945c8f4882b1929f10d18bb45a883c116d1ce06493a50580069743d26062da9171006405d27e2f7220a897024dca507b737a6c32ba3d925e15c9789589507a768ca075beb2fb17a17144c52810566a972dba60ad806a2ff15957a3bbd85a8f1ef34445d18cc668ca7a8ac5fc7545934221a4c92c60024069cc34d592ac30c88c3376bc133622e2b192e9b4b60a9a84e5304873e62d6f98103cc8c43f6024fb7739418cc2602b21416040220cb3ec588679c033d61a3c697c403463c17c13a63d7304044a9f024b907b440b39b7b6423723dda943447a900af0170144755d9a968f634e26f892ee19cd00a97b48d5041b4473ec8741e077126f85bbb8334b8b2cbd63429afa543a540740c1e56893f6b2f2f7c42a12bcd48c647726cca06841212656ff9b3d3e799e92c48414d653a61ca8dc2c49b7342469a868b7938db8d7844e6311134b2c30538ffa927ee3961a44e0a66438c5643aa1d13658fe8a7c2a84702a8211422831994ca1e801131ab88a25162d3cd988ebe09e6cb01ca7324256691635c536f576990664841b7c89b0dc325472271fdc2b0824a9514b5eb46a743f9734ee20648a407f5d505cc9614748f344a16950b5483e45516236d43afd1494d564c23e20b64a124593604404c879a776a5bd9399629600e86aa1a641be7a13418cda318bbc3af0c2a66c999841251a1c2868b05028f6a56a72c33d8a653c77f69af4247dc6f80d329921ce3355894605c35372ddf0c84cacb42d6ccbdf39a55b672a891749622a011747a01625764c788413f2c0fd877275c88fd5730fa9e87a3c783702223a4443525cc5b5381c976dd9cb08ac47490125ca5c70baac01ff9143bc40ceeb2a16c1529d70c07074a0013749656ff4b16d890868b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb3338e5d6352d5a5006d7cd901489e7f851711c08e00cd4162ccfc2564d5893d52b2c7300e2d894b0eaa40a6ab254506d8c1176a33c4a1b2879604b1b80df48d31dd");
1✔
4177
         const std::vector<uint8_t> b_pub_bits = Botan::hex_decode(
1✔
4178
            "ee5c56d7490ae77a61b1c5951e359d2a89a946f200b1f647c0283de5d403282c693dfccca1c1b54804ab86f36e1f16550a77b75328916c770c225b142dfb750659ba6d532003f8b6d48825b122682051acda7c20f09117b3e5c93e8c1bd446672512947d964f0484a05b85af82f4401d323484d23373c0c6c8990a3fba70f8a2c13e7350ce945c8f4882b1929f10d18bb45a883c116d1ce06493a50580069743d26062da9171006405d27e2f7220a897024dca507b737a6c32ba3d925e15c9789589507a768ca075beb2fb17a17144c52810566a972dba60ad806a2ff15957a3bbd85a8f1ef34445d18cc668ca7a8ac5fc7545934221a4c92c60024069cc34d592ac30c88c3376bc133622e2b192e9b4b60a9a84e5304873e62d6f98103cc8c43f6024fb7739418cc2602b21416040220cb3ec588679c033d61a3c697c403463c17c13a63d7304044a9f024b907b440b39b7b6423723dda943447a900af0170144755d9a968f634e26f892ee19cd00a97b48d5041b4473ec8741e077126f85bbb8334b8b2cbd63429afa543a540740c1e56893f6b2f2f7c42a12bcd48c647726cca06841212656ff9b3d3e799e92c48414d653a61ca8dc2c49b7342469a868b7938db8d7844e6311134b2c30538ffa927ee3961a44e0a66438c5643aa1d13658fe8a7c2a84702a8211422831994ca1e801131ab88a25162d3cd988ebe09e6cb01ca7324256691635c536f576990664841b7c89b0dc325472271fdc2b0824a9514b5eb46a743f9734ee20648a407f5d505cc9614748f344a16950b5483e45516236d43afd1494d564c23e20b64a124593604404c879a776a5bd9399629600e86aa1a641be7a13418cda318bbc3af0c2a66c999841251a1c2868b05028f6a56a72c33d8a653c77f69af4247dc6f80d329921ce3355894605c35372ddf0c84cacb42d6ccbdf39a55b672a891749622a011747a01625764c788413f2c0fd877275c88fd5730fa9e87a3c783702223a4443525cc5b5381c976dd9cb08ac47490125ca5c70baac01ff9143bc40ceeb2a16c1529d70c07074a0013749656ff4b16d890868b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb333");
1✔
4179

4180
         botan_privkey_t b_priv;
1✔
4181
         if(!TEST_FFI_INIT(botan_privkey_load_kyber, (&b_priv, b_priv_bits.data(), 1632))) {
1✔
4182
            return;
×
4183
         }
4184

4185
         ViewBytesSink privkey_read;
1✔
4186
         ViewBytesSink privkey_read_raw;
1✔
4187
         TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.delegate(), privkey_read.callback()));
1✔
4188
         TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.delegate(), privkey_read_raw.callback()));
1✔
4189
         result.test_eq("kyber512 private key", privkey_read.get(), b_priv_bits);
2✔
4190
         result.test_eq("kyber512 private key raw", privkey_read_raw.get(), b_priv_bits);
2✔
4191

4192
         ViewBytesSink pubkey_read;
1✔
4193
         ViewBytesSink pubkey_read_raw;
1✔
4194

4195
         botan_pubkey_t b_pub;
1✔
4196
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
4197
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4198
         TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.delegate(), pubkey_read_raw.callback()));
1✔
4199
         result.test_eq("kyber512 public key b", pubkey_read.get(), b_pub_bits);
2✔
4200
         result.test_eq("kyber512 raw public key b", pubkey_read_raw.get(), b_pub_bits);
2✔
4201

4202
         botan_pubkey_t a_pub;
1✔
4203
         TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 800));
1✔
4204
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (a_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4205
         result.test_eq("kyber512 public key a", pubkey_read.get(), a_pub_bits);
2✔
4206

4207
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
4208
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
4209
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
2✔
4210
      }
7✔
4211
};
4212

4213
class FFI_Kyber768_Test final : public FFI_Test {
×
4214
   public:
4215
      std::string name() const override { return "FFI Kyber768"; }
1✔
4216

4217
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
4218
         const std::vector<uint8_t> a_pub_bits = Botan::hex_decode(
1✔
4219
            "38d4851e5c010da39a7470bc1c80916f78c7bd5891dcd3b1ea84b6f051b346b803c1b97c94604020b7279b27836c3049ea0b9a3758510b7559593237ade72587462206b709f365848c96559326a5fe6c6f4cf531fd1a18477267f66ba14af20163c41f1138a01995147f271ddfc2be5361b281e6029d210584b2859b7383667284f767bb32782baad10933da0138a3a0660a149531c03f9c8ffccb33e3c3a5a7984e21fab26aa72a8a6b942f265e52551a9c800e5a44805f0c0141a05554213387f105df56458496bd8f469051886da223cb9fe78e7b390bf94b0a937691af9550082b76d045cb4d29c23c67942608d078a1c80f24767a945d19f077d82c9b9b197073464abe69cf7c5626177308f384672d5263b0c4826db4470e1a70e4751e3918abe8fcbc3bc0531ae89e5512214b5cc94a16a014bcb3826c79fbf4add0825eeefbab88cb7cff37bb8d491f8de902578a1e961655565b7718782a23504fdc13c783f130e177925e305d1fbc63cc8c15c2c67f85500cca785de9f480490558ef71aaf0fb5b513914401269b309c4c59c64d2a757d8855f58465615925f1ea6812cb143fff383e1048e285118bf932944b86fbdf4b1b9e65685664a07775c46952aaada1168f54b47c7a231e7355c64637467b5a3c09cab67bb35f58640c2726283bb63530a15f66eca48a840c00ca8862e283c73bfbb413a2915b8d1159a043f12c59bfa828248249b76106faa61a127a0280c586350e7a42cb74ca49cabd606891ec7cb8e84affe4b2e14c71658332b755611bab7977fa76ce736b21ed34a17ac0ec3561ca9b282d4a2bc407697924b1cf918ba83d3a4fdc82564c95bd904bdeee91ed6ccb36baa88a05c80712901bf280aee6538ec2078c2a84ee5862fc137cd92e97968d69fc3453a1e1cb161c50c9f2473a0d09037b188a0fa01efc344c2ac8fe8592b0a58456662a95033659a158a2d90a6e50c253a87975785ce29c4570000a154d4b3b2c642205c8c7cf9ac6b1071fbb368ab950a744b88c95ba5243017831120a9048338d29847830d12a933a09abd21a46b828cb14e808cd35129c9dc6e5b931d4a126fefe07909618e2b4586e7b6b424963b7323ba505ba112bb9b834a7d1b78ad0df53d556a1c69369f09148b1dc9938df59223f087fd6833be5b2bc2651fe58911ac01467f9297dfdc22b41a0f1702718710b78cf35b1865813a896d45214d338155b6c043c532330c002d520739467a504a866637fb3451c849f8f83e6a94147f168da53acdf9d8affd968a84124a9abc09af960cd3b29f2344831bb41e67605eebf00df202857117399dd748b6514aed61bb2f6cb841d168d5f35e20054573a331cd4882a04b072c179158825bcf471266da0dcceab1a021c73254751d5a161c1a92062c220a217a69d9823314b4de996fe8d45f6db5af16c1561495a4c43090bc394c94e1b0ec738eb56267201c2ecd1c7b4993c0efc0284bdc9a091c294f95703a7178822c8a95b79b1e4591e0998d893875c1a879c08a073cc67df426bba792c18ae6c1feba879bec54812c2affa012973b700ad48e271078280864268600a7aa309eaa1098750a0f8a522eb929577b412f7855613688b72f9bc85c0a13b9d041586fd583feb12afd5a402dd33b43543f5fa4eb436c8d");
1✔
4220
         const std::vector<uint8_t> b_priv_bits = Botan::hex_decode(
1✔
4221
            "9bc4986eec853ac90896c7300f914216773baa687f57f81f94e6b5a26515c0a74c73b19dc6b9888755a1d1db6a1128b02c5144ed9ba75e874a68a14dee3a9bf770b767121fbbdb292e097444757fe2f324a875b0a07a4fbdcc8fd6137fce80c69f412be103b01f8b3bed392600f830d1b20d73ca0b386666d16c5d96db10e309041890bfd4ab7bdec27191979abe7637e76153918cc2af1545724abfd95ca496281a0cc6ca63a87819b75aa86452e5027d429cad64a9c029112a3a7b9fb993c6a6d0671f6c9e24986b83f67cf1236d94c051559616826a947eaa15074025d1ab810c80220e8a8c2c222d4e8594bf35811b444a57e9bf94fb2479d174d6b38c8c3b4730437c244b2513232ec798adec4a8e597bca83bca5948468f93c022ba65311a91e3d95c299c70c3f1a43cd0c83dd500bd2211b9b385b82f2c003b10d295765b3e367563a5f19033fc1231db9620f835c95f5a261190a5da1c24ed528316f0a1520d223e208a8c99b24d28598ade74fc88370e7f45102c5a6411891c661b356b9a32e1cc0fafaa085d7670e8bcb5e768eb255204f2445b5b73b04079881903a553c865744343a925c7899777b1c9dd5579a481512f8157061606a9a67c041d38bc179048be17dd9e19dc0a572bce595afa3b68ff21bf78a63a7560636b6bb01ec3362e2aaabc8965818b7f2417ca8f66a5a2a67f72a3931e125d638a872862a7b680a54aa1f25d90dbd567635ec6664919e29517325a5c5048cc8d1c31af5e4866e85025b9184a7b75ed7f2c9c8d88259fa2ec5b05ed3751584f88308c67ff1a72fa2453305160baf404db7d4be56f1547b20bb7dec23f02b10db584b28ca40d8b39c1c3ab9f3d7bbda0822604ca48f26694d69810aa888ae3c0983c5ba4cb74211f7a5361ccdee694f4202aebe13a75b1b2dda1b3232376be213582afc4fde3474766671fe865e2fd98384eb65b2f349f1e24269b91bd9d08c80849735a9951304afd130b5c2211314630aed4b6ac3b1252a0999ff5a3ec26a283342389d219fd243706128b389eb2334fb2a6184a4eab6735d7428df5633ce030b8f853ee47c4401fc5d06b43c9b66b7aeeb23b5f000a30a6f88f027ee3994fe8b63e51b83bc24bb733a3773a35cbe138f6d9c91a3a3898bca6776030d740ac355176547d624719656a9a44e91c63faf7699dc6c2c45575718d48828828b39043c2fda2af416837efc38d17c56d4b63c63a5ab43434647d029f7b236b288958f06910763610f8b2f027a8dcd780039ab34a6871427476ff6500240e83b87c95dcfa45ac5315ef34b343fb609eb296e915c849bb8c57f57c69b177eaa8456377403fe8c6627a3282d45308f675d67085a15f0b1b55aa2a8f21afd6c05c3c00e9eb8c32418cb41963ce427b43e7545c58325c7b9368db2333de424dbeb3430f007d18a68d73b7dc67960b28206a68a1be400a770b5cd9d45a72824ca00345ac56491c1414fe5287a2eb2ad61f3bdcd0c84c335b04a703425d79dbd02b0a0e90de5b331c3c29f6562969e04cdf7095b2a7646b3d006b0b83cb68580b5ccb71de1b4d9f131bac133d6088e10613a00599d81d4818403a4bea83905304cc45ca645a9b2c6484cf9490f1755c744d9988ed60475e6ae44355ed15c7b549366f29581ec2721fd6704e0ca3f878812805675141c0a15a7b7ac35a9e3f8b2a010bc184981c57852895b2695d56131e32326717f6b101df1bc82b3ba0222d52656d118538c4ca3416be1c76ba37a9901a36e4883be6c541f2bbb561818cd2f136b98f658250545c1fa5bcfdc04374016db1c5132447fd6d568866451c25412f72967de868eaeb9c546fb40ea88cd84a1a586ca51c74bc9c3e56e104323afb658d1ac003151bdc35879a4b6762648bff0caa682f1b3319805d2326d5a46af832aacefbaa1ea820568ea3925870e9b6577eb93898e1b0cfbd1c995cb4cd6cabb979813819749b40a9952f50e97c4365e777dcfe9084219294c205acb350e07db9c98f53444546460962e2bf5aa1cc12273d882fcc215a7397b3f9b307c56b9a0429b30f88453a2376669b28b4bc4b84b51714b6652b7a1a0b53e9ec61b55ca51cdb38243239ee5f18243e515f178768a888f475b3d9060136bb22ee355b3da02c16ad83bdbb4aaa13809cb4bcd5bb53710737d3883632f9254e3336af61621a376720572450e3937c0d930e349adbfa7642ff822b9135e18f943e0178617604d10e0c09ffb3e09783c09d12cbe93311757af9857b77d1488ed39321ca97c3745c5bc176ca81274c8321bcb2029938b32bbd01aec137032f9760849701649120050b50d8353c36b8bb7724a67e7660fc93324065d63912c35a86d8fe60683067bbd2685c552ad8c65c77c57c937676fd61595c453174bf996e9d3a9ccb837b25464115c1ba3343ac097b80735aed3225091167cd8f841ffe49c5e698ef542124253084623179394433a4b61547b9ee09c98c2736ea086bd69d1bc7ae68a6ae5ce682a215860006b4604dee45a3e212f97643acb77a79a880382e483537c5198d4483a176d25aac9c3670a3f30956f18ad441904776bcd48131c7d6465bce0c133010f3176c92ec962f5c6b84d4c3ae949619cf48172997ca3b1ccf5c8cc7a67923e1295801048a3d40ac4f2c6467c750fc71314a0c1fc22637dd52e7ea50907ea973d765a6a9bb2b11aa405b9187f72026696710e61af3e41c33da1a05eb65e6523704f078e74e32f10e00247967aee3a8c6546889ef67cd613ad7236583f2104122ac6c6a40a84dc96d81c569e76a952c0a25f396e48337a4fe029a4c91cc7406872706a55573b75f160a4facad7c85fab141c63454bf48990729096ce9965604c7cc1e60ae6868dcc41bc3df71c3e5593f0488b0c6a3063e817f9f4bacb17599c8666ff3591126b4891fb7f5d29660bab60cf5007043a4311d41ab3b29787184f3d3c9ab7cc247f635145b67e970505ba44ad0e06b11ec5cda4175295199d19d660204cbdc17947cc66442d3a2cd408a20fe98174f31ee4e5bb3fa8bcd102bedc26527e9bae836442978a6ccbe510f93ab77569ab1f09d0e6312dd0cc0bcaf095fa8a52a7212d14714a7bf852416c9b026301bd965c30a43d24d97298346a46b2c4bc814ba4059653358b03c9456c60bf0193932eaa2f24ea8e4b010a5a4425ce4540fbab90d8e55c97ac2687f15ff5299278824a08d4743e1a62e1c6619cd3278cd75a97a5b4e3a38668b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb3339ae9c9ce46d9da0e714c0bae8712a670d0e5dcfdd1dd0d045932c79c559b2ab3c7300e2d894b0eaa40a6ab254506d8c1176a33c4a1b2879604b1b80df48d31dd");
1✔
4222
         const std::vector<uint8_t> b_pub_bits = Botan::hex_decode(
1✔
4223
            "f9490f1755c744d9988ed60475e6ae44355ed15c7b549366f29581ec2721fd6704e0ca3f878812805675141c0a15a7b7ac35a9e3f8b2a010bc184981c57852895b2695d56131e32326717f6b101df1bc82b3ba0222d52656d118538c4ca3416be1c76ba37a9901a36e4883be6c541f2bbb561818cd2f136b98f658250545c1fa5bcfdc04374016db1c5132447fd6d568866451c25412f72967de868eaeb9c546fb40ea88cd84a1a586ca51c74bc9c3e56e104323afb658d1ac003151bdc35879a4b6762648bff0caa682f1b3319805d2326d5a46af832aacefbaa1ea820568ea3925870e9b6577eb93898e1b0cfbd1c995cb4cd6cabb979813819749b40a9952f50e97c4365e777dcfe9084219294c205acb350e07db9c98f53444546460962e2bf5aa1cc12273d882fcc215a7397b3f9b307c56b9a0429b30f88453a2376669b28b4bc4b84b51714b6652b7a1a0b53e9ec61b55ca51cdb38243239ee5f18243e515f178768a888f475b3d9060136bb22ee355b3da02c16ad83bdbb4aaa13809cb4bcd5bb53710737d3883632f9254e3336af61621a376720572450e3937c0d930e349adbfa7642ff822b9135e18f943e0178617604d10e0c09ffb3e09783c09d12cbe93311757af9857b77d1488ed39321ca97c3745c5bc176ca81274c8321bcb2029938b32bbd01aec137032f9760849701649120050b50d8353c36b8bb7724a67e7660fc93324065d63912c35a86d8fe60683067bbd2685c552ad8c65c77c57c937676fd61595c453174bf996e9d3a9ccb837b25464115c1ba3343ac097b80735aed3225091167cd8f841ffe49c5e698ef542124253084623179394433a4b61547b9ee09c98c2736ea086bd69d1bc7ae68a6ae5ce682a215860006b4604dee45a3e212f97643acb77a79a880382e483537c5198d4483a176d25aac9c3670a3f30956f18ad441904776bcd48131c7d6465bce0c133010f3176c92ec962f5c6b84d4c3ae949619cf48172997ca3b1ccf5c8cc7a67923e1295801048a3d40ac4f2c6467c750fc71314a0c1fc22637dd52e7ea50907ea973d765a6a9bb2b11aa405b9187f72026696710e61af3e41c33da1a05eb65e6523704f078e74e32f10e00247967aee3a8c6546889ef67cd613ad7236583f2104122ac6c6a40a84dc96d81c569e76a952c0a25f396e48337a4fe029a4c91cc7406872706a55573b75f160a4facad7c85fab141c63454bf48990729096ce9965604c7cc1e60ae6868dcc41bc3df71c3e5593f0488b0c6a3063e817f9f4bacb17599c8666ff3591126b4891fb7f5d29660bab60cf5007043a4311d41ab3b29787184f3d3c9ab7cc247f635145b67e970505ba44ad0e06b11ec5cda4175295199d19d660204cbdc17947cc66442d3a2cd408a20fe98174f31ee4e5bb3fa8bcd102bedc26527e9bae836442978a6ccbe510f93ab77569ab1f09d0e6312dd0cc0bcaf095fa8a52a7212d14714a7bf852416c9b026301bd965c30a43d24d97298346a46b2c4bc814ba4059653358b03c9456c60bf0193932eaa2f24ea8e4b010a5a4425ce4540fbab90d8e55c97ac2687f15ff5299278824a08d4743e1a62e1c6619cd3278cd75a97a5b4e3a38668b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb333");
1✔
4224

4225
         botan_privkey_t b_priv;
1✔
4226
         if(!TEST_FFI_INIT(botan_privkey_load_kyber, (&b_priv, b_priv_bits.data(), 2400))) {
1✔
4227
            return;
×
4228
         }
4229

4230
         ViewBytesSink privkey_read;
1✔
4231
         ViewBytesSink privkey_read_raw;
1✔
4232
         TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.delegate(), privkey_read.callback()));
1✔
4233
         TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.delegate(), privkey_read_raw.callback()));
1✔
4234
         result.test_eq("kyber768 private key", privkey_read.get(), b_priv_bits);
2✔
4235
         result.test_eq("kyber768 private key raw", privkey_read_raw.get(), b_priv_bits);
2✔
4236

4237
         ViewBytesSink pubkey_read;
1✔
4238
         ViewBytesSink pubkey_read_raw;
1✔
4239

4240
         botan_pubkey_t b_pub;
1✔
4241
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
4242
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4243
         TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.delegate(), pubkey_read_raw.callback()));
1✔
4244
         result.test_eq("kyber768 public key b", pubkey_read.get(), b_pub_bits);
2✔
4245
         result.test_eq("kyber768 public key raw b", pubkey_read_raw.get(), b_pub_bits);
2✔
4246

4247
         botan_pubkey_t a_pub;
1✔
4248
         TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 1184));
1✔
4249
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (a_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4250
         result.test_eq("kyber768 public key a", pubkey_read.get(), a_pub_bits);
2✔
4251

4252
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
4253
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
4254
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
2✔
4255
      }
7✔
4256
};
4257

4258
class FFI_Kyber1024_Test final : public FFI_Test {
×
4259
   public:
4260
      std::string name() const override { return "FFI Kyber1024"; }
1✔
4261

4262
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
4263
         const std::vector<uint8_t> a_pub_bits = Botan::hex_decode(
1✔
4264
            "9779a4d1fc45ec261f048b9c9daa38c9ec228b6505e8905226b38486802059c2c5c89601560634cb1337b1315365144842bc405a292e683cafa4514526945c4dfb68ee2acdb8b79532836696d53125a045bdbb8a3bcc8123083d1e682c5bd7820c76c448351151474f69d601d7708dbb2c979d77527494b68520a8ff66c34162ca2aec8072a2a51ff259389648e75b95c16abe14604edbfabaf400b76a7a0f07db61dce19102f43b2d1060747b02c4425485341fd5d9bffaa7016061374963b985209c6b9a7db3f94958311d027900a3d8c44f8435b093a236a0509f1928df7719ce8c4e90228f4db87cb9e882f2712180238845d31eb906c60eb63e0ff55e84b867a91b79ae74a03ac00473c8c1b3e6aedcc37f1e69b8e136019bdb01c374a122e164c32584b2fbcf5e013a45127c893326b6860378cb5525a48b522b30132b7688214b69808dd19aa4ff033e16252016fc9479222424393e51db7115e38114e6893cdcc8ae1117a4316548010ab4629fb672148d031a6c601a6a4a661d872d8ef693750a115958716ab9263eb0516357102358cde5256464805ca8f59661751ad6a475a7ec78cb7319c3bbc544e1bb1185aaaeb751ba0b3923246e33f40a4ff4780b745362a218d169474d7208a9f7577228308af20f8d2403a27477cf53cff133a247d5c2b298bf21bac6dc44649e63afcef54ad3a07a74e447b36bacca295e053368ef7c146e1c28edb31b3777c941a7c27dc559437b0ff83c2910f827ef244d7726af2b9708654bcfb139a26844c6f4b79cd9e4747065a77596b927f96cbdbc7267ac9e32ac396f6c4ce739aa0aa60fccac178edab1e04688fe71a74201a99bc64b55f8cb89e11545e5275af48626ec667520ba8a7c88c2307e793455ef8780fae16412ea59e92406f595902dc21c612b142801cf31abc0475c7bde772d51c55a2dfc651bc5ab4143022813cc4c8cc6f52c8d27e3cd7851849a8c4343f0c7ed6c6cb9f765c5047e55bc48aad5b932128287f70939db753a61c0d7db1830c256288c1c85cc9bbce58366dac528c893d61b69850bcb82758e836936e1f8163861586482cad35b4db1437fad6980b66280b1652d72f52407a8015f85c29e75b2158933a4f5887db320b583cdcbca274eac21f8702879b8bc4afb62ba056d146512921554c765464d4c96bd3c9a9720187c3339d0593bc4bba59155469ff6b8688a5fc5fa6b46d4070668bd168c5f796492760940999927628236b2412968438d2cbc2a978abc097320291b0ed7e4631ec9bbe28ac63ab6860e976ac1552afc43897d6937a092432dc481a914c3a1273c43009e8ec523cb93ced9898f90905340ba6e01bc572d03a893fa21c4342d88dc3e77b33b1fc063dcdb689d8c4ffc840ce879cfb3471385512cc7c7591383b1fac89832bb1cb3324e6d2868918844cb20ca4df812b42824192a43380430a37a7f3ac41ed064cfe055157b91b5c0108fb7a613a0112af4d64e48f8a345328a99b7bf0c91cb037215b0177ad4c263e6d78f5958c848158e4fd2117c248e0cab3cf98c1e27868838f8428ba0562df6b61e8736e2b8b266607918e0ce2ce3af67c81fa5c2a4d2bc8e871825b702b3beca397b33a518dac8b1393d494a90900c01b55925857cbf8027051d36a4f141a4d2dc440341305e033cb50a074be459c76a339a9a52c447360dea2a5699ccea683a42430aa6fc9545c75c0492641af7a4e9267bcc384e55714cf49741eba3b69d6417a555475d3c021112b8b3588c63747b5ce2ccfee91297fa419f9c4298978fff0870d8a855b48899ca9bb47d836d62d2038cc3816f3a698bb3bbff78c7a015b0ea1960634292e1d50b03e1043a98ca9b27063e668b05e2c17d692d382b181365a818518ec747720337ca1868596af42a90fab1870373d74b8f6d42ac86b18bca3ab04764680cf2060c529abe5b8ef4474dc8cc47a8033ebd884d3e0a0f1a94420d8a3c9162b7af87a2c8a394647434f4a3bc2b477813ac82cf387185b587f7f68938eccddd6934d143ba17bb4a712566d2a55aaddb3323713667401b4a20b86c23bf1076439cb6b8c115389dba4e6f0c915be7602b9703b535070e4a5c5649a5d7080515026706b2604575cbd0687f2729a92a997d21ea7200c41ed8315275f4c7b72f9bc85c0a13b9d041586fd583feb12afd5a402dd33b43543f5fa4eb436c8d");
1✔
4265
         const std::vector<uint8_t> b_priv_bits = Botan::hex_decode(
1✔
4266
            "9bc4986eec853ac90896c7300f914216773baa687f57f81f94e6b5a26515c0a74c73b19dc6b9888755a1d1db6a1128b02c5144ed9ba75e874a68a14dee3a9bf770b767121fbbdb292e097444757fe2f324a875b0a07a4fbdcc8fd6137fce80c69f412be103b01f8b3bed392600f830d1b20d73ca0b386666d16c5d96db10e309041890bfd4ab7bdec27191979abe7637e76153918cc2af1545724abfd95ca496281a0cc6ca63a87819b75aa86452e5027d429cad64a9c029112a3a7b9fb993c6a6d0671f6c9e24986b83f67cf1236d94c051559616826a947eaa15074025d1ab810c80220e8a8c2c222d4e8594bf35811b444a57e9bf94fb2479d174d6b38c8c3b4730437c244b2513232ec798adec4a8e597bca83bca5948468f93c022ba65311a91e3d95c299c70c3f1a43cd0c83dd500bd2211b9b385b82f2c003b10d295765b3e367563a5f19033fc1231db9620f835c95f5a261190a5da1c24ed528316f0a1520d223e208a8c99b24d28598ade74fc88370e7f45102c5a6411891c661b356b9a32e1cc0fafaa085d7670e8bcb5e768eb255204f2445b5b73b04079881903a553c865744343a925c7899777b1c9dd5579a481512f8157061606a9a67c041d38bc179048be17dd9e19dc0a572bce595afa3b68ff21bf78a63a7560636b6bb01ec3362e2aaabc8965818b7f2417ca8f66a5a2a67f72a3931e125d638a872862a7b680a54aa1f25d90dbd567635ec6664919e29517325a5c5048cc8d1c31af5e4866e85025b9184a7b75ed7f2c9c8d88259fa2ec5b05ed3751584f88308c67ff1a72fa2453305160baf404db7d4be56f1547b20bb7dec23f02b10db584b28ca40d8b39c1c3ab9f3d7bbda0822604ca48f26694d69810aa888ae3c0983c5ba4cb74211f7a5361ccdee694f4202aebe13a75b1b2dda1b3232376be213582afc4fde3474766671fe865e2fd98384eb65b2f349f1e24269b91bd9d08c80849735a9951304afd130b5c2211314630aed4b6ac3b1252a0999ff5a3ec26a283342389d219fd243706128b389eb2334fb2a6184a4eab6735d7428df5633ce030b8f853ee47c4401fc5d06b43c9b66b7aeeb23b5f000a30a6f88f027ee3994fe8b63e51b83bc24bb733a3773a35cbe138f6d9c91a3a3898bca6776030d740ac355176547d624719656a9a44e91c63faf7699dc6c2c45575718d48828828b39043c2fda2af416837efc38d17c56d4b63c63a5ab43434647d029f7b236b288958f06910763610f8b2f027a8dcd780039ab34a6871427476ff6500240e83b87c95dcfa45ac5315ef34b343fb609eb296e915c849bb8c57f57c69b177eaa8456377403fe8c6627a3282d45308f675d67085a15f0b1b55aa2a8f21afd6c05c3c00e9eb8c32418cb41963ce427b43e7545c58325c7b9368db2333de424dbeb3430f007d18a68d73b7dc67960b28206a68a1be400a770b5cd9d45a72824ca00345ac56491c1414fe5287a2eb2ad61f3bdcd0c84c335b04a703425d79dbd02b0a0e90de5b331c3c29f6562969e04cdf7095b2a7646b3d006b0b83cb68580b5ccb71de1b4d9f131bac133d6088e10613a00599d81d4818403a4bea83905304cc45ca645a9b2c6484ce4f7bfbe3597f0c2c50784065abc214b5518ed8c7d427205392987d807cdfa571d09932e0a1217e7c5703dfc9be7c4a0f2f33338f316b8c203c6b84285a0957c363d3722145b592f9d6277b1b7446aa2005663b9898901da3b8978eaa8aee87a209c72bfd6cd10a2bedac527f26c419b4bb9a4ca13dba14cff5671461c4cff238d213988120c3cae3b15b607269420c14a9b23a6bb887ad048e6688528137dd5c071172bcaddd5ba4fb9acfb1712ca04aa267b0686a237414b16c4ac03525a45513a393605a29f3b4c07dc5cd082c67b770e69723c6425a23f573216c4cabd6c9c39533f16643bc6151672c466dea63fb8e2180fbcb453c5670b01c0fc7043d198b6c320bf0dfc5016d00f46dc0ba75c7369fc13b65733301b3a92c0cf8dcc1f01e33291a9974d5b5debfa3be5531c69a066a6f4230ba778502654b7e76191d3ba68b1488c848d8ef11bb9ac5a5374af6ccacd02432b247a963685127728825a162c43c1cc79a7b60f571481a3a635a18f0050cbe6f4af1a5a2224044622bb3893bc837be699d5279dac78c9d49818ebc91d4ff6cb54b294e4c378d8eb584f561d21ca87b7c77b1c551f52112ba72c4b6514bb286856e89b48b0a62bad093894474b246a515f849056c9aeb572060ee11b93e236204a8ff1784ede0c3f4c0cd0cdb2a50bd4bcb1225c0dd2caa8a129fdcb01f0e1a75da465b6b8742e4946dbe3ab21ca6c4e592d398a5700375b7b770c17e117663b51313824854585ece4a1520c59a513555f548afdc6748eb9b770b7af8adc9b3c1861efc00ebde93f91fa1539c3411ec9b154c93d1f508b9714cdd0aaabcb436951aa54978b84faa8bd838c29a12657a6389fa658237326bf80e44cff183d9c9107d30c7b4df83908a8badbc1bb5328ae61e6451291710408196261bb913b285c168fe5c7456cd74970377330139beb4c8b4c00c5954254a748308bc30f3a1ccabed83628422e5515b294e80bfed024902a81518c0e6827caa13230016b72aec10d31aab9f9b072652486c3b779c845804d001b223b4065667a5e318b4e0b27c41a099168ce763ac245c1c26354cfc8214cacf01dc8c99c5fc855639cb7486a7a6b71766d62369ee6349f521591344fb8026099fc055c3a0ca2002271c9361f52acaf4675a97b3593f3447b284ad69a9711501411e14e48f080e2a0bceba07a02f79dc15c3c971c1e671a66bf7144395a94d08c46603c4369b25b38d924693492f6500745cb1d2a037e2cd814fac70d8254aea4526e061648d227350dec1ba6305299a45bde4029a9f63e4f62acb5246ba8b54208a37b98fa77e4b720f02b18969635cc16cb6e236ff78111b621cab0339c60b529a9207c94a74925aa3d177636a6d205d72b429f614d452358b98582e42c2f3a32c94202a8625a760483807bbac74c083a7a786ae7b46aff3810a5318e3f479e67e83b4c94587d345ffda17273a55e0432281c670e36b76539263636445e4d110fa1c92b2e65b1ee993b26c41c8c66b181206ff559728993503e7611fa0ca24156642d29a52cbb6aeff88fa1bb790b4344472503ae77967d11a904550a95cc47c3435f1e44b4b890cf5dc4cbd7486a6cab60d1a6622e40c67e854ed0e6a0c4c2aa92a29731e69bc6b3ca9e83893df4bdb37338055bc16bc7cd875b0691d0212109b77236b10b0c72b7a76e9ce346061028be3271c480435e2482d3d2733ed619c2d3698d29a3225a7731a62db4f214a0b11569e91895fbccb8a92d18f94d307a542ff96d2ce8c2bbaa8fab948c83365162268124cabe934b3a5e6530b7f74397a980c243bdce2989747565dd9ba65a7498aa7c3ee711c3be239e93cb45134c082a900cc951756afa42e74a65001822cab95f41798fdef89ea8a751740842e2f7a271e98dbd5158d7455fe9b9cdcd0a0f68c91e59b00979673a1deabf8d213971f994c0bb08899a91e0b896319b9fc69651e3453b14d1cc94462341548fc81c643ab0b10303c7be2c3458b226d0e45f58b21658a853b84615ac5234da9bc5699646fc53c0df907f9a3c598dab6c409b7884a7a84e1a51c2caa80779cd86b77314dabae85caa28972bb6503273a82eb96ab24af6bb0ad0c9ba07ce24216696e265206abc9e147ceef1ad2e343d17aabbc4803496366c7afb53f604c92323c70be5c1e3f601c215c888f3ab239c72aba0634a2901a71891f5d072d41b524e410c7f276ff1109878d7196b5615f1f50c13976257600a821909cb36cf8d2857a2f801cf258913f56a5153234640b9e61bbd4e7b69f83a1eb8ac6b92cb841e808b700aa784a733451048211797563cccc748c9fbb54b3b65445cba676149c7ae9a9a2ecab6599b8505bc561ad85d8c052ed9669e50e684270c86f1cb4fd6708a6746c643392c8a088477dc8bf58ba4a54a8b79e523fc19a28bd47d7e5a334d8296ec86c7f52b7e73b475a0716422953cdd8a8aed0b3a84dc8425145c240c55870240a23977215b364c5596286bc496728717c329dd4b5d0b310980bc0b3f591a2d5cb2c9eaccfa1c7d3a096fc11091a4007a0f23a59782699c3171da53bc7b914f26c95391d6445073a1bd7a44691bafab9c9aceccc7ec389255c3a0ff24c71b30b6bf80c010803383485a7b295991d759cefbae257bbdee1806818565ebd09bf814c98686bbf44a0b14d28735f79ca2261bf9a31b2ca090c7667168b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb33357e74a31d3cd71513fb880e1e177438f29009bab0a131fec4cc24752015efe71c7300e2d894b0eaa40a6ab254506d8c1176a33c4a1b2879604b1b80df48d31dd");
1✔
4267
         const std::vector<uint8_t> b_pub_bits = Botan::hex_decode(
1✔
4268
            "93bc837be699d5279dac78c9d49818ebc91d4ff6cb54b294e4c378d8eb584f561d21ca87b7c77b1c551f52112ba72c4b6514bb286856e89b48b0a62bad093894474b246a515f849056c9aeb572060ee11b93e236204a8ff1784ede0c3f4c0cd0cdb2a50bd4bcb1225c0dd2caa8a129fdcb01f0e1a75da465b6b8742e4946dbe3ab21ca6c4e592d398a5700375b7b770c17e117663b51313824854585ece4a1520c59a513555f548afdc6748eb9b770b7af8adc9b3c1861efc00ebde93f91fa1539c3411ec9b154c93d1f508b9714cdd0aaabcb436951aa54978b84faa8bd838c29a12657a6389fa658237326bf80e44cff183d9c9107d30c7b4df83908a8badbc1bb5328ae61e6451291710408196261bb913b285c168fe5c7456cd74970377330139beb4c8b4c00c5954254a748308bc30f3a1ccabed83628422e5515b294e80bfed024902a81518c0e6827caa13230016b72aec10d31aab9f9b072652486c3b779c845804d001b223b4065667a5e318b4e0b27c41a099168ce763ac245c1c26354cfc8214cacf01dc8c99c5fc855639cb7486a7a6b71766d62369ee6349f521591344fb8026099fc055c3a0ca2002271c9361f52acaf4675a97b3593f3447b284ad69a9711501411e14e48f080e2a0bceba07a02f79dc15c3c971c1e671a66bf7144395a94d08c46603c4369b25b38d924693492f6500745cb1d2a037e2cd814fac70d8254aea4526e061648d227350dec1ba6305299a45bde4029a9f63e4f62acb5246ba8b54208a37b98fa77e4b720f02b18969635cc16cb6e236ff78111b621cab0339c60b529a9207c94a74925aa3d177636a6d205d72b429f614d452358b98582e42c2f3a32c94202a8625a760483807bbac74c083a7a786ae7b46aff3810a5318e3f479e67e83b4c94587d345ffda17273a55e0432281c670e36b76539263636445e4d110fa1c92b2e65b1ee993b26c41c8c66b181206ff559728993503e7611fa0ca24156642d29a52cbb6aeff88fa1bb790b4344472503ae77967d11a904550a95cc47c3435f1e44b4b890cf5dc4cbd7486a6cab60d1a6622e40c67e854ed0e6a0c4c2aa92a29731e69bc6b3ca9e83893df4bdb37338055bc16bc7cd875b0691d0212109b77236b10b0c72b7a76e9ce346061028be3271c480435e2482d3d2733ed619c2d3698d29a3225a7731a62db4f214a0b11569e91895fbccb8a92d18f94d307a542ff96d2ce8c2bbaa8fab948c83365162268124cabe934b3a5e6530b7f74397a980c243bdce2989747565dd9ba65a7498aa7c3ee711c3be239e93cb45134c082a900cc951756afa42e74a65001822cab95f41798fdef89ea8a751740842e2f7a271e98dbd5158d7455fe9b9cdcd0a0f68c91e59b00979673a1deabf8d213971f994c0bb08899a91e0b896319b9fc69651e3453b14d1cc94462341548fc81c643ab0b10303c7be2c3458b226d0e45f58b21658a853b84615ac5234da9bc5699646fc53c0df907f9a3c598dab6c409b7884a7a84e1a51c2caa80779cd86b77314dabae85caa28972bb6503273a82eb96ab24af6bb0ad0c9ba07ce24216696e265206abc9e147ceef1ad2e343d17aabbc4803496366c7afb53f604c92323c70be5c1e3f601c215c888f3ab239c72aba0634a2901a71891f5d072d41b524e410c7f276ff1109878d7196b5615f1f50c13976257600a821909cb36cf8d2857a2f801cf258913f56a5153234640b9e61bbd4e7b69f83a1eb8ac6b92cb841e808b700aa784a733451048211797563cccc748c9fbb54b3b65445cba676149c7ae9a9a2ecab6599b8505bc561ad85d8c052ed9669e50e684270c86f1cb4fd6708a6746c643392c8a088477dc8bf58ba4a54a8b79e523fc19a28bd47d7e5a334d8296ec86c7f52b7e73b475a0716422953cdd8a8aed0b3a84dc8425145c240c55870240a23977215b364c5596286bc496728717c329dd4b5d0b310980bc0b3f591a2d5cb2c9eaccfa1c7d3a096fc11091a4007a0f23a59782699c3171da53bc7b914f26c95391d6445073a1bd7a44691bafab9c9aceccc7ec389255c3a0ff24c71b30b6bf80c010803383485a7b295991d759cefbae257bbdee1806818565ebd09bf814c98686bbf44a0b14d28735f79ca2261bf9a31b2ca090c7667168b26c99bf8461495793bbb1b12ca369c825cb31d68731326bf4764b416bb333");
1✔
4269

4270
         botan_privkey_t b_priv;
1✔
4271
         if(!TEST_FFI_INIT(botan_privkey_load_kyber, (&b_priv, b_priv_bits.data(), 3168))) {
1✔
4272
            return;
×
4273
         }
4274

4275
         ViewBytesSink privkey_read;
1✔
4276
         ViewBytesSink privkey_read_raw;
1✔
4277
         TEST_FFI_OK(botan_privkey_view_kyber_raw_key, (b_priv, privkey_read.delegate(), privkey_read.callback()));
1✔
4278
         TEST_FFI_OK(botan_privkey_view_raw, (b_priv, privkey_read_raw.delegate(), privkey_read_raw.callback()));
1✔
4279
         result.test_eq("kyber1024 private key", privkey_read.get(), b_priv_bits);
2✔
4280
         result.test_eq("kyber1024 private key raw", privkey_read_raw.get(), b_priv_bits);
2✔
4281

4282
         ViewBytesSink pubkey_read;
1✔
4283
         ViewBytesSink pubkey_read_raw;
1✔
4284

4285
         botan_pubkey_t b_pub;
1✔
4286
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
4287
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (b_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4288
         TEST_FFI_OK(botan_pubkey_view_raw, (b_pub, pubkey_read_raw.delegate(), pubkey_read_raw.callback()));
1✔
4289
         result.test_eq("kyber1024 public key b", pubkey_read.get(), b_pub_bits);
2✔
4290
         result.test_eq("kyber1024 public key raw b", pubkey_read_raw.get(), b_pub_bits);
2✔
4291

4292
         botan_pubkey_t a_pub;
1✔
4293
         TEST_FFI_OK(botan_pubkey_load_kyber, (&a_pub, a_pub_bits.data(), 1568));
1✔
4294
         TEST_FFI_OK(botan_pubkey_view_kyber_raw_key, (a_pub, pubkey_read.delegate(), pubkey_read.callback()));
1✔
4295
         result.test_eq("kyber1024 public key a", pubkey_read.get(), a_pub_bits);
2✔
4296

4297
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
4298
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
4299
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
2✔
4300
      }
7✔
4301
};
4302

4303
class FFI_ML_KEM_Test final : public FFI_KEM_Roundtrip_Test {
×
4304
   public:
4305
      std::string name() const override { return "FFI ML-KEM"; }
1✔
4306

4307
   private:
4308
      const char* algo() const override { return "ML-KEM"; }
3✔
4309

4310
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_ml_kem; }
3✔
4311

4312
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_ml_kem; }
3✔
4313

4314
      std::vector<const char*> modes() const override { return {"ML-KEM-512", "ML-KEM-768", "ML-KEM-1024"}; }
1✔
4315
};
4316

4317
class FFI_FrodoKEM_Test final : public FFI_KEM_Roundtrip_Test {
×
4318
   public:
4319
      std::string name() const override { return "FFI FrodoKEM"; }
1✔
4320

4321
   protected:
4322
      const char* algo() const override { return "FrodoKEM"; }
12✔
4323

4324
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_frodokem; }
12✔
4325

4326
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_frodokem; }
12✔
4327

4328
      std::vector<const char*> modes() const override {
1✔
4329
         return std::vector{
1✔
4330
            "FrodoKEM-640-SHAKE",
4331
            "FrodoKEM-976-SHAKE",
4332
            "FrodoKEM-1344-SHAKE",
4333
            "eFrodoKEM-640-SHAKE",
4334
            "eFrodoKEM-976-SHAKE",
4335
            "eFrodoKEM-1344-SHAKE",
4336
            "FrodoKEM-640-AES",
4337
            "FrodoKEM-976-AES",
4338
            "FrodoKEM-1344-AES",
4339
            "eFrodoKEM-640-AES",
4340
            "eFrodoKEM-976-AES",
4341
            "eFrodoKEM-1344-AES",
4342
         };
1✔
4343
      }
4344
};
4345

4346
class FFI_ML_DSA_Test final : public FFI_Signature_Roundtrip_Test {
×
4347
   public:
4348
      std::string name() const override { return "FFI ML-DSA"; }
1✔
4349

4350
   private:
4351
      const char* algo() const override { return "ML-DSA"; }
3✔
4352

4353
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_ml_dsa; }
3✔
4354

4355
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_ml_dsa; }
3✔
4356

4357
      std::vector<const char*> modes() const override {
1✔
4358
         return {
1✔
4359
            "ML-DSA-4x4",
4360
            "ML-DSA-6x5",
4361
            "ML-DSA-8x7",
4362
         };
1✔
4363
      }
4364

4365
      const char* hash_algo_or_padding() const override { return ""; }
12✔
4366
};
4367

4368
class FFI_SLH_DSA_Test final : public FFI_Signature_Roundtrip_Test {
×
4369
   public:
4370
      std::string name() const override { return "FFI SLH-DSA"; }
1✔
4371

4372
   private:
4373
      const char* algo() const override { return "SLH-DSA"; }
12✔
4374

4375
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_slh_dsa; }
12✔
4376

4377
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_slh_dsa; }
12✔
4378

4379
      std::vector<const char*> modes() const override {
1✔
4380
         auto modes = std::vector{
1✔
4381
            "SLH-DSA-SHA2-128f",
4382
            "SLH-DSA-SHAKE-128f",
4383
            "SLH-DSA-SHA2-192f",
4384
            "SLH-DSA-SHAKE-192f",
4385
            "SLH-DSA-SHA2-256f",
4386
            "SLH-DSA-SHAKE-256f",
4387
         };
1✔
4388

4389
         if(Test::run_long_tests()) {
1✔
4390
            modes = Botan::concat(modes,
3✔
4391
                                  std::vector{
1✔
4392
                                     "SLH-DSA-SHA2-128s",
4393
                                     "SLH-DSA-SHA2-192s",
4394
                                     "SLH-DSA-SHA2-256s",
4395
                                     "SLH-DSA-SHAKE-128s",
4396
                                     "SLH-DSA-SHAKE-192s",
4397
                                     "SLH-DSA-SHAKE-256s",
4398
                                  });
2✔
4399
         }
4400

4401
         return modes;
1✔
4402
      }
×
4403

4404
      const char* hash_algo_or_padding() const override { return ""; }
48✔
4405
};
4406

4407
class FFI_Classic_McEliece_Test final : public FFI_KEM_Roundtrip_Test {
×
4408
   public:
4409
      std::string name() const override { return "FFI Classic McEliece"; }
1✔
4410

4411
   protected:
4412
      const char* algo() const override { return "ClassicMcEliece"; }
16✔
4413

4414
      privkey_loader_fn_t private_key_load_function() const override { return botan_privkey_load_classic_mceliece; }
16✔
4415

4416
      pubkey_loader_fn_t public_key_load_function() const override { return botan_pubkey_load_classic_mceliece; }
16✔
4417

4418
      std::vector<const char*> modes() const override {
1✔
4419
         auto modes = std::vector{
1✔
4420
            "348864f",
4421
            "460896f",
4422
         };
1✔
4423
         if(Test::run_long_tests()) {
1✔
4424
            modes = Botan::concat(modes,
3✔
4425
                                  std::vector{
1✔
4426
                                     "348864",
4427
                                     "460896",
4428
                                     "6688128",
4429
                                     "6688128f",
4430
                                     "6688128pc",
4431
                                     "6688128pcf",
4432
                                     "6960119",
4433
                                     "6960119f",
4434
                                     "6960119pc",
4435
                                     "6960119pcf",
4436
                                     "8192128",
4437
                                     "8192128f",
4438
                                     "8192128pc",
4439
                                     "8192128pcf",
4440
                                  });
2✔
4441
         }
4442
         return modes;
1✔
4443
      }
×
4444
};
4445

4446
class FFI_ElGamal_Test final : public FFI_Test {
×
4447
   public:
4448
      std::string name() const override { return "FFI ElGamal"; }
1✔
4449

4450
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4451
         botan_privkey_t priv;
1✔
4452

4453
         if(TEST_FFI_INIT(botan_privkey_create, (&priv, "ElGamal", "modp/ietf/1024", rng))) {
1✔
4454
            do_elgamal_test(priv, rng, result);
1✔
4455
         }
4456

4457
         if(TEST_FFI_INIT(botan_privkey_create_elgamal, (&priv, rng, 1024, 160))) {
1✔
4458
            do_elgamal_test(priv, rng, result);
1✔
4459
         }
4460
      }
1✔
4461

4462
   private:
4463
      static void do_elgamal_test(botan_privkey_t priv, botan_rng_t rng, Test::Result& result) {
2✔
4464
         TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
2✔
4465

4466
         botan_pubkey_t pub = nullptr;
2✔
4467
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
2✔
4468
         TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
2✔
4469

4470
         ffi_test_pubkey_export(result, pub, priv, rng);
2✔
4471
         botan_mp_t p = nullptr;
2✔
4472
         botan_mp_t g = nullptr;
2✔
4473
         botan_mp_t x = nullptr;
2✔
4474
         botan_mp_t y = nullptr;
2✔
4475
         botan_mp_init(&p);
2✔
4476
         botan_mp_init(&g);
2✔
4477
         botan_mp_init(&x);
2✔
4478
         botan_mp_init(&y);
2✔
4479

4480
         TEST_FFI_OK(botan_pubkey_get_field, (p, pub, "p"));
2✔
4481
         TEST_FFI_OK(botan_pubkey_get_field, (g, pub, "g"));
2✔
4482
         TEST_FFI_OK(botan_pubkey_get_field, (y, pub, "y"));
2✔
4483
         TEST_FFI_OK(botan_privkey_get_field, (x, priv, "x"));
2✔
4484

4485
         size_t p_len = 0;
2✔
4486
         TEST_FFI_OK(botan_mp_num_bytes, (p, &p_len));
2✔
4487

4488
         botan_privkey_t loaded_privkey;
2✔
4489
         TEST_FFI_OK(botan_privkey_load_elgamal, (&loaded_privkey, p, g, x));
2✔
4490

4491
         botan_pubkey_t loaded_pubkey;
2✔
4492
         TEST_FFI_OK(botan_pubkey_load_elgamal, (&loaded_pubkey, p, g, y));
2✔
4493

4494
         botan_mp_destroy(p);
2✔
4495
         botan_mp_destroy(g);
2✔
4496
         botan_mp_destroy(y);
2✔
4497
         botan_mp_destroy(x);
2✔
4498

4499
         std::vector<uint8_t> plaintext(16, 0xFF);
2✔
4500
         std::vector<uint8_t> ciphertext;
2✔
4501
         std::vector<uint8_t> decryption;
2✔
4502

4503
   #if defined(BOTAN_HAS_OAEP) && defined(BOTAN_HAS_SHA2_32)
4504
         const std::string padding = "OAEP(SHA-256)";
2✔
4505
   #else
4506
         const std::string padding = "Raw";
4507
   #endif
4508

4509
         // Test encryption
4510
         botan_pk_op_encrypt_t op_enc;
2✔
4511
         if(TEST_FFI_OK(botan_pk_op_encrypt_create, (&op_enc, loaded_pubkey, padding.c_str(), 0))) {
2✔
4512
            size_t ctext_len;
2✔
4513
            TEST_FFI_OK(botan_pk_op_encrypt_output_length, (op_enc, plaintext.size(), &ctext_len));
2✔
4514
            ciphertext.resize(ctext_len);
2✔
4515
            TEST_FFI_OK(botan_pk_op_encrypt,
2✔
4516
                        (op_enc, rng, ciphertext.data(), &ctext_len, plaintext.data(), plaintext.size()));
4517
            ciphertext.resize(ctext_len);
2✔
4518
            TEST_FFI_OK(botan_pk_op_encrypt_destroy, (op_enc));
4✔
4519
         }
4520

4521
         // Test decryption
4522
         botan_pk_op_decrypt_t op_dec;
2✔
4523
         if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&op_dec, loaded_privkey, padding.c_str(), 0))) {
2✔
4524
            size_t ptext_len;
2✔
4525
            TEST_FFI_OK(botan_pk_op_decrypt_output_length, (op_dec, ciphertext.size(), &ptext_len));
2✔
4526
            decryption.resize(ptext_len);
2✔
4527
            TEST_FFI_OK(botan_pk_op_decrypt,
2✔
4528
                        (op_dec, decryption.data(), &ptext_len, ciphertext.data(), ciphertext.size()));
4529
            decryption.resize(ptext_len);
2✔
4530
            TEST_FFI_OK(botan_pk_op_decrypt_destroy, (op_dec));
4✔
4531
         }
4532

4533
         result.test_eq("decryption worked", decryption, plaintext);
4✔
4534

4535
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
4536
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
2✔
4537
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
2✔
4538
         TEST_FFI_OK(botan_privkey_destroy, (priv));
4✔
4539
      }
8✔
4540
};
4541

4542
class FFI_DH_Test final : public FFI_Test {
×
4543
   public:
4544
      std::string name() const override { return "FFI DH"; }
1✔
4545

4546
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4547
         botan_privkey_t priv1;
1✔
4548
         if(!TEST_FFI_INIT(botan_privkey_create_dh, (&priv1, rng, "modp/ietf/2048"))) {
1✔
4549
            return;
×
4550
         }
4551

4552
         botan_privkey_t priv2;
1✔
4553
         REQUIRE_FFI_OK(botan_privkey_create_dh, (&priv2, rng, "modp/ietf/2048"));
1✔
4554

4555
         botan_pubkey_t pub1;
1✔
4556
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub1, priv1));
1✔
4557

4558
         botan_pubkey_t pub2;
1✔
4559
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub2, priv2));
1✔
4560

4561
         // Reload key-pair1 in order to test functions for key loading
4562
         botan_mp_t private_x;
1✔
4563
         botan_mp_t public_g;
1✔
4564
         botan_mp_t public_p;
1✔
4565
         botan_mp_t public_y;
1✔
4566

4567
         botan_mp_init(&private_x);
1✔
4568
         botan_mp_init(&public_g);
1✔
4569
         botan_mp_init(&public_p);
1✔
4570
         botan_mp_init(&public_y);
1✔
4571

4572
         TEST_FFI_OK(botan_privkey_get_field, (private_x, priv1, "x"));
1✔
4573
         TEST_FFI_OK(botan_pubkey_get_field, (public_g, pub1, "g"));
1✔
4574
         TEST_FFI_OK(botan_pubkey_get_field, (public_p, pub1, "p"));
1✔
4575
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub1, "y"));
1✔
4576

4577
         botan_privkey_t loaded_privkey1;
1✔
4578
         botan_pubkey_t loaded_pubkey1;
1✔
4579
         TEST_FFI_OK(botan_privkey_load_dh, (&loaded_privkey1, public_p, public_g, private_x));
1✔
4580
         TEST_FFI_OK(botan_pubkey_load_dh, (&loaded_pubkey1, public_p, public_g, public_y));
1✔
4581

4582
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey1, rng, 0));
1✔
4583
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
4584

4585
         botan_mp_t loaded_public_g;
1✔
4586
         botan_mp_t loaded_public_p;
1✔
4587
         botan_mp_t loaded_public_y;
1✔
4588
         botan_mp_init(&loaded_public_g);
1✔
4589
         botan_mp_init(&loaded_public_p);
1✔
4590
         botan_mp_init(&loaded_public_y);
1✔
4591

4592
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_g, loaded_pubkey1, "g"));
1✔
4593
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_p, loaded_pubkey1, "p"));
1✔
4594
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_y, loaded_pubkey1, "y"));
1✔
4595

4596
         int cmp;
1✔
4597

4598
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_g, public_g));
1✔
4599
         result.confirm("bigint_mp_cmp(g, g)", cmp == 0);
2✔
4600

4601
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_p, public_p));
1✔
4602
         result.confirm("bigint_mp_cmp(p, p)", cmp == 0);
2✔
4603

4604
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_y, public_y));
1✔
4605
         result.confirm("bigint_mp_cmp(y, y)", cmp == 0);
2✔
4606

4607
         botan_pk_op_ka_t ka1;
1✔
4608
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka1, loaded_privkey1, "Raw", 0));
1✔
4609
         botan_pk_op_ka_t ka2;
1✔
4610
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka2, priv2, "Raw", 0));
1✔
4611

4612
         size_t pubkey1_len = 0;
1✔
4613
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
4614
                     botan_pk_op_key_agreement_export_public,
4615
                     (priv1, nullptr, &pubkey1_len));
4616
         std::vector<uint8_t> pubkey1(pubkey1_len);
1✔
4617
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv1, pubkey1.data(), &pubkey1_len));
1✔
4618
         size_t pubkey2_len = 0;
1✔
4619
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
4620
                     botan_pk_op_key_agreement_export_public,
4621
                     (priv2, nullptr, &pubkey2_len));
4622
         std::vector<uint8_t> pubkey2(pubkey2_len);
1✔
4623
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv2, pubkey2.data(), &pubkey2_len));
1✔
4624

4625
         const size_t shared_key_len = 256;
1✔
4626

4627
         std::vector<uint8_t> key1(shared_key_len);
1✔
4628
         size_t key1_len = key1.size();
1✔
4629

4630
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
4631
                     (ka1, key1.data(), &key1_len, pubkey2.data(), pubkey2.size(), nullptr, 0));
4632

4633
         std::vector<uint8_t> key2(shared_key_len);
1✔
4634
         size_t key2_len = key2.size();
1✔
4635

4636
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
4637
                     (ka2, key2.data(), &key2_len, pubkey1.data(), pubkey1.size(), nullptr, 0));
4638

4639
         result.test_eq("shared DH key", key1, key2);
2✔
4640

4641
         TEST_FFI_OK(botan_mp_destroy, (private_x));
1✔
4642
         TEST_FFI_OK(botan_mp_destroy, (public_p));
1✔
4643
         TEST_FFI_OK(botan_mp_destroy, (public_g));
1✔
4644
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
4645

4646
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_p));
1✔
4647
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_g));
1✔
4648
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_y));
1✔
4649

4650
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka1));
1✔
4651
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka2));
1✔
4652
         TEST_FFI_OK(botan_privkey_destroy, (priv1));
1✔
4653
         TEST_FFI_OK(botan_privkey_destroy, (priv2));
1✔
4654
         TEST_FFI_OK(botan_pubkey_destroy, (pub1));
1✔
4655
         TEST_FFI_OK(botan_pubkey_destroy, (pub2));
1✔
4656
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey1));
1✔
4657
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
2✔
4658
      }
4✔
4659
};
4660

4661
class FFI_OID_Test final : public FFI_Test {
×
4662
   public:
4663
      std::string name() const override { return "FFI OID"; }
1✔
4664

4665
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4666
         botan_asn1_oid_t oid;
1✔
4667
         botan_asn1_oid_t new_oid;
1✔
4668
         botan_asn1_oid_t new_oid_from_string;
1✔
4669
         botan_asn1_oid_t oid_a;
1✔
4670
         botan_asn1_oid_t oid_b;
1✔
4671
         botan_asn1_oid_t oid_c;
1✔
4672

4673
         TEST_FFI_FAIL("empty oid", botan_oid_from_string, (&oid, ""));
2✔
4674
         TEST_FFI_OK(botan_oid_from_string, (&oid, "1.2.3.4.5"));
1✔
4675

4676
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_oid_from_string, (&new_oid, "a.a.a"));
1✔
4677
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_oid_from_string, (&new_oid, "0.40"));
1✔
4678
         TEST_FFI_RC(
1✔
4679
            BOTAN_FFI_ERROR_BAD_PARAMETER, botan_oid_from_string, (&new_oid, "random-name-that-definitely-has-no-oid"));
4680

4681
         TEST_FFI_OK(botan_oid_from_string, (&new_oid, "1.2.3.4.5.6.7.8"));
1✔
4682
         TEST_FFI_OK(botan_oid_register, (new_oid, "random-name-that-definitely-has-no-oid"));
1✔
4683

4684
         TEST_FFI_OK(botan_oid_from_string, (&new_oid_from_string, "random-name-that-definitely-has-no-oid"));
1✔
4685
         TEST_FFI_RC(1, botan_oid_equal, (new_oid, new_oid_from_string));
1✔
4686

4687
         TEST_FFI_OK(botan_oid_from_string, (&oid_a, "1.2.3.4.5.6"));
1✔
4688
         TEST_FFI_OK(botan_oid_from_string, (&oid_b, "1.2.3.4.5.6"));
1✔
4689
         TEST_FFI_OK(botan_oid_from_string, (&oid_c, "1.2.3.4.4"));
1✔
4690

4691
         TEST_FFI_RC(1, botan_oid_equal, (oid_a, oid_b));
1✔
4692
         TEST_FFI_RC(0, botan_oid_equal, (oid_a, oid_c));
1✔
4693

4694
         int res;
1✔
4695

4696
         TEST_FFI_OK(botan_oid_cmp, (&res, oid_a, oid_b));
1✔
4697
         result.confirm("oid_a and oid_b are equal", res == 0);
2✔
4698

4699
         TEST_FFI_OK(botan_oid_cmp, (&res, oid_a, oid_c));
1✔
4700
         result.confirm("oid_a is bigger", res == 1);
2✔
4701

4702
         TEST_FFI_OK(botan_oid_cmp, (&res, oid_c, oid_a));
1✔
4703
         result.confirm("oid_c is smaller", res == -1);
2✔
4704

4705
         TEST_FFI_OK(botan_oid_destroy, (oid));
1✔
4706
         TEST_FFI_OK(botan_oid_destroy, (new_oid));
1✔
4707
         TEST_FFI_OK(botan_oid_destroy, (new_oid_from_string));
1✔
4708
         TEST_FFI_OK(botan_oid_destroy, (oid_a));
1✔
4709
         TEST_FFI_OK(botan_oid_destroy, (oid_b));
1✔
4710
         TEST_FFI_OK(botan_oid_destroy, (oid_c));
1✔
4711

4712
         botan_privkey_t priv;
1✔
4713
         if(TEST_FFI_INIT(botan_privkey_create_rsa, (&priv, rng, 1024))) {
1✔
4714
            TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
1✔
4715

4716
            const std::string oid_rsa_expexted = "1.2.840.113549.1.1.1";
1✔
4717

4718
            botan_asn1_oid_t rsa_oid_priv;
1✔
4719
            botan_asn1_oid_t rsa_oid_pub;
1✔
4720
            botan_asn1_oid_t rsa_oid_expected;
1✔
4721
            botan_asn1_oid_t rsa_oid_from_name;
1✔
4722

4723
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_oid_from_string, (&rsa_oid_expected, nullptr));
1✔
4724
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_oid_from_string, (nullptr, "1.2.3.4.5"));
1✔
4725
            TEST_FFI_OK(botan_oid_from_string, (&rsa_oid_expected, oid_rsa_expexted.c_str()));
1✔
4726
            TEST_FFI_OK(botan_privkey_oid, (&rsa_oid_priv, priv));
1✔
4727

4728
            TEST_FFI_RC(1, botan_oid_equal, (rsa_oid_priv, rsa_oid_expected));
1✔
4729

4730
            botan_pubkey_t pub;
1✔
4731
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
4732

4733
            TEST_FFI_OK(botan_pubkey_oid, (&rsa_oid_pub, pub));
1✔
4734
            TEST_FFI_RC(1, botan_oid_equal, (rsa_oid_pub, rsa_oid_expected));
1✔
4735

4736
            ViewStringSink oid_string;
1✔
4737
            TEST_FFI_OK(botan_oid_view_string, (rsa_oid_expected, oid_string.delegate(), oid_string.callback()));
1✔
4738
            std::string oid_actual = {oid_string.get().begin(), oid_string.get().end()};
2✔
4739

4740
            result.test_eq("oid to string", oid_actual, oid_rsa_expexted);
1✔
4741

4742
            TEST_FFI_OK(botan_oid_from_string, (&rsa_oid_from_name, "RSA"));
1✔
4743
            TEST_FFI_RC(1, botan_oid_equal, (rsa_oid_expected, rsa_oid_from_name));
1✔
4744

4745
            ViewStringSink rsa_name;
1✔
4746
            TEST_FFI_OK(botan_oid_view_name, (rsa_oid_from_name, rsa_name.delegate(), rsa_name.callback()));
1✔
4747
            std::string rsa_name_string = {rsa_name.get().begin(), rsa_name.get().end()};
2✔
4748
            result.test_eq("oid to name", rsa_name_string, "RSA");
2✔
4749

4750
            TEST_FFI_OK(botan_oid_destroy, (rsa_oid_priv));
1✔
4751
            TEST_FFI_OK(botan_oid_destroy, (rsa_oid_pub));
1✔
4752
            TEST_FFI_OK(botan_oid_destroy, (rsa_oid_expected));
1✔
4753
            TEST_FFI_OK(botan_oid_destroy, (rsa_oid_from_name));
1✔
4754

4755
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
4756
            TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
4757
         }
1✔
4758
      }
1✔
4759
};
4760

4761
class FFI_EC_Group_Test final : public FFI_Test {
×
4762
   public:
4763
      std::string name() const override { return "FFI EC Group"; }
1✔
4764

4765
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
4766
         int appl_spec_groups;
1✔
4767
         int named_group;
1✔
4768
         TEST_FFI_OK(botan_ec_group_supports_application_specific_group, (&appl_spec_groups));
1✔
4769
         TEST_FFI_OK(botan_ec_group_supports_named_group, ("secp256r1", &named_group));
1✔
4770
         result.confirm("application specific groups support matches build",
2✔
4771
                        appl_spec_groups == 1,
4772
                        Botan::EC_Group::supports_application_specific_group());
1✔
4773
         result.confirm(
2✔
4774
            "named group support matches build", named_group == 1, Botan::EC_Group::supports_named_group("secp256r1"));
1✔
4775

4776
         if(named_group == 1) {
1✔
4777
            botan_ec_group_t group_from_name;
1✔
4778
            botan_asn1_oid_t oid_from_name;
1✔
4779
            botan_mp_t p_from_name;
1✔
4780
            botan_mp_t a_from_name;
1✔
4781
            botan_mp_t b_from_name;
1✔
4782
            botan_mp_t g_x_from_name;
1✔
4783
            botan_mp_t g_y_from_name;
1✔
4784
            botan_mp_t order_from_name;
1✔
4785

4786
            TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_ec_group_from_name, (&group_from_name, ""));
1✔
4787

4788
            TEST_FFI_OK(botan_ec_group_from_name, (&group_from_name, "secp256r1"));
1✔
4789

4790
            get_group_parameters(group_from_name,
1✔
4791
                                 &oid_from_name,
4792
                                 &p_from_name,
4793
                                 &a_from_name,
4794
                                 &b_from_name,
4795
                                 &g_x_from_name,
4796
                                 &g_y_from_name,
4797
                                 &order_from_name,
4798
                                 result);
4799

4800
            botan_asn1_oid_t group_oid;
1✔
4801
            botan_ec_group_t group_from_oid;
1✔
4802
            botan_asn1_oid_t oid_from_oid;
1✔
4803
            botan_mp_t p_from_oid;
1✔
4804
            botan_mp_t a_from_oid;
1✔
4805
            botan_mp_t b_from_oid;
1✔
4806
            botan_mp_t g_x_from_oid;
1✔
4807
            botan_mp_t g_y_from_oid;
1✔
4808
            botan_mp_t order_from_oid;
1✔
4809

4810
            TEST_FFI_OK(botan_oid_from_string, (&group_oid, "1.2.840.10045.3.1.7"));
1✔
4811

4812
            TEST_FFI_OK(botan_ec_group_from_oid, (&group_from_oid, group_oid));
1✔
4813

4814
            get_group_parameters(group_from_oid,
1✔
4815
                                 &oid_from_oid,
4816
                                 &p_from_oid,
4817
                                 &a_from_oid,
4818
                                 &b_from_oid,
4819
                                 &g_x_from_oid,
4820
                                 &g_y_from_oid,
4821
                                 &order_from_oid,
4822
                                 result);
4823

4824
            TEST_FFI_RC(1, botan_oid_equal, (group_oid, oid_from_oid));
1✔
4825
            TEST_FFI_RC(1, botan_oid_equal, (oid_from_name, oid_from_oid));
1✔
4826

4827
            if(appl_spec_groups == 1) {
1✔
4828
               botan_asn1_oid_t group_parameter_oid;
1✔
4829
               botan_mp_t p_parameter;
1✔
4830
               botan_mp_t a_parameter;
1✔
4831
               botan_mp_t b_parameter;
1✔
4832
               botan_mp_t g_x_parameter;
1✔
4833
               botan_mp_t g_y_parameter;
1✔
4834
               botan_mp_t order_parameter;
1✔
4835

4836
               botan_ec_group_t group_from_parameters;
1✔
4837
               botan_asn1_oid_t oid_from_parameters;
1✔
4838
               botan_mp_t p_from_parameters;
1✔
4839
               botan_mp_t a_from_parameters;
1✔
4840
               botan_mp_t b_from_parameters;
1✔
4841
               botan_mp_t g_x_from_parameters;
1✔
4842
               botan_mp_t g_y_from_parameters;
1✔
4843
               botan_mp_t order_from_parameters;
1✔
4844

4845
               TEST_FFI_OK(botan_oid_from_string, (&group_parameter_oid, "1.3.6.1.4.1.25258.100.0"));
1✔
4846
               botan_oid_register(group_parameter_oid, "secp256r1-but-manually-registered");
1✔
4847
               botan_mp_init(&p_parameter);
1✔
4848
               botan_mp_init(&a_parameter);
1✔
4849
               botan_mp_init(&b_parameter);
1✔
4850
               botan_mp_init(&g_x_parameter);
1✔
4851
               botan_mp_init(&g_y_parameter);
1✔
4852
               botan_mp_init(&order_parameter);
1✔
4853

4854
               botan_mp_set_from_str(p_parameter, "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF");
1✔
4855
               botan_mp_set_from_str(a_parameter, "0xFFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC");
1✔
4856
               botan_mp_set_from_str(b_parameter, "0x5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B");
1✔
4857
               botan_mp_set_from_str(g_x_parameter,
1✔
4858
                                     "0x6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296");
4859
               botan_mp_set_from_str(g_y_parameter,
1✔
4860
                                     "0x4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5");
4861
               botan_mp_set_from_str(order_parameter,
1✔
4862
                                     "0xFFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551");
4863

4864
               TEST_FFI_OK(botan_ec_group_from_params,
1✔
4865
                           (&group_from_parameters,
4866
                            group_parameter_oid,
4867
                            p_parameter,
4868
                            a_parameter,
4869
                            b_parameter,
4870
                            g_x_parameter,
4871
                            g_y_parameter,
4872
                            order_parameter));
4873

4874
               get_group_parameters(group_from_parameters,
1✔
4875
                                    &oid_from_parameters,
4876
                                    &p_from_parameters,
4877
                                    &a_from_parameters,
4878
                                    &b_from_parameters,
4879
                                    &g_x_from_parameters,
4880
                                    &g_y_from_parameters,
4881
                                    &order_from_parameters,
4882
                                    result);
4883

4884
               botan_ec_group_t group_from_registered_oid;
1✔
4885

4886
               TEST_FFI_OK(botan_ec_group_from_name, (&group_from_registered_oid, "secp256r1-but-manually-registered"));
1✔
4887

4888
               // we registered this group under a different oid
4889
               TEST_FFI_RC(0, botan_oid_equal, (oid_from_oid, oid_from_parameters));
1✔
4890

4891
               TEST_FFI_RC(1, botan_ec_group_equal, (group_from_name, group_from_parameters));
1✔
4892
               TEST_FFI_RC(1, botan_ec_group_equal, (group_from_parameters, group_from_registered_oid));
1✔
4893

4894
               std::vector<std::tuple<botan_mp_t, botan_mp_t>> parameters_inner = {
1✔
4895
                  {p_from_name, p_from_parameters},
4896
                  {a_from_name, a_from_parameters},
4897
                  {b_from_name, b_from_parameters},
4898
                  {g_x_from_name, g_x_from_parameters},
4899
                  {g_y_from_name, g_y_from_parameters},
4900
                  {order_from_name, order_from_parameters}};
1✔
4901

4902
               for(auto [x, y] : parameters_inner) {
7✔
4903
                  TEST_FFI_RC(1, botan_mp_equal, (x, y));
6✔
4904
                  botan_mp_destroy(y);
6✔
4905
               }
4906

4907
               botan_mp_destroy(p_parameter);
1✔
4908
               botan_mp_destroy(a_parameter);
1✔
4909
               botan_mp_destroy(b_parameter);
1✔
4910
               botan_mp_destroy(g_x_parameter);
1✔
4911
               botan_mp_destroy(g_y_parameter);
1✔
4912
               botan_mp_destroy(order_parameter);
1✔
4913

4914
               botan_oid_destroy(group_parameter_oid);
1✔
4915
               botan_oid_destroy(oid_from_parameters);
1✔
4916

4917
               TEST_FFI_OK(botan_ec_group_destroy, (group_from_parameters));
1✔
4918
               TEST_FFI_OK(botan_ec_group_destroy, (group_from_registered_oid));
2✔
4919
            }
1✔
4920

4921
            botan_oid_destroy(oid_from_name);
1✔
4922
            botan_oid_destroy(group_oid);
1✔
4923
            botan_oid_destroy(oid_from_oid);
1✔
4924

4925
            std::vector<std::tuple<botan_mp_t, botan_mp_t>> parameters = {{p_from_name, p_from_oid},
1✔
4926
                                                                          {a_from_name, a_from_oid},
4927
                                                                          {b_from_name, b_from_oid},
4928
                                                                          {g_x_from_name, g_x_from_oid},
4929
                                                                          {g_y_from_name, g_y_from_oid},
4930
                                                                          {order_from_name, order_from_oid}};
1✔
4931

4932
            for(auto [x, y] : parameters) {
7✔
4933
               TEST_FFI_RC(1, botan_mp_equal, (x, y));
6✔
4934
               botan_mp_destroy(x);
6✔
4935
               botan_mp_destroy(y);
6✔
4936
            }
4937

4938
            botan_ec_group_t secp384r1;
1✔
4939
            botan_ec_group_t secp384r1_with_seed;
1✔
4940

4941
            TEST_FFI_OK(botan_ec_group_from_name, (&secp384r1, "secp384r1"));
1✔
4942
            TEST_FFI_OK(botan_ec_group_from_pem,
2✔
4943
                        (&secp384r1_with_seed, Test::read_data_file("x509/ecc/secp384r1_seed.pem").c_str()));
4944

4945
            botan_mp_t p;
1✔
4946
            botan_mp_t p_with_seed;
1✔
4947
            TEST_FFI_OK(botan_ec_group_get_p, (&p, secp384r1));
1✔
4948
            TEST_FFI_OK(botan_ec_group_get_p, (&p_with_seed, secp384r1_with_seed));
1✔
4949
            TEST_FFI_RC(1, botan_mp_equal, (p, p_with_seed));
1✔
4950
            botan_mp_destroy(p);
1✔
4951
            botan_mp_destroy(p_with_seed);
1✔
4952

4953
            TEST_FFI_RC(0, botan_ec_group_equal, (group_from_name, secp384r1));
1✔
4954
            TEST_FFI_RC(1, botan_ec_group_equal, (group_from_name, group_from_oid));
1✔
4955

4956
            ViewBytesSink der_bytes;
1✔
4957
            TEST_FFI_OK(botan_ec_group_view_der, (group_from_name, der_bytes.delegate(), der_bytes.callback()));
1✔
4958
            botan_ec_group_t group_from_ber;
1✔
4959
            TEST_FFI_OK(
1✔
4960
               botan_ec_group_from_ber,
4961
               (&group_from_ber, reinterpret_cast<const uint8_t*>(der_bytes.get().data()), der_bytes.get().size()));
4962

4963
            ViewStringSink pem_string;
1✔
4964
            TEST_FFI_OK(botan_ec_group_view_pem, (group_from_name, pem_string.delegate(), pem_string.callback()));
1✔
4965
            std::string pem_actual = {pem_string.get().begin(), pem_string.get().end()};
2✔
4966

4967
            botan_ec_group_t group_from_pem;
1✔
4968
            TEST_FFI_OK(botan_ec_group_from_pem, (&group_from_pem, pem_actual.c_str()));
1✔
4969

4970
            TEST_FFI_RC(1, botan_ec_group_equal, (group_from_name, group_from_ber));
1✔
4971
            TEST_FFI_RC(1, botan_ec_group_equal, (group_from_name, group_from_pem));
1✔
4972

4973
            botan_privkey_t priv;
1✔
4974
            TEST_FFI_OK(botan_ec_privkey_create, (&priv, "ECDSA", secp384r1, rng));
1✔
4975
            std::array<char, 32> namebuf{};
1✔
4976
            size_t name_len = namebuf.size();
1✔
4977

4978
            TEST_FFI_OK(botan_privkey_algo_name, (priv, namebuf.data(), &name_len));
1✔
4979
            result.test_eq("Key name is expected value", namebuf.data(), "ECDSA");
1✔
4980

4981
            botan_privkey_destroy(priv);
1✔
4982

4983
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_name));
1✔
4984
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_oid));
1✔
4985
            TEST_FFI_OK(botan_ec_group_destroy, (secp384r1));
1✔
4986
            TEST_FFI_OK(botan_ec_group_destroy, (secp384r1_with_seed));
1✔
4987
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_ber));
1✔
4988
            TEST_FFI_OK(botan_ec_group_destroy, (group_from_pem));
2✔
4989
         }
3✔
4990
      }
1✔
4991

4992
   private:
4993
      static void get_group_parameters(botan_ec_group_t ec_group,
3✔
4994
                                       botan_asn1_oid_t* oid,
4995
                                       botan_mp_t* p,
4996
                                       botan_mp_t* a,
4997
                                       botan_mp_t* b,
4998
                                       botan_mp_t* g_x,
4999
                                       botan_mp_t* g_y,
5000
                                       botan_mp_t* order,
5001
                                       Test::Result& result) {
5002
         TEST_FFI_OK(botan_ec_group_get_curve_oid, (oid, ec_group));
3✔
5003
         TEST_FFI_OK(botan_ec_group_get_p, (p, ec_group));
3✔
5004
         TEST_FFI_OK(botan_ec_group_get_a, (a, ec_group));
3✔
5005
         TEST_FFI_OK(botan_ec_group_get_b, (b, ec_group));
3✔
5006
         TEST_FFI_OK(botan_ec_group_get_g_x, (g_x, ec_group));
3✔
5007
         TEST_FFI_OK(botan_ec_group_get_g_y, (g_y, ec_group));
3✔
5008
         TEST_FFI_OK(botan_ec_group_get_order, (order, ec_group));
3✔
5009
      }
3✔
5010
};
5011

5012
// NOLINTEND(*-init-variables)
5013

5014
BOTAN_REGISTER_TEST("ffi", "ffi_utils", FFI_Utils_Test);
5015
BOTAN_REGISTER_TEST("ffi", "ffi_rng", FFI_RNG_Test);
5016
BOTAN_REGISTER_TEST("ffi", "ffi_rsa_cert", FFI_RSA_Cert_Test);
5017
BOTAN_REGISTER_TEST("ffi", "ffi_zfec", FFI_ZFEC_Test);
5018
BOTAN_REGISTER_TEST("ffi", "ffi_crl", FFI_CRL_Test);
5019
BOTAN_REGISTER_TEST("ffi", "ffi_cert_validation", FFI_Cert_Validation_Test);
5020
BOTAN_REGISTER_TEST("ffi", "ffi_cert_creation", FFI_Cert_Creation_Test);
5021
BOTAN_REGISTER_TEST("ffi", "ffi_x509_rpki", FFI_X509_RPKI_Test);
5022
BOTAN_REGISTER_TEST("ffi", "ffi_ecdsa_certificate", FFI_ECDSA_Certificate_Test);
5023
BOTAN_REGISTER_TEST("ffi", "ffi_pkcs_hashid", FFI_PKCS_Hashid_Test);
5024
BOTAN_REGISTER_TEST("ffi", "ffi_cbc_cipher", FFI_CBC_Cipher_Test);
5025
BOTAN_REGISTER_TEST("ffi", "ffi_gcm", FFI_GCM_Test);
5026
BOTAN_REGISTER_TEST("ffi", "ffi_chacha", FFI_ChaCha20Poly1305_Test);
5027
BOTAN_REGISTER_TEST("ffi", "ffi_eax", FFI_EAX_Test);
5028
BOTAN_REGISTER_TEST("ffi", "ffi_aead", FFI_AEAD_Test);
5029
BOTAN_REGISTER_TEST("ffi", "ffi_streamcipher", FFI_StreamCipher_Test);
5030
BOTAN_REGISTER_TEST("ffi", "ffi_hashfunction", FFI_HashFunction_Test);
5031
BOTAN_REGISTER_TEST("ffi", "ffi_mac", FFI_MAC_Test);
5032
BOTAN_REGISTER_TEST("ffi", "ffi_scrypt", FFI_Scrypt_Test);
5033
BOTAN_REGISTER_TEST("ffi", "ffi_kdf", FFI_KDF_Test);
5034
BOTAN_REGISTER_TEST("ffi", "ffi_blockcipher", FFI_Blockcipher_Test);
5035
BOTAN_REGISTER_TEST("ffi", "ffi_errorhandling", FFI_ErrorHandling_Test);
5036
BOTAN_REGISTER_TEST("ffi", "ffi_base64", FFI_Base64_Test);
5037
BOTAN_REGISTER_TEST("ffi", "ffi_hex", FFI_Hex_Test);
5038
BOTAN_REGISTER_TEST("ffi", "ffi_mp", FFI_MP_Test);
5039
BOTAN_REGISTER_TEST("ffi", "ffi_fpe", FFI_FPE_Test);
5040
BOTAN_REGISTER_TEST("ffi", "ffi_totp", FFI_TOTP_Test);
5041
BOTAN_REGISTER_TEST("ffi", "ffi_hotp", FFI_HOTP_Test);
5042
BOTAN_REGISTER_TEST("ffi", "ffi_keywrap", FFI_Keywrap_Test);
5043
BOTAN_REGISTER_TEST("ffi", "ffi_xmss", FFI_XMSS_Test);
5044
BOTAN_REGISTER_TEST("ffi", "ffi_rsa", FFI_RSA_Test);
5045
BOTAN_REGISTER_TEST("ffi", "ffi_dsa", FFI_DSA_Test);
5046
BOTAN_REGISTER_TEST("ffi", "ffi_ecdsa", FFI_ECDSA_Test);
5047
BOTAN_REGISTER_TEST("ffi", "ffi_sm2_sig", FFI_SM2_Sig_Test);
5048
BOTAN_REGISTER_TEST("ffi", "ffi_sm2_enc", FFI_SM2_Enc_Test);
5049
BOTAN_REGISTER_TEST("ffi", "ffi_ecdh", FFI_ECDH_Test);
5050
BOTAN_REGISTER_TEST("ffi", "ffi_mceliece", FFI_McEliece_Test);
5051
BOTAN_REGISTER_TEST("ffi", "ffi_ed25519", FFI_Ed25519_Test);
5052
BOTAN_REGISTER_TEST("ffi", "ffi_ed448", FFI_Ed448_Test);
5053
BOTAN_REGISTER_TEST("ffi", "ffi_x25519", FFI_X25519_Test);
5054
BOTAN_REGISTER_TEST("ffi", "ffi_x448", FFI_X448_Test);
5055
BOTAN_REGISTER_TEST("ffi", "ffi_kyber512", FFI_Kyber512_Test);
5056
BOTAN_REGISTER_TEST("ffi", "ffi_kyber768", FFI_Kyber768_Test);
5057
BOTAN_REGISTER_TEST("ffi", "ffi_kyber1024", FFI_Kyber1024_Test);
5058
BOTAN_REGISTER_TEST("ffi", "ffi_ml_kem", FFI_ML_KEM_Test);
5059
BOTAN_REGISTER_TEST("ffi", "ffi_ml_dsa", FFI_ML_DSA_Test);
5060
BOTAN_REGISTER_TEST("ffi", "ffi_slh_dsa", FFI_SLH_DSA_Test);
5061
BOTAN_REGISTER_TEST("ffi", "ffi_frodokem", FFI_FrodoKEM_Test);
5062
BOTAN_REGISTER_TEST("ffi", "ffi_cmce", FFI_Classic_McEliece_Test);
5063
BOTAN_REGISTER_TEST("ffi", "ffi_elgamal", FFI_ElGamal_Test);
5064
BOTAN_REGISTER_TEST("ffi", "ffi_dh", FFI_DH_Test);
5065
BOTAN_REGISTER_TEST("ffi", "ffi_oid", FFI_OID_Test);
5066
BOTAN_REGISTER_TEST("ffi", "ffi_ec_group", FFI_EC_Group_Test);
5067

5068
#endif
5069

5070
}  // namespace
5071

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

© 2026 Coveralls, Inc