1 /*	$NetBSD: ipseckey_45.c,v 1.6 2014/12/10 04:37:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2005, 2007, 2009, 2011, 2012, 2014  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Id */
20 
21 #ifndef RDATA_GENERIC_IPSECKEY_45_C
22 #define RDATA_GENERIC_IPSECKEY_45_C
23 
24 #include <string.h>
25 
26 #include <isc/net.h>
27 
28 #define RRTYPE_IPSECKEY_ATTRIBUTES (0)
29 
30 static inline isc_result_t
31 fromtext_ipseckey(ARGS_FROMTEXT) {
32 	isc_token_t token;
33 	dns_name_t name;
34 	isc_buffer_t buffer;
35 	unsigned int gateway;
36 	struct in_addr addr;
37 	unsigned char addr6[16];
38 	isc_region_t region;
39 
40 	REQUIRE(type == 45);
41 
42 	UNUSED(type);
43 	UNUSED(rdclass);
44 	UNUSED(callbacks);
45 
46 	/*
47 	 * Precedence.
48 	 */
49 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
50 				      ISC_FALSE));
51 	if (token.value.as_ulong > 0xffU)
52 		RETTOK(ISC_R_RANGE);
53 	RETERR(uint8_tobuffer(token.value.as_ulong, target));
54 
55 	/*
56 	 * Gateway type.
57 	 */
58 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
59 				      ISC_FALSE));
60 	if (token.value.as_ulong > 0x3U)
61 		RETTOK(ISC_R_RANGE);
62 	RETERR(uint8_tobuffer(token.value.as_ulong, target));
63 	gateway = token.value.as_ulong;
64 
65 	/*
66 	 * Algorithm.
67 	 */
68 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
69 				      ISC_FALSE));
70 	if (token.value.as_ulong > 0xffU)
71 		RETTOK(ISC_R_RANGE);
72 	RETERR(uint8_tobuffer(token.value.as_ulong, target));
73 
74 	/*
75 	 * Gateway.
76 	 */
77 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
78 				      ISC_FALSE));
79 
80 	switch (gateway) {
81 	case 0:
82 		if (strcmp(DNS_AS_STR(token), ".") != 0)
83 			RETTOK(DNS_R_SYNTAX);
84 		break;
85 
86 	case 1:
87 		if (getquad(DNS_AS_STR(token), &addr, lexer, callbacks) != 1)
88 			RETTOK(DNS_R_BADDOTTEDQUAD);
89 		isc_buffer_availableregion(target, &region);
90 		if (region.length < 4)
91 			return (ISC_R_NOSPACE);
92 		memmove(region.base, &addr, 4);
93 		isc_buffer_add(target, 4);
94 		break;
95 
96 	case 2:
97 		if (inet_pton(AF_INET6, DNS_AS_STR(token), addr6) != 1)
98 			RETTOK(DNS_R_BADAAAA);
99 		isc_buffer_availableregion(target, &region);
100 		if (region.length < 16)
101 			return (ISC_R_NOSPACE);
102 		memmove(region.base, addr6, 16);
103 		isc_buffer_add(target, 16);
104 		break;
105 
106 	case 3:
107 		dns_name_init(&name, NULL);
108 		buffer_fromregion(&buffer, &token.value.as_region);
109 		origin = (origin != NULL) ? origin : dns_rootname;
110 		RETTOK(dns_name_fromtext(&name, &buffer, origin,
111 					 options, target));
112 		break;
113 	}
114 
115 	/*
116 	 * Public key.
117 	 */
118 	return (isc_base64_tobuffer(lexer, target, -1));
119 }
120 
121 static inline isc_result_t
122 totext_ipseckey(ARGS_TOTEXT) {
123 	isc_region_t region;
124 	dns_name_t name;
125 	char buf[sizeof("255 ")];
126 	unsigned short num;
127 	unsigned short gateway;
128 
129 	REQUIRE(rdata->type == 45);
130 	REQUIRE(rdata->length >= 3);
131 
132 	dns_name_init(&name, NULL);
133 
134 	if (rdata->data[1] > 3U)
135 		return (ISC_R_NOTIMPLEMENTED);
136 
137 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
138 		RETERR(str_totext("( ", target));
139 
140 	/*
141 	 * Precedence.
142 	 */
143 	dns_rdata_toregion(rdata, &region);
144 	num = uint8_fromregion(&region);
145 	isc_region_consume(&region, 1);
146 	sprintf(buf, "%u ", num);
147 	RETERR(str_totext(buf, target));
148 
149 	/*
150 	 * Gateway type.
151 	 */
152 	gateway = uint8_fromregion(&region);
153 	isc_region_consume(&region, 1);
154 	sprintf(buf, "%u ", gateway);
155 	RETERR(str_totext(buf, target));
156 
157 	/*
158 	 * Algorithm.
159 	 */
160 	num = uint8_fromregion(&region);
161 	isc_region_consume(&region, 1);
162 	sprintf(buf, "%u ", num);
163 	RETERR(str_totext(buf, target));
164 
165 	/*
166 	 * Gateway.
167 	 */
168 	switch (gateway) {
169 	case 0:
170 		RETERR(str_totext(".", target));
171 		break;
172 
173 	case 1:
174 		RETERR(inet_totext(AF_INET, &region, target));
175 		isc_region_consume(&region, 4);
176 		break;
177 
178 	case 2:
179 		RETERR(inet_totext(AF_INET6, &region, target));
180 		isc_region_consume(&region, 16);
181 		break;
182 
183 	case 3:
184 		dns_name_fromregion(&name, &region);
185 		RETERR(dns_name_totext(&name, ISC_FALSE, target));
186 		isc_region_consume(&region, name_length(&name));
187 		break;
188 	}
189 
190 	/*
191 	 * Key.
192 	 */
193 	if (region.length > 0U) {
194 		RETERR(str_totext(tctx->linebreak, target));
195 		if (tctx->width == 0)   /* No splitting */
196 			RETERR(isc_base64_totext(&region, 60, "", target));
197 		else
198 			RETERR(isc_base64_totext(&region, tctx->width - 2,
199 						 tctx->linebreak, target));
200 	}
201 
202 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
203 		RETERR(str_totext(" )", target));
204 	return (ISC_R_SUCCESS);
205 }
206 
207 static inline isc_result_t
208 fromwire_ipseckey(ARGS_FROMWIRE) {
209 	dns_name_t name;
210 	isc_region_t region;
211 
212 	REQUIRE(type == 45);
213 
214 	UNUSED(type);
215 	UNUSED(rdclass);
216 
217 	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
218 
219 	dns_name_init(&name, NULL);
220 
221 	isc_buffer_activeregion(source, &region);
222 	if (region.length < 3)
223 		return (ISC_R_UNEXPECTEDEND);
224 
225 	switch (region.base[1]) {
226 	case 0:
227 		isc_buffer_forward(source, region.length);
228 		return (mem_tobuffer(target, region.base, region.length));
229 
230 	case 1:
231 		if (region.length < 7)
232 			return (ISC_R_UNEXPECTEDEND);
233 		isc_buffer_forward(source, region.length);
234 		return (mem_tobuffer(target, region.base, region.length));
235 
236 	case 2:
237 		if (region.length < 19)
238 			return (ISC_R_UNEXPECTEDEND);
239 		isc_buffer_forward(source, region.length);
240 		return (mem_tobuffer(target, region.base, region.length));
241 
242 	case 3:
243 		RETERR(mem_tobuffer(target, region.base, 3));
244 		isc_buffer_forward(source, 3);
245 		RETERR(dns_name_fromwire(&name, source, dctx, options, target));
246 		isc_buffer_activeregion(source, &region);
247 		isc_buffer_forward(source, region.length);
248 		return(mem_tobuffer(target, region.base, region.length));
249 
250 	default:
251 		return (ISC_R_NOTIMPLEMENTED);
252 	}
253 }
254 
255 static inline isc_result_t
256 towire_ipseckey(ARGS_TOWIRE) {
257 	isc_region_t region;
258 
259 	REQUIRE(rdata->type == 45);
260 	REQUIRE(rdata->length != 0);
261 
262 	UNUSED(cctx);
263 
264 	dns_rdata_toregion(rdata, &region);
265 	return (mem_tobuffer(target, region.base, region.length));
266 }
267 
268 static inline int
269 compare_ipseckey(ARGS_COMPARE) {
270 	isc_region_t region1;
271 	isc_region_t region2;
272 
273 	REQUIRE(rdata1->type == rdata2->type);
274 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
275 	REQUIRE(rdata1->type == 45);
276 	REQUIRE(rdata1->length >= 3);
277 	REQUIRE(rdata2->length >= 3);
278 
279 	dns_rdata_toregion(rdata1, &region1);
280 	dns_rdata_toregion(rdata2, &region2);
281 
282 	return (isc_region_compare(&region1, &region2));
283 }
284 
285 static inline isc_result_t
286 fromstruct_ipseckey(ARGS_FROMSTRUCT) {
287 	dns_rdata_ipseckey_t *ipseckey = source;
288 	isc_region_t region;
289 	isc_uint32_t n;
290 
291 	REQUIRE(type == 45);
292 	REQUIRE(source != NULL);
293 	REQUIRE(ipseckey->common.rdtype == type);
294 	REQUIRE(ipseckey->common.rdclass == rdclass);
295 
296 	UNUSED(type);
297 	UNUSED(rdclass);
298 
299 	if (ipseckey->gateway_type > 3U)
300 		return (ISC_R_NOTIMPLEMENTED);
301 
302 	RETERR(uint8_tobuffer(ipseckey->precedence, target));
303 	RETERR(uint8_tobuffer(ipseckey->gateway_type, target));
304 	RETERR(uint8_tobuffer(ipseckey->algorithm, target));
305 
306 	switch  (ipseckey->gateway_type) {
307 	case 0:
308 		break;
309 
310 	case 1:
311 		n = ntohl(ipseckey->in_addr.s_addr);
312 		RETERR(uint32_tobuffer(n, target));
313 		break;
314 
315 	case 2:
316 		RETERR(mem_tobuffer(target, ipseckey->in6_addr.s6_addr, 16));
317 		break;
318 
319 	case 3:
320 		dns_name_toregion(&ipseckey->gateway, &region);
321 		RETERR(isc_buffer_copyregion(target, &region));
322 		break;
323 	}
324 
325 	return (mem_tobuffer(target, ipseckey->key, ipseckey->keylength));
326 }
327 
328 static inline isc_result_t
329 tostruct_ipseckey(ARGS_TOSTRUCT) {
330 	isc_region_t region;
331 	dns_rdata_ipseckey_t *ipseckey = target;
332 	dns_name_t name;
333 	isc_uint32_t n;
334 
335 	REQUIRE(rdata->type == 45);
336 	REQUIRE(target != NULL);
337 	REQUIRE(rdata->length >= 3);
338 
339 	if (rdata->data[1] > 3U)
340 		return (ISC_R_NOTIMPLEMENTED);
341 
342 	ipseckey->common.rdclass = rdata->rdclass;
343 	ipseckey->common.rdtype = rdata->type;
344 	ISC_LINK_INIT(&ipseckey->common, link);
345 
346 	dns_name_init(&name, NULL);
347 	dns_rdata_toregion(rdata, &region);
348 
349 	ipseckey->precedence = uint8_fromregion(&region);
350 	isc_region_consume(&region, 1);
351 
352 	ipseckey->gateway_type = uint8_fromregion(&region);
353 	isc_region_consume(&region, 1);
354 
355 	ipseckey->algorithm = uint8_fromregion(&region);
356 	isc_region_consume(&region, 1);
357 
358 	switch (ipseckey->gateway_type) {
359 	case 0:
360 		break;
361 
362 	case 1:
363 		n = uint32_fromregion(&region);
364 		ipseckey->in_addr.s_addr = htonl(n);
365 		isc_region_consume(&region, 4);
366 		break;
367 
368 	case 2:
369 		memmove(ipseckey->in6_addr.s6_addr, region.base, 16);
370 		isc_region_consume(&region, 16);
371 		break;
372 
373 	case 3:
374 		dns_name_init(&ipseckey->gateway, NULL);
375 		dns_name_fromregion(&name, &region);
376 		RETERR(name_duporclone(&name, mctx, &ipseckey->gateway));
377 		isc_region_consume(&region, name_length(&name));
378 		break;
379 	}
380 
381 	ipseckey->keylength = region.length;
382 	if (ipseckey->keylength != 0U) {
383 		ipseckey->key = mem_maybedup(mctx, region.base,
384 					     ipseckey->keylength);
385 		if (ipseckey->key == NULL) {
386 			if (ipseckey->gateway_type == 3)
387 				dns_name_free(&ipseckey->gateway,
388 					      ipseckey->mctx);
389 			return (ISC_R_NOMEMORY);
390 		}
391 	} else
392 		ipseckey->key = NULL;
393 
394 	ipseckey->mctx = mctx;
395 	return (ISC_R_SUCCESS);
396 }
397 
398 static inline void
399 freestruct_ipseckey(ARGS_FREESTRUCT) {
400 	dns_rdata_ipseckey_t *ipseckey = source;
401 
402 	REQUIRE(source != NULL);
403 	REQUIRE(ipseckey->common.rdtype == 45);
404 
405 	if (ipseckey->mctx == NULL)
406 		return;
407 
408 	if (ipseckey->gateway_type == 3)
409 		dns_name_free(&ipseckey->gateway, ipseckey->mctx);
410 
411 	if (ipseckey->key != NULL)
412 		isc_mem_free(ipseckey->mctx, ipseckey->key);
413 
414 	ipseckey->mctx = NULL;
415 }
416 
417 static inline isc_result_t
418 additionaldata_ipseckey(ARGS_ADDLDATA) {
419 
420 	REQUIRE(rdata->type == 45);
421 
422 	UNUSED(rdata);
423 	UNUSED(add);
424 	UNUSED(arg);
425 
426 	return (ISC_R_SUCCESS);
427 }
428 
429 static inline isc_result_t
430 digest_ipseckey(ARGS_DIGEST) {
431 	isc_region_t region;
432 
433 	REQUIRE(rdata->type == 45);
434 
435 	dns_rdata_toregion(rdata, &region);
436 	return ((digest)(arg, &region));
437 }
438 
439 static inline isc_boolean_t
440 checkowner_ipseckey(ARGS_CHECKOWNER) {
441 
442 	REQUIRE(type == 45);
443 
444 	UNUSED(name);
445 	UNUSED(type);
446 	UNUSED(rdclass);
447 	UNUSED(wildcard);
448 
449 	return (ISC_TRUE);
450 }
451 
452 static inline isc_boolean_t
453 checknames_ipseckey(ARGS_CHECKNAMES) {
454 
455 	REQUIRE(rdata->type == 45);
456 
457 	UNUSED(rdata);
458 	UNUSED(owner);
459 	UNUSED(bad);
460 
461 	return (ISC_TRUE);
462 }
463 
464 static inline int
465 casecompare_ipseckey(ARGS_COMPARE) {
466 	isc_region_t region1;
467 	isc_region_t region2;
468 	dns_name_t name1;
469 	dns_name_t name2;
470 	int order;
471 
472 	REQUIRE(rdata1->type == rdata2->type);
473 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
474 	REQUIRE(rdata1->type == 45);
475 	REQUIRE(rdata1->length >= 3);
476 	REQUIRE(rdata2->length >= 3);
477 
478 	dns_rdata_toregion(rdata1, &region1);
479 	dns_rdata_toregion(rdata2, &region2);
480 
481 	if (memcmp(region1.base, region2.base, 3) != 0 || region1.base[1] != 3)
482 		return (isc_region_compare(&region1, &region2));
483 
484 	dns_name_init(&name1, NULL);
485 	dns_name_init(&name2, NULL);
486 
487 	isc_region_consume(&region1, 3);
488 	isc_region_consume(&region2, 3);
489 
490 	dns_name_fromregion(&name1, &region1);
491 	dns_name_fromregion(&name2, &region2);
492 
493 	order = dns_name_rdatacompare(&name1, &name2);
494 	if (order != 0)
495 		return (order);
496 
497 	isc_region_consume(&region1, name_length(&name1));
498 	isc_region_consume(&region2, name_length(&name2));
499 
500 	return (isc_region_compare(&region1, &region2));
501 }
502 
503 #endif	/* RDATA_GENERIC_IPSECKEY_45_C */
504