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

randombit / botan / 24014286417

06 Apr 2026 12:48AM UTC coverage: 89.453% (-0.001%) from 89.454%
24014286417

Pull #5521

github

web-flow
Merge 2fb3a6cd7 into 417709dd7
Pull Request #5521: Rollup of small fixes

105877 of 118360 relevant lines covered (89.45%)

11453159.57 hits per line

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

93.1
/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(
57✔
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);
57✔
90

91
   if(key == nullptr) {
57✔
92
      return BOTAN_FFI_ERROR_NULL_POINTER;
93
   }
94

95
   *key = nullptr;
57✔
96

97
   if(bits == nullptr && len > 0) {
57✔
98
      return BOTAN_FFI_ERROR_NULL_POINTER;
99
   }
100

101
   return ffi_guard_thunk(__func__, [=]() -> int {
57✔
102
      Botan::DataSource_Memory src(bits, len);
57✔
103

104
      std::unique_ptr<Botan::Private_Key> pkcs8;
57✔
105

106
      if(password == nullptr) {
57✔
107
         pkcs8 = Botan::PKCS8::load_key(src);
25✔
108
      } else {
109
         pkcs8 = Botan::PKCS8::load_key(src, std::string(password));
32✔
110
      }
111

112
      if(pkcs8) {
57✔
113
         ffi_new_object(key, std::move(pkcs8));
57✔
114
         return BOTAN_FFI_SUCCESS;
57✔
115
      }
116
      return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
117
   });
171✔
118
}
119

120
int botan_privkey_destroy(botan_privkey_t key) {
221✔
121
   return BOTAN_FFI_CHECKED_DELETE(key);
221✔
122
}
123

124
int botan_pubkey_load(botan_pubkey_t* key, const uint8_t bits[], size_t bits_len) {
15✔
125
   if(key == nullptr) {
15✔
126
      return BOTAN_FFI_ERROR_NULL_POINTER;
127
   }
128

129
   *key = nullptr;
15✔
130

131
   if(bits == nullptr && bits_len > 0) {
15✔
132
      return BOTAN_FFI_ERROR_NULL_POINTER;
133
   }
134

135
   return ffi_guard_thunk(__func__, [=]() -> int {
15✔
136
      Botan::DataSource_Memory src(bits, bits_len);
15✔
137
      std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(src));
15✔
138

139
      if(pubkey == nullptr) {
15✔
140
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
141
      }
142

143
      ffi_new_object(key, std::move(pubkey));
15✔
144
      return BOTAN_FFI_SUCCESS;
15✔
145
   });
45✔
146
}
147

148
int botan_pubkey_destroy(botan_pubkey_t key) {
210✔
149
   return BOTAN_FFI_CHECKED_DELETE(key);
210✔
150
}
151

152
int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj) {
105✔
153
   return ffi_guard_thunk(__func__, [=]() -> int {
105✔
154
      auto public_key = safe_get(key_obj).public_key();
105✔
155
      ffi_new_object(pubout, std::move(public_key));
105✔
156
      return BOTAN_FFI_SUCCESS;
105✔
157
   });
105✔
158
}
159

160
int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len) {
4✔
161
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { return write_str_output(out, out_len, k.algo_name()); });
8✔
162
}
163

164
int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) {
7✔
165
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { return write_str_output(out, out_len, k.algo_name()); });
14✔
166
}
167

168
int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags) {
30✔
169
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS) != 0;
30✔
170

171
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
60✔
172
      return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
173
   });
174
}
175

176
int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags) {
15✔
177
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS) != 0;
15✔
178
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
30✔
179
      return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
180
   });
181
}
182

183
int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
48✔
184
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
48✔
185
      return copy_view_bin(out, out_len, botan_pubkey_view_der, key);
24✔
186
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
24✔
187
      return copy_view_str(out, out_len, botan_pubkey_view_pem, key);
24✔
188
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_RAW) {
×
189
      return copy_view_bin(out, out_len, botan_pubkey_view_raw, key);
×
190
   } else {
191
      return BOTAN_FFI_ERROR_BAD_FLAG;
192
   }
193
}
194

195
int botan_pubkey_view_der(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
25✔
196
   return BOTAN_FFI_VISIT(
100✔
197
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.subject_public_key()); });
198
}
199

200
int botan_pubkey_view_pem(botan_pubkey_t key, botan_view_ctx ctx, botan_view_str_fn view) {
28✔
201
   return BOTAN_FFI_VISIT(
84✔
202
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::X509::PEM_encode(k)); });
203
}
204

205
int botan_pubkey_view_raw(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
131✔
206
   return BOTAN_FFI_VISIT(
522✔
207
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.raw_public_key_bits()); });
208
}
209

210
int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
48✔
211
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
48✔
212
      return copy_view_bin(out, out_len, botan_privkey_view_der, key);
24✔
213
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
24✔
214
      return copy_view_str(out, out_len, botan_privkey_view_pem, key);
24✔
215
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_RAW) {
×
216
      return copy_view_bin(out, out_len, botan_privkey_view_raw, key);
×
217
   } else {
218
      return BOTAN_FFI_ERROR_BAD_FLAG;
219
   }
220
}
221

222
int botan_privkey_view_der(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
29✔
223
   return BOTAN_FFI_VISIT(key,
116✔
224
                          [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.private_key_info()); });
225
}
226

227
int botan_privkey_view_pem(botan_privkey_t key, botan_view_ctx ctx, botan_view_str_fn view) {
36✔
228
   return BOTAN_FFI_VISIT(
108✔
229
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::PKCS8::PEM_encode(k)); });
230
}
231

232
int botan_privkey_view_raw(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
110✔
233
   return BOTAN_FFI_VISIT(
438✔
234
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.raw_private_key_bits()); });
235
}
236

237
int botan_privkey_export_encrypted(botan_privkey_t key,
×
238
                                   uint8_t out[],
239
                                   size_t* out_len,
240
                                   botan_rng_t rng_obj,
241
                                   const char* pass,
242
                                   const char* /*ignored - pbe*/,
243
                                   uint32_t flags) {
244
   return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags);
×
245
}
246

247
int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key,
12✔
248
                                              uint8_t out[],
249
                                              size_t* out_len,
250
                                              botan_rng_t rng,
251
                                              const char* passphrase,
252
                                              uint32_t pbkdf_msec,
253
                                              size_t* pbkdf_iters_out,
254
                                              const char* cipher,
255
                                              const char* pbkdf_hash,
256
                                              uint32_t flags) {
257
   if(pbkdf_iters_out != nullptr) {
12✔
258
      *pbkdf_iters_out = 0;
12✔
259
   }
260

261
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
12✔
262
      return copy_view_bin(
12✔
263
         out, out_len, botan_privkey_view_encrypted_der_timed, key, rng, passphrase, cipher, pbkdf_hash, pbkdf_msec);
12✔
264
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
×
265
      return copy_view_str(
×
266
         out, out_len, botan_privkey_view_encrypted_pem_timed, key, rng, passphrase, cipher, pbkdf_hash, pbkdf_msec);
×
267
   } else {
268
      return BOTAN_FFI_ERROR_BAD_FLAG;
269
   }
270
}
271

272
int botan_privkey_view_encrypted_der_timed(botan_privkey_t key,
15✔
273
                                           botan_rng_t rng_obj,
274
                                           const char* passphrase,
275
                                           const char* maybe_cipher,
276
                                           const char* maybe_pbkdf_algo,
277
                                           size_t pbkdf_runtime_msec,
278
                                           botan_view_ctx ctx,
279
                                           botan_view_bin_fn view) {
280
   if(passphrase == nullptr) {
15✔
281
      return BOTAN_FFI_ERROR_NULL_POINTER;
282
   }
283

284
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
102✔
285
      const std::chrono::milliseconds pbkdf_time(pbkdf_runtime_msec);
286
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
287

288
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
289
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
290

291
      auto pkcs8 =
292
         Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, passphrase, pbkdf_time, nullptr, cipher, pbkdf_algo);
293

294
      return invoke_view_callback(view, ctx, pkcs8);
295
   });
296
}
297

298
int botan_privkey_view_encrypted_pem_timed(botan_privkey_t key,
3✔
299
                                           botan_rng_t rng_obj,
300
                                           const char* passphrase,
301
                                           const char* maybe_cipher,
302
                                           const char* maybe_pbkdf_algo,
303
                                           size_t pbkdf_runtime_msec,
304
                                           botan_view_ctx ctx,
305
                                           botan_view_str_fn view) {
306
   if(passphrase == nullptr) {
3✔
307
      return BOTAN_FFI_ERROR_NULL_POINTER;
308
   }
309

310
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
15✔
311
      const std::chrono::milliseconds pbkdf_time(pbkdf_runtime_msec);
312
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
313

314
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
315
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
316

317
      auto pkcs8 =
318
         Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, passphrase, pbkdf_time, nullptr, cipher, pbkdf_algo);
319

320
      return invoke_view_callback(view, ctx, pkcs8);
321
   });
322
}
323

324
int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key,
48✔
325
                                              uint8_t out[],
326
                                              size_t* out_len,
327
                                              botan_rng_t rng,
328
                                              const char* passphrase,
329
                                              size_t pbkdf_iter,
330
                                              const char* cipher,
331
                                              const char* pbkdf_algo,
332
                                              uint32_t flags) {
333
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
48✔
334
      return copy_view_bin(
24✔
335
         out, out_len, botan_privkey_view_encrypted_der, key, rng, passphrase, cipher, pbkdf_algo, pbkdf_iter);
24✔
336
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
24✔
337
      return copy_view_str(
24✔
338
         out, out_len, botan_privkey_view_encrypted_pem, key, rng, passphrase, cipher, pbkdf_algo, pbkdf_iter);
24✔
339
   } else {
340
      return BOTAN_FFI_ERROR_BAD_FLAG;
341
   }
342
}
343

344
int botan_privkey_view_encrypted_der(botan_privkey_t key,
24✔
345
                                     botan_rng_t rng_obj,
346
                                     const char* passphrase,
347
                                     const char* maybe_cipher,
348
                                     const char* maybe_pbkdf_algo,
349
                                     size_t maybe_pbkdf_iterations,
350
                                     botan_view_ctx ctx,
351
                                     botan_view_bin_fn view) {
352
   if(passphrase == nullptr) {
24✔
353
      return BOTAN_FFI_ERROR_NULL_POINTER;
354
   }
355

356
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
192✔
357
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
358

359
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
360
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
361
      const size_t pbkdf_iter = (maybe_pbkdf_iterations ? maybe_pbkdf_iterations : 100000);
362

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

365
      return invoke_view_callback(view, ctx, pkcs8);
366
   });
367
}
368

369
int botan_privkey_view_encrypted_pem(botan_privkey_t key,
24✔
370
                                     botan_rng_t rng_obj,
371
                                     const char* passphrase,
372
                                     const char* maybe_cipher,
373
                                     const char* maybe_pbkdf_algo,
374
                                     size_t maybe_pbkdf_iterations,
375
                                     botan_view_ctx ctx,
376
                                     botan_view_str_fn view) {
377
   if(passphrase == nullptr) {
24✔
378
      return BOTAN_FFI_ERROR_NULL_POINTER;
379
   }
380

381
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
168✔
382
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
383

384
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
385
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
386
      const size_t pbkdf_iter = (maybe_pbkdf_iterations ? maybe_pbkdf_iterations : 100000);
387

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

390
      return invoke_view_callback(view, ctx, pkcs8);
391
   });
392
}
393

394
int botan_pubkey_oid(botan_asn1_oid_t* oid, botan_pubkey_t key) {
2✔
395
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
396
      if(oid == nullptr) {
397
         return BOTAN_FFI_ERROR_NULL_POINTER;
398
      }
399

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

403
      return BOTAN_FFI_SUCCESS;
404
   });
405
}
406

407
int botan_privkey_oid(botan_asn1_oid_t* oid, botan_privkey_t key) {
2✔
408
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
409
      if(oid == nullptr) {
410
         return BOTAN_FFI_ERROR_NULL_POINTER;
411
      }
412

413
      auto oid_ptr = std::make_unique<Botan::OID>(k.object_identifier());
414
      ffi_new_object(oid, std::move(oid_ptr));
415

416
      return BOTAN_FFI_SUCCESS;
417
   });
418
}
419

420
int botan_privkey_stateful_operation(botan_privkey_t key, int* 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(k.stateful_operation()) {
427
         *out = 1;
428
      } else {
429
         *out = 0;
430
      }
431
      return BOTAN_FFI_SUCCESS;
432
   });
433
}
434

435
int botan_privkey_remaining_operations(botan_privkey_t key, uint64_t* out) {
5✔
436
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
10✔
437
      if(out == nullptr) {
438
         return BOTAN_FFI_ERROR_NULL_POINTER;
439
      }
440

441
      if(auto remaining = k.remaining_operations()) {
442
         *out = remaining.value();
443
         return BOTAN_FFI_SUCCESS;
444
      } else {
445
         return BOTAN_FFI_ERROR_NO_VALUE;
446
      }
447
   });
448
}
449

450
int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) {
15✔
451
   if(estimate == nullptr) {
15✔
452
      return BOTAN_FFI_ERROR_NULL_POINTER;
453
   }
454
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { *estimate = k.estimated_strength(); });
30✔
455
}
456

457
int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn, uint8_t out[], size_t* out_len) {
24✔
458
   if(hash_fn == nullptr) {
24✔
459
      return BOTAN_FFI_ERROR_NULL_POINTER;
460
   }
461
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
120✔
462
      auto h = Botan::HashFunction::create_or_throw(hash_fn);
463
      return write_vec_output(out, out_len, h->process(k.public_key_bits()));
464
   });
465
}
466

467
int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len) {
2✔
468
   if(hash_name == nullptr) {
2✔
469
      return BOTAN_FFI_ERROR_NULL_POINTER;
470
   }
471
#if defined(BOTAN_HAS_HASH_ID)
472
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
473
      const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name);
2✔
474
      return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size());
2✔
475
   });
2✔
476
#else
477
   BOTAN_UNUSED(hash_name, pkcs_id, pkcs_id_len);
478
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
479
#endif
480
}
481
}
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