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