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