xref: /minix/external/bsd/bind/dist/lib/isccc/cc.c (revision 00b67f09)
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