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