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

randombit / botan / 22632786303

03 Mar 2026 04:33PM UTC coverage: 90.222% (-0.1%) from 90.317%
22632786303

Pull #5404

github

web-flow
Merge 29e610b86 into a78272b61
Pull Request #5404: Add EC scalars and points to FFI

103594 of 114821 relevant lines covered (90.22%)

11540883.54 hits per line

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

92.75
/src/lib/ffi/ffi_pkey.cpp
1
/*
2
* (C) 2015,2017 Jack Lloyd
3
*
4
* Botan is released under the Simplified BSD License (see license.txt)
5
*/
6

7
#include <botan/ffi.h>
8

9
#include <botan/assert.h>
10
#include <botan/data_src.h>
11
#include <botan/ecc_key.h>
12
#include <botan/hash.h>
13
#include <botan/pk_algs.h>
14
#include <botan/pk_keys.h>
15
#include <botan/pkcs8.h>
16
#include <botan/x509_key.h>
17
#include <botan/internal/ffi_ec.h>
18
#include <botan/internal/ffi_oid.h>
19
#include <botan/internal/ffi_pkey.h>
20
#include <botan/internal/ffi_rng.h>
21
#include <botan/internal/ffi_util.h>
22

23
#if defined(BOTAN_HAS_HASH_ID)
24
   #include <botan/internal/hash_id.h>
25
#endif
26

27
extern "C" {
28

29
using namespace Botan_FFI;
30

31
int botan_privkey_create(botan_privkey_t* key_obj,
85✔
32
                         const char* algo_name,
33
                         const char* algo_params,
34
                         botan_rng_t rng_obj) {
35
   // TODO(Botan4) remove this implicit algorithm choice and reject nullptr algo_name
36
   if(algo_name == nullptr) {
85✔
37
      return botan_privkey_create(key_obj, "RSA", algo_params, rng_obj);
38
   }
39

40
   return ffi_guard_thunk(__func__, [=]() -> int {
85✔
41
      if(key_obj == nullptr) {
85✔
42
         return BOTAN_FFI_ERROR_NULL_POINTER;
43
      }
44

45
      *key_obj = nullptr;
85✔
46
      if(rng_obj == nullptr) {
85✔
47
         return BOTAN_FFI_ERROR_NULL_POINTER;
48
      }
49

50
      const std::string params(algo_params != nullptr ? algo_params : "");
170✔
51

52
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
85✔
53

54
      if(auto key = Botan::create_private_key(algo_name, rng, params)) {
85✔
55
         return ffi_new_object(key_obj, std::move(key));
85✔
56
      } else {
57
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
58
      }
85✔
59
   });
85✔
60
}
61

62
int botan_ec_privkey_create(botan_privkey_t* key_obj,
2✔
63
                            const char* algo_name,
64
                            botan_ec_group_t ec_group_obj,
65
                            botan_rng_t rng_obj) {
66
   // TODO(Botan4) remove this implicit algorithm choice and reject nullptr algo_name
67
   if(algo_name == nullptr) {
2✔
68
      return botan_ec_privkey_create(key_obj, "ECDSA", ec_group_obj, rng_obj);
69
   }
70

71
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
72
      if(key_obj == nullptr) {
2✔
73
         return BOTAN_FFI_ERROR_NULL_POINTER;
74
      }
75
      *key_obj = nullptr;
2✔
76

77
      const Botan::EC_Group ec_group = safe_get(ec_group_obj);
2✔
78
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
2✔
79

80
      if(auto key = Botan::create_ec_private_key(algo_name, ec_group, rng)) {
2✔
81
         return ffi_new_object(key_obj, std::move(key));
2✔
82
      } else {
83
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
84
      }
×
85
   });
2✔
86
}
87

88
int botan_privkey_load(
57✔
89
   botan_privkey_t* key, botan_rng_t rng_obj, const uint8_t bits[], size_t len, const char* password) {
90
   BOTAN_UNUSED(rng_obj);
57✔
91

92
   *key = nullptr;
57✔
93

94
   return ffi_guard_thunk(__func__, [=]() -> int {
57✔
95
      Botan::DataSource_Memory src(bits, len);
57✔
96

97
      std::unique_ptr<Botan::Private_Key> pkcs8;
57✔
98

99
      if(password == nullptr) {
57✔
100
         pkcs8 = Botan::PKCS8::load_key(src);
25✔
101
      } else {
102
         pkcs8 = Botan::PKCS8::load_key(src, std::string(password));
32✔
103
      }
104

105
      if(pkcs8) {
57✔
106
         ffi_new_object(key, std::move(pkcs8));
57✔
107
         return BOTAN_FFI_SUCCESS;
57✔
108
      }
109
      return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
110
   });
114✔
111
}
112

113
int botan_privkey_destroy(botan_privkey_t key) {
222✔
114
   return BOTAN_FFI_CHECKED_DELETE(key);
222✔
115
}
116

117
int botan_pubkey_load(botan_pubkey_t* key, const uint8_t bits[], size_t bits_len) {
15✔
118
   *key = nullptr;
15✔
119

120
   return ffi_guard_thunk(__func__, [=]() -> int {
15✔
121
      Botan::DataSource_Memory src(bits, bits_len);
15✔
122
      std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(src));
15✔
123

124
      if(pubkey == nullptr) {
15✔
125
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
126
      }
127

128
      ffi_new_object(key, std::move(pubkey));
15✔
129
      return BOTAN_FFI_SUCCESS;
15✔
130
   });
30✔
131
}
132

133
int botan_pubkey_destroy(botan_pubkey_t key) {
210✔
134
   return BOTAN_FFI_CHECKED_DELETE(key);
210✔
135
}
136

137
int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj) {
105✔
138
   return ffi_guard_thunk(__func__, [=]() -> int {
105✔
139
      auto public_key = safe_get(key_obj).public_key();
105✔
140
      ffi_new_object(pubout, std::move(public_key));
105✔
141
      return BOTAN_FFI_SUCCESS;
105✔
142
   });
105✔
143
}
144

145
int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len) {
4✔
146
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { return write_str_output(out, out_len, k.algo_name()); });
8✔
147
}
148

149
int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) {
7✔
150
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { return write_str_output(out, out_len, k.algo_name()); });
14✔
151
}
152

153
int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags) {
30✔
154
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS) != 0;
30✔
155

156
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
60✔
157
      return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
158
   });
159
}
160

161
int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags) {
16✔
162
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS) != 0;
16✔
163
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
32✔
164
      return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
165
   });
166
}
167

168
int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
48✔
169
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
48✔
170
      return copy_view_bin(out, out_len, botan_pubkey_view_der, key);
24✔
171
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
24✔
172
      return copy_view_str(out, out_len, botan_pubkey_view_pem, key);
24✔
173
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_RAW) {
×
174
      return copy_view_bin(out, out_len, botan_pubkey_view_raw, key);
×
175
   } else {
176
      return BOTAN_FFI_ERROR_BAD_FLAG;
177
   }
178
}
179

180
int botan_pubkey_view_der(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
25✔
181
   return BOTAN_FFI_VISIT(
100✔
182
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.subject_public_key()); });
183
}
184

185
int botan_pubkey_view_pem(botan_pubkey_t key, botan_view_ctx ctx, botan_view_str_fn view) {
28✔
186
   return BOTAN_FFI_VISIT(
84✔
187
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::X509::PEM_encode(k)); });
188
}
189

190
int botan_pubkey_view_raw(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
131✔
191
   return BOTAN_FFI_VISIT(
522✔
192
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.raw_public_key_bits()); });
193
}
194

195
int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
48✔
196
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
48✔
197
      return copy_view_bin(out, out_len, botan_privkey_view_der, key);
24✔
198
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
24✔
199
      return copy_view_str(out, out_len, botan_privkey_view_pem, key);
24✔
200
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_RAW) {
×
201
      return copy_view_bin(out, out_len, botan_privkey_view_raw, key);
×
202
   } else {
203
      return BOTAN_FFI_ERROR_BAD_FLAG;
204
   }
205
}
206

207
int botan_privkey_view_der(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
29✔
208
   return BOTAN_FFI_VISIT(key,
116✔
209
                          [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.private_key_info()); });
210
}
211

212
int botan_privkey_view_pem(botan_privkey_t key, botan_view_ctx ctx, botan_view_str_fn view) {
36✔
213
   return BOTAN_FFI_VISIT(
108✔
214
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::PKCS8::PEM_encode(k)); });
215
}
216

217
int botan_privkey_view_raw(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
110✔
218
   return BOTAN_FFI_VISIT(
438✔
219
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.raw_private_key_bits()); });
220
}
221

222
int botan_privkey_export_encrypted(botan_privkey_t key,
×
223
                                   uint8_t out[],
224
                                   size_t* out_len,
225
                                   botan_rng_t rng_obj,
226
                                   const char* pass,
227
                                   const char* /*ignored - pbe*/,
228
                                   uint32_t flags) {
229
   return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags);
×
230
}
231

232
int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key,
12✔
233
                                              uint8_t out[],
234
                                              size_t* out_len,
235
                                              botan_rng_t rng,
236
                                              const char* passphrase,
237
                                              uint32_t pbkdf_msec,
238
                                              size_t* pbkdf_iters_out,
239
                                              const char* cipher,
240
                                              const char* pbkdf_hash,
241
                                              uint32_t flags) {
242
   if(pbkdf_iters_out != nullptr) {
12✔
243
      *pbkdf_iters_out = 0;
12✔
244
   }
245

246
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
12✔
247
      return copy_view_bin(
12✔
248
         out, out_len, botan_privkey_view_encrypted_der_timed, key, rng, passphrase, cipher, pbkdf_hash, pbkdf_msec);
12✔
249
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
×
250
      return copy_view_str(
×
251
         out, out_len, botan_privkey_view_encrypted_pem_timed, key, rng, passphrase, cipher, pbkdf_hash, pbkdf_msec);
×
252
   } else {
253
      return BOTAN_FFI_ERROR_BAD_FLAG;
254
   }
255
}
256

257
int botan_privkey_view_encrypted_der_timed(botan_privkey_t key,
15✔
258
                                           botan_rng_t rng_obj,
259
                                           const char* passphrase,
260
                                           const char* maybe_cipher,
261
                                           const char* maybe_pbkdf_algo,
262
                                           size_t pbkdf_runtime_msec,
263
                                           botan_view_ctx ctx,
264
                                           botan_view_bin_fn view) {
265
   if(passphrase == nullptr) {
15✔
266
      return BOTAN_FFI_ERROR_NULL_POINTER;
267
   }
268

269
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
102✔
270
      const std::chrono::milliseconds pbkdf_time(pbkdf_runtime_msec);
271
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
272

273
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
274
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
275

276
      auto pkcs8 =
277
         Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, passphrase, pbkdf_time, nullptr, cipher, pbkdf_algo);
278

279
      return invoke_view_callback(view, ctx, pkcs8);
280
   });
281
}
282

283
int botan_privkey_view_encrypted_pem_timed(botan_privkey_t key,
3✔
284
                                           botan_rng_t rng_obj,
285
                                           const char* passphrase,
286
                                           const char* maybe_cipher,
287
                                           const char* maybe_pbkdf_algo,
288
                                           size_t pbkdf_runtime_msec,
289
                                           botan_view_ctx ctx,
290
                                           botan_view_str_fn view) {
291
   if(passphrase == nullptr) {
3✔
292
      return BOTAN_FFI_ERROR_NULL_POINTER;
293
   }
294

295
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
15✔
296
      const std::chrono::milliseconds pbkdf_time(pbkdf_runtime_msec);
297
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
298

299
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
300
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
301

302
      auto pkcs8 =
303
         Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, passphrase, pbkdf_time, nullptr, cipher, pbkdf_algo);
304

305
      return invoke_view_callback(view, ctx, pkcs8);
306
   });
307
}
308

309
int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key,
48✔
310
                                              uint8_t out[],
311
                                              size_t* out_len,
312
                                              botan_rng_t rng,
313
                                              const char* passphrase,
314
                                              size_t pbkdf_iter,
315
                                              const char* cipher,
316
                                              const char* pbkdf_algo,
317
                                              uint32_t flags) {
318
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
48✔
319
      return copy_view_bin(
24✔
320
         out, out_len, botan_privkey_view_encrypted_der, key, rng, passphrase, cipher, pbkdf_algo, pbkdf_iter);
24✔
321
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
24✔
322
      return copy_view_str(
24✔
323
         out, out_len, botan_privkey_view_encrypted_pem, key, rng, passphrase, cipher, pbkdf_algo, pbkdf_iter);
24✔
324
   } else {
325
      return BOTAN_FFI_ERROR_BAD_FLAG;
326
   }
327
}
328

329
int botan_privkey_view_encrypted_der(botan_privkey_t key,
24✔
330
                                     botan_rng_t rng_obj,
331
                                     const char* passphrase,
332
                                     const char* maybe_cipher,
333
                                     const char* maybe_pbkdf_algo,
334
                                     size_t maybe_pbkdf_iterations,
335
                                     botan_view_ctx ctx,
336
                                     botan_view_bin_fn view) {
337
   if(passphrase == nullptr) {
24✔
338
      return BOTAN_FFI_ERROR_NULL_POINTER;
339
   }
340

341
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
192✔
342
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
343

344
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
345
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
346
      const size_t pbkdf_iter = (maybe_pbkdf_iterations ? maybe_pbkdf_iterations : 100000);
347

348
      auto pkcs8 = Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(k, rng, passphrase, pbkdf_iter, cipher, pbkdf_algo);
349

350
      return invoke_view_callback(view, ctx, pkcs8);
351
   });
352
}
353

354
int botan_privkey_view_encrypted_pem(botan_privkey_t key,
24✔
355
                                     botan_rng_t rng_obj,
356
                                     const char* passphrase,
357
                                     const char* maybe_cipher,
358
                                     const char* maybe_pbkdf_algo,
359
                                     size_t maybe_pbkdf_iterations,
360
                                     botan_view_ctx ctx,
361
                                     botan_view_str_fn view) {
362
   if(passphrase == nullptr) {
24✔
363
      return BOTAN_FFI_ERROR_NULL_POINTER;
364
   }
365

366
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
168✔
367
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
368

369
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
370
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
371
      const size_t pbkdf_iter = (maybe_pbkdf_iterations ? maybe_pbkdf_iterations : 100000);
372

373
      auto pkcs8 = Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(k, rng, passphrase, pbkdf_iter, cipher, pbkdf_algo);
374

375
      return invoke_view_callback(view, ctx, pkcs8);
376
   });
377
}
378

379
int botan_pubkey_oid(botan_asn1_oid_t* oid, botan_pubkey_t key) {
2✔
380
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
381
      if(oid == nullptr) {
382
         return BOTAN_FFI_ERROR_NULL_POINTER;
383
      }
384

385
      auto oid_ptr = std::make_unique<Botan::OID>(k.object_identifier());
386
      ffi_new_object(oid, std::move(oid_ptr));
387

388
      return BOTAN_FFI_SUCCESS;
389
   });
390
}
391

392
int botan_privkey_oid(botan_asn1_oid_t* oid, botan_privkey_t key) {
2✔
393
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
394
      if(oid == nullptr) {
395
         return BOTAN_FFI_ERROR_NULL_POINTER;
396
      }
397

398
      auto oid_ptr = std::make_unique<Botan::OID>(k.object_identifier());
399
      ffi_new_object(oid, std::move(oid_ptr));
400

401
      return BOTAN_FFI_SUCCESS;
402
   });
403
}
404

405
int botan_privkey_stateful_operation(botan_privkey_t key, int* out) {
5✔
406
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
10✔
407
      if(out == nullptr) {
408
         return BOTAN_FFI_ERROR_NULL_POINTER;
409
      }
410

411
      if(k.stateful_operation()) {
412
         *out = 1;
413
      } else {
414
         *out = 0;
415
      }
416
      return BOTAN_FFI_SUCCESS;
417
   });
418
}
419

420
int botan_privkey_remaining_operations(botan_privkey_t key, uint64_t* out) {
5✔
421
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
10✔
422
      if(out == nullptr) {
423
         return BOTAN_FFI_ERROR_NULL_POINTER;
424
      }
425

426
      if(auto remaining = k.remaining_operations()) {
427
         *out = remaining.value();
428
         return BOTAN_FFI_SUCCESS;
429
      } else {
430
         return BOTAN_FFI_ERROR_NO_VALUE;
431
      }
432
   });
433
}
434

435
int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) {
15✔
436
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { *estimate = k.estimated_strength(); });
30✔
437
}
438

439
int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn, uint8_t out[], size_t* out_len) {
24✔
440
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
120✔
441
      auto h = Botan::HashFunction::create_or_throw(hash_fn);
442
      return write_vec_output(out, out_len, h->process(k.public_key_bits()));
443
   });
444
}
445

446
int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len) {
2✔
447
#if defined(BOTAN_HAS_HASH_ID)
448
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
449
      const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name);
2✔
450
      return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size());
2✔
451
   });
4✔
452
#else
453
   BOTAN_UNUSED(hash_name, pkcs_id, pkcs_id_len);
454
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
455
#endif
456
}
457
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc