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 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 113 dst_lib_destroy(void) { 114 RUNTIME_CHECK(dst_initialized); 115 dst_initialized = 0; 116 117 dst__openssl_destroy(); 118 } 119 120 int 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 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