|  | /* | 
|  | * 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 <string.h> | 
|  | #include <openssl/err.h> | 
|  | #include <openssl/ossl_typ.h> | 
|  | #include <openssl/asn1.h> | 
|  | #include <openssl/hmac.h> | 
|  | #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 | 
|  | }; |