hmac_link.c 13.4 KB
Newer Older
1
/*
Evan Hunt's avatar
Evan Hunt committed
2
 * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
Automatic Updater's avatar
Automatic Updater committed
3
 *
4 5 6
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Automatic Updater's avatar
Automatic Updater committed
7
 *
8 9 10 11
 * See the COPYRIGHT file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * Portions Copyright (C) Network Associates, Inc.
12
 *
Automatic Updater's avatar
Automatic Updater committed
13
 * Permission to use, copy, modify, and/or distribute this software for any
14 15
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
16
 *
Mark Andrews's avatar
Mark Andrews committed
17 18 19 20 21 22 23
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 25 26 27
 */

#include <config.h>

28
#include <stdbool.h>
29
#include <arpa/inet.h>
30

31
#include <isc/buffer.h>
32 33
#include <isc/hmac.h>
#include <isc/md.h>
34
#include <isc/nonce.h>
35
#include <isc/random.h>
36
#include <isc/mem.h>
Evan Hunt's avatar
Evan Hunt committed
37
#include <isc/safe.h>
38
#include <isc/string.h>
Bob Halley's avatar
Bob Halley committed
39
#include <isc/util.h>
40

41 42
#include <pk11/site.h>

43 44
#include <dst/result.h>

45
#include "dst_internal.h"
46 47 48
#ifdef HAVE_FIPS_MODE
#include "dst_openssl.h"	/* FIPS_mode() prototype */
#endif
49 50
#include "dst_parse.h"

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
#define ISC_MD_md5    ISC_MD_MD5
#define ISC_MD_sha1   ISC_MD_SHA1
#define ISC_MD_sha224 ISC_MD_SHA224
#define ISC_MD_sha256 ISC_MD_SHA256
#define ISC_MD_sha384 ISC_MD_SHA384
#define ISC_MD_sha512 ISC_MD_SHA512

#define hmac_register_algorithm(alg)					\
	static isc_result_t					\
	hmac##alg##_createctx(dst_key_t *key,				\
			      dst_context_t *dctx) {			\
		return (hmac_createctx(ISC_MD_##alg, key, dctx));	\
	}								\
	static void						\
	hmac##alg##_destroyctx(dst_context_t *dctx) {			\
		hmac_destroyctx(dctx);					\
	}								\
	static isc_result_t					\
	hmac##alg##_adddata(dst_context_t *dctx,			\
			    const isc_region_t *data) {			\
		return (hmac_adddata(dctx, data));			\
	}								\
	static isc_result_t					\
	hmac##alg##_sign(dst_context_t *dctx,				\
			 isc_buffer_t *sig) {				\
		return (hmac_sign(dctx, sig));				\
	}								\
	static isc_result_t					\
	hmac##alg##_verify(dst_context_t *dctx,				\
			   const isc_region_t *sig) {			\
		return (hmac_verify(dctx, sig));			\
	}								\
	static bool						\
	hmac##alg##_compare(const dst_key_t *key1,			\
			    const dst_key_t *key2) {			\
		return (hmac_compare(ISC_MD_##alg, key1, key2));	\
	}								\
	static isc_result_t					\
	hmac##alg##_generate(dst_key_t *key,				\
			     int pseudorandom_ok,			\
			     void (*callback)(int)) {			\
		UNUSED(pseudorandom_ok);				\
		UNUSED(callback);					\
		return (hmac_generate(ISC_MD_##alg, key));		\
	}								\
	static bool						\
	hmac##alg##_isprivate(const dst_key_t *key) {			\
		return (hmac_isprivate(key));				\
	}								\
	static void						\
	hmac##alg##_destroy(dst_key_t *key) {				\
		hmac_destroy(key);					\
	}								\
	static isc_result_t						\
	hmac##alg##_todns(const dst_key_t *key, isc_buffer_t *data) {	\
		return (hmac_todns(key, data));				\
	}								\
	static isc_result_t					\
	hmac##alg##_fromdns(dst_key_t *key, isc_buffer_t *data) {	\
		return (hmac_fromdns(ISC_MD_##alg, key, data));		\
	}								\
	static isc_result_t					\
	hmac##alg##_tofile(const dst_key_t *key, const char *directory) { \
		return (hmac_tofile(ISC_MD_##alg, key, directory));	\
	}								\
	static isc_result_t					\
	hmac##alg##_parse(dst_key_t *key, isc_lex_t *lexer,		\
			  dst_key_t *pub) {				\
		return(hmac_parse(ISC_MD_##alg, key, lexer, pub));	\
	}								\
	static dst_func_t hmac##alg##_functions = {			\
		hmac##alg##_createctx,					\
		NULL, /*%< createctx2 */				\
		hmac##alg##_destroyctx,					\
		hmac##alg##_adddata,					\
		hmac##alg##_sign,					\
		hmac##alg##_verify,					\
		NULL, /*%< verify2 */					\
		NULL, /*%< computesecret */				\
		hmac##alg##_compare,					\
		NULL, /*%< paramcompare */				\
		hmac##alg##_generate,					\
		hmac##alg##_isprivate,					\
		hmac##alg##_destroy,					\
		hmac##alg##_todns,					\
		hmac##alg##_fromdns,					\
		hmac##alg##_tofile,					\
		hmac##alg##_parse,					\
		NULL, /*%< cleanup */					\
		NULL, /*%< fromlabel */					\
		NULL, /*%< dump */					\
		NULL, /*%< restore */					\
	};								\
	isc_result_t							\
	dst__hmac##alg##_init(dst_func_t **funcp) {			\
		REQUIRE(funcp != NULL);					\
		if (*funcp == NULL) {					\
			*funcp = &hmac##alg##_functions;		\
		}							\
		return (ISC_R_SUCCESS);					\
	}

static isc_result_t
hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data);
155

156 157
struct dst_hmac_key  {
	uint8_t key[ISC_MAX_BLOCK_SIZE];
158
};
159

160
static inline isc_result_t
161
getkeybits(dst_key_t *key, struct dst_private_element *element) {
162
	uint16_t *bits = (uint16_t *)element->data;
163

164
	if (element->length != 2) {
165
		return (DST_R_INVALIDPRIVATEKEY);
166
	}
167

168
	key->key_bits =	ntohs(*bits);
169

170
	return (ISC_R_SUCCESS);
171 172
}

173 174 175
static inline isc_result_t
hmac_createctx(isc_md_type_t type, const dst_key_t *key,
	       dst_context_t *dctx)
176
{
177 178 179 180 181 182 183 184
	isc_result_t result;
	const dst_hmac_key_t *hkey = key->keydata.hmac_key;
	isc_hmac_t *ctx = isc_hmac_new(); /* Either returns or abort()s */

	result = isc_hmac_init(ctx, hkey->key,
			       isc_md_type_get_block_size(type), type);
	if (result != ISC_R_SUCCESS) {
		return (DST_R_UNSUPPORTEDALG);
185
	}
186

187
	dctx->ctxdata.hmac_ctx = ctx;
Brian Wellington's avatar
Brian Wellington committed
188
	return (ISC_R_SUCCESS);
189 190
}

191 192 193 194
static inline void
hmac_destroyctx(dst_context_t *dctx) {
	isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
	REQUIRE(ctx != NULL);
195

196 197 198
	isc_hmac_free(ctx);
	dctx->ctxdata.hmac_ctx = NULL;
}
199

200 201 202 203
static inline isc_result_t
hmac_adddata(const dst_context_t *dctx, const isc_region_t *data) {
	isc_result_t result;
	isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
204

205
	REQUIRE(ctx != NULL);
206

207 208 209
	result = isc_hmac_update(ctx, data->base, data->length);
	if (result != ISC_R_SUCCESS) {
		return (DST_R_OPENSSLFAILURE);
210
	}
211

Brian Wellington's avatar
Brian Wellington committed
212
	return (ISC_R_SUCCESS);
213 214
}

215 216 217 218 219 220
static inline isc_result_t
hmac_sign(const dst_context_t *dctx, isc_buffer_t *sig) {
	isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
	REQUIRE(ctx != NULL);
	unsigned int digestlen;
	unsigned char digest[ISC_MAX_MD_SIZE];
221

222 223
	if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) {
		return (DST_R_OPENSSLFAILURE);
224
	}
225

226 227
	if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) {
		return (DST_R_OPENSSLFAILURE);
228
	}
229

230 231
	if (isc_buffer_availablelength(sig) < digestlen) {
		return (ISC_R_NOSPACE);
232 233
	}

234
	isc_buffer_putmem(sig, digest, digestlen);
235 236 237 238

	return (ISC_R_SUCCESS);
}

239 240 241 242 243
static inline isc_result_t
hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) {
	isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
	unsigned int digestlen;
	unsigned char digest[ISC_MAX_MD_SIZE];
244

245
	REQUIRE(ctx != NULL);
246

247 248 249
	if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) {
		return (DST_R_OPENSSLFAILURE);
	}
250

251 252 253
	if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) {
		return (DST_R_OPENSSLFAILURE);
	}
254

255
	if (sig->length > digestlen) {
256
		return (DST_R_VERIFYFAILURE);
257
	}
258

259 260 261
	return (isc_safe_memequal(digest, sig->base, sig->length) ?
		ISC_R_SUCCESS :
		DST_R_VERIFYFAILURE);
262 263
}

264 265 266
static inline bool
hmac_compare(isc_md_type_t type, const dst_key_t *key1, const dst_key_t *key2) {
	dst_hmac_key_t *hkey1, *hkey2;
267

268 269
	hkey1 = key1->keydata.hmac_key;
	hkey2 = key2->keydata.hmac_key;
270

271
	if (hkey1 == NULL && hkey2 == NULL) {
272
		return (true);
273
	} else if (hkey1 == NULL || hkey2 == NULL) {
274
		return (false);
275
	}
276

277 278
	return (isc_safe_memequal(hkey1->key, hkey2->key,
				  isc_md_type_get_block_size(type)));
279 280
}

281 282
static inline isc_result_t
hmac_generate(isc_md_type_t type, dst_key_t *key) {
283 284
	isc_buffer_t b;
	isc_result_t ret;
285 286
	unsigned int bytes, len;
	unsigned char data[ISC_MAX_MD_SIZE] = { 0 };
287

288
	len = isc_md_type_get_block_size(type);
289

290
	bytes = (key->key_size + 7) / 8;
291 292 293 294

	if (bytes > len) {
		bytes = len;
		key->key_size = len * 8;
295 296
	}

297
	isc_nonce_buf(data, bytes);
298 299 300

	isc_buffer_init(&b, data, bytes);
	isc_buffer_add(&b, bytes);
301 302 303

	ret = hmac_fromdns(type, key, &b);

304
	isc_safe_memwipe(data, sizeof(data));
305 306 307 308

	return (ret);
}

309 310
static inline bool
hmac_isprivate(const dst_key_t *key) {
311
	UNUSED(key);
312
	return (true);
313 314
}

315 316 317
static inline void
hmac_destroy(dst_key_t *key) {
	dst_hmac_key_t *hkey = key->keydata.hmac_key;
318 319
	isc_safe_memwipe(hkey, sizeof(*hkey));
	isc_mem_put(key->mctx, hkey, sizeof(*hkey));
320
	key->keydata.hmac_key = NULL;
321 322
}

323 324 325
static inline isc_result_t
hmac_todns(const dst_key_t *key, isc_buffer_t *data) {
	dst_hmac_key_t *hkey = key->keydata.hmac_key;
326 327
	unsigned int bytes;

328
	REQUIRE(hkey != NULL);
329 330

	bytes = (key->key_size + 7) / 8;
331
	if (isc_buffer_availablelength(data) < bytes) {
332
		return (ISC_R_NOSPACE);
333
	}
334 335 336 337 338
	isc_buffer_putmem(data, hkey->key, bytes);

	return (ISC_R_SUCCESS);
}

339 340 341
static inline isc_result_t
hmac_fromdns(isc_md_type_t type, dst_key_t *key, isc_buffer_t *data) {
	dst_hmac_key_t *hkey;
342
	unsigned int keylen;
343 344 345
	isc_region_t r;

	isc_buffer_remainingregion(data, &r);
346
	if (r.length == 0) {
347
		return (ISC_R_SUCCESS);
348
	}
349

350 351
	hkey = isc_mem_get(key->mctx, sizeof(dst_hmac_key_t));
	if (hkey == NULL) {
352
		return (ISC_R_NOMEMORY);
353
	}
354 355 356

	memset(hkey->key, 0, sizeof(hkey->key));

357 358 359 360 361
	/* Hash the key if the key is longer then chosen MD block size */
	if (r.length > (unsigned int)isc_md_type_get_block_size(type)) {
		if (isc_md(type, r.base, r.length, hkey->key, &keylen)
		    != ISC_R_SUCCESS) {
			return (DST_R_OPENSSLFAILURE);
362
		}
363 364
	} else {
		memmove(hkey->key, r.base, r.length);
365 366 367 368
		keylen = r.length;
	}

	key->key_size = keylen * 8;
369
	key->keydata.hmac_key = hkey;
370

371 372
	isc_buffer_forward(data, r.length);

373 374 375
	return (ISC_R_SUCCESS);
}

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
static inline int
hmac__get_tag_key(isc_md_type_t type) {
	if (type == ISC_MD_MD5) {
		return (TAG_HMACMD5_KEY);
	} else if (type == ISC_MD_SHA1) {
		return (TAG_HMACSHA1_KEY);
	} else if (type == ISC_MD_SHA224) {
		return (TAG_HMACSHA224_KEY);
	} else if (type == ISC_MD_SHA256) {
		return (TAG_HMACSHA256_KEY);
	} else if (type == ISC_MD_SHA384) {
		return (TAG_HMACSHA384_KEY);
	} else if (type == ISC_MD_SHA512) {
		return (TAG_HMACSHA512_KEY);
	} else {
		INSIST(0);
	}
}

static inline int
hmac__get_tag_bits(isc_md_type_t type) {
	if (type == ISC_MD_MD5) {
		return (TAG_HMACMD5_BITS);
	} else if (type == ISC_MD_SHA1) {
		return (TAG_HMACSHA1_BITS);
	} else if (type == ISC_MD_SHA224) {
		return (TAG_HMACSHA224_BITS);
	} else if (type == ISC_MD_SHA256) {
		return (TAG_HMACSHA256_BITS);
	} else if (type == ISC_MD_SHA384) {
		return (TAG_HMACSHA384_BITS);
	} else if (type == ISC_MD_SHA512) {
		return (TAG_HMACSHA512_BITS);
	} else {
		INSIST(0);
	}
}

static inline isc_result_t
hmac_tofile(isc_md_type_t type, const dst_key_t *key, const char *directory) {
	dst_hmac_key_t *hkey;
417 418
	dst_private_t priv;
	int bytes = (key->key_size + 7) / 8;
419
	uint16_t bits;
420

421
	if (key->keydata.hmac_key == NULL) {
422
		return (DST_R_NULLKEY);
423
	}
424

425
	if (key->external) {
426
		return (DST_R_EXTERNALKEY);
427 428 429
	}

	hkey = key->keydata.hmac_key;
430

431 432 433
	priv.elements[0].tag = hmac__get_tag_key(type);
	priv.elements[0].length = bytes;
	priv.elements[0].data = hkey->key;
434

435
	bits = htons(key->key_bits);
436

437 438 439 440 441
	priv.elements[1].tag = hmac__get_tag_bits(type);
	priv.elements[1].length = sizeof(bits);
	priv.elements[1].data = (uint8_t *)&bits;

	priv.nelements = 2;
442 443 444 445

	return (dst__privstruct_writefile(key, &priv, directory));
}

446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468
static inline int
hmac__to_dst_alg(isc_md_type_t type) {
	if (type == ISC_MD_MD5) {
		return (DST_ALG_HMACMD5);
	} else if (type == ISC_MD_SHA1) {
		return (DST_ALG_HMACSHA1);
	} else if (type == ISC_MD_SHA224) {
		return (DST_ALG_HMACSHA224);
	} else if (type == ISC_MD_SHA256) {
		return (DST_ALG_HMACSHA256);
	} else if (type == ISC_MD_SHA384) {
		return (DST_ALG_HMACSHA384);
	} else if (type == ISC_MD_SHA512) {
		return (DST_ALG_HMACSHA512);
	} else {
		INSIST(0);
	}
}

static inline isc_result_t
hmac_parse(isc_md_type_t type, dst_key_t *key,
	   isc_lex_t *lexer, dst_key_t *pub)
{
469 470 471 472 473 474
	dst_private_t priv;
	isc_result_t result, tresult;
	isc_buffer_t b;
	isc_mem_t *mctx = key->mctx;
	unsigned int i;

475
	UNUSED(pub);
476
	/* read private key file */
477
	result = dst__privstruct_parse(key, hmac__to_dst_alg(type), lexer, mctx,
478
				       &priv);
479
	if (result != ISC_R_SUCCESS) {
480
		return (result);
481
	}
482

483
	if (key->external) {
484
		result = DST_R_EXTERNALKEY;
485
	}
486

487
	key->key_bits = 0;
488
	for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
489
		switch (priv.elements[i].tag) {
490
		case TAG_HMACMD5_KEY:
491
		case TAG_HMACSHA1_KEY:
492 493 494 495
		case TAG_HMACSHA224_KEY:
		case TAG_HMACSHA256_KEY:
		case TAG_HMACSHA384_KEY:
		case TAG_HMACSHA512_KEY:
496
			isc_buffer_init(&b, priv.elements[i].data,
Automatic Updater's avatar
Automatic Updater committed
497
					priv.elements[i].length);
498
			isc_buffer_add(&b, priv.elements[i].length);
499 500
			tresult = hmac_fromdns(type, key, &b);
			if (tresult != ISC_R_SUCCESS) {
501
				result = tresult;
502
			}
503
			break;
504
		case TAG_HMACMD5_BITS:
505
		case TAG_HMACSHA1_BITS:
506 507 508 509
		case TAG_HMACSHA224_BITS:
		case TAG_HMACSHA256_BITS:
		case TAG_HMACSHA384_BITS:
		case TAG_HMACSHA512_BITS:
510
			tresult = getkeybits(key, &priv.elements[i]);
511
			if (tresult != ISC_R_SUCCESS) {
512
				result = tresult;
513
			}
514 515 516 517 518 519 520
			break;
		default:
			result = DST_R_INVALIDPRIVATEKEY;
			break;
		}
	}
	dst__privstruct_free(&priv, mctx);
521
	isc_safe_memwipe(&priv, sizeof(priv));
522 523 524
	return (result);
}

525 526 527 528 529 530
hmac_register_algorithm(md5);
hmac_register_algorithm(sha1);
hmac_register_algorithm(sha224);
hmac_register_algorithm(sha256);
hmac_register_algorithm(sha384);
hmac_register_algorithm(sha512);
531

532
/*! \file */