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