xref: /openbsd/usr.bin/dig/lib/dns/dst_api.c (revision 1fb015a8)
1 /*
2  * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
9  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
11  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
14  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  *
16  * See the COPYRIGHT file distributed with this work for additional
17  * information regarding copyright ownership.
18  *
19  * Portions Copyright (C) Network Associates, Inc.
20  *
21  * Permission to use, copy, modify, and/or distribute this software for any
22  * purpose with or without fee is hereby granted, provided that the above
23  * copyright notice and this permission notice appear in all copies.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
26  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
27  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
28  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
29  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
30  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
31  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32  */
33 
34 /*
35  * Principal Author: Brian Wellington
36  * $Id: dst_api.c,v 1.16 2020/09/14 08:40:43 florian Exp $
37  */
38 
39 /*! \file */
40 #include <stdlib.h>
41 #include <string.h>
42 
43 #include <isc/buffer.h>
44 #include <isc/refcount.h>
45 #include <isc/util.h>
46 
47 #include <dns/keyvalues.h>
48 
49 #include <dst/result.h>
50 
51 #include "dst_internal.h"
52 
53 static dst_func_t *dst_t_func[DST_MAX_ALGS];
54 static int dst_initialized = 0;
55 
56 /*
57  * Static functions.
58  */
59 static dst_key_t *	get_key_struct(unsigned int alg,
60 				       unsigned int flags,
61 				       unsigned int protocol,
62 				       unsigned int bits);
63 static isc_result_t	computeid(dst_key_t *key);
64 static isc_result_t	frombuffer(unsigned int alg,
65 				   unsigned int flags,
66 				   unsigned int protocol,
67 				   isc_buffer_t *source,
68 				   dst_key_t **keyp);
69 
70 static isc_result_t	algorithm_status(unsigned int alg);
71 
72 #define RETERR(x)				\
73 	do {					\
74 		result = (x);			\
75 		if (result != ISC_R_SUCCESS)	\
76 			goto out;		\
77 	} while (0)
78 
79 #define CHECKALG(alg)				\
80 	do {					\
81 		isc_result_t _r;		\
82 		_r = algorithm_status(alg);	\
83 		if (_r != ISC_R_SUCCESS)	\
84 			return (_r);		\
85 	} while (0);				\
86 
87 isc_result_t
dst_lib_init(void)88 dst_lib_init(void) {
89 	isc_result_t result;
90 
91 	REQUIRE(!dst_initialized);
92 
93 	dst_result_register();
94 
95 	memset(dst_t_func, 0, sizeof(dst_t_func));
96 	RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
97 	RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
98 	RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
99 	RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
100 	RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
101 	RETERR(dst__openssl_init());
102 	dst_initialized = 1;
103 	return (ISC_R_SUCCESS);
104 
105  out:
106 	/* avoid immediate crash! */
107 	dst_initialized = 1;
108 	dst_lib_destroy();
109 	return (result);
110 }
111 
112 void
dst_lib_destroy(void)113 dst_lib_destroy(void) {
114 	RUNTIME_CHECK(dst_initialized);
115 	dst_initialized = 0;
116 
117 	dst__openssl_destroy();
118 }
119 
120 int
dst_algorithm_supported(unsigned int alg)121 dst_algorithm_supported(unsigned int alg) {
122 	REQUIRE(dst_initialized);
123 
124 	if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
125 		return (0);
126 	return (1);
127 }
128 
129 isc_result_t
dst_context_create3(dst_key_t * key,isc_logcategory_t * category,int useforsigning,dst_context_t ** dctxp)130 dst_context_create3(dst_key_t *key,
131 		    isc_logcategory_t *category, int useforsigning,
132 		    dst_context_t **dctxp)
133 {
134 	dst_context_t *dctx;
135 	isc_result_t result;
136 
137 	REQUIRE(dst_initialized);
138 	REQUIRE(dctxp != NULL && *dctxp == NULL);
139 
140 	dctx = malloc(sizeof(dst_context_t));
141 	if (dctx == NULL)
142 		return (ISC_R_NOMEMORY);
143 	memset(dctx, 0, sizeof(*dctx));
144 	dst_key_attach(key, &dctx->key);
145 	dctx->category = category;
146 	if (useforsigning)
147 		dctx->use = DO_SIGN;
148 	else
149 		dctx->use = DO_VERIFY;
150 	result = key->func->createctx(key, dctx);
151 	if (result != ISC_R_SUCCESS) {
152 		if (dctx->key != NULL)
153 			dst_key_free(&dctx->key);
154 		free(dctx);
155 		return (result);
156 	}
157 	*dctxp = dctx;
158 	return (ISC_R_SUCCESS);
159 }
160 
161 void
dst_context_destroy(dst_context_t ** dctxp)162 dst_context_destroy(dst_context_t **dctxp) {
163 	dst_context_t *dctx;
164 
165 	REQUIRE(dctxp != NULL);
166 
167 	dctx = *dctxp;
168 	dctx->key->func->destroyctx(dctx);
169 	if (dctx->key != NULL)
170 		dst_key_free(&dctx->key);
171 	free(dctx);
172 	*dctxp = NULL;
173 }
174 
175 isc_result_t
dst_context_adddata(dst_context_t * dctx,const isc_region_t * data)176 dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
177 	REQUIRE(data != NULL);
178 	return (dctx->key->func->adddata(dctx, data));
179 }
180 
181 isc_result_t
dst_context_sign(dst_context_t * dctx,isc_buffer_t * sig)182 dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
183 	dst_key_t *key;
184 
185 	REQUIRE(sig != NULL);
186 
187 	key = dctx->key;
188 	CHECKALG(key->key_alg);
189 
190 	return (key->func->sign(dctx, sig));
191 }
192 
193 isc_result_t
dst_context_verify(dst_context_t * dctx,isc_region_t * sig)194 dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
195 	REQUIRE(sig != NULL);
196 
197 	CHECKALG(dctx->key->key_alg);
198 
199 	return (dctx->key->func->verify(dctx, sig));
200 }
201 
202 isc_result_t
dst_key_todns(const dst_key_t * key,isc_buffer_t * target)203 dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
204 	REQUIRE(dst_initialized);
205 	REQUIRE(target != NULL);
206 
207 	CHECKALG(key->key_alg);
208 
209 	if (isc_buffer_availablelength(target) < 4)
210 		return (ISC_R_NOSPACE);
211 	isc_buffer_putuint16(target, (uint16_t)(key->key_flags & 0xffff));
212 	isc_buffer_putuint8(target, (uint8_t)key->key_proto);
213 	isc_buffer_putuint8(target, (uint8_t)key->key_alg);
214 
215 	if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
216 		if (isc_buffer_availablelength(target) < 2)
217 			return (ISC_R_NOSPACE);
218 		isc_buffer_putuint16(target,
219 				     (uint16_t)((key->key_flags >> 16)
220 						    & 0xffff));
221 	}
222 
223 	return (key->func->todns(key, target));
224 }
225 
226 isc_result_t
dst_key_frombuffer(unsigned int alg,unsigned int flags,unsigned int protocol,isc_buffer_t * source,dst_key_t ** keyp)227 dst_key_frombuffer(unsigned int alg, unsigned int flags, unsigned int protocol,
228 		   isc_buffer_t *source, dst_key_t **keyp)
229 {
230 	dst_key_t *key = NULL;
231 	isc_result_t result;
232 
233 	REQUIRE(dst_initialized);
234 
235 	result = frombuffer(alg, flags, protocol, source, &key);
236 	if (result != ISC_R_SUCCESS)
237 		return (result);
238 
239 	result = computeid(key);
240 	if (result != ISC_R_SUCCESS) {
241 		dst_key_free(&key);
242 		return (result);
243 	}
244 
245 	*keyp = key;
246 	return (ISC_R_SUCCESS);
247 }
248 
249 void
dst_key_attach(dst_key_t * source,dst_key_t ** target)250 dst_key_attach(dst_key_t *source, dst_key_t **target) {
251 
252 	REQUIRE(dst_initialized);
253 	REQUIRE(target != NULL && *target == NULL);
254 
255 	isc_refcount_increment(&source->refs, NULL);
256 	*target = source;
257 }
258 
259 void
dst_key_free(dst_key_t ** keyp)260 dst_key_free(dst_key_t **keyp) {
261 	dst_key_t *key;
262 	unsigned int refs;
263 
264 	REQUIRE(dst_initialized);
265 	REQUIRE(keyp != NULL);
266 
267 	key = *keyp;
268 
269 	isc_refcount_decrement(&key->refs, &refs);
270 	if (refs != 0)
271 		return;
272 
273 	isc_refcount_destroy(&key->refs);
274 	key->func->destroy(key);
275 	freezero(key, sizeof(*key));
276 	*keyp = NULL;
277 }
278 
279 isc_result_t
dst_key_sigsize(const dst_key_t * key,unsigned int * n)280 dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
281 	REQUIRE(dst_initialized);
282 	REQUIRE(n != NULL);
283 
284 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
285 	switch (key->key_alg) {
286 	case DST_ALG_HMACSHA1:
287 		*n = ISC_SHA1_DIGESTLENGTH;
288 		break;
289 	case DST_ALG_HMACSHA224:
290 		*n = ISC_SHA224_DIGESTLENGTH;
291 		break;
292 	case DST_ALG_HMACSHA256:
293 		*n = ISC_SHA256_DIGESTLENGTH;
294 		break;
295 	case DST_ALG_HMACSHA384:
296 		*n = ISC_SHA384_DIGESTLENGTH;
297 		break;
298 	case DST_ALG_HMACSHA512:
299 		*n = ISC_SHA512_DIGESTLENGTH;
300 		break;
301 	default:
302 		return (DST_R_UNSUPPORTEDALG);
303 	}
304 	return (ISC_R_SUCCESS);
305 }
306 
307 /***
308  *** Static methods
309  ***/
310 
311 /*%
312  * Allocates a key structure and fills in some of the fields.
313  */
314 static dst_key_t *
get_key_struct(unsigned int alg,unsigned int flags,unsigned int protocol,unsigned int bits)315 get_key_struct(unsigned int alg,
316 	       unsigned int flags, unsigned int protocol,
317 	       unsigned int bits)
318 {
319 	dst_key_t *key;
320 	isc_result_t result;
321 
322 	key = (dst_key_t *) malloc(sizeof(dst_key_t));
323 	if (key == NULL)
324 		return (NULL);
325 
326 	memset(key, 0, sizeof(dst_key_t));
327 
328 	result = isc_refcount_init(&key->refs, 1);
329 	if (result != ISC_R_SUCCESS) {
330 		free(key);
331 		return (NULL);
332 	}
333 	key->key_alg = alg;
334 	key->key_flags = flags;
335 	key->key_proto = protocol;
336 	key->key_size = bits;
337 	key->func = dst_t_func[alg];
338 	return (key);
339 }
340 
341 static isc_result_t
computeid(dst_key_t * key)342 computeid(dst_key_t *key) {
343 	isc_buffer_t dnsbuf;
344 	unsigned char dns_array[DST_KEY_MAXSIZE];
345 	isc_region_t r;
346 	isc_result_t ret;
347 
348 	isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
349 	ret = dst_key_todns(key, &dnsbuf);
350 	if (ret != ISC_R_SUCCESS)
351 		return (ret);
352 
353 	isc_buffer_usedregion(&dnsbuf, &r);
354 	return (ISC_R_SUCCESS);
355 }
356 
357 static isc_result_t
frombuffer(unsigned int alg,unsigned int flags,unsigned int protocol,isc_buffer_t * source,dst_key_t ** keyp)358 frombuffer(unsigned int alg, unsigned int flags,
359 	   unsigned int protocol, isc_buffer_t *source, dst_key_t **keyp)
360 {
361 	dst_key_t *key;
362 	isc_result_t ret;
363 
364 	REQUIRE(source != NULL);
365 	REQUIRE(keyp != NULL && *keyp == NULL);
366 
367 	key = get_key_struct(alg, flags, protocol, 0);
368 	if (key == NULL)
369 		return (ISC_R_NOMEMORY);
370 
371 	if (isc_buffer_remaininglength(source) > 0) {
372 		ret = algorithm_status(alg);
373 		if (ret != ISC_R_SUCCESS) {
374 			dst_key_free(&key);
375 			return (ret);
376 		}
377 
378 		ret = key->func->fromdns(key, source);
379 		if (ret != ISC_R_SUCCESS) {
380 			dst_key_free(&key);
381 			return (ret);
382 		}
383 	}
384 
385 	*keyp = key;
386 	return (ISC_R_SUCCESS);
387 }
388 
389 static isc_result_t
algorithm_status(unsigned int alg)390 algorithm_status(unsigned int alg) {
391 	REQUIRE(dst_initialized);
392 
393 	if (dst_algorithm_supported(alg))
394 		return (ISC_R_SUCCESS);
395 	return (DST_R_UNSUPPORTEDALG);
396 }
397