/* * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ #include #include #include #include #include #include "internal/evp_int.h" /* local HMAC context structure */ /* typedef EVP_MAC_IMPL */ struct evp_mac_impl_st { /* tmpmd and tmpengine are set to NULL after a CMAC_Init call */ const EVP_MD *tmpmd; /* HMAC digest */ const ENGINE *tmpengine; /* HMAC digest engine */ HMAC_CTX *ctx; /* HMAC context */ }; static EVP_MAC_IMPL *hmac_new(void) { EVP_MAC_IMPL *hctx; if ((hctx = OPENSSL_zalloc(sizeof(*hctx))) == NULL || (hctx->ctx = HMAC_CTX_new()) == NULL) { OPENSSL_free(hctx); return NULL; } return hctx; } static void hmac_free(EVP_MAC_IMPL *hctx) { if (hctx != NULL) { HMAC_CTX_free(hctx->ctx); OPENSSL_free(hctx); } } static int hmac_copy(EVP_MAC_IMPL *hdst, EVP_MAC_IMPL *hsrc) { if (!HMAC_CTX_copy(hdst->ctx, hsrc->ctx)) return 0; hdst->tmpengine = hsrc->tmpengine; hdst->tmpmd = hsrc->tmpmd; return 1; } static size_t hmac_size(EVP_MAC_IMPL *hctx) { return HMAC_size(hctx->ctx); } static int hmac_init(EVP_MAC_IMPL *hctx) { int rv = 1; /* HMAC_Init_ex doesn't tolerate all zero params, so we must be careful */ if (hctx->tmpmd != NULL) rv = HMAC_Init_ex(hctx->ctx, NULL, 0, hctx->tmpmd, (ENGINE * )hctx->tmpengine); hctx->tmpengine = NULL; hctx->tmpmd = NULL; return rv; } static int hmac_update(EVP_MAC_IMPL *hctx, const unsigned char *data, size_t datalen) { return HMAC_Update(hctx->ctx, data, datalen); } static int hmac_final(EVP_MAC_IMPL *hctx, unsigned char *out) { unsigned int hlen; return HMAC_Final(hctx->ctx, out, &hlen); } static int hmac_ctrl(EVP_MAC_IMPL *hctx, int cmd, va_list args) { switch (cmd) { case EVP_MAC_CTRL_SET_FLAGS: { unsigned long flags = va_arg(args, unsigned long); HMAC_CTX_set_flags(hctx->ctx, flags); } break; case EVP_MAC_CTRL_SET_KEY: { const unsigned char *key = va_arg(args, const unsigned char *); size_t keylen = va_arg(args, size_t); int rv = HMAC_Init_ex(hctx->ctx, key, keylen, hctx->tmpmd, (ENGINE *)hctx->tmpengine); hctx->tmpengine = NULL; hctx->tmpmd = NULL; return rv; } break; case EVP_MAC_CTRL_SET_MD: hctx->tmpmd = va_arg(args, const EVP_MD *); break; case EVP_MAC_CTRL_SET_ENGINE: hctx->tmpengine = va_arg(args, const ENGINE *); break; default: return -2; } return 1; } static int hmac_ctrl_int(EVP_MAC_IMPL *hctx, int cmd, ...) { int rv; va_list args; va_start(args, cmd); rv = hmac_ctrl(hctx, cmd, args); va_end(args); return rv; } static int hmac_ctrl_str_cb(void *hctx, int cmd, void *buf, size_t buflen) { return hmac_ctrl_int(hctx, cmd, buf, buflen); } static int hmac_ctrl_str(EVP_MAC_IMPL *hctx, const char *type, const char *value) { if (!value) return 0; if (strcmp(type, "digest") == 0) { const EVP_MD *d = EVP_get_digestbyname(value); if (d == NULL) return 0; return hmac_ctrl_int(hctx, EVP_MAC_CTRL_SET_MD, d); } if (strcmp(type, "key") == 0) return EVP_str2ctrl(hmac_ctrl_str_cb, hctx, EVP_MAC_CTRL_SET_KEY, value); if (strcmp(type, "hexkey") == 0) return EVP_hex2ctrl(hmac_ctrl_str_cb, hctx, EVP_MAC_CTRL_SET_KEY, value); return -2; } const EVP_MAC hmac_meth = { EVP_MAC_HMAC, hmac_new, hmac_copy, hmac_free, hmac_size, hmac_init, hmac_update, hmac_final, hmac_ctrl, hmac_ctrl_str };