1 /* $NetBSD: hmac.c,v 1.7 2025/01/26 16:25:37 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #include <openssl/err.h> 17 #include <openssl/evp.h> 18 #include <openssl/opensslv.h> 19 20 #include <isc/assertions.h> 21 #include <isc/hmac.h> 22 #include <isc/md.h> 23 #include <isc/safe.h> 24 #include <isc/string.h> 25 #include <isc/types.h> 26 #include <isc/util.h> 27 28 #include "openssl_shim.h" 29 30 isc_hmac_t * 31 isc_hmac_new(void) { 32 EVP_MD_CTX *hmac_st = EVP_MD_CTX_new(); 33 RUNTIME_CHECK(hmac_st != NULL); 34 return (isc_hmac_t *)hmac_st; 35 } 36 37 void 38 isc_hmac_free(isc_hmac_t *hmac_st) { 39 if (hmac_st == NULL) { 40 return; 41 } 42 43 EVP_MD_CTX_free((EVP_MD_CTX *)hmac_st); 44 } 45 46 isc_result_t 47 isc_hmac_init(isc_hmac_t *hmac_st, const void *key, const size_t keylen, 48 const isc_md_type_t *md_type) { 49 EVP_PKEY *pkey; 50 51 REQUIRE(hmac_st != NULL); 52 REQUIRE(key != NULL); 53 REQUIRE(keylen <= INT_MAX); 54 55 if (md_type == NULL) { 56 return ISC_R_NOTIMPLEMENTED; 57 } 58 59 pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL, key, keylen); 60 if (pkey == NULL) { 61 ERR_clear_error(); 62 return ISC_R_CRYPTOFAILURE; 63 } 64 65 if (EVP_DigestSignInit(hmac_st, NULL, md_type, NULL, pkey) != 1) { 66 EVP_PKEY_free(pkey); 67 ERR_clear_error(); 68 return ISC_R_CRYPTOFAILURE; 69 } 70 71 EVP_PKEY_free(pkey); 72 73 return ISC_R_SUCCESS; 74 } 75 76 isc_result_t 77 isc_hmac_reset(isc_hmac_t *hmac_st) { 78 REQUIRE(hmac_st != NULL); 79 80 if (EVP_MD_CTX_reset(hmac_st) != 1) { 81 ERR_clear_error(); 82 return ISC_R_CRYPTOFAILURE; 83 } 84 85 return ISC_R_SUCCESS; 86 } 87 88 isc_result_t 89 isc_hmac_update(isc_hmac_t *hmac_st, const unsigned char *buf, 90 const size_t len) { 91 REQUIRE(hmac_st != NULL); 92 93 if (buf == NULL || len == 0) { 94 return ISC_R_SUCCESS; 95 } 96 97 if (EVP_DigestSignUpdate(hmac_st, buf, len) != 1) { 98 ERR_clear_error(); 99 return ISC_R_CRYPTOFAILURE; 100 } 101 102 return ISC_R_SUCCESS; 103 } 104 105 isc_result_t 106 isc_hmac_final(isc_hmac_t *hmac_st, unsigned char *digest, 107 unsigned int *digestlen) { 108 REQUIRE(hmac_st != NULL); 109 REQUIRE(digest != NULL); 110 REQUIRE(digestlen != NULL); 111 112 size_t len = *digestlen; 113 114 if (EVP_DigestSignFinal(hmac_st, digest, &len) != 1) { 115 ERR_clear_error(); 116 return ISC_R_CRYPTOFAILURE; 117 } 118 119 *digestlen = (unsigned int)len; 120 121 return ISC_R_SUCCESS; 122 } 123 124 const isc_md_type_t * 125 isc_hmac_get_md_type(isc_hmac_t *hmac_st) { 126 REQUIRE(hmac_st != NULL); 127 128 return EVP_MD_CTX_get0_md(hmac_st); 129 } 130 131 size_t 132 isc_hmac_get_size(isc_hmac_t *hmac_st) { 133 REQUIRE(hmac_st != NULL); 134 135 return (size_t)EVP_MD_CTX_size(hmac_st); 136 } 137 138 int 139 isc_hmac_get_block_size(isc_hmac_t *hmac_st) { 140 REQUIRE(hmac_st != NULL); 141 142 return EVP_MD_CTX_block_size(hmac_st); 143 } 144 145 isc_result_t 146 isc_hmac(const isc_md_type_t *type, const void *key, const size_t keylen, 147 const unsigned char *buf, const size_t len, unsigned char *digest, 148 unsigned int *digestlen) { 149 isc_result_t res; 150 isc_hmac_t *hmac_st = isc_hmac_new(); 151 152 res = isc_hmac_init(hmac_st, key, keylen, type); 153 if (res != ISC_R_SUCCESS) { 154 goto end; 155 } 156 157 res = isc_hmac_update(hmac_st, buf, len); 158 if (res != ISC_R_SUCCESS) { 159 goto end; 160 } 161 162 res = isc_hmac_final(hmac_st, digest, digestlen); 163 if (res != ISC_R_SUCCESS) { 164 goto end; 165 } 166 end: 167 isc_hmac_free(hmac_st); 168 169 return res; 170 } 171