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

randombit / botan / 16248620128

13 Jul 2025 11:27AM UTC coverage: 90.565% (-0.01%) from 90.575%
16248620128

push

github

web-flow
Merge pull request #4983 from randombit/jack/clang-tidy-cppcoreguidelines-owning-memory

Enable and fix clang-tidy warning cppcoreguidelines-owning-memory

99026 of 109342 relevant lines covered (90.57%)

12444574.04 hits per line

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

93.43
/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
         return ffi_new_object(key_obj, std::move(key));
85✔
49
      } else {
50
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
51
      }
52
   });
85✔
53
}
54

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

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

70
      if(key) {
2✔
71
         return ffi_new_object(key_obj, std::move(key));
2✔
72
      } else {
73
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
74
      }
75
   });
2✔
76
}
77

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

82
   *key = nullptr;
51✔
83

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

87
      std::unique_ptr<Botan::Private_Key> pkcs8;
51✔
88

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

95
      if(pkcs8) {
51✔
96
         ffi_new_object(key, std::move(pkcs8));
51✔
97
         return BOTAN_FFI_SUCCESS;
51✔
98
      }
99
      return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
100
   });
102✔
101
}
102

103
int botan_privkey_destroy(botan_privkey_t key) {
216✔
104
   return BOTAN_FFI_CHECKED_DELETE(key);
216✔
105
}
106

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

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

114
      if(pubkey == nullptr) {
12✔
115
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
116
      }
117

118
      ffi_new_object(key, std::move(pubkey));
12✔
119
      return BOTAN_FFI_SUCCESS;
12✔
120
   });
24✔
121
}
122

123
int botan_pubkey_destroy(botan_pubkey_t key) {
179✔
124
   return BOTAN_FFI_CHECKED_DELETE(key);
179✔
125
}
126

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

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

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

143
int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags) {
25✔
144
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS) != 0;
25✔
145

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

263
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
264
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
265

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

269
      return invoke_view_callback(view, ctx, pkcs8);
270
   });
271
}
272

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

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

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

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

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

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

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

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

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

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

340
      return invoke_view_callback(view, ctx, pkcs8);
341
   });
342
}
343

344
int botan_privkey_view_encrypted_pem(botan_privkey_t key,
22✔
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_str_fn view) {
352
   if(passphrase == nullptr) {
22✔
353
      return BOTAN_FFI_ERROR_NULL_POINTER;
354
   }
355

356
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
154✔
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::PEM_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_pubkey_oid(botan_asn1_oid_t* oid, botan_pubkey_t key) {
2✔
370
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
4✔
371
      if(oid == nullptr) {
372
         return BOTAN_FFI_ERROR_NULL_POINTER;
373
      }
374

375
      auto oid_ptr = std::make_unique<Botan::OID>(k.object_identifier());
376
      ffi_new_object(oid, std::move(oid_ptr));
377

378
      return BOTAN_FFI_SUCCESS;
379
   });
380
}
381

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

388
      auto oid_ptr = std::make_unique<Botan::OID>(k.object_identifier());
389
      ffi_new_object(oid, std::move(oid_ptr));
390

391
      return BOTAN_FFI_SUCCESS;
392
   });
393
}
394

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

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

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

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

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

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

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