1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0 AND ISC
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 /*
15  * Copyright (C) 2001 Nominum, Inc.
16  *
17  * Permission to use, copy, modify, and/or distribute this software for any
18  * purpose with or without fee is hereby granted, provided that the above
19  * copyright notice and this permission notice appear in all copies.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NOMINUM DISCLAIMS ALL
22  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY
24  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
25  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
26  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
27  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28  */
29 
30 /*! \file */
31 
32 #include <errno.h>
33 #include <inttypes.h>
34 #include <stdbool.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include <isc/assertions.h>
40 #include <isc/hmac.h>
41 #include <isc/print.h>
42 #include <isc/safe.h>
43 
44 #include <pk11/site.h>
45 
46 #include <isccc/alist.h>
47 #include <isccc/base64.h>
48 #include <isccc/cc.h>
49 #include <isccc/result.h>
50 #include <isccc/sexpr.h>
51 #include <isccc/symtab.h>
52 #include <isccc/symtype.h>
53 #include <isccc/util.h>
54 
55 #define MAX_TAGS     256
56 #define DUP_LIFETIME 900
57 
58 typedef isccc_sexpr_t *sexpr_ptr;
59 
60 static unsigned char auth_hmd5[] = {
61 	0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
62 	ISCCC_CCMSGTYPE_TABLE,		    /*%< message type */
63 	0x00, 0x00, 0x00, 0x20,		    /*%< length == 32 */
64 	0x04, 0x68, 0x6d, 0x64, 0x35,	    /*%< len + hmd5 */
65 	ISCCC_CCMSGTYPE_BINARYDATA,	    /*%< message type */
66 	0x00, 0x00, 0x00, 0x16,		    /*%< length == 22 */
67 	/*
68 	 * The base64 encoding of one of our HMAC-MD5 signatures is
69 	 * 22 bytes.
70 	 */
71 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
72 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
73 };
74 
75 #define HMD5_OFFSET 21 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 */
76 #define HMD5_LENGTH 22
77 
78 static unsigned char auth_hsha[] = {
79 	0x05, 0x5f, 0x61, 0x75, 0x74, 0x68, /*%< len + _auth */
80 	ISCCC_CCMSGTYPE_TABLE,		    /*%< message type */
81 	0x00, 0x00, 0x00, 0x63,		    /*%< length == 99 */
82 	0x04, 0x68, 0x73, 0x68, 0x61,	    /*%< len + hsha */
83 	ISCCC_CCMSGTYPE_BINARYDATA,	    /*%< message type */
84 	0x00, 0x00, 0x00, 0x59,		    /*%< length == 89 */
85 	0x00,				    /*%< algorithm */
86 	/*
87 	 * The base64 encoding of one of our HMAC-SHA* signatures is
88 	 * 88 bytes.
89 	 */
90 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 	0x00, 0x00, 0x00, 0x00
98 };
99 
100 #define HSHA_OFFSET 22 /*%< 21 = 6 + 1 + 4 + 5 + 1 + 4 + 1 */
101 #define HSHA_LENGTH 88
102 
103 static isc_result_t
104 table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
105 
106 static isc_result_t
107 list_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer);
108 
109 static isc_result_t
value_towire(isccc_sexpr_t * elt,isc_buffer_t ** buffer)110 value_towire(isccc_sexpr_t *elt, isc_buffer_t **buffer) {
111 	unsigned int len;
112 	isccc_region_t *vr;
113 	isc_result_t result;
114 
115 	if (isccc_sexpr_binaryp(elt)) {
116 		vr = isccc_sexpr_tobinary(elt);
117 		len = REGION_SIZE(*vr);
118 		result = isc_buffer_reserve(buffer, 1 + 4);
119 		if (result != ISC_R_SUCCESS) {
120 			return (ISC_R_NOSPACE);
121 		}
122 		isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_BINARYDATA);
123 		isc_buffer_putuint32(*buffer, len);
124 
125 		result = isc_buffer_reserve(buffer, len);
126 		if (result != ISC_R_SUCCESS) {
127 			return (ISC_R_NOSPACE);
128 		}
129 		isc_buffer_putmem(*buffer, vr->rstart, len);
130 	} else if (isccc_alist_alistp(elt)) {
131 		unsigned int used;
132 		isc_buffer_t b;
133 
134 		result = isc_buffer_reserve(buffer, 1 + 4);
135 		if (result != ISC_R_SUCCESS) {
136 			return (ISC_R_NOSPACE);
137 		}
138 		isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_TABLE);
139 		/*
140 		 * Emit a placeholder length.
141 		 */
142 		used = (*buffer)->used;
143 		isc_buffer_putuint32(*buffer, 0);
144 
145 		/*
146 		 * Emit the table.
147 		 */
148 		result = table_towire(elt, buffer);
149 		if (result != ISC_R_SUCCESS) {
150 			return (result);
151 		}
152 
153 		len = (*buffer)->used - used;
154 		/*
155 		 * 'len' is 4 bytes too big, since it counts
156 		 * the placeholder length too.	Adjust and
157 		 * emit.
158 		 */
159 		INSIST(len >= 4U);
160 		len -= 4;
161 
162 		isc_buffer_init(&b, (unsigned char *)(*buffer)->base + used, 4);
163 		isc_buffer_putuint32(&b, len);
164 	} else if (isccc_sexpr_listp(elt)) {
165 		unsigned int used;
166 		isc_buffer_t b;
167 
168 		result = isc_buffer_reserve(buffer, 1 + 4);
169 		if (result != ISC_R_SUCCESS) {
170 			return (ISC_R_NOSPACE);
171 		}
172 		isc_buffer_putuint8(*buffer, ISCCC_CCMSGTYPE_LIST);
173 		/*
174 		 * Emit a placeholder length.
175 		 */
176 		used = (*buffer)->used;
177 		isc_buffer_putuint32(*buffer, 0);
178 
179 		/*
180 		 * Emit the list.
181 		 */
182 		result = list_towire(elt, buffer);
183 		if (result != ISC_R_SUCCESS) {
184 			return (result);
185 		}
186 
187 		len = (*buffer)->used - used;
188 		/*
189 		 * 'len' is 4 bytes too big, since it counts
190 		 * the placeholder length too.	Adjust and
191 		 * emit.
192 		 */
193 		INSIST(len >= 4U);
194 		len -= 4;
195 
196 		isc_buffer_init(&b, (unsigned char *)(*buffer)->base + used, 4);
197 		isc_buffer_putuint32(&b, len);
198 	}
199 
200 	return (ISC_R_SUCCESS);
201 }
202 
203 static isc_result_t
table_towire(isccc_sexpr_t * alist,isc_buffer_t ** buffer)204 table_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer) {
205 	isccc_sexpr_t *kv, *elt, *k, *v;
206 	char *ks;
207 	isc_result_t result;
208 	unsigned int len;
209 
210 	for (elt = isccc_alist_first(alist); elt != NULL;
211 	     elt = ISCCC_SEXPR_CDR(elt)) {
212 		kv = ISCCC_SEXPR_CAR(elt);
213 		k = ISCCC_SEXPR_CAR(kv);
214 		ks = isccc_sexpr_tostring(k);
215 		v = ISCCC_SEXPR_CDR(kv);
216 		len = (unsigned int)strlen(ks);
217 		INSIST(len <= 255U);
218 		/*
219 		 * Emit the key name.
220 		 */
221 		result = isc_buffer_reserve(buffer, 1 + len);
222 		if (result != ISC_R_SUCCESS) {
223 			return (ISC_R_NOSPACE);
224 		}
225 		isc_buffer_putuint8(*buffer, (uint8_t)len);
226 		isc_buffer_putmem(*buffer, (const unsigned char *)ks, len);
227 		/*
228 		 * Emit the value.
229 		 */
230 		result = value_towire(v, buffer);
231 		if (result != ISC_R_SUCCESS) {
232 			return (result);
233 		}
234 	}
235 
236 	return (ISC_R_SUCCESS);
237 }
238 
239 static isc_result_t
list_towire(isccc_sexpr_t * list,isc_buffer_t ** buffer)240 list_towire(isccc_sexpr_t *list, isc_buffer_t **buffer) {
241 	isc_result_t result;
242 
243 	while (list != NULL) {
244 		result = value_towire(ISCCC_SEXPR_CAR(list), buffer);
245 		if (result != ISC_R_SUCCESS) {
246 			return (result);
247 		}
248 		list = ISCCC_SEXPR_CDR(list);
249 	}
250 
251 	return (ISC_R_SUCCESS);
252 }
253 
254 static isc_result_t
sign(unsigned char * data,unsigned int length,unsigned char * hmac,uint32_t algorithm,isccc_region_t * secret)255 sign(unsigned char *data, unsigned int length, unsigned char *hmac,
256      uint32_t algorithm, isccc_region_t *secret) {
257 	const isc_md_type_t *md_type;
258 	isc_result_t result;
259 	isccc_region_t source, target;
260 	unsigned char digest[ISC_MAX_MD_SIZE];
261 	unsigned int digestlen;
262 	unsigned char digestb64[HSHA_LENGTH + 4];
263 
264 	source.rstart = digest;
265 
266 	switch (algorithm) {
267 	case ISCCC_ALG_HMACMD5:
268 		md_type = ISC_MD_MD5;
269 		break;
270 	case ISCCC_ALG_HMACSHA1:
271 		md_type = ISC_MD_SHA1;
272 		break;
273 	case ISCCC_ALG_HMACSHA224:
274 		md_type = ISC_MD_SHA224;
275 		break;
276 	case ISCCC_ALG_HMACSHA256:
277 		md_type = ISC_MD_SHA256;
278 		break;
279 	case ISCCC_ALG_HMACSHA384:
280 		md_type = ISC_MD_SHA384;
281 		break;
282 	case ISCCC_ALG_HMACSHA512:
283 		md_type = ISC_MD_SHA512;
284 		break;
285 	default:
286 		return (ISC_R_NOTIMPLEMENTED);
287 	}
288 
289 	result = isc_hmac(md_type, secret->rstart, REGION_SIZE(*secret), data,
290 			  length, digest, &digestlen);
291 	if (result != ISC_R_SUCCESS) {
292 		return (result);
293 	}
294 	source.rend = digest + digestlen;
295 
296 	memset(digestb64, 0, sizeof(digestb64));
297 	target.rstart = digestb64;
298 	target.rend = digestb64 + sizeof(digestb64);
299 	result = isccc_base64_encode(&source, 64, "", &target);
300 	if (result != ISC_R_SUCCESS) {
301 		return (result);
302 	}
303 	if (algorithm == ISCCC_ALG_HMACMD5) {
304 		PUT_MEM(digestb64, HMD5_LENGTH, hmac);
305 	} else {
306 		PUT_MEM(digestb64, HSHA_LENGTH, hmac);
307 	}
308 	return (ISC_R_SUCCESS);
309 }
310 
311 isc_result_t
isccc_cc_towire(isccc_sexpr_t * alist,isc_buffer_t ** buffer,uint32_t algorithm,isccc_region_t * secret)312 isccc_cc_towire(isccc_sexpr_t *alist, isc_buffer_t **buffer, uint32_t algorithm,
313 		isccc_region_t *secret) {
314 	unsigned int hmac_base, signed_base;
315 	isc_result_t result;
316 
317 	result = isc_buffer_reserve(buffer,
318 				    4 + ((algorithm == ISCCC_ALG_HMACMD5)
319 						 ? sizeof(auth_hmd5)
320 						 : sizeof(auth_hsha)));
321 	if (result != ISC_R_SUCCESS) {
322 		return (ISC_R_NOSPACE);
323 	}
324 
325 	/*
326 	 * Emit protocol version.
327 	 */
328 	isc_buffer_putuint32(*buffer, 1);
329 
330 	if (secret != NULL) {
331 		/*
332 		 * Emit _auth section with zeroed HMAC signature.
333 		 * We'll replace the zeros with the real signature once
334 		 * we know what it is.
335 		 */
336 		if (algorithm == ISCCC_ALG_HMACMD5) {
337 			hmac_base = (*buffer)->used + HMD5_OFFSET;
338 			isc_buffer_putmem(*buffer, auth_hmd5,
339 					  sizeof(auth_hmd5));
340 		} else {
341 			unsigned char *hmac_alg;
342 
343 			hmac_base = (*buffer)->used + HSHA_OFFSET;
344 			hmac_alg = (unsigned char *)isc_buffer_used(*buffer) +
345 				   HSHA_OFFSET - 1;
346 			isc_buffer_putmem(*buffer, auth_hsha,
347 					  sizeof(auth_hsha));
348 			*hmac_alg = algorithm;
349 		}
350 	} else {
351 		hmac_base = 0;
352 	}
353 	signed_base = (*buffer)->used;
354 	/*
355 	 * Delete any existing _auth section so that we don't try
356 	 * to encode it.
357 	 */
358 	isccc_alist_delete(alist, "_auth");
359 	/*
360 	 * Emit the message.
361 	 */
362 	result = table_towire(alist, buffer);
363 	if (result != ISC_R_SUCCESS) {
364 		return (result);
365 	}
366 	if (secret != NULL) {
367 		return (sign((unsigned char *)(*buffer)->base + signed_base,
368 			     (*buffer)->used - signed_base,
369 			     (unsigned char *)(*buffer)->base + hmac_base,
370 			     algorithm, secret));
371 	}
372 	return (ISC_R_SUCCESS);
373 }
374 
375 static isc_result_t
verify(isccc_sexpr_t * alist,unsigned char * data,unsigned int length,uint32_t algorithm,isccc_region_t * secret)376 verify(isccc_sexpr_t *alist, unsigned char *data, unsigned int length,
377        uint32_t algorithm, isccc_region_t *secret) {
378 	const isc_md_type_t *md_type;
379 	isccc_region_t source;
380 	isccc_region_t target;
381 	isc_result_t result;
382 	isccc_sexpr_t *_auth, *hmac;
383 	unsigned char digest[ISC_MAX_MD_SIZE];
384 	unsigned int digestlen;
385 	unsigned char digestb64[HSHA_LENGTH * 4];
386 
387 	/*
388 	 * Extract digest.
389 	 */
390 	_auth = isccc_alist_lookup(alist, "_auth");
391 	if (!isccc_alist_alistp(_auth)) {
392 		return (ISC_R_FAILURE);
393 	}
394 	if (algorithm == ISCCC_ALG_HMACMD5) {
395 		hmac = isccc_alist_lookup(_auth, "hmd5");
396 	} else {
397 		hmac = isccc_alist_lookup(_auth, "hsha");
398 	}
399 	if (!isccc_sexpr_binaryp(hmac)) {
400 		return (ISC_R_FAILURE);
401 	}
402 	/*
403 	 * Compute digest.
404 	 */
405 	source.rstart = digest;
406 
407 	switch (algorithm) {
408 	case ISCCC_ALG_HMACMD5:
409 		md_type = ISC_MD_MD5;
410 		break;
411 	case ISCCC_ALG_HMACSHA1:
412 		md_type = ISC_MD_SHA1;
413 		break;
414 	case ISCCC_ALG_HMACSHA224:
415 		md_type = ISC_MD_SHA224;
416 		break;
417 	case ISCCC_ALG_HMACSHA256:
418 		md_type = ISC_MD_SHA256;
419 		break;
420 	case ISCCC_ALG_HMACSHA384:
421 		md_type = ISC_MD_SHA384;
422 		break;
423 	case ISCCC_ALG_HMACSHA512:
424 		md_type = ISC_MD_SHA512;
425 		break;
426 	default:
427 		return (ISC_R_NOTIMPLEMENTED);
428 	}
429 
430 	result = isc_hmac(md_type, secret->rstart, REGION_SIZE(*secret), data,
431 			  length, digest, &digestlen);
432 	if (result != ISC_R_SUCCESS) {
433 		return (result);
434 	}
435 	source.rend = digest + digestlen;
436 
437 	target.rstart = digestb64;
438 	target.rend = digestb64 + sizeof(digestb64);
439 	memset(digestb64, 0, sizeof(digestb64));
440 	result = isccc_base64_encode(&source, 64, "", &target);
441 	if (result != ISC_R_SUCCESS) {
442 		return (result);
443 	}
444 
445 	/*
446 	 * Verify.
447 	 */
448 	if (algorithm == ISCCC_ALG_HMACMD5) {
449 		isccc_region_t *region;
450 		unsigned char *value;
451 
452 		region = isccc_sexpr_tobinary(hmac);
453 		if ((region->rend - region->rstart) != HMD5_LENGTH) {
454 			return (ISCCC_R_BADAUTH);
455 		}
456 		value = region->rstart;
457 		if (!isc_safe_memequal(value, digestb64, HMD5_LENGTH)) {
458 			return (ISCCC_R_BADAUTH);
459 		}
460 	} else {
461 		isccc_region_t *region;
462 		unsigned char *value;
463 		uint32_t valalg;
464 
465 		region = isccc_sexpr_tobinary(hmac);
466 
467 		/*
468 		 * Note: with non-MD5 algorithms, there's an extra octet
469 		 * to identify which algorithm is in use.
470 		 */
471 		if ((region->rend - region->rstart) != HSHA_LENGTH + 1) {
472 			return (ISCCC_R_BADAUTH);
473 		}
474 		value = region->rstart;
475 		GET8(valalg, value);
476 		if ((valalg != algorithm) ||
477 		    !isc_safe_memequal(value, digestb64, HSHA_LENGTH)) {
478 			return (ISCCC_R_BADAUTH);
479 		}
480 	}
481 
482 	return (ISC_R_SUCCESS);
483 }
484 
485 static isc_result_t
486 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
487 	       uint32_t algorithm, isccc_sexpr_t **alistp);
488 
489 static isc_result_t
490 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp);
491 
492 static isc_result_t
value_fromwire(isccc_region_t * source,isccc_sexpr_t ** valuep)493 value_fromwire(isccc_region_t *source, isccc_sexpr_t **valuep) {
494 	unsigned int msgtype;
495 	uint32_t len;
496 	isccc_sexpr_t *value;
497 	isccc_region_t active;
498 	isc_result_t result;
499 
500 	if (REGION_SIZE(*source) < 1 + 4) {
501 		return (ISC_R_UNEXPECTEDEND);
502 	}
503 	GET8(msgtype, source->rstart);
504 	GET32(len, source->rstart);
505 	if (REGION_SIZE(*source) < len) {
506 		return (ISC_R_UNEXPECTEDEND);
507 	}
508 	active.rstart = source->rstart;
509 	active.rend = active.rstart + len;
510 	source->rstart = active.rend;
511 	if (msgtype == ISCCC_CCMSGTYPE_BINARYDATA) {
512 		value = isccc_sexpr_frombinary(&active);
513 		if (value != NULL) {
514 			*valuep = value;
515 			result = ISC_R_SUCCESS;
516 		} else {
517 			result = ISC_R_NOMEMORY;
518 		}
519 	} else if (msgtype == ISCCC_CCMSGTYPE_TABLE) {
520 		result = table_fromwire(&active, NULL, 0, valuep);
521 	} else if (msgtype == ISCCC_CCMSGTYPE_LIST) {
522 		result = list_fromwire(&active, valuep);
523 	} else {
524 		result = ISCCC_R_SYNTAX;
525 	}
526 
527 	return (result);
528 }
529 
530 static isc_result_t
table_fromwire(isccc_region_t * source,isccc_region_t * secret,uint32_t algorithm,isccc_sexpr_t ** alistp)531 table_fromwire(isccc_region_t *source, isccc_region_t *secret,
532 	       uint32_t algorithm, isccc_sexpr_t **alistp) {
533 	char key[256];
534 	uint32_t len;
535 	isc_result_t result;
536 	isccc_sexpr_t *alist, *value;
537 	bool first_tag;
538 	unsigned char *checksum_rstart;
539 
540 	REQUIRE(alistp != NULL && *alistp == NULL);
541 
542 	checksum_rstart = NULL;
543 	first_tag = true;
544 	alist = isccc_alist_create();
545 	if (alist == NULL) {
546 		return (ISC_R_NOMEMORY);
547 	}
548 
549 	while (!REGION_EMPTY(*source)) {
550 		GET8(len, source->rstart);
551 		if (REGION_SIZE(*source) < len) {
552 			result = ISC_R_UNEXPECTEDEND;
553 			goto bad;
554 		}
555 		GET_MEM(key, len, source->rstart);
556 		key[len] = '\0'; /* Ensure NUL termination. */
557 		value = NULL;
558 		result = value_fromwire(source, &value);
559 		if (result != ISC_R_SUCCESS) {
560 			goto bad;
561 		}
562 		if (isccc_alist_define(alist, key, value) == NULL) {
563 			result = ISC_R_NOMEMORY;
564 			goto bad;
565 		}
566 		if (first_tag && secret != NULL && strcmp(key, "_auth") == 0) {
567 			checksum_rstart = source->rstart;
568 		}
569 		first_tag = false;
570 	}
571 
572 	if (secret != NULL) {
573 		if (checksum_rstart != NULL) {
574 			result = verify(
575 				alist, checksum_rstart,
576 				(unsigned int)(source->rend - checksum_rstart),
577 				algorithm, secret);
578 		} else {
579 			result = ISCCC_R_BADAUTH;
580 		}
581 	} else {
582 		result = ISC_R_SUCCESS;
583 	}
584 
585 bad:
586 	if (result == ISC_R_SUCCESS) {
587 		*alistp = alist;
588 	} else {
589 		isccc_sexpr_free(&alist);
590 	}
591 
592 	return (result);
593 }
594 
595 static isc_result_t
list_fromwire(isccc_region_t * source,isccc_sexpr_t ** listp)596 list_fromwire(isccc_region_t *source, isccc_sexpr_t **listp) {
597 	isccc_sexpr_t *list, *value;
598 	isc_result_t result;
599 
600 	list = NULL;
601 	while (!REGION_EMPTY(*source)) {
602 		value = NULL;
603 		result = value_fromwire(source, &value);
604 		if (result != ISC_R_SUCCESS) {
605 			isccc_sexpr_free(&list);
606 			return (result);
607 		}
608 		if (isccc_sexpr_addtolist(&list, value) == NULL) {
609 			isccc_sexpr_free(&value);
610 			isccc_sexpr_free(&list);
611 			return (ISC_R_NOMEMORY);
612 		}
613 	}
614 
615 	*listp = list;
616 
617 	return (ISC_R_SUCCESS);
618 }
619 
620 isc_result_t
isccc_cc_fromwire(isccc_region_t * source,isccc_sexpr_t ** alistp,uint32_t algorithm,isccc_region_t * secret)621 isccc_cc_fromwire(isccc_region_t *source, isccc_sexpr_t **alistp,
622 		  uint32_t algorithm, isccc_region_t *secret) {
623 	unsigned int size;
624 	uint32_t version;
625 
626 	size = REGION_SIZE(*source);
627 	if (size < 4) {
628 		return (ISC_R_UNEXPECTEDEND);
629 	}
630 	GET32(version, source->rstart);
631 	if (version != 1) {
632 		return (ISCCC_R_UNKNOWNVERSION);
633 	}
634 
635 	return (table_fromwire(source, secret, algorithm, alistp));
636 }
637 
638 static isc_result_t
createmessage(uint32_t version,const char * from,const char * to,uint32_t serial,isccc_time_t now,isccc_time_t expires,isccc_sexpr_t ** alistp,bool want_expires)639 createmessage(uint32_t version, const char *from, const char *to,
640 	      uint32_t serial, isccc_time_t now, isccc_time_t expires,
641 	      isccc_sexpr_t **alistp, bool want_expires) {
642 	isccc_sexpr_t *alist, *_ctrl, *_data;
643 	isc_result_t result;
644 
645 	REQUIRE(alistp != NULL && *alistp == NULL);
646 
647 	if (version != 1) {
648 		return (ISCCC_R_UNKNOWNVERSION);
649 	}
650 
651 	alist = isccc_alist_create();
652 	if (alist == NULL) {
653 		return (ISC_R_NOMEMORY);
654 	}
655 
656 	result = ISC_R_NOMEMORY;
657 
658 	_ctrl = isccc_alist_create();
659 	if (_ctrl == NULL) {
660 		goto bad;
661 	}
662 	if (isccc_alist_define(alist, "_ctrl", _ctrl) == NULL) {
663 		isccc_sexpr_free(&_ctrl);
664 		goto bad;
665 	}
666 
667 	_data = isccc_alist_create();
668 	if (_data == NULL) {
669 		goto bad;
670 	}
671 	if (isccc_alist_define(alist, "_data", _data) == NULL) {
672 		isccc_sexpr_free(&_data);
673 		goto bad;
674 	}
675 
676 	if (isccc_cc_defineuint32(_ctrl, "_ser", serial) == NULL ||
677 	    isccc_cc_defineuint32(_ctrl, "_tim", now) == NULL ||
678 	    (want_expires &&
679 	     isccc_cc_defineuint32(_ctrl, "_exp", expires) == NULL))
680 	{
681 		goto bad;
682 	}
683 	if (from != NULL && isccc_cc_definestring(_ctrl, "_frm", from) == NULL)
684 	{
685 		goto bad;
686 	}
687 	if (to != NULL && isccc_cc_definestring(_ctrl, "_to", to) == NULL) {
688 		goto bad;
689 	}
690 
691 	*alistp = alist;
692 
693 	return (ISC_R_SUCCESS);
694 
695 bad:
696 	isccc_sexpr_free(&alist);
697 
698 	return (result);
699 }
700 
701 isc_result_t
isccc_cc_createmessage(uint32_t version,const char * from,const char * to,uint32_t serial,isccc_time_t now,isccc_time_t expires,isccc_sexpr_t ** alistp)702 isccc_cc_createmessage(uint32_t version, const char *from, const char *to,
703 		       uint32_t serial, isccc_time_t now, isccc_time_t expires,
704 		       isccc_sexpr_t **alistp) {
705 	return (createmessage(version, from, to, serial, now, expires, alistp,
706 			      true));
707 }
708 
709 isc_result_t
isccc_cc_createack(isccc_sexpr_t * message,bool ok,isccc_sexpr_t ** ackp)710 isccc_cc_createack(isccc_sexpr_t *message, bool ok, isccc_sexpr_t **ackp) {
711 	char *_frm, *_to;
712 	uint32_t serial;
713 	isccc_sexpr_t *ack, *_ctrl;
714 	isc_result_t result;
715 	isccc_time_t t;
716 
717 	REQUIRE(ackp != NULL && *ackp == NULL);
718 
719 	_ctrl = isccc_alist_lookup(message, "_ctrl");
720 	if (!isccc_alist_alistp(_ctrl) ||
721 	    isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
722 	    isccc_cc_lookupuint32(_ctrl, "_tim", &t) != ISC_R_SUCCESS)
723 	{
724 		return (ISC_R_FAILURE);
725 	}
726 	/*
727 	 * _frm and _to are optional.
728 	 */
729 	_frm = NULL;
730 	(void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
731 	_to = NULL;
732 	(void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
733 	/*
734 	 * Create the ack.
735 	 */
736 	ack = NULL;
737 	result = createmessage(1, _to, _frm, serial, t, 0, &ack, false);
738 	if (result != ISC_R_SUCCESS) {
739 		return (result);
740 	}
741 
742 	_ctrl = isccc_alist_lookup(ack, "_ctrl");
743 	if (_ctrl == NULL) {
744 		result = ISC_R_FAILURE;
745 		goto bad;
746 	}
747 	if (isccc_cc_definestring(ack, "_ack", (ok) ? "1" : "0") == NULL) {
748 		result = ISC_R_NOMEMORY;
749 		goto bad;
750 	}
751 
752 	*ackp = ack;
753 
754 	return (ISC_R_SUCCESS);
755 
756 bad:
757 	isccc_sexpr_free(&ack);
758 
759 	return (result);
760 }
761 
762 bool
isccc_cc_isack(isccc_sexpr_t * message)763 isccc_cc_isack(isccc_sexpr_t *message) {
764 	isccc_sexpr_t *_ctrl;
765 
766 	_ctrl = isccc_alist_lookup(message, "_ctrl");
767 	if (!isccc_alist_alistp(_ctrl)) {
768 		return (false);
769 	}
770 	if (isccc_cc_lookupstring(_ctrl, "_ack", NULL) == ISC_R_SUCCESS) {
771 		return (true);
772 	}
773 	return (false);
774 }
775 
776 bool
isccc_cc_isreply(isccc_sexpr_t * message)777 isccc_cc_isreply(isccc_sexpr_t *message) {
778 	isccc_sexpr_t *_ctrl;
779 
780 	_ctrl = isccc_alist_lookup(message, "_ctrl");
781 	if (!isccc_alist_alistp(_ctrl)) {
782 		return (false);
783 	}
784 	if (isccc_cc_lookupstring(_ctrl, "_rpl", NULL) == ISC_R_SUCCESS) {
785 		return (true);
786 	}
787 	return (false);
788 }
789 
790 isc_result_t
isccc_cc_createresponse(isccc_sexpr_t * message,isccc_time_t now,isccc_time_t expires,isccc_sexpr_t ** alistp)791 isccc_cc_createresponse(isccc_sexpr_t *message, isccc_time_t now,
792 			isccc_time_t expires, isccc_sexpr_t **alistp) {
793 	char *_frm, *_to, *type = NULL;
794 	uint32_t serial;
795 	isccc_sexpr_t *alist, *_ctrl, *_data;
796 	isc_result_t result;
797 
798 	REQUIRE(alistp != NULL && *alistp == NULL);
799 
800 	_ctrl = isccc_alist_lookup(message, "_ctrl");
801 	_data = isccc_alist_lookup(message, "_data");
802 	if (!isccc_alist_alistp(_ctrl) || !isccc_alist_alistp(_data) ||
803 	    isccc_cc_lookupuint32(_ctrl, "_ser", &serial) != ISC_R_SUCCESS ||
804 	    isccc_cc_lookupstring(_data, "type", &type) != ISC_R_SUCCESS)
805 	{
806 		return (ISC_R_FAILURE);
807 	}
808 	/*
809 	 * _frm and _to are optional.
810 	 */
811 	_frm = NULL;
812 	(void)isccc_cc_lookupstring(_ctrl, "_frm", &_frm);
813 	_to = NULL;
814 	(void)isccc_cc_lookupstring(_ctrl, "_to", &_to);
815 	/*
816 	 * Create the response.
817 	 */
818 	alist = NULL;
819 	result = isccc_cc_createmessage(1, _to, _frm, serial, now, expires,
820 					&alist);
821 	if (result != ISC_R_SUCCESS) {
822 		return (result);
823 	}
824 
825 	_ctrl = isccc_alist_lookup(alist, "_ctrl");
826 	if (_ctrl == NULL) {
827 		result = ISC_R_FAILURE;
828 		goto bad;
829 	}
830 
831 	_data = isccc_alist_lookup(alist, "_data");
832 	if (_data == NULL) {
833 		result = ISC_R_FAILURE;
834 		goto bad;
835 	}
836 
837 	if (isccc_cc_definestring(_ctrl, "_rpl", "1") == NULL ||
838 	    isccc_cc_definestring(_data, "type", type) == NULL)
839 	{
840 		result = ISC_R_NOMEMORY;
841 		goto bad;
842 	}
843 
844 	*alistp = alist;
845 
846 	return (ISC_R_SUCCESS);
847 
848 bad:
849 	isccc_sexpr_free(&alist);
850 	return (result);
851 }
852 
853 isccc_sexpr_t *
isccc_cc_definestring(isccc_sexpr_t * alist,const char * key,const char * str)854 isccc_cc_definestring(isccc_sexpr_t *alist, const char *key, const char *str) {
855 	size_t len;
856 	isccc_region_t r;
857 
858 	len = strlen(str);
859 	DE_CONST(str, r.rstart);
860 	r.rend = r.rstart + len;
861 
862 	return (isccc_alist_definebinary(alist, key, &r));
863 }
864 
865 isccc_sexpr_t *
isccc_cc_defineuint32(isccc_sexpr_t * alist,const char * key,uint32_t i)866 isccc_cc_defineuint32(isccc_sexpr_t *alist, const char *key, uint32_t i) {
867 	char b[100];
868 	size_t len;
869 	isccc_region_t r;
870 
871 	snprintf(b, sizeof(b), "%u", i);
872 	len = strlen(b);
873 	r.rstart = (unsigned char *)b;
874 	r.rend = (unsigned char *)b + len;
875 
876 	return (isccc_alist_definebinary(alist, key, &r));
877 }
878 
879 isc_result_t
isccc_cc_lookupstring(isccc_sexpr_t * alist,const char * key,char ** strp)880 isccc_cc_lookupstring(isccc_sexpr_t *alist, const char *key, char **strp) {
881 	isccc_sexpr_t *kv, *v;
882 
883 	REQUIRE(strp == NULL || *strp == NULL);
884 
885 	kv = isccc_alist_assq(alist, key);
886 	if (kv != NULL) {
887 		v = ISCCC_SEXPR_CDR(kv);
888 		if (isccc_sexpr_binaryp(v)) {
889 			if (strp != NULL) {
890 				*strp = isccc_sexpr_tostring(v);
891 			}
892 			return (ISC_R_SUCCESS);
893 		} else {
894 			return (ISC_R_EXISTS);
895 		}
896 	}
897 
898 	return (ISC_R_NOTFOUND);
899 }
900 
901 isc_result_t
isccc_cc_lookupuint32(isccc_sexpr_t * alist,const char * key,uint32_t * uintp)902 isccc_cc_lookupuint32(isccc_sexpr_t *alist, const char *key, uint32_t *uintp) {
903 	isccc_sexpr_t *kv, *v;
904 
905 	kv = isccc_alist_assq(alist, key);
906 	if (kv != NULL) {
907 		v = ISCCC_SEXPR_CDR(kv);
908 		if (isccc_sexpr_binaryp(v)) {
909 			if (uintp != NULL) {
910 				*uintp = (uint32_t)strtoul(
911 					isccc_sexpr_tostring(v), NULL, 10);
912 			}
913 			return (ISC_R_SUCCESS);
914 		} else {
915 			return (ISC_R_EXISTS);
916 		}
917 	}
918 
919 	return (ISC_R_NOTFOUND);
920 }
921 
922 static void
symtab_undefine(char * key,unsigned int type,isccc_symvalue_t value,void * arg)923 symtab_undefine(char *key, unsigned int type, isccc_symvalue_t value,
924 		void *arg) {
925 	UNUSED(type);
926 	UNUSED(value);
927 	UNUSED(arg);
928 
929 	free(key);
930 }
931 
932 static bool
symtab_clean(char * key,unsigned int type,isccc_symvalue_t value,void * arg)933 symtab_clean(char *key, unsigned int type, isccc_symvalue_t value, void *arg) {
934 	isccc_time_t *now;
935 
936 	UNUSED(key);
937 	UNUSED(type);
938 
939 	now = arg;
940 
941 	if (*now < value.as_uinteger) {
942 		return (false);
943 	}
944 	if ((*now - value.as_uinteger) < DUP_LIFETIME) {
945 		return (false);
946 	}
947 	return (true);
948 }
949 
950 isc_result_t
isccc_cc_createsymtab(isccc_symtab_t ** symtabp)951 isccc_cc_createsymtab(isccc_symtab_t **symtabp) {
952 	return (isccc_symtab_create(11897, symtab_undefine, NULL, false,
953 				    symtabp));
954 }
955 
956 void
isccc_cc_cleansymtab(isccc_symtab_t * symtab,isccc_time_t now)957 isccc_cc_cleansymtab(isccc_symtab_t *symtab, isccc_time_t now) {
958 	isccc_symtab_foreach(symtab, symtab_clean, &now);
959 }
960 
961 static bool
has_whitespace(const char * str)962 has_whitespace(const char *str) {
963 	char c;
964 
965 	if (str == NULL) {
966 		return (false);
967 	}
968 	while ((c = *str++) != '\0') {
969 		if (c == ' ' || c == '\t' || c == '\n') {
970 			return (true);
971 		}
972 	}
973 	return (false);
974 }
975 
976 isc_result_t
isccc_cc_checkdup(isccc_symtab_t * symtab,isccc_sexpr_t * message,isccc_time_t now)977 isccc_cc_checkdup(isccc_symtab_t *symtab, isccc_sexpr_t *message,
978 		  isccc_time_t now) {
979 	const char *_frm;
980 	const char *_to;
981 	char *_ser = NULL, *_tim = NULL, *tmp;
982 	isc_result_t result;
983 	char *key;
984 	size_t len;
985 	isccc_symvalue_t value;
986 	isccc_sexpr_t *_ctrl;
987 
988 	_ctrl = isccc_alist_lookup(message, "_ctrl");
989 	if (!isccc_alist_alistp(_ctrl) ||
990 	    isccc_cc_lookupstring(_ctrl, "_ser", &_ser) != ISC_R_SUCCESS ||
991 	    isccc_cc_lookupstring(_ctrl, "_tim", &_tim) != ISC_R_SUCCESS)
992 	{
993 		return (ISC_R_FAILURE);
994 	}
995 
996 	INSIST(_ser != NULL);
997 	INSIST(_tim != NULL);
998 
999 	/*
1000 	 * _frm and _to are optional.
1001 	 */
1002 	tmp = NULL;
1003 	if (isccc_cc_lookupstring(_ctrl, "_frm", &tmp) != ISC_R_SUCCESS) {
1004 		_frm = "";
1005 	} else {
1006 		_frm = tmp;
1007 	}
1008 	tmp = NULL;
1009 	if (isccc_cc_lookupstring(_ctrl, "_to", &tmp) != ISC_R_SUCCESS) {
1010 		_to = "";
1011 	} else {
1012 		_to = tmp;
1013 	}
1014 	/*
1015 	 * Ensure there is no newline in any of the strings.  This is so
1016 	 * we can write them to a file later.
1017 	 */
1018 	if (has_whitespace(_frm) || has_whitespace(_to) ||
1019 	    has_whitespace(_ser) || has_whitespace(_tim))
1020 	{
1021 		return (ISC_R_FAILURE);
1022 	}
1023 	len = strlen(_frm) + strlen(_to) + strlen(_ser) + strlen(_tim) + 4;
1024 	key = malloc(len);
1025 	if (key == NULL) {
1026 		return (ISC_R_NOMEMORY);
1027 	}
1028 	snprintf(key, len, "%s;%s;%s;%s", _frm, _to, _ser, _tim);
1029 	value.as_uinteger = now;
1030 	result = isccc_symtab_define(symtab, key, ISCCC_SYMTYPE_CCDUP, value,
1031 				     isccc_symexists_reject);
1032 	if (result != ISC_R_SUCCESS) {
1033 		free(key);
1034 		return (result);
1035 	}
1036 
1037 	return (ISC_R_SUCCESS);
1038 }
1039