1 /*	$NetBSD: hip_55.c,v 1.5 2014/12/10 04:37:59 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2009, 2011, 2013, 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: hip_55.c,v 1.8 2011/01/13 04:59:26 tbox Exp  */
20 
21 /* reviewed: TBC */
22 
23 /* RFC 5205 */
24 
25 #ifndef RDATA_GENERIC_HIP_5_C
26 #define RDATA_GENERIC_HIP_5_C
27 
28 #define RRTYPE_HIP_ATTRIBUTES (0)
29 
30 static inline isc_result_t
31 fromtext_hip(ARGS_FROMTEXT) {
32 	isc_token_t token;
33 	dns_name_t name;
34 	isc_buffer_t buffer;
35 	isc_buffer_t hit_len;
36 	isc_buffer_t key_len;
37 	unsigned char *start;
38 	size_t len;
39 
40 	REQUIRE(type == 55);
41 
42 	UNUSED(type);
43 	UNUSED(rdclass);
44 	UNUSED(callbacks);
45 
46 	/*
47 	 * Dummy HIT len.
48 	 */
49 	hit_len = *target;
50 	RETERR(uint8_tobuffer(0, target));
51 
52 	/*
53 	 * Algorithm.
54 	 */
55 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
56 				      ISC_FALSE));
57 	if (token.value.as_ulong > 0xffU)
58 		RETTOK(ISC_R_RANGE);
59 	RETERR(uint8_tobuffer(token.value.as_ulong, target));
60 
61 	/*
62 	 * Dummy KEY len.
63 	 */
64 	key_len = *target;
65 	RETERR(uint16_tobuffer(0, target));
66 
67 	/*
68 	 * HIT (base16).
69 	 */
70 	start = isc_buffer_used(target);
71 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
72 				      ISC_FALSE));
73 	RETTOK(isc_hex_decodestring(DNS_AS_STR(token), target));
74 
75 	/*
76 	 * Fill in HIT len.
77 	 */
78 	len = (unsigned char *)isc_buffer_used(target) - start;
79 	if (len > 0xffU)
80 		RETTOK(ISC_R_RANGE);
81 	RETERR(uint8_tobuffer((isc_uint32_t)len, &hit_len));
82 
83 	/*
84 	 * Public key (base64).
85 	 */
86 	start = isc_buffer_used(target);
87 	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
88 				      ISC_FALSE));
89 	RETTOK(isc_base64_decodestring(DNS_AS_STR(token), target));
90 
91 	/*
92 	 * Fill in KEY len.
93 	 */
94 	len = (unsigned char *)isc_buffer_used(target) - start;
95 	if (len > 0xffffU)
96 		RETTOK(ISC_R_RANGE);
97 	RETERR(uint16_tobuffer((isc_uint32_t)len, &key_len));
98 
99 	/*
100 	 * Rendezvous Servers.
101 	 */
102 	dns_name_init(&name, NULL);
103 	do {
104 		RETERR(isc_lex_getmastertoken(lexer, &token,
105 					      isc_tokentype_string,
106 					      ISC_TRUE));
107 		if (token.type != isc_tokentype_string)
108 			break;
109 		buffer_fromregion(&buffer, &token.value.as_region);
110 		origin = (origin != NULL) ? origin : dns_rootname;
111 		RETTOK(dns_name_fromtext(&name, &buffer, origin, options,
112 					 target));
113 	} while (1);
114 
115 	/*
116 	 * Let upper layer handle eol/eof.
117 	 */
118 	isc_lex_ungettoken(lexer, &token);
119 
120 	return (ISC_R_SUCCESS);
121 }
122 
123 static inline isc_result_t
124 totext_hip(ARGS_TOTEXT) {
125 	isc_region_t region;
126 	dns_name_t name;
127 	unsigned int length, key_len, hit_len;
128 	unsigned char algorithm;
129 	char buf[sizeof("225 ")];
130 
131 	REQUIRE(rdata->type == 55);
132 	REQUIRE(rdata->length != 0);
133 
134 	dns_rdata_toregion(rdata, &region);
135 
136 	hit_len = uint8_fromregion(&region);
137 	isc_region_consume(&region, 1);
138 
139 	algorithm = uint8_fromregion(&region);
140 	isc_region_consume(&region, 1);
141 
142 	key_len = uint16_fromregion(&region);
143 	isc_region_consume(&region, 2);
144 
145 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
146 		RETERR(str_totext("( ", target));
147 
148 	/*
149 	 * Algorithm
150 	 */
151 	sprintf(buf, "%u ", algorithm);
152 	RETERR(str_totext(buf, target));
153 
154 	/*
155 	 * HIT.
156 	 */
157 	INSIST(hit_len < region.length);
158 	length = region.length;
159 	region.length = hit_len;
160 	RETERR(isc_hex_totext(&region, 1, "", target));
161 	region.length = length - hit_len;
162 	RETERR(str_totext(tctx->linebreak, target));
163 
164 	/*
165 	 * Public KEY.
166 	 */
167 	INSIST(key_len <= region.length);
168 	length = region.length;
169 	region.length = key_len;
170 	RETERR(isc_base64_totext(&region, 1, "", target));
171 	region.length = length - key_len;
172 	RETERR(str_totext(tctx->linebreak, target));
173 
174 	/*
175 	 * Rendezvous Servers.
176 	 */
177 	dns_name_init(&name, NULL);
178 	while (region.length > 0) {
179 		dns_name_fromregion(&name, &region);
180 
181 		RETERR(dns_name_totext(&name, ISC_FALSE, target));
182 		isc_region_consume(&region, name.length);
183 		if (region.length > 0)
184 			RETERR(str_totext(tctx->linebreak, target));
185 	}
186 	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
187 		RETERR(str_totext(" )", target));
188 	return (ISC_R_SUCCESS);
189 }
190 
191 static inline isc_result_t
192 fromwire_hip(ARGS_FROMWIRE) {
193 	isc_region_t region, rr;
194 	dns_name_t name;
195 	isc_uint8_t hit_len;
196 	isc_uint16_t key_len;
197 
198 	REQUIRE(type == 55);
199 
200 	UNUSED(type);
201 	UNUSED(rdclass);
202 
203 	isc_buffer_activeregion(source, &region);
204 	if (region.length < 4U)
205 		RETERR(DNS_R_FORMERR);
206 
207 	rr = region;
208 	hit_len = uint8_fromregion(&region);
209 	if (hit_len == 0)
210 		RETERR(DNS_R_FORMERR);
211 	isc_region_consume(&region, 2);  	/* hit length + algorithm */
212 	key_len = uint16_fromregion(&region);
213 	if (key_len == 0)
214 		RETERR(DNS_R_FORMERR);
215 	isc_region_consume(&region, 2);
216 	if (region.length < (unsigned) (hit_len + key_len))
217 		RETERR(DNS_R_FORMERR);
218 
219 	RETERR(mem_tobuffer(target, rr.base, 4 + hit_len + key_len));
220 	isc_buffer_forward(source, 4 + hit_len + key_len);
221 
222 	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
223 	while (isc_buffer_activelength(source) > 0) {
224 		dns_name_init(&name, NULL);
225 		RETERR(dns_name_fromwire(&name, source, dctx, options, target));
226 	}
227 	return (ISC_R_SUCCESS);
228 }
229 
230 static inline isc_result_t
231 towire_hip(ARGS_TOWIRE) {
232 	isc_region_t region;
233 
234 	REQUIRE(rdata->type == 55);
235 	REQUIRE(rdata->length != 0);
236 
237 	UNUSED(cctx);
238 
239 	dns_rdata_toregion(rdata, &region);
240 	return (mem_tobuffer(target, region.base, region.length));
241 }
242 
243 static inline int
244 compare_hip(ARGS_COMPARE) {
245 	isc_region_t region1;
246 	isc_region_t region2;
247 
248 	REQUIRE(rdata1->type == rdata2->type);
249 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
250 	REQUIRE(rdata1->type == 55);
251 	REQUIRE(rdata1->length != 0);
252 	REQUIRE(rdata2->length != 0);
253 
254 	dns_rdata_toregion(rdata1, &region1);
255 	dns_rdata_toregion(rdata2, &region2);
256 	return (isc_region_compare(&region1, &region2));
257 }
258 
259 static inline isc_result_t
260 fromstruct_hip(ARGS_FROMSTRUCT) {
261 	dns_rdata_hip_t *hip = source;
262 	dns_rdata_hip_t myhip;
263 	isc_result_t result;
264 
265 	REQUIRE(type == 55);
266 	REQUIRE(source != NULL);
267 	REQUIRE(hip->common.rdtype == type);
268 	REQUIRE(hip->common.rdclass == rdclass);
269 	REQUIRE(hip->hit_len > 0 && hip->hit != NULL);
270 	REQUIRE(hip->key_len > 0 && hip->key != NULL);
271 	REQUIRE((hip->servers == NULL && hip->servers_len == 0) ||
272 		 (hip->servers != NULL && hip->servers_len != 0));
273 
274 	UNUSED(type);
275 	UNUSED(rdclass);
276 
277 	RETERR(uint8_tobuffer(hip->hit_len, target));
278 	RETERR(uint8_tobuffer(hip->algorithm, target));
279 	RETERR(uint16_tobuffer(hip->key_len, target));
280 	RETERR(mem_tobuffer(target, hip->hit, hip->hit_len));
281 	RETERR(mem_tobuffer(target, hip->key, hip->key_len));
282 
283 	myhip = *hip;
284 	for (result = dns_rdata_hip_first(&myhip);
285 	     result == ISC_R_SUCCESS;
286 	     result = dns_rdata_hip_next(&myhip))
287 		/* empty */;
288 
289 	return(mem_tobuffer(target, hip->servers, hip->servers_len));
290 }
291 
292 static inline isc_result_t
293 tostruct_hip(ARGS_TOSTRUCT) {
294 	isc_region_t region;
295 	dns_rdata_hip_t *hip = target;
296 
297 	REQUIRE(rdata->type == 55);
298 	REQUIRE(target != NULL);
299 	REQUIRE(rdata->length != 0);
300 
301 	hip->common.rdclass = rdata->rdclass;
302 	hip->common.rdtype = rdata->type;
303 	ISC_LINK_INIT(&hip->common, link);
304 
305 	dns_rdata_toregion(rdata, &region);
306 
307 	hip->hit_len = uint8_fromregion(&region);
308 	isc_region_consume(&region, 1);
309 
310 	hip->algorithm = uint8_fromregion(&region);
311 	isc_region_consume(&region, 1);
312 
313 	hip->key_len = uint16_fromregion(&region);
314 	isc_region_consume(&region, 2);
315 
316 	hip->hit = hip->key = hip->servers = NULL;
317 
318 	hip->hit = mem_maybedup(mctx, region.base, hip->hit_len);
319 	if (hip->hit == NULL)
320 		goto cleanup;
321 	isc_region_consume(&region, hip->hit_len);
322 
323 	INSIST(hip->key_len <= region.length);
324 
325 	hip->key = mem_maybedup(mctx, region.base, hip->key_len);
326 	if (hip->key == NULL)
327 		goto cleanup;
328 	isc_region_consume(&region, hip->key_len);
329 
330 	hip->servers_len = region.length;
331 	if (hip->servers_len != 0) {
332 		hip->servers = mem_maybedup(mctx, region.base, region.length);
333 		if (hip->servers == NULL)
334 			goto cleanup;
335 	}
336 
337 	hip->offset = hip->servers_len;
338 	hip->mctx = mctx;
339 	return (ISC_R_SUCCESS);
340 
341  cleanup:
342 	if (hip->hit != NULL)
343 		isc_mem_free(mctx, hip->hit);
344 	if (hip->key != NULL)
345 		isc_mem_free(mctx, hip->key);
346 	if (hip->servers != NULL)
347 		isc_mem_free(mctx, hip->servers);
348 	return (ISC_R_NOMEMORY);
349 
350 }
351 
352 static inline void
353 freestruct_hip(ARGS_FREESTRUCT) {
354 	dns_rdata_hip_t *hip = source;
355 
356 	REQUIRE(source != NULL);
357 
358 	if (hip->mctx == NULL)
359 		return;
360 
361 	isc_mem_free(hip->mctx, hip->hit);
362 	isc_mem_free(hip->mctx, hip->key);
363 	if (hip->servers != NULL)
364 		isc_mem_free(hip->mctx, hip->servers);
365 	hip->mctx = NULL;
366 }
367 
368 static inline isc_result_t
369 additionaldata_hip(ARGS_ADDLDATA) {
370 	UNUSED(rdata);
371 	UNUSED(add);
372 	UNUSED(arg);
373 
374 	REQUIRE(rdata->type == 55);
375 
376 	return (ISC_R_SUCCESS);
377 }
378 
379 static inline isc_result_t
380 digest_hip(ARGS_DIGEST) {
381 	isc_region_t r;
382 
383 	REQUIRE(rdata->type == 55);
384 
385 	dns_rdata_toregion(rdata, &r);
386 	return ((digest)(arg, &r));
387 }
388 
389 static inline isc_boolean_t
390 checkowner_hip(ARGS_CHECKOWNER) {
391 
392 	REQUIRE(type == 55);
393 
394 	UNUSED(name);
395 	UNUSED(type);
396 	UNUSED(rdclass);
397 	UNUSED(wildcard);
398 
399 	return (ISC_TRUE);
400 }
401 
402 static inline isc_boolean_t
403 checknames_hip(ARGS_CHECKNAMES) {
404 
405 	REQUIRE(rdata->type == 55);
406 
407 	UNUSED(rdata);
408 	UNUSED(owner);
409 	UNUSED(bad);
410 
411 	return (ISC_TRUE);
412 }
413 
414 isc_result_t
415 dns_rdata_hip_first(dns_rdata_hip_t *hip) {
416 	if (hip->servers_len == 0)
417 		return (ISC_R_NOMORE);
418 	hip->offset = 0;
419 	return (ISC_R_SUCCESS);
420 }
421 
422 isc_result_t
423 dns_rdata_hip_next(dns_rdata_hip_t *hip) {
424 	isc_region_t region;
425 	dns_name_t name;
426 
427 	if (hip->offset >= hip->servers_len)
428 		return (ISC_R_NOMORE);
429 
430 	region.base = hip->servers + hip->offset;
431 	region.length = hip->servers_len - hip->offset;
432 	dns_name_init(&name, NULL);
433 	dns_name_fromregion(&name, &region);
434 	hip->offset += name.length;
435 	INSIST(hip->offset <= hip->servers_len);
436 	return (ISC_R_SUCCESS);
437 }
438 
439 void
440 dns_rdata_hip_current(dns_rdata_hip_t *hip, dns_name_t *name) {
441 	isc_region_t region;
442 
443 	REQUIRE(hip->offset < hip->servers_len);
444 
445 	region.base = hip->servers + hip->offset;
446 	region.length = hip->servers_len - hip->offset;
447 	dns_name_fromregion(name, &region);
448 
449 	INSIST(name->length + hip->offset <= hip->servers_len);
450 }
451 
452 static inline int
453 casecompare_hip(ARGS_COMPARE) {
454 	isc_region_t r1;
455 	isc_region_t r2;
456 	dns_name_t name1;
457 	dns_name_t name2;
458 	int order;
459 	isc_uint8_t hit_len;
460 	isc_uint16_t key_len;
461 
462 	REQUIRE(rdata1->type == rdata2->type);
463 	REQUIRE(rdata1->rdclass == rdata2->rdclass);
464 	REQUIRE(rdata1->type == 55);
465 	REQUIRE(rdata1->length != 0);
466 	REQUIRE(rdata2->length != 0);
467 
468 	dns_rdata_toregion(rdata1, &r1);
469 	dns_rdata_toregion(rdata2, &r2);
470 
471 	INSIST(r1.length > 4);
472 	INSIST(r2.length > 4);
473 	order = memcmp(r1.base, r2.base, 4);
474 	if (order != 0)
475 		return (order);
476 
477 	hit_len = uint8_fromregion(&r1);
478 	isc_region_consume(&r1, 2);         /* hit length + algorithm */
479 	key_len = uint16_fromregion(&r1);
480 	isc_region_consume(&r1, 2);         /* key length */
481 	isc_region_consume(&r2, 4);
482 
483 	INSIST(r1.length >= (unsigned) (hit_len + key_len));
484 	INSIST(r2.length >= (unsigned) (hit_len + key_len));
485 	order = memcmp(r1.base, r2.base, hit_len + key_len);
486 	if (order != 0)
487 		return (order);
488 	isc_region_consume(&r1, hit_len + key_len);
489 	isc_region_consume(&r2, hit_len + key_len);
490 
491 	dns_name_init(&name1, NULL);
492 	dns_name_init(&name2, NULL);
493 	while (r1.length != 0 && r2.length != 0) {
494 		dns_name_fromregion(&name1, &r1);
495 		dns_name_fromregion(&name2, &r2);
496 		order = dns_name_rdatacompare(&name1, &name2);
497 		if (order != 0)
498 			return (order);
499 
500 		isc_region_consume(&r1, name_length(&name1));
501 		isc_region_consume(&r2, name_length(&name2));
502 	}
503 	return (isc_region_compare(&r1, &r2));
504 }
505 
506 #endif	/* RDATA_GENERIC_HIP_5_C */
507