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