aboutsummaryrefslogtreecommitdiffstats
path: root/lib/crypto/c_src/cmac.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto/c_src/cmac.c')
-rw-r--r--lib/crypto/c_src/cmac.c66
1 files changed, 42 insertions, 24 deletions
diff --git a/lib/crypto/c_src/cmac.c b/lib/crypto/c_src/cmac.c
index 526de11a01..49e67ccf29 100644
--- a/lib/crypto/c_src/cmac.c
+++ b/lib/crypto/c_src/cmac.c
@@ -24,42 +24,60 @@
ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key, Data) */
#if defined(HAVE_CMAC)
- struct cipher_type_t *cipherp = NULL;
+ const struct cipher_type_t *cipherp;
const EVP_CIPHER *cipher;
- CMAC_CTX *ctx;
+ CMAC_CTX *ctx = NULL;
ErlNifBinary key;
ErlNifBinary data;
ERL_NIF_TERM ret;
size_t ret_size;
+ unsigned char *outp;
+ int cipher_len;
- if (!enif_inspect_iolist_as_binary(env, argv[1], &key)
- || !(cipherp = get_cipher_type(argv[0], key.size))
- || !enif_inspect_iolist_as_binary(env, argv[2], &data)) {
- return enif_make_badarg(env);
- }
- cipher = cipherp->cipher.p;
- if (!cipher) {
+ ASSERT(argc == 3);
+
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &key))
+ goto bad_arg;
+ if ((cipherp = get_cipher_type(argv[0], key.size)) == NULL)
+ goto bad_arg;
+ if (cipherp->flags & (NON_EVP_CIPHER | AEAD_CIPHER))
+ goto bad_arg;
+ if (!enif_inspect_iolist_as_binary(env, argv[2], &data))
+ goto bad_arg;
+
+ if (FORBIDDEN_IN_FIPS(cipherp))
+ return enif_raise_exception(env, atom_notsup);
+ if ((cipher = cipherp->cipher.p) == NULL)
return enif_raise_exception(env, atom_notsup);
- }
- ctx = CMAC_CTX_new();
- if (!CMAC_Init(ctx, key.data, key.size, cipher, NULL)) {
- CMAC_CTX_free(ctx);
- return atom_notsup;
- }
+ if ((ctx = CMAC_CTX_new()) == NULL)
+ goto err;
+ if (!CMAC_Init(ctx, key.data, key.size, cipher, NULL))
+ goto err;
+ if (!CMAC_Update(ctx, data.data, data.size))
+ goto err;
+ if ((cipher_len = EVP_CIPHER_block_size(cipher)) < 0)
+ goto err;
+ if ((outp = enif_make_new_binary(env, (size_t)cipher_len, &ret)) == NULL)
+ goto err;
+ if (!CMAC_Final(ctx, outp, &ret_size))
+ goto err;
- if (!CMAC_Update(ctx, data.data, data.size) ||
- !CMAC_Final(ctx,
- enif_make_new_binary(env, EVP_CIPHER_block_size(cipher), &ret),
- &ret_size)) {
- CMAC_CTX_free(ctx);
- return atom_notsup;
- }
ASSERT(ret_size == (unsigned)EVP_CIPHER_block_size(cipher));
-
- CMAC_CTX_free(ctx);
CONSUME_REDS(env, data);
+ goto done;
+
+ bad_arg:
+ return enif_make_badarg(env);
+
+ err:
+ ret = atom_notsup;
+
+ done:
+ if (ctx)
+ CMAC_CTX_free(ctx);
return ret;
+
#else
/* The CMAC functionality was introduced in OpenSSL 1.0.1
* Although OTP requires at least version 0.9.8, the versions 0.9.8 and 1.0.0 are