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

randombit / botan / 21850311256

10 Feb 2026 03:17AM UTC coverage: 91.635% (+0.001%) from 91.634%
21850311256

Pull #5302

github

web-flow
Merge 26bacb252 into 1d119e57a
Pull Request #5302: Cleanup various header inclusions

104007 of 113502 relevant lines covered (91.63%)

11071649.74 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/hash.h>
12
#include <botan/pk_algs.h>
13
#include <botan/pk_keys.h>
14
#include <botan/pkcs8.h>
15
#include <botan/x509_key.h>
16
#include <botan/internal/ffi_ec.h>
17
#include <botan/internal/ffi_oid.h>
18
#include <botan/internal/ffi_pkey.h>
19
#include <botan/internal/ffi_rng.h>
20
#include <botan/internal/ffi_util.h>
21

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

26
extern "C" {
27

28
using namespace Botan_FFI;
29

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

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

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

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

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

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

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

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

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

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

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

91
   *key = nullptr;
55✔
92

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

96
      std::unique_ptr<Botan::Private_Key> pkcs8;
55✔
97

98
      if(password == nullptr) {
55✔
99
         pkcs8 = Botan::PKCS8::load_key(src);
24✔
100
      } else {
101
         pkcs8 = Botan::PKCS8::load_key(src, std::string(password));
31✔
102
      }
103

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

112
int botan_privkey_destroy(botan_privkey_t key) {
220✔
113
   return BOTAN_FFI_CHECKED_DELETE(key);
220✔
114
}
115

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

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

123
      if(pubkey == nullptr) {
14✔
124
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
125
      }
126

127
      ffi_new_object(key, std::move(pubkey));
14✔
128
      return BOTAN_FFI_SUCCESS;
14✔
129
   });
28✔
130
}
131

132
int botan_pubkey_destroy(botan_pubkey_t key) {
207✔
133
   return BOTAN_FFI_CHECKED_DELETE(key);
207✔
134
}
135

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

387
      return BOTAN_FFI_SUCCESS;
388
   });
389
}
390

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

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

400
      return BOTAN_FFI_SUCCESS;
401
   });
402
}
403

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

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

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

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

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

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

445
int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len) {
2✔
446
#if defined(BOTAN_HAS_HASH_ID)
447
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
448
      const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name);
2✔
449
      return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size());
2✔
450
   });
4✔
451
#else
452
   BOTAN_UNUSED(hash_name, pkcs_id, pkcs_id_len);
453
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
454
#endif
455
}
456
}
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