1 /* $NetBSD: hip_55.c,v 1.9 2024/02/21 22:52:12 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, false, 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 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 232 while (isc_buffer_activelength(source) > 0) { 233 dns_name_init(&name, NULL); 234 RETERR(dns_name_fromwire(&name, source, dctx, options, 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 if (hip->hit == NULL) { 330 goto cleanup; 331 } 332 isc_region_consume(®ion, hip->hit_len); 333 334 INSIST(hip->key_len <= region.length); 335 336 hip->key = mem_maybedup(mctx, region.base, hip->key_len); 337 if (hip->key == NULL) { 338 goto cleanup; 339 } 340 isc_region_consume(®ion, hip->key_len); 341 342 hip->servers_len = region.length; 343 if (hip->servers_len != 0) { 344 hip->servers = mem_maybedup(mctx, region.base, region.length); 345 if (hip->servers == NULL) { 346 goto cleanup; 347 } 348 } 349 350 hip->offset = hip->servers_len; 351 hip->mctx = mctx; 352 return (ISC_R_SUCCESS); 353 354 cleanup: 355 if (hip->hit != NULL) { 356 isc_mem_free(mctx, hip->hit); 357 } 358 if (hip->key != NULL) { 359 isc_mem_free(mctx, hip->key); 360 } 361 if (hip->servers != NULL) { 362 isc_mem_free(mctx, hip->servers); 363 } 364 return (ISC_R_NOMEMORY); 365 } 366 367 static void 368 freestruct_hip(ARGS_FREESTRUCT) { 369 dns_rdata_hip_t *hip = source; 370 371 REQUIRE(hip != NULL); 372 373 if (hip->mctx == NULL) { 374 return; 375 } 376 377 isc_mem_free(hip->mctx, hip->hit); 378 isc_mem_free(hip->mctx, hip->key); 379 if (hip->servers != NULL) { 380 isc_mem_free(hip->mctx, hip->servers); 381 } 382 hip->mctx = NULL; 383 } 384 385 static isc_result_t 386 additionaldata_hip(ARGS_ADDLDATA) { 387 REQUIRE(rdata->type == dns_rdatatype_hip); 388 389 UNUSED(rdata); 390 UNUSED(owner); 391 UNUSED(add); 392 UNUSED(arg); 393 394 return (ISC_R_SUCCESS); 395 } 396 397 static isc_result_t 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 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 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 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 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 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 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