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, ®ion);
134
135 hit_len = uint8_fromregion(®ion);
136 isc_region_consume(®ion, 1);
137
138 algorithm = uint8_fromregion(®ion);
139 isc_region_consume(®ion, 1);
140
141 key_len = uint16_fromregion(®ion);
142 isc_region_consume(®ion, 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(®ion, 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(®ion, 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, ®ion);
182
183 RETERR(dns_name_totext(&name, false, target));
184 isc_region_consume(®ion, 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, ®ion);
209 if (region.length < 4U) {
210 RETERR(DNS_R_FORMERR);
211 }
212
213 rr = region;
214 hit_len = uint8_fromregion(®ion);
215 if (hit_len == 0) {
216 RETERR(DNS_R_FORMERR);
217 }
218 isc_region_consume(®ion, 2); /* hit length + algorithm */
219 key_len = uint16_fromregion(®ion);
220 if (key_len == 0) {
221 RETERR(DNS_R_FORMERR);
222 }
223 isc_region_consume(®ion, 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, ®ion);
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, ®ion1);
265 dns_rdata_toregion(rdata2, ®ion2);
266 return (isc_region_compare(®ion1, ®ion2));
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, ®ion);
317
318 hip->hit_len = uint8_fromregion(®ion);
319 isc_region_consume(®ion, 1);
320
321 hip->algorithm = uint8_fromregion(®ion);
322 isc_region_consume(®ion, 1);
323
324 hip->key_len = uint16_fromregion(®ion);
325 isc_region_consume(®ion, 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(®ion, 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(®ion, 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, ®ion);
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, ®ion);
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