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

randombit / botan / 14572538029

21 Apr 2025 11:16AM UTC coverage: 91.344% (+0.03%) from 91.317%
14572538029

Pull #4833

github

web-flow
Merge 5226c60f2 into 4c413a8ac
Pull Request #4833: Add EC_Group related methods to FFI

95889 of 104976 relevant lines covered (91.34%)

12942170.1 hits per line

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

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

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

25
extern "C" {
26

27
using namespace Botan_FFI;
28

29
int botan_privkey_create(botan_privkey_t* key_obj,
85✔
30
                         const char* algo_name,
31
                         const char* algo_params,
32
                         botan_rng_t rng_obj) {
33
   return ffi_guard_thunk(__func__, [=]() -> int {
85✔
34
      if(key_obj == nullptr) {
85✔
35
         return BOTAN_FFI_ERROR_NULL_POINTER;
36
      }
37

38
      *key_obj = nullptr;
85✔
39
      if(rng_obj == nullptr) {
85✔
40
         return BOTAN_FFI_ERROR_NULL_POINTER;
41
      }
42

43
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
85✔
44
      std::unique_ptr<Botan::Private_Key> key(
85✔
45
         Botan::create_private_key(algo_name ? algo_name : "RSA", rng, algo_params ? algo_params : ""));
255✔
46

47
      if(key) {
85✔
48
         *key_obj = new botan_privkey_struct(std::move(key));
85✔
49
         return BOTAN_FFI_SUCCESS;
85✔
50
      } else {
51
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
52
      }
53
   });
85✔
54
}
55

56
int botan_ec_privkey_create(botan_privkey_t* key_obj,
2✔
57
                            const char* algo_name,
58
                            botan_ec_group_t ec_group_obj,
59
                            botan_rng_t rng_obj) {
60
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
61
      if(key_obj == nullptr) {
2✔
62
         return BOTAN_FFI_ERROR_NULL_POINTER;
63
      }
64
      *key_obj = nullptr;
2✔
65

66
      Botan::EC_Group ec_group = safe_get(ec_group_obj);
2✔
67
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
2✔
68
      std::unique_ptr<Botan::Private_Key> key(
2✔
69
         Botan::create_ec_private_key(algo_name ? algo_name : "ECDSA", ec_group, rng));
4✔
70

71
      if(key) {
2✔
72
         *key_obj = new botan_privkey_struct(std::move(key));
2✔
73
         return BOTAN_FFI_SUCCESS;
2✔
74
      } else {
75
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
76
      }
77
   });
2✔
78
}
79

80
int botan_privkey_load(
51✔
81
   botan_privkey_t* key, botan_rng_t rng_obj, const uint8_t bits[], size_t len, const char* password) {
82
   BOTAN_UNUSED(rng_obj);
51✔
83

84
   *key = nullptr;
51✔
85

86
   return ffi_guard_thunk(__func__, [=]() -> int {
51✔
87
      Botan::DataSource_Memory src(bits, len);
51✔
88

89
      std::unique_ptr<Botan::Private_Key> pkcs8;
51✔
90

91
      if(password == nullptr) {
51✔
92
         pkcs8 = Botan::PKCS8::load_key(src);
22✔
93
      } else {
94
         pkcs8 = Botan::PKCS8::load_key(src, std::string(password));
29✔
95
      }
96

97
      if(pkcs8) {
51✔
98
         *key = new botan_privkey_struct(std::move(pkcs8));
51✔
99
         return BOTAN_FFI_SUCCESS;
51✔
100
      }
101
      return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
102
   });
102✔
103
}
104

105
int botan_privkey_destroy(botan_privkey_t key) {
216✔
106
   return BOTAN_FFI_CHECKED_DELETE(key);
216✔
107
}
108

109
int botan_pubkey_load(botan_pubkey_t* key, const uint8_t bits[], size_t bits_len) {
12✔
110
   *key = nullptr;
12✔
111

112
   return ffi_guard_thunk(__func__, [=]() -> int {
12✔
113
      Botan::DataSource_Memory src(bits, bits_len);
12✔
114
      std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(src));
12✔
115

116
      if(pubkey == nullptr) {
12✔
117
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
118
      }
119

120
      *key = new botan_pubkey_struct(std::move(pubkey));
12✔
121
      return BOTAN_FFI_SUCCESS;
12✔
122
   });
24✔
123
}
124

125
int botan_pubkey_destroy(botan_pubkey_t key) {
179✔
126
   return BOTAN_FFI_CHECKED_DELETE(key);
179✔
127
}
128

129
int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj) {
91✔
130
   return ffi_guard_thunk(__func__, [=]() -> int {
91✔
131
      auto public_key = safe_get(key_obj).public_key();
91✔
132
      *pubout = new botan_pubkey_struct(std::move(public_key));
91✔
133
      return BOTAN_FFI_SUCCESS;
91✔
134
   });
91✔
135
}
136

137
int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len) {
4✔
138
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { return write_str_output(out, out_len, k.algo_name()); });
8✔
139
}
140

141
int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) {
7✔
142
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { return write_str_output(out, out_len, k.algo_name()); });
14✔
143
}
144

145
int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags) {
25✔
146
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
25✔
147

148
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
50✔
149
      return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
150
   });
151
}
152

153
int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags) {
16✔
154
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
16✔
155
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
32✔
156
      return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
157
   });
158
}
159

160
int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
44✔
161
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
44✔
162
      return copy_view_bin(out, out_len, botan_pubkey_view_der, key);
22✔
163
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
22✔
164
      return copy_view_str(out, out_len, botan_pubkey_view_pem, key);
22✔
165
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_RAW) {
×
166
      return copy_view_bin(out, out_len, botan_pubkey_view_raw, key);
×
167
   } else {
168
      return BOTAN_FFI_ERROR_BAD_FLAG;
169
   }
170
}
171

172
int botan_pubkey_view_der(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
23✔
173
   return BOTAN_FFI_VISIT(
92✔
174
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.subject_public_key()); });
175
}
176

177
int botan_pubkey_view_pem(botan_pubkey_t key, botan_view_ctx ctx, botan_view_str_fn view) {
26✔
178
   return BOTAN_FFI_VISIT(
78✔
179
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::X509::PEM_encode(k)); });
180
}
181

182
int botan_pubkey_view_raw(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
110✔
183
   return BOTAN_FFI_VISIT(
438✔
184
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.raw_public_key_bits()); });
185
}
186

187
int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
44✔
188
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
44✔
189
      return copy_view_bin(out, out_len, botan_privkey_view_der, key);
22✔
190
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
22✔
191
      return copy_view_str(out, out_len, botan_privkey_view_pem, key);
22✔
192
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_RAW) {
×
193
      return copy_view_bin(out, out_len, botan_privkey_view_raw, key);
×
194
   } else {
195
      return BOTAN_FFI_ERROR_BAD_FLAG;
196
   }
197
}
198

199
int botan_privkey_view_der(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
27✔
200
   return BOTAN_FFI_VISIT(
108✔
201
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::PKCS8::BER_encode(k)); });
202
}
203

204
int botan_privkey_view_pem(botan_privkey_t key, botan_view_ctx ctx, botan_view_str_fn view) {
34✔
205
   return BOTAN_FFI_VISIT(
102✔
206
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::PKCS8::PEM_encode(k)); });
207
}
208

209
int botan_privkey_view_raw(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
110✔
210
   return BOTAN_FFI_VISIT(
438✔
211
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, k.raw_private_key_bits()); });
212
}
213

214
int botan_privkey_export_encrypted(botan_privkey_t key,
×
215
                                   uint8_t out[],
216
                                   size_t* out_len,
217
                                   botan_rng_t rng_obj,
218
                                   const char* pass,
219
                                   const char* /*ignored - pbe*/,
220
                                   uint32_t flags) {
221
   return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags);
×
222
}
223

224
int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key,
11✔
225
                                              uint8_t out[],
226
                                              size_t* out_len,
227
                                              botan_rng_t rng,
228
                                              const char* passphrase,
229
                                              uint32_t pbkdf_msec,
230
                                              size_t* pbkdf_iters_out,
231
                                              const char* cipher,
232
                                              const char* pbkdf_hash,
233
                                              uint32_t flags) {
234
   if(pbkdf_iters_out) {
11✔
235
      *pbkdf_iters_out = 0;
11✔
236
   }
237

238
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
11✔
239
      return copy_view_bin(
11✔
240
         out, out_len, botan_privkey_view_encrypted_der_timed, key, rng, passphrase, cipher, pbkdf_hash, pbkdf_msec);
11✔
241
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
×
242
      return copy_view_str(
×
243
         out, out_len, botan_privkey_view_encrypted_pem_timed, key, rng, passphrase, cipher, pbkdf_hash, pbkdf_msec);
×
244
   } else {
245
      return BOTAN_FFI_ERROR_BAD_FLAG;
246
   }
247
}
248

249
int botan_privkey_view_encrypted_der_timed(botan_privkey_t key,
14✔
250
                                           botan_rng_t rng_obj,
251
                                           const char* passphrase,
252
                                           const char* maybe_cipher,
253
                                           const char* maybe_pbkdf_algo,
254
                                           size_t pbkdf_runtime_msec,
255
                                           botan_view_ctx ctx,
256
                                           botan_view_bin_fn view) {
257
   if(passphrase == nullptr) {
14✔
258
      return BOTAN_FFI_ERROR_NULL_POINTER;
259
   }
260

261
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
95✔
262
      const std::chrono::milliseconds pbkdf_time(pbkdf_runtime_msec);
263
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
264

265
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
266
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
267

268
      auto pkcs8 =
269
         Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, passphrase, pbkdf_time, nullptr, cipher, pbkdf_algo);
270

271
      return invoke_view_callback(view, ctx, pkcs8);
272
   });
273
}
274

275
int botan_privkey_view_encrypted_pem_timed(botan_privkey_t key,
3✔
276
                                           botan_rng_t rng_obj,
277
                                           const char* passphrase,
278
                                           const char* maybe_cipher,
279
                                           const char* maybe_pbkdf_algo,
280
                                           size_t pbkdf_runtime_msec,
281
                                           botan_view_ctx ctx,
282
                                           botan_view_str_fn view) {
283
   if(passphrase == nullptr) {
3✔
284
      return BOTAN_FFI_ERROR_NULL_POINTER;
285
   }
286

287
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
15✔
288
      const std::chrono::milliseconds pbkdf_time(pbkdf_runtime_msec);
289
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
290

291
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
292
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
293

294
      auto pkcs8 =
295
         Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, passphrase, pbkdf_time, nullptr, cipher, pbkdf_algo);
296

297
      return invoke_view_callback(view, ctx, pkcs8);
298
   });
299
}
300

301
int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key,
44✔
302
                                              uint8_t out[],
303
                                              size_t* out_len,
304
                                              botan_rng_t rng,
305
                                              const char* passphrase,
306
                                              size_t pbkdf_iter,
307
                                              const char* cipher,
308
                                              const char* pbkdf_algo,
309
                                              uint32_t flags) {
310
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
44✔
311
      return copy_view_bin(
22✔
312
         out, out_len, botan_privkey_view_encrypted_der, key, rng, passphrase, cipher, pbkdf_algo, pbkdf_iter);
22✔
313
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
22✔
314
      return copy_view_str(
22✔
315
         out, out_len, botan_privkey_view_encrypted_pem, key, rng, passphrase, cipher, pbkdf_algo, pbkdf_iter);
22✔
316
   } else {
317
      return BOTAN_FFI_ERROR_BAD_FLAG;
318
   }
319
}
320

321
int botan_privkey_view_encrypted_der(botan_privkey_t key,
22✔
322
                                     botan_rng_t rng_obj,
323
                                     const char* passphrase,
324
                                     const char* maybe_cipher,
325
                                     const char* maybe_pbkdf_algo,
326
                                     size_t maybe_pbkdf_iterations,
327
                                     botan_view_ctx ctx,
328
                                     botan_view_bin_fn view) {
329
   if(passphrase == nullptr) {
22✔
330
      return BOTAN_FFI_ERROR_NULL_POINTER;
331
   }
332

333
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
176✔
334
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
335

336
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
337
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
338
      const size_t pbkdf_iter = (maybe_pbkdf_iterations ? maybe_pbkdf_iterations : 100000);
339

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

342
      return invoke_view_callback(view, ctx, pkcs8);
343
   });
344
}
345

346
int botan_privkey_view_encrypted_pem(botan_privkey_t key,
22✔
347
                                     botan_rng_t rng_obj,
348
                                     const char* passphrase,
349
                                     const char* maybe_cipher,
350
                                     const char* maybe_pbkdf_algo,
351
                                     size_t maybe_pbkdf_iterations,
352
                                     botan_view_ctx ctx,
353
                                     botan_view_str_fn view) {
354
   if(passphrase == nullptr) {
22✔
355
      return BOTAN_FFI_ERROR_NULL_POINTER;
356
   }
357

358
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
154✔
359
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
360

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

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

367
      return invoke_view_callback(view, ctx, pkcs8);
368
   });
369
}
370

371
int botan_pubkey_oid(botan_asn1_oid_t* oid, botan_pubkey_t key) {
2✔
372
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
373
      if(oid == nullptr) {
374
         return BOTAN_FFI_ERROR_NULL_POINTER;
375
      }
376

377
      std::unique_ptr<Botan::OID> o = std::make_unique<Botan::OID>(k.object_identifier());
378
      *oid = new botan_asn1_oid_struct(std::move(o));
379

380
      return BOTAN_FFI_SUCCESS;
381
   });
382
}
383

384
int botan_privkey_oid(botan_asn1_oid_t* oid, botan_privkey_t key) {
2✔
385
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
386
      if(oid == nullptr) {
387
         return BOTAN_FFI_ERROR_NULL_POINTER;
388
      }
389

390
      std::unique_ptr<Botan::OID> o = std::make_unique<Botan::OID>(k.object_identifier());
391
      *oid = new botan_asn1_oid_struct(std::move(o));
392

393
      return BOTAN_FFI_SUCCESS;
394
   });
395
}
396

397
int botan_privkey_stateful_operation(botan_privkey_t key, int* out) {
5✔
398
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
10✔
399
      if(out == nullptr) {
400
         return BOTAN_FFI_ERROR_NULL_POINTER;
401
      }
402

403
      if(k.stateful_operation()) {
404
         *out = 1;
405
      } else {
406
         *out = 0;
407
      }
408
      return BOTAN_FFI_SUCCESS;
409
   });
410
}
411

412
int botan_privkey_remaining_operations(botan_privkey_t key, uint64_t* out) {
5✔
413
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
10✔
414
      if(out == nullptr) {
415
         return BOTAN_FFI_ERROR_NULL_POINTER;
416
      }
417

418
      if(auto remaining = k.remaining_operations()) {
419
         *out = remaining.value();
420
         return BOTAN_FFI_SUCCESS;
421
      } else {
422
         return BOTAN_FFI_ERROR_NO_VALUE;
423
      }
424
   });
425
}
426

427
int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) {
14✔
428
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { *estimate = k.estimated_strength(); });
28✔
429
}
430

431
int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn, uint8_t out[], size_t* out_len) {
22✔
432
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
110✔
433
      auto h = Botan::HashFunction::create_or_throw(hash_fn);
434
      return write_vec_output(out, out_len, h->process(k.public_key_bits()));
435
   });
436
}
437

438
int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len) {
2✔
439
#if defined(BOTAN_HAS_HASH_ID)
440
   return ffi_guard_thunk(__func__, [=]() -> int {
2✔
441
      const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name);
2✔
442
      return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size());
2✔
443
   });
2✔
444
#else
445
   BOTAN_UNUSED(hash_name, pkcs_id, pkcs_id_len);
446
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
447
#endif
448
}
449
}
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