Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / isccc / cc.c
blobdd60479c8727bf1ec20bf0fc334f1184871eb247
1 /* $NetBSD: cc.c,v 1.8 2014/12/10 04:38:01 christos Exp $ */
3 /*
4 * Portions Copyright (C) 2004-2007, 2012, 2013 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 2001-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
12 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
13 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Portions Copyright (C) 2001 Nominum, Inc.
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.
25 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
26 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY
28 * 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
31 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
34 /* Id: cc.c,v 1.18 2007/08/28 07:20:43 tbox Exp */
36 /*! \file */
38 #include <config.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <errno.h>
44 #include <isc/assertions.h>
45 #include <isc/hmacmd5.h>
46 #include <isc/hmacsha.h>
47 #include <isc/print.h>
48 #include <isc/safe.h>
49 #include <isc/stdlib.h>
51 #include <isccc/alist.h>
52 #include <isccc/base64.h>
53 #include <isccc/cc.h>
54 #include <isccc/result.h>
55 #include <isccc/sexpr.h>
56 #include <isccc/symtab.h>
57 #include <isccc/symtype.h>
58 #include <isccc/util.h>
60 #define MAX_TAGS 256
61 #define DUP_LIFETIME 900
63 typedef isccc_sexpr_t *sexpr_ptr;
65 static unsigned char auth_hmd5[] = {
66 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
67 ISCCC_CCMSGTYPE_TABLE, /*%< message type */
68 0x00, 0x00, 0x00, 0x20, /*%< length == 32 */
69 0x04, 0x68, 0x6d, 0x64, 0x35, /*%< len + hmd5 */
70 ISCCC_CCMSGTYPE_BINARYDATA, /*%< message type */
71 0x00, 0x00, 0x00, 0x16, /*%< length == 22 */
73 * The base64 encoding of one of our HMAC-MD5 signatures is
74 * 22 bytes.
76 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
77 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
81 #define HMD5_OFFSET 21 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
82 #define HMD5_LENGTH 22
84 static unsigned char auth_hsha[] = {
85 0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
86 ISCCC_CCMSGTYPE_TABLE, /*%< message type */
87 0x00, 0x00, 0x00, 0x63, /*%< length == 99 */
88 0x04, 0x68, 0x73, 0x68, 0x61, /*%< len + hsha */
89 ISCCC_CCMSGTYPE_BINARYDATA, /*%< message type */
90 0x00, 0x00, 0x00, 0x59, /*%< length == 89 */
91 0x00, /*%< algorithm */
93 * The base64 encoding of one of our HMAC-SHA* signatures is
94 * 88 bytes.
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
99 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
103 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
104 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
109 #define HSHA_OFFSET 22 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 + 1 */
110 #define HSHA_LENGTH 88
112 static isc_result_t
113 table_towire(isccc_sexpr_t *alist, isccc_region_t *target);
115 static isc_result_t
116 list_towire(isccc_sexpr_t *alist, isccc_region_t *target);
118 static isc_result_t
119 value_towire(isccc_sexpr_t *elt, isccc_region_t *target)
121 unsigned int len;
122 unsigned char *lenp;
123 isccc_region_t *vr;
124 isc_result_t result;
126 if (isccc_sexpr_binaryp(elt)) {
127 vr = isccc_sexpr_tobinary(elt);
128 len = REGION_SIZE(*vr);
129 if (REGION_SIZE(*target) < 1 + 4 + len)
130 return (ISC_R_NOSPACE);
131 PUT8(ISCCC_CCMSGTYPE_BINARYDATA, target->rstart);
132 PUT32(len, target->rstart);
133 if (REGION_SIZE(*target) < len)
134 return (ISC_R_NOSPACE);
135 PUT_MEM(vr->rstart, len, target->rstart);
136 } else if (isccc_alist_alistp(elt)) {
137 if (REGION_SIZE(*target) < 1 + 4)
138 return (ISC_R_NOSPACE);
139 PUT8(ISCCC_CCMSGTYPE_TABLE, target->rstart);
141 * Emit a placeholder length.
143 lenp = target->rstart;
144 PUT32(0, target->rstart);
146 * Emit the table.
148 result = table_towire(elt, target);
149 if (result != ISC_R_SUCCESS)
150 return (result);
151 len = (unsigned int)(target->rstart - lenp);
153 * 'len' is 4 bytes too big, since it counts
154 * the placeholder length too. Adjust and
155 * emit.
157 INSIST(len >= 4U);
158 len -= 4;
159 PUT32(len, lenp);
160 } else if (isccc_sexpr_listp(elt)) {
161 if (REGION_SIZE(*target) < 1 + 4)
162 return (ISC_R_NOSPACE);
163 PUT8(ISCCC_CCMSGTYPE_LIST, target->rstart);
165 * Emit a placeholder length and count.
167 lenp = target->rstart;
168 PUT32(0, target->rstart);
170 * Emit the list.
172 result = list_towire(elt, target);
173 if (result != ISC_R_SUCCESS)
174 return (result);
175 len = (unsigned int)(target->rstart - lenp);
177 * 'len' is 4 bytes too big, since it counts
178 * the placeholder length. Adjust and emit.
180 INSIST(len >= 4U);
181 len -= 4;
182 PUT32(len, lenp);
185 return (ISC_R_SUCCESS);
188 static isc_result_t
189 table_towire(isccc_sexpr_t *alist, isccc_region_t *target)
191 isccc_sexpr_t *kv, *elt, *k, *v;
192 char *ks;
193 isc_result_t result;
194 size_t len;
196 for (elt = isccc_alist_first(alist);
197 elt != NULL;
198 elt = ISCCC_SEXPR_CDR(elt)) {
199 kv = ISCCC_SEXPR_CAR(elt);
200 k = ISCCC_SEXPR_CAR(kv);
201 ks = isccc_sexpr_tostring(k);
202 v = ISCCC_SEXPR_CDR(kv);
203 len = strlen(ks);
204 INSIST(len <= 255U);
206 * Emit the key name.
208 if (REGION_SIZE(*target) < 1 + len)
209 return (ISC_R_NOSPACE);
210 PUT8(len, target->rstart);
211 PUT_MEM(ks, len, target->rstart);
213 * Emit the value.
215 result = value_towire(v, target);
216 if (result != ISC_R_SUCCESS)
217 return (result);
220 return (ISC_R_SUCCESS);
223 static isc_result_t
224 list_towire(isccc_sexpr_t *list, isccc_region_t *target)
226 isc_result_t result;
228 while (list != NULL) {
229 result = value_towire(ISCCC_SEXPR_CAR(list), target);
230 if (result != ISC_R_SUCCESS)
231 return (result);
232 list = ISCCC_SEXPR_CDR(list);
235 return (ISC_R_SUCCESS);
238 static isc_result_t
239 sign(unsigned char *data, unsigned int length, unsigned char *hmac,
240 isc_uint32_t algorithm, isccc_region_t *secret)
242 union {
243 isc_hmacmd5_t hmd5;
244 isc_hmacsha1_t hsha;
245 isc_hmacsha224_t h224;
246 isc_hmacsha256_t h256;
247 isc_hmacsha384_t h384;
248 isc_hmacsha512_t h512;
249 } ctx;
250 isc_result_t result;
251 isccc_region_t source, target;
252 unsigned char digest[ISC_SHA512_DIGESTLENGTH];
253 unsigned char digestb64[HSHA_LENGTH + 4];
255 source.rstart = digest;
257 switch (algorithm) {
258 case ISCCC_ALG_HMACMD5:
259 isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
260 REGION_SIZE(*secret));
261 isc_hmacmd5_update(&ctx.hmd5, data, length);
262 isc_hmacmd5_sign(&ctx.hmd5, digest);
263 source.rend = digest + ISC_MD5_DIGESTLENGTH;
264 break;
266 case ISCCC_ALG_HMACSHA1:
267 isc_hmacsha1_init(&ctx.hsha, secret->rstart,
268 REGION_SIZE(*secret));
269 isc_hmacsha1_update(&ctx.hsha, data, length);
270 isc_hmacsha1_sign(&ctx.hsha, digest,
271 ISC_SHA1_DIGESTLENGTH);
272 source.rend = digest + ISC_SHA1_DIGESTLENGTH;
273 break;
275 case ISCCC_ALG_HMACSHA224:
276 isc_hmacsha224_init(&ctx.h224, secret->rstart,
277 REGION_SIZE(*secret));
278 isc_hmacsha224_update(&ctx.h224, data, length);
279 isc_hmacsha224_sign(&ctx.h224, digest,
280 ISC_SHA224_DIGESTLENGTH);
281 source.rend = digest + ISC_SHA224_DIGESTLENGTH;
282 break;
284 case ISCCC_ALG_HMACSHA256:
285 isc_hmacsha256_init(&ctx.h256, secret->rstart,
286 REGION_SIZE(*secret));
287 isc_hmacsha256_update(&ctx.h256, data, length);
288 isc_hmacsha256_sign(&ctx.h256, digest,
289 ISC_SHA256_DIGESTLENGTH);
290 source.rend = digest + ISC_SHA256_DIGESTLENGTH;
291 break;
293 case ISCCC_ALG_HMACSHA384:
294 isc_hmacsha384_init(&ctx.h384, secret->rstart,
295 REGION_SIZE(*secret));
296 isc_hmacsha384_update(&ctx.h384, data, length);
297 isc_hmacsha384_sign(&ctx.h384, digest,
298 ISC_SHA384_DIGESTLENGTH);
299 source.rend = digest + ISC_SHA384_DIGESTLENGTH;
300 break;
302 case ISCCC_ALG_HMACSHA512:
303 isc_hmacsha512_init(&ctx.h512, secret->rstart,
304 REGION_SIZE(*secret));
305 isc_hmacsha512_update(&ctx.h512, data, length);
306 isc_hmacsha512_sign(&ctx.h512, digest,
307 ISC_SHA512_DIGESTLENGTH);
308 source.rend = digest + ISC_SHA512_DIGESTLENGTH;
309 break;
311 default:
312 return (ISC_R_FAILURE);
315 memset(digestb64, 0, sizeof(digestb64));
316 target.rstart = digestb64;
317 target.rend = digestb64 + sizeof(digestb64);
318 result = isccc_base64_encode(&source, 64, "", &target);
319 if (result != ISC_R_SUCCESS)
320 return (result);
321 if (algorithm == ISCCC_ALG_HMACMD5)
322 PUT_MEM(digestb64, HMD5_LENGTH, hmac);
323 else
324 PUT_MEM(digestb64, HSHA_LENGTH, hmac);
325 return (ISC_R_SUCCESS);
328 isc_result_t
329 isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
330 isc_uint32_t algorithm, isccc_region_t *secret)
332 unsigned char *hmac_rstart, *signed_rstart;
333 isc_result_t result;
335 if (algorithm == ISCCC_ALG_HMACMD5) {
336 if (REGION_SIZE(*target) < 4 + sizeof(auth_hmd5))
337 return (ISC_R_NOSPACE);
338 } else {
339 if (REGION_SIZE(*target) < 4 + sizeof(auth_hsha))
340 return (ISC_R_NOSPACE);
344 * Emit protocol version.
346 PUT32(1, target->rstart);
347 if (secret != NULL) {
349 * Emit _auth section with zeroed HMAC signature.
350 * We'll replace the zeros with the real signature once
351 * we know what it is.
353 if (algorithm == ISCCC_ALG_HMACMD5) {
354 hmac_rstart = target->rstart + HMD5_OFFSET;
355 PUT_MEM(auth_hmd5, sizeof(auth_hmd5), target->rstart);
356 } else {
357 unsigned char *hmac_alg;
359 hmac_rstart = target->rstart + HSHA_OFFSET;
360 hmac_alg = hmac_rstart - 1;
361 PUT_MEM(auth_hsha, sizeof(auth_hsha), target->rstart);
362 PUT8(algorithm, hmac_alg);
364 } else
365 hmac_rstart = NULL;
366 signed_rstart = target->rstart;
368 * Delete any existing _auth section so that we don't try
369 * to encode it.
371 isccc_alist_delete(alist, "_auth");
373 * Emit the message.
375 result = table_towire(alist, target);
376 if (result != ISC_R_SUCCESS)
377 return (result);
378 if (secret != NULL)
379 return (sign(signed_rstart,
380 (unsigned int)(target->rstart - signed_rstart),
381 hmac_rstart, algorithm, secret));
382 return (ISC_R_SUCCESS);
385 static isc_result_t
386 verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
387 isc_uint32_t algorithm, isccc_region_t *secret)
389 union {
390 isc_hmacmd5_t hmd5;
391 isc_hmacsha1_t hsha;
392 isc_hmacsha224_t h224;
393 isc_hmacsha256_t h256;
394 isc_hmacsha384_t h384;
395 isc_hmacsha512_t h512;
396 } ctx;
397 isccc_region_t source;
398 isccc_region_t target;
399 isc_result_t result;
400 isccc_sexpr_t *_auth, *hmac;
401 unsigned char digest[ISC_SHA512_DIGESTLENGTH];
402 unsigned char digestb64[HSHA_LENGTH * 4];
405 * Extract digest.
407 _auth = isccc_alist_lookup(alist, "_auth");
408 if (_auth == NULL)
409 return (ISC_R_FAILURE);
410 if (algorithm == ISCCC_ALG_HMACMD5)
411 hmac = isccc_alist_lookup(_auth, "hmd5");
412 else
413 hmac = isccc_alist_lookup(_auth, "hsha");
414 if (hmac == NULL)
415 return (ISC_R_FAILURE);
417 * Compute digest.
419 source.rstart = digest;
420 target.rstart = digestb64;
421 switch (algorithm) {
422 case ISCCC_ALG_HMACMD5:
423 isc_hmacmd5_init(&ctx.hmd5, secret->rstart,
424 REGION_SIZE(*secret));
425 isc_hmacmd5_update(&ctx.hmd5, data, length);
426 isc_hmacmd5_sign(&ctx.hmd5, digest);
427 source.rend = digest + ISC_MD5_DIGESTLENGTH;
428 break;
430 case ISCCC_ALG_HMACSHA1:
431 isc_hmacsha1_init(&ctx.hsha, secret->rstart,
432 REGION_SIZE(*secret));
433 isc_hmacsha1_update(&ctx.hsha, data, length);
434 isc_hmacsha1_sign(&ctx.hsha, digest,
435 ISC_SHA1_DIGESTLENGTH);
436 source.rend = digest + ISC_SHA1_DIGESTLENGTH;
437 break;
439 case ISCCC_ALG_HMACSHA224:
440 isc_hmacsha224_init(&ctx.h224, secret->rstart,
441 REGION_SIZE(*secret));
442 isc_hmacsha224_update(&ctx.h224, data, length);
443 isc_hmacsha224_sign(&ctx.h224, digest,
444 ISC_SHA224_DIGESTLENGTH);
445 source.rend = digest + ISC_SHA224_DIGESTLENGTH;
446 break;
448 case ISCCC_ALG_HMACSHA256:
449 isc_hmacsha256_init(&ctx.h256, secret->rstart,
450 REGION_SIZE(*secret));
451 isc_hmacsha256_update(&ctx.h256, data, length);
452 isc_hmacsha256_sign(&ctx.h256, digest,
453 ISC_SHA256_DIGESTLENGTH);
454 source.rend = digest + ISC_SHA256_DIGESTLENGTH;
455 break;
457 case ISCCC_ALG_HMACSHA384:
458 isc_hmacsha384_init(&ctx.h384, secret->rstart,
459 REGION_SIZE(*secret));
460 isc_hmacsha384_update(&ctx.h384, data, length);
461 isc_hmacsha384_sign(&ctx.h384, digest,
462 ISC_SHA384_DIGESTLENGTH);
463 source.rend = digest + ISC_SHA384_DIGESTLENGTH;
464 break;
466 case ISCCC_ALG_HMACSHA512:
467 isc_hmacsha512_init(&ctx.h512, secret->rstart,
468 REGION_SIZE(*secret));
469 isc_hmacsha512_update(&ctx.h512, data, length);
470 isc_hmacsha512_sign(&ctx.h512, digest,
471 ISC_SHA512_DIGESTLENGTH);
472 source.rend = digest + ISC_SHA512_DIGESTLENGTH;
473 break;
475 default:
476 return (ISC_R_FAILURE);
478 target.rstart = digestb64;
479 target.rend = digestb64 + sizeof(digestb64);
480 memset(digestb64, 0, sizeof(digestb64));
481 result = isccc_base64_encode(&source, 64, "", &target);
482 if (result != ISC_R_SUCCESS)
483 return (result);
486 * Verify.
488 if (algorithm == ISCCC_ALG_HMACMD5) {
489 unsigned char *value;
491 value = (unsigned char *) isccc_sexpr_tostring(hmac);
492 if (!isc_safe_memcmp(value, digestb64, HMD5_LENGTH))
493 return (ISCCC_R_BADAUTH);
494 } else {
495 unsigned char *value;
496 isc_uint32_t valalg;
498 value = (unsigned char *) isccc_sexpr_tostring(hmac);
499 GET8(valalg, value);
500 if ((valalg != algorithm) ||
501 (!isc_safe_memcmp(value, digestb64, HSHA_LENGTH)))
502 return (ISCCC_R_BADAUTH);
505 return (ISC_R_SUCCESS);
508 static isc_result_t
509 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
510 isc_uint32_t algorithm, isccc_sexpr_t **alistp);
512 static isc_result_t
513 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
515 static isc_result_t
516 value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep)
518 unsigned int msgtype;
519 isc_uint32_t len;
520 isccc_sexpr_t *value;
521 isccc_region_t active;
522 isc_result_t result;
524 if (REGION_SIZE(*source) < 1 + 4)
525 return (ISC_R_UNEXPECTEDEND);
526 GET8(msgtype, source->rstart);
527 GET32(len, source->rstart);
528 if (REGION_SIZE(*source) < len)
529 return (ISC_R_UNEXPECTEDEND);
530 active.rstart = source->rstart;
531 active.rend = active.rstart + len;
532 source->rstart = active.rend;
533 if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) {
534 value = isccc_sexpr_frombinary(&active);
535 if (value != NULL) {
536 *valuep = value;
537 result = ISC_R_SUCCESS;
538 } else
539 result = ISC_R_NOMEMORY;
540 } else if (msgtype == ISCCC_CCMSGTYPE_TABLE)
541 result = table_fromwire(&active, NULL, 0, valuep);
542 else if (msgtype == ISCCC_CCMSGTYPE_LIST)
543 result = list_fromwire(&active, valuep);
544 else
545 result = ISCCC_R_SYNTAX;
547 return (result);
550 static isc_result_t
551 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
552 isc_uint32_t algorithm, isccc_sexpr_t **alistp)
554 char key[256];
555 isc_uint32_t len;
556 isc_result_t result;
557 isccc_sexpr_t *alist, *value;
558 isc_boolean_t first_tag;
559 unsigned char *checksum_rstart;
561 REQUIRE(alistp != NULL && *alistp == NULL);
563 checksum_rstart = NULL;
564 first_tag = ISC_TRUE;
565 alist = isccc_alist_create();
566 if (alist == NULL)
567 return (ISC_R_NOMEMORY);
569 while (!REGION_EMPTY(*source)) {
570 GET8(len, source->rstart);
571 if (REGION_SIZE(*source) < len) {
572 result = ISC_R_UNEXPECTEDEND;
573 goto bad;
575 GET_MEM(key, len, source->rstart);
576 key[len] = '\0'; /* Ensure NUL termination. */
577 value = NULL;
578 result = value_fromwire(source, &value);
579 if (result != ISC_R_SUCCESS)
580 goto bad;
581 if (isccc_alist_define(alist, key, value) == NULL) {
582 result = ISC_R_NOMEMORY;
583 goto bad;
585 if (first_tag && secret != NULL && strcmp(key, "_auth") == 0)
586 checksum_rstart = source->rstart;
587 first_tag = ISC_FALSE;
590 if (secret != NULL) {
591 if (checksum_rstart != NULL)
592 result = verify(alist, checksum_rstart,
593 (unsigned int)
594 (source->rend - checksum_rstart),
595 algorithm, secret);
596 else
597 result = ISCCC_R_BADAUTH;
598 } else
599 result = ISC_R_SUCCESS;
601 bad:
602 if (result == ISC_R_SUCCESS)
603 *alistp = alist;
604 else
605 isccc_sexpr_free(&alist);
607 return (result);
610 static isc_result_t
611 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp)
613 isccc_sexpr_t *list, *value;
614 isc_result_t result;
616 list = NULL;
617 while (!REGION_EMPTY(*source)) {
618 value = NULL;
619 result = value_fromwire(source, &value);
620 if (result != ISC_R_SUCCESS) {
621 isccc_sexpr_free(&list);
622 return (result);
624 if (isccc_sexpr_addtolist(&list, value) == NULL) {
625 isccc_sexpr_free(&value);
626 isccc_sexpr_free(&list);
627 return (result);
631 *listp = list;
633 return (ISC_R_SUCCESS);
636 isc_result_t
637 isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
638 isc_uint32_t algorithm, isccc_region_t *secret)
640 unsigned int size;
641 isc_uint32_t version;
643 size = REGION_SIZE(*source);
644 if (size < 4)
645 return (ISC_R_UNEXPECTEDEND);
646 GET32(version, source->rstart);
647 if (version != 1)
648 return (ISCCC_R_UNKNOWNVERSION);
650 return (table_fromwire(source, secret, algorithm, alistp));
653 static isc_result_t
654 createmessage(isc_uint32_t version, const char *from, const char *to,
655 isc_uint32_t serial, isccc_time_t now,
656 isccc_time_t expires, isccc_sexpr_t **alistp,
657 isc_boolean_t want_expires)
659 isccc_sexpr_t *alist, *_ctrl, *_data;
660 isc_result_t result;
662 REQUIRE(alistp != NULL && *alistp == NULL);
664 if (version != 1)
665 return (ISCCC_R_UNKNOWNVERSION);
667 alist = isccc_alist_create();
668 if (alist == NULL)
669 return (ISC_R_NOMEMORY);
671 result = ISC_R_NOMEMORY;
673 _ctrl = isccc_alist_create();
674 if (_ctrl == NULL)
675 goto bad;
676 if (isccc_alist_define(alist, "_ctrl", _ctrl) == NULL) {
677 isccc_sexpr_free(&_ctrl);
678 goto bad;
681 _data = isccc_alist_create();
682 if (_data == NULL)
683 goto bad;
684 if (isccc_alist_define(alist, "_data", _data) == NULL) {
685 isccc_sexpr_free(&_data);
686 goto bad;
689 if (isccc_cc_defineuint32(_ctrl, "_ser", serial) == NULL ||
690 isccc_cc_defineuint32(_ctrl, "_tim", now) == NULL ||
691 (want_expires &&
692 isccc_cc_defineuint32(_ctrl, "_exp", expires) == NULL))
693 goto bad;
694 if (from != NULL &&
695 isccc_cc_definestring(_ctrl, "_frm", from) == NULL)
696 goto bad;
697 if (to != NULL &&
698 isccc_cc_definestring(_ctrl, "_to", to) == NULL)
699 goto bad;
701 *alistp = alist;
703 return (ISC_R_SUCCESS);
705 bad:
706 isccc_sexpr_free(&alist);
708 return (result);
711 isc_result_t
712 isccc_cc_createmessage(isc_uint32_t version, const char *from, const char *to,
713 isc_uint32_t serial, isccc_time_t now,
714 isccc_time_t expires, isccc_sexpr_t **alistp)
716 return (createmessage(version, from, to, serial, now, expires,
717 alistp, ISC_TRUE));
720 isc_result_t
721 isccc_cc_createack(isccc_sexpr_t *message, isc_boolean_t ok,
722 isccc_sexpr_t **ackp)
724 char *_frm, *_to;
725 isc_uint32_t serial;
726 isccc_sexpr_t *ack, *_ctrl;
727 isc_result_t result;
728 isccc_time_t t;
730 REQUIRE(ackp != NULL && *ackp == NULL);
732 _ctrl = isccc_alist_lookup(message, "_ctrl");
733 if (_ctrl == NULL ||
734 isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
735 isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS)
736 return (ISC_R_FAILURE);
738 * _frm and _to are optional.
740 _frm = NULL;
741 (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
742 _to = NULL;
743 (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
745 * Create the ack.
747 ack = NULL;
748 result = createmessage(1, _to, _frm, serial, t, 0, &ack, ISC_FALSE);
749 if (result != ISC_R_SUCCESS)
750 return (result);
752 _ctrl = isccc_alist_lookup(ack, "_ctrl");
753 if (_ctrl == NULL) {
754 result = ISC_R_FAILURE;
755 goto bad;
757 if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
758 result = ISC_R_NOMEMORY;
759 goto bad;
762 *ackp = ack;
764 return (ISC_R_SUCCESS);
766 bad:
767 isccc_sexpr_free(&ack);
769 return (result);
772 isc_boolean_t
773 isccc_cc_isack(isccc_sexpr_t *message)
775 isccc_sexpr_t *_ctrl;
777 _ctrl = isccc_alist_lookup(message, "_ctrl");
778 if (_ctrl == NULL)
779 return (ISC_FALSE);
780 if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS)
781 return (ISC_TRUE);
782 return (ISC_FALSE);
785 isc_boolean_t
786 isccc_cc_isreply(isccc_sexpr_t *message)
788 isccc_sexpr_t *_ctrl;
790 _ctrl = isccc_alist_lookup(message, "_ctrl");
791 if (_ctrl == NULL)
792 return (ISC_FALSE);
793 if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS)
794 return (ISC_TRUE);
795 return (ISC_FALSE);
798 isc_result_t
799 isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
800 isccc_time_t expires, isccc_sexpr_t **alistp)
802 char *_frm, *_to, *type = NULL;
803 isc_uint32_t serial;
804 isccc_sexpr_t *alist, *_ctrl, *_data;
805 isc_result_t result;
807 REQUIRE(alistp != NULL && *alistp == NULL);
809 _ctrl = isccc_alist_lookup(message, "_ctrl");
810 _data = isccc_alist_lookup(message, "_data");
811 if (_ctrl == NULL || _data == NULL ||
812 isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
813 isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS)
814 return (ISC_R_FAILURE);
816 * _frm and _to are optional.
818 _frm = NULL;
819 (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
820 _to = NULL;
821 (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
823 * Create the response.
825 alist = NULL;
826 result = isccc_cc_createmessage(1, _to, _frm, serial, now, expires,
827 &alist);
828 if (result != ISC_R_SUCCESS)
829 return (result);
831 _ctrl = isccc_alist_lookup(alist, "_ctrl");
832 if (_ctrl == NULL) {
833 result = ISC_R_FAILURE;
834 goto bad;
837 _data = isccc_alist_lookup(alist, "_data");
838 if (_data == NULL) {
839 result = ISC_R_FAILURE;
840 goto bad;
843 if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
844 isccc_cc_definestring(_data, "type", type) == NULL)
846 result = ISC_R_NOMEMORY;
847 goto bad;
850 *alistp = alist;
852 return (ISC_R_SUCCESS);
854 bad:
855 isccc_sexpr_free(&alist);
856 return (result);
859 isccc_sexpr_t *
860 isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
862 size_t len;
863 isccc_region_t r;
865 len = strlen(str);
866 DE_CONST(str, r.rstart);
867 r.rend = r.rstart + len;
869 return (isccc_alist_definebinary(alist, key, &r));
872 isccc_sexpr_t *
873 isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, isc_uint32_t i)
875 char b[100];
876 size_t len;
877 isccc_region_t r;
879 snprintf(b, sizeof(b), "%u", i);
880 len = strlen(b);
881 r.rstart = (unsigned char *)b;
882 r.rend = (unsigned char *)b + len;
884 return (isccc_alist_definebinary(alist, key, &r));
887 isc_result_t
888 isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
890 isccc_sexpr_t *kv, *v;
892 REQUIRE(strp == NULL || *strp == NULL);
894 kv = isccc_alist_assq(alist, key);
895 if (kv != NULL) {
896 v = ISCCC_SEXPR_CDR(kv);
897 if (isccc_sexpr_binaryp(v)) {
898 if (strp != NULL)
899 *strp = isccc_sexpr_tostring(v);
900 return (ISC_R_SUCCESS);
901 } else
902 return (ISC_R_EXISTS);
905 return (ISC_R_NOTFOUND);
908 isc_result_t
909 isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
910 isc_uint32_t *uintp)
912 isccc_sexpr_t *kv, *v;
914 kv = isccc_alist_assq(alist, key);
915 if (kv != NULL) {
916 v = ISCCC_SEXPR_CDR(kv);
917 if (isccc_sexpr_binaryp(v)) {
918 if (uintp != NULL)
919 *uintp = (isc_uint32_t)
920 strtoul(isccc_sexpr_tostring(v),
921 NULL, 10);
922 return (ISC_R_SUCCESS);
923 } else
924 return (ISC_R_EXISTS);
927 return (ISC_R_NOTFOUND);
930 static void
931 symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
932 void *arg)
934 UNUSED(type);
935 UNUSED(value);
936 UNUSED(arg);
938 free(key);
941 static isc_boolean_t
942 symtab_clean(char *key, unsigned int type, isccc_symvalue_t value,
943 void *arg)
945 isccc_time_t *now;
947 UNUSED(key);
948 UNUSED(type);
950 now = arg;
952 if (*now < value.as_uinteger)
953 return (ISC_FALSE);
954 if ((*now - value.as_uinteger) < DUP_LIFETIME)
955 return (ISC_FALSE);
956 return (ISC_TRUE);
959 isc_result_t
960 isccc_cc_createsymtab(isccc_symtab_t **symtabp)
962 return (isccc_symtab_create(11897, symtab_undefine, NULL, ISC_FALSE,
963 symtabp));
966 void
967 isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now)
969 isccc_symtab_foreach(symtab, symtab_clean, &now);
972 static isc_boolean_t
973 has_whitespace(const char *str)
975 char c;
977 if (str == NULL)
978 return (ISC_FALSE);
979 while ((c = *str++) != '\0') {
980 if (c == ' ' || c == '\t' || c == '\n')
981 return (ISC_TRUE);
983 return (ISC_FALSE);
986 isc_result_t
987 isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
988 isccc_time_t now)
990 const char *_frm;
991 const char *_to;
992 char *_ser = NULL, *_tim = NULL, *tmp;
993 isc_result_t result;
994 char *key;
995 size_t len;
996 isccc_symvalue_t value;
997 isccc_sexpr_t *_ctrl;
999 _ctrl = isccc_alist_lookup(message, "_ctrl");
1000 if (_ctrl == NULL ||
1001 isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS ||
1002 isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS)
1003 return (ISC_R_FAILURE);
1005 INSIST(_ser != NULL);
1006 INSIST(_tim != NULL);
1009 * _frm and _to are optional.
1011 tmp = NULL;
1012 if (isccc_cc_lookupstring(_ctrl, "_frm", &tmp) != ISC_R_SUCCESS)
1013 _frm = "";
1014 else
1015 _frm = tmp;
1016 tmp = NULL;
1017 if (isccc_cc_lookupstring(_ctrl, "_to", &tmp) != ISC_R_SUCCESS)
1018 _to = "";
1019 else
1020 _to = tmp;
1022 * Ensure there is no newline in any of the strings. This is so
1023 * we can write them to a file later.
1025 if (has_whitespace(_frm) || has_whitespace(_to) ||
1026 has_whitespace(_ser) || has_whitespace(_tim))
1027 return (ISC_R_FAILURE);
1028 len = strlen(_frm) + strlen(_to) + strlen(_ser) + strlen(_tim) + 4;
1029 key = malloc(len);
1030 if (key == NULL)
1031 return (ISC_R_NOMEMORY);
1032 snprintf(key, len, "%s;%s;%s;%s", _frm, _to, _ser, _tim);
1033 value.as_uinteger = now;
1034 result = isccc_symtab_define(symtab, key, ISCCC_SYMTYPE_CCDUP, value,
1035 isccc_symexists_reject);
1036 if (result != ISC_R_SUCCESS) {
1037 free(key);
1038 return (result);
1041 return (ISC_R_SUCCESS);