diff options
Diffstat (limited to 'lib/crypto.c')
-rw-r--r-- | lib/crypto.c | 138 |
1 files changed, 138 insertions, 0 deletions
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); +} |