Pull signing out to its own module
This commit is contained in:
parent
4eaef57a76
commit
f5b8a8eb3b
@ -39,6 +39,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||
resource rather than on the Erlang side. This avoids some checks in the code,
|
||||
and streamlines a good deal of the interface.
|
||||
- Split AEAD routines off from the main enacl_nif.c file
|
||||
- Renamed many routines from enif_* to enacl_*. This better reflects where they live
|
||||
in the code base, and avoids pollution of the enif_* "namespace".
|
||||
- Split Sign Public Key routines from the rest. Modernize the handling of contexts.
|
||||
|
||||
### Fixes
|
||||
- Fix a resource leak in generichash/sign init/update/final.
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "enacl.h"
|
||||
#include "generichash.h"
|
||||
#include "hash.h"
|
||||
#include "sign.h"
|
||||
|
||||
#define CRYPTO_SIGN_STATE_RESOURCE "crypto_sign_state"
|
||||
|
||||
@ -18,13 +19,6 @@
|
||||
{ a, b, c }
|
||||
#endif
|
||||
|
||||
//{"crypto_box_keypair", 0, enif_crypto_box_keypair,
|
||||
// ERL_NIF_DIRTY_JOB_CPU_BOUND}
|
||||
/* Errors */
|
||||
|
||||
/* These are global variables for resource types */
|
||||
static ErlNifResourceType *sign_state_type = NULL;
|
||||
|
||||
/* Initialization */
|
||||
static int enif_crypto_load(ErlNifEnv *env, void **priv_data,
|
||||
ERL_NIF_TERM load_info) {
|
||||
@ -32,10 +26,8 @@ static int enif_crypto_load(ErlNifEnv *env, void **priv_data,
|
||||
if (!enacl_init_generic_hash_ctx(env)) {
|
||||
return -1;
|
||||
}
|
||||
// Create a new resource type for crypto_sign_state
|
||||
if (!(sign_state_type =
|
||||
enif_open_resource_type(env, NULL, CRYPTO_SIGN_STATE_RESOURCE, NULL,
|
||||
ERL_NIF_RT_CREATE, NULL))) {
|
||||
|
||||
if (!enacl_init_sign_ctx(env)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -639,139 +631,6 @@ enif_crypto_sign_verify_detached(ErlNifEnv *env, int argc,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_init(crypto_sign_state *state)
|
||||
*/
|
||||
|
||||
static ERL_NIF_TERM enif_crypto_sign_init(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]) {
|
||||
if ((argc != 0)) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
void *state = enif_alloc_resource(sign_state_type, crypto_sign_statebytes());
|
||||
|
||||
if (!state) {
|
||||
return nacl_error_tuple(env, "alloc_failed");
|
||||
}
|
||||
|
||||
if (0 != crypto_sign_init(state)) {
|
||||
enif_release_resource(state);
|
||||
return nacl_error_tuple(env, "sign_init_error");
|
||||
}
|
||||
|
||||
// Create return values
|
||||
ERL_NIF_TERM e1 = enif_make_atom(env, "signstate");
|
||||
ERL_NIF_TERM e2 = enif_make_resource(env, state);
|
||||
|
||||
// release dynamically allocated memory to erlang to mange
|
||||
enif_release_resource(state);
|
||||
|
||||
// return a tuple
|
||||
return enif_make_tuple2(env, e1, e2);
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_update(crypto_sign_state *state,
|
||||
const unsigned char *m,
|
||||
unsigned long long mlen);
|
||||
*/
|
||||
|
||||
static ERL_NIF_TERM enif_crypto_sign_update(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]) {
|
||||
ErlNifBinary data;
|
||||
|
||||
void *state;
|
||||
|
||||
// Validate the arguments
|
||||
if ((argc != 2) ||
|
||||
(!enif_get_resource(env, argv[0], sign_state_type, (void **)&state)) ||
|
||||
(!enif_inspect_binary(env, argv[1], &data))) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if (0 != crypto_sign_update(state, data.data, data.size)) {
|
||||
return nacl_error_tuple(env, "sign_update_error");
|
||||
}
|
||||
|
||||
// Generate return value
|
||||
ERL_NIF_TERM e1 = enif_make_atom(env, "signstate");
|
||||
ERL_NIF_TERM e2 = enif_make_resource(env, state);
|
||||
|
||||
// return a tuple
|
||||
return enif_make_tuple2(env, e1, e2);
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_final_create(crypto_sign_state *state,
|
||||
unsigned char *sig,
|
||||
unsigned long long *siglen_p,
|
||||
const unsigned char *sk);
|
||||
*/
|
||||
|
||||
static ERL_NIF_TERM enif_crypto_sign_final_create(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]) {
|
||||
ErlNifBinary sk, sig;
|
||||
|
||||
void *state;
|
||||
|
||||
unsigned long long siglen;
|
||||
|
||||
if ((argc != 2) ||
|
||||
(!enif_get_resource(env, argv[0], sign_state_type, (void **)&state)) ||
|
||||
(!enif_inspect_binary(env, argv[1], &sk))) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if (sk.size != crypto_sign_SECRETKEYBYTES) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if (!enif_alloc_binary(crypto_sign_BYTES, &sig)) {
|
||||
return nacl_error_tuple(env, "alloc_failed");
|
||||
}
|
||||
|
||||
if (0 != crypto_sign_final_create(state, sig.data, &siglen, sk.data)) {
|
||||
enif_release_binary(&sig);
|
||||
return nacl_error_tuple(env, "sign_error");
|
||||
}
|
||||
|
||||
ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
|
||||
ERL_NIF_TERM ret = enif_make_binary(env, &sig);
|
||||
|
||||
return enif_make_tuple2(env, ok, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_final_verify(crypto_sign_state *state,
|
||||
unsigned char *sig,
|
||||
const unsigned char *pk);
|
||||
*/
|
||||
|
||||
static ERL_NIF_TERM enif_crypto_sign_final_verify(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]) {
|
||||
ErlNifBinary pk, sig;
|
||||
|
||||
void *state;
|
||||
|
||||
if ((argc != 3) ||
|
||||
(!enif_get_resource(env, argv[0], sign_state_type, (void **)&state)) ||
|
||||
(!enif_inspect_binary(env, argv[1], &sig)) ||
|
||||
(!enif_inspect_binary(env, argv[2], &pk))) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if (pk.size != crypto_sign_PUBLICKEYBYTES) {
|
||||
return enif_make_badarg(env);
|
||||
}
|
||||
|
||||
if (0 == crypto_sign_final_verify(state, sig.data, pk.data)) {
|
||||
return enif_make_atom(env, ATOM_OK);
|
||||
}
|
||||
|
||||
return nacl_error_tuple(env, "failed_verification");
|
||||
}
|
||||
|
||||
/* Sealed box functions */
|
||||
|
||||
static ERL_NIF_TERM enif_crypto_box_SEALBYTES(ErlNifEnv *env, int argc,
|
||||
@ -1584,12 +1443,12 @@ static ErlNifFunc nif_funcs[] = {
|
||||
enif_crypto_sign_detached),
|
||||
erl_nif_dirty_job_cpu_bound_macro("crypto_sign_verify_detached", 3,
|
||||
enif_crypto_sign_verify_detached),
|
||||
{"crypto_sign_init", 0, enif_crypto_sign_init},
|
||||
{"crypto_sign_update", 2, enif_crypto_sign_update},
|
||||
{"crypto_sign_init", 0, enacl_crypto_sign_init},
|
||||
{"crypto_sign_update", 2, enacl_crypto_sign_update},
|
||||
erl_nif_dirty_job_cpu_bound_macro("crypto_sign_final_create", 2,
|
||||
enif_crypto_sign_final_create),
|
||||
enacl_crypto_sign_final_create),
|
||||
erl_nif_dirty_job_cpu_bound_macro("crypto_sign_final_verify", 3,
|
||||
enif_crypto_sign_final_verify),
|
||||
enacl_crypto_sign_final_verify),
|
||||
|
||||
{"crypto_sign_ed25519_sk_to_pk", 1, enif_crypto_sign_ed25519_sk_to_pk},
|
||||
|
||||
|
216
c_src/sign.c
Normal file
216
c_src/sign.c
Normal file
@ -0,0 +1,216 @@
|
||||
#include "erl_nif.h"
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
#include "enacl.h"
|
||||
#include "sign.h"
|
||||
|
||||
typedef struct enacl_sign_ctx {
|
||||
crypto_sign_state *state; // The underlying signature state
|
||||
int alive; // Is the context still valid for updates/finalization
|
||||
} enacl_sign_ctx;
|
||||
|
||||
static ErlNifResourceType *enacl_sign_ctx_rtype = NULL;
|
||||
|
||||
static void enacl_sign_ctx_dtor(ErlNifEnv *env, enacl_sign_ctx *);
|
||||
|
||||
int enacl_init_sign_ctx(ErlNifEnv *env) {
|
||||
enacl_sign_ctx_rtype =
|
||||
enif_open_resource_type(env, NULL, "enacl_sign_context",
|
||||
(ErlNifResourceDtor *)enacl_sign_ctx_dtor,
|
||||
ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);
|
||||
|
||||
if (enacl_sign_ctx_rtype == NULL)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void enacl_sign_ctx_dtor(ErlNifEnv *env, enacl_sign_ctx *obj) {
|
||||
if (!obj->alive)
|
||||
return;
|
||||
|
||||
if (obj->state) {
|
||||
sodium_memzero(obj->state, crypto_sign_statebytes());
|
||||
enif_free(obj->state);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_init(crypto_sign_state *state)
|
||||
*/
|
||||
|
||||
ERL_NIF_TERM enacl_crypto_sign_init(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]) {
|
||||
ERL_NIF_TERM ret;
|
||||
enacl_sign_ctx *obj = NULL;
|
||||
|
||||
if (argc != 0)
|
||||
goto bad_arg;
|
||||
|
||||
if ((obj = enif_alloc_resource(enacl_sign_ctx_rtype,
|
||||
sizeof(enacl_sign_ctx))) == NULL) {
|
||||
ret = nacl_error_tuple(env, "alloc_failed");
|
||||
goto done;
|
||||
}
|
||||
obj->alive = 0;
|
||||
obj->state = enif_alloc(crypto_sign_statebytes());
|
||||
if (obj->state == NULL) {
|
||||
ret = nacl_error_tuple(env, "state_malloc");
|
||||
goto release;
|
||||
}
|
||||
obj->alive = 1;
|
||||
|
||||
if (0 != crypto_sign_init(obj->state)) {
|
||||
ret = nacl_error_tuple(env, "sign_init_error");
|
||||
goto free;
|
||||
}
|
||||
|
||||
// Create return values
|
||||
ret = enif_make_resource(env, obj);
|
||||
|
||||
goto release;
|
||||
|
||||
bad_arg:
|
||||
return enif_make_badarg(env);
|
||||
free:
|
||||
if (obj->alive)
|
||||
if (obj->state != NULL) {
|
||||
sodium_memzero(obj->state, crypto_sign_statebytes());
|
||||
enif_free(obj->state);
|
||||
obj->state = NULL;
|
||||
}
|
||||
release:
|
||||
enif_release_resource(obj);
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
int crypto_sign_update(crypto_sign_state *state,
|
||||
const unsigned char *m,
|
||||
unsigned long long mlen);
|
||||
*/
|
||||
|
||||
ERL_NIF_TERM enacl_crypto_sign_update(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]) {
|
||||
ERL_NIF_TERM ret;
|
||||
enacl_sign_ctx *obj = NULL;
|
||||
ErlNifBinary data;
|
||||
|
||||
// Validate the arguments
|
||||
if (argc != 2)
|
||||
goto bad_arg;
|
||||
|
||||
if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
|
||||
goto bad_arg;
|
||||
|
||||
if (!enif_inspect_binary(env, argv[1], &data))
|
||||
goto bad_arg;
|
||||
|
||||
if (!obj->alive) {
|
||||
ret = nacl_error_tuple(env, "finalized");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 != crypto_sign_update(obj->state, data.data, data.size)) {
|
||||
ret = nacl_error_tuple(env, "sign_update_error");
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = argv[0];
|
||||
goto done;
|
||||
|
||||
bad_arg:
|
||||
return enif_make_badarg(env);
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
ERL_NIF_TERM enacl_crypto_sign_final_create(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]) {
|
||||
ERL_NIF_TERM ret;
|
||||
enacl_sign_ctx *obj = NULL;
|
||||
ErlNifBinary sk, sig;
|
||||
unsigned long long siglen;
|
||||
|
||||
if (argc != 2)
|
||||
goto bad_arg;
|
||||
if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
|
||||
goto bad_arg;
|
||||
if (!enif_inspect_binary(env, argv[1], &sk))
|
||||
goto bad_arg;
|
||||
if (sk.size != crypto_sign_SECRETKEYBYTES)
|
||||
goto bad_arg;
|
||||
|
||||
if (!obj->alive) {
|
||||
ret = nacl_error_tuple(env, "finalized");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!enif_alloc_binary(crypto_sign_BYTES, &sig)) {
|
||||
ret = nacl_error_tuple(env, "alloc_failed");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (0 != crypto_sign_final_create(obj->state, sig.data, &siglen, sk.data)) {
|
||||
ret = nacl_error_tuple(env, "sign_error");
|
||||
goto release;
|
||||
}
|
||||
|
||||
ERL_NIF_TERM ok = enif_make_atom(env, ATOM_OK);
|
||||
ERL_NIF_TERM signature = enif_make_binary(env, &sig);
|
||||
|
||||
ret = enif_make_tuple2(env, ok, signature);
|
||||
goto cleanup;
|
||||
bad_arg:
|
||||
return enif_make_badarg(env);
|
||||
release:
|
||||
enif_release_binary(&sig);
|
||||
cleanup:
|
||||
obj->alive = 0;
|
||||
sodium_memzero(obj->state, crypto_sign_statebytes());
|
||||
enif_free(obj->state);
|
||||
obj->state = NULL;
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
ERL_NIF_TERM enacl_crypto_sign_final_verify(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]) {
|
||||
ErlNifBinary pk, sig;
|
||||
enacl_sign_ctx *obj = NULL;
|
||||
ERL_NIF_TERM ret;
|
||||
|
||||
if (argc != 3)
|
||||
goto bad_arg;
|
||||
if (!enif_get_resource(env, argv[0], enacl_sign_ctx_rtype, (void **)&obj))
|
||||
goto bad_arg;
|
||||
if (!enif_inspect_binary(env, argv[1], &sig))
|
||||
goto bad_arg;
|
||||
if (!enif_inspect_binary(env, argv[2], &pk))
|
||||
goto bad_arg;
|
||||
if (pk.size != crypto_sign_PUBLICKEYBYTES)
|
||||
goto bad_arg;
|
||||
|
||||
if (0 == crypto_sign_final_verify(obj->state, sig.data, pk.data)) {
|
||||
ret = enif_make_atom(env, ATOM_OK);
|
||||
} else {
|
||||
ret = nacl_error_tuple(env, "failed_verification");
|
||||
}
|
||||
// Mark as done
|
||||
goto cleanup;
|
||||
|
||||
bad_arg:
|
||||
return enif_make_badarg(env);
|
||||
cleanup:
|
||||
// Get rid of the context and mark it as dead
|
||||
obj->alive = 0;
|
||||
sodium_memzero(obj->state, crypto_sign_statebytes());
|
||||
enif_free(obj->state);
|
||||
obj->state = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
19
c_src/sign.h
Normal file
19
c_src/sign.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef ENACL_SIGN_H
|
||||
#define ENACL_SIGN_H
|
||||
|
||||
#include "erl_nif.h"
|
||||
|
||||
int enacl_init_sign_ctx(ErlNifEnv *env);
|
||||
|
||||
ERL_NIF_TERM enacl_crypto_sign_init(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]);
|
||||
|
||||
ERL_NIF_TERM enacl_crypto_sign_update(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]);
|
||||
|
||||
ERL_NIF_TERM enacl_crypto_sign_final_create(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]);
|
||||
|
||||
ERL_NIF_TERM enacl_crypto_sign_final_verify(ErlNifEnv *env, int argc,
|
||||
ERL_NIF_TERM const argv[]);
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user