xref: /netbsd-src/external/mpl/bind/dist/lib/dns/hmac_link.c (revision bcda20f65a8566e103791ec395f7f499ef322704)
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