hmac_link.c 43.9 KB
Newer Older
1
/*
2
 * Portions Copyright (C) 1999-2002, 2004-2018  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
 * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
9
 *
Automatic Updater's avatar
Automatic Updater committed
10
 * Permission to use, copy, modify, and/or distribute this software for any
11 12
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
13
 *
Mark Andrews's avatar
Mark Andrews committed
14 15 16 17 18 19 20
 * 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.
21 22 23 24 25 26 27 28
 */

/*
 * Principal Author: Brian Wellington
 */

#include <config.h>

29 30
#include <isc/buffer.h>
#include <isc/hmacmd5.h>
31
#include <isc/hmacsha.h>
32
#include <isc/md5.h>
33
#include <isc/sha1.h>
34
#include <isc/mem.h>
Evan Hunt's avatar
Evan Hunt committed
35
#include <isc/safe.h>
36
#include <isc/string.h>
Bob Halley's avatar
Bob Halley committed
37
#include <isc/util.h>
38

39 40
#include <pk11/site.h>

41 42
#include <dst/result.h>

43
#include "dst_internal.h"
44
#include "dst_openssl.h"
45 46
#include "dst_parse.h"

47
#ifndef PK11_MD5_DISABLE
48 49
static isc_result_t hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data);

50
struct dst_hmacmd5_key {
51
	unsigned char key[ISC_MD5_BLOCK_LENGTH];
52
};
53
#endif
54

55 56 57 58 59 60 61 62 63 64 65
static isc_result_t
getkeybits(dst_key_t *key, struct dst_private_element *element) {

	if (element->length != 2)
		return (DST_R_INVALIDPRIVATEKEY);

	key->key_bits =	(element->data[0] << 8) + element->data[1];

	return (ISC_R_SUCCESS);
}

66
#ifndef PK11_MD5_DISABLE
67
static isc_result_t
68
hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) {
69
	isc_hmacmd5_t *hmacmd5ctx;
70
	dst_hmacmd5_key_t *hkey = key->keydata.hmacmd5;
71

72 73
	hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t));
	if (hmacmd5ctx == NULL)
74
		return (ISC_R_NOMEMORY);
75
	isc_hmacmd5_init(hmacmd5ctx, hkey->key, ISC_MD5_BLOCK_LENGTH);
76
	dctx->ctxdata.hmacmd5ctx = hmacmd5ctx;
77 78
	return (ISC_R_SUCCESS);
}
79

80 81
static void
hmacmd5_destroyctx(dst_context_t *dctx) {
82
	isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx;
83

84 85 86
	if (hmacmd5ctx != NULL) {
		isc_hmacmd5_invalidate(hmacmd5ctx);
		isc_mem_put(dctx->mctx, hmacmd5ctx, sizeof(isc_hmacmd5_t));
87
		dctx->ctxdata.hmacmd5ctx = NULL;
88
	}
89
}
90 91

static isc_result_t
92
hmacmd5_adddata(dst_context_t *dctx, const isc_region_t *data) {
93
	isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx;
94

95
	isc_hmacmd5_update(hmacmd5ctx, data->base, data->length);
96
	return (ISC_R_SUCCESS);
97
}
98 99

static isc_result_t
100
hmacmd5_sign(dst_context_t *dctx, isc_buffer_t *sig) {
101
	isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx;
102
	unsigned char *digest;
103 104 105 106 107

	if (isc_buffer_availablelength(sig) < ISC_MD5_DIGESTLENGTH)
		return (ISC_R_NOSPACE);
	digest = isc_buffer_used(sig);
	isc_hmacmd5_sign(hmacmd5ctx, digest);
108
	isc_buffer_add(sig, ISC_MD5_DIGESTLENGTH);
109

110
	return (ISC_R_SUCCESS);
111 112
}

113
static isc_result_t
114
hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) {
115
	isc_hmacmd5_t *hmacmd5ctx = dctx->ctxdata.hmacmd5ctx;
Brian Wellington's avatar
Brian Wellington committed
116

117
	if (sig->length > ISC_MD5_DIGESTLENGTH)
118
		return (DST_R_VERIFYFAILURE);
119

120
	if (isc_hmacmd5_verify2(hmacmd5ctx, sig->base, sig->length))
121 122
		return (ISC_R_SUCCESS);
	else
123
		return (DST_R_VERIFYFAILURE);
124 125
}

126 127
static isc_boolean_t
hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) {
128
	dst_hmacmd5_key_t *hkey1, *hkey2;
129

130 131
	hkey1 = key1->keydata.hmacmd5;
	hkey2 = key2->keydata.hmacmd5;
Brian Wellington's avatar
Brian Wellington committed
132

133
	if (hkey1 == NULL && hkey2 == NULL)
134 135 136
		return (ISC_TRUE);
	else if (hkey1 == NULL || hkey2 == NULL)
		return (ISC_FALSE);
Brian Wellington's avatar
Brian Wellington committed
137

138
	if (isc_safe_memequal(hkey1->key, hkey2->key, ISC_MD5_BLOCK_LENGTH))
139 140 141 142
		return (ISC_TRUE);
	else
		return (ISC_FALSE);
}
143

144
static isc_result_t
145
hmacmd5_generate(dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) {
146 147
	isc_buffer_t b;
	isc_result_t ret;
148
	unsigned int bytes;
149
	unsigned char data[ISC_MD5_BLOCK_LENGTH];
150

151 152
	UNUSED(callback);

153
	bytes = (key->key_size + 7) / 8;
154 155 156
	if (bytes > ISC_MD5_BLOCK_LENGTH) {
		bytes = ISC_MD5_BLOCK_LENGTH;
		key->key_size = ISC_MD5_BLOCK_LENGTH * 8;
157
	}
158

159
	memset(data, 0, ISC_MD5_BLOCK_LENGTH);
160
	ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
161

162 163
	if (ret != ISC_R_SUCCESS)
		return (ret);
164

165 166
	isc_buffer_init(&b, data, bytes);
	isc_buffer_add(&b, bytes);
167
	ret = hmacmd5_fromdns(key, &b);
168
	isc_safe_memwipe(data, sizeof(data));
169

170
	return (ret);
171 172
}

173
static isc_boolean_t
174
hmacmd5_isprivate(const dst_key_t *key) {
175
	UNUSED(key);
Brian Wellington's avatar
Brian Wellington committed
176
	return (ISC_TRUE);
177 178
}

179 180
static void
hmacmd5_destroy(dst_key_t *key) {
181
	dst_hmacmd5_key_t *hkey = key->keydata.hmacmd5;
182

183 184
	isc_safe_memwipe(hkey, sizeof(*hkey));
	isc_mem_put(key->mctx, hkey, sizeof(*hkey));
185
	key->keydata.hmacmd5 = NULL;
186 187
}

188
static isc_result_t
189
hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) {
190
	dst_hmacmd5_key_t *hkey;
191
	unsigned int bytes;
192

193
	REQUIRE(key->keydata.hmacmd5 != NULL);
194

195
	hkey = key->keydata.hmacmd5;
196 197

	bytes = (key->key_size + 7) / 8;
198
	if (isc_buffer_availablelength(data) < bytes)
Brian Wellington's avatar
Brian Wellington committed
199
		return (ISC_R_NOSPACE);
200
	isc_buffer_putmem(data, hkey->key, bytes);
201

Brian Wellington's avatar
Brian Wellington committed
202
	return (ISC_R_SUCCESS);
203 204
}

205
static isc_result_t
206
hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
207
	dst_hmacmd5_key_t *hkey;
208
	int keylen;
209
	isc_region_t r;
210
	isc_md5_t md5ctx;
211

212
	isc_buffer_remainingregion(data, &r);
213
	if (r.length == 0)
Brian Wellington's avatar
Brian Wellington committed
214
		return (ISC_R_SUCCESS);
215

216
	hkey = isc_mem_get(key->mctx, sizeof(dst_hmacmd5_key_t));
217
	if (hkey == NULL)
Brian Wellington's avatar
Brian Wellington committed
218
		return (ISC_R_NOMEMORY);
219

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

222
	if (r.length > ISC_MD5_BLOCK_LENGTH) {
223 224 225 226
		isc_md5_init(&md5ctx);
		isc_md5_update(&md5ctx, r.base, r.length);
		isc_md5_final(&md5ctx, hkey->key);
		keylen = ISC_MD5_DIGESTLENGTH;
227 228
	} else {
		memmove(hkey->key, r.base, r.length);
229 230
		keylen = r.length;
	}
231

232
	key->key_size = keylen * 8;
233
	key->keydata.hmacmd5 = hkey;
234

235 236
	isc_buffer_forward(data, r.length);

Brian Wellington's avatar
Brian Wellington committed
237
	return (ISC_R_SUCCESS);
238 239
}

240
static isc_result_t
Brian Wellington's avatar
Brian Wellington committed
241
hmacmd5_tofile(const dst_key_t *key, const char *directory) {
242
	int cnt = 0;
243
	dst_hmacmd5_key_t *hkey;
244
	dst_private_t priv;
245
	int bytes = (key->key_size + 7) / 8;
246
	unsigned char buf[2];
247

248
	if (key->keydata.hmacmd5 == NULL)
Brian Wellington's avatar
Brian Wellington committed
249
		return (DST_R_NULLKEY);
250

251 252 253
	if (key->external)
		return (DST_R_EXTERNALKEY);

254
	hkey = key->keydata.hmacmd5;
255 256

	priv.elements[cnt].tag = TAG_HMACMD5_KEY;
257
	priv.elements[cnt].length = bytes;
258
	priv.elements[cnt++].data = hkey->key;
259

260 261 262 263 264 265
	buf[0] = (key->key_bits >> 8) & 0xffU;
	buf[1] = key->key_bits & 0xffU;
	priv.elements[cnt].tag = TAG_HMACMD5_BITS;
	priv.elements[cnt].data = buf;
	priv.elements[cnt++].length = 2;

266
	priv.nelements = cnt;
Brian Wellington's avatar
Brian Wellington committed
267
	return (dst__privstruct_writefile(key, &priv, directory));
268 269
}

270
static isc_result_t
271
hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
272
	dst_private_t priv;
273
	isc_result_t result, tresult;
274
	isc_buffer_t b;
275
	isc_mem_t *mctx = key->mctx;
276
	unsigned int i;
277

278
	UNUSED(pub);
279
	/* read private key file */
280 281
	result = dst__privstruct_parse(key, DST_ALG_HMACMD5, lexer, mctx,
				       &priv);
282 283
	if (result != ISC_R_SUCCESS)
		return (result);
284

285 286 287
	if (key->external)
		result = DST_R_EXTERNALKEY;

288 289 290 291 292
	key->key_bits = 0;
	for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
		switch (priv.elements[i].tag) {
		case TAG_HMACMD5_KEY:
			isc_buffer_init(&b, priv.elements[i].data,
Automatic Updater's avatar
Automatic Updater committed
293
					priv.elements[i].length);
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
			isc_buffer_add(&b, priv.elements[i].length);
			tresult = hmacmd5_fromdns(key, &b);
			if (tresult != ISC_R_SUCCESS)
				result = tresult;
			break;
		case TAG_HMACMD5_BITS:
			tresult = getkeybits(key, &priv.elements[i]);
			if (tresult != ISC_R_SUCCESS)
				result = tresult;
			break;
		default:
			result = DST_R_INVALIDPRIVATEKEY;
			break;
		}
	}
Brian Wellington's avatar
Brian Wellington committed
309
	dst__privstruct_free(&priv, mctx);
310
	isc_safe_memwipe(&priv, sizeof(priv));
311
	return (result);
312 313
}

Brian Wellington's avatar
Brian Wellington committed
314
static dst_func_t hmacmd5_functions = {
315
	hmacmd5_createctx,
Evan Hunt's avatar
Evan Hunt committed
316
	NULL, /*%< createctx2 */
317 318 319 320
	hmacmd5_destroyctx,
	hmacmd5_adddata,
	hmacmd5_sign,
	hmacmd5_verify,
321
	NULL, /*%< verify2 */
322
	NULL, /*%< computesecret */
323
	hmacmd5_compare,
324
	NULL, /*%< paramcompare */
325 326 327 328 329 330
	hmacmd5_generate,
	hmacmd5_isprivate,
	hmacmd5_destroy,
	hmacmd5_todns,
	hmacmd5_fromdns,
	hmacmd5_tofile,
331
	hmacmd5_parse,
332
	NULL, /*%< cleanup */
Francis Dupont's avatar
Francis Dupont committed
333
	NULL, /*%< fromlabel */
334 335
	NULL, /*%< dump */
	NULL, /*%< restore */
336
};
337

Brian Wellington's avatar
Brian Wellington committed
338
isc_result_t
Brian Wellington's avatar
Brian Wellington committed
339
dst__hmacmd5_init(dst_func_t **funcp) {
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
#ifdef HAVE_FIPS_MODE
	/*
	 * Problems from OpenSSL are likely from FIPS mode
	 */
	int fips_mode = FIPS_mode();

	if (fips_mode != 0) {
		UNEXPECTED_ERROR(__FILE__, __LINE__,
				 "FIPS mode is %d: MD5 is only supported "
				 "if the value is 0.\n"
				 "Please disable either FIPS mode or MD5.",
				 fips_mode);
	}
#endif

	/*
	 * Prevent use of incorrect crypto
	 */

	RUNTIME_CHECK(isc_md5_check(ISC_FALSE));
	RUNTIME_CHECK(isc_hmacmd5_check(0));

362 363 364
	REQUIRE(funcp != NULL);
	if (*funcp == NULL)
		*funcp = &hmacmd5_functions;
Brian Wellington's avatar
Brian Wellington committed
365 366
	return (ISC_R_SUCCESS);
}
367
#endif
368

369 370
static isc_result_t hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data);

371
struct dst_hmacsha1_key {
372
	unsigned char key[ISC_SHA1_BLOCK_LENGTH];
373
};
374 375 376 377

static isc_result_t
hmacsha1_createctx(dst_key_t *key, dst_context_t *dctx) {
	isc_hmacsha1_t *hmacsha1ctx;
378
	dst_hmacsha1_key_t *hkey = key->keydata.hmacsha1;
379 380 381 382

	hmacsha1ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha1_t));
	if (hmacsha1ctx == NULL)
		return (ISC_R_NOMEMORY);
383
	isc_hmacsha1_init(hmacsha1ctx, hkey->key, ISC_SHA1_BLOCK_LENGTH);
384
	dctx->ctxdata.hmacsha1ctx = hmacsha1ctx;
385 386 387 388 389
	return (ISC_R_SUCCESS);
}

static void
hmacsha1_destroyctx(dst_context_t *dctx) {
390
	isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx;
391 392 393 394

	if (hmacsha1ctx != NULL) {
		isc_hmacsha1_invalidate(hmacsha1ctx);
		isc_mem_put(dctx->mctx, hmacsha1ctx, sizeof(isc_hmacsha1_t));
395
		dctx->ctxdata.hmacsha1ctx = NULL;
396 397 398 399 400
	}
}

static isc_result_t
hmacsha1_adddata(dst_context_t *dctx, const isc_region_t *data) {
401
	isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx;
402 403 404 405 406 407 408

	isc_hmacsha1_update(hmacsha1ctx, data->base, data->length);
	return (ISC_R_SUCCESS);
}

static isc_result_t
hmacsha1_sign(dst_context_t *dctx, isc_buffer_t *sig) {
409
	isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx;
410 411 412 413 414 415 416 417 418 419 420 421 422
	unsigned char *digest;

	if (isc_buffer_availablelength(sig) < ISC_SHA1_DIGESTLENGTH)
		return (ISC_R_NOSPACE);
	digest = isc_buffer_used(sig);
	isc_hmacsha1_sign(hmacsha1ctx, digest, ISC_SHA1_DIGESTLENGTH);
	isc_buffer_add(sig, ISC_SHA1_DIGESTLENGTH);

	return (ISC_R_SUCCESS);
}

static isc_result_t
hmacsha1_verify(dst_context_t *dctx, const isc_region_t *sig) {
423
	isc_hmacsha1_t *hmacsha1ctx = dctx->ctxdata.hmacsha1ctx;
424 425 426 427 428 429 430 431 432 433 434 435

	if (sig->length > ISC_SHA1_DIGESTLENGTH || sig->length == 0)
		return (DST_R_VERIFYFAILURE);

	if (isc_hmacsha1_verify(hmacsha1ctx, sig->base, sig->length))
		return (ISC_R_SUCCESS);
	else
		return (DST_R_VERIFYFAILURE);
}

static isc_boolean_t
hmacsha1_compare(const dst_key_t *key1, const dst_key_t *key2) {
436
	dst_hmacsha1_key_t *hkey1, *hkey2;
437

438 439
	hkey1 = key1->keydata.hmacsha1;
	hkey2 = key2->keydata.hmacsha1;
440 441 442 443 444 445

	if (hkey1 == NULL && hkey2 == NULL)
		return (ISC_TRUE);
	else if (hkey1 == NULL || hkey2 == NULL)
		return (ISC_FALSE);

446
	if (isc_safe_memequal(hkey1->key, hkey2->key, ISC_SHA1_BLOCK_LENGTH))
447 448 449 450 451 452
		return (ISC_TRUE);
	else
		return (ISC_FALSE);
}

static isc_result_t
453
hmacsha1_generate(dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) {
454 455
	isc_buffer_t b;
	isc_result_t ret;
456 457
	unsigned int bytes;
	unsigned char data[ISC_SHA1_BLOCK_LENGTH];
458

459 460
	UNUSED(callback);

461
	bytes = (key->key_size + 7) / 8;
462 463 464
	if (bytes > ISC_SHA1_BLOCK_LENGTH) {
		bytes = ISC_SHA1_BLOCK_LENGTH;
		key->key_size = ISC_SHA1_BLOCK_LENGTH * 8;
465 466
	}

467
	memset(data, 0, ISC_SHA1_BLOCK_LENGTH);
468 469 470 471 472 473 474 475
	ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));

	if (ret != ISC_R_SUCCESS)
		return (ret);

	isc_buffer_init(&b, data, bytes);
	isc_buffer_add(&b, bytes);
	ret = hmacsha1_fromdns(key, &b);
476
	isc_safe_memwipe(data, sizeof(data));
477 478 479 480 481 482 483 484 485 486 487 488

	return (ret);
}

static isc_boolean_t
hmacsha1_isprivate(const dst_key_t *key) {
	UNUSED(key);
	return (ISC_TRUE);
}

static void
hmacsha1_destroy(dst_key_t *key) {
489
	dst_hmacsha1_key_t *hkey = key->keydata.hmacsha1;
490

491 492
	isc_safe_memwipe(hkey, sizeof(*hkey));
	isc_mem_put(key->mctx, hkey, sizeof(*hkey));
493
	key->keydata.hmacsha1 = NULL;
494 495 496 497
}

static isc_result_t
hmacsha1_todns(const dst_key_t *key, isc_buffer_t *data) {
498
	dst_hmacsha1_key_t *hkey;
499 500
	unsigned int bytes;

501
	REQUIRE(key->keydata.hmacsha1 != NULL);
502

503
	hkey = key->keydata.hmacsha1;
504 505 506 507 508 509 510 511 512 513 514

	bytes = (key->key_size + 7) / 8;
	if (isc_buffer_availablelength(data) < bytes)
		return (ISC_R_NOSPACE);
	isc_buffer_putmem(data, hkey->key, bytes);

	return (ISC_R_SUCCESS);
}

static isc_result_t
hmacsha1_fromdns(dst_key_t *key, isc_buffer_t *data) {
515
	dst_hmacsha1_key_t *hkey;
516 517 518 519 520 521 522 523
	int keylen;
	isc_region_t r;
	isc_sha1_t sha1ctx;

	isc_buffer_remainingregion(data, &r);
	if (r.length == 0)
		return (ISC_R_SUCCESS);

524
	hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha1_key_t));
525 526 527 528 529
	if (hkey == NULL)
		return (ISC_R_NOMEMORY);

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

530
	if (r.length > ISC_SHA1_BLOCK_LENGTH) {
531 532 533 534
		isc_sha1_init(&sha1ctx);
		isc_sha1_update(&sha1ctx, r.base, r.length);
		isc_sha1_final(&sha1ctx, hkey->key);
		keylen = ISC_SHA1_DIGESTLENGTH;
535 536
	} else {
		memmove(hkey->key, r.base, r.length);
537 538 539 540
		keylen = r.length;
	}

	key->key_size = keylen * 8;
541
	key->keydata.hmacsha1 = hkey;
542

543 544
	isc_buffer_forward(data, r.length);

545 546 547 548 549 550
	return (ISC_R_SUCCESS);
}

static isc_result_t
hmacsha1_tofile(const dst_key_t *key, const char *directory) {
	int cnt = 0;
551
	dst_hmacsha1_key_t *hkey;
552 553 554 555
	dst_private_t priv;
	int bytes = (key->key_size + 7) / 8;
	unsigned char buf[2];

556
	if (key->keydata.hmacsha1 == NULL)
557 558
		return (DST_R_NULLKEY);

559 560 561
	if (key->external)
		return (DST_R_EXTERNALKEY);

562
	hkey = key->keydata.hmacsha1;
563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578

	priv.elements[cnt].tag = TAG_HMACSHA1_KEY;
	priv.elements[cnt].length = bytes;
	priv.elements[cnt++].data = hkey->key;

	buf[0] = (key->key_bits >> 8) & 0xffU;
	buf[1] = key->key_bits & 0xffU;
	priv.elements[cnt].tag = TAG_HMACSHA1_BITS;
	priv.elements[cnt].data = buf;
	priv.elements[cnt++].length = 2;

	priv.nelements = cnt;
	return (dst__privstruct_writefile(key, &priv, directory));
}

static isc_result_t
579
hmacsha1_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
580 581 582 583 584 585
	dst_private_t priv;
	isc_result_t result, tresult;
	isc_buffer_t b;
	isc_mem_t *mctx = key->mctx;
	unsigned int i;

586
	UNUSED(pub);
587 588 589 590 591 592
	/* read private key file */
	result = dst__privstruct_parse(key, DST_ALG_HMACSHA1, lexer, mctx,
				       &priv);
	if (result != ISC_R_SUCCESS)
		return (result);

593 594 595
	if (key->external)
		result = DST_R_EXTERNALKEY;

596
	key->key_bits = 0;
597
	for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
598 599 600
		switch (priv.elements[i].tag) {
		case TAG_HMACSHA1_KEY:
			isc_buffer_init(&b, priv.elements[i].data,
Automatic Updater's avatar
Automatic Updater committed
601
					priv.elements[i].length);
602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617
			isc_buffer_add(&b, priv.elements[i].length);
			tresult = hmacsha1_fromdns(key, &b);
			if (tresult != ISC_R_SUCCESS)
				result = tresult;
			break;
		case TAG_HMACSHA1_BITS:
			tresult = getkeybits(key, &priv.elements[i]);
			if (tresult != ISC_R_SUCCESS)
				result = tresult;
			break;
		default:
			result = DST_R_INVALIDPRIVATEKEY;
			break;
		}
	}
	dst__privstruct_free(&priv, mctx);
618
	isc_safe_memwipe(&priv, sizeof(priv));
619 620 621 622 623
	return (result);
}

static dst_func_t hmacsha1_functions = {
	hmacsha1_createctx,
Evan Hunt's avatar
Evan Hunt committed
624
	NULL, /*%< createctx2 */
625 626 627 628
	hmacsha1_destroyctx,
	hmacsha1_adddata,
	hmacsha1_sign,
	hmacsha1_verify,
629
	NULL, /* verify2 */
630 631 632 633 634 635 636 637 638 639 640
	NULL, /* computesecret */
	hmacsha1_compare,
	NULL, /* paramcompare */
	hmacsha1_generate,
	hmacsha1_isprivate,
	hmacsha1_destroy,
	hmacsha1_todns,
	hmacsha1_fromdns,
	hmacsha1_tofile,
	hmacsha1_parse,
	NULL, /* cleanup */
Francis Dupont's avatar
Francis Dupont committed
641
	NULL, /* fromlabel */
642 643
	NULL, /* dump */
	NULL, /* restore */
644 645 646 647
};

isc_result_t
dst__hmacsha1_init(dst_func_t **funcp) {
648 649 650 651 652 653
	/*
	 * Prevent use of incorrect crypto
	 */
	RUNTIME_CHECK(isc_sha1_check(ISC_FALSE));
	RUNTIME_CHECK(isc_hmacsha1_check(0));

654 655 656 657 658 659 660 661
	REQUIRE(funcp != NULL);
	if (*funcp == NULL)
		*funcp = &hmacsha1_functions;
	return (ISC_R_SUCCESS);
}

static isc_result_t hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data);

662
struct dst_hmacsha224_key {
663
	unsigned char key[ISC_SHA224_BLOCK_LENGTH];
664
};
665 666 667 668

static isc_result_t
hmacsha224_createctx(dst_key_t *key, dst_context_t *dctx) {
	isc_hmacsha224_t *hmacsha224ctx;
669
	dst_hmacsha224_key_t *hkey = key->keydata.hmacsha224;
670 671 672 673

	hmacsha224ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacsha224_t));
	if (hmacsha224ctx == NULL)
		return (ISC_R_NOMEMORY);
674
	isc_hmacsha224_init(hmacsha224ctx, hkey->key, ISC_SHA224_BLOCK_LENGTH);
675
	dctx->ctxdata.hmacsha224ctx = hmacsha224ctx;
676 677 678 679 680
	return (ISC_R_SUCCESS);
}

static void
hmacsha224_destroyctx(dst_context_t *dctx) {
681
	isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx;
682 683 684 685

	if (hmacsha224ctx != NULL) {
		isc_hmacsha224_invalidate(hmacsha224ctx);
		isc_mem_put(dctx->mctx, hmacsha224ctx, sizeof(isc_hmacsha224_t));
686
		dctx->ctxdata.hmacsha224ctx = NULL;
687 688 689 690 691
	}
}

static isc_result_t
hmacsha224_adddata(dst_context_t *dctx, const isc_region_t *data) {
692
	isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx;
693 694 695 696 697 698 699

	isc_hmacsha224_update(hmacsha224ctx, data->base, data->length);
	return (ISC_R_SUCCESS);
}

static isc_result_t
hmacsha224_sign(dst_context_t *dctx, isc_buffer_t *sig) {
700
	isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx;
701 702 703 704 705 706 707 708 709 710 711 712 713
	unsigned char *digest;

	if (isc_buffer_availablelength(sig) < ISC_SHA224_DIGESTLENGTH)
		return (ISC_R_NOSPACE);
	digest = isc_buffer_used(sig);
	isc_hmacsha224_sign(hmacsha224ctx, digest, ISC_SHA224_DIGESTLENGTH);
	isc_buffer_add(sig, ISC_SHA224_DIGESTLENGTH);

	return (ISC_R_SUCCESS);
}

static isc_result_t
hmacsha224_verify(dst_context_t *dctx, const isc_region_t *sig) {
714
	isc_hmacsha224_t *hmacsha224ctx = dctx->ctxdata.hmacsha224ctx;
715 716 717 718 719 720 721 722 723 724 725 726

	if (sig->length > ISC_SHA224_DIGESTLENGTH || sig->length == 0)
		return (DST_R_VERIFYFAILURE);

	if (isc_hmacsha224_verify(hmacsha224ctx, sig->base, sig->length))
		return (ISC_R_SUCCESS);
	else
		return (DST_R_VERIFYFAILURE);
}

static isc_boolean_t
hmacsha224_compare(const dst_key_t *key1, const dst_key_t *key2) {
727
	dst_hmacsha224_key_t *hkey1, *hkey2;
728

729 730
	hkey1 = key1->keydata.hmacsha224;
	hkey2 = key2->keydata.hmacsha224;
731 732 733 734 735 736

	if (hkey1 == NULL && hkey2 == NULL)
		return (ISC_TRUE);
	else if (hkey1 == NULL || hkey2 == NULL)
		return (ISC_FALSE);

737
	if (isc_safe_memequal(hkey1->key, hkey2->key, ISC_SHA224_BLOCK_LENGTH))
738 739 740 741 742 743
		return (ISC_TRUE);
	else
		return (ISC_FALSE);
}

static isc_result_t
744 745 746
hmacsha224_generate(dst_key_t *key, int pseudorandom_ok,
		    void (*callback)(int))
{
747 748
	isc_buffer_t b;
	isc_result_t ret;
749 750
	unsigned int bytes;
	unsigned char data[ISC_SHA224_BLOCK_LENGTH];
751

752 753
	UNUSED(callback);

754
	bytes = (key->key_size + 7) / 8;
755 756 757
	if (bytes > ISC_SHA224_BLOCK_LENGTH) {
		bytes = ISC_SHA224_BLOCK_LENGTH;
		key->key_size = ISC_SHA224_BLOCK_LENGTH * 8;
758 759
	}

760
	memset(data, 0, ISC_SHA224_BLOCK_LENGTH);
761 762 763 764 765 766 767 768
	ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));

	if (ret != ISC_R_SUCCESS)
		return (ret);

	isc_buffer_init(&b, data, bytes);
	isc_buffer_add(&b, bytes);
	ret = hmacsha224_fromdns(key, &b);
769
	isc_safe_memwipe(data, sizeof(data));
770 771 772 773 774 775 776 777 778 779 780 781

	return (ret);
}

static isc_boolean_t
hmacsha224_isprivate(const dst_key_t *key) {
	UNUSED(key);
	return (ISC_TRUE);
}

static void
hmacsha224_destroy(dst_key_t *key) {
782
	dst_hmacsha224_key_t *hkey = key->keydata.hmacsha224;
783

784 785
	isc_safe_memwipe(hkey, sizeof(*hkey));
	isc_mem_put(key->mctx, hkey, sizeof(*hkey));
786
	key->keydata.hmacsha224 = NULL;
787 788 789 790
}

static isc_result_t
hmacsha224_todns(const dst_key_t *key, isc_buffer_t *data) {
791
	dst_hmacsha224_key_t *hkey;
792 793
	unsigned int bytes;

794
	REQUIRE(key->keydata.hmacsha224 != NULL);
795

796
	hkey = key->keydata.hmacsha224;
797 798 799 800 801 802 803 804 805 806 807

	bytes = (key->key_size + 7) / 8;
	if (isc_buffer_availablelength(data) < bytes)
		return (ISC_R_NOSPACE);
	isc_buffer_putmem(data, hkey->key, bytes);

	return (ISC_R_SUCCESS);
}

static isc_result_t
hmacsha224_fromdns(dst_key_t *key, isc_buffer_t *data) {
808
	dst_hmacsha224_key_t *hkey;
809 810 811 812 813 814 815 816
	int keylen;
	isc_region_t r;
	isc_sha224_t sha224ctx;

	isc_buffer_remainingregion(data, &r);
	if (r.length == 0)
		return (ISC_R_SUCCESS);

817
	hkey = isc_mem_get(key->mctx, sizeof(dst_hmacsha224_key_t));
818 819 820 821 822
	if (hkey == NULL)
		return (ISC_R_NOMEMORY);

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

823
	if (r.length > ISC_SHA224_BLOCK_LENGTH) {
824 825 826 827
		isc_sha224_init(&sha224ctx);
		isc_sha224_update(&sha224ctx, r.base, r.length);
		isc_sha224_final(hkey->key, &sha224ctx);
		keylen = ISC_SHA224_DIGESTLENGTH;
828 829
	} else {
		memmove(hkey->key, r.base, r.length);
830 831 832 833
		keylen = r.length;
	}

	key->key_size = keylen * 8;
834
	key->keydata.hmacsha224 = hkey;
835

836 837
	isc_buffer_forward(data, r.length);

838 839 840 841 842 843
	return (ISC_R_SUCCESS);
}

static isc_result_t
hmacsha224_tofile(const dst_key_t *key, const char *directory) {
	int cnt = 0;
844
	dst_hmacsha224_key_t *hkey;
845 846 847 848
	dst_private_t priv;
	int bytes = (key->key_size + 7) / 8;
	unsigned char buf[2];

849
	if (key->keydata.hmacsha224 == NULL)
850 851
		return (DST_R_NULLKEY);

852 853 854
	if (key->external)
		return (DST_R_EXTERNALKEY);

855
	hkey = key->keydata.hmacsha224;
856 857 858 859 860 861 862 863 864 865 866 867 868 869