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, ®ion); 132 133 hit_len = uint8_fromregion(®ion); 134 isc_region_consume(®ion, 1); 135 136 algorithm = uint8_fromregion(®ion); 137 isc_region_consume(®ion, 1); 138 139 key_len = uint16_fromregion(®ion); 140 isc_region_consume(®ion, 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(®ion, 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(®ion, 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, ®ion); 180 181 RETERR(dns_name_totext(&name, false, target)); 182 isc_region_consume(®ion, 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, ®ion); 207 if (region.length < 4U) { 208 RETERR(DNS_R_FORMERR); 209 } 210 211 rr = region; 212 hit_len = uint8_fromregion(®ion); 213 if (hit_len == 0) { 214 RETERR(DNS_R_FORMERR); 215 } 216 isc_region_consume(®ion, 2); /* hit length + algorithm */ 217 key_len = uint16_fromregion(®ion); 218 if (key_len == 0) { 219 RETERR(DNS_R_FORMERR); 220 } 221 isc_region_consume(®ion, 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, ®ion); 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, ®ion1); 263 dns_rdata_toregion(rdata2, ®ion2); 264 return (isc_region_compare(®ion1, ®ion2)); 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, ®ion); 313 314 hip->hit_len = uint8_fromregion(®ion); 315 isc_region_consume(®ion, 1); 316 317 hip->algorithm = uint8_fromregion(®ion); 318 isc_region_consume(®ion, 1); 319 320 hip->key_len = uint16_fromregion(®ion); 321 isc_region_consume(®ion, 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(®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 if (hip->key == NULL) { 335 goto cleanup; 336 } 337 isc_region_consume(®ion, 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, ®ion); 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, ®ion); 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