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

randombit / botan / 5111374265

29 May 2023 11:19AM UTC coverage: 92.227% (+0.5%) from 91.723%
5111374265

push

github

randombit
Next release will be 3.1.0. Update release notes

75588 of 81959 relevant lines covered (92.23%)

11886470.91 hits per line

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

96.96
/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/ffi.h>
17
   #include <botan/hex.h>
18
   #include <botan/internal/loadstor.h>
19
   #include <set>
20
#endif
21

22
namespace Botan_Tests {
23

24
namespace {
25

26
#if defined(BOTAN_HAS_FFI)
27

28
   #define TEST_FFI_OK(func, args) result.test_rc_ok(#func, func args)
29
   #define TEST_FFI_INIT(func, args) result.test_rc_init(#func, func args)
30
   #define TEST_FFI_FAIL(msg, func, args) result.test_rc_fail(#func, msg, func args)
31
   #define TEST_FFI_RC(rc, func, args) result.test_rc(#func, rc, func args)
32

33
   #define REQUIRE_FFI_OK(func, args)                           \
34
      if(!TEST_FFI_OK(func, args)) {                            \
35
         result.test_note("Exiting test early due to failure"); \
36
         return;                                                \
37
      }
38

39
class FFI_Test : public Test {
36✔
40
   public:
41
      std::vector<Test::Result> run() override {
36✔
42
         Test::Result result(this->name());
36✔
43

44
         botan_rng_t rng;
36✔
45
         if(botan_rng_init(&rng, "system") != 0) {
36✔
46
            result.test_failure("Failed to init RNG");
×
47
            return {result};
×
48
         }
49

50
         result.start_timer();
36✔
51
         ffi_test(result, rng);
36✔
52
         result.end_timer();
36✔
53

54
         botan_rng_destroy(rng);
36✔
55

56
         return {result};
72✔
57
      }
36✔
58

59
   private:
60
      virtual std::string name() const = 0;
61
      virtual void ffi_test(Test::Result& result, botan_rng_t rng) = 0;
62
};
63

64
void ffi_test_pubkey_export(Test::Result& result, botan_pubkey_t pub, botan_privkey_t priv, botan_rng_t rng) {
11✔
65
   // export public key
66
   size_t pubkey_len = 0;
11✔
67
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
68
               botan_pubkey_export,
69
               (pub, nullptr, &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
70

71
   std::vector<uint8_t> pubkey(pubkey_len);
11✔
72
   TEST_FFI_OK(botan_pubkey_export, (pub, pubkey.data(), &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
11✔
73

74
   pubkey_len = 0;
11✔
75
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
76
               botan_pubkey_export,
77
               (pub, nullptr, &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
78

79
   pubkey.resize(pubkey_len);
11✔
80
   TEST_FFI_OK(botan_pubkey_export, (pub, pubkey.data(), &pubkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
11✔
81

82
   // reimport exported public key
83
   botan_pubkey_t pub_copy;
11✔
84
   TEST_FFI_OK(botan_pubkey_load, (&pub_copy, pubkey.data(), pubkey_len));
11✔
85
   TEST_FFI_OK(botan_pubkey_check_key, (pub_copy, rng, 0));
11✔
86
   TEST_FFI_OK(botan_pubkey_destroy, (pub_copy));
11✔
87

88
   // export private key
89
   std::vector<uint8_t> privkey;
11✔
90
   size_t privkey_len = 0;
11✔
91

92
   // call with nullptr to query the length
93
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
94
               botan_privkey_export,
95
               (priv, nullptr, &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
96

97
   privkey.resize(privkey_len);
11✔
98
   privkey_len = privkey.size();  // set buffer size
11✔
99

100
   TEST_FFI_OK(botan_privkey_export, (priv, privkey.data(), &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
11✔
101

102
   privkey.resize(privkey_len);
11✔
103

104
   result.test_gte("Reasonable size", privkey.size(), 32);
11✔
105

106
   // reimport exported private key
107
   botan_privkey_t copy;
11✔
108
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), nullptr));
11✔
109
   botan_privkey_destroy(copy);
11✔
110

111
   // Now again for PEM
112
   privkey_len = 0;
11✔
113

114
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
115
               botan_privkey_export,
116
               (priv, nullptr, &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
117

118
   privkey.resize(privkey_len);
11✔
119
   TEST_FFI_OK(botan_privkey_export, (priv, privkey.data(), &privkey_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
11✔
120

121
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), nullptr));
11✔
122
   botan_privkey_destroy(copy);
11✔
123

124
   #if defined(BOTAN_HAS_AES) && defined(BOTAN_HAS_PKCS5_PBES2)
125
   const size_t pbkdf_iter = 1000;
11✔
126

127
   // export private key encrypted
128
   privkey_len = 0;
11✔
129
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
130
               botan_privkey_export_encrypted_pbkdf_iter,
131
               (priv, nullptr, &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_DER));
132

133
   privkey.resize(privkey_len);
11✔
134
   privkey_len = privkey.size();
11✔
135

136
   TEST_FFI_OK(
11✔
137
      botan_privkey_export_encrypted_pbkdf_iter,
138
      (priv, privkey.data(), &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_DER));
139

140
   // reimport encrypted private key
141
   botan_privkey_load(&copy, rng, privkey.data(), privkey.size(), "password");
11✔
142
   botan_privkey_destroy(copy);
11✔
143

144
   privkey_len = 0;
11✔
145
   TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
11✔
146
               botan_privkey_export_encrypted_pbkdf_iter,
147
               (priv, nullptr, &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
148

149
   privkey.resize(privkey_len);
11✔
150
   TEST_FFI_OK(
11✔
151
      botan_privkey_export_encrypted_pbkdf_iter,
152
      (priv, privkey.data(), &privkey_len, rng, "password", pbkdf_iter, "", "", BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
153

154
   privkey.resize(privkey_len * 2);
11✔
155
   privkey_len = privkey.size();
11✔
156
   const uint32_t pbkdf_msec = 100;
11✔
157
   size_t pbkdf_iters_out = 0;
11✔
158

159
      #if defined(BOTAN_HAS_SCRYPT)
160
   const std::string pbe_hash = "Scrypt";
11✔
161
      #else
162
   const std::string pbe_hash = "SHA-512";
163
      #endif
164

165
      #if defined(BOTAN_HAS_AEAD_GCM)
166
   const std::string pbe_cipher = "AES-256/GCM";
11✔
167
      #else
168
   const std::string pbe_cipher = "AES-256/CBC";
169
      #endif
170

171
   TEST_FFI_OK(botan_privkey_export_encrypted_pbkdf_msec,
11✔
172
               (priv,
173
                privkey.data(),
174
                &privkey_len,
175
                rng,
176
                "password",
177
                pbkdf_msec,
178
                &pbkdf_iters_out,
179
                pbe_cipher.c_str(),
180
                pbe_hash.c_str(),
181
                0));
182

183
   if(pbe_hash == "Scrypt") {
11✔
184
      result.test_eq("Scrypt iters set to zero in this API", pbkdf_iters_out, 0);
22✔
185
   } else {
186
      // PBKDF2 currently always rounds to multiple of 2000
187
      result.test_eq("Expected PBKDF2 iters", pbkdf_iters_out % 2000, 0);
×
188
   }
189

190
   privkey.resize(privkey_len);
11✔
191

192
   TEST_FFI_OK(botan_privkey_load, (&copy, rng, privkey.data(), privkey.size(), "password"));
11✔
193
   botan_privkey_destroy(copy);
11✔
194
   #endif
195

196
   // calculate fingerprint
197
   size_t strength = 0;
11✔
198
   TEST_FFI_OK(botan_pubkey_estimated_strength, (pub, &strength));
11✔
199
   result.test_gte("estimated strength", strength, 1);
11✔
200

201
   size_t fingerprint_len = 0;
11✔
202
   TEST_FFI_RC(
11✔
203
      BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_pubkey_fingerprint, (pub, "SHA-256", nullptr, &fingerprint_len));
204

205
   std::vector<uint8_t> fingerprint(fingerprint_len);
11✔
206
   TEST_FFI_OK(botan_pubkey_fingerprint, (pub, "SHA-256", fingerprint.data(), &fingerprint_len));
22✔
207
}
33✔
208

209
class FFI_Utils_Test final : public FFI_Test {
×
210
   public:
211
      std::string name() const override { return "FFI Utils"; }
1✔
212

213
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
214
         result.test_is_eq("FFI API version", botan_ffi_api_version(), uint32_t(BOTAN_HAS_FFI));
1✔
215
         result.test_is_eq("Major version", botan_version_major(), Botan::version_major());
1✔
216
         result.test_is_eq("Minor version", botan_version_minor(), Botan::version_minor());
1✔
217
         result.test_is_eq("Patch version", botan_version_patch(), Botan::version_patch());
1✔
218
         result.test_is_eq("Botan version", botan_version_string(), Botan::version_cstr());
1✔
219
         result.test_is_eq("Botan version datestamp", botan_version_datestamp(), Botan::version_datestamp());
1✔
220
         result.test_is_eq("FFI supports its own version", botan_ffi_supports_api(botan_ffi_api_version()), 0);
1✔
221

222
         result.test_is_eq("FFI supports 2.0 version", botan_ffi_supports_api(20150515), 0);
1✔
223
         result.test_is_eq("FFI supports 2.1 version", botan_ffi_supports_api(20170327), 0);
1✔
224
         result.test_is_eq("FFI supports 2.3 version", botan_ffi_supports_api(20170815), 0);
1✔
225
         result.test_is_eq("FFI supports 2.8 version", botan_ffi_supports_api(20180713), 0);
1✔
226

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

229
         const std::vector<uint8_t> mem1 = {0xFF, 0xAA, 0xFF};
1✔
230
         const std::vector<uint8_t> mem2 = {0xFF, 0xA9, 0xFF};
1✔
231

232
         TEST_FFI_RC(0, botan_constant_time_compare, (mem1.data(), mem1.data(), mem1.size()));
1✔
233
         TEST_FFI_RC(-1, botan_constant_time_compare, (mem1.data(), mem2.data(), mem1.size()));
1✔
234

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

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

241
         std::string outstr;
1✔
242
         std::vector<uint8_t> outbuf;
1✔
243

244
         outstr.resize(2 * bin.size());
1✔
245
         TEST_FFI_OK(botan_hex_encode, (bin.data(), bin.size(), &outstr[0], 0));
1✔
246
         result.test_eq("uppercase hex", outstr, "AADE01");
2✔
247

248
         TEST_FFI_OK(botan_hex_encode, (bin.data(), bin.size(), &outstr[0], BOTAN_FFI_HEX_LOWER_CASE));
1✔
249
         result.test_eq("lowercase hex", outstr, "aade01");
2✔
250
      }
5✔
251
};
252

253
class FFI_RNG_Test final : public FFI_Test {
×
254
   public:
255
      std::string name() const override { return "FFI RNG"; }
1✔
256

257
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
258
         // RNG test and initialization
259
         botan_rng_t rng;
1✔
260
         botan_rng_t system_rng;
1✔
261
         botan_rng_t hwrng_rng = nullptr;
1✔
262
         botan_rng_t null_rng;
1✔
263
         botan_rng_t custom_rng;
1✔
264

265
         TEST_FFI_FAIL("invalid rng type", botan_rng_init, (&rng, "invalid_type"));
2✔
266

267
         REQUIRE_FFI_OK(botan_rng_init, (&system_rng, "system"));
1✔
268
         REQUIRE_FFI_OK(botan_rng_init, (&null_rng, "null"));
1✔
269

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

273
         std::vector<uint8_t> outbuf(512);
1✔
274

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

278
         if(rc != 0) {
1✔
279
            REQUIRE_FFI_OK(botan_rng_init, (&rng, "user"));
×
280
            REQUIRE_FFI_OK(botan_rng_destroy, (rng));
×
281
         }
282

283
         if(rc == 0) {
1✔
284
            TEST_FFI_OK(botan_rng_get, (rng, outbuf.data(), outbuf.size()));
1✔
285
            TEST_FFI_OK(botan_rng_reseed, (rng, 256));
1✔
286

287
            TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, botan_rng_reseed_from_rng, (rng, null_rng, 256));
1✔
288
            if(hwrng_rng) {
1✔
289
               TEST_FFI_OK(botan_rng_reseed_from_rng, (rng, hwrng_rng, 256));
2✔
290
            }
291
            TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT_STATE, botan_rng_get, (null_rng, outbuf.data(), outbuf.size()));
1✔
292

293
            TEST_FFI_OK(botan_rng_destroy, (rng));
2✔
294
         }
295

296
         if(TEST_FFI_OK(botan_rng_init, (&rng, "user"))) {
1✔
297
            TEST_FFI_OK(botan_rng_get, (rng, outbuf.data(), outbuf.size()));
1✔
298
            TEST_FFI_OK(botan_rng_reseed, (rng, 256));
1✔
299

300
            TEST_FFI_OK(botan_rng_reseed_from_rng, (rng, system_rng, 256));
1✔
301

302
            uint8_t not_really_entropy[32] = {0};
1✔
303
            TEST_FFI_OK(botan_rng_add_entropy, (rng, not_really_entropy, 32));
2✔
304
         }
305

306
         uint8_t system_rng_buf[4096];
1✔
307
         TEST_FFI_OK(botan_system_rng_get, (system_rng_buf, sizeof(system_rng_buf)));
1✔
308

309
         size_t cb_counter = 0;
1✔
310

311
         auto custom_get_cb = +[](void* context, uint8_t* out, size_t out_len) -> int {
1✔
312
            Botan::set_mem(out, out_len, 0x12);
313
            BOTAN_UNUSED(out, out_len);
314
            (*(static_cast<size_t*>(context)))++;
315
            return 0;
316
         };
317

318
         auto custom_add_entropy_cb = +[](void* context, const uint8_t input[], size_t length) -> int {
1✔
319
            BOTAN_UNUSED(input, length);
320
            (*(static_cast<size_t*>(context)))++;
321
            return 0;
322
         };
323

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

326
         if(TEST_FFI_OK(
2✔
327
               botan_rng_init_custom,
328
               (&custom_rng, "custom rng", &cb_counter, custom_get_cb, custom_add_entropy_cb, custom_destroy_cb))) {
329
            Botan::clear_mem(outbuf.data(), outbuf.size());
1✔
330
            TEST_FFI_OK(botan_rng_get, (custom_rng, outbuf.data(), outbuf.size()));
1✔
331
            result.test_eq("custom_get_cb called", cb_counter, 1);
1✔
332
            std::vector<uint8_t> pattern(outbuf.size(), 0x12);
1✔
333
            result.test_eq("custom_get_cb returned bytes", pattern, outbuf);
1✔
334

335
            TEST_FFI_OK(botan_rng_reseed, (custom_rng, 256));
1✔
336
            result.test_eq("custom_add_entropy_cb called", cb_counter, 2);
1✔
337

338
            TEST_FFI_OK(botan_rng_reseed_from_rng, (custom_rng, system_rng, 256));
1✔
339
            result.test_eq("custom_add_entropy_cb called", cb_counter, 3);
1✔
340

341
            uint8_t not_really_entropy[32] = {0};
1✔
342
            TEST_FFI_OK(botan_rng_add_entropy, (custom_rng, not_really_entropy, 32));
1✔
343
            result.test_eq("custom_add_entropy_cb called", cb_counter, 4);
1✔
344

345
            TEST_FFI_OK(botan_rng_destroy, (custom_rng));
1✔
346
            result.test_eq("custom_destroy_cb called", cb_counter, 5);
2✔
347
         }
1✔
348

349
         TEST_FFI_OK(botan_rng_destroy, (rng));
1✔
350
         TEST_FFI_OK(botan_rng_destroy, (null_rng));
1✔
351
         TEST_FFI_OK(botan_rng_destroy, (system_rng));
1✔
352
         TEST_FFI_OK(botan_rng_destroy, (hwrng_rng));
2✔
353
      }
1✔
354
};
355

356
class FFI_RSA_Cert_Test final : public FFI_Test {
×
357
   public:
358
      std::string name() const override { return "FFI RSA cert"; }
1✔
359

360
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
361
         botan_x509_cert_t cert;
1✔
362
         if(TEST_FFI_INIT(botan_x509_cert_load_file, (&cert, Test::data_file("x509/ocsp/randombit.pem").c_str()))) {
4✔
363
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (cert, "randombit.net"));
1✔
364
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (cert, "www.randombit.net"));
1✔
365
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "*.randombit.net"));
1✔
366
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "flub.randombit.net"));
1✔
367
            TEST_FFI_RC(-1, botan_x509_cert_hostname_match, (cert, "randombit.net.com"));
1✔
368

369
            botan_x509_cert_t copy;
1✔
370
            TEST_FFI_OK(botan_x509_cert_dup, (&copy, cert));
1✔
371
            TEST_FFI_RC(0, botan_x509_cert_hostname_match, (copy, "randombit.net"));
1✔
372

373
            TEST_FFI_OK(botan_x509_cert_destroy, (copy));
1✔
374
            TEST_FFI_OK(botan_x509_cert_destroy, (cert));
2✔
375
         }
376
      }
1✔
377
};
378

379
class FFI_ZFEC_Test final : public FFI_Test {
×
380
   public:
381
      std::string name() const override { return "FFI ZFEC"; }
1✔
382

383
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
384
         /* exercise a simple success case
385
          */
386

387
         // Select some arbitrary, valid encoding parameters.  There is
388
         // nothing special about them but some relationships between these
389
         // values and other inputs must hold.
390
         const size_t K = 3;
1✔
391
         const size_t N = 11;
1✔
392

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

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

403
         // K of the blocks are required so the total information represented
404
         // can be this multiple.  totalSize must be a multiple of K and it
405
         // always will be using this construction.
406
         const size_t totalSize = blockSize * K;
1✔
407

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

412
         // Allocate memory for the encoding and decoding output parameters.
413
         std::vector<uint8_t> encoded_buf(N * blockSize);
1✔
414
         std::vector<uint8_t> decoded_buf(K * blockSize);
1✔
415

416
         std::vector<uint8_t*> encoded(N);
1✔
417
         for(size_t i = 0; i < N; ++i) {
12✔
418
            encoded[i] = &encoded_buf[i * blockSize];
11✔
419
         }
420
         std::vector<uint8_t*> decoded(K);
1✔
421
         for(size_t i = 0; i < K; ++i) {
4✔
422
            decoded[i] = &decoded_buf[i * blockSize];
3✔
423
         }
424

425
         // First encode the complete input string into N blocks where K are
426
         // required for reconstruction.  The N encoded blocks will end up in
427
         // `encoded`.
428
         if(!TEST_FFI_INIT(botan_zfec_encode, (K, N, input, totalSize, encoded.data())))
2✔
429
            return;
430

431
         // Any K blocks can be decoded to reproduce the original input (split
432
         // across an array of K strings of blockSize bytes each).  This loop
433
         // only exercises decoding with consecutive blocks because it's
434
         // harder to pick non-consecutive blocks out for a test.
435
         for(size_t offset = 0; offset < N - K; ++offset) {
9✔
436
            result.test_note("About to decode with offset " + std::to_string(offset));
16✔
437
            // Pass in the K shares starting from `offset` (and their indexes)
438
            // so that we can try decoding a certain group of blocks here.  Any
439
            // K shares *should* work.
440
            REQUIRE_FFI_OK(botan_zfec_decode,
16✔
441
                           (K, N, indexes.data() + offset, encoded.data() + offset, blockSize, decoded.data()));
442

443
            // Check that the original input bytes have been written to the
444
            // output parameter.
445
            for(size_t k = 0, pos = 0; k < K; ++k, pos += blockSize) {
32✔
446
               TEST_FFI_RC(0, botan_constant_time_compare, (input + pos, decoded[k], blockSize));
48✔
447
            }
448
         }
449

450
         /* Exercise a couple basic failure cases, such as you encounter if
451
          * the caller supplies invalid parameters.  We don't try to
452
          * exhaustively prove invalid parameters are handled through this
453
          * interface since the implementation only passes them through to
454
          * ZFEC::{encode,decode} where the real checking is.  We just want to
455
          * see that errors can propagate.
456
          */
457
         TEST_FFI_FAIL("encode with out-of-bounds encoding parameters should have failed",
2✔
458
                       botan_zfec_encode,
459
                       (0, 0, nullptr, 0, nullptr));
460
         TEST_FFI_FAIL("decode with out-of-bounds encoding parameters should have failed",
3✔
461
                       botan_zfec_decode,
462
                       (0, 0, nullptr, nullptr, 0, nullptr));
463
      }
5✔
464
};
465

466
class FFI_CRL_Test final : public FFI_Test {
×
467
   public:
468
      std::string name() const override { return "FFI CRL"; }
1✔
469

470
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
471
         const char* crl_string =
1✔
472
            "-----BEGIN X509 CRL-----\n"
473
            "MIICoTCCAQkCAQEwDQYJKoZIhvcNAQELBQAwgZQxLTArBgNVBAMTJFVzYWJsZSBj\n"
474
            "ZXJ0IHZhbGlkYXRpb246IFRlbXBvcmFyeSBDQTE5MDcGA1UECxMwQ2VudHJlIGZv\n"
475
            "ciBSZXNlYXJjaCBvbiBDcnlwdG9ncmFwaHkgYW5kIFNlY3VyaXR5MRswGQYDVQQK\n"
476
            "ExJNYXNhcnlrIFVuaXZlcnNpdHkxCzAJBgNVBAYTAkNaGA8yMDUwMDIyNTE1MjE0\n"
477
            "MloYDzIwNTAwMjI1MTUyNDQxWjAAoDowODAfBgNVHSMEGDAWgBRKzxAvI4+rVVo/\n"
478
            "JzLigRznREyB+TAVBgNVHRQEDgIMXcr16yNys/gjeuCFMA0GCSqGSIb3DQEBCwUA\n"
479
            "A4IBgQCfxv/5REM/KUnzeVycph3dJr1Yrtxhc6pZmQ9pMzSW/nawLN3rUHm5oG44\n"
480
            "ZuQgjvzE4PnbU0/DNRu/4w3H58kgrctJHHXbbvkU3lf2ZZLh2wBl+EUh92+/COow\n"
481
            "ZyGB+jqj/XwB99hYUhrY6NLEWRz08kpgG6dnNMEU0uFqdQKWk0CQPnmgPRgDb8BW\n"
482
            "IuMBcjY7aF9XoCZFOqPYdEvUKzAo4QGCf7uJ7fNGS3LqvjaLjAHJseSr5/yR7Q9r\n"
483
            "nEdI38yKPbRj0tNHe7j+BbYg31C+X+AZZKJtlTg8GxYR3qfQio1kDgpZ3rQLzHY3\n"
484
            "ea2MLX/Kdx9cPSwh4KwlcDxQmQKoELb4EnZW1CScSBHi9HQyCBNyCkgkOBMGcJqz\n"
485
            "Ihq1dGeSf8eca9+Avk5kAQ3yjXK1TI2CDEi0msrXLr9XbgowXiOLLzR+rYkhQz+V\n"
486
            "RnIoBwjnrGoJoz636KS170SZCB9ARNs17WE4IvbJdZrTXNOGaVZCQUUpiLRj4ZSO\n"
487
            "Na/nobI=\n"
488
            "-----END X509 CRL-----";
489

490
         botan_x509_crl_t bytecrl;
1✔
491
         if(!TEST_FFI_INIT(botan_x509_crl_load, (&bytecrl, reinterpret_cast<const uint8_t*>(crl_string), 966)))
2✔
492
            return;
×
493

494
         botan_x509_crl_t crl;
1✔
495
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&crl, Test::data_file("x509/nist/root.crl").c_str()));
4✔
496

497
         botan_x509_cert_t cert1;
1✔
498
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&cert1, Test::data_file("x509/nist/test01/end.crt").c_str()));
4✔
499
         TEST_FFI_RC(-1, botan_x509_is_revoked, (crl, cert1));
1✔
500
         TEST_FFI_OK(botan_x509_cert_destroy, (cert1));
1✔
501

502
         botan_x509_cert_t cert2;
1✔
503
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&cert2, Test::data_file("x509/nist/test20/int.crt").c_str()));
4✔
504
         TEST_FFI_RC(0, botan_x509_is_revoked, (crl, cert2));
1✔
505
         TEST_FFI_RC(-1, botan_x509_is_revoked, (bytecrl, cert2));
1✔
506
         TEST_FFI_OK(botan_x509_cert_destroy, (cert2));
1✔
507

508
         TEST_FFI_OK(botan_x509_crl_destroy, (crl));
1✔
509
         TEST_FFI_OK(botan_x509_crl_destroy, (bytecrl));
2✔
510
      }
511
};
512

513
class FFI_Cert_Validation_Test final : public FFI_Test {
×
514
   public:
515
      std::string name() const override { return "FFI Cert Validation"; }
1✔
516

517
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
518
         botan_x509_cert_t root;
1✔
519
         int rc;
1✔
520

521
         if(!TEST_FFI_INIT(botan_x509_cert_load_file, (&root, Test::data_file("x509/nist/root.crt").c_str())))
4✔
522
            return;
×
523

524
         botan_x509_cert_t end2;
1✔
525
         botan_x509_cert_t sub2;
1✔
526
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end2, Test::data_file("x509/nist/test02/end.crt").c_str()));
4✔
527
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub2, Test::data_file("x509/nist/test02/int.crt").c_str()));
4✔
528

529
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end2, &sub2, 1, &root, 1, nullptr, 0, nullptr, 0));
1✔
530
         result.confirm("Validation failed", rc == 5002);
2✔
531
         result.test_eq("Validation status string", botan_x509_cert_validation_status(rc), "Signature error");
1✔
532

533
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end2, nullptr, 0, &root, 1, nullptr, 0, nullptr, 0));
1✔
534
         result.confirm("Validation failed", rc == 3000);
2✔
535
         result.test_eq(
1✔
536
            "Validation status string", botan_x509_cert_validation_status(rc), "Certificate issuer not found");
537

538
         botan_x509_cert_t end7;
1✔
539
         botan_x509_cert_t sub7;
1✔
540
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end7, Test::data_file("x509/nist/test07/end.crt").c_str()));
4✔
541
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub7, Test::data_file("x509/nist/test07/int.crt").c_str()));
4✔
542

543
         botan_x509_cert_t subs[2] = {sub2, sub7};
1✔
544
         TEST_FFI_RC(1, botan_x509_cert_verify, (&rc, end7, subs, 2, &root, 1, nullptr, 0, nullptr, 0));
1✔
545
         result.confirm("Validation failed", rc == 1001);
2✔
546
         result.test_eq("Validation status string",
1✔
547
                        botan_x509_cert_validation_status(rc),
548
                        "Hash function used is considered too weak for security");
549

550
         TEST_FFI_RC(0, botan_x509_cert_verify, (&rc, end7, subs, 2, &root, 1, nullptr, 80, nullptr, 0));
1✔
551
         result.confirm("Validation passed", rc == 0);
2✔
552
         result.test_eq("Validation status string", botan_x509_cert_validation_status(rc), "Verified");
1✔
553

554
         TEST_FFI_RC(1,
1✔
555
                     botan_x509_cert_verify_with_crl,
556
                     (&rc, end7, subs, 2, nullptr, 0, nullptr, 0, "x509/farce", 0, nullptr, 0));
557
         result.confirm("Validation failed", rc == 3000);
2✔
558
         result.test_eq(
1✔
559
            "Validation status string", botan_x509_cert_validation_status(rc), "Certificate issuer not found");
560

561
         botan_x509_crl_t rootcrl;
1✔
562

563
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&rootcrl, Test::data_file("x509/nist/root.crl").c_str()));
4✔
564
         TEST_FFI_RC(
1✔
565
            0, botan_x509_cert_verify_with_crl, (&rc, end7, subs, 2, &root, 1, &rootcrl, 1, nullptr, 80, nullptr, 0));
566
         result.confirm("Validation passed", rc == 0);
2✔
567
         result.test_eq("Validation status string", botan_x509_cert_validation_status(rc), "Verified");
1✔
568

569
         botan_x509_cert_t end20;
1✔
570
         botan_x509_cert_t sub20;
1✔
571
         botan_x509_crl_t sub20crl;
1✔
572
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&end20, Test::data_file("x509/nist/test20/end.crt").c_str()));
4✔
573
         REQUIRE_FFI_OK(botan_x509_cert_load_file, (&sub20, Test::data_file("x509/nist/test20/int.crt").c_str()));
4✔
574
         REQUIRE_FFI_OK(botan_x509_crl_load_file, (&sub20crl, Test::data_file("x509/nist/test20/int.crl").c_str()));
4✔
575
         botan_x509_crl_t crls[2] = {sub20crl, rootcrl};
1✔
576
         TEST_FFI_RC(
1✔
577
            1, botan_x509_cert_verify_with_crl, (&rc, end20, &sub20, 1, &root, 1, crls, 2, nullptr, 80, nullptr, 0));
578
         result.confirm("Validation failed", rc == 5000);
2✔
579
         result.test_eq("Validation status string", botan_x509_cert_validation_status(rc), "Certificate is revoked");
1✔
580

581
         TEST_FFI_OK(botan_x509_cert_destroy, (end2));
1✔
582
         TEST_FFI_OK(botan_x509_cert_destroy, (sub2));
1✔
583
         TEST_FFI_OK(botan_x509_cert_destroy, (end7));
1✔
584
         TEST_FFI_OK(botan_x509_cert_destroy, (sub7));
1✔
585
         TEST_FFI_OK(botan_x509_cert_destroy, (end20));
1✔
586
         TEST_FFI_OK(botan_x509_cert_destroy, (sub20));
1✔
587
         TEST_FFI_OK(botan_x509_crl_destroy, (sub20crl));
1✔
588
         TEST_FFI_OK(botan_x509_cert_destroy, (root));
1✔
589
         TEST_FFI_OK(botan_x509_crl_destroy, (rootcrl));
2✔
590
      }
591
};
592

593
class FFI_ECDSA_Certificate_Test final : public FFI_Test {
×
594
   public:
595
      std::string name() const override { return "FFI ECDSA cert"; }
1✔
596

597
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
598
         botan_x509_cert_t cert;
1✔
599
         if(TEST_FFI_INIT(botan_x509_cert_load_file,
4✔
600
                          (&cert, Test::data_file("x509/ecc/CSCA.CSCA.csca-germany.1.crt").c_str()))) {
601
            size_t date_len = 0;
1✔
602
            TEST_FFI_RC(
1✔
603
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_starts, (cert, nullptr, &date_len));
604

605
            date_len = 8;
1✔
606
            TEST_FFI_RC(
1✔
607
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_starts, (cert, nullptr, &date_len));
608

609
            std::string date(date_len - 1, '0');
1✔
610
            TEST_FFI_OK(botan_x509_cert_get_time_starts, (cert, &date[0], &date_len));
1✔
611
            result.test_eq("cert valid from", date, "070719152718Z");
2✔
612

613
            date_len = 0;
1✔
614
            TEST_FFI_RC(
1✔
615
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_get_time_expires, (cert, nullptr, &date_len));
616

617
            date.resize(date_len - 1);
1✔
618
            TEST_FFI_OK(botan_x509_cert_get_time_expires, (cert, &date[0], &date_len));
1✔
619
            result.test_eq("cert valid until", date, "280119151800Z");
2✔
620

621
            uint64_t not_before = 0;
1✔
622
            TEST_FFI_OK(botan_x509_cert_not_before, (cert, &not_before));
1✔
623
            result.confirm("cert not before", not_before == 1184858838);
2✔
624

625
            uint64_t not_after = 0;
1✔
626
            TEST_FFI_OK(botan_x509_cert_not_after, (cert, &not_after));
1✔
627
            result.confirm("cert not after", not_after == 1831907880);
2✔
628

629
            size_t serial_len = 0;
1✔
630
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
631
                        botan_x509_cert_get_serial_number,
632
                        (cert, nullptr, &serial_len));
633

634
            std::vector<uint8_t> serial(serial_len);
1✔
635
            TEST_FFI_OK(botan_x509_cert_get_serial_number, (cert, serial.data(), &serial_len));
1✔
636
            result.test_eq("cert serial length", serial.size(), 1);
1✔
637
            result.test_int_eq(serial[0], 1, "cert serial");
1✔
638

639
            size_t fingerprint_len = 0;
1✔
640
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
641
                        botan_x509_cert_get_fingerprint,
642
                        (cert, "SHA-256", nullptr, &fingerprint_len));
643

644
            std::vector<uint8_t> fingerprint(fingerprint_len);
1✔
645
            TEST_FFI_OK(botan_x509_cert_get_fingerprint, (cert, "SHA-256", fingerprint.data(), &fingerprint_len));
1✔
646
            result.test_eq(
1✔
647
               "cert fingerprint",
648
               reinterpret_cast<const char*>(fingerprint.data()),
1✔
649
               "3B:6C:99:1C:D6:5A:51:FC:EB:17:E3:AA:F6:3C:1A:DA:14:1F:82:41:30:6F:64:EE:FF:63:F3:1F:D6:07:14:9F");
650

651
            size_t key_id_len = 0;
1✔
652
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
653
                        botan_x509_cert_get_authority_key_id,
654
                        (cert, nullptr, &key_id_len));
655

656
            std::vector<uint8_t> key_id(key_id_len);
1✔
657
            TEST_FFI_OK(botan_x509_cert_get_authority_key_id, (cert, key_id.data(), &key_id_len));
1✔
658
            result.test_eq("cert authority key id",
3✔
659
                           Botan::hex_encode(key_id.data(), key_id.size(), true),
2✔
660
                           "0096452DE588F966C4CCDF161DD1F3F5341B71E7");
661

662
            key_id_len = 0;
1✔
663
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
664
                        botan_x509_cert_get_subject_key_id,
665
                        (cert, nullptr, &key_id_len));
666

667
            key_id.resize(key_id_len);
1✔
668
            TEST_FFI_OK(botan_x509_cert_get_subject_key_id, (cert, key_id.data(), &key_id_len));
1✔
669
            result.test_eq("cert subject key id",
3✔
670
                           Botan::hex_encode(key_id.data(), key_id.size(), true),
2✔
671
                           "0096452DE588F966C4CCDF161DD1F3F5341B71E7");
672

673
            size_t pubkey_len = 0;
1✔
674
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
675
                        botan_x509_cert_get_public_key_bits,
676
                        (cert, nullptr, &pubkey_len));
677

678
            std::vector<uint8_t> pubkey(pubkey_len);
1✔
679
            TEST_FFI_OK(botan_x509_cert_get_public_key_bits, (cert, pubkey.data(), &pubkey_len));
1✔
680

681
            botan_pubkey_t pub;
1✔
682
            if(TEST_FFI_OK(botan_x509_cert_get_public_key, (cert, &pub))) {
2✔
683
               TEST_FFI_OK(botan_pubkey_destroy, (pub));
2✔
684
            }
685

686
            size_t dn_len = 0;
1✔
687
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
688
                        botan_x509_cert_get_issuer_dn,
689
                        (cert, "Name", 0, nullptr, &dn_len));
690

691
            std::vector<uint8_t> dn(dn_len);
1✔
692
            TEST_FFI_OK(botan_x509_cert_get_issuer_dn, (cert, "Name", 0, dn.data(), &dn_len));
1✔
693
            result.test_eq("issuer dn", reinterpret_cast<const char*>(dn.data()), "csca-germany");
1✔
694

695
            dn_len = 0;
1✔
696
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
697
                        botan_x509_cert_get_subject_dn,
698
                        (cert, "Name", 0, nullptr, &dn_len));
699

700
            dn.resize(dn_len);
1✔
701
            TEST_FFI_OK(botan_x509_cert_get_subject_dn, (cert, "Name", 0, dn.data(), &dn_len));
1✔
702
            result.test_eq("subject dn", reinterpret_cast<const char*>(dn.data()), "csca-germany");
1✔
703

704
            size_t printable_len = 0;
1✔
705
            TEST_FFI_RC(
1✔
706
               BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_x509_cert_to_string, (cert, nullptr, &printable_len));
707

708
            std::string printable(printable_len - 1, '0');
1✔
709
            TEST_FFI_OK(botan_x509_cert_to_string, (cert, &printable[0], &printable_len));
1✔
710

711
            TEST_FFI_RC(0, botan_x509_cert_allowed_usage, (cert, KEY_CERT_SIGN));
1✔
712
            TEST_FFI_RC(0, botan_x509_cert_allowed_usage, (cert, CRL_SIGN));
1✔
713
            TEST_FFI_RC(1, botan_x509_cert_allowed_usage, (cert, DIGITAL_SIGNATURE));
1✔
714

715
            TEST_FFI_OK(botan_x509_cert_destroy, (cert));
2✔
716
         }
6✔
717
      }
1✔
718
};
719

720
class FFI_PKCS_Hashid_Test final : public FFI_Test {
×
721
   public:
722
      std::string name() const override { return "FFI PKCS hash id"; }
1✔
723

724
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
725
         std::vector<uint8_t> hash_id(64);
1✔
726
         size_t hash_id_len = hash_id.size();
1✔
727

728
         if(TEST_FFI_INIT(botan_pkcs_hash_id, ("SHA-256", hash_id.data(), &hash_id_len))) {
2✔
729
            result.test_eq("Expected SHA-256 PKCS hash id len", hash_id_len, 19);
1✔
730

731
            hash_id.resize(hash_id_len);
1✔
732
            result.test_eq("Expected SHA_256 PKCS hash id", hash_id, "3031300D060960864801650304020105000420");
1✔
733

734
            hash_id_len = 3;  // too short
1✔
735
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
2✔
736
                        botan_pkcs_hash_id,
737
                        ("SHA-256", hash_id.data(), &hash_id_len));
738
         }
739
      }
1✔
740
};
741

742
class FFI_CBC_Cipher_Test final : public FFI_Test {
×
743
   public:
744
      std::string name() const override { return "FFI CBC cipher"; }
1✔
745

746
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
747
         botan_cipher_t cipher_encrypt, cipher_decrypt;
1✔
748

749
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/CBC/PKCS7", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
2✔
750
            size_t min_keylen = 0;
1✔
751
            size_t max_keylen = 0;
1✔
752
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
753
            result.test_int_eq(min_keylen, 16, "Min key length");
1✔
754
            result.test_int_eq(max_keylen, 16, "Max key length");
1✔
755

756
            // from https://github.com/geertj/bluepass/blob/master/tests/vectors/aes-cbc-pkcs7.txt
757
            const std::vector<uint8_t> plaintext =
1✔
758
               Botan::hex_decode("0397f4f6820b1f9386f14403be5ac16e50213bd473b4874b9bcbf5f318ee686b1d");
1✔
759
            const std::vector<uint8_t> symkey = Botan::hex_decode("898be9cc5004ed0fa6e117c9a3099d31");
1✔
760
            const std::vector<uint8_t> nonce = Botan::hex_decode("9dea7621945988f96491083849b068df");
1✔
761
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
762
               "e232cd6ef50047801ee681ec30f61d53cfd6b0bca02fd03c1b234baa10ea82ac9dab8b960926433a19ce6dea08677e34");
1✔
763

764
            size_t output_written = 0;
1✔
765
            size_t input_consumed = 0;
1✔
766

767
            // Test that after clear or final the object can be reused
768
            for(size_t r = 0; r != 2; ++r) {
3✔
769
               size_t ctext_len;
2✔
770
               TEST_FFI_OK(botan_cipher_output_length, (cipher_encrypt, plaintext.size(), &ctext_len));
2✔
771
               result.test_eq("Expected size of padded message", ctext_len, plaintext.size() + 15);
2✔
772
               std::vector<uint8_t> ciphertext(ctext_len);
2✔
773

774
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
775
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
776
               TEST_FFI_OK(botan_cipher_update,
2✔
777
                           (cipher_encrypt,
778
                            0,
779
                            ciphertext.data(),
780
                            ciphertext.size(),
781
                            &output_written,
782
                            plaintext.data(),
783
                            plaintext.size(),
784
                            &input_consumed));
785
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
786

787
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
788
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
789
               TEST_FFI_OK(botan_cipher_update,
2✔
790
                           (cipher_encrypt,
791
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
792
                            ciphertext.data(),
793
                            ciphertext.size(),
794
                            &output_written,
795
                            plaintext.data(),
796
                            plaintext.size(),
797
                            &input_consumed));
798

799
               ciphertext.resize(output_written);
2✔
800
               result.test_eq("AES/CBC ciphertext", ciphertext, exp_ciphertext);
2✔
801

802
               if(TEST_FFI_OK(botan_cipher_init, (&cipher_decrypt, "AES-128/CBC", BOTAN_CIPHER_INIT_FLAG_DECRYPT))) {
4✔
803
                  size_t ptext_len;
2✔
804
                  TEST_FFI_OK(botan_cipher_output_length, (cipher_decrypt, ciphertext.size(), &ptext_len));
2✔
805
                  std::vector<uint8_t> decrypted(ptext_len);
2✔
806

807
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
808
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
809
                  TEST_FFI_OK(botan_cipher_update,
2✔
810
                              (cipher_decrypt,
811
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
812
                               decrypted.data(),
813
                               decrypted.size(),
814
                               &output_written,
815
                               ciphertext.data(),
816
                               ciphertext.size(),
817
                               &input_consumed));
818

819
                  decrypted.resize(output_written);
2✔
820

821
                  result.test_eq("AES/CBC plaintext", decrypted, plaintext);
2✔
822

823
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
4✔
824
               }
2✔
825
            }
2✔
826

827
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
2✔
828
         }
4✔
829
      }
1✔
830
};
831

832
class FFI_GCM_Test final : public FFI_Test {
×
833
   public:
834
      std::string name() const override { return "FFI GCM"; }
1✔
835

836
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
837
         botan_cipher_t cipher_encrypt, cipher_decrypt;
1✔
838

839
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/GCM", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
2✔
840
            char namebuf[18];
1✔
841
            size_t name_len = 15;
1✔
842
            TEST_FFI_FAIL("output buffer too short", botan_cipher_name, (cipher_encrypt, namebuf, &name_len));
2✔
843
            result.test_eq("name len", name_len, 16);
1✔
844

845
            name_len = sizeof(namebuf);
1✔
846
            if(TEST_FFI_OK(botan_cipher_name, (cipher_encrypt, namebuf, &name_len))) {
2✔
847
               result.test_eq("name len", name_len, 16);
1✔
848
               result.test_eq("name", std::string(namebuf), "AES-128/GCM(16)");
2✔
849
            }
850

851
            size_t min_keylen = 0;
1✔
852
            size_t max_keylen = 0;
1✔
853
            size_t nonce_len = 0;
1✔
854
            size_t tag_len = 0;
1✔
855

856
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
857
            result.test_int_eq(min_keylen, 16, "Min key length");
1✔
858
            result.test_int_eq(max_keylen, 16, "Max key length");
1✔
859

860
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &nonce_len));
1✔
861
            result.test_int_eq(nonce_len, 12, "Expected default GCM nonce length");
1✔
862

863
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &tag_len));
1✔
864
            result.test_int_eq(tag_len, 16, "Expected GCM tag length");
1✔
865

866
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 12));
1✔
867
            // GCM accepts any nonce size except zero
868
            TEST_FFI_RC(0, botan_cipher_valid_nonce_length, (cipher_encrypt, 0));
1✔
869
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 1));
1✔
870
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 100009));
1✔
871

872
            // NIST test vector
873
            const std::vector<uint8_t> plaintext = Botan::hex_decode(
1✔
874
               "D9313225F88406E5A55909C5AFF5269A86A7A9531534F7DA2E4C303D8A318A721C3C0C95956809532FCF0E2449A6B525B16AEDF5AA0DE657BA637B39");
1✔
875

876
            const std::vector<uint8_t> symkey = Botan::hex_decode("FEFFE9928665731C6D6A8F9467308308");
1✔
877
            const std::vector<uint8_t> nonce = Botan::hex_decode("CAFEBABEFACEDBADDECAF888");
1✔
878
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
879
               "42831EC2217774244B7221B784D0D49CE3AA212F2C02A4E035C17E2329ACA12E21D514B25466931C7D8F6A5AAC84AA051BA30B396A0AAC973D58E0915BC94FBC3221A5DB94FAE95AE7121A47");
1✔
880
            const std::vector<uint8_t> aad = Botan::hex_decode("FEEDFACEDEADBEEFFEEDFACEDEADBEEFABADDAD2");
1✔
881

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

884
            size_t output_written = 0;
1✔
885
            size_t input_consumed = 0;
1✔
886

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

891
               // First use a nonce of the AAD, and ensure reset works
892
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, aad.data(), aad.size()));
2✔
893
               TEST_FFI_OK(botan_cipher_reset, (cipher_encrypt));
2✔
894

895
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
896
               TEST_FFI_OK(botan_cipher_update,
2✔
897
                           (cipher_encrypt,
898
                            0,
899
                            ciphertext.data(),
900
                            ciphertext.size(),
901
                            &output_written,
902
                            plaintext.data(),
903
                            plaintext.size(),
904
                            &input_consumed));
905
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
906

907
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
908
               TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_encrypt, aad.data(), aad.size()));
2✔
909
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
910
               TEST_FFI_OK(botan_cipher_update,
2✔
911
                           (cipher_encrypt,
912
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
913
                            ciphertext.data(),
914
                            ciphertext.size(),
915
                            &output_written,
916
                            plaintext.data(),
917
                            plaintext.size(),
918
                            &input_consumed));
919

920
               ciphertext.resize(output_written);
2✔
921
               result.test_eq("AES/GCM ciphertext", ciphertext, exp_ciphertext);
2✔
922

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

926
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
927
                  TEST_FFI_OK(botan_cipher_set_associated_data, (cipher_decrypt, aad.data(), aad.size()));
2✔
928
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
929
                  TEST_FFI_OK(botan_cipher_update,
2✔
930
                              (cipher_decrypt,
931
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
932
                               decrypted.data(),
933
                               decrypted.size(),
934
                               &output_written,
935
                               ciphertext.data(),
936
                               ciphertext.size(),
937
                               &input_consumed));
938

939
                  result.test_int_eq(input_consumed, ciphertext.size(), "All input consumed");
2✔
940
                  result.test_int_eq(output_written, decrypted.size(), "Expected output size produced");
2✔
941
                  result.test_eq("AES/GCM plaintext", decrypted, plaintext);
2✔
942

943
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
4✔
944
               }
2✔
945
            }
946

947
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
2✔
948
         }
6✔
949
      }
1✔
950
};
951

952
class FFI_EAX_Test final : public FFI_Test {
×
953
   public:
954
      std::string name() const override { return "FFI EAX"; }
1✔
955

956
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
957
         botan_cipher_t cipher_encrypt, cipher_decrypt;
1✔
958

959
         if(TEST_FFI_INIT(botan_cipher_init, (&cipher_encrypt, "AES-128/EAX", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
2✔
960
            size_t min_keylen = 0;
1✔
961
            size_t max_keylen = 0;
1✔
962
            size_t mod_keylen = 0;
1✔
963
            size_t nonce_len = 0;
1✔
964
            size_t tag_len = 0;
1✔
965

966
            TEST_FFI_OK(botan_cipher_query_keylen, (cipher_encrypt, &min_keylen, &max_keylen));
1✔
967
            result.test_int_eq(min_keylen, 16, "Min key length");
1✔
968
            result.test_int_eq(max_keylen, 16, "Max key length");
1✔
969

970
            TEST_FFI_OK(botan_cipher_get_keyspec, (cipher_encrypt, &min_keylen, &max_keylen, &mod_keylen));
1✔
971
            result.test_int_eq(min_keylen, 16, "Min key length");
1✔
972
            result.test_int_eq(max_keylen, 16, "Max key length");
1✔
973
            result.test_int_eq(mod_keylen, 1, "Mod key length");
1✔
974

975
            TEST_FFI_OK(botan_cipher_get_default_nonce_length, (cipher_encrypt, &nonce_len));
1✔
976
            result.test_int_eq(nonce_len, 12, "Expected default EAX nonce length");
1✔
977

978
            TEST_FFI_OK(botan_cipher_get_tag_length, (cipher_encrypt, &tag_len));
1✔
979
            result.test_int_eq(tag_len, 16, "Expected EAX tag length");
1✔
980

981
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 12));
1✔
982
            // EAX accepts any nonce size...
983
            TEST_FFI_RC(1, botan_cipher_valid_nonce_length, (cipher_encrypt, 0));
1✔
984

985
            const std::vector<uint8_t> plaintext =
1✔
986
               Botan::hex_decode("0000000000000000000000000000000011111111111111111111111111111111");
1✔
987
            const std::vector<uint8_t> symkey = Botan::hex_decode("000102030405060708090a0b0c0d0e0f");
1✔
988
            const std::vector<uint8_t> nonce = Botan::hex_decode("3c8cc2970a008f75cc5beae2847258c2");
1✔
989
            const std::vector<uint8_t> exp_ciphertext = Botan::hex_decode(
1✔
990
               "3c441f32ce07822364d7a2990e50bb13d7b02a26969e4a937e5e9073b0d9c968db90bdb3da3d00afd0fc6a83551da95e");
1✔
991

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

994
            size_t output_written = 0;
1✔
995
            size_t input_consumed = 0;
1✔
996

997
            // Test that after clear or final the object can be reused
998
            for(size_t r = 0; r != 2; ++r) {
3✔
999
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1000
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1001
               TEST_FFI_OK(botan_cipher_update,
2✔
1002
                           (cipher_encrypt,
1003
                            0,
1004
                            ciphertext.data(),
1005
                            ciphertext.size(),
1006
                            &output_written,
1007
                            plaintext.data(),
1008
                            plaintext.size(),
1009
                            &input_consumed));
1010
               TEST_FFI_OK(botan_cipher_clear, (cipher_encrypt));
2✔
1011

1012
               TEST_FFI_OK(botan_cipher_set_key, (cipher_encrypt, symkey.data(), symkey.size()));
2✔
1013
               TEST_FFI_OK(botan_cipher_start, (cipher_encrypt, nonce.data(), nonce.size()));
2✔
1014
               TEST_FFI_OK(botan_cipher_update,
2✔
1015
                           (cipher_encrypt,
1016
                            BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1017
                            ciphertext.data(),
1018
                            ciphertext.size(),
1019
                            &output_written,
1020
                            plaintext.data(),
1021
                            plaintext.size(),
1022
                            &input_consumed));
1023

1024
               ciphertext.resize(output_written);
2✔
1025
               result.test_eq("AES/EAX ciphertext", ciphertext, exp_ciphertext);
2✔
1026

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

1030
                  TEST_FFI_OK(botan_cipher_set_key, (cipher_decrypt, symkey.data(), symkey.size()));
2✔
1031
                  TEST_FFI_OK(botan_cipher_start, (cipher_decrypt, nonce.data(), nonce.size()));
2✔
1032
                  TEST_FFI_OK(botan_cipher_update,
2✔
1033
                              (cipher_decrypt,
1034
                               BOTAN_CIPHER_UPDATE_FLAG_FINAL,
1035
                               decrypted.data(),
1036
                               decrypted.size(),
1037
                               &output_written,
1038
                               ciphertext.data(),
1039
                               ciphertext.size(),
1040
                               &input_consumed));
1041

1042
                  result.test_int_eq(input_consumed, ciphertext.size(), "All input consumed");
2✔
1043
                  result.test_int_eq(output_written, decrypted.size(), "Expected output size produced");
2✔
1044
                  result.test_eq("AES/EAX plaintext", decrypted, plaintext);
2✔
1045

1046
                  TEST_FFI_OK(botan_cipher_destroy, (cipher_decrypt));
4✔
1047
               }
2✔
1048
            }
1049

1050
            TEST_FFI_OK(botan_cipher_destroy, (cipher_encrypt));
2✔
1051
         }
5✔
1052
      }
1✔
1053
};
1054

1055
class FFI_StreamCipher_Test final : public FFI_Test {
×
1056
   public:
1057
      std::string name() const override { return "FFI stream ciphers"; }
1✔
1058

1059
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1060
         botan_cipher_t ctr;
1✔
1061

1062
         if(TEST_FFI_INIT(botan_cipher_init, (&ctr, "AES-128/CTR-BE", BOTAN_CIPHER_INIT_FLAG_ENCRYPT))) {
2✔
1063
            const std::vector<uint8_t> key = Botan::hex_decode("2B7E151628AED2A6ABF7158809CF4F3C");
1✔
1064
            const std::vector<uint8_t> nonce = Botan::hex_decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFF");
1✔
1065
            const std::vector<uint8_t> pt = Botan::hex_decode(
1✔
1066
               "AE2D8A571E03AC9C9EB76FAC45AF8E5130C81C46A35CE411E5FBC1191A0A52EFF69F2445DF4F9B17AD2B417BE66C3710");
1✔
1067
            const std::vector<uint8_t> exp_ct = Botan::hex_decode(
1✔
1068
               "9806F66B7970FDFF8617187BB9FFFDFF5AE4DF3EDBD5D35E5B4F09020DB03EAB1E031DDA2FBE03D1792170A0F3009CEE");
1✔
1069

1070
            std::vector<uint8_t> ct(pt.size());
1✔
1071

1072
            size_t input_consumed = 0;
1✔
1073
            size_t output_written = 0;
1✔
1074

1075
            TEST_FFI_OK(botan_cipher_set_key, (ctr, key.data(), key.size()));
1✔
1076
            TEST_FFI_OK(botan_cipher_start, (ctr, nonce.data(), nonce.size()));
1✔
1077

1078
            // Test partial updates...
1079
            TEST_FFI_OK(botan_cipher_update,
1✔
1080
                        (ctr, 0, ct.data(), ct.size(), &output_written, pt.data(), 5, &input_consumed));
1081

1082
            result.test_int_eq(output_written, 5, "Expected output written");
1✔
1083
            result.test_int_eq(input_consumed, 5, "Expected input consumed");
1✔
1084

1085
            TEST_FFI_OK(botan_cipher_update,
1✔
1086
                        (ctr, 0, &ct[5], ct.size() - 5, &output_written, &pt[5], pt.size() - 5, &input_consumed));
1087

1088
            result.test_int_eq(output_written, ct.size() - 5, "Expected output written");
1✔
1089
            result.test_int_eq(input_consumed, pt.size() - 5, "Expected input consumed");
1✔
1090
            result.test_eq("AES-128/CTR ciphertext", ct, exp_ct);
1✔
1091

1092
            TEST_FFI_OK(botan_cipher_destroy, (ctr));
2✔
1093
         }
5✔
1094
      }
1✔
1095
};
1096

1097
class FFI_HashFunction_Test final : public FFI_Test {
×
1098
   public:
1099
      std::string name() const override { return "FFI hash"; }
1✔
1100

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

1104
         botan_hash_t hash;
1✔
1105
         TEST_FFI_FAIL("invalid hash name", botan_hash_init, (&hash, "SHA-255", 0));
2✔
1106
         TEST_FFI_FAIL("invalid flags", botan_hash_init, (&hash, "SHA-256", 1));
2✔
1107

1108
         if(TEST_FFI_INIT(botan_hash_init, (&hash, "SHA-256", 0))) {
1✔
1109
            char namebuf[10];
1✔
1110
            size_t name_len = 7;
1✔
1111
            TEST_FFI_FAIL("output buffer too short", botan_hash_name, (hash, namebuf, &name_len));
2✔
1112
            result.test_eq("name len", name_len, 8);
1✔
1113

1114
            name_len = sizeof(namebuf);
1✔
1115
            if(TEST_FFI_OK(botan_hash_name, (hash, namebuf, &name_len))) {
1✔
1116
               result.test_eq("name len", name_len, 8);
1✔
1117
               result.test_eq("name", std::string(namebuf), "SHA-256");
2✔
1118
            }
1119

1120
            size_t block_size;
1✔
1121
            if(TEST_FFI_OK(botan_hash_block_size, (hash, &block_size))) {
2✔
1122
               result.test_eq("hash block size", block_size, 64);
2✔
1123
            }
1124

1125
            size_t output_len;
1✔
1126
            if(TEST_FFI_OK(botan_hash_output_length, (hash, &output_len))) {
2✔
1127
               result.test_eq("hash output length", output_len, 32);
1✔
1128

1129
               std::vector<uint8_t> outbuf(output_len);
1✔
1130

1131
               // Test that after clear or final the object can be reused
1132
               for(size_t r = 0; r != 2; ++r) {
3✔
1133
                  TEST_FFI_OK(botan_hash_update, (hash, reinterpret_cast<const uint8_t*>(input_str), 1));
2✔
1134
                  TEST_FFI_OK(botan_hash_clear, (hash));
2✔
1135

1136
                  TEST_FFI_OK(botan_hash_update,
2✔
1137
                              (hash, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
1138
                  TEST_FFI_OK(botan_hash_final, (hash, outbuf.data()));
2✔
1139

1140
                  result.test_eq(
4✔
1141
                     "SHA-256 output", outbuf, "B5D4045C3F466FA91FE2CC6ABE79232A1A57CDF104F7A26E716E0A1E2789DF78");
1142
               }
1143

1144
               // Test botan_hash_copy_state
1145
               const char* msg = "message digest";
1✔
1146
               const char* expected = "F7846F55CF23E14EEBEAB5B4E1550CAD5B509E3348FBC4EFA3A1413D393CB650";
1✔
1147
               TEST_FFI_OK(botan_hash_clear, (hash));
1✔
1148
               TEST_FFI_OK(botan_hash_update, (hash, reinterpret_cast<const uint8_t*>(&msg[0]), 1));
1✔
1149
               botan_hash_t fork;
1✔
1150
               if(TEST_FFI_OK(botan_hash_copy_state, (&fork, hash))) {
2✔
1151
                  TEST_FFI_OK(botan_hash_update,
1✔
1152
                              (fork, reinterpret_cast<const uint8_t*>(&msg[1]), std::strlen(msg) - 2));
1153

1154
                  TEST_FFI_OK(botan_hash_update,
1✔
1155
                              (hash, reinterpret_cast<const uint8_t*>(&msg[1]), std::strlen(msg) - 1));
1156
                  TEST_FFI_OK(botan_hash_final, (hash, outbuf.data()));
1✔
1157
                  result.test_eq("hashing split", outbuf, expected);
1✔
1158

1159
                  TEST_FFI_OK(botan_hash_update,
1✔
1160
                              (fork, reinterpret_cast<const uint8_t*>(&msg[std::strlen(msg) - 1]), 1));
1161
                  TEST_FFI_OK(botan_hash_final, (fork, outbuf.data()));
1✔
1162
                  result.test_eq("hashing split", outbuf, expected);
1✔
1163

1164
                  TEST_FFI_OK(botan_hash_destroy, (fork));
2✔
1165
               }
1166
            }
1✔
1167

1168
            TEST_FFI_OK(botan_hash_destroy, (hash));
2✔
1169
         }
1170
      }
1✔
1171
};
1172

1173
class FFI_MAC_Test final : public FFI_Test {
×
1174
   public:
1175
      std::string name() const override { return "FFI MAC"; }
1✔
1176

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

1180
         // MAC test
1181
         botan_mac_t mac;
1✔
1182
         TEST_FFI_FAIL("bad flag", botan_mac_init, (&mac, "HMAC(SHA-256)", 1));
2✔
1183
         TEST_FFI_FAIL("bad name", botan_mac_init, (&mac, "HMAC(SHA-259)", 0));
2✔
1184

1185
         if(TEST_FFI_INIT(botan_mac_init, (&mac, "HMAC(SHA-256)", 0))) {
1✔
1186
            char namebuf[16];
1✔
1187
            size_t name_len = 13;
1✔
1188
            TEST_FFI_FAIL("output buffer too short", botan_mac_name, (mac, namebuf, &name_len));
2✔
1189
            result.test_eq("name len", name_len, 14);
1✔
1190

1191
            name_len = sizeof(namebuf);
1✔
1192
            if(TEST_FFI_OK(botan_mac_name, (mac, namebuf, &name_len))) {
1✔
1193
               result.test_eq("name len", name_len, 14);
1✔
1194
               result.test_eq("name", std::string(namebuf), "HMAC(SHA-256)");
2✔
1195
            }
1196

1197
            size_t min_keylen = 0, max_keylen = 0, mod_keylen = 0;
1✔
1198
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, nullptr, nullptr));
1✔
1199
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, &min_keylen, nullptr, nullptr));
1✔
1200
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, &max_keylen, nullptr));
1✔
1201
            TEST_FFI_RC(0, botan_mac_get_keyspec, (mac, nullptr, nullptr, &mod_keylen));
1✔
1202

1203
            result.test_eq("Expected min keylen", min_keylen, 0);
1✔
1204
            result.test_eq("Expected max keylen", max_keylen, 4096);
1✔
1205
            result.test_eq("Expected mod keylen", mod_keylen, 1);
1✔
1206

1207
            size_t output_len;
1✔
1208
            if(TEST_FFI_OK(botan_mac_output_length, (mac, &output_len))) {
2✔
1209
               result.test_eq("MAC output length", output_len, 32);
1✔
1210

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

1214
               // Test that after clear or final the object can be reused
1215
               for(size_t r = 0; r != 2; ++r) {
3✔
1216
                  TEST_FFI_OK(botan_mac_set_key, (mac, mac_key, sizeof(mac_key)));
2✔
1217
                  TEST_FFI_OK(botan_mac_update,
2✔
1218
                              (mac, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
1219
                  TEST_FFI_OK(botan_mac_clear, (mac));
2✔
1220

1221
                  TEST_FFI_OK(botan_mac_set_key, (mac, mac_key, sizeof(mac_key)));
2✔
1222
                  TEST_FFI_OK(botan_mac_update,
2✔
1223
                              (mac, reinterpret_cast<const uint8_t*>(input_str), std::strlen(input_str)));
1224
                  TEST_FFI_OK(botan_mac_final, (mac, outbuf.data()));
2✔
1225

1226
                  result.test_eq(
4✔
1227
                     "HMAC output", outbuf, "1A82EEA984BC4A7285617CC0D05F1FE1D6C96675924A81BC965EE8FF7B0697A7");
1228
               }
1229
            }
1✔
1230

1231
            TEST_FFI_OK(botan_mac_destroy, (mac));
2✔
1232
         }
1233
      }
1✔
1234
};
1235

1236
class FFI_Scrypt_Test final : public FFI_Test {
×
1237
   public:
1238
      std::string name() const override { return "FFI Scrypt"; }
1✔
1239

1240
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1241
         std::vector<uint8_t> output(24);
1✔
1242
         const uint8_t salt[8] = {0};
1✔
1243
         const char* pass = "password";
1✔
1244

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

1248
            size_t N, r, p;
1✔
1249
            TEST_FFI_OK(botan_pwdhash_timed,
1✔
1250
                        ("Scrypt", 50, &r, &p, &N, output.data(), output.size(), "bunny", 5, salt, sizeof(salt)));
1251

1252
            std::vector<uint8_t> cmp(output.size());
1✔
1253

1254
            TEST_FFI_OK(botan_pwdhash, ("Scrypt", N, r, p, cmp.data(), cmp.size(), "bunny", 5, salt, sizeof(salt)));
1✔
1255
            result.test_eq("recomputed scrypt", cmp, output);
2✔
1256
         }
1✔
1257
      }
1✔
1258
};
1259

1260
class FFI_KDF_Test final : public FFI_Test {
×
1261
   public:
1262
      std::string name() const override { return "FFI KDF"; }
1✔
1263

1264
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
1265
         std::vector<uint8_t> outbuf;
1✔
1266

1267
         const std::string passphrase = "ltexmfeyylmlbrsyikaw";
1✔
1268

1269
         const std::vector<uint8_t> pbkdf_salt = Botan::hex_decode("ED1F39A0A7F3889AAF7E60743B3BC1CC2C738E60");
1✔
1270
         const size_t pbkdf_out_len = 10;
1✔
1271
         const size_t pbkdf_iterations = 1000;
1✔
1272

1273
         outbuf.resize(pbkdf_out_len);
1✔
1274

1275
         if(TEST_FFI_INIT(botan_pbkdf,
1✔
1276
                          ("PBKDF2(SHA-1)",
1277
                           outbuf.data(),
1278
                           outbuf.size(),
1279
                           passphrase.c_str(),
1280
                           pbkdf_salt.data(),
1281
                           pbkdf_salt.size(),
1282
                           pbkdf_iterations))) {
1283
            result.test_eq("PBKDF output", outbuf, "027AFADD48F4BE8DCC4F");
1✔
1284

1285
            size_t iters_10ms, iters_100ms;
1✔
1286

1287
            TEST_FFI_OK(botan_pbkdf_timed,
1✔
1288
                        ("PBKDF2(SHA-1)",
1289
                         outbuf.data(),
1290
                         outbuf.size(),
1291
                         passphrase.c_str(),
1292
                         pbkdf_salt.data(),
1293
                         pbkdf_salt.size(),
1294
                         10,
1295
                         &iters_10ms));
1296
            TEST_FFI_OK(botan_pbkdf_timed,
1✔
1297
                        ("PBKDF2(SHA-1)",
1298
                         outbuf.data(),
1299
                         outbuf.size(),
1300
                         passphrase.c_str(),
1301
                         pbkdf_salt.data(),
1302
                         pbkdf_salt.size(),
1303
                         100,
1304
                         &iters_100ms));
1305

1306
            result.test_note("PBKDF timed 10 ms " + std::to_string(iters_10ms) + " iterations " + "100 ms " +
3✔
1307
                             std::to_string(iters_100ms) + " iterations");
4✔
1308
         }
1309

1310
         const std::vector<uint8_t> kdf_secret = Botan::hex_decode("92167440112E");
1✔
1311
         const std::vector<uint8_t> kdf_salt = Botan::hex_decode("45A9BEDED69163123D0348F5185F61ABFB1BF18D6AEA454F");
1✔
1312
         const size_t kdf_out_len = 18;
1✔
1313
         outbuf.resize(kdf_out_len);
1✔
1314

1315
         if(TEST_FFI_INIT(botan_kdf,
1✔
1316
                          ("KDF2(SHA-1)",
1317
                           outbuf.data(),
1318
                           outbuf.size(),
1319
                           kdf_secret.data(),
1320
                           kdf_secret.size(),
1321
                           kdf_salt.data(),
1322
                           kdf_salt.size(),
1323
                           nullptr,
1324
                           0))) {
1325
            result.test_eq("KDF output", outbuf, "3A5DC9AA1C872B4744515AC2702D6396FC2A");
2✔
1326
         }
1327

1328
         size_t out_len = 64;
1✔
1329
         std::string outstr;
1✔
1330
         outstr.resize(out_len);
1✔
1331

1332
         int rc =
1✔
1333
            botan_bcrypt_generate(reinterpret_cast<uint8_t*>(&outstr[0]), &out_len, passphrase.c_str(), rng, 4, 0);
1✔
1334

1335
         if(rc == 0) {
1✔
1336
            result.test_eq("bcrypt output size", out_len, 61);
1✔
1337

1338
            TEST_FFI_OK(botan_bcrypt_is_valid, (passphrase.c_str(), outstr.data()));
1✔
1339
            TEST_FFI_FAIL("bad password", botan_bcrypt_is_valid, ("nope", outstr.data()));
2✔
1340
         }
1341
      }
6✔
1342
};
1343

1344
class FFI_Blockcipher_Test final : public FFI_Test {
×
1345
   public:
1346
      std::string name() const override { return "FFI block ciphers"; }
1✔
1347

1348
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1349
         botan_block_cipher_t cipher;
1✔
1350

1351
         if(TEST_FFI_INIT(botan_block_cipher_init, (&cipher, "AES-128"))) {
2✔
1352
            char namebuf[10];
1✔
1353
            size_t name_len = 7;
1✔
1354
            TEST_FFI_FAIL("output buffer too short", botan_block_cipher_name, (cipher, namebuf, &name_len));
2✔
1355
            result.test_eq("name len", name_len, 8);
1✔
1356

1357
            name_len = sizeof(namebuf);
1✔
1358
            if(TEST_FFI_OK(botan_block_cipher_name, (cipher, namebuf, &name_len))) {
2✔
1359
               result.test_eq("name len", name_len, 8);
1✔
1360
               result.test_eq("name", std::string(namebuf), "AES-128");
2✔
1361
            }
1362

1363
            const std::vector<uint8_t> zero16(16, 0);
1✔
1364
            std::vector<uint8_t> block(16, 0);
1✔
1365

1366
            TEST_FFI_OK(botan_block_cipher_clear, (cipher));
1✔
1367

1368
            TEST_FFI_RC(
1✔
1369
               BOTAN_FFI_ERROR_KEY_NOT_SET, botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
1370
            TEST_FFI_RC(
1✔
1371
               BOTAN_FFI_ERROR_KEY_NOT_SET, botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
1372

1373
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_block_cipher_encrypt_blocks, (cipher, nullptr, nullptr, 0));
1✔
1374
            TEST_FFI_RC(BOTAN_FFI_ERROR_NULL_POINTER, botan_block_cipher_decrypt_blocks, (cipher, nullptr, nullptr, 0));
1✔
1375

1376
            TEST_FFI_RC(16, botan_block_cipher_block_size, (cipher));
1✔
1377

1378
            size_t min_keylen = 0, max_keylen = 0, mod_keylen = 0;
1✔
1379
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, nullptr, nullptr));
1✔
1380
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, &min_keylen, nullptr, nullptr));
1✔
1381
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, &max_keylen, nullptr));
1✔
1382
            TEST_FFI_RC(0, botan_block_cipher_get_keyspec, (cipher, nullptr, nullptr, &mod_keylen));
1✔
1383

1384
            result.test_eq("Expected min keylen", min_keylen, 16);
1✔
1385
            result.test_eq("Expected max keylen", max_keylen, 16);
1✔
1386
            result.test_eq("Expected mod keylen", mod_keylen, 1);
1✔
1387

1388
            TEST_FFI_OK(botan_block_cipher_set_key, (cipher, zero16.data(), zero16.size()));
1✔
1389

1390
            TEST_FFI_OK(botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
1391
            result.test_eq("AES-128 encryption works", block, "66E94BD4EF8A2C3B884CFA59CA342B2E");
1✔
1392

1393
            TEST_FFI_OK(botan_block_cipher_encrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
1394
            result.test_eq("AES-128 encryption works", block, "F795BD4A52E29ED713D313FA20E98DBC");
1✔
1395

1396
            TEST_FFI_OK(botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
1397
            result.test_eq("AES-128 decryption works", block, "66E94BD4EF8A2C3B884CFA59CA342B2E");
1✔
1398

1399
            TEST_FFI_OK(botan_block_cipher_decrypt_blocks, (cipher, block.data(), block.data(), 1));
1✔
1400
            result.test_eq("AES-128 decryption works", block, "00000000000000000000000000000000");
1✔
1401

1402
            TEST_FFI_OK(botan_block_cipher_clear, (cipher));
1✔
1403
            botan_block_cipher_destroy(cipher);
1✔
1404
         }
2✔
1405
      }
1✔
1406
};
1407

1408
class FFI_ErrorHandling_Test final : public FFI_Test {
×
1409
   public:
1410
      std::string name() const override { return "FFI error handling"; }
1✔
1411

1412
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1413
         // delete of null is ok/ignored
1414
         TEST_FFI_RC(0, botan_hash_destroy, (nullptr));
1✔
1415

1416
   #if !defined(BOTAN_HAS_SANITIZER_UNDEFINED)
1417
         // Confirm that botan_x_destroy checks the argument type
1418
         botan_mp_t mp;
1✔
1419
         botan_mp_init(&mp);
1✔
1420
         TEST_FFI_RC(BOTAN_FFI_ERROR_INVALID_OBJECT, botan_hash_destroy, (reinterpret_cast<botan_hash_t>(mp)));
1✔
1421
         TEST_FFI_RC(0, botan_mp_destroy, (mp));
1✔
1422
   #endif
1423

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

1429
            if(err) {
150✔
1430
               std::string s(err);
150✔
1431

1432
               if(s != "Unknown error") {
150✔
1433
                  result.confirm("No duplicate messages", !errors.contains(s));
40✔
1434
                  errors.insert(s);
170✔
1435
               }
1436
            }
150✔
1437
         }
1438
      }
1✔
1439
};
1440

1441
class FFI_Base64_Test final : public FFI_Test {
×
1442
   public:
1443
      std::string name() const override { return "FFI base64"; }
1✔
1444

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

1449
         size_t out_len = sizeof(out_buf);
1✔
1450
         TEST_FFI_OK(botan_base64_encode, (bin, sizeof(bin), out_buf, &out_len));
1✔
1451

1452
         result.test_eq("encoded string", out_buf, "FoofBunny900");
1✔
1453

1454
         out_len -= 1;
1✔
1455
         TEST_FFI_RC(
1✔
1456
            BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_base64_encode, (bin, sizeof(bin), out_buf, &out_len));
1457

1458
         const char* base64 = "U3VjaCBiYXNlNjQgd293IQ==";
1✔
1459
         uint8_t out_bin[1024] = {0};
1✔
1460

1461
         out_len = 3;
1✔
1462
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1463
                     botan_base64_decode,
1464
                     (base64, strlen(base64), out_bin, &out_len));
1465

1466
         result.test_eq("output length", out_len, 18);
1✔
1467

1468
         out_len = sizeof(out_bin);
1✔
1469
         TEST_FFI_OK(botan_base64_decode, (base64, strlen(base64), out_bin, &out_len));
1✔
1470

1471
         result.test_eq(
3✔
1472
            "decoded string", std::string(reinterpret_cast<const char*>(out_bin), out_len), "Such base64 wow!");
3✔
1473
      }
1✔
1474
};
1475

1476
class FFI_Hex_Test final : public FFI_Test {
×
1477
   public:
1478
      std::string name() const override { return "FFI hex"; }
1✔
1479

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

1484
         TEST_FFI_OK(botan_hex_encode, (bin, sizeof(bin), hex_buf, 0));
1✔
1485

1486
         result.test_eq("encoded string", hex_buf, "DEADBEEF");
1✔
1487

1488
         const char* hex = "67657420796572206A756D626F20736872696D70";
1✔
1489
         uint8_t out_bin[1024] = {0};
1✔
1490
         size_t out_len = 5;
1✔
1491

1492
         TEST_FFI_RC(
1✔
1493
            BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_hex_decode, (hex, strlen(hex), out_bin, &out_len));
1494

1495
         out_len = sizeof(out_bin);
1✔
1496
         TEST_FFI_OK(botan_hex_decode, (hex, strlen(hex), out_bin, &out_len));
1✔
1497

1498
         result.test_eq(
3✔
1499
            "decoded string", std::string(reinterpret_cast<const char*>(out_bin), out_len), "get yer jumbo shrimp");
3✔
1500
      }
1✔
1501
};
1502

1503
class FFI_MP_Test final : public FFI_Test {
×
1504
   public:
1505
      std::string name() const override { return "FFI MP"; }
1✔
1506

1507
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
1508
         char str_buf[1024] = {0};
1✔
1509
         size_t str_len = 0;
1✔
1510

1511
         botan_mp_t x;
1✔
1512
         botan_mp_init(&x);
1✔
1513
         TEST_FFI_RC(0, botan_mp_is_odd, (x));
1✔
1514
         TEST_FFI_RC(1, botan_mp_is_even, (x));
1✔
1515
         TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
1516
         TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
1517
         TEST_FFI_RC(1, botan_mp_is_zero, (x));
1✔
1518
         botan_mp_destroy(x);
1✔
1519

1520
         botan_mp_init(&x);
1✔
1521
         size_t bn_bytes = 0;
1✔
1522
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
1523
         result.test_eq("Expected size for MP 0", bn_bytes, 0);
1✔
1524

1525
         botan_mp_set_from_int(x, 5);
1✔
1526
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
1527
         result.test_eq("Expected size for MP 5", bn_bytes, 1);
1✔
1528

1529
         botan_mp_add_u32(x, x, 75);
1✔
1530
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
1531
         result.test_eq("Expected size for MP 80", bn_bytes, 1);
1✔
1532

1533
         str_len = sizeof(str_buf);
1✔
1534
         TEST_FFI_OK(botan_mp_to_str, (x, 10, str_buf, &str_len));
1✔
1535
         result.test_eq("botan_mp_add", std::string(str_buf), "80");
2✔
1536

1537
         botan_mp_sub_u32(x, x, 80);
1✔
1538
         TEST_FFI_RC(1, botan_mp_is_zero, (x));
1✔
1539
         botan_mp_add_u32(x, x, 259);
1✔
1540
         TEST_FFI_OK(botan_mp_num_bytes, (x, &bn_bytes));
1✔
1541
         result.test_eq("Expected size for MP 259", bn_bytes, 2);
1✔
1542

1543
         str_len = sizeof(str_buf);
1✔
1544
         TEST_FFI_OK(botan_mp_to_str, (x, 10, str_buf, &str_len));
1✔
1545
         result.test_eq("botan_mp_add", std::string(str_buf), "259");
2✔
1546

1547
         TEST_FFI_RC(1, botan_mp_is_odd, (x));
1✔
1548
         TEST_FFI_RC(0, botan_mp_is_even, (x));
1✔
1549
         TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
1550
         TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
1551
         TEST_FFI_RC(0, botan_mp_is_zero, (x));
1✔
1552

1553
         {
1✔
1554
            botan_mp_t zero;
1✔
1555
            botan_mp_init(&zero);
1✔
1556
            int cmp;
1✔
1557
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, zero));
1✔
1558
            result.confirm("bigint_mp_cmp(+, 0)", cmp == 1);
2✔
1559

1560
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, x));
1✔
1561
            result.confirm("bigint_mp_cmp(0, +)", cmp == -1);
2✔
1562

1563
            TEST_FFI_RC(0, botan_mp_is_negative, (x));
1✔
1564
            TEST_FFI_RC(1, botan_mp_is_positive, (x));
1✔
1565
            TEST_FFI_OK(botan_mp_flip_sign, (x));
1✔
1566
            TEST_FFI_RC(1, botan_mp_is_negative, (x));
1✔
1567
            TEST_FFI_RC(0, botan_mp_is_positive, (x));
1✔
1568

1569
            // test no negative zero
1570
            TEST_FFI_RC(0, botan_mp_is_negative, (zero));
1✔
1571
            TEST_FFI_RC(1, botan_mp_is_positive, (zero));
1✔
1572
            TEST_FFI_OK(botan_mp_flip_sign, (zero));
1✔
1573
            TEST_FFI_RC(0, botan_mp_is_negative, (zero));
1✔
1574
            TEST_FFI_RC(1, botan_mp_is_positive, (zero));
1✔
1575

1576
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, zero));
1✔
1577
            result.confirm("bigint_mp_cmp(-, 0)", cmp == -1);
2✔
1578

1579
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, x));
1✔
1580
            result.confirm("bigint_mp_cmp(0, -)", cmp == 1);
2✔
1581

1582
            TEST_FFI_OK(botan_mp_cmp, (&cmp, zero, zero));
1✔
1583
            result.confirm("bigint_mp_cmp(0, 0)", cmp == 0);
2✔
1584

1585
            TEST_FFI_OK(botan_mp_cmp, (&cmp, x, x));
1✔
1586
            result.confirm("bigint_mp_cmp(x, x)", cmp == 0);
2✔
1587

1588
            TEST_FFI_OK(botan_mp_flip_sign, (x));
1✔
1589

1590
            botan_mp_destroy(zero);
1✔
1591
         }
1592

1593
         size_t x_bits = 0;
1✔
1594
         TEST_FFI_OK(botan_mp_num_bits, (x, &x_bits));
1✔
1595
         result.test_eq("botan_mp_num_bits", x_bits, 9);
1✔
1596

1597
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
1598
         result.test_eq("botan_mp_to_hex", std::string(str_buf), "0x0103");
2✔
1599

1600
         uint32_t x_32;
1✔
1601
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
1602
         result.test_eq("botan_mp_to_uint32", size_t(x_32), size_t(0x103));
1✔
1603

1604
         TEST_FFI_RC(1, botan_mp_get_bit, (x, 1));
1✔
1605
         TEST_FFI_RC(0, botan_mp_get_bit, (x, 87));
1✔
1606
         TEST_FFI_OK(botan_mp_set_bit, (x, 87));
1✔
1607
         TEST_FFI_RC(1, botan_mp_get_bit, (x, 87));
1✔
1608
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
1609
         result.test_eq("botan_mp_set_bit", std::string(str_buf), "0x8000000000000000000103");
3✔
1610

1611
         TEST_FFI_OK(botan_mp_clear_bit, (x, 87));
1✔
1612
         TEST_FFI_OK(botan_mp_to_hex, (x, str_buf));
1✔
1613
         result.test_eq("botan_mp_set_bit", std::string(str_buf), "0x0103");
2✔
1614

1615
         botan_mp_t y;
1✔
1616
         TEST_FFI_OK(botan_mp_init, (&y));
1✔
1617
         TEST_FFI_OK(botan_mp_set_from_int, (y, 0x1234567));
1✔
1618

1619
         botan_mp_t r;
1✔
1620
         botan_mp_init(&r);
1✔
1621

1622
         TEST_FFI_OK(botan_mp_add, (r, x, y));
1✔
1623
         str_len = sizeof(str_buf);
1✔
1624
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1625
         result.test_eq("botan_mp_add", std::string(str_buf), "19089002");
2✔
1626

1627
         TEST_FFI_OK(botan_mp_mul, (r, x, y));
1✔
1628
         str_len = sizeof(str_buf);
1✔
1629
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1630
         result.test_eq("botan_mp_mul", std::string(str_buf), "4943984437");
2✔
1631
         TEST_FFI_RC(0, botan_mp_is_negative, (r));
1✔
1632

1633
         botan_mp_t q;
1✔
1634
         botan_mp_init(&q);
1✔
1635
         TEST_FFI_OK(botan_mp_div, (q, r, y, x));
1✔
1636

1637
         str_len = sizeof(str_buf);
1✔
1638
         TEST_FFI_OK(botan_mp_to_str, (q, 10, str_buf, &str_len));
1✔
1639
         result.test_eq("botan_mp_div_q", std::string(str_buf), "73701");
2✔
1640

1641
         str_len = sizeof(str_buf);
1✔
1642
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1643
         result.test_eq("botan_mp_div_r", std::string(str_buf), "184");
2✔
1644

1645
         TEST_FFI_OK(botan_mp_set_from_str, (y, "4943984437"));
1✔
1646
         TEST_FFI_OK(botan_mp_sub, (r, x, y));
1✔
1647
         str_len = sizeof(str_buf);
1✔
1648
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1649
         result.test_eq("botan_mp_sub", std::string(str_buf), "-4943984178");
2✔
1650
         TEST_FFI_RC(1, botan_mp_is_negative, (r));
1✔
1651

1652
         TEST_FFI_OK(botan_mp_lshift, (r, x, 39));
1✔
1653
         str_len = sizeof(str_buf);
1✔
1654
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1655
         result.test_eq("botan_mp_lshift", std::string(str_buf), "142386755796992");
2✔
1656

1657
         TEST_FFI_OK(botan_mp_rshift, (r, r, 3));
1✔
1658
         str_len = sizeof(str_buf);
1✔
1659
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1660
         result.test_eq("botan_mp_rshift", std::string(str_buf), "17798344474624");
2✔
1661

1662
         TEST_FFI_OK(botan_mp_gcd, (r, x, y));
1✔
1663
         str_len = sizeof(str_buf);
1✔
1664
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1665
         result.test_eq("botan_mp_gcd", std::string(str_buf), "259");
2✔
1666

1667
         botan_mp_t p;
1✔
1668
         botan_mp_init(&p);
1✔
1669
         const uint8_t M127[] = {
1✔
1670
            0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1671
         TEST_FFI_OK(botan_mp_from_bin, (p, M127, sizeof(M127)));
1✔
1672
         TEST_FFI_RC(1, botan_mp_is_prime, (p, rng, 64));
1✔
1673

1674
         size_t p_bits = 0;
1✔
1675
         TEST_FFI_OK(botan_mp_num_bits, (p, &p_bits));
1✔
1676
         result.test_eq("botan_mp_num_bits", p_bits, 127);
1✔
1677

1678
         TEST_FFI_OK(botan_mp_mod_inverse, (r, x, p));
1✔
1679
         str_len = sizeof(str_buf);
1✔
1680
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1681
         result.test_eq("botan_mp_mod_inverse", std::string(str_buf), "40728777507911553541948312086427855425");
3✔
1682

1683
         TEST_FFI_OK(botan_mp_powmod, (r, x, r, p));
1✔
1684
         str_len = sizeof(str_buf);
1✔
1685
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1686
         result.test_eq("botan_mp_powmod", std::string(str_buf), "40550417419160441638948180641668117560");
3✔
1687

1688
         TEST_FFI_OK(botan_mp_num_bytes, (r, &bn_bytes));
1✔
1689
         result.test_eq("botan_mp_num_bytes", bn_bytes, 16);
1✔
1690

1691
         std::vector<uint8_t> bn_buf;
1✔
1692
         bn_buf.resize(bn_bytes);
1✔
1693
         botan_mp_to_bin(r, bn_buf.data());
1✔
1694
         result.test_eq("botan_mp_to_bin", bn_buf, "1E81B9EFE0BE1902F6D03F9F5E5FB438");
1✔
1695

1696
         TEST_FFI_OK(botan_mp_set_from_mp, (y, r));
1✔
1697
         TEST_FFI_OK(botan_mp_mod_mul, (r, x, y, p));
1✔
1698
         str_len = sizeof(str_buf);
1✔
1699
         TEST_FFI_OK(botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1700
         result.test_eq("botan_mp_mod_mul", std::string(str_buf), "123945920473931248854653259523111998693");
3✔
1701

1702
         str_len = 0;
1✔
1703
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE, botan_mp_to_str, (r, 10, str_buf, &str_len));
1✔
1704

1705
         size_t x_bytes;
1✔
1706
         botan_mp_rand_bits(x, rng, 512);
1✔
1707
         TEST_FFI_OK(botan_mp_num_bytes, (x, &x_bytes));
1✔
1708
         result.test_lte("botan_mp_num_bytes", x_bytes, 512 / 8);
1✔
1709

1710
         TEST_FFI_OK(botan_mp_set_from_radix_str, (x, "909A", 16));
1✔
1711
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
1712
         result.test_eq("botan_mp_set_from_radix_str(16)", x_32, static_cast<size_t>(0x909A));
1✔
1713

1714
         TEST_FFI_OK(botan_mp_set_from_radix_str, (x, "9098135", 10));
1✔
1715
         TEST_FFI_OK(botan_mp_to_uint32, (x, &x_32));
1✔
1716
         result.test_eq("botan_mp_set_from_radix_str(10)", x_32, static_cast<size_t>(9098135));
1✔
1717

1718
         botan_mp_destroy(p);
1✔
1719
         botan_mp_destroy(x);
1✔
1720
         botan_mp_destroy(y);
1✔
1721
         botan_mp_destroy(r);
1✔
1722
         botan_mp_destroy(q);
1✔
1723
      }
1✔
1724
};
1725

1726
class FFI_FPE_Test final : public FFI_Test {
×
1727
   public:
1728
      std::string name() const override { return "FFI FPE"; }
1✔
1729

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

1733
         botan_mp_t n;
1✔
1734
         botan_mp_init(&n);
1✔
1735
         botan_mp_set_from_str(n, "1000000000");
1✔
1736

1737
         botan_fpe_t fpe;
1✔
1738
         if(!TEST_FFI_INIT(botan_fpe_fe1_init, (&fpe, n, key, sizeof(key), 5, 0))) {
2✔
1739
            botan_mp_destroy(n);
×
1740
            return;
×
1741
         }
1742

1743
         botan_mp_t x;
1✔
1744
         botan_mp_init(&x);
1✔
1745
         botan_mp_set_from_str(x, "178051120");
1✔
1746

1747
         TEST_FFI_OK(botan_fpe_encrypt, (fpe, x, nullptr, 0));
1✔
1748

1749
         uint32_t xval = 0;
1✔
1750
         TEST_FFI_OK(botan_mp_to_uint32, (x, &xval));
1✔
1751
         result.test_eq("Expected FPE ciphertext", xval, size_t(605648666));
1✔
1752

1753
         TEST_FFI_OK(botan_fpe_encrypt, (fpe, x, nullptr, 0));
1✔
1754
         TEST_FFI_OK(botan_fpe_decrypt, (fpe, x, nullptr, 0));
1✔
1755
         TEST_FFI_OK(botan_fpe_decrypt, (fpe, x, nullptr, 0));
1✔
1756

1757
         TEST_FFI_OK(botan_mp_to_uint32, (x, &xval));
1✔
1758
         result.test_eq("FPE round trip", xval, size_t(178051120));
1✔
1759

1760
         TEST_FFI_OK(botan_fpe_destroy, (fpe));
1✔
1761
         TEST_FFI_OK(botan_mp_destroy, (x));
1✔
1762
         TEST_FFI_OK(botan_mp_destroy, (n));
2✔
1763
      }
1764
};
1765

1766
class FFI_TOTP_Test final : public FFI_Test {
×
1767
   public:
1768
      std::string name() const override { return "FFI TOTP"; }
1✔
1769

1770
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1771
         const std::vector<uint8_t> key = Botan::hex_decode("3132333435363738393031323334353637383930");
1✔
1772
         const size_t digits = 8;
1✔
1773
         const size_t timestep = 30;
1✔
1774
         botan_totp_t totp;
1✔
1775

1776
         if(!TEST_FFI_INIT(botan_totp_init, (&totp, key.data(), key.size(), "SHA-1", digits, timestep)))
1✔
1777
            return;
×
1778

1779
         uint32_t code;
1✔
1780
         TEST_FFI_OK(botan_totp_generate, (totp, &code, 59));
1✔
1781
         result.confirm("TOTP code", code == 94287082);
2✔
1782

1783
         TEST_FFI_OK(botan_totp_generate, (totp, &code, 1111111109));
1✔
1784
         result.confirm("TOTP code 2", code == 7081804);
2✔
1785

1786
         TEST_FFI_OK(botan_totp_check, (totp, 94287082, 59 + 60, 60));
1✔
1787
         TEST_FFI_RC(1, botan_totp_check, (totp, 94287082, 59 + 31, 1));
1✔
1788
         TEST_FFI_RC(1, botan_totp_check, (totp, 94287082, 59 + 61, 1));
1✔
1789

1790
         TEST_FFI_OK(botan_totp_destroy, (totp));
2✔
1791
      }
1✔
1792
};
1793

1794
class FFI_HOTP_Test final : public FFI_Test {
×
1795
   public:
1796
      std::string name() const override { return "FFI HOTP"; }
1✔
1797

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

1802
         botan_hotp_t hotp;
1✔
1803
         uint32_t hotp_val;
1✔
1804

1805
         if(!TEST_FFI_INIT(botan_hotp_init, (&hotp, key.data(), key.size(), "SHA-1", digits)))
1✔
1806
            return;
×
1807

1808
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 0));
1✔
1809
         result.confirm("Valid value for counter 0", hotp_val == 755224);
2✔
1810
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 1));
1✔
1811
         result.confirm("Valid value for counter 0", hotp_val == 287082);
2✔
1812
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 2));
1✔
1813
         result.confirm("Valid value for counter 0", hotp_val == 359152);
2✔
1814
         TEST_FFI_OK(botan_hotp_generate, (hotp, &hotp_val, 0));
1✔
1815
         result.confirm("Valid value for counter 0", hotp_val == 755224);
2✔
1816

1817
         uint64_t next_ctr = 0;
1✔
1818

1819
         TEST_FFI_OK(botan_hotp_check, (hotp, &next_ctr, 755224, 0, 0));
1✔
1820
         result.confirm("HOTP resync", next_ctr == 1);
2✔
1821
         TEST_FFI_OK(botan_hotp_check, (hotp, nullptr, 359152, 2, 0));
1✔
1822
         TEST_FFI_RC(1, botan_hotp_check, (hotp, nullptr, 359152, 1, 0));
1✔
1823
         TEST_FFI_OK(botan_hotp_check, (hotp, &next_ctr, 359152, 0, 2));
1✔
1824
         result.confirm("HOTP resync", next_ctr == 3);
2✔
1825

1826
         TEST_FFI_OK(botan_hotp_destroy, (hotp));
2✔
1827
      }
1✔
1828
};
1829

1830
class FFI_Keywrap_Test final : public FFI_Test {
×
1831
   public:
1832
      std::string name() const override { return "FFI Keywrap"; }
1✔
1833

1834
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
1835
         const uint8_t key[16] = {0};
1✔
1836
         const uint8_t kek[16] = {0xFF, 0};
1✔
1837

1838
         uint8_t wrapped[16 + 8] = {0};
1✔
1839
         size_t wrapped_keylen = sizeof(wrapped);
1✔
1840

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

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

1848
            result.test_eq(
1✔
1849
               nullptr, "Wrapped key", wrapped, wrapped_keylen, expected_wrapped_key, sizeof(expected_wrapped_key));
1850

1851
            uint8_t dec_key[16] = {0};
1✔
1852
            size_t dec_keylen = sizeof(dec_key);
1✔
1853
            TEST_FFI_OK(botan_key_unwrap3394, (wrapped, sizeof(wrapped), kek, sizeof(kek), dec_key, &dec_keylen));
1✔
1854

1855
            result.test_eq(nullptr, "Unwrapped key", dec_key, dec_keylen, key, sizeof(key));
2✔
1856
         }
1857
      }
1✔
1858
};
1859

1860
class FFI_RSA_Test final : public FFI_Test {
×
1861
   public:
1862
      std::string name() const override { return "FFI RSA"; }
1✔
1863

1864
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
1865
         botan_privkey_t priv;
1✔
1866

1867
         if(TEST_FFI_INIT(botan_privkey_create_rsa, (&priv, rng, 1024))) {
2✔
1868
            TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
1✔
1869

1870
            botan_pubkey_t pub;
1✔
1871
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
1872
            TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
1✔
1873

1874
            ffi_test_pubkey_export(result, pub, priv, rng);
1✔
1875

1876
            botan_mp_t p, q, d, n, e;
1✔
1877
            botan_mp_init(&p);
1✔
1878
            botan_mp_init(&q);
1✔
1879
            botan_mp_init(&d);
1✔
1880
            botan_mp_init(&n);
1✔
1881
            botan_mp_init(&e);
1✔
1882

1883
            TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (p, priv, "quux"));
1✔
1884
            TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_pubkey_get_field, (p, pub, "quux"));
1✔
1885

1886
            TEST_FFI_OK(botan_privkey_rsa_get_p, (p, priv));
1✔
1887
            TEST_FFI_OK(botan_privkey_rsa_get_q, (q, priv));
1✔
1888
            TEST_FFI_OK(botan_privkey_rsa_get_d, (d, priv));
1✔
1889
            TEST_FFI_OK(botan_privkey_rsa_get_e, (e, priv));
1✔
1890
            TEST_FFI_OK(botan_privkey_rsa_get_n, (n, priv));
1✔
1891

1892
            // Confirm same (e,n) values in public key
1893
            {
1✔
1894
               botan_mp_t pub_e, pub_n;
1✔
1895
               botan_mp_init(&pub_e);
1✔
1896
               botan_mp_init(&pub_n);
1✔
1897
               TEST_FFI_OK(botan_pubkey_rsa_get_e, (pub_e, pub));
1✔
1898
               TEST_FFI_OK(botan_pubkey_rsa_get_n, (pub_n, pub));
1✔
1899

1900
               TEST_FFI_RC(1, botan_mp_equal, (pub_e, e));
1✔
1901
               TEST_FFI_RC(1, botan_mp_equal, (pub_n, n));
1✔
1902
               botan_mp_destroy(pub_e);
1✔
1903
               botan_mp_destroy(pub_n);
1✔
1904
            }
1905

1906
            TEST_FFI_RC(1, botan_mp_is_prime, (p, rng, 64));
1✔
1907
            TEST_FFI_RC(1, botan_mp_is_prime, (q, rng, 64));
1✔
1908

1909
            // Test p != q
1910
            TEST_FFI_RC(0, botan_mp_equal, (p, q));
1✔
1911

1912
            // Test p * q == n
1913
            botan_mp_t x;
1✔
1914
            botan_mp_init(&x);
1✔
1915
            TEST_FFI_OK(botan_mp_mul, (x, p, q));
1✔
1916

1917
            TEST_FFI_RC(1, botan_mp_equal, (x, n));
1✔
1918
            botan_mp_destroy(x);
1✔
1919

1920
            botan_privkey_t loaded_privkey;
1✔
1921
            // First try loading a bogus key and verify check_key fails
1922
            TEST_FFI_OK(botan_privkey_load_rsa, (&loaded_privkey, n, d, q));
1✔
1923
            TEST_FFI_RC(-1, botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
1924
            botan_privkey_destroy(loaded_privkey);
1✔
1925

1926
            TEST_FFI_OK(botan_privkey_load_rsa, (&loaded_privkey, p, q, e));
1✔
1927
            TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
1928

1929
            botan_pubkey_t loaded_pubkey;
1✔
1930
            TEST_FFI_OK(botan_pubkey_load_rsa, (&loaded_pubkey, n, e));
1✔
1931
            TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
1932

1933
            botan_mp_destroy(p);
1✔
1934
            botan_mp_destroy(q);
1✔
1935
            botan_mp_destroy(d);
1✔
1936
            botan_mp_destroy(e);
1✔
1937
            botan_mp_destroy(n);
1✔
1938

1939
            size_t pkcs1_len = 0;
1✔
1940
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1941
                        botan_privkey_rsa_get_privkey,
1942
                        (loaded_privkey, nullptr, &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
1943

1944
            std::vector<uint8_t> pkcs1(pkcs1_len);
1✔
1945
            TEST_FFI_OK(botan_privkey_rsa_get_privkey,
1✔
1946
                        (loaded_privkey, pkcs1.data(), &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_DER));
1947

1948
            botan_privkey_t privkey_from_pkcs1;
1✔
1949
            TEST_FFI_OK(botan_privkey_load_rsa_pkcs1, (&privkey_from_pkcs1, pkcs1.data(), pkcs1_len));
1✔
1950
            TEST_FFI_OK(botan_privkey_destroy, (privkey_from_pkcs1));
1✔
1951

1952
            pkcs1_len = 0;
1✔
1953
            TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
1954
                        botan_privkey_rsa_get_privkey,
1955
                        (loaded_privkey, nullptr, &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
1956
            pkcs1.resize(pkcs1_len);
1✔
1957
            TEST_FFI_OK(botan_privkey_rsa_get_privkey,
1✔
1958
                        (loaded_privkey, pkcs1.data(), &pkcs1_len, BOTAN_PRIVKEY_EXPORT_FLAG_PEM));
1959

1960
            char namebuf[32] = {0};
1✔
1961
            size_t name_len = sizeof(namebuf);
1✔
1962
            if(TEST_FFI_OK(botan_pubkey_algo_name, (loaded_pubkey, namebuf, &name_len))) {
2✔
1963
               result.test_eq("algo name", std::string(namebuf), "RSA");
2✔
1964
            }
1965

1966
            name_len = sizeof(namebuf);
1✔
1967
            if(TEST_FFI_OK(botan_privkey_algo_name, (loaded_privkey, namebuf, &name_len))) {
2✔
1968
               result.test_eq("algo name", std::string(namebuf), "RSA");
2✔
1969
            }
1970

1971
            botan_pk_op_encrypt_t encrypt;
1✔
1972

1973
            if(TEST_FFI_INIT(botan_pk_op_encrypt_create, (&encrypt, loaded_pubkey, "OAEP(SHA-256)", 0))) {
2✔
1974
               std::vector<uint8_t> plaintext(32);
1✔
1975
               TEST_FFI_OK(botan_rng_get, (rng, plaintext.data(), plaintext.size()));
1✔
1976

1977
               size_t ctext_len;
1✔
1978
               TEST_FFI_OK(botan_pk_op_encrypt_output_length, (encrypt, plaintext.size(), &ctext_len));
1✔
1979
               std::vector<uint8_t> ciphertext(ctext_len);
1✔
1980

1981
               if(TEST_FFI_OK(botan_pk_op_encrypt,
2✔
1982
                              (encrypt, rng, ciphertext.data(), &ctext_len, plaintext.data(), plaintext.size()))) {
1983
                  ciphertext.resize(ctext_len);
1✔
1984

1985
                  botan_pk_op_decrypt_t decrypt;
1✔
1986
                  if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&decrypt, priv, "OAEP(SHA-256)", 0))) {
2✔
1987
                     size_t decrypted_len;
1✔
1988
                     TEST_FFI_OK(botan_pk_op_decrypt_output_length, (decrypt, ciphertext.size(), &decrypted_len));
1✔
1989
                     std::vector<uint8_t> decrypted(decrypted_len);
1✔
1990
                     TEST_FFI_OK(botan_pk_op_decrypt,
1✔
1991
                                 (decrypt, decrypted.data(), &decrypted_len, ciphertext.data(), ciphertext.size()));
1992
                     decrypted.resize(decrypted_len);
1✔
1993

1994
                     result.test_eq("RSA plaintext", decrypted, plaintext);
2✔
1995
                  }
1✔
1996

1997
                  TEST_FFI_OK(botan_pk_op_decrypt_destroy, (decrypt));
2✔
1998
               }
1999

2000
               TEST_FFI_OK(botan_pk_op_encrypt_destroy, (encrypt));
2✔
2001
            }
2✔
2002

2003
            TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
1✔
2004
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
2005
            TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
2006
            TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
2007
         }
1✔
2008
      }
1✔
2009
};
2010

2011
class FFI_DSA_Test final : public FFI_Test {
×
2012
   public:
2013
      std::string name() const override { return "FFI DSA"; }
1✔
2014

2015
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2016
         botan_privkey_t priv;
1✔
2017

2018
         if(TEST_FFI_INIT(botan_privkey_create, (&priv, "DSA", "dsa/jce/1024", rng))) {
2✔
2019
            do_dsa_test(priv, rng, result);
1✔
2020
         }
2021

2022
         if(TEST_FFI_INIT(botan_privkey_create_dsa, (&priv, rng, 1024, 160))) {
2✔
2023
            do_dsa_test(priv, rng, result);
1✔
2024
         }
2025
      }
1✔
2026

2027
   private:
2028
      static void do_dsa_test(botan_privkey_t priv, botan_rng_t rng, Test::Result& result) {
2✔
2029
         TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
2✔
2030

2031
         botan_pubkey_t pub;
2✔
2032
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
2✔
2033
         TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
2✔
2034

2035
         ffi_test_pubkey_export(result, pub, priv, rng);
2✔
2036

2037
         botan_mp_t p, q, g, x, y;
2✔
2038
         botan_mp_init(&p);
2✔
2039
         botan_mp_init(&q);
2✔
2040
         botan_mp_init(&g);
2✔
2041
         botan_mp_init(&x);
2✔
2042
         botan_mp_init(&y);
2✔
2043

2044
         TEST_FFI_OK(botan_privkey_dsa_get_x, (x, priv));
2✔
2045
         TEST_FFI_OK(botan_pubkey_dsa_get_g, (g, pub));
2✔
2046
         TEST_FFI_OK(botan_pubkey_dsa_get_p, (p, pub));
2✔
2047
         TEST_FFI_OK(botan_pubkey_dsa_get_q, (q, pub));
2✔
2048
         TEST_FFI_OK(botan_pubkey_dsa_get_y, (y, pub));
2✔
2049

2050
         botan_mp_t cmp;
2✔
2051
         botan_mp_init(&cmp);
2✔
2052
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (cmp, priv, "quux"));
2✔
2053

2054
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "x"));
2✔
2055
         TEST_FFI_RC(1, botan_mp_equal, (cmp, x));
2✔
2056

2057
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "y"));
2✔
2058
         TEST_FFI_RC(1, botan_mp_equal, (cmp, y));
2✔
2059

2060
         TEST_FFI_OK(botan_privkey_get_field, (cmp, priv, "p"));
2✔
2061
         TEST_FFI_RC(1, botan_mp_equal, (cmp, p));
2✔
2062
         botan_mp_destroy(cmp);
2✔
2063

2064
         botan_privkey_t loaded_privkey;
2✔
2065
         TEST_FFI_OK(botan_privkey_load_dsa, (&loaded_privkey, p, q, g, x));
2✔
2066
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
2✔
2067

2068
         botan_pubkey_t loaded_pubkey;
2✔
2069
         TEST_FFI_OK(botan_pubkey_load_dsa, (&loaded_pubkey, p, q, g, y));
2✔
2070
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
2✔
2071

2072
         botan_mp_destroy(p);
2✔
2073
         botan_mp_destroy(q);
2✔
2074
         botan_mp_destroy(g);
2✔
2075
         botan_mp_destroy(y);
2✔
2076
         botan_mp_destroy(x);
2✔
2077

2078
         botan_pk_op_sign_t signer;
2✔
2079

2080
         std::vector<uint8_t> message(6, 6);
2✔
2081
         std::vector<uint8_t> signature;
2✔
2082

2083
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, loaded_privkey, "SHA-256", 0))) {
4✔
2084
            // TODO: break input into multiple calls to update
2085
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
2✔
2086

2087
            size_t sig_len;
2✔
2088
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
2✔
2089
            signature.resize(sig_len);
2✔
2090

2091
            size_t output_sig_len = sig_len;
2✔
2092
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &output_sig_len));
2✔
2093
            result.test_lte("Output length is upper bound", output_sig_len, sig_len);
2✔
2094
            signature.resize(output_sig_len);
2✔
2095

2096
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
4✔
2097
         }
2098

2099
         botan_pk_op_verify_t verifier = nullptr;
2✔
2100

2101
         if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-256", 0))) {
4✔
2102
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2103
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
2104

2105
            // TODO: randomize this
2106
            signature[0] ^= 1;
2✔
2107
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2108
            TEST_FFI_RC(
2✔
2109
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2110

2111
            message[0] ^= 1;
2✔
2112
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2113
            TEST_FFI_RC(
2✔
2114
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2115

2116
            signature[0] ^= 1;
2✔
2117
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2118
            TEST_FFI_RC(
2✔
2119
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2120

2121
            message[0] ^= 1;
2✔
2122
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2123
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
2124

2125
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
4✔
2126
         }
2127

2128
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
2129
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
2✔
2130
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
2✔
2131
         TEST_FFI_OK(botan_privkey_destroy, (priv));
4✔
2132
      }
4✔
2133
};
2134

2135
class FFI_ECDSA_Test final : public FFI_Test {
×
2136
   public:
2137
      std::string name() const override { return "FFI ECDSA"; }
1✔
2138

2139
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2140
         static const char* kCurve = "secp384r1";
1✔
2141
         botan_privkey_t priv;
1✔
2142
         botan_pubkey_t pub;
1✔
2143

2144
         if(!TEST_FFI_INIT(botan_privkey_create_ecdsa, (&priv, rng, kCurve)))
2✔
2145
            return;
×
2146

2147
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
2148
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
2149

2150
         // Check key load functions
2151
         botan_mp_t private_scalar, public_x, public_y;
1✔
2152
         botan_mp_init(&private_scalar);
1✔
2153
         botan_mp_init(&public_x);
1✔
2154
         botan_mp_init(&public_y);
1✔
2155

2156
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_privkey_get_field, (private_scalar, priv, "quux"));
1✔
2157
         TEST_FFI_RC(BOTAN_FFI_ERROR_BAD_PARAMETER, botan_pubkey_get_field, (private_scalar, pub, "quux"));
1✔
2158

2159
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
2160
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
2161
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
2162

2163
         botan_privkey_t loaded_privkey;
1✔
2164
         botan_pubkey_t loaded_pubkey;
1✔
2165
         TEST_FFI_OK(botan_privkey_load_ecdsa, (&loaded_privkey, private_scalar, kCurve));
1✔
2166
         TEST_FFI_OK(botan_pubkey_load_ecdsa, (&loaded_pubkey, public_x, public_y, kCurve));
1✔
2167
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
2168
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
2169

2170
         char namebuf[32] = {0};
1✔
2171
         size_t name_len = sizeof(namebuf);
1✔
2172

2173
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, &namebuf[0], &name_len));
1✔
2174
         result.test_eq(namebuf, namebuf, "ECDSA");
1✔
2175

2176
         std::vector<uint8_t> message(1280), signature;
1✔
2177
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
2178

2179
         for(uint32_t flags = 0; flags <= 1; ++flags) {
3✔
2180
            botan_pk_op_sign_t signer;
2✔
2181
            if(TEST_FFI_INIT(botan_pk_op_sign_create, (&signer, loaded_privkey, "SHA-384", flags))) {
4✔
2182
               // TODO: break input into multiple calls to update
2183
               TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
2✔
2184

2185
               size_t sig_len;
2✔
2186
               TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
2✔
2187

2188
               signature.resize(sig_len);
2✔
2189

2190
               size_t output_sig_len = signature.size();
2✔
2191
               TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &output_sig_len));
2✔
2192
               signature.resize(output_sig_len);
2✔
2193

2194
               TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
4✔
2195
            }
2196

2197
            botan_pk_op_verify_t verifier = nullptr;
2✔
2198

2199
            if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-384", flags))) {
4✔
2200
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2201
               TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
2202

2203
               // TODO: randomize this
2204
               signature[0] ^= 1;
2✔
2205
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2206
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
2207
                           botan_pk_op_verify_finish,
2208
                           (verifier, signature.data(), signature.size()));
2209

2210
               message[0] ^= 1;
2✔
2211
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2212
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
2213
                           botan_pk_op_verify_finish,
2214
                           (verifier, signature.data(), signature.size()));
2215

2216
               signature[0] ^= 1;
2✔
2217
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2218
               TEST_FFI_RC(BOTAN_FFI_INVALID_VERIFIER,
2✔
2219
                           botan_pk_op_verify_finish,
2220
                           (verifier, signature.data(), signature.size()));
2221

2222
               message[0] ^= 1;
2✔
2223
               TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
2✔
2224
               TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2✔
2225

2226
               TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
4✔
2227
            }
2228
         }
2229

2230
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
2231
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
2232
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
2233
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
2234
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
2235
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
2236
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
2237
      }
2✔
2238
};
2239

2240
class FFI_SM2_Sig_Test final : public FFI_Test {
×
2241
   public:
2242
      std::string name() const override { return "FFI SM2 Sig"; }
1✔
2243

2244
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2245
         static const char* kCurve = "sm2p256v1";
1✔
2246
         const std::string sm2_ident = "SM2 Ident Field";
1✔
2247
         botan_privkey_t priv;
1✔
2248
         botan_pubkey_t pub;
1✔
2249
         botan_privkey_t loaded_privkey;
1✔
2250
         botan_pubkey_t loaded_pubkey;
1✔
2251

2252
         if(!TEST_FFI_INIT(botan_privkey_create, (&priv, "SM2_Sig", kCurve, rng)))
2✔
2253
            return;
2254

2255
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
2256
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
2257

2258
         uint8_t za[32];
1✔
2259
         size_t sizeof_za = sizeof(za);
1✔
2260
         TEST_FFI_OK(botan_pubkey_sm2_compute_za, (za, &sizeof_za, "Ident", "SM3", pub));
1✔
2261

2262
         // Check key load functions
2263
         botan_mp_t private_scalar, public_x, public_y;
1✔
2264
         botan_mp_init(&private_scalar);
1✔
2265
         botan_mp_init(&public_x);
1✔
2266
         botan_mp_init(&public_y);
1✔
2267

2268
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
2269
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
2270
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
2271
         REQUIRE_FFI_OK(botan_privkey_load_sm2, (&loaded_privkey, private_scalar, kCurve));
2✔
2272
         REQUIRE_FFI_OK(botan_pubkey_load_sm2, (&loaded_pubkey, public_x, public_y, kCurve));
2✔
2273
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
2274
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
2275

2276
         char namebuf[32] = {0};
1✔
2277
         size_t name_len = sizeof(namebuf);
1✔
2278

2279
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, &namebuf[0], &name_len));
1✔
2280
         result.test_eq(namebuf, namebuf, "SM2");
1✔
2281

2282
         std::vector<uint8_t> message(1280), signature;
1✔
2283
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
2284
         botan_pk_op_sign_t signer;
1✔
2285
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, loaded_privkey, sm2_ident.c_str(), 0))) {
2✔
2286
            // TODO: break input into multiple calls to update
2287
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
1✔
2288

2289
            size_t sig_len;
1✔
2290
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
1✔
2291

2292
            signature.resize(sig_len);
1✔
2293

2294
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_len));
1✔
2295
            signature.resize(sig_len);
1✔
2296

2297
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
2✔
2298
         }
2299

2300
         botan_pk_op_verify_t verifier = nullptr;
1✔
2301

2302
         if(!signature.empty() && TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, sm2_ident.c_str(), 0))) {
2✔
2303
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
2304
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
2305

2306
            // TODO: randomize this
2307
            signature[0] ^= 1;
1✔
2308
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
2309
            TEST_FFI_RC(
1✔
2310
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2311

2312
            message[0] ^= 1;
1✔
2313
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
2314
            TEST_FFI_RC(
1✔
2315
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2316

2317
            signature[0] ^= 1;
1✔
2318
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
2319
            TEST_FFI_RC(
1✔
2320
               BOTAN_FFI_INVALID_VERIFIER, botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
2321

2322
            message[0] ^= 1;
1✔
2323
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
2324
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
2325

2326
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
2✔
2327
         }
2328

2329
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
2330
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
2331
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
2332
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
2333
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
2334
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
2335
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
2336
      }
2✔
2337
};
2338

2339
class FFI_SM2_Enc_Test final : public FFI_Test {
×
2340
   public:
2341
      std::string name() const override { return "FFI SM2 Enc"; }
1✔
2342

2343
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2344
         static const char* kCurve = "sm2p256v1";
1✔
2345
         botan_privkey_t priv;
1✔
2346
         botan_pubkey_t pub;
1✔
2347
         botan_privkey_t loaded_privkey;
1✔
2348
         botan_pubkey_t loaded_pubkey;
1✔
2349

2350
         if(!TEST_FFI_INIT(botan_privkey_create, (&priv, "SM2_Enc", kCurve, rng)))
2✔
2351
            return;
×
2352

2353
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
2354
         ffi_test_pubkey_export(result, pub, priv, rng);
1✔
2355

2356
         uint8_t za[32];
1✔
2357
         size_t sizeof_za = sizeof(za);
1✔
2358
         TEST_FFI_OK(botan_pubkey_sm2_compute_za, (za, &sizeof_za, "Ident", "SM3", pub));
1✔
2359

2360
         // Check key load functions
2361
         botan_mp_t private_scalar, public_x, public_y;
1✔
2362
         botan_mp_init(&private_scalar);
1✔
2363
         botan_mp_init(&public_x);
1✔
2364
         botan_mp_init(&public_y);
1✔
2365

2366
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv, "x"));
1✔
2367
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub, "public_x"));
1✔
2368
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub, "public_y"));
1✔
2369
         REQUIRE_FFI_OK(botan_privkey_load_sm2_enc, (&loaded_privkey, private_scalar, kCurve));
2✔
2370
         REQUIRE_FFI_OK(botan_pubkey_load_sm2_enc, (&loaded_pubkey, public_x, public_y, kCurve));
2✔
2371
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey, rng, 0));
1✔
2372
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey, rng, 0));
1✔
2373

2374
         char namebuf[32] = {0};
1✔
2375
         size_t name_len = sizeof(namebuf);
1✔
2376

2377
         TEST_FFI_OK(botan_pubkey_algo_name, (pub, &namebuf[0], &name_len));
1✔
2378
         result.test_eq(namebuf, namebuf, "SM2");
1✔
2379

2380
         std::vector<uint8_t> message(32);
1✔
2381

2382
         std::vector<uint8_t> ciphertext;
1✔
2383
         TEST_FFI_OK(botan_rng_get, (rng, message.data(), message.size()));
1✔
2384

2385
         botan_pk_op_encrypt_t enc;
1✔
2386
         if(TEST_FFI_OK(botan_pk_op_encrypt_create, (&enc, loaded_pubkey, "", 0))) {
2✔
2387
            size_t ctext_len;
1✔
2388
            TEST_FFI_OK(botan_pk_op_encrypt_output_length, (enc, message.size(), &ctext_len));
1✔
2389

2390
            ciphertext.resize(ctext_len);
1✔
2391
            TEST_FFI_OK(botan_pk_op_encrypt, (enc, rng, ciphertext.data(), &ctext_len, message.data(), message.size()));
1✔
2392
            ciphertext.resize(ctext_len);
1✔
2393

2394
            botan_pk_op_decrypt_t dec;
1✔
2395
            TEST_FFI_OK(botan_pk_op_decrypt_create, (&dec, loaded_privkey, "", 0));
1✔
2396

2397
            std::vector<uint8_t> recovered(message.size());
1✔
2398
            size_t recovered_len = recovered.size();
1✔
2399

2400
            TEST_FFI_OK(botan_pk_op_decrypt,
1✔
2401
                        (dec, recovered.data(), &recovered_len, ciphertext.data(), ciphertext.size()));
2402

2403
            botan_pk_op_decrypt_destroy(dec);
1✔
2404
         }
1✔
2405
         botan_pk_op_encrypt_destroy(enc);
1✔
2406

2407
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
2408
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
2409
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
2410
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
2411
         TEST_FFI_OK(botan_privkey_destroy, (priv));
1✔
2412
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
1✔
2413
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
2414
      }
2✔
2415
};
2416

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

2421
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2422
         botan_privkey_t priv1;
1✔
2423
         if(!TEST_FFI_INIT(botan_privkey_create_ecdh, (&priv1, rng, "secp256r1")))
2✔
2424
            return;
×
2425

2426
         botan_privkey_t priv2;
1✔
2427
         REQUIRE_FFI_OK(botan_privkey_create_ecdh, (&priv2, rng, "secp256r1"));
2✔
2428

2429
         botan_pubkey_t pub1;
1✔
2430
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub1, priv1));
2✔
2431

2432
         botan_pubkey_t pub2;
1✔
2433
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub2, priv2));
2✔
2434

2435
         /* Reload key-pair1 in order to test functions for key loading */
2436
         botan_mp_t private_scalar, public_x, public_y;
1✔
2437
         botan_mp_init(&private_scalar);
1✔
2438
         botan_mp_init(&public_x);
1✔
2439
         botan_mp_init(&public_y);
1✔
2440

2441
         TEST_FFI_OK(botan_privkey_get_field, (private_scalar, priv1, "x"));
1✔
2442
         TEST_FFI_OK(botan_pubkey_get_field, (public_x, pub1, "public_x"));
1✔
2443
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub1, "public_y"));
1✔
2444

2445
         botan_privkey_t loaded_privkey1;
1✔
2446
         botan_pubkey_t loaded_pubkey1;
1✔
2447
         REQUIRE_FFI_OK(botan_privkey_load_ecdh, (&loaded_privkey1, private_scalar, "secp256r1"));
2✔
2448
         REQUIRE_FFI_OK(botan_pubkey_load_ecdh, (&loaded_pubkey1, public_x, public_y, "secp256r1"));
2✔
2449
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey1, rng, 0));
1✔
2450
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
2451

2452
         ffi_test_pubkey_export(result, loaded_pubkey1, priv1, rng);
1✔
2453
         ffi_test_pubkey_export(result, pub2, priv2, rng);
1✔
2454

2455
         botan_pk_op_ka_t ka1;
1✔
2456
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka1, loaded_privkey1, "KDF2(SHA-256)", 0));
2✔
2457
         botan_pk_op_ka_t ka2;
1✔
2458
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka2, priv2, "KDF2(SHA-256)", 0));
2✔
2459

2460
         size_t pubkey1_len = 0;
1✔
2461
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
2462
                     botan_pk_op_key_agreement_export_public,
2463
                     (priv1, nullptr, &pubkey1_len));
2464
         std::vector<uint8_t> pubkey1(pubkey1_len);
1✔
2465
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv1, pubkey1.data(), &pubkey1_len));
2✔
2466
         size_t pubkey2_len = 0;
1✔
2467
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
2468
                     botan_pk_op_key_agreement_export_public,
2469
                     (priv2, nullptr, &pubkey2_len));
2470
         std::vector<uint8_t> pubkey2(pubkey2_len);
1✔
2471
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv2, pubkey2.data(), &pubkey2_len));
2✔
2472

2473
         std::vector<uint8_t> salt(32);
1✔
2474
         TEST_FFI_OK(botan_rng_get, (rng, salt.data(), salt.size()));
1✔
2475

2476
         const size_t shared_key_len = 64;
1✔
2477

2478
         std::vector<uint8_t> key1(shared_key_len);
1✔
2479
         size_t key1_len = key1.size();
1✔
2480
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
2481
                     (ka1, key1.data(), &key1_len, pubkey2.data(), pubkey2.size(), salt.data(), salt.size()));
2482

2483
         std::vector<uint8_t> key2(shared_key_len);
1✔
2484
         size_t key2_len = key2.size();
1✔
2485
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
2486
                     (ka2, key2.data(), &key2_len, pubkey1.data(), pubkey1.size(), salt.data(), salt.size()));
2487

2488
         result.test_eq("shared ECDH key", key1, key2);
1✔
2489

2490
         TEST_FFI_OK(botan_mp_destroy, (private_scalar));
1✔
2491
         TEST_FFI_OK(botan_mp_destroy, (public_x));
1✔
2492
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
2493
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka1));
1✔
2494
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka2));
1✔
2495
         TEST_FFI_OK(botan_privkey_destroy, (priv1));
1✔
2496
         TEST_FFI_OK(botan_privkey_destroy, (priv2));
1✔
2497
         TEST_FFI_OK(botan_pubkey_destroy, (pub1));
1✔
2498
         TEST_FFI_OK(botan_pubkey_destroy, (pub2));
1✔
2499
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey1));
1✔
2500
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
2✔
2501
      }
5✔
2502
};
2503

2504
class FFI_McEliece_Test final : public FFI_Test {
×
2505
   public:
2506
      std::string name() const override { return "FFI McEliece"; }
1✔
2507

2508
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2509
         botan_privkey_t priv;
1✔
2510
         if(TEST_FFI_INIT(botan_privkey_create_mceliece, (&priv, rng, 2048, 50))) {
2✔
2511
            botan_pubkey_t pub;
1✔
2512
            TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
2513

2514
            ffi_test_pubkey_export(result, pub, priv, rng);
1✔
2515

2516
            char namebuf[32] = {0};
1✔
2517
            size_t name_len = sizeof(namebuf);
1✔
2518
            if(TEST_FFI_OK(botan_pubkey_algo_name, (pub, namebuf, &name_len))) {
2✔
2519
               result.test_eq("algo name", std::string(namebuf), "McEliece");
2✔
2520
            }
2521

2522
            // TODO test KEM
2523

2524
            TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
2525
            TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
2526
         }
2527
      }
1✔
2528
};
2529

2530
class FFI_Ed25519_Test final : public FFI_Test {
×
2531
   public:
2532
      std::string name() const override { return "FFI Ed25519"; }
1✔
2533

2534
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2535
         botan_pubkey_t pub;
1✔
2536
         botan_privkey_t priv;
1✔
2537

2538
         // From draft-koch-eddsa-for-openpgp-04
2539
         const std::vector<uint8_t> seed =
1✔
2540
            Botan::hex_decode("1a8b1ff05ded48e18bf50166c664ab023ea70003d78d9e41f5758a91d850f8d2");
1✔
2541
         const std::vector<uint8_t> pubkey =
1✔
2542
            Botan::hex_decode("3f098994bdd916ed4053197934e4a87c80733a1280d62f8010992e43ee3b2406");
1✔
2543
         const std::vector<uint8_t> message = Botan::hex_decode("4f70656e504750040016080006050255f95f9504ff0000000c");
1✔
2544
         const std::vector<uint8_t> exp_sig = Botan::hex_decode(
1✔
2545
            "56f90cca98e2102637bd983fdb16c131dfd27ed82bf4dde5606e0d756aed3366"
2546
            "d09c4fa11527f038e0f57f2201d82f2ea2c9033265fa6ceb489e854bae61b404");
1✔
2547

2548
         if(!TEST_FFI_INIT(botan_privkey_load_ed25519, (&priv, seed.data())))
2✔
2549
            return;
×
2550

2551
         uint8_t retr_privkey[64];
1✔
2552
         TEST_FFI_OK(botan_privkey_ed25519_get_privkey, (priv, retr_privkey));
1✔
2553

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

2556
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
1✔
2557

2558
         uint8_t retr_pubkey[32];
1✔
2559
         TEST_FFI_OK(botan_pubkey_ed25519_get_pubkey, (pub, retr_pubkey));
1✔
2560
         result.test_eq(nullptr, "Public key matches", retr_pubkey, 32, pubkey.data(), pubkey.size());
1✔
2561

2562
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
2563
         TEST_FFI_OK(botan_pubkey_load_ed25519, (&pub, pubkey.data()));
1✔
2564

2565
         botan_pk_op_sign_t signer;
1✔
2566
         std::vector<uint8_t> signature;
1✔
2567

2568
         if(TEST_FFI_OK(botan_pk_op_sign_create, (&signer, priv, "SHA-256", 0))) {
2✔
2569
            TEST_FFI_OK(botan_pk_op_sign_update, (signer, message.data(), message.size()));
1✔
2570

2571
            size_t sig_len;
1✔
2572
            TEST_FFI_OK(botan_pk_op_sign_output_length, (signer, &sig_len));
1✔
2573

2574
            signature.resize(sig_len);
1✔
2575

2576
            TEST_FFI_OK(botan_pk_op_sign_finish, (signer, rng, signature.data(), &sig_len));
1✔
2577
            signature.resize(sig_len);
1✔
2578

2579
            TEST_FFI_OK(botan_pk_op_sign_destroy, (signer));
2✔
2580
         }
2581

2582
         result.test_eq("Expected signature", signature, exp_sig);
1✔
2583

2584
         botan_pk_op_verify_t verifier;
1✔
2585

2586
         if(TEST_FFI_OK(botan_pk_op_verify_create, (&verifier, pub, "SHA-256", 0))) {
2✔
2587
            TEST_FFI_OK(botan_pk_op_verify_update, (verifier, message.data(), message.size()));
1✔
2588
            TEST_FFI_OK(botan_pk_op_verify_finish, (verifier, signature.data(), signature.size()));
1✔
2589

2590
            TEST_FFI_OK(botan_pk_op_verify_destroy, (verifier));
2✔
2591
         }
2592

2593
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
1✔
2594
         TEST_FFI_OK(botan_privkey_destroy, (priv));
2✔
2595
      }
5✔
2596
};
2597

2598
class FFI_X25519_Test final : public FFI_Test {
×
2599
   public:
2600
      std::string name() const override { return "FFI X25519"; }
1✔
2601

2602
      void ffi_test(Test::Result& result, botan_rng_t /*unused*/) override {
1✔
2603
         // From RFC 8037
2604

2605
         const std::vector<uint8_t> a_pub_bits =
1✔
2606
            Botan::hex_decode("de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f");
1✔
2607
         const std::vector<uint8_t> b_priv_bits =
1✔
2608
            Botan::hex_decode("77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a");
1✔
2609
         const std::vector<uint8_t> b_pub_bits =
1✔
2610
            Botan::hex_decode("8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a");
1✔
2611
         const std::vector<uint8_t> shared_secret_bits =
1✔
2612
            Botan::hex_decode("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742");
1✔
2613

2614
         botan_privkey_t b_priv;
1✔
2615
         if(!TEST_FFI_INIT(botan_privkey_load_x25519, (&b_priv, b_priv_bits.data())))
2✔
2616
            return;
2617

2618
         std::vector<uint8_t> privkey_read(32);
1✔
2619
         TEST_FFI_OK(botan_privkey_x25519_get_privkey, (b_priv, privkey_read.data()));
1✔
2620
         result.test_eq("X25519 private key", privkey_read, b_priv_bits);
1✔
2621

2622
         std::vector<uint8_t> pubkey_read(32);
1✔
2623

2624
         botan_pubkey_t b_pub;
1✔
2625
         TEST_FFI_OK(botan_privkey_export_pubkey, (&b_pub, b_priv));
1✔
2626
         TEST_FFI_OK(botan_pubkey_x25519_get_pubkey, (b_pub, pubkey_read.data()));
1✔
2627
         result.test_eq("X25519 public key b", pubkey_read, b_pub_bits);
1✔
2628

2629
         botan_pubkey_t a_pub;
1✔
2630
         TEST_FFI_OK(botan_pubkey_load_x25519, (&a_pub, a_pub_bits.data()));
1✔
2631
         TEST_FFI_OK(botan_pubkey_x25519_get_pubkey, (a_pub, pubkey_read.data()));
1✔
2632
         result.test_eq("X25519 public key a", pubkey_read, a_pub_bits);
1✔
2633

2634
         botan_pk_op_ka_t ka;
1✔
2635
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka, b_priv, "Raw", 0));
2✔
2636

2637
         std::vector<uint8_t> shared_output(32);
1✔
2638
         size_t shared_len = shared_output.size();
1✔
2639
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
2640
                     (ka, shared_output.data(), &shared_len, a_pub_bits.data(), a_pub_bits.size(), nullptr, 0));
2641

2642
         result.test_eq("Shared secret matches expected", shared_secret_bits, shared_output);
1✔
2643

2644
         TEST_FFI_OK(botan_pubkey_destroy, (a_pub));
1✔
2645
         TEST_FFI_OK(botan_pubkey_destroy, (b_pub));
1✔
2646
         TEST_FFI_OK(botan_privkey_destroy, (b_priv));
1✔
2647
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka));
2✔
2648
      }
7✔
2649
};
2650

2651
class FFI_ElGamal_Test final : public FFI_Test {
×
2652
   public:
2653
      std::string name() const override { return "FFI ElGamal"; }
1✔
2654

2655
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2656
         botan_privkey_t priv;
1✔
2657

2658
         if(TEST_FFI_INIT(botan_privkey_create, (&priv, "ElGamal", "modp/ietf/1024", rng))) {
2✔
2659
            do_elgamal_test(priv, rng, result);
1✔
2660
         }
2661

2662
         if(TEST_FFI_INIT(botan_privkey_create_elgamal, (&priv, rng, 1024, 160))) {
2✔
2663
            do_elgamal_test(priv, rng, result);
1✔
2664
         }
2665
      }
1✔
2666

2667
   private:
2668
      static void do_elgamal_test(botan_privkey_t priv, botan_rng_t rng, Test::Result& result) {
2✔
2669
         TEST_FFI_OK(botan_privkey_check_key, (priv, rng, 0));
2✔
2670

2671
         botan_pubkey_t pub;
2✔
2672
         TEST_FFI_OK(botan_privkey_export_pubkey, (&pub, priv));
2✔
2673
         TEST_FFI_OK(botan_pubkey_check_key, (pub, rng, 0));
2✔
2674

2675
         ffi_test_pubkey_export(result, pub, priv, rng);
2✔
2676
         botan_mp_t p, g, x, y;
2✔
2677
         botan_mp_init(&p);
2✔
2678
         botan_mp_init(&g);
2✔
2679
         botan_mp_init(&x);
2✔
2680
         botan_mp_init(&y);
2✔
2681

2682
         TEST_FFI_OK(botan_pubkey_get_field, (p, pub, "p"));
2✔
2683
         TEST_FFI_OK(botan_pubkey_get_field, (g, pub, "g"));
2✔
2684
         TEST_FFI_OK(botan_pubkey_get_field, (y, pub, "y"));
2✔
2685
         TEST_FFI_OK(botan_privkey_get_field, (x, priv, "x"));
2✔
2686

2687
         size_t p_len = 0;
2✔
2688
         TEST_FFI_OK(botan_mp_num_bytes, (p, &p_len));
2✔
2689

2690
         botan_privkey_t loaded_privkey;
2✔
2691
         TEST_FFI_OK(botan_privkey_load_elgamal, (&loaded_privkey, p, g, x));
2✔
2692

2693
         botan_pubkey_t loaded_pubkey;
2✔
2694
         TEST_FFI_OK(botan_pubkey_load_elgamal, (&loaded_pubkey, p, g, y));
2✔
2695

2696
         botan_mp_destroy(p);
2✔
2697
         botan_mp_destroy(g);
2✔
2698
         botan_mp_destroy(y);
2✔
2699
         botan_mp_destroy(x);
2✔
2700

2701
         std::vector<uint8_t> plaintext(16, 0xFF);
2✔
2702
         std::vector<uint8_t> ciphertext;
2✔
2703
         std::vector<uint8_t> decryption;
2✔
2704

2705
         // Test encryption
2706
         botan_pk_op_encrypt_t op_enc;
2✔
2707
         if(TEST_FFI_OK(botan_pk_op_encrypt_create, (&op_enc, loaded_pubkey, "Raw", 0))) {
4✔
2708
            size_t ctext_len;
2✔
2709
            TEST_FFI_OK(botan_pk_op_encrypt_output_length, (op_enc, plaintext.size(), &ctext_len));
2✔
2710
            ciphertext.resize(ctext_len);
2✔
2711
            TEST_FFI_OK(botan_pk_op_encrypt,
2✔
2712
                        (op_enc, rng, ciphertext.data(), &ctext_len, plaintext.data(), plaintext.size()));
2713
            ciphertext.resize(ctext_len);
2✔
2714
            TEST_FFI_OK(botan_pk_op_encrypt_destroy, (op_enc));
4✔
2715
         }
2716

2717
         // Test decryption
2718
         botan_pk_op_decrypt_t op_dec;
2✔
2719
         if(TEST_FFI_OK(botan_pk_op_decrypt_create, (&op_dec, loaded_privkey, "Raw", 0))) {
4✔
2720
            size_t ptext_len;
2✔
2721
            TEST_FFI_OK(botan_pk_op_decrypt_output_length, (op_dec, ciphertext.size(), &ptext_len));
2✔
2722
            decryption.resize(ptext_len);
2✔
2723
            TEST_FFI_OK(botan_pk_op_decrypt,
2✔
2724
                        (op_dec, decryption.data(), &ptext_len, ciphertext.data(), ciphertext.size()));
2725
            decryption.resize(ptext_len);
2✔
2726
            TEST_FFI_OK(botan_pk_op_decrypt_destroy, (op_dec));
4✔
2727
         }
2728

2729
         result.test_eq("decryption worked", decryption, plaintext);
2✔
2730

2731
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey));
2✔
2732
         TEST_FFI_OK(botan_pubkey_destroy, (pub));
2✔
2733
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey));
2✔
2734
         TEST_FFI_OK(botan_privkey_destroy, (priv));
4✔
2735
      }
6✔
2736
};
2737

2738
class FFI_DH_Test final : public FFI_Test {
×
2739
   public:
2740
      std::string name() const override { return "FFI DH"; }
1✔
2741

2742
      void ffi_test(Test::Result& result, botan_rng_t rng) override {
1✔
2743
         botan_privkey_t priv1;
1✔
2744
         if(!TEST_FFI_INIT(botan_privkey_create_dh, (&priv1, rng, "modp/ietf/2048")))
2✔
2745
            return;
×
2746

2747
         botan_privkey_t priv2;
1✔
2748
         REQUIRE_FFI_OK(botan_privkey_create_dh, (&priv2, rng, "modp/ietf/2048"));
2✔
2749

2750
         botan_pubkey_t pub1;
1✔
2751
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub1, priv1));
2✔
2752

2753
         botan_pubkey_t pub2;
1✔
2754
         REQUIRE_FFI_OK(botan_privkey_export_pubkey, (&pub2, priv2));
2✔
2755

2756
         // Reload key-pair1 in order to test functions for key loading
2757
         botan_mp_t private_x, public_g, public_p, public_y;
1✔
2758

2759
         botan_mp_init(&private_x);
1✔
2760
         botan_mp_init(&public_g);
1✔
2761
         botan_mp_init(&public_p);
1✔
2762
         botan_mp_init(&public_y);
1✔
2763

2764
         TEST_FFI_OK(botan_privkey_get_field, (private_x, priv1, "x"));
1✔
2765
         TEST_FFI_OK(botan_pubkey_get_field, (public_g, pub1, "g"));
1✔
2766
         TEST_FFI_OK(botan_pubkey_get_field, (public_p, pub1, "p"));
1✔
2767
         TEST_FFI_OK(botan_pubkey_get_field, (public_y, pub1, "y"));
1✔
2768

2769
         botan_privkey_t loaded_privkey1;
1✔
2770
         botan_pubkey_t loaded_pubkey1;
1✔
2771
         TEST_FFI_OK(botan_privkey_load_dh, (&loaded_privkey1, public_p, public_g, private_x));
1✔
2772
         TEST_FFI_OK(botan_pubkey_load_dh, (&loaded_pubkey1, public_p, public_g, public_y));
1✔
2773

2774
         TEST_FFI_OK(botan_privkey_check_key, (loaded_privkey1, rng, 0));
1✔
2775
         TEST_FFI_OK(botan_pubkey_check_key, (loaded_pubkey1, rng, 0));
1✔
2776

2777
         botan_mp_t loaded_public_g, loaded_public_p, loaded_public_y;
1✔
2778
         botan_mp_init(&loaded_public_g);
1✔
2779
         botan_mp_init(&loaded_public_p);
1✔
2780
         botan_mp_init(&loaded_public_y);
1✔
2781

2782
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_g, loaded_pubkey1, "g"));
1✔
2783
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_p, loaded_pubkey1, "p"));
1✔
2784
         TEST_FFI_OK(botan_pubkey_get_field, (loaded_public_y, loaded_pubkey1, "y"));
1✔
2785

2786
         int cmp;
1✔
2787

2788
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_g, public_g));
1✔
2789
         result.confirm("bigint_mp_cmp(g, g)", cmp == 0);
2✔
2790

2791
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_p, public_p));
1✔
2792
         result.confirm("bigint_mp_cmp(p, p)", cmp == 0);
2✔
2793

2794
         TEST_FFI_OK(botan_mp_cmp, (&cmp, loaded_public_y, public_y));
1✔
2795
         result.confirm("bigint_mp_cmp(y, y)", cmp == 0);
2✔
2796

2797
         botan_pk_op_ka_t ka1;
1✔
2798
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka1, loaded_privkey1, "Raw", 0));
2✔
2799
         botan_pk_op_ka_t ka2;
1✔
2800
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_create, (&ka2, priv2, "Raw", 0));
2✔
2801

2802
         size_t pubkey1_len = 0;
1✔
2803
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
2804
                     botan_pk_op_key_agreement_export_public,
2805
                     (priv1, nullptr, &pubkey1_len));
2806
         std::vector<uint8_t> pubkey1(pubkey1_len);
1✔
2807
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv1, pubkey1.data(), &pubkey1_len));
2✔
2808
         size_t pubkey2_len = 0;
1✔
2809
         TEST_FFI_RC(BOTAN_FFI_ERROR_INSUFFICIENT_BUFFER_SPACE,
1✔
2810
                     botan_pk_op_key_agreement_export_public,
2811
                     (priv2, nullptr, &pubkey2_len));
2812
         std::vector<uint8_t> pubkey2(pubkey2_len);
1✔
2813
         REQUIRE_FFI_OK(botan_pk_op_key_agreement_export_public, (priv2, pubkey2.data(), &pubkey2_len));
2✔
2814

2815
         const size_t shared_key_len = 256;
1✔
2816

2817
         std::vector<uint8_t> key1(shared_key_len);
1✔
2818
         size_t key1_len = key1.size();
1✔
2819

2820
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
2821
                     (ka1, key1.data(), &key1_len, pubkey2.data(), pubkey2.size(), nullptr, 0));
2822

2823
         std::vector<uint8_t> key2(shared_key_len);
1✔
2824
         size_t key2_len = key2.size();
1✔
2825

2826
         TEST_FFI_OK(botan_pk_op_key_agreement,
1✔
2827
                     (ka2, key2.data(), &key2_len, pubkey1.data(), pubkey1.size(), nullptr, 0));
2828

2829
         result.test_eq("shared DH key", key1, key2);
1✔
2830

2831
         TEST_FFI_OK(botan_mp_destroy, (private_x));
1✔
2832
         TEST_FFI_OK(botan_mp_destroy, (public_p));
1✔
2833
         TEST_FFI_OK(botan_mp_destroy, (public_g));
1✔
2834
         TEST_FFI_OK(botan_mp_destroy, (public_y));
1✔
2835

2836
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_p));
1✔
2837
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_g));
1✔
2838
         TEST_FFI_OK(botan_mp_destroy, (loaded_public_y));
1✔
2839

2840
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka1));
1✔
2841
         TEST_FFI_OK(botan_pk_op_key_agreement_destroy, (ka2));
1✔
2842
         TEST_FFI_OK(botan_privkey_destroy, (priv1));
1✔
2843
         TEST_FFI_OK(botan_privkey_destroy, (priv2));
1✔
2844
         TEST_FFI_OK(botan_pubkey_destroy, (pub1));
1✔
2845
         TEST_FFI_OK(botan_pubkey_destroy, (pub2));
1✔
2846
         TEST_FFI_OK(botan_privkey_destroy, (loaded_privkey1));
1✔
2847
         TEST_FFI_OK(botan_pubkey_destroy, (loaded_pubkey1));
2✔
2848
      }
4✔
2849
};
2850

2851
BOTAN_REGISTER_TEST("ffi", "ffi_utils", FFI_Utils_Test);
2852
BOTAN_REGISTER_TEST("ffi", "ffi_rng", FFI_RNG_Test);
2853
BOTAN_REGISTER_TEST("ffi", "ffi_rsa_cert", FFI_RSA_Cert_Test);
2854
BOTAN_REGISTER_TEST("ffi", "ffi_zfec", FFI_ZFEC_Test);
2855
BOTAN_REGISTER_TEST("ffi", "ffi_crl", FFI_CRL_Test);
2856
BOTAN_REGISTER_TEST("ffi", "ffi_cert_validation", FFI_Cert_Validation_Test);
2857
BOTAN_REGISTER_TEST("ffi", "ffi_ecdsa_certificate", FFI_ECDSA_Certificate_Test);
2858
BOTAN_REGISTER_TEST("ffi", "ffi_pkcs_hashid", FFI_PKCS_Hashid_Test);
2859
BOTAN_REGISTER_TEST("ffi", "ffi_cbc_cipher", FFI_CBC_Cipher_Test);
2860
BOTAN_REGISTER_TEST("ffi", "ffi_gcm", FFI_GCM_Test);
2861
BOTAN_REGISTER_TEST("ffi", "ffi_eax", FFI_EAX_Test);
2862
BOTAN_REGISTER_TEST("ffi", "ffi_streamcipher", FFI_StreamCipher_Test);
2863
BOTAN_REGISTER_TEST("ffi", "ffi_hashfunction", FFI_HashFunction_Test);
2864
BOTAN_REGISTER_TEST("ffi", "ffi_mac", FFI_MAC_Test);
2865
BOTAN_REGISTER_TEST("ffi", "ffi_scrypt", FFI_Scrypt_Test);
2866
BOTAN_REGISTER_TEST("ffi", "ffi_kdf", FFI_KDF_Test);
2867
BOTAN_REGISTER_TEST("ffi", "ffi_blockcipher", FFI_Blockcipher_Test);
2868
BOTAN_REGISTER_TEST("ffi", "ffi_errorhandling", FFI_ErrorHandling_Test);
2869
BOTAN_REGISTER_TEST("ffi", "ffi_base64", FFI_Base64_Test);
2870
BOTAN_REGISTER_TEST("ffi", "ffi_hex", FFI_Hex_Test);
2871
BOTAN_REGISTER_TEST("ffi", "ffi_mp", FFI_MP_Test);
2872
BOTAN_REGISTER_TEST("ffi", "ffi_fpe", FFI_FPE_Test);
2873
BOTAN_REGISTER_TEST("ffi", "ffi_totp", FFI_TOTP_Test);
2874
BOTAN_REGISTER_TEST("ffi", "ffi_hotp", FFI_HOTP_Test);
2875
BOTAN_REGISTER_TEST("ffi", "ffi_keywrap", FFI_Keywrap_Test);
2876
BOTAN_REGISTER_TEST("ffi", "ffi_rsa", FFI_RSA_Test);
2877
BOTAN_REGISTER_TEST("ffi", "ffi_dsa", FFI_DSA_Test);
2878
BOTAN_REGISTER_TEST("ffi", "ffi_ecdsa", FFI_ECDSA_Test);
2879
BOTAN_REGISTER_TEST("ffi", "ffi_sm2_sig", FFI_SM2_Sig_Test);
2880
BOTAN_REGISTER_TEST("ffi", "ffi_sm2_enc", FFI_SM2_Enc_Test);
2881
BOTAN_REGISTER_TEST("ffi", "ffi_ecdh", FFI_ECDH_Test);
2882
BOTAN_REGISTER_TEST("ffi", "ffi_mceliece", FFI_McEliece_Test);
2883
BOTAN_REGISTER_TEST("ffi", "ffi_ed25519", FFI_Ed25519_Test);
2884
BOTAN_REGISTER_TEST("ffi", "ffi_x25519", FFI_X25519_Test);
2885
BOTAN_REGISTER_TEST("ffi", "ffi_elgamal", FFI_ElGamal_Test);
2886
BOTAN_REGISTER_TEST("ffi", "ffi_dh", FFI_DH_Test);
2887

2888
#endif
2889

2890
}  // namespace
2891

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

© 2025 Coveralls, Inc