Format; release resources

In the push path, release resources
in a stack fashion. This avoids releasing
a binary incorrectly.
This commit is contained in:
Jesper Louis Andersen 2020-03-07 12:01:27 +01:00
parent 67fe9c7863
commit 8361450745

View File

@ -1,25 +1,26 @@
#include <sodium.h>
#include <erl_nif.h>
#include <sodium.h>
#include "enacl.h"
#include "secretstream.h"
typedef struct enacl_secretstream_ctx {
ErlNifMutex *mtx;
crypto_secretstream_xchacha20poly1305_state *state; // The underlying secretstream state
int alive; // Is the context still valid for updates/finalization
crypto_secretstream_xchacha20poly1305_state
*state; // The underlying secretstream state
int alive; // Is the context still valid for updates/finalization
} enacl_secretstream_ctx;
ErlNifResourceType *enacl_secretstream_ctx_rtype = NULL;
static void enacl_secretstream_ctx_dtor(ErlNifEnv *env,
enacl_secretstream_ctx *);
enacl_secretstream_ctx *);
int enacl_init_secretstream_ctx(ErlNifEnv *env) {
enacl_secretstream_ctx_rtype =
enif_open_resource_type(env, NULL, "enacl_secretstream_context",
(ErlNifResourceDtor *)enacl_secretstream_ctx_dtor,
ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);
enif_open_resource_type(env, NULL, "enacl_secretstream_context",
(ErlNifResourceDtor *)enacl_secretstream_ctx_dtor,
ERL_NIF_RT_CREATE | ERL_NIF_RT_TAKEOVER, NULL);
if (enacl_secretstream_ctx_rtype == NULL)
return 0;
@ -34,8 +35,9 @@ static void enacl_secretstream_ctx_dtor(ErlNifEnv *env,
}
if (obj->state)
sodium_memzero(obj->state, crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
if (obj->mtx != NULL)
enif_mutex_destroy(obj->mtx);
@ -47,62 +49,57 @@ static void enacl_secretstream_ctx_dtor(ErlNifEnv *env,
* Secretstream
*/
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_ABYTES(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_ABYTES(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_ABYTES);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_HEADERBYTES(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_HEADERBYTES);
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env,
crypto_secretstream_xchacha20poly1305_HEADERBYTES);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_KEYBYTES(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_KEYBYTES);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX);
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(
env, crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_MESSAGE(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_TAG_MESSAGE);
return enif_make_int64(env,
crypto_secretstream_xchacha20poly1305_TAG_MESSAGE);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_PUSH(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_TAG_PUSH);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_REKEY(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_TAG_REKEY);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_TAG_FINAL(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
return enif_make_int64(env, crypto_secretstream_xchacha20poly1305_TAG_FINAL);
}
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_keygen(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_keygen(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ErlNifBinary key;
@ -110,8 +107,9 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_keygen(
return enif_make_badarg(env);
}
if (!enif_alloc_binary(crypto_secretstream_xchacha20poly1305_KEYBYTES, &key)) {
return enacl_internal_error(env);
if (!enif_alloc_binary(crypto_secretstream_xchacha20poly1305_KEYBYTES,
&key)) {
return enacl_internal_error(env);
}
crypto_secretstream_xchacha20poly1305_keygen(key.data);
@ -126,9 +124,7 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_keygen(
const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
*/
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_push(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
) {
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary key, header;
enacl_secretstream_ctx *obj = NULL;
@ -141,13 +137,14 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_push(
goto bad_arg;
}
if (!enif_alloc_binary(crypto_secretstream_xchacha20poly1305_HEADERBYTES, &header)) {
if (!enif_alloc_binary(crypto_secretstream_xchacha20poly1305_HEADERBYTES,
&header)) {
ret = enacl_internal_error(env);
goto done;
}
if((obj = enif_alloc_resource(enacl_secretstream_ctx_rtype,
sizeof(enacl_secretstream_ctx))) == NULL) {
if ((obj = enif_alloc_resource(enacl_secretstream_ctx_rtype,
sizeof(enacl_secretstream_ctx))) == NULL) {
ret = enacl_internal_error(env);
goto release_header;
}
@ -155,37 +152,38 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_push(
obj->state = enif_alloc(crypto_secretstream_xchacha20poly1305_statebytes());
if (obj->state == NULL) {
ret = enacl_internal_error(env);
goto release;
}
obj->alive = 1;
if ((obj->mtx = enif_mutex_create("enacl.secretstream")) == NULL) {
ret = enacl_internal_error(env);
goto free;
}
crypto_secretstream_xchacha20poly1305_init_push(obj->state, header.data, key.data);
crypto_secretstream_xchacha20poly1305_init_push(obj->state, header.data,
key.data);
ret = enif_make_tuple2(env,
enif_make_binary(env, &header),
enif_make_resource(env, obj)
);
ret = enif_make_tuple2(env, enif_make_binary(env, &header),
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_secretstream_xchacha20poly1305_statebytes());
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
release_header:
enif_release_binary(&header);
release:
// This also frees the mutex via the destructor
enif_release_resource(obj);
release_header:
enif_release_binary(&header);
done:
return ret;
}
@ -197,9 +195,7 @@ crypto_secretstream_xchacha20poly1305_init_pull
const unsigned char k[crypto_secretstream_xchacha20poly1305_KEYBYTES])
*/
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_pull(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
) {
ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary header, key;
enacl_secretstream_ctx *obj = NULL;
@ -208,22 +204,21 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_pull(
goto bad_arg;
}
if(!enif_inspect_binary(env, argv[0], &header)) {
if (!enif_inspect_binary(env, argv[0], &header)) {
goto bad_arg;
}
if(!enif_inspect_binary(env, argv[1], &key)) {
if (!enif_inspect_binary(env, argv[1], &key)) {
goto bad_arg;
}
if ((key.size != crypto_secretstream_xchacha20poly1305_KEYBYTES) ||
(header.size != crypto_secretstream_xchacha20poly1305_HEADERBYTES))
{
(header.size != crypto_secretstream_xchacha20poly1305_HEADERBYTES)) {
goto bad_arg;
}
if((obj = enif_alloc_resource(enacl_secretstream_ctx_rtype,
sizeof(enacl_secretstream_ctx))) == NULL) {
if ((obj = enif_alloc_resource(enacl_secretstream_ctx_rtype,
sizeof(enacl_secretstream_ctx))) == NULL) {
ret = enacl_internal_error(env);
goto done;
}
@ -240,7 +235,8 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_init_pull(
goto free;
}
crypto_secretstream_xchacha20poly1305_init_pull(obj->state, header.data, key.data);
crypto_secretstream_xchacha20poly1305_init_pull(obj->state, header.data,
key.data);
ret = enif_make_resource(env, obj);
@ -251,7 +247,8 @@ bad_arg:
free:
if (obj->alive)
if (obj->state != NULL) {
sodium_memzero(obj->state, crypto_secretstream_xchacha20poly1305_statebytes());
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
@ -267,10 +264,9 @@ void
crypto_secretstream_xchacha20poly1305_rekey
(crypto_secretstream_xchacha20poly1305_state *state)
*/
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_rekey(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
) {
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_rekey(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
enacl_secretstream_ctx *obj = NULL;
@ -278,9 +274,9 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_rekey(
goto bad_arg;
}
if(!enif_get_resource(env, argv[0],
(ErlNifResourceType *) enacl_secretstream_ctx_rtype,
(void **)&obj)) {
if (!enif_get_resource(env, argv[0],
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
(void **)&obj)) {
goto bad_arg;
}
@ -312,10 +308,9 @@ crypto_secretstream_xchacha20poly1305_push
const unsigned char *m, unsigned long long mlen,
const unsigned char *ad, unsigned long long adlen, unsigned char tag)
*/
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_push(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
) {
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_push(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary m, ad, out;
ErlNifUInt64 tag;
@ -325,25 +320,26 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_push(
goto bad_arg;
}
if(!enif_get_resource(env, argv[0],
(ErlNifResourceType *) enacl_secretstream_ctx_rtype,
(void **)&obj)) {
if (!enif_get_resource(env, argv[0],
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
(void **)&obj)) {
goto bad_arg;
}
if(!enif_inspect_binary(env, argv[1], &m)) {
if (!enif_inspect_binary(env, argv[1], &m)) {
goto bad_arg;
}
if(!enif_inspect_binary(env, argv[2], &ad)) {
if (!enif_inspect_binary(env, argv[2], &ad)) {
goto bad_arg;
}
if(!enif_get_uint64(env, argv[3], &tag)) {
if (!enif_get_uint64(env, argv[3], &tag)) {
goto bad_arg;
}
if (!enif_alloc_binary(m.size + crypto_secretstream_xchacha20poly1305_ABYTES, &out)) {
if (!enif_alloc_binary(m.size + crypto_secretstream_xchacha20poly1305_ABYTES,
&out)) {
return enacl_internal_error(env);
}
@ -352,12 +348,14 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_push(
goto err;
}
crypto_secretstream_xchacha20poly1305_push(obj->state, out.data, NULL, m.data, m.size, ad.data, ad.size, tag);
crypto_secretstream_xchacha20poly1305_push(obj->state, out.data, NULL, m.data,
m.size, ad.data, ad.size, tag);
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
if(obj->state) {
if (obj->state) {
obj->alive = 0;
sodium_memzero(obj->state, crypto_secretstream_xchacha20poly1305_statebytes());
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
@ -384,10 +382,9 @@ done:
const unsigned char *in, unsigned long long inlen,
const unsigned char *ad, unsigned long long adlen)
*/
ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_pull(
ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]
) {
ERL_NIF_TERM
enacl_crypto_secretstream_xchacha20poly1305_pull(ErlNifEnv *env, int argc,
const ERL_NIF_TERM argv[]) {
ERL_NIF_TERM ret;
ErlNifBinary m, in, ad;
unsigned char tag;
@ -397,55 +394,57 @@ ERL_NIF_TERM enacl_crypto_secretstream_xchacha20poly1305_pull(
goto bad_arg;
}
if(!enif_get_resource(env, argv[0],
(ErlNifResourceType *) enacl_secretstream_ctx_rtype,
(void **)&obj)) {
if (!enif_get_resource(env, argv[0],
(ErlNifResourceType *)enacl_secretstream_ctx_rtype,
(void **)&obj)) {
goto bad_arg;
}
if(!enif_inspect_binary(env, argv[1], &in)) {
if (!enif_inspect_binary(env, argv[1], &in)) {
goto bad_arg;
}
if(in.size < crypto_secretstream_xchacha20poly1305_ABYTES) {
if (in.size < crypto_secretstream_xchacha20poly1305_ABYTES) {
goto bad_arg;
}
if(!enif_inspect_binary(env, argv[2], &ad)) {
if (!enif_inspect_binary(env, argv[2], &ad)) {
goto bad_arg;
}
if(in.size < crypto_secretstream_xchacha20poly1305_ABYTES) {
if (in.size < crypto_secretstream_xchacha20poly1305_ABYTES) {
goto bad_arg;
}
if (!enif_alloc_binary(in.size - crypto_secretstream_xchacha20poly1305_ABYTES, &m)) {
if (!enif_alloc_binary(in.size - crypto_secretstream_xchacha20poly1305_ABYTES,
&m)) {
return enacl_internal_error(env);
}
enif_mutex_lock(obj->mtx);
if(!obj->alive) {
if (!obj->alive) {
goto err;
}
if (0 != crypto_secretstream_xchacha20poly1305_pull(obj->state, m.data, NULL, &tag, in.data, in.size, ad.data, ad.size)) {
if (0 != crypto_secretstream_xchacha20poly1305_pull(obj->state, m.data, NULL,
&tag, in.data, in.size,
ad.data, ad.size)) {
ret = enacl_error_tuple(env, "failed_verification");
goto release;
}
if (tag == crypto_secretstream_xchacha20poly1305_TAG_FINAL) {
if(obj->state) {
if (obj->state) {
obj->alive = 0;
sodium_memzero(obj->state, crypto_secretstream_xchacha20poly1305_statebytes());
sodium_memzero(obj->state,
crypto_secretstream_xchacha20poly1305_statebytes());
enif_free(obj->state);
obj->state = NULL;
}
}
ret = enif_make_tuple2(env,
enif_make_binary(env, &m),
enif_make_int64(env, tag)
);
ret = enif_make_tuple2(env, enif_make_binary(env, &m),
enif_make_int64(env, tag));
goto done;