aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/ffi
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2015-10-01 16:59:47 -0400
committerJack Lloyd <[email protected]>2015-10-01 16:59:47 -0400
commit7bbee7e62e65d5de1d46b912b73440070feab0ff (patch)
treece97557bce9c5e03c2700c0eaed97efcb4d5b319 /src/lib/ffi
parent43348030a0f059f43388086279dd54ac3bcfd565 (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.cpp155
-rw-r--r--src/lib/ffi/ffi.h125
-rw-r--r--src/lib/ffi/info.txt1
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>