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 #include <botan/internal/ffi_util.h>
9 #include <botan/internal/ffi_pkey.h>
10 #include <botan/internal/ffi_rng.h>
11 #include <botan/data_src.h>
12 #include <botan/hash.h>
13 #include <botan/pkcs8.h>
14 #include <botan/pk_keys.h>
15 #include <botan/x509_key.h>
16 #include <botan/pk_algs.h>
17 
18 #if defined(BOTAN_HAS_HASH_ID)
19   #include <botan/hash_id.h>
20 #endif
21 
22 extern "C" {
23 
24 using namespace Botan_FFI;
25 
botan_privkey_create(botan_privkey_t * key_obj,const char * algo_name,const char * algo_params,botan_rng_t rng_obj)26 int botan_privkey_create(botan_privkey_t* key_obj,
27                          const char* algo_name,
28                          const char* algo_params,
29                          botan_rng_t rng_obj)
30    {
31    return ffi_guard_thunk(__func__, [=]() -> int {
32       if(key_obj == nullptr)
33          return BOTAN_FFI_ERROR_NULL_POINTER;
34 
35       *key_obj = nullptr;
36       if(rng_obj == nullptr)
37          return BOTAN_FFI_ERROR_NULL_POINTER;
38 
39       Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
40       std::unique_ptr<Botan::Private_Key> key(
41          Botan::create_private_key(algo_name ? algo_name : "RSA",
42                                    rng,
43                                    algo_params ? algo_params : ""));
44 
45       if(key)
46          {
47          *key_obj = new botan_privkey_struct(key.release());
48          return BOTAN_FFI_SUCCESS;
49          }
50       else
51          {
52          return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
53          }
54       });
55    }
56 
botan_privkey_load(botan_privkey_t * key,botan_rng_t rng_obj,const uint8_t bits[],size_t len,const char * password)57 int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng_obj,
58                        const uint8_t bits[], size_t len,
59                        const char* password)
60    {
61    BOTAN_UNUSED(rng_obj);
62 
63    *key = nullptr;
64 
65    return ffi_guard_thunk(__func__, [=]() -> int {
66       Botan::DataSource_Memory src(bits, len);
67 
68       std::unique_ptr<Botan::Private_Key> pkcs8;
69 
70       if(password == nullptr)
71          {
72          pkcs8 = Botan::PKCS8::load_key(src);
73          }
74       else
75          {
76          pkcs8 = Botan::PKCS8::load_key(src, std::string(password));
77          }
78 
79       if(pkcs8)
80          {
81          *key = new botan_privkey_struct(pkcs8.release());
82          return BOTAN_FFI_SUCCESS;
83          }
84       return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
85       });
86    }
87 
botan_privkey_destroy(botan_privkey_t key)88 int botan_privkey_destroy(botan_privkey_t key)
89    {
90    return BOTAN_FFI_CHECKED_DELETE(key);
91    }
92 
botan_pubkey_load(botan_pubkey_t * key,const uint8_t bits[],size_t bits_len)93 int botan_pubkey_load(botan_pubkey_t* key,
94                       const uint8_t bits[], size_t bits_len)
95    {
96    *key = nullptr;
97 
98    return ffi_guard_thunk(__func__, [=]() -> int {
99       Botan::DataSource_Memory src(bits, bits_len);
100       std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(src));
101 
102       if(pubkey == nullptr)
103          return BOTAN_FFI_ERROR_UNKNOWN_ERROR;
104 
105       *key = new botan_pubkey_struct(pubkey.release());
106       return BOTAN_FFI_SUCCESS;
107       });
108    }
109 
botan_pubkey_destroy(botan_pubkey_t key)110 int botan_pubkey_destroy(botan_pubkey_t key)
111    {
112    return BOTAN_FFI_CHECKED_DELETE(key);
113    }
114 
botan_privkey_export_pubkey(botan_pubkey_t * pubout,botan_privkey_t key_obj)115 int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj)
116    {
117    return ffi_guard_thunk(__func__, [=]() -> int {
118       std::unique_ptr<Botan::Public_Key>
119          pubkey(Botan::X509::load_key(Botan::X509::BER_encode(safe_get(key_obj))));
120 
121       *pubout = new botan_pubkey_struct(pubkey.release());
122       return BOTAN_FFI_SUCCESS;
123       });
124    }
125 
botan_privkey_algo_name(botan_privkey_t key,char out[],size_t * out_len)126 int botan_privkey_algo_name(botan_privkey_t key, char out[], size_t* out_len)
127    {
128    return BOTAN_FFI_DO(Botan::Private_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); });
129    }
130 
botan_pubkey_algo_name(botan_pubkey_t key,char out[],size_t * out_len)131 int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len)
132    {
133    return BOTAN_FFI_DO(Botan::Public_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); });
134    }
135 
botan_pubkey_check_key(botan_pubkey_t key,botan_rng_t rng,uint32_t flags)136 int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags)
137    {
138    const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
139 
140    return BOTAN_FFI_RETURNING(Botan::Public_Key, key, k, {
141       return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
142       });
143    }
144 
botan_privkey_check_key(botan_privkey_t key,botan_rng_t rng,uint32_t flags)145 int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags)
146    {
147    const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS);
148    return BOTAN_FFI_RETURNING(Botan::Private_Key, key, k, {
149       return (k.check_key(safe_get(rng), strong) == true) ? 0 : BOTAN_FFI_ERROR_INVALID_INPUT;
150       });
151    }
152 
botan_pubkey_export(botan_pubkey_t key,uint8_t out[],size_t * out_len,uint32_t flags)153 int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags)
154    {
155    return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
156       if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
157          return write_vec_output(out, out_len, Botan::X509::BER_encode(k));
158       else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
159          return write_str_output(out, out_len, Botan::X509::PEM_encode(k));
160       else
161          return BOTAN_FFI_ERROR_BAD_FLAG;
162       });
163    }
164 
botan_privkey_export(botan_privkey_t key,uint8_t out[],size_t * out_len,uint32_t flags)165 int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags)
166    {
167    return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
168       if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
169          return write_vec_output(out, out_len, Botan::PKCS8::BER_encode(k));
170       else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
171          return write_str_output(out, out_len, Botan::PKCS8::PEM_encode(k));
172       else
173          return BOTAN_FFI_ERROR_BAD_FLAG;
174       });
175    }
176 
botan_privkey_export_encrypted(botan_privkey_t key,uint8_t out[],size_t * out_len,botan_rng_t rng_obj,const char * pass,const char *,uint32_t flags)177 int botan_privkey_export_encrypted(botan_privkey_t key,
178                                    uint8_t out[], size_t* out_len,
179                                    botan_rng_t rng_obj,
180                                    const char* pass,
181                                    const char* /*ignored - pbe*/,
182                                    uint32_t flags)
183    {
184    return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags);
185    }
186 
botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key,uint8_t out[],size_t * out_len,botan_rng_t rng_obj,const char * pass,uint32_t pbkdf_msec,size_t * pbkdf_iters_out,const char * maybe_cipher,const char * maybe_pbkdf_hash,uint32_t flags)187 int botan_privkey_export_encrypted_pbkdf_msec(botan_privkey_t key,
188                                               uint8_t out[], size_t* out_len,
189                                               botan_rng_t rng_obj,
190                                               const char* pass,
191                                               uint32_t pbkdf_msec,
192                                               size_t* pbkdf_iters_out,
193                                               const char* maybe_cipher,
194                                               const char* maybe_pbkdf_hash,
195                                               uint32_t flags)
196    {
197    return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
198       const std::chrono::milliseconds pbkdf_time(pbkdf_msec);
199       Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
200 
201       const std::string cipher = (maybe_cipher ? maybe_cipher : "");
202       const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : "");
203 
204       if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
205          {
206          return write_vec_output(out, out_len,
207                                  Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash));
208          }
209       else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
210          {
211          return write_str_output(out, out_len,
212                                  Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash));
213          }
214       else
215          {
216          return -2;
217          }
218       });
219    }
220 
botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key,uint8_t out[],size_t * out_len,botan_rng_t rng_obj,const char * pass,size_t pbkdf_iter,const char * maybe_cipher,const char * maybe_pbkdf_hash,uint32_t flags)221 int botan_privkey_export_encrypted_pbkdf_iter(botan_privkey_t key,
222                                               uint8_t out[], size_t* out_len,
223                                               botan_rng_t rng_obj,
224                                               const char* pass,
225                                               size_t pbkdf_iter,
226                                               const char* maybe_cipher,
227                                               const char* maybe_pbkdf_hash,
228                                               uint32_t flags)
229    {
230    return BOTAN_FFI_DO(Botan::Private_Key, key, k, {
231       Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
232 
233       const std::string cipher = (maybe_cipher ? maybe_cipher : "");
234       const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : "");
235 
236       if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER)
237          {
238          return write_vec_output(out, out_len,
239                                  Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash));
240          }
241       else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM)
242          {
243          return write_str_output(out, out_len,
244                                  Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash));
245          }
246       else
247          {
248          return -2;
249          }
250       });
251    }
252 
botan_pubkey_estimated_strength(botan_pubkey_t key,size_t * estimate)253 int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate)
254    {
255    return BOTAN_FFI_DO(Botan::Public_Key, key, k, { *estimate = k.estimated_strength(); });
256    }
257 
botan_pubkey_fingerprint(botan_pubkey_t key,const char * hash_fn,uint8_t out[],size_t * out_len)258 int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn,
259                              uint8_t out[], size_t* out_len)
260    {
261    return BOTAN_FFI_DO(Botan::Public_Key, key, k, {
262       std::unique_ptr<Botan::HashFunction> h(Botan::HashFunction::create(hash_fn));
263       return write_vec_output(out, out_len, h->process(k.public_key_bits()));
264       });
265    }
266 
botan_pkcs_hash_id(const char * hash_name,uint8_t pkcs_id[],size_t * pkcs_id_len)267 int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len)
268    {
269 #if defined(BOTAN_HAS_HASH_ID)
270    return ffi_guard_thunk(__func__, [=]() -> int {
271       const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name);
272       return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size());
273       });
274 #else
275    return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
276 #endif
277    }
278 
279 }
280