diff options
Diffstat (limited to 'src/lib/ffi/ffi_pkey.cpp')
-rw-r--r-- | src/lib/ffi/ffi_pkey.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/lib/ffi/ffi_pkey.cpp b/src/lib/ffi/ffi_pkey.cpp new file mode 100644 index 000000000..1577118b1 --- /dev/null +++ b/src/lib/ffi/ffi_pkey.cpp @@ -0,0 +1,263 @@ +/* +* (C) 2015,2017 Jack Lloyd +* +* Botan is released under the Simplified BSD License (see license.txt) +*/ + +#include <botan/ffi.h> +#include <botan/internal/ffi_util.h> +#include <botan/internal/ffi_pkey.h> +#include <botan/internal/ffi_rng.h> +#include <botan/hash.h> +#include <botan/pkcs8.h> +#include <botan/x509_key.h> +#include <botan/pk_algs.h> + +#if defined(BOTAN_HAS_HASH_ID) + #include <botan/hash_id.h> +#endif + +extern "C" { + +int botan_privkey_create(botan_privkey_t* key_obj, + const char* algo_name, + const char* algo_params, + botan_rng_t rng_obj) + { + return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() { + if(key_obj == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + *key_obj = nullptr; + if(rng_obj == nullptr) + return BOTAN_FFI_ERROR_NULL_POINTER; + + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + std::unique_ptr<Botan::Private_Key> key( + Botan::create_private_key(algo_name ? algo_name : "RSA", + rng, + algo_params ? algo_params : "")); + + if(key) + { + *key_obj = new botan_privkey_struct(key.release()); + return BOTAN_FFI_SUCCESS; + } + else + { + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; + } + }); + } + +int botan_privkey_load(botan_privkey_t* key, botan_rng_t rng_obj, + const uint8_t bits[], size_t len, + const char* password) + { + *key = nullptr; + + if(password == nullptr) + password = ""; + + return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() { + Botan::DataSource_Memory src(bits, len); + + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + + std::unique_ptr<Botan::PKCS8_PrivateKey> pkcs8( + Botan::PKCS8::load_key(src, rng, static_cast<std::string>(password))); + + if(pkcs8) + { + *key = new botan_privkey_struct(pkcs8.release()); + return BOTAN_FFI_SUCCESS; + } + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + }); + } + +int botan_privkey_destroy(botan_privkey_t key) + { + return BOTAN_FFI_CHECKED_DELETE(key); + } + +int botan_pubkey_load(botan_pubkey_t* key, + const uint8_t bits[], size_t bits_len) + { + *key = nullptr; + + return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() { + Botan::DataSource_Memory src(bits, bits_len); + std::unique_ptr<Botan::Public_Key> pubkey(Botan::X509::load_key(src)); + + if(pubkey == nullptr) + return BOTAN_FFI_ERROR_UNKNOWN_ERROR; + + *key = new botan_pubkey_struct(pubkey.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pubkey_destroy(botan_pubkey_t key) + { + return BOTAN_FFI_CHECKED_DELETE(key); + } + +int botan_privkey_export_pubkey(botan_pubkey_t* pubout, botan_privkey_t key_obj) + { + return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() { + std::unique_ptr<Botan::Public_Key> + pubkey(Botan::X509::load_key(Botan::X509::BER_encode(safe_get(key_obj)))); + + *pubout = new botan_pubkey_struct(pubkey.release()); + return BOTAN_FFI_SUCCESS; + }); + } + +int botan_pubkey_algo_name(botan_pubkey_t key, char out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { return write_str_output(out, out_len, k.algo_name()); }); + } + +int botan_pubkey_check_key(botan_pubkey_t key, botan_rng_t rng, uint32_t flags) + { + const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS); + + return BOTAN_FFI_DO(Botan::Public_Key, key, k, + { return (k.check_key(safe_get(rng), strong) == true) ? 0 : -1; }); + } + +int botan_privkey_check_key(botan_privkey_t key, botan_rng_t rng, uint32_t flags) + { + const bool strong = (flags & BOTAN_CHECK_KEY_EXPENSIVE_TESTS); + return BOTAN_FFI_DO(Botan::Private_Key, key, k, + { return (k.check_key(safe_get(rng), strong) == true) ? 0 : -1; }); + } + +int botan_pubkey_export(botan_pubkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) + { + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + return write_vec_output(out, out_len, Botan::X509::BER_encode(k)); + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + return write_str_output(out, out_len, Botan::X509::PEM_encode(k)); + else + return BOTAN_FFI_ERROR_BAD_FLAG; + }); + } + +int botan_privkey_export(botan_privkey_t key, uint8_t out[], size_t* out_len, uint32_t flags) + { + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + return write_vec_output(out, out_len, Botan::PKCS8::BER_encode(k)); + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + return write_str_output(out, out_len, Botan::PKCS8::PEM_encode(k)); + else + return BOTAN_FFI_ERROR_BAD_FLAG; + }); + } + +int 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* /*ignored - pbe*/, + uint32_t flags) + { + return botan_privkey_export_encrypted_pbkdf_iter(key, out, out_len, rng_obj, pass, 100000, nullptr, nullptr, flags); + } + +int 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) + { + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + const std::chrono::milliseconds pbkdf_time(pbkdf_msec); + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + + const std::string cipher = (maybe_cipher ? maybe_cipher : ""); + const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : ""); + + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + { + return write_vec_output(out, out_len, + Botan::PKCS8::BER_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash)); + } + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + { + return write_str_output(out, out_len, + Botan::PKCS8::PEM_encode_encrypted_pbkdf_msec(k, rng, pass, pbkdf_time, pbkdf_iters_out, cipher, pbkdf_hash)); + } + else + { + return -2; + } + }); + } + +int 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) + { + return BOTAN_FFI_DO(Botan::Private_Key, key, k, { + Botan::RandomNumberGenerator& rng = safe_get(rng_obj); + + const std::string cipher = (maybe_cipher ? maybe_cipher : ""); + const std::string pbkdf_hash = (maybe_pbkdf_hash ? maybe_pbkdf_hash : ""); + + if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_DER) + { + return write_vec_output(out, out_len, + Botan::PKCS8::BER_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash)); + } + else if(flags == BOTAN_PRIVKEY_EXPORT_FLAG_PEM) + { + return write_str_output(out, out_len, + Botan::PKCS8::PEM_encode_encrypted_pbkdf_iter(k, rng, pass, pbkdf_iter, cipher, pbkdf_hash)); + } + else + { + return -2; + } + }); + } + +int botan_pubkey_estimated_strength(botan_pubkey_t key, size_t* estimate) + { + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { *estimate = k.estimated_strength(); }); + } + +int botan_pubkey_fingerprint(botan_pubkey_t key, const char* hash_fn, + uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::Public_Key, key, k, { + std::unique_ptr<Botan::HashFunction> h(Botan::HashFunction::create(hash_fn)); + return write_vec_output(out, out_len, h->process(k.public_key_bits())); + }); + } + +int botan_pkcs_hash_id(const char* hash_name, uint8_t pkcs_id[], size_t* pkcs_id_len) + { +#if defined(BOTAN_HAS_HASH_ID) + return ffi_guard_thunk(BOTAN_CURRENT_FUNCTION, [=]() { + const std::vector<uint8_t> hash_id = Botan::pkcs_hash_id(hash_name); + return write_output(pkcs_id, pkcs_id_len, hash_id.data(), hash_id.size()); + }); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif + } + +} |