xref: /openbsd-src/usr.bin/dig/lib/dns/dst_api.c (revision 1fb015a8af3a7e9b85db2510147a155826ef04d9)
15185a700Sflorian /*
25185a700Sflorian  * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian  *
45185a700Sflorian  * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian  * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian  * copyright notice and this permission notice appear in all copies.
75185a700Sflorian  *
85185a700Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
95185a700Sflorian  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
105185a700Sflorian  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
115185a700Sflorian  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
125185a700Sflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
135185a700Sflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
145185a700Sflorian  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian  *
165185a700Sflorian  * See the COPYRIGHT file distributed with this work for additional
175185a700Sflorian  * information regarding copyright ownership.
185185a700Sflorian  *
195185a700Sflorian  * Portions Copyright (C) Network Associates, Inc.
205185a700Sflorian  *
215185a700Sflorian  * Permission to use, copy, modify, and/or distribute this software for any
225185a700Sflorian  * purpose with or without fee is hereby granted, provided that the above
235185a700Sflorian  * copyright notice and this permission notice appear in all copies.
245185a700Sflorian  *
255185a700Sflorian  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
265185a700Sflorian  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
275185a700Sflorian  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
285185a700Sflorian  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
295185a700Sflorian  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
305185a700Sflorian  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
315185a700Sflorian  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
325185a700Sflorian  */
335185a700Sflorian 
345185a700Sflorian /*
355185a700Sflorian  * Principal Author: Brian Wellington
36*1fb015a8Sflorian  * $Id: dst_api.c,v 1.16 2020/09/14 08:40:43 florian Exp $
375185a700Sflorian  */
385185a700Sflorian 
395185a700Sflorian /*! \file */
405185a700Sflorian #include <stdlib.h>
41d7fbd970Sflorian #include <string.h>
425185a700Sflorian 
435185a700Sflorian #include <isc/buffer.h>
445185a700Sflorian #include <isc/refcount.h>
455185a700Sflorian #include <isc/util.h>
465185a700Sflorian 
475185a700Sflorian #include <dns/keyvalues.h>
485185a700Sflorian 
495185a700Sflorian #include <dst/result.h>
505185a700Sflorian 
515185a700Sflorian #include "dst_internal.h"
525185a700Sflorian 
535185a700Sflorian static dst_func_t *dst_t_func[DST_MAX_ALGS];
54*1fb015a8Sflorian static int dst_initialized = 0;
555185a700Sflorian 
565185a700Sflorian /*
575185a700Sflorian  * Static functions.
585185a700Sflorian  */
5927db9c2cSflorian static dst_key_t *	get_key_struct(unsigned int alg,
605185a700Sflorian 				       unsigned int flags,
615185a700Sflorian 				       unsigned int protocol,
6227db9c2cSflorian 				       unsigned int bits);
635185a700Sflorian static isc_result_t	computeid(dst_key_t *key);
6427db9c2cSflorian static isc_result_t	frombuffer(unsigned int alg,
655185a700Sflorian 				   unsigned int flags,
665185a700Sflorian 				   unsigned int protocol,
675185a700Sflorian 				   isc_buffer_t *source,
685185a700Sflorian 				   dst_key_t **keyp);
695185a700Sflorian 
705185a700Sflorian static isc_result_t	algorithm_status(unsigned int alg);
715185a700Sflorian 
725185a700Sflorian #define RETERR(x)				\
735185a700Sflorian 	do {					\
745185a700Sflorian 		result = (x);			\
755185a700Sflorian 		if (result != ISC_R_SUCCESS)	\
765185a700Sflorian 			goto out;		\
775185a700Sflorian 	} while (0)
785185a700Sflorian 
795185a700Sflorian #define CHECKALG(alg)				\
805185a700Sflorian 	do {					\
815185a700Sflorian 		isc_result_t _r;		\
825185a700Sflorian 		_r = algorithm_status(alg);	\
835185a700Sflorian 		if (_r != ISC_R_SUCCESS)	\
845185a700Sflorian 			return (_r);		\
855185a700Sflorian 	} while (0);				\
865185a700Sflorian 
875185a700Sflorian isc_result_t
dst_lib_init(void)885185a700Sflorian dst_lib_init(void) {
895185a700Sflorian 	isc_result_t result;
905185a700Sflorian 
91*1fb015a8Sflorian 	REQUIRE(!dst_initialized);
925185a700Sflorian 
935185a700Sflorian 	dst_result_register();
945185a700Sflorian 
955185a700Sflorian 	memset(dst_t_func, 0, sizeof(dst_t_func));
965185a700Sflorian 	RETERR(dst__hmacsha1_init(&dst_t_func[DST_ALG_HMACSHA1]));
975185a700Sflorian 	RETERR(dst__hmacsha224_init(&dst_t_func[DST_ALG_HMACSHA224]));
985185a700Sflorian 	RETERR(dst__hmacsha256_init(&dst_t_func[DST_ALG_HMACSHA256]));
995185a700Sflorian 	RETERR(dst__hmacsha384_init(&dst_t_func[DST_ALG_HMACSHA384]));
1005185a700Sflorian 	RETERR(dst__hmacsha512_init(&dst_t_func[DST_ALG_HMACSHA512]));
10159bd6e9fSflorian 	RETERR(dst__openssl_init());
102*1fb015a8Sflorian 	dst_initialized = 1;
1035185a700Sflorian 	return (ISC_R_SUCCESS);
1045185a700Sflorian 
1055185a700Sflorian  out:
1065185a700Sflorian 	/* avoid immediate crash! */
107*1fb015a8Sflorian 	dst_initialized = 1;
1085185a700Sflorian 	dst_lib_destroy();
1095185a700Sflorian 	return (result);
1105185a700Sflorian }
1115185a700Sflorian 
1125185a700Sflorian void
dst_lib_destroy(void)1135185a700Sflorian dst_lib_destroy(void) {
114*1fb015a8Sflorian 	RUNTIME_CHECK(dst_initialized);
115*1fb015a8Sflorian 	dst_initialized = 0;
1165185a700Sflorian 
1175185a700Sflorian 	dst__openssl_destroy();
1185185a700Sflorian }
1195185a700Sflorian 
120*1fb015a8Sflorian int
dst_algorithm_supported(unsigned int alg)1215185a700Sflorian dst_algorithm_supported(unsigned int alg) {
122*1fb015a8Sflorian 	REQUIRE(dst_initialized);
1235185a700Sflorian 
1245185a700Sflorian 	if (alg >= DST_MAX_ALGS || dst_t_func[alg] == NULL)
125*1fb015a8Sflorian 		return (0);
126*1fb015a8Sflorian 	return (1);
1275185a700Sflorian }
1285185a700Sflorian 
1295185a700Sflorian isc_result_t
dst_context_create3(dst_key_t * key,isc_logcategory_t * category,int useforsigning,dst_context_t ** dctxp)1305185a700Sflorian dst_context_create3(dst_key_t *key,
131*1fb015a8Sflorian 		    isc_logcategory_t *category, int useforsigning,
1325185a700Sflorian 		    dst_context_t **dctxp)
1335185a700Sflorian {
1345185a700Sflorian 	dst_context_t *dctx;
1355185a700Sflorian 	isc_result_t result;
1365185a700Sflorian 
137*1fb015a8Sflorian 	REQUIRE(dst_initialized);
1385185a700Sflorian 	REQUIRE(dctxp != NULL && *dctxp == NULL);
1395185a700Sflorian 
1405185a700Sflorian 	dctx = malloc(sizeof(dst_context_t));
1415185a700Sflorian 	if (dctx == NULL)
1425185a700Sflorian 		return (ISC_R_NOMEMORY);
1435185a700Sflorian 	memset(dctx, 0, sizeof(*dctx));
1445185a700Sflorian 	dst_key_attach(key, &dctx->key);
1455185a700Sflorian 	dctx->category = category;
1465185a700Sflorian 	if (useforsigning)
1475185a700Sflorian 		dctx->use = DO_SIGN;
1485185a700Sflorian 	else
1495185a700Sflorian 		dctx->use = DO_VERIFY;
1505185a700Sflorian 	result = key->func->createctx(key, dctx);
1515185a700Sflorian 	if (result != ISC_R_SUCCESS) {
1525185a700Sflorian 		if (dctx->key != NULL)
1535185a700Sflorian 			dst_key_free(&dctx->key);
1545185a700Sflorian 		free(dctx);
1555185a700Sflorian 		return (result);
1565185a700Sflorian 	}
1575185a700Sflorian 	*dctxp = dctx;
1585185a700Sflorian 	return (ISC_R_SUCCESS);
1595185a700Sflorian }
1605185a700Sflorian 
1615185a700Sflorian void
dst_context_destroy(dst_context_t ** dctxp)1625185a700Sflorian dst_context_destroy(dst_context_t **dctxp) {
1635185a700Sflorian 	dst_context_t *dctx;
1645185a700Sflorian 
1658b553854Sflorian 	REQUIRE(dctxp != NULL);
1665185a700Sflorian 
1675185a700Sflorian 	dctx = *dctxp;
1685185a700Sflorian 	dctx->key->func->destroyctx(dctx);
1695185a700Sflorian 	if (dctx->key != NULL)
1705185a700Sflorian 		dst_key_free(&dctx->key);
1715185a700Sflorian 	free(dctx);
1725185a700Sflorian 	*dctxp = NULL;
1735185a700Sflorian }
1745185a700Sflorian 
1755185a700Sflorian isc_result_t
dst_context_adddata(dst_context_t * dctx,const isc_region_t * data)1765185a700Sflorian dst_context_adddata(dst_context_t *dctx, const isc_region_t *data) {
1775185a700Sflorian 	REQUIRE(data != NULL);
1785185a700Sflorian 	return (dctx->key->func->adddata(dctx, data));
1795185a700Sflorian }
1805185a700Sflorian 
1815185a700Sflorian isc_result_t
dst_context_sign(dst_context_t * dctx,isc_buffer_t * sig)1825185a700Sflorian dst_context_sign(dst_context_t *dctx, isc_buffer_t *sig) {
1835185a700Sflorian 	dst_key_t *key;
1845185a700Sflorian 
1855185a700Sflorian 	REQUIRE(sig != NULL);
1865185a700Sflorian 
1875185a700Sflorian 	key = dctx->key;
1885185a700Sflorian 	CHECKALG(key->key_alg);
1895185a700Sflorian 
1905185a700Sflorian 	return (key->func->sign(dctx, sig));
1915185a700Sflorian }
1925185a700Sflorian 
1935185a700Sflorian isc_result_t
dst_context_verify(dst_context_t * dctx,isc_region_t * sig)1945185a700Sflorian dst_context_verify(dst_context_t *dctx, isc_region_t *sig) {
1955185a700Sflorian 	REQUIRE(sig != NULL);
1965185a700Sflorian 
1975185a700Sflorian 	CHECKALG(dctx->key->key_alg);
1985185a700Sflorian 
1995185a700Sflorian 	return (dctx->key->func->verify(dctx, sig));
2005185a700Sflorian }
2015185a700Sflorian 
2025185a700Sflorian isc_result_t
dst_key_todns(const dst_key_t * key,isc_buffer_t * target)2035185a700Sflorian dst_key_todns(const dst_key_t *key, isc_buffer_t *target) {
204*1fb015a8Sflorian 	REQUIRE(dst_initialized);
2055185a700Sflorian 	REQUIRE(target != NULL);
2065185a700Sflorian 
2075185a700Sflorian 	CHECKALG(key->key_alg);
2085185a700Sflorian 
2095185a700Sflorian 	if (isc_buffer_availablelength(target) < 4)
2105185a700Sflorian 		return (ISC_R_NOSPACE);
2115185a700Sflorian 	isc_buffer_putuint16(target, (uint16_t)(key->key_flags & 0xffff));
2125185a700Sflorian 	isc_buffer_putuint8(target, (uint8_t)key->key_proto);
2135185a700Sflorian 	isc_buffer_putuint8(target, (uint8_t)key->key_alg);
2145185a700Sflorian 
2155185a700Sflorian 	if (key->key_flags & DNS_KEYFLAG_EXTENDED) {
2165185a700Sflorian 		if (isc_buffer_availablelength(target) < 2)
2175185a700Sflorian 			return (ISC_R_NOSPACE);
2185185a700Sflorian 		isc_buffer_putuint16(target,
2195185a700Sflorian 				     (uint16_t)((key->key_flags >> 16)
2205185a700Sflorian 						    & 0xffff));
2215185a700Sflorian 	}
2225185a700Sflorian 
2235185a700Sflorian 	return (key->func->todns(key, target));
2245185a700Sflorian }
2255185a700Sflorian 
2265185a700Sflorian isc_result_t
dst_key_frombuffer(unsigned int alg,unsigned int flags,unsigned int protocol,isc_buffer_t * source,dst_key_t ** keyp)22727db9c2cSflorian dst_key_frombuffer(unsigned int alg, unsigned int flags, unsigned int protocol,
2285185a700Sflorian 		   isc_buffer_t *source, dst_key_t **keyp)
2295185a700Sflorian {
2305185a700Sflorian 	dst_key_t *key = NULL;
2315185a700Sflorian 	isc_result_t result;
2325185a700Sflorian 
2335185a700Sflorian 	REQUIRE(dst_initialized);
2345185a700Sflorian 
23527db9c2cSflorian 	result = frombuffer(alg, flags, protocol, source, &key);
2365185a700Sflorian 	if (result != ISC_R_SUCCESS)
2375185a700Sflorian 		return (result);
2385185a700Sflorian 
2395185a700Sflorian 	result = computeid(key);
2405185a700Sflorian 	if (result != ISC_R_SUCCESS) {
2415185a700Sflorian 		dst_key_free(&key);
2425185a700Sflorian 		return (result);
2435185a700Sflorian 	}
2445185a700Sflorian 
2455185a700Sflorian 	*keyp = key;
2465185a700Sflorian 	return (ISC_R_SUCCESS);
2475185a700Sflorian }
2485185a700Sflorian 
2495185a700Sflorian void
dst_key_attach(dst_key_t * source,dst_key_t ** target)2505185a700Sflorian dst_key_attach(dst_key_t *source, dst_key_t **target) {
2515185a700Sflorian 
252*1fb015a8Sflorian 	REQUIRE(dst_initialized);
2535185a700Sflorian 	REQUIRE(target != NULL && *target == NULL);
2545185a700Sflorian 
2555185a700Sflorian 	isc_refcount_increment(&source->refs, NULL);
2565185a700Sflorian 	*target = source;
2575185a700Sflorian }
2585185a700Sflorian 
2595185a700Sflorian void
dst_key_free(dst_key_t ** keyp)2605185a700Sflorian dst_key_free(dst_key_t **keyp) {
2615185a700Sflorian 	dst_key_t *key;
2625185a700Sflorian 	unsigned int refs;
2635185a700Sflorian 
264*1fb015a8Sflorian 	REQUIRE(dst_initialized);
2658b553854Sflorian 	REQUIRE(keyp != NULL);
2665185a700Sflorian 
2675185a700Sflorian 	key = *keyp;
2685185a700Sflorian 
2695185a700Sflorian 	isc_refcount_decrement(&key->refs, &refs);
2705185a700Sflorian 	if (refs != 0)
2715185a700Sflorian 		return;
2725185a700Sflorian 
2735185a700Sflorian 	isc_refcount_destroy(&key->refs);
2745185a700Sflorian 	key->func->destroy(key);
2755a5442cbSderaadt 	freezero(key, sizeof(*key));
2765185a700Sflorian 	*keyp = NULL;
2775185a700Sflorian }
2785185a700Sflorian 
2795185a700Sflorian isc_result_t
dst_key_sigsize(const dst_key_t * key,unsigned int * n)2805185a700Sflorian dst_key_sigsize(const dst_key_t *key, unsigned int *n) {
281*1fb015a8Sflorian 	REQUIRE(dst_initialized);
2825185a700Sflorian 	REQUIRE(n != NULL);
2835185a700Sflorian 
2845185a700Sflorian 	/* XXXVIX this switch statement is too sparse to gen a jump table. */
2855185a700Sflorian 	switch (key->key_alg) {
2865185a700Sflorian 	case DST_ALG_HMACSHA1:
2875185a700Sflorian 		*n = ISC_SHA1_DIGESTLENGTH;
2885185a700Sflorian 		break;
2895185a700Sflorian 	case DST_ALG_HMACSHA224:
2905185a700Sflorian 		*n = ISC_SHA224_DIGESTLENGTH;
2915185a700Sflorian 		break;
2925185a700Sflorian 	case DST_ALG_HMACSHA256:
2935185a700Sflorian 		*n = ISC_SHA256_DIGESTLENGTH;
2945185a700Sflorian 		break;
2955185a700Sflorian 	case DST_ALG_HMACSHA384:
2965185a700Sflorian 		*n = ISC_SHA384_DIGESTLENGTH;
2975185a700Sflorian 		break;
2985185a700Sflorian 	case DST_ALG_HMACSHA512:
2995185a700Sflorian 		*n = ISC_SHA512_DIGESTLENGTH;
3005185a700Sflorian 		break;
3015185a700Sflorian 	default:
3025185a700Sflorian 		return (DST_R_UNSUPPORTEDALG);
3035185a700Sflorian 	}
3045185a700Sflorian 	return (ISC_R_SUCCESS);
3055185a700Sflorian }
3065185a700Sflorian 
3075185a700Sflorian /***
3085185a700Sflorian  *** Static methods
3095185a700Sflorian  ***/
3105185a700Sflorian 
3115185a700Sflorian /*%
3125185a700Sflorian  * Allocates a key structure and fills in some of the fields.
3135185a700Sflorian  */
3145185a700Sflorian static dst_key_t *
get_key_struct(unsigned int alg,unsigned int flags,unsigned int protocol,unsigned int bits)31527db9c2cSflorian get_key_struct(unsigned int alg,
3165185a700Sflorian 	       unsigned int flags, unsigned int protocol,
31727db9c2cSflorian 	       unsigned int bits)
3185185a700Sflorian {
3195185a700Sflorian 	dst_key_t *key;
3205185a700Sflorian 	isc_result_t result;
3215185a700Sflorian 
3225185a700Sflorian 	key = (dst_key_t *) malloc(sizeof(dst_key_t));
3235185a700Sflorian 	if (key == NULL)
3245185a700Sflorian 		return (NULL);
3255185a700Sflorian 
3265185a700Sflorian 	memset(key, 0, sizeof(dst_key_t));
3275185a700Sflorian 
3285185a700Sflorian 	result = isc_refcount_init(&key->refs, 1);
3295185a700Sflorian 	if (result != ISC_R_SUCCESS) {
3305185a700Sflorian 		free(key);
3315185a700Sflorian 		return (NULL);
3325185a700Sflorian 	}
3335185a700Sflorian 	key->key_alg = alg;
3345185a700Sflorian 	key->key_flags = flags;
3355185a700Sflorian 	key->key_proto = protocol;
3365185a700Sflorian 	key->key_size = bits;
3375185a700Sflorian 	key->func = dst_t_func[alg];
3385185a700Sflorian 	return (key);
3395185a700Sflorian }
3405185a700Sflorian 
3415185a700Sflorian static isc_result_t
computeid(dst_key_t * key)3425185a700Sflorian computeid(dst_key_t *key) {
3435185a700Sflorian 	isc_buffer_t dnsbuf;
3445185a700Sflorian 	unsigned char dns_array[DST_KEY_MAXSIZE];
3455185a700Sflorian 	isc_region_t r;
3465185a700Sflorian 	isc_result_t ret;
3475185a700Sflorian 
3485185a700Sflorian 	isc_buffer_init(&dnsbuf, dns_array, sizeof(dns_array));
3495185a700Sflorian 	ret = dst_key_todns(key, &dnsbuf);
3505185a700Sflorian 	if (ret != ISC_R_SUCCESS)
3515185a700Sflorian 		return (ret);
3525185a700Sflorian 
3535185a700Sflorian 	isc_buffer_usedregion(&dnsbuf, &r);
3545185a700Sflorian 	return (ISC_R_SUCCESS);
3555185a700Sflorian }
3565185a700Sflorian 
3575185a700Sflorian static isc_result_t
frombuffer(unsigned int alg,unsigned int flags,unsigned int protocol,isc_buffer_t * source,dst_key_t ** keyp)35827db9c2cSflorian frombuffer(unsigned int alg, unsigned int flags,
35927db9c2cSflorian 	   unsigned int protocol, isc_buffer_t *source, dst_key_t **keyp)
3605185a700Sflorian {
3615185a700Sflorian 	dst_key_t *key;
3625185a700Sflorian 	isc_result_t ret;
3635185a700Sflorian 
3645185a700Sflorian 	REQUIRE(source != NULL);
3655185a700Sflorian 	REQUIRE(keyp != NULL && *keyp == NULL);
3665185a700Sflorian 
36727db9c2cSflorian 	key = get_key_struct(alg, flags, protocol, 0);
3685185a700Sflorian 	if (key == NULL)
3695185a700Sflorian 		return (ISC_R_NOMEMORY);
3705185a700Sflorian 
3715185a700Sflorian 	if (isc_buffer_remaininglength(source) > 0) {
3725185a700Sflorian 		ret = algorithm_status(alg);
3735185a700Sflorian 		if (ret != ISC_R_SUCCESS) {
3745185a700Sflorian 			dst_key_free(&key);
3755185a700Sflorian 			return (ret);
3765185a700Sflorian 		}
3775185a700Sflorian 
3785185a700Sflorian 		ret = key->func->fromdns(key, source);
3795185a700Sflorian 		if (ret != ISC_R_SUCCESS) {
3805185a700Sflorian 			dst_key_free(&key);
3815185a700Sflorian 			return (ret);
3825185a700Sflorian 		}
3835185a700Sflorian 	}
3845185a700Sflorian 
3855185a700Sflorian 	*keyp = key;
3865185a700Sflorian 	return (ISC_R_SUCCESS);
3875185a700Sflorian }
3885185a700Sflorian 
3895185a700Sflorian static isc_result_t
algorithm_status(unsigned int alg)3905185a700Sflorian algorithm_status(unsigned int alg) {
391*1fb015a8Sflorian 	REQUIRE(dst_initialized);
3925185a700Sflorian 
3935185a700Sflorian 	if (dst_algorithm_supported(alg))
3945185a700Sflorian 		return (ISC_R_SUCCESS);
3955185a700Sflorian 	return (DST_R_UNSUPPORTEDALG);
3965185a700Sflorian }
397