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 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 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 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 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 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 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 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 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 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 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 527 #endif /* RDATA_GENERIC_HIP_5_C */ 528