/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 | | } |