diff options
author | Jack Lloyd <[email protected]> | 2015-10-01 16:59:47 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2015-10-01 16:59:47 -0400 |
commit | 7bbee7e62e65d5de1d46b912b73440070feab0ff (patch) | |
tree | ce97557bce9c5e03c2700c0eaed97efcb4d5b319 /src/lib/ffi | |
parent | 43348030a0f059f43388086279dd54ac3bcfd565 (diff) |
Export X.509 certificates to ffi and python
Missing path validation, probably other things
Diffstat (limited to 'src/lib/ffi')
-rw-r--r-- | src/lib/ffi/ffi.cpp | 155 | ||||
-rw-r--r-- | src/lib/ffi/ffi.h | 125 | ||||
-rw-r--r-- | src/lib/ffi/info.txt | 1 |
3 files changed, 266 insertions, 15 deletions
diff --git a/src/lib/ffi/ffi.cpp b/src/lib/ffi/ffi.cpp index 606415575..608bd291b 100644 --- a/src/lib/ffi/ffi.cpp +++ b/src/lib/ffi/ffi.cpp @@ -13,6 +13,8 @@ #include <botan/pbkdf.h> #include <botan/version.h> #include <botan/pkcs8.h> +#include <botan/x509cert.h> +#include <botan/data_src.h> #include <botan/pubkey.h> #include <botan/data_src.h> #include <botan/hex.h> @@ -161,12 +163,14 @@ BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_sign_struct, Botan::PK_Signer, 0x1AF0C39F); BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_verify_struct, Botan::PK_Verifier, 0x2B91F936); BOTAN_FFI_DECLARE_STRUCT(botan_pk_op_ka_struct, Botan::PK_Key_Agreement, 0x2939CAB1); +BOTAN_FFI_DECLARE_STRUCT(botan_x509_cert_struct, Botan::X509_Certificate, 0x8F628937); + /* * Versioning */ uint32_t botan_ffi_api_version() { - return 20150210; // should match value in info.txt + return BOTAN_HAS_FFI; } const char* botan_version_string() @@ -636,7 +640,6 @@ int botan_kdf(const char* kdf_algo, return -1; } -#if defined(BOTAN_HAS_BCRYPT) int botan_bcrypt_generate(uint8_t* out, size_t* out_len, const char* pass, botan_rng_t rng_obj, size_t wf, @@ -654,9 +657,13 @@ int botan_bcrypt_generate(uint8_t* out, size_t* out_len, if(wf < 2 || wf > 30) throw std::runtime_error("Bad bcrypt work factor " + std::to_string(wf)); +#if defined(BOTAN_HAS_BCRYPT) Botan::RandomNumberGenerator& rng = safe_get(rng_obj); const std::string bcrypt = Botan::generate_bcrypt(pass, rng, wf); return write_str_output(out, out_len, bcrypt); +#else + return BOTAN_FFI_ERROR_NOT_IMPLEMENTED; +#endif } catch(std::exception& e) { @@ -674,6 +681,7 @@ int botan_bcrypt_is_valid(const char* pass, const char* hash) { try { + #define BOTAN_ if(Botan::check_bcrypt(pass, hash)) return 0; // success return 1; @@ -690,8 +698,6 @@ int botan_bcrypt_is_valid(const char* pass, const char* hash) return BOTAN_FFI_ERROR_EXCEPTION_THROWN; } -#endif - int botan_privkey_create_rsa(botan_privkey_t* key_obj, botan_rng_t rng_obj, size_t n_bits) { try @@ -1137,5 +1143,146 @@ int botan_pk_op_key_agreement(botan_pk_op_ka_t op, }); } +int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* cert_path) + { + try + { + if(!cert_obj || !cert_path) + return -1; + + std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(cert_path)); + + if(c) + { + *cert_obj = new botan_x509_cert_struct(c.release()); + return 0; + } + } + catch(std::exception& e) + { + log_exception(BOTAN_CURRENT_FUNCTION, e.what()); + } + catch(...) + { + log_exception(BOTAN_CURRENT_FUNCTION, "unknown"); + } + + return -2; + } + +int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert_bits[], size_t cert_bits_len) + { + try + { + if(!cert_obj || !cert_bits) + return -1; + + Botan::DataSource_Memory bits(cert_bits, cert_bits_len); + + std::unique_ptr<Botan::X509_Certificate> c(new Botan::X509_Certificate(bits)); + + if(c) + { + *cert_obj = new botan_x509_cert_struct(c.release()); + return 0; + } + } + catch(std::exception& e) + { + log_exception(BOTAN_CURRENT_FUNCTION, e.what()); + } + catch(...) + { + log_exception(BOTAN_CURRENT_FUNCTION, "unknown"); + } + + return -2; + + } + +int botan_x509_cert_destroy(botan_x509_cert_t cert) + { + delete cert; + return 0; + } + +int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_str_output(out, out_len, cert.start_time()); }); + } + +int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_str_output(out, out_len, cert.end_time()); }); + } + +int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_vec_output(out, out_len, cert.serial_number()); }); + } + +int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_str_output(out, out_len, cert.fingerprint(hash)); }); + } + +int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_vec_output(out, out_len, cert.authority_key_id()); }); + } + +int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_vec_output(out, out_len, cert.subject_key_id()); }); + } + +int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_vec_output(out, out_len, cert.subject_public_key_bits()); }); + } + + +/* +int botan_x509_cert_path_verify(botan_x509_cert_t cert, const char* dir) +{ +} +*/ + +int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key) + { + *key = nullptr; + return -1; + //return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_vec_output(out, out_len, cert.subject_public_key_bits()); }); + } + +int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert, + const char* key, size_t index, + uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_str_output(out, out_len, cert.issuer_info(key).at(index)); }); + } + +int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert, + const char* key, size_t index, + uint8_t out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_str_output(out, out_len, cert.subject_info(key).at(index)); }); + } + +int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { return write_str_output(out, out_len, cert.to_string()); }); + } + +int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage) + { + return BOTAN_FFI_DO(Botan::X509_Certificate, cert, { + const Botan::Key_Constraints k = static_cast<Botan::Key_Constraints>(key_usage); + if(cert.allowed_usage(k)) + return 0; + return 1; + }); + } + } diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h index a516529b4..1402ec129 100644 --- a/src/lib/ffi/ffi.h +++ b/src/lib/ffi/ffi.h @@ -1,4 +1,5 @@ /* +* FFI (C89 API) * (C) 2015 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) @@ -11,19 +12,46 @@ extern "C" { #endif -#include <botan/build.h> -#include <stdint.h> -#include <stddef.h> - /* +This header exports some of botan's functionality via a C89 interface. The API +is intended to be as easy as possible to call from other languages, which often +have easy ways to call C, because C. But some C code is easier to deal with than +others, so to make things easy this API follows a few simple rules: + +- All interactions are via pointers to opaque structs. No need to worry about + structure padding issues and the like. + +- All functions return an int error code (except the version calls, which are + assumed to always have something to say). + +- No ownership of memory transfers across the API boundary. The API will write + to buffers provided by the caller, or return opaque pointers which may not be + dereferenced. + +- If exporting a value (a string or a blob) the function takes a pointer to the + output array and a read/write pointer to the length. If it is insufficient, an + error is returned. So passing nullptr/0 + +This API is uesd by the Python and OCaml bindings via those languages respective +ctypes libraries. + +The API is not currently documented, nor should it be considered stable. It is +buggy as heck, most likely. However the goal is to provide a long term API +usable for language bindings, or for use by systems written in C. Suggestions on +how to provide the cleanest API for such users would be most welcome. + * TODO: * - Better error reporting -* - User callback for exception logging +* - User callback for exception logging? * - Doxygen comments for all functions/params * - X.509 certs and PKIX path validation goo * - TLS */ +#include <botan/build.h> +#include <stdint.h> +#include <stddef.h> + /* * Versioning */ @@ -37,11 +65,30 @@ BOTAN_DLL uint32_t botan_version_datestamp(); /* * Error handling +* +* Some way of exporting these values to other languages would be useful + + THIS FUNCTION ASSUMES BOTH ARGUMENTS ARE LITERAL STRINGS + so it retains only the pointers and does not make a copy. + +int botan_make_error(const char* msg, const char* func, int line); +* This value is returned to callers ^^ + + normally called like + return botan_make_error(BOTAN_ERROR_STRING_NOT_IMPLEMENTED, BOTAN_FUNCTION, __LINE__); + +#define botan_make_error_inf(s) return botan_make_error(s, BOTAN_FUNCTION, __LINE__); + +* +* Later call: +* const char* botan_get_error_str(int); +* To recover the msg, func, and line + */ #define BOTAN_FFI_ERROR_EXCEPTION_THROWN (-20) #define BOTAN_FFI_ERROR_BAD_FLAG (-30) #define BOTAN_FFI_ERROR_NULL_POINTER (-31) -#define BOTAN_FFI_ERROR_NULL_POINTER (-31) +#define BOTAN_FFI_ERROR_NOT_IMPLEMENTED (-40) //const char* botan_error_description(int err); @@ -53,6 +100,9 @@ BOTAN_DLL int botan_same_mem(const uint8_t* x, const uint8_t* y, size_t len); #define BOTAN_FFI_HEX_LOWER_CASE 1 BOTAN_DLL int botan_hex_encode(const uint8_t* x, size_t len, char* out, uint32_t flags); +// TODO: botan_hex_decode +// TODO: botan_base64_encode +// TODO: botan_base64_decode /* * RNG @@ -198,8 +248,6 @@ BOTAN_DLL int botan_kdf(const char* kdf_algo, /* * Bcrypt */ -#if defined(BOTAN_HAS_BCRYPT) - BOTAN_DLL int botan_bcrypt_generate(uint8_t* out, size_t* out_len, const char* pass, botan_rng_t rng, @@ -213,8 +261,6 @@ BOTAN_DLL int botan_bcrypt_generate(uint8_t* out, size_t* out_len, */ BOTAN_DLL int botan_bcrypt_is_valid(const char* pass, const char* hash); -#endif - /* * Public/private key creation, import, ... */ @@ -359,6 +405,63 @@ BOTAN_DLL int botan_pk_op_key_agreement(botan_pk_op_ka_t op, const uint8_t other_key[], size_t other_key_len, const uint8_t salt[], size_t salt_len); + +typedef struct botan_x509_cert_struct* botan_x509_cert_t; +BOTAN_DLL int botan_x509_cert_load(botan_x509_cert_t* cert_obj, const uint8_t cert[], size_t cert_len); +BOTAN_DLL int botan_x509_cert_load_file(botan_x509_cert_t* cert_obj, const char* filename); +BOTAN_DLL int botan_x509_cert_destroy(botan_x509_cert_t cert); + +BOTAN_DLL int botan_x509_cert_gen_selfsigned(botan_x509_cert_t* cert, + botan_privkey_t key, + botan_rng_t rng, + const char* common_name, + const char* org_name); + +// TODO: return botan_time_struct instead +BOTAN_DLL int botan_x509_cert_get_time_starts(botan_x509_cert_t cert, char out[], size_t* out_len); +BOTAN_DLL int botan_x509_cert_get_time_expires(botan_x509_cert_t cert, char out[], size_t* out_len); + +BOTAN_DLL int botan_x509_cert_get_fingerprint(botan_x509_cert_t cert, const char* hash, uint8_t out[], size_t* out_len); + +BOTAN_DLL int botan_x509_cert_get_serial_number(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); +BOTAN_DLL int botan_x509_cert_get_authority_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); +BOTAN_DLL int botan_x509_cert_get_subject_key_id(botan_x509_cert_t cert, uint8_t out[], size_t* out_len); + +BOTAN_DLL int botan_x509_cert_path_verify(botan_x509_cert_t cert, + const char* ca_dir); + +BOTAN_DLL int botan_x509_cert_get_public_key_bits(botan_x509_cert_t cert, + uint8_t out[], size_t* out_len); + +BOTAN_DLL int botan_x509_cert_get_public_key(botan_x509_cert_t cert, botan_pubkey_t* key); + +BOTAN_DLL int botan_x509_cert_get_issuer_dn(botan_x509_cert_t cert, + const char* key, size_t index, + uint8_t out[], size_t* out_len); + + +BOTAN_DLL int botan_x509_cert_get_subject_dn(botan_x509_cert_t cert, + const char* key, size_t index, + uint8_t out[], size_t* out_len); + +BOTAN_DLL int botan_x509_cert_to_string(botan_x509_cert_t cert, char out[], size_t* out_len); + +// Must match values of Key_Constraints in key_constraints.h +enum botan_x509_cert_key_constraints { + NO_CONSTRAINTS = 0, + DIGITAL_SIGNATURE = 32768, + NON_REPUDIATION = 16384, + KEY_ENCIPHERMENT = 8192, + DATA_ENCIPHERMENT = 4096, + KEY_AGREEMENT = 2048, + KEY_CERT_SIGN = 1024, + CRL_SIGN = 512, + ENCIPHER_ONLY = 256, + DECIPHER_ONLY = 128 +}; + +BOTAN_DLL int botan_x509_cert_allowed_usage(botan_x509_cert_t cert, unsigned int key_usage); + /* * TLS (WIP) */ @@ -368,6 +471,7 @@ typedef struct botan_tls_session_struct* botan_tls_session_t; BOTAN_DLL int botan_tls_session_get_version(botan_tls_session_t* session, uint16_t* tls_version); BOTAN_DLL int botan_tls_session_get_ciphersuite(botan_tls_session_t* session, uint16_t* ciphersuite); +BOTAN_DLL int botan_tls_session // TODO: peer certs, validation, ... typedef struct botan_tls_channel_struct* botan_tls_channel_t; @@ -401,7 +505,6 @@ BOTAN_DLL int botan_tls_channel_close(botan_tls_channel_t chan); BOTAN_DLL int botan_tls_channel_destroy(botan_tls_channel_t chan); #endif - #ifdef __cplusplus } #endif diff --git a/src/lib/ffi/info.txt b/src/lib/ffi/info.txt index 94a804ba0..52885e8e1 100644 --- a/src/lib/ffi/info.txt +++ b/src/lib/ffi/info.txt @@ -6,6 +6,7 @@ filters kdf pbkdf pubkey +x509 auto_rng system_rng </requires> |