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