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