1*bcda20f6Schristos /* $NetBSD: hmac_link.c,v 1.10 2025/01/26 16:25:22 christos Exp $ */ 2d68c78b8Schristos 3d68c78b8Schristos /* 48596601aSchristos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 58596601aSchristos * 68596601aSchristos * SPDX-License-Identifier: MPL-2.0 AND ISC 7d68c78b8Schristos * 8d68c78b8Schristos * This Source Code Form is subject to the terms of the Mozilla Public 9d68c78b8Schristos * License, v. 2.0. If a copy of the MPL was not distributed with this 10fce770bdSchristos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11d68c78b8Schristos * 12d68c78b8Schristos * See the COPYRIGHT file distributed with this work for additional 13d68c78b8Schristos * information regarding copyright ownership. 148596601aSchristos */ 158596601aSchristos 168596601aSchristos /* 178596601aSchristos * Copyright (C) Network Associates, Inc. 18d68c78b8Schristos * 19d68c78b8Schristos * Permission to use, copy, modify, and/or distribute this software for any 20d68c78b8Schristos * purpose with or without fee is hereby granted, provided that the above 21d68c78b8Schristos * copyright notice and this permission notice appear in all copies. 22d68c78b8Schristos * 23d68c78b8Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS 24d68c78b8Schristos * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 25d68c78b8Schristos * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE 26d68c78b8Schristos * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 27d68c78b8Schristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 28d68c78b8Schristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 29d68c78b8Schristos * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 30d68c78b8Schristos */ 31d68c78b8Schristos 32d4a20c3eSchristos #include <arpa/inet.h> 33bb5aa156Schristos #include <stdbool.h> 34d4a20c3eSchristos 35d68c78b8Schristos #include <isc/buffer.h> 36d4a20c3eSchristos #include <isc/hmac.h> 37bb5aa156Schristos #include <isc/lex.h> 38d4a20c3eSchristos #include <isc/md.h> 395606745fSchristos #include <isc/mem.h> 40d4a20c3eSchristos #include <isc/nonce.h> 41d4a20c3eSchristos #include <isc/random.h> 42bb5aa156Schristos #include <isc/result.h> 43d68c78b8Schristos #include <isc/safe.h> 44d68c78b8Schristos #include <isc/string.h> 45d68c78b8Schristos #include <isc/util.h> 46d68c78b8Schristos 47d68c78b8Schristos #include "dst_internal.h" 48d68c78b8Schristos #include "dst_parse.h" 49d68c78b8Schristos 50d4a20c3eSchristos #define ISC_MD_md5 ISC_MD_MD5 51d4a20c3eSchristos #define ISC_MD_sha1 ISC_MD_SHA1 52d4a20c3eSchristos #define ISC_MD_sha224 ISC_MD_SHA224 53d4a20c3eSchristos #define ISC_MD_sha256 ISC_MD_SHA256 54d4a20c3eSchristos #define ISC_MD_sha384 ISC_MD_SHA384 55d4a20c3eSchristos #define ISC_MD_sha512 ISC_MD_SHA512 56d68c78b8Schristos 57d4a20c3eSchristos #define hmac_register_algorithm(alg) \ 585606745fSchristos static isc_result_t hmac##alg##_createctx(dst_key_t *key, \ 59d4a20c3eSchristos dst_context_t *dctx) { \ 60d4a20c3eSchristos return (hmac_createctx(ISC_MD_##alg, key, dctx)); \ 61d4a20c3eSchristos } \ 625606745fSchristos static void hmac##alg##_destroyctx(dst_context_t *dctx) { \ 63d4a20c3eSchristos hmac_destroyctx(dctx); \ 64d4a20c3eSchristos } \ 655606745fSchristos static isc_result_t hmac##alg##_adddata(dst_context_t *dctx, \ 66d4a20c3eSchristos const isc_region_t *data) { \ 67d4a20c3eSchristos return (hmac_adddata(dctx, data)); \ 68d4a20c3eSchristos } \ 695606745fSchristos static isc_result_t hmac##alg##_sign(dst_context_t *dctx, \ 70d4a20c3eSchristos isc_buffer_t *sig) { \ 71d4a20c3eSchristos return (hmac_sign(dctx, sig)); \ 72d4a20c3eSchristos } \ 735606745fSchristos static isc_result_t hmac##alg##_verify(dst_context_t *dctx, \ 74d4a20c3eSchristos const isc_region_t *sig) { \ 75d4a20c3eSchristos return (hmac_verify(dctx, sig)); \ 76d4a20c3eSchristos } \ 775606745fSchristos static bool hmac##alg##_compare(const dst_key_t *key1, \ 78d4a20c3eSchristos const dst_key_t *key2) { \ 79d4a20c3eSchristos return (hmac_compare(ISC_MD_##alg, key1, key2)); \ 80d4a20c3eSchristos } \ 815606745fSchristos static isc_result_t hmac##alg##_generate( \ 825606745fSchristos dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) { \ 83d4a20c3eSchristos UNUSED(pseudorandom_ok); \ 84d4a20c3eSchristos UNUSED(callback); \ 85d4a20c3eSchristos return (hmac_generate(ISC_MD_##alg, key)); \ 86d4a20c3eSchristos } \ 875606745fSchristos static bool hmac##alg##_isprivate(const dst_key_t *key) { \ 88d4a20c3eSchristos return (hmac_isprivate(key)); \ 89d4a20c3eSchristos } \ 905606745fSchristos static void hmac##alg##_destroy(dst_key_t *key) { hmac_destroy(key); } \ 915606745fSchristos static isc_result_t hmac##alg##_todns(const dst_key_t *key, \ 925606745fSchristos isc_buffer_t *data) { \ 93d4a20c3eSchristos return (hmac_todns(key, data)); \ 94d4a20c3eSchristos } \ 955606745fSchristos static isc_result_t hmac##alg##_fromdns(dst_key_t *key, \ 965606745fSchristos isc_buffer_t *data) { \ 97d4a20c3eSchristos return (hmac_fromdns(ISC_MD_##alg, key, data)); \ 98d4a20c3eSchristos } \ 995606745fSchristos static isc_result_t hmac##alg##_tofile(const dst_key_t *key, \ 1005606745fSchristos const char *directory) { \ 101d4a20c3eSchristos return (hmac_tofile(ISC_MD_##alg, key, directory)); \ 102d4a20c3eSchristos } \ 1035606745fSchristos static isc_result_t hmac##alg##_parse( \ 1045606745fSchristos dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { \ 105bb5aa156Schristos const char *file = isc_lex_getsourcename(lexer); \ 106bb5aa156Schristos isc_result_t result; \ 107bb5aa156Schristos result = hmac_parse(ISC_MD_##alg, key, lexer, pub); \ 108bb5aa156Schristos if (result == ISC_R_SUCCESS && file != NULL) { \ 109bb5aa156Schristos isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL, \ 110bb5aa156Schristos DNS_LOGMODULE_CRYPTO, ISC_LOG_WARNING, \ 111bb5aa156Schristos "%s: Use of K* file pairs for HMAC is " \ 112bb5aa156Schristos "deprecated\n", \ 113bb5aa156Schristos file); \ 114bb5aa156Schristos } \ 115bb5aa156Schristos return (result); \ 116d4a20c3eSchristos } \ 117d4a20c3eSchristos static dst_func_t hmac##alg##_functions = { \ 118d4a20c3eSchristos hmac##alg##_createctx, \ 119d4a20c3eSchristos NULL, /*%< createctx2 */ \ 120d4a20c3eSchristos hmac##alg##_destroyctx, \ 121d4a20c3eSchristos hmac##alg##_adddata, \ 122d4a20c3eSchristos hmac##alg##_sign, \ 123d4a20c3eSchristos hmac##alg##_verify, \ 124d4a20c3eSchristos NULL, /*%< verify2 */ \ 125d4a20c3eSchristos NULL, /*%< computesecret */ \ 126d4a20c3eSchristos hmac##alg##_compare, \ 127d4a20c3eSchristos NULL, /*%< paramcompare */ \ 128d4a20c3eSchristos hmac##alg##_generate, \ 129d4a20c3eSchristos hmac##alg##_isprivate, \ 130d4a20c3eSchristos hmac##alg##_destroy, \ 131d4a20c3eSchristos hmac##alg##_todns, \ 132d4a20c3eSchristos hmac##alg##_fromdns, \ 133d4a20c3eSchristos hmac##alg##_tofile, \ 134d4a20c3eSchristos hmac##alg##_parse, \ 135d4a20c3eSchristos NULL, /*%< cleanup */ \ 136d4a20c3eSchristos NULL, /*%< fromlabel */ \ 137d4a20c3eSchristos NULL, /*%< dump */ \ 138d4a20c3eSchristos NULL, /*%< restore */ \ 139d4a20c3eSchristos }; \ 1405606745fSchristos isc_result_t dst__hmac##alg##_init(dst_func_t **funcp) { \ 141d4a20c3eSchristos REQUIRE(funcp != NULL); \ 142d4a20c3eSchristos if (*funcp == NULL) { \ 143*bcda20f6Schristos isc_hmac_t *ctx = isc_hmac_new(); \ 144*bcda20f6Schristos if (isc_hmac_init(ctx, "test", 4, ISC_MD_##alg) == \ 145*bcda20f6Schristos ISC_R_SUCCESS) \ 146*bcda20f6Schristos { \ 147d4a20c3eSchristos *funcp = &hmac##alg##_functions; \ 148d4a20c3eSchristos } \ 149*bcda20f6Schristos isc_hmac_free(ctx); \ 150*bcda20f6Schristos } \ 151d4a20c3eSchristos return (ISC_R_SUCCESS); \ 152d4a20c3eSchristos } 153d4a20c3eSchristos 154d4a20c3eSchristos static isc_result_t 1555606745fSchristos hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data); 156d4a20c3eSchristos 157d4a20c3eSchristos struct dst_hmac_key { 158d4a20c3eSchristos uint8_t key[ISC_MAX_BLOCK_SIZE]; 159d68c78b8Schristos }; 160d68c78b8Schristos 1618596601aSchristos static isc_result_t 162d68c78b8Schristos getkeybits(dst_key_t *key, struct dst_private_element *element) { 163d4a20c3eSchristos uint16_t *bits = (uint16_t *)element->data; 164d68c78b8Schristos 165d4a20c3eSchristos if (element->length != 2) { 166*bcda20f6Schristos return DST_R_INVALIDPRIVATEKEY; 167d4a20c3eSchristos } 168d68c78b8Schristos 169d4a20c3eSchristos key->key_bits = ntohs(*bits); 170d68c78b8Schristos 171*bcda20f6Schristos return ISC_R_SUCCESS; 172d68c78b8Schristos } 173d68c78b8Schristos 1748596601aSchristos static isc_result_t 1755606745fSchristos hmac_createctx(const isc_md_type_t *type, const dst_key_t *key, 1765606745fSchristos dst_context_t *dctx) { 177d4a20c3eSchristos isc_result_t result; 178d4a20c3eSchristos const dst_hmac_key_t *hkey = key->keydata.hmac_key; 179d4a20c3eSchristos isc_hmac_t *ctx = isc_hmac_new(); /* Either returns or abort()s */ 180d68c78b8Schristos 1815606745fSchristos result = isc_hmac_init(ctx, hkey->key, isc_md_type_get_block_size(type), 1825606745fSchristos type); 183d4a20c3eSchristos if (result != ISC_R_SUCCESS) { 184f16d61c4Schristos isc_hmac_free(ctx); 185*bcda20f6Schristos return DST_R_UNSUPPORTEDALG; 186d4a20c3eSchristos } 187d4a20c3eSchristos 188d4a20c3eSchristos dctx->ctxdata.hmac_ctx = ctx; 189*bcda20f6Schristos return ISC_R_SUCCESS; 190d68c78b8Schristos } 191d68c78b8Schristos 1928596601aSchristos static void 193d4a20c3eSchristos hmac_destroyctx(dst_context_t *dctx) { 194d4a20c3eSchristos isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; 195d4a20c3eSchristos REQUIRE(ctx != NULL); 196d68c78b8Schristos 197d4a20c3eSchristos isc_hmac_free(ctx); 198d4a20c3eSchristos dctx->ctxdata.hmac_ctx = NULL; 199d68c78b8Schristos } 200d68c78b8Schristos 2018596601aSchristos static isc_result_t 202d4a20c3eSchristos hmac_adddata(const dst_context_t *dctx, const isc_region_t *data) { 203d4a20c3eSchristos isc_result_t result; 204d4a20c3eSchristos isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; 205d68c78b8Schristos 206d4a20c3eSchristos REQUIRE(ctx != NULL); 207d4a20c3eSchristos 208d4a20c3eSchristos result = isc_hmac_update(ctx, data->base, data->length); 209d4a20c3eSchristos if (result != ISC_R_SUCCESS) { 210*bcda20f6Schristos return DST_R_OPENSSLFAILURE; 211d4a20c3eSchristos } 212d4a20c3eSchristos 213*bcda20f6Schristos return ISC_R_SUCCESS; 214d68c78b8Schristos } 215d68c78b8Schristos 2168596601aSchristos static isc_result_t 217d4a20c3eSchristos hmac_sign(const dst_context_t *dctx, isc_buffer_t *sig) { 218d4a20c3eSchristos isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; 219d4a20c3eSchristos REQUIRE(ctx != NULL); 220d4a20c3eSchristos unsigned char digest[ISC_MAX_MD_SIZE]; 221bb5aa156Schristos unsigned int digestlen = sizeof(digest); 222d68c78b8Schristos 223d4a20c3eSchristos if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) { 224*bcda20f6Schristos return DST_R_OPENSSLFAILURE; 225d4a20c3eSchristos } 226d4a20c3eSchristos 227d4a20c3eSchristos if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) { 228*bcda20f6Schristos return DST_R_OPENSSLFAILURE; 229d4a20c3eSchristos } 230d4a20c3eSchristos 231d4a20c3eSchristos if (isc_buffer_availablelength(sig) < digestlen) { 232*bcda20f6Schristos return ISC_R_NOSPACE; 233d4a20c3eSchristos } 234d4a20c3eSchristos 235d4a20c3eSchristos isc_buffer_putmem(sig, digest, digestlen); 236d68c78b8Schristos 237*bcda20f6Schristos return ISC_R_SUCCESS; 238d68c78b8Schristos } 239d68c78b8Schristos 2408596601aSchristos static isc_result_t 241d4a20c3eSchristos hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) { 242d4a20c3eSchristos isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx; 243d4a20c3eSchristos unsigned char digest[ISC_MAX_MD_SIZE]; 244bb5aa156Schristos unsigned int digestlen = sizeof(digest); 245d68c78b8Schristos 246d4a20c3eSchristos REQUIRE(ctx != NULL); 247d68c78b8Schristos 248d4a20c3eSchristos if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) { 249*bcda20f6Schristos return DST_R_OPENSSLFAILURE; 250d4a20c3eSchristos } 251d4a20c3eSchristos 252d4a20c3eSchristos if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) { 253*bcda20f6Schristos return DST_R_OPENSSLFAILURE; 254d4a20c3eSchristos } 255d4a20c3eSchristos 256d4a20c3eSchristos if (sig->length > digestlen) { 257*bcda20f6Schristos return DST_R_VERIFYFAILURE; 258d68c78b8Schristos } 259d68c78b8Schristos 260*bcda20f6Schristos return isc_safe_memequal(digest, sig->base, sig->length) 2615606745fSchristos ? ISC_R_SUCCESS 262*bcda20f6Schristos : DST_R_VERIFYFAILURE; 263d68c78b8Schristos } 264d68c78b8Schristos 2658596601aSchristos static bool 2665606745fSchristos hmac_compare(const isc_md_type_t *type, const dst_key_t *key1, 2675606745fSchristos const dst_key_t *key2) { 268d4a20c3eSchristos dst_hmac_key_t *hkey1, *hkey2; 269d4a20c3eSchristos 270d4a20c3eSchristos hkey1 = key1->keydata.hmac_key; 271d4a20c3eSchristos hkey2 = key2->keydata.hmac_key; 272d4a20c3eSchristos 273d4a20c3eSchristos if (hkey1 == NULL && hkey2 == NULL) { 274*bcda20f6Schristos return true; 275d4a20c3eSchristos } else if (hkey1 == NULL || hkey2 == NULL) { 276*bcda20f6Schristos return false; 277d4a20c3eSchristos } 278d4a20c3eSchristos 279*bcda20f6Schristos return isc_safe_memequal(hkey1->key, hkey2->key, 280*bcda20f6Schristos isc_md_type_get_block_size(type)); 281d4a20c3eSchristos } 282d4a20c3eSchristos 2838596601aSchristos static isc_result_t 2845606745fSchristos hmac_generate(const isc_md_type_t *type, dst_key_t *key) { 285d68c78b8Schristos isc_buffer_t b; 286d68c78b8Schristos isc_result_t ret; 287d4a20c3eSchristos unsigned int bytes, len; 288d4a20c3eSchristos unsigned char data[ISC_MAX_MD_SIZE] = { 0 }; 289d68c78b8Schristos 290d4a20c3eSchristos len = isc_md_type_get_block_size(type); 291d68c78b8Schristos 292d68c78b8Schristos bytes = (key->key_size + 7) / 8; 293d4a20c3eSchristos 294d4a20c3eSchristos if (bytes > len) { 295d4a20c3eSchristos bytes = len; 296d4a20c3eSchristos key->key_size = len * 8; 297d68c78b8Schristos } 298d68c78b8Schristos 299d4a20c3eSchristos isc_nonce_buf(data, bytes); 300d68c78b8Schristos 301d68c78b8Schristos isc_buffer_init(&b, data, bytes); 302d68c78b8Schristos isc_buffer_add(&b, bytes); 303d4a20c3eSchristos 304d4a20c3eSchristos ret = hmac_fromdns(type, key, &b); 305d4a20c3eSchristos 306d68c78b8Schristos isc_safe_memwipe(data, sizeof(data)); 307d68c78b8Schristos 308*bcda20f6Schristos return ret; 309d68c78b8Schristos } 310d68c78b8Schristos 3118596601aSchristos static bool 312d4a20c3eSchristos hmac_isprivate(const dst_key_t *key) { 313d68c78b8Schristos UNUSED(key); 314*bcda20f6Schristos return true; 315d68c78b8Schristos } 316d68c78b8Schristos 3178596601aSchristos static void 318d4a20c3eSchristos hmac_destroy(dst_key_t *key) { 319d4a20c3eSchristos dst_hmac_key_t *hkey = key->keydata.hmac_key; 320d68c78b8Schristos isc_safe_memwipe(hkey, sizeof(*hkey)); 321d68c78b8Schristos isc_mem_put(key->mctx, hkey, sizeof(*hkey)); 322d4a20c3eSchristos key->keydata.hmac_key = NULL; 323d68c78b8Schristos } 324d68c78b8Schristos 3258596601aSchristos static isc_result_t 326d4a20c3eSchristos hmac_todns(const dst_key_t *key, isc_buffer_t *data) { 3275606745fSchristos REQUIRE(key != NULL && key->keydata.hmac_key != NULL); 328d4a20c3eSchristos dst_hmac_key_t *hkey = key->keydata.hmac_key; 329d68c78b8Schristos unsigned int bytes; 330d68c78b8Schristos 331d68c78b8Schristos bytes = (key->key_size + 7) / 8; 332d4a20c3eSchristos if (isc_buffer_availablelength(data) < bytes) { 333*bcda20f6Schristos return ISC_R_NOSPACE; 334d4a20c3eSchristos } 335d68c78b8Schristos isc_buffer_putmem(data, hkey->key, bytes); 336d68c78b8Schristos 337*bcda20f6Schristos return ISC_R_SUCCESS; 338d68c78b8Schristos } 339d68c78b8Schristos 3408596601aSchristos static isc_result_t 3415606745fSchristos hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data) { 342d4a20c3eSchristos dst_hmac_key_t *hkey; 343d4a20c3eSchristos unsigned int keylen; 344d68c78b8Schristos isc_region_t r; 345d68c78b8Schristos 346d68c78b8Schristos isc_buffer_remainingregion(data, &r); 347d4a20c3eSchristos if (r.length == 0) { 348*bcda20f6Schristos return ISC_R_SUCCESS; 349d4a20c3eSchristos } 350d68c78b8Schristos 351d4a20c3eSchristos hkey = isc_mem_get(key->mctx, sizeof(dst_hmac_key_t)); 352d68c78b8Schristos 353d68c78b8Schristos memset(hkey->key, 0, sizeof(hkey->key)); 354d68c78b8Schristos 355d4a20c3eSchristos /* Hash the key if the key is longer then chosen MD block size */ 356d4a20c3eSchristos if (r.length > (unsigned int)isc_md_type_get_block_size(type)) { 3575606745fSchristos if (isc_md(type, r.base, r.length, hkey->key, &keylen) != 358903adeddSchristos ISC_R_SUCCESS) 359903adeddSchristos { 360d4a20c3eSchristos isc_mem_put(key->mctx, hkey, sizeof(dst_hmac_key_t)); 361*bcda20f6Schristos return DST_R_OPENSSLFAILURE; 362d4a20c3eSchristos } 363d68c78b8Schristos } else { 364d68c78b8Schristos memmove(hkey->key, r.base, r.length); 365d68c78b8Schristos keylen = r.length; 366d68c78b8Schristos } 367d68c78b8Schristos 368d68c78b8Schristos key->key_size = keylen * 8; 369d4a20c3eSchristos key->keydata.hmac_key = hkey; 370d68c78b8Schristos 371d68c78b8Schristos isc_buffer_forward(data, r.length); 372d68c78b8Schristos 373*bcda20f6Schristos return ISC_R_SUCCESS; 374d68c78b8Schristos } 375d68c78b8Schristos 3768596601aSchristos static int 3775606745fSchristos hmac__get_tag_key(const isc_md_type_t *type) { 378d4a20c3eSchristos if (type == ISC_MD_MD5) { 379*bcda20f6Schristos return TAG_HMACMD5_KEY; 380d4a20c3eSchristos } else if (type == ISC_MD_SHA1) { 381*bcda20f6Schristos return TAG_HMACSHA1_KEY; 382d4a20c3eSchristos } else if (type == ISC_MD_SHA224) { 383*bcda20f6Schristos return TAG_HMACSHA224_KEY; 384d4a20c3eSchristos } else if (type == ISC_MD_SHA256) { 385*bcda20f6Schristos return TAG_HMACSHA256_KEY; 386d4a20c3eSchristos } else if (type == ISC_MD_SHA384) { 387*bcda20f6Schristos return TAG_HMACSHA384_KEY; 388d4a20c3eSchristos } else if (type == ISC_MD_SHA512) { 389*bcda20f6Schristos return TAG_HMACSHA512_KEY; 390d4a20c3eSchristos } else { 3918596601aSchristos UNREACHABLE(); 392d4a20c3eSchristos } 393d4a20c3eSchristos } 394d4a20c3eSchristos 3958596601aSchristos static int 3965606745fSchristos hmac__get_tag_bits(const isc_md_type_t *type) { 397d4a20c3eSchristos if (type == ISC_MD_MD5) { 398*bcda20f6Schristos return TAG_HMACMD5_BITS; 399d4a20c3eSchristos } else if (type == ISC_MD_SHA1) { 400*bcda20f6Schristos return TAG_HMACSHA1_BITS; 401d4a20c3eSchristos } else if (type == ISC_MD_SHA224) { 402*bcda20f6Schristos return TAG_HMACSHA224_BITS; 403d4a20c3eSchristos } else if (type == ISC_MD_SHA256) { 404*bcda20f6Schristos return TAG_HMACSHA256_BITS; 405d4a20c3eSchristos } else if (type == ISC_MD_SHA384) { 406*bcda20f6Schristos return TAG_HMACSHA384_BITS; 407d4a20c3eSchristos } else if (type == ISC_MD_SHA512) { 408*bcda20f6Schristos return TAG_HMACSHA512_BITS; 409d4a20c3eSchristos } else { 4108596601aSchristos UNREACHABLE(); 411d4a20c3eSchristos } 412d4a20c3eSchristos } 413d4a20c3eSchristos 4148596601aSchristos static isc_result_t 4155606745fSchristos hmac_tofile(const isc_md_type_t *type, const dst_key_t *key, 4165606745fSchristos const char *directory) { 417d4a20c3eSchristos dst_hmac_key_t *hkey; 418d68c78b8Schristos dst_private_t priv; 419d68c78b8Schristos int bytes = (key->key_size + 7) / 8; 420d4a20c3eSchristos uint16_t bits; 421d68c78b8Schristos 422d4a20c3eSchristos if (key->keydata.hmac_key == NULL) { 423*bcda20f6Schristos return DST_R_NULLKEY; 424d4a20c3eSchristos } 425d68c78b8Schristos 426d4a20c3eSchristos if (key->external) { 427*bcda20f6Schristos return DST_R_EXTERNALKEY; 428d4a20c3eSchristos } 429d68c78b8Schristos 430d4a20c3eSchristos hkey = key->keydata.hmac_key; 431d68c78b8Schristos 432d4a20c3eSchristos priv.elements[0].tag = hmac__get_tag_key(type); 433d4a20c3eSchristos priv.elements[0].length = bytes; 434d4a20c3eSchristos priv.elements[0].data = hkey->key; 435d68c78b8Schristos 436d4a20c3eSchristos bits = htons(key->key_bits); 437d68c78b8Schristos 438d4a20c3eSchristos priv.elements[1].tag = hmac__get_tag_bits(type); 439d4a20c3eSchristos priv.elements[1].length = sizeof(bits); 440d4a20c3eSchristos priv.elements[1].data = (uint8_t *)&bits; 441d4a20c3eSchristos 442d4a20c3eSchristos priv.nelements = 2; 443d4a20c3eSchristos 444*bcda20f6Schristos return dst__privstruct_writefile(key, &priv, directory); 445d68c78b8Schristos } 446d68c78b8Schristos 4478596601aSchristos static int 4485606745fSchristos hmac__to_dst_alg(const isc_md_type_t *type) { 449d4a20c3eSchristos if (type == ISC_MD_MD5) { 450*bcda20f6Schristos return DST_ALG_HMACMD5; 451d4a20c3eSchristos } else if (type == ISC_MD_SHA1) { 452*bcda20f6Schristos return DST_ALG_HMACSHA1; 453d4a20c3eSchristos } else if (type == ISC_MD_SHA224) { 454*bcda20f6Schristos return DST_ALG_HMACSHA224; 455d4a20c3eSchristos } else if (type == ISC_MD_SHA256) { 456*bcda20f6Schristos return DST_ALG_HMACSHA256; 457d4a20c3eSchristos } else if (type == ISC_MD_SHA384) { 458*bcda20f6Schristos return DST_ALG_HMACSHA384; 459d4a20c3eSchristos } else if (type == ISC_MD_SHA512) { 460*bcda20f6Schristos return DST_ALG_HMACSHA512; 461d4a20c3eSchristos } else { 4628596601aSchristos UNREACHABLE(); 463d4a20c3eSchristos } 464d4a20c3eSchristos } 465d4a20c3eSchristos 4668596601aSchristos static isc_result_t 4675606745fSchristos hmac_parse(const isc_md_type_t *type, dst_key_t *key, isc_lex_t *lexer, 4685606745fSchristos dst_key_t *pub) { 469d68c78b8Schristos dst_private_t priv; 470d68c78b8Schristos isc_result_t result, tresult; 471d68c78b8Schristos isc_buffer_t b; 472d68c78b8Schristos isc_mem_t *mctx = key->mctx; 473d68c78b8Schristos unsigned int i; 474d68c78b8Schristos 475d68c78b8Schristos UNUSED(pub); 476d68c78b8Schristos /* read private key file */ 477d4a20c3eSchristos result = dst__privstruct_parse(key, hmac__to_dst_alg(type), lexer, mctx, 478d68c78b8Schristos &priv); 479d4a20c3eSchristos if (result != ISC_R_SUCCESS) { 480*bcda20f6Schristos return result; 481d4a20c3eSchristos } 482d68c78b8Schristos 483d4a20c3eSchristos if (key->external) { 484d68c78b8Schristos result = DST_R_EXTERNALKEY; 485d4a20c3eSchristos } 486d68c78b8Schristos 487d68c78b8Schristos key->key_bits = 0; 488d68c78b8Schristos for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) { 489d68c78b8Schristos switch (priv.elements[i].tag) { 490d68c78b8Schristos case TAG_HMACMD5_KEY: 491d68c78b8Schristos case TAG_HMACSHA1_KEY: 492d68c78b8Schristos case TAG_HMACSHA224_KEY: 493d68c78b8Schristos case TAG_HMACSHA256_KEY: 494d68c78b8Schristos case TAG_HMACSHA384_KEY: 495d68c78b8Schristos case TAG_HMACSHA512_KEY: 496d68c78b8Schristos isc_buffer_init(&b, priv.elements[i].data, 497d68c78b8Schristos priv.elements[i].length); 498d68c78b8Schristos isc_buffer_add(&b, priv.elements[i].length); 499d4a20c3eSchristos tresult = hmac_fromdns(type, key, &b); 500d4a20c3eSchristos if (tresult != ISC_R_SUCCESS) { 501d68c78b8Schristos result = tresult; 502d4a20c3eSchristos } 503d68c78b8Schristos break; 504d4a20c3eSchristos case TAG_HMACMD5_BITS: 505d4a20c3eSchristos case TAG_HMACSHA1_BITS: 506d4a20c3eSchristos case TAG_HMACSHA224_BITS: 507d4a20c3eSchristos case TAG_HMACSHA256_BITS: 508d4a20c3eSchristos case TAG_HMACSHA384_BITS: 509d68c78b8Schristos case TAG_HMACSHA512_BITS: 510d68c78b8Schristos tresult = getkeybits(key, &priv.elements[i]); 511d4a20c3eSchristos if (tresult != ISC_R_SUCCESS) { 512d68c78b8Schristos result = tresult; 513d4a20c3eSchristos } 514d68c78b8Schristos break; 515d68c78b8Schristos default: 516d68c78b8Schristos result = DST_R_INVALIDPRIVATEKEY; 517d68c78b8Schristos break; 518d68c78b8Schristos } 519d68c78b8Schristos } 520d68c78b8Schristos dst__privstruct_free(&priv, mctx); 521d68c78b8Schristos isc_safe_memwipe(&priv, sizeof(priv)); 522*bcda20f6Schristos return result; 523d68c78b8Schristos } 524d68c78b8Schristos 525d4a20c3eSchristos hmac_register_algorithm(md5); 526d4a20c3eSchristos hmac_register_algorithm(sha1); 527d4a20c3eSchristos hmac_register_algorithm(sha224); 528d4a20c3eSchristos hmac_register_algorithm(sha256); 529d4a20c3eSchristos hmac_register_algorithm(sha384); 530d4a20c3eSchristos hmac_register_algorithm(sha512); 531d68c78b8Schristos 532d68c78b8Schristos /*! \file */ 533