diff options
-rw-r--r-- | CMakeLists.txt | 13 | ||||
-rw-r--r-- | lib/crypto.c | 138 |
2 files changed, 151 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 4564818..b6bcf62 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,7 @@ find_library(libuci NAMES uci) find_library(libubox NAMES ubox) find_library(libubus NAMES ubus) find_library(libblobmsg_json NAMES blobmsg_json) +find_library(libmbedtls NAMES mbedtls) find_package(ZLIB) if(LINUX) @@ -54,6 +55,10 @@ if(ZLIB_FOUND) set(DEFAULT_ZLIB_SUPPORT ON) endif() +if(libmbedtls) + set(DEFAULT_CRYPTO_SUPPORT ON) +endif() + option(DEBUG_SUPPORT "Debug plugin support" ON) option(FS_SUPPORT "Filesystem plugin support" ON) option(MATH_SUPPORT "Math plugin support" ON) @@ -67,6 +72,7 @@ option(ULOOP_SUPPORT "Uloop plugin support" ${DEFAULT_ULOOP_SUPPORT}) option(LOG_SUPPORT "Log plugin support" ON) option(SOCKET_SUPPORT "Socket plugin support" ON) option(ZLIB_SUPPORT "Zlib plugin support" ${DEFAULT_ZLIB_SUPPORT}) +option(CRYPTO_SUPPORT "Crypto Mbed-TLS plugin support" ${DEFAULT_CRYPTO_SUPPORT}) set(LIB_SEARCH_PATH "${CMAKE_INSTALL_PREFIX}/lib/ucode/*.so:${CMAKE_INSTALL_PREFIX}/share/ucode/*.uc:./*.so:./*.uc" CACHE STRING "Default library search path") string(REPLACE ":" "\", \"" LIB_SEARCH_DEFINE "${LIB_SEARCH_PATH}") @@ -290,6 +296,13 @@ if(ZLIB_SUPPORT) target_link_libraries(zlib_lib ZLIB::ZLIB) endif() +if(CRYPTO_SUPPORT) + set(LIBRARIES ${LIBRARIES} crypto_lib) + add_library(crypto_lib MODULE lib/crypto.c) + set_target_properties(crypto_lib PROPERTIES OUTPUT_NAME crypto PREFIX "") + target_link_options(crypto_lib PRIVATE ${UCODE_MODULE_LINK_OPTIONS}) +endif() + if(UNIT_TESTING) enable_testing() add_definitions(-DUNIT_TESTING) diff --git a/lib/crypto.c b/lib/crypto.c new file mode 100644 index 0000000..1cc9a99 --- /dev/null +++ b/lib/crypto.c @@ -0,0 +1,138 @@ +#include <stdint.h> +//#include <stdio.h> +//#include <unistd.h> +#include <errno.h> +#include <alloca.h> + +#include <ucode/module.h> + +#include <mbedtls/error.h> +#include <mbedtls/md.h> +#include <mbedtls/pk.h> + +#define TRUE ucv_boolean_new(true) +#define FALSE ucv_boolean_new(false) + +static uc_resource_type_t *pk_type; + +static uc_value_t * +md_digest(uc_vm_t *vm, size_t nargs) +{ + uc_value_t *alg = uc_fn_arg(0); + uc_value_t *input = uc_fn_arg(1); + + if (ucv_type(alg) != UC_STRING) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "alg not a string"); + + if (ucv_type(input) != UC_STRING) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "input not a string"); + + const mbedtls_md_info_t *info = mbedtls_md_info_from_string(ucv_string_get(alg)); + + if (!info) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "unknown MD algorithm"); + + unsigned char size = mbedtls_md_get_size(info); + char *output = alloca(size); + + if (mbedtls_md(info, (const unsigned char*)ucv_string_get(input), ucv_string_length(input), (unsigned char*)output)) + uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "bad input data"); + + uc_value_t *rv = ucv_string_new_length(output, size); + return rv; +} + +static uc_value_t * +pk_init(uc_vm_t *vm, size_t nargs) +{ + mbedtls_pk_context *ctx = malloc(sizeof(mbedtls_pk_context)); + + mbedtls_pk_init(ctx); + return uc_resource_new(pk_type, ctx); +} + +static void +pk_free(void *ptr) +{ + mbedtls_pk_context *ctx = ptr; + + mbedtls_pk_free(ctx); + free(ctx); +} + +static uc_value_t * +pk_set_public_key(uc_vm_t *vm, size_t nargs) +{ + mbedtls_pk_context *ctx = uc_fn_thisval("mbedtls.pk"); + + if (!ctx) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "invalid mbedtls.pk object"); + + uc_value_t *key = uc_fn_arg(0); + + if (ucv_type(key) != UC_STRING) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "key is not a string"); + + int err = mbedtls_pk_parse_public_key(ctx, (const unsigned char*)ucv_string_get(key), ucv_string_length(key)); + if (err) + uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "not a valid PEM/DER key %s: %s", + mbedtls_high_level_strerr(err), + mbedtls_low_level_strerr(err)); + return NULL; +} + +static uc_value_t * +pk_verify(uc_vm_t *vm, size_t nargs) +{ + mbedtls_pk_context *ctx = uc_fn_thisval("mbedtls.pk"); + + if (!ctx) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "invalid mbedtls.pk object"); + + uc_value_t *md_alg = uc_fn_arg(0); + uc_value_t *hash = uc_fn_arg(1); + uc_value_t *sig = uc_fn_arg(2); + + if (ucv_type(md_alg) != UC_STRING) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "md_alg is not a string"); + + if (ucv_type(hash) != UC_STRING) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "hash is not a string"); + + if (ucv_type(sig) != UC_STRING) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "sig is not a string"); + + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_string(ucv_string_get(md_alg)); + + if (!md_info) + uc_vm_raise_exception(vm, EXCEPTION_TYPE, "unknown MD algorithm"); + + const mbedtls_md_type_t md_type = mbedtls_md_get_type(md_info); + + int err = mbedtls_pk_verify(ctx, md_type, + (const unsigned char*)ucv_string_get(hash), ucv_string_length(hash), + (const unsigned char*)ucv_string_get(sig), ucv_string_length(sig)); + if (err) + uc_vm_raise_exception(vm, EXCEPTION_RUNTIME, "validation failed: %s: %s", + mbedtls_high_level_strerr(err), + mbedtls_low_level_strerr(err)); + + return TRUE; +} + +static const uc_function_list_t global_fns[] = { + { "md_digest", md_digest }, + { "pk", pk_init }, +}; + +static const uc_function_list_t pk_fns[] = { + { "set_public_key", pk_set_public_key }, + { "verify", pk_verify }, +}; + +void uc_module_init(uc_vm_t *vm, uc_value_t *scope) +{ + uc_function_list_register(scope, global_fns); + + pk_type = uc_type_declare(vm, "mbedtls.pk", pk_fns, pk_free); +} |