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