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