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