1 /* $NetBSD: cc.c,v 1.8 2014/12/10 04:38:01 christos Exp $ */
2
3 /*
4 * Portions Copyright (C) 2004-2007, 2012, 2013 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 2001-2003 Internet Software Consortium.
6 *
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.
10 *
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.
18 *
19 * Portions Copyright (C) 2001 Nominum, 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 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.
32 */
33
34 /* Id: cc.c,v 1.18 2007/08/28 07:20:43 tbox Exp */
35
36 /*! \file */
37
38 #include <config.h>
39
40 #include <stdio.h>
41 #include <string.h>
42 #include <errno.h>
43
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>
50
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>
59
60 #define MAX_TAGS 256
61 #define DUP_LIFETIME 900
62
63 typedef isccc_sexpr_t *sexpr_ptr;
64
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 */
72 /*
73 * The base64 encoding of one of our HMAC-MD5 signatures is
74 * 22 bytes.
75 */
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
79 };
80
81 #define HMD5_OFFSET 21 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
82 #define HMD5_LENGTH 22
83
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 */
92 /*
93 * The base64 encoding of one of our HMAC-SHA* signatures is
94 * 88 bytes.
95 */
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
107 };
108
109 #define HSHA_OFFSET 22 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 + 1 */
110 #define HSHA_LENGTH 88
111
112 static isc_result_t
113 table_towire(isccc_sexpr_t *alist, isccc_region_t *target);
114
115 static isc_result_t
116 list_towire(isccc_sexpr_t *alist, isccc_region_t *target);
117
118 static isc_result_t
value_towire(isccc_sexpr_t * elt,isccc_region_t * target)119 value_towire(isccc_sexpr_t *elt, isccc_region_t *target)
120 {
121 unsigned int len;
122 unsigned char *lenp;
123 isccc_region_t *vr;
124 isc_result_t result;
125
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);
140 /*
141 * Emit a placeholder length.
142 */
143 lenp = target->rstart;
144 PUT32(0, target->rstart);
145 /*
146 * Emit the table.
147 */
148 result = table_towire(elt, target);
149 if (result != ISC_R_SUCCESS)
150 return (result);
151 len = (unsigned int)(target->rstart - lenp);
152 /*
153 * 'len' is 4 bytes too big, since it counts
154 * the placeholder length too. Adjust and
155 * emit.
156 */
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);
164 /*
165 * Emit a placeholder length and count.
166 */
167 lenp = target->rstart;
168 PUT32(0, target->rstart);
169 /*
170 * Emit the list.
171 */
172 result = list_towire(elt, target);
173 if (result != ISC_R_SUCCESS)
174 return (result);
175 len = (unsigned int)(target->rstart - lenp);
176 /*
177 * 'len' is 4 bytes too big, since it counts
178 * the placeholder length. Adjust and emit.
179 */
180 INSIST(len >= 4U);
181 len -= 4;
182 PUT32(len, lenp);
183 }
184
185 return (ISC_R_SUCCESS);
186 }
187
188 static isc_result_t
table_towire(isccc_sexpr_t * alist,isccc_region_t * target)189 table_towire(isccc_sexpr_t *alist, isccc_region_t *target)
190 {
191 isccc_sexpr_t *kv, *elt, *k, *v;
192 char *ks;
193 isc_result_t result;
194 size_t len;
195
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);
205 /*
206 * Emit the key name.
207 */
208 if (REGION_SIZE(*target) < 1 + len)
209 return (ISC_R_NOSPACE);
210 PUT8(len, target->rstart);
211 PUT_MEM(ks, len, target->rstart);
212 /*
213 * Emit the value.
214 */
215 result = value_towire(v, target);
216 if (result != ISC_R_SUCCESS)
217 return (result);
218 }
219
220 return (ISC_R_SUCCESS);
221 }
222
223 static isc_result_t
list_towire(isccc_sexpr_t * list,isccc_region_t * target)224 list_towire(isccc_sexpr_t *list, isccc_region_t *target)
225 {
226 isc_result_t result;
227
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);
233 }
234
235 return (ISC_R_SUCCESS);
236 }
237
238 static isc_result_t
sign(unsigned char * data,unsigned int length,unsigned char * hmac,isc_uint32_t algorithm,isccc_region_t * secret)239 sign(unsigned char *data, unsigned int length, unsigned char *hmac,
240 isc_uint32_t algorithm, isccc_region_t *secret)
241 {
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];
254
255 source.rstart = digest;
256
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;
265
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;
274
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;
283
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;
292
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;
301
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;
310
311 default:
312 return (ISC_R_FAILURE);
313 }
314
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);
326 }
327
328 isc_result_t
isccc_cc_towire(isccc_sexpr_t * alist,isccc_region_t * target,isc_uint32_t algorithm,isccc_region_t * secret)329 isccc_cc_towire(isccc_sexpr_t *alist, isccc_region_t *target,
330 isc_uint32_t algorithm, isccc_region_t *secret)
331 {
332 unsigned char *hmac_rstart, *signed_rstart;
333 isc_result_t result;
334
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);
341 }
342
343 /*
344 * Emit protocol version.
345 */
346 PUT32(1, target->rstart);
347 if (secret != NULL) {
348 /*
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.
352 */
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;
358
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);
363 }
364 } else
365 hmac_rstart = NULL;
366 signed_rstart = target->rstart;
367 /*
368 * Delete any existing _auth section so that we don't try
369 * to encode it.
370 */
371 isccc_alist_delete(alist, "_auth");
372 /*
373 * Emit the message.
374 */
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);
383 }
384
385 static isc_result_t
verify(isccc_sexpr_t * alist,unsigned char * data,unsigned int length,isc_uint32_t algorithm,isccc_region_t * secret)386 verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
387 isc_uint32_t algorithm, isccc_region_t *secret)
388 {
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];
403
404 /*
405 * Extract digest.
406 */
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);
416 /*
417 * Compute digest.
418 */
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;
429
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;
438
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;
447
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;
456
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;
465
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;
474
475 default:
476 return (ISC_R_FAILURE);
477 }
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);
484
485 /*
486 * Verify.
487 */
488 if (algorithm == ISCCC_ALG_HMACMD5) {
489 unsigned char *value;
490
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;
497
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);
503 }
504
505 return (ISC_R_SUCCESS);
506 }
507
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);
511
512 static isc_result_t
513 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
514
515 static isc_result_t
value_fromwire(isccc_region_t * source,isccc_sexpr_t ** valuep)516 value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep)
517 {
518 unsigned int msgtype;
519 isc_uint32_t len;
520 isccc_sexpr_t *value;
521 isccc_region_t active;
522 isc_result_t result;
523
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;
546
547 return (result);
548 }
549
550 static isc_result_t
table_fromwire(isccc_region_t * source,isccc_region_t * secret,isc_uint32_t algorithm,isccc_sexpr_t ** alistp)551 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
552 isc_uint32_t algorithm, isccc_sexpr_t **alistp)
553 {
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;
560
561 REQUIRE(alistp != NULL && *alistp == NULL);
562
563 checksum_rstart = NULL;
564 first_tag = ISC_TRUE;
565 alist = isccc_alist_create();
566 if (alist == NULL)
567 return (ISC_R_NOMEMORY);
568
569 while (!REGION_EMPTY(*source)) {
570 GET8(len, source->rstart);
571 if (REGION_SIZE(*source) < len) {
572 result = ISC_R_UNEXPECTEDEND;
573 goto bad;
574 }
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;
584 }
585 if (first_tag && secret != NULL && strcmp(key, "_auth") == 0)
586 checksum_rstart = source->rstart;
587 first_tag = ISC_FALSE;
588 }
589
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;
600
601 bad:
602 if (result == ISC_R_SUCCESS)
603 *alistp = alist;
604 else
605 isccc_sexpr_free(&alist);
606
607 return (result);
608 }
609
610 static isc_result_t
list_fromwire(isccc_region_t * source,isccc_sexpr_t ** listp)611 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp)
612 {
613 isccc_sexpr_t *list, *value;
614 isc_result_t result;
615
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);
623 }
624 if (isccc_sexpr_addtolist(&list, value) == NULL) {
625 isccc_sexpr_free(&value);
626 isccc_sexpr_free(&list);
627 return (result);
628 }
629 }
630
631 *listp = list;
632
633 return (ISC_R_SUCCESS);
634 }
635
636 isc_result_t
isccc_cc_fromwire(isccc_region_t * source,isccc_sexpr_t ** alistp,isc_uint32_t algorithm,isccc_region_t * secret)637 isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
638 isc_uint32_t algorithm, isccc_region_t *secret)
639 {
640 unsigned int size;
641 isc_uint32_t version;
642
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);
649
650 return (table_fromwire(source, secret, algorithm, alistp));
651 }
652
653 static isc_result_t
createmessage(isc_uint32_t version,const char * from,const char * to,isc_uint32_t serial,isccc_time_t now,isccc_time_t expires,isccc_sexpr_t ** alistp,isc_boolean_t want_expires)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)
658 {
659 isccc_sexpr_t *alist, *_ctrl, *_data;
660 isc_result_t result;
661
662 REQUIRE(alistp != NULL && *alistp == NULL);
663
664 if (version != 1)
665 return (ISCCC_R_UNKNOWNVERSION);
666
667 alist = isccc_alist_create();
668 if (alist == NULL)
669 return (ISC_R_NOMEMORY);
670
671 result = ISC_R_NOMEMORY;
672
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;
679 }
680
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;
687 }
688
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;
700
701 *alistp = alist;
702
703 return (ISC_R_SUCCESS);
704
705 bad:
706 isccc_sexpr_free(&alist);
707
708 return (result);
709 }
710
711 isc_result_t
isccc_cc_createmessage(isc_uint32_t version,const char * from,const char * to,isc_uint32_t serial,isccc_time_t now,isccc_time_t expires,isccc_sexpr_t ** alistp)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)
715 {
716 return (createmessage(version, from, to, serial, now, expires,
717 alistp, ISC_TRUE));
718 }
719
720 isc_result_t
isccc_cc_createack(isccc_sexpr_t * message,isc_boolean_t ok,isccc_sexpr_t ** ackp)721 isccc_cc_createack(isccc_sexpr_t *message, isc_boolean_t ok,
722 isccc_sexpr_t **ackp)
723 {
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;
729
730 REQUIRE(ackp != NULL && *ackp == NULL);
731
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);
737 /*
738 * _frm and _to are optional.
739 */
740 _frm = NULL;
741 (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
742 _to = NULL;
743 (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
744 /*
745 * Create the ack.
746 */
747 ack = NULL;
748 result = createmessage(1, _to, _frm, serial, t, 0, &ack, ISC_FALSE);
749 if (result != ISC_R_SUCCESS)
750 return (result);
751
752 _ctrl = isccc_alist_lookup(ack, "_ctrl");
753 if (_ctrl == NULL) {
754 result = ISC_R_FAILURE;
755 goto bad;
756 }
757 if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
758 result = ISC_R_NOMEMORY;
759 goto bad;
760 }
761
762 *ackp = ack;
763
764 return (ISC_R_SUCCESS);
765
766 bad:
767 isccc_sexpr_free(&ack);
768
769 return (result);
770 }
771
772 isc_boolean_t
isccc_cc_isack(isccc_sexpr_t * message)773 isccc_cc_isack(isccc_sexpr_t *message)
774 {
775 isccc_sexpr_t *_ctrl;
776
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);
783 }
784
785 isc_boolean_t
isccc_cc_isreply(isccc_sexpr_t * message)786 isccc_cc_isreply(isccc_sexpr_t *message)
787 {
788 isccc_sexpr_t *_ctrl;
789
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);
796 }
797
798 isc_result_t
isccc_cc_createresponse(isccc_sexpr_t * message,isccc_time_t now,isccc_time_t expires,isccc_sexpr_t ** alistp)799 isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
800 isccc_time_t expires, isccc_sexpr_t **alistp)
801 {
802 char *_frm, *_to, *type = NULL;
803 isc_uint32_t serial;
804 isccc_sexpr_t *alist, *_ctrl, *_data;
805 isc_result_t result;
806
807 REQUIRE(alistp != NULL && *alistp == NULL);
808
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);
815 /*
816 * _frm and _to are optional.
817 */
818 _frm = NULL;
819 (void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
820 _to = NULL;
821 (void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
822 /*
823 * Create the response.
824 */
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);
830
831 _ctrl = isccc_alist_lookup(alist, "_ctrl");
832 if (_ctrl == NULL) {
833 result = ISC_R_FAILURE;
834 goto bad;
835 }
836
837 _data = isccc_alist_lookup(alist, "_data");
838 if (_data == NULL) {
839 result = ISC_R_FAILURE;
840 goto bad;
841 }
842
843 if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
844 isccc_cc_definestring(_data, "type", type) == NULL)
845 {
846 result = ISC_R_NOMEMORY;
847 goto bad;
848 }
849
850 *alistp = alist;
851
852 return (ISC_R_SUCCESS);
853
854 bad:
855 isccc_sexpr_free(&alist);
856 return (result);
857 }
858
859 isccc_sexpr_t *
isccc_cc_definestring(isccc_sexpr_t * alist,const char * key,const char * str)860 isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str)
861 {
862 size_t len;
863 isccc_region_t r;
864
865 len = strlen(str);
866 DE_CONST(str, r.rstart);
867 r.rend = r.rstart + len;
868
869 return (isccc_alist_definebinary(alist, key, &r));
870 }
871
872 isccc_sexpr_t *
isccc_cc_defineuint32(isccc_sexpr_t * alist,const char * key,isc_uint32_t i)873 isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, isc_uint32_t i)
874 {
875 char b[100];
876 size_t len;
877 isccc_region_t r;
878
879 snprintf(b, sizeof(b), "%u", i);
880 len = strlen(b);
881 r.rstart = (unsigned char *)b;
882 r.rend = (unsigned char *)b + len;
883
884 return (isccc_alist_definebinary(alist, key, &r));
885 }
886
887 isc_result_t
isccc_cc_lookupstring(isccc_sexpr_t * alist,const char * key,char ** strp)888 isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp)
889 {
890 isccc_sexpr_t *kv, *v;
891
892 REQUIRE(strp == NULL || *strp == NULL);
893
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);
903 }
904
905 return (ISC_R_NOTFOUND);
906 }
907
908 isc_result_t
isccc_cc_lookupuint32(isccc_sexpr_t * alist,const char * key,isc_uint32_t * uintp)909 isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key,
910 isc_uint32_t *uintp)
911 {
912 isccc_sexpr_t *kv, *v;
913
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);
925 }
926
927 return (ISC_R_NOTFOUND);
928 }
929
930 static void
symtab_undefine(char * key,unsigned int type,isccc_symvalue_t value,void * arg)931 symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
932 void *arg)
933 {
934 UNUSED(type);
935 UNUSED(value);
936 UNUSED(arg);
937
938 free(key);
939 }
940
941 static isc_boolean_t
symtab_clean(char * key,unsigned int type,isccc_symvalue_t value,void * arg)942 symtab_clean(char *key, unsigned int type, isccc_symvalue_t value,
943 void *arg)
944 {
945 isccc_time_t *now;
946
947 UNUSED(key);
948 UNUSED(type);
949
950 now = arg;
951
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);
957 }
958
959 isc_result_t
isccc_cc_createsymtab(isccc_symtab_t ** symtabp)960 isccc_cc_createsymtab(isccc_symtab_t **symtabp)
961 {
962 return (isccc_symtab_create(11897, symtab_undefine, NULL, ISC_FALSE,
963 symtabp));
964 }
965
966 void
isccc_cc_cleansymtab(isccc_symtab_t * symtab,isccc_time_t now)967 isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now)
968 {
969 isccc_symtab_foreach(symtab, symtab_clean, &now);
970 }
971
972 static isc_boolean_t
has_whitespace(const char * str)973 has_whitespace(const char *str)
974 {
975 char c;
976
977 if (str == NULL)
978 return (ISC_FALSE);
979 while ((c = *str++) != '\0') {
980 if (c == ' ' || c == '\t' || c == '\n')
981 return (ISC_TRUE);
982 }
983 return (ISC_FALSE);
984 }
985
986 isc_result_t
isccc_cc_checkdup(isccc_symtab_t * symtab,isccc_sexpr_t * message,isccc_time_t now)987 isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
988 isccc_time_t now)
989 {
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;
998
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);
1004
1005 INSIST(_ser != NULL);
1006 INSIST(_tim != NULL);
1007
1008 /*
1009 * _frm and _to are optional.
1010 */
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;
1021 /*
1022 * Ensure there is no newline in any of the strings. This is so
1023 * we can write them to a file later.
1024 */
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);
1039 }
1040
1041 return (ISC_R_SUCCESS);
1042 }
1043