Coverage Report

Created: 2025-10-10 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/Botan-3.4.0/src/lib/ffi/ffi_pkey.cpp
Line
Count
Source
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_pkey.h>
16
#include <botan/internal/ffi_rng.h>
17
#include <botan/internal/ffi_util.h>
18
19
#if defined(BOTAN_HAS_HASH_ID)
20
   #include <botan/internal/hash_id.h>
21
#endif
22
23
extern "C" {
24
25
using namespace Botan_FFI;
26
27
int botan_privkey_create(botan_privkey_t* key_obj,
28
                         const char* algo_name,
29
                         const char* algo_params,
30
0
                         botan_rng_t rng_obj) {
31
0
   return ffi_guard_thunk(__func__, [=]() -> int {
32
0
      if(key_obj == nullptr) {
33
0
         return BOTAN_FFI_ERROR_NULL_POINTER;
34
0
      }
35
36
0
      *key_obj = nullptr;
37
0
      if(rng_obj == nullptr) {
38
0
         return BOTAN_FFI_ERROR_NULL_POINTER;
39
0
      }
40
41
0
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
42
0
      std::unique_ptr<Botan::Private_Key> key(
43
0
         Botan::create_private_key(algo_name ? algo_name : "RSA", rng, algo_params ? algo_params : ""));
44
45
0
      if(key) {
46
0
         *key_obj = new botan_privkey_struct(std::move(key));
47
0
         return BOTAN_FFI_SUCCESS;
48
0
      } else {
49
0
         return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
50
0
      }
51
0
   });
52
0
}
53
54
int botan_privkey_load(
55
0
   botan_privkey_t* key, botan_rng_t rng_obj, const uint8_t bits[], size_t len, const char* password) {
56
0
   BOTAN_UNUSED(rng_obj);
57
58
0
   *key = nullptr;
59
60
0
   return ffi_guard_thunk(__func__, [=]() -> int {
61
0
      Botan::DataSource_Memory src(bits, len);
62
63
0
      std::unique_ptr<Botan::Private_Key> pkcs8;
64
65
0
      if(password == nullptr) {
66
0
         pkcs8 = Botan::PKCS8::load_key(src);
67
0
      } else {
68
0
         pkcs8 = Botan::PKCS8::load_key(src, std::string(password));
69
0
      }
70
71
0
      if(pkcs8) {
72
0
         *key = new botan_privkey_struct(std::move(pkcs8));
73
0
         return BOTAN_FFI_SUCCESS;
74
0
      }
75
0
      return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
76
0
   });
77
0
}
78
79
0
int botan_privkey_destroy(botan_privkey_t key) {
80
0
   return BOTAN_FFI_CHECKED_DELETE(key);
81
0
}
82
83
0
int botan_pubkey_load(botan_pubkey_t* key, const uint8_t bits[], size_t bits_len) {
84
0
   *key = nullptr;
85
86
0
   return ffi_guard_thunk(__func__, [=]() -> int {
87
0
      Botan::DataSource_Memory src(bits, bits_len);
88
0
      std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(src));
89
90
0
      if(pubkey == nullptr) {
91
0
         return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
92
0
      }
93
94
0
      *key = new botan_pubkey_struct(std::move(pubkey));
95
0
      return BOTAN_FFI_SUCCESS;
96
0
   });
97
0
}
98
99
205k
int botan_pubkey_destroy(botan_pubkey_t key) {
100
205k
   return BOTAN_FFI_CHECKED_DELETE(key);
101
205k
}
102
103
0
int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj) {
104
0
   return ffi_guard_thunk(__func__, [=]() -> int {
105
0
      auto public_key = safe_get(key_obj).public_key();
106
0
      *pubout = new botan_pubkey_struct(std::move(public_key));
107
0
      return BOTAN_FFI_SUCCESS;
108
0
   });
109
0
}
110
111
0
int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len) {
112
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { return write_str_output(out, out_len, k.algo_name()); });
113
0
}
114
115
0
int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) {
116
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { return write_str_output(out, out_len, k.algo_name()); });
117
0
}
118
119
0
int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags) {
120
0
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
121
122
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
123
0
      return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
124
0
   });
125
0
}
126
127
0
int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags) {
128
0
   const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
129
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
130
0
      return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
131
0
   });
132
0
}
133
134
0
int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
135
0
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
136
0
      return copy_view_bin(out, out_len, botan_pubkey_view_der, key);
137
0
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
138
0
      return copy_view_str(out, out_len, botan_pubkey_view_pem, key);
139
0
   } else {
140
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
141
0
   }
142
0
}
143
144
0
int botan_pubkey_view_der(botan_pubkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
145
0
   return BOTAN_FFI_VISIT(
146
0
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::X509::BER_encode(k)); });
147
0
}
148
149
0
int botan_pubkey_view_pem(botan_pubkey_t key, botan_view_ctx ctx, botan_view_str_fn view) {
150
0
   return BOTAN_FFI_VISIT(
151
0
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::X509::PEM_encode(k)); });
152
0
}
153
154
0
int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) {
155
0
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
156
0
      return copy_view_bin(out, out_len, botan_privkey_view_der, key);
157
0
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
158
0
      return copy_view_str(out, out_len, botan_privkey_view_pem, key);
159
0
   } else {
160
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
161
0
   }
162
0
}
163
164
0
int botan_privkey_view_der(botan_privkey_t key, botan_view_ctx ctx, botan_view_bin_fn view) {
165
0
   return BOTAN_FFI_VISIT(
166
0
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::PKCS8::BER_encode(k)); });
167
0
}
168
169
0
int botan_privkey_view_pem(botan_privkey_t key, botan_view_ctx ctx, botan_view_str_fn view) {
170
0
   return BOTAN_FFI_VISIT(
171
0
      key, [=](const auto& k) -> int { return invoke_view_callback(view, ctx, Botan::PKCS8::PEM_encode(k)); });
172
0
}
173
174
int botan_privkey_export_encrypted(botan_privkey_t key,
175
                                   uint8_t out[],
176
                                   size_t* out_len,
177
                                   botan_rng_t rng_obj,
178
                                   const char* pass,
179
                                   const char* /*ignored - pbe*/,
180
0
                                   uint32_t flags) {
181
0
   return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags);
182
0
}
183
184
int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key,
185
                                              uint8_t out[],
186
                                              size_t* out_len,
187
                                              botan_rng_t rng,
188
                                              const char* passphrase,
189
                                              uint32_t pbkdf_msec,
190
                                              size_t* pbkdf_iters_out,
191
                                              const char* cipher,
192
                                              const char* pbkdf_hash,
193
0
                                              uint32_t flags) {
194
0
   if(pbkdf_iters_out) {
195
0
      *pbkdf_iters_out = 0;
196
0
   }
197
198
0
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
199
0
      return copy_view_bin(
200
0
         out, out_len, botan_privkey_view_encrypted_der_timed, key, rng, passphrase, cipher, pbkdf_hash, pbkdf_msec);
201
0
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
202
0
      return copy_view_str(
203
0
         out, out_len, botan_privkey_view_encrypted_pem_timed, key, rng, passphrase, cipher, pbkdf_hash, pbkdf_msec);
204
0
   } else {
205
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
206
0
   }
207
0
}
208
209
int botan_privkey_view_encrypted_der_timed(botan_privkey_t key,
210
                                           botan_rng_t rng_obj,
211
                                           const char* passphrase,
212
                                           const char* maybe_cipher,
213
                                           const char* maybe_pbkdf_algo,
214
                                           size_t pbkdf_runtime_msec,
215
                                           botan_view_ctx ctx,
216
0
                                           botan_view_bin_fn view) {
217
0
   if(passphrase == nullptr) {
218
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
219
0
   }
220
221
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
222
0
      const std::chrono::milliseconds pbkdf_time(pbkdf_runtime_msec);
223
0
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
224
225
0
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
226
0
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
227
228
0
      auto pkcs8 =
229
0
         Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, passphrase, pbkdf_time, nullptr, cipher, pbkdf_algo);
230
231
0
      return invoke_view_callback(view, ctx, pkcs8);
232
0
   });
233
0
}
234
235
int botan_privkey_view_encrypted_pem_timed(botan_privkey_t key,
236
                                           botan_rng_t rng_obj,
237
                                           const char* passphrase,
238
                                           const char* maybe_cipher,
239
                                           const char* maybe_pbkdf_algo,
240
                                           size_t pbkdf_runtime_msec,
241
                                           botan_view_ctx ctx,
242
0
                                           botan_view_str_fn view) {
243
0
   if(passphrase == nullptr) {
244
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
245
0
   }
246
247
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
248
0
      const std::chrono::milliseconds pbkdf_time(pbkdf_runtime_msec);
249
0
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
250
251
0
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
252
0
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
253
254
0
      auto pkcs8 =
255
0
         Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, passphrase, pbkdf_time, nullptr, cipher, pbkdf_algo);
256
257
0
      return invoke_view_callback(view, ctx, pkcs8);
258
0
   });
259
0
}
260
261
int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key,
262
                                              uint8_t out[],
263
                                              size_t* out_len,
264
                                              botan_rng_t rng,
265
                                              const char* passphrase,
266
                                              size_t pbkdf_iter,
267
                                              const char* cipher,
268
                                              const char* pbkdf_algo,
269
0
                                              uint32_t flags) {
270
0
   if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) {
271
0
      return copy_view_bin(
272
0
         out, out_len, botan_privkey_view_encrypted_der, key, rng, passphrase, cipher, pbkdf_algo, pbkdf_iter);
273
0
   } else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) {
274
0
      return copy_view_str(
275
0
         out, out_len, botan_privkey_view_encrypted_pem, key, rng, passphrase, cipher, pbkdf_algo, pbkdf_iter);
276
0
   } else {
277
0
      return BOTAN_FFI_ERROR_BAD_FLAG;
278
0
   }
279
0
}
280
281
int botan_privkey_view_encrypted_der(botan_privkey_t key,
282
                                     botan_rng_t rng_obj,
283
                                     const char* passphrase,
284
                                     const char* maybe_cipher,
285
                                     const char* maybe_pbkdf_algo,
286
                                     size_t maybe_pbkdf_iterations,
287
                                     botan_view_ctx ctx,
288
0
                                     botan_view_bin_fn view) {
289
0
   if(passphrase == nullptr) {
290
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
291
0
   }
292
293
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
294
0
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
295
296
0
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
297
0
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
298
0
      const size_t pbkdf_iter = (maybe_pbkdf_iterations ? maybe_pbkdf_iterations : 100000);
299
300
0
      auto pkcs8 = Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(k, rng, passphrase, pbkdf_iter, cipher, pbkdf_algo);
301
302
0
      return invoke_view_callback(view, ctx, pkcs8);
303
0
   });
304
0
}
305
306
int botan_privkey_view_encrypted_pem(botan_privkey_t key,
307
                                     botan_rng_t rng_obj,
308
                                     const char* passphrase,
309
                                     const char* maybe_cipher,
310
                                     const char* maybe_pbkdf_algo,
311
                                     size_t maybe_pbkdf_iterations,
312
                                     botan_view_ctx ctx,
313
0
                                     botan_view_str_fn view) {
314
0
   if(passphrase == nullptr) {
315
0
      return BOTAN_FFI_ERROR_NULL_POINTER;
316
0
   }
317
318
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
319
0
      Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
320
321
0
      const std::string cipher = (maybe_cipher ? maybe_cipher : "");
322
0
      const std::string pbkdf_algo = (maybe_pbkdf_algo ? maybe_pbkdf_algo : "");
323
0
      const size_t pbkdf_iter = (maybe_pbkdf_iterations ? maybe_pbkdf_iterations : 100000);
324
325
0
      auto pkcs8 = Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(k, rng, passphrase, pbkdf_iter, cipher, pbkdf_algo);
326
327
0
      return invoke_view_callback(view, ctx, pkcs8);
328
0
   });
329
0
}
330
331
0
int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) {
332
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) { *estimate = k.estimated_strength(); });
333
0
}
334
335
0
int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn, uint8_t out[], size_t* out_len) {
336
0
   return BOTAN_FFI_VISIT(key, [=](const auto& k) {
337
0
      auto h = Botan::HashFunction::create_or_throw(hash_fn);
338
0
      return write_vec_output(out, out_len, h->process(k.public_key_bits()));
339
0
   });
340
0
}
341
342
0
int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len) {
343
0
#if defined(BOTAN_HAS_HASH_ID)
344
0
   return ffi_guard_thunk(__func__, [=]() -> int {
345
0
      const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name);
346
0
      return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size());
347
0
   });
348
#else
349
   BOTAN_UNUSED(hash_name, pkcs_id, pkcs_id_len);
350
   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
351
#endif
352
0
}
353
}