1/* $NetBSD: rrsig_46.c,v 1.1 2024/02/18 20:57:44 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/* RFC2535 */ 17 18#ifndef RDATA_GENERIC_RRSIG_46_C 19#define RDATA_GENERIC_RRSIG_46_C 20 21#define RRTYPE_RRSIG_ATTRIBUTES \ 22 (DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH | \ 23 DNS_RDATATYPEATTR_ATCNAME) 24 25static isc_result_t 26fromtext_rrsig(ARGS_FROMTEXT) { 27 isc_token_t token; 28 unsigned char c; 29 long i; 30 dns_rdatatype_t covered; 31 char *e; 32 isc_result_t result; 33 dns_name_t name; 34 isc_buffer_t buffer; 35 uint32_t time_signed, time_expire; 36 37 REQUIRE(type == dns_rdatatype_rrsig); 38 39 UNUSED(type); 40 UNUSED(rdclass); 41 UNUSED(callbacks); 42 43 /* 44 * Type covered. 45 */ 46 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 47 false)); 48 result = dns_rdatatype_fromtext(&covered, &token.value.as_textregion); 49 if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) { 50 i = strtol(DNS_AS_STR(token), &e, 10); 51 if (i < 0 || i > 65535) { 52 RETTOK(ISC_R_RANGE); 53 } 54 if (*e != 0) { 55 RETTOK(result); 56 } 57 covered = (dns_rdatatype_t)i; 58 } 59 RETERR(uint16_tobuffer(covered, target)); 60 61 /* 62 * Algorithm. 63 */ 64 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 65 false)); 66 RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion)); 67 RETERR(mem_tobuffer(target, &c, 1)); 68 69 /* 70 * Labels. 71 */ 72 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 73 false)); 74 if (token.value.as_ulong > 0xffU) { 75 RETTOK(ISC_R_RANGE); 76 } 77 c = (unsigned char)token.value.as_ulong; 78 RETERR(mem_tobuffer(target, &c, 1)); 79 80 /* 81 * Original ttl. 82 */ 83 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 84 false)); 85 RETERR(uint32_tobuffer(token.value.as_ulong, target)); 86 87 /* 88 * Signature expiration. 89 */ 90 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 91 false)); 92 if (strlen(DNS_AS_STR(token)) <= 10U && *DNS_AS_STR(token) != '-' && 93 *DNS_AS_STR(token) != '+') 94 { 95 char *end; 96 unsigned long u; 97 uint64_t u64; 98 99 u64 = u = strtoul(DNS_AS_STR(token), &end, 10); 100 if (u == ULONG_MAX || *end != 0) { 101 RETTOK(DNS_R_SYNTAX); 102 } 103 if (u64 > 0xffffffffUL) { 104 RETTOK(ISC_R_RANGE); 105 } 106 time_expire = u; 107 } else { 108 RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_expire)); 109 } 110 RETERR(uint32_tobuffer(time_expire, target)); 111 112 /* 113 * Time signed. 114 */ 115 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 116 false)); 117 if (strlen(DNS_AS_STR(token)) <= 10U && *DNS_AS_STR(token) != '-' && 118 *DNS_AS_STR(token) != '+') 119 { 120 char *end; 121 unsigned long u; 122 uint64_t u64; 123 124 u64 = u = strtoul(DNS_AS_STR(token), &end, 10); 125 if (u == ULONG_MAX || *end != 0) { 126 RETTOK(DNS_R_SYNTAX); 127 } 128 if (u64 > 0xffffffffUL) { 129 RETTOK(ISC_R_RANGE); 130 } 131 time_signed = u; 132 } else { 133 RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_signed)); 134 } 135 RETERR(uint32_tobuffer(time_signed, target)); 136 137 /* 138 * Key footprint. 139 */ 140 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 141 false)); 142 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 143 144 /* 145 * Signer. 146 */ 147 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 148 false)); 149 dns_name_init(&name, NULL); 150 buffer_fromregion(&buffer, &token.value.as_region); 151 if (origin == NULL) { 152 origin = dns_rootname; 153 } 154 RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target)); 155 156 /* 157 * Sig. 158 */ 159 return (isc_base64_tobuffer(lexer, target, -2)); 160} 161 162static isc_result_t 163totext_rrsig(ARGS_TOTEXT) { 164 isc_region_t sr; 165 char buf[sizeof("4294967295")]; /* Also TYPE65000. */ 166 dns_rdatatype_t covered; 167 unsigned long ttl; 168 unsigned long when; 169 unsigned long exp; 170 unsigned long foot; 171 dns_name_t name; 172 173 REQUIRE(rdata->type == dns_rdatatype_rrsig); 174 REQUIRE(rdata->length != 0); 175 176 dns_rdata_toregion(rdata, &sr); 177 178 /* 179 * Type covered. 180 */ 181 covered = uint16_fromregion(&sr); 182 isc_region_consume(&sr, 2); 183 /* 184 * XXXAG We should have something like dns_rdatatype_isknown() 185 * that does the right thing with type 0. 186 */ 187 if (dns_rdatatype_isknown(covered) && covered != 0) { 188 RETERR(dns_rdatatype_totext(covered, target)); 189 } else { 190 snprintf(buf, sizeof(buf), "TYPE%u", covered); 191 RETERR(str_totext(buf, target)); 192 } 193 RETERR(str_totext(" ", target)); 194 195 /* 196 * Algorithm. 197 */ 198 snprintf(buf, sizeof(buf), "%u", sr.base[0]); 199 isc_region_consume(&sr, 1); 200 RETERR(str_totext(buf, target)); 201 RETERR(str_totext(" ", target)); 202 203 /* 204 * Labels. 205 */ 206 snprintf(buf, sizeof(buf), "%u", sr.base[0]); 207 isc_region_consume(&sr, 1); 208 RETERR(str_totext(buf, target)); 209 RETERR(str_totext(" ", target)); 210 211 /* 212 * Ttl. 213 */ 214 ttl = uint32_fromregion(&sr); 215 isc_region_consume(&sr, 4); 216 snprintf(buf, sizeof(buf), "%lu", ttl); 217 RETERR(str_totext(buf, target)); 218 219 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 220 RETERR(str_totext(" (", target)); 221 } 222 RETERR(str_totext(tctx->linebreak, target)); 223 224 /* 225 * Sig exp. 226 */ 227 exp = uint32_fromregion(&sr); 228 isc_region_consume(&sr, 4); 229 RETERR(dns_time32_totext(exp, target)); 230 RETERR(str_totext(" ", target)); 231 232 /* 233 * Time signed. 234 */ 235 when = uint32_fromregion(&sr); 236 isc_region_consume(&sr, 4); 237 RETERR(dns_time32_totext(when, target)); 238 RETERR(str_totext(" ", target)); 239 240 /* 241 * Footprint. 242 */ 243 foot = uint16_fromregion(&sr); 244 isc_region_consume(&sr, 2); 245 snprintf(buf, sizeof(buf), "%lu", foot); 246 RETERR(str_totext(buf, target)); 247 RETERR(str_totext(" ", target)); 248 249 /* 250 * Signer. 251 */ 252 dns_name_init(&name, NULL); 253 dns_name_fromregion(&name, &sr); 254 isc_region_consume(&sr, name_length(&name)); 255 RETERR(dns_name_totext(&name, false, target)); 256 257 /* 258 * Sig. 259 */ 260 RETERR(str_totext(tctx->linebreak, target)); 261 if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) { 262 if (tctx->width == 0) { /* No splitting */ 263 RETERR(isc_base64_totext(&sr, 60, "", target)); 264 } else { 265 RETERR(isc_base64_totext(&sr, tctx->width - 2, 266 tctx->linebreak, target)); 267 } 268 } else { 269 RETERR(str_totext("[omitted]", target)); 270 } 271 272 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 273 RETERR(str_totext(" )", target)); 274 } 275 276 return (ISC_R_SUCCESS); 277} 278 279static isc_result_t 280fromwire_rrsig(ARGS_FROMWIRE) { 281 isc_region_t sr; 282 dns_name_t name; 283 284 REQUIRE(type == dns_rdatatype_rrsig); 285 286 UNUSED(type); 287 UNUSED(rdclass); 288 289 dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE); 290 291 isc_buffer_activeregion(source, &sr); 292 /* 293 * type covered: 2 294 * algorithm: 1 295 * labels: 1 296 * original ttl: 4 297 * signature expiration: 4 298 * time signed: 4 299 * key footprint: 2 300 */ 301 if (sr.length < 18) { 302 return (ISC_R_UNEXPECTEDEND); 303 } 304 305 isc_buffer_forward(source, 18); 306 RETERR(mem_tobuffer(target, sr.base, 18)); 307 308 /* 309 * Signer. 310 */ 311 dns_name_init(&name, NULL); 312 RETERR(dns_name_fromwire(&name, source, dctx, options, target)); 313 314 /* 315 * Sig. 316 */ 317 isc_buffer_activeregion(source, &sr); 318 if (sr.length < 1) { 319 return (DNS_R_FORMERR); 320 } 321 isc_buffer_forward(source, sr.length); 322 return (mem_tobuffer(target, sr.base, sr.length)); 323} 324 325static isc_result_t 326towire_rrsig(ARGS_TOWIRE) { 327 isc_region_t sr; 328 dns_name_t name; 329 dns_offsets_t offsets; 330 331 REQUIRE(rdata->type == dns_rdatatype_rrsig); 332 REQUIRE(rdata->length != 0); 333 334 dns_compress_setmethods(cctx, DNS_COMPRESS_NONE); 335 dns_rdata_toregion(rdata, &sr); 336 /* 337 * type covered: 2 338 * algorithm: 1 339 * labels: 1 340 * original ttl: 4 341 * signature expiration: 4 342 * time signed: 4 343 * key footprint: 2 344 */ 345 RETERR(mem_tobuffer(target, sr.base, 18)); 346 isc_region_consume(&sr, 18); 347 348 /* 349 * Signer. 350 */ 351 dns_name_init(&name, offsets); 352 dns_name_fromregion(&name, &sr); 353 isc_region_consume(&sr, name_length(&name)); 354 RETERR(dns_name_towire(&name, cctx, target)); 355 356 /* 357 * Signature. 358 */ 359 return (mem_tobuffer(target, sr.base, sr.length)); 360} 361 362static int 363compare_rrsig(ARGS_COMPARE) { 364 isc_region_t r1; 365 isc_region_t r2; 366 367 REQUIRE(rdata1->type == rdata2->type); 368 REQUIRE(rdata1->rdclass == rdata2->rdclass); 369 REQUIRE(rdata1->type == dns_rdatatype_rrsig); 370 REQUIRE(rdata1->length != 0); 371 REQUIRE(rdata2->length != 0); 372 373 dns_rdata_toregion(rdata1, &r1); 374 dns_rdata_toregion(rdata2, &r2); 375 return (isc_region_compare(&r1, &r2)); 376} 377 378static isc_result_t 379fromstruct_rrsig(ARGS_FROMSTRUCT) { 380 dns_rdata_rrsig_t *sig = source; 381 382 REQUIRE(type == dns_rdatatype_rrsig); 383 REQUIRE(sig != NULL); 384 REQUIRE(sig->common.rdtype == type); 385 REQUIRE(sig->common.rdclass == rdclass); 386 REQUIRE(sig->signature != NULL || sig->siglen == 0); 387 388 UNUSED(type); 389 UNUSED(rdclass); 390 391 /* 392 * Type covered. 393 */ 394 RETERR(uint16_tobuffer(sig->covered, target)); 395 396 /* 397 * Algorithm. 398 */ 399 RETERR(uint8_tobuffer(sig->algorithm, target)); 400 401 /* 402 * Labels. 403 */ 404 RETERR(uint8_tobuffer(sig->labels, target)); 405 406 /* 407 * Original TTL. 408 */ 409 RETERR(uint32_tobuffer(sig->originalttl, target)); 410 411 /* 412 * Expire time. 413 */ 414 RETERR(uint32_tobuffer(sig->timeexpire, target)); 415 416 /* 417 * Time signed. 418 */ 419 RETERR(uint32_tobuffer(sig->timesigned, target)); 420 421 /* 422 * Key ID. 423 */ 424 RETERR(uint16_tobuffer(sig->keyid, target)); 425 426 /* 427 * Signer name. 428 */ 429 RETERR(name_tobuffer(&sig->signer, target)); 430 431 /* 432 * Signature. 433 */ 434 return (mem_tobuffer(target, sig->signature, sig->siglen)); 435} 436 437static isc_result_t 438tostruct_rrsig(ARGS_TOSTRUCT) { 439 isc_region_t sr; 440 dns_rdata_rrsig_t *sig = target; 441 dns_name_t signer; 442 443 REQUIRE(rdata->type == dns_rdatatype_rrsig); 444 REQUIRE(sig != NULL); 445 REQUIRE(rdata->length != 0); 446 447 sig->common.rdclass = rdata->rdclass; 448 sig->common.rdtype = rdata->type; 449 ISC_LINK_INIT(&sig->common, link); 450 451 dns_rdata_toregion(rdata, &sr); 452 453 /* 454 * Type covered. 455 */ 456 sig->covered = uint16_fromregion(&sr); 457 isc_region_consume(&sr, 2); 458 459 /* 460 * Algorithm. 461 */ 462 sig->algorithm = uint8_fromregion(&sr); 463 isc_region_consume(&sr, 1); 464 465 /* 466 * Labels. 467 */ 468 sig->labels = uint8_fromregion(&sr); 469 isc_region_consume(&sr, 1); 470 471 /* 472 * Original TTL. 473 */ 474 sig->originalttl = uint32_fromregion(&sr); 475 isc_region_consume(&sr, 4); 476 477 /* 478 * Expire time. 479 */ 480 sig->timeexpire = uint32_fromregion(&sr); 481 isc_region_consume(&sr, 4); 482 483 /* 484 * Time signed. 485 */ 486 sig->timesigned = uint32_fromregion(&sr); 487 isc_region_consume(&sr, 4); 488 489 /* 490 * Key ID. 491 */ 492 sig->keyid = uint16_fromregion(&sr); 493 isc_region_consume(&sr, 2); 494 495 dns_name_init(&signer, NULL); 496 dns_name_fromregion(&signer, &sr); 497 dns_name_init(&sig->signer, NULL); 498 RETERR(name_duporclone(&signer, mctx, &sig->signer)); 499 isc_region_consume(&sr, name_length(&sig->signer)); 500 501 /* 502 * Signature. 503 */ 504 sig->siglen = sr.length; 505 sig->signature = mem_maybedup(mctx, sr.base, sig->siglen); 506 if (sig->signature == NULL) { 507 goto cleanup; 508 } 509 510 sig->mctx = mctx; 511 return (ISC_R_SUCCESS); 512 513cleanup: 514 if (mctx != NULL) { 515 dns_name_free(&sig->signer, mctx); 516 } 517 return (ISC_R_NOMEMORY); 518} 519 520static void 521freestruct_rrsig(ARGS_FREESTRUCT) { 522 dns_rdata_rrsig_t *sig = (dns_rdata_rrsig_t *)source; 523 524 REQUIRE(sig != NULL); 525 REQUIRE(sig->common.rdtype == dns_rdatatype_rrsig); 526 527 if (sig->mctx == NULL) { 528 return; 529 } 530 531 dns_name_free(&sig->signer, sig->mctx); 532 if (sig->signature != NULL) { 533 isc_mem_free(sig->mctx, sig->signature); 534 } 535 sig->mctx = NULL; 536} 537 538static isc_result_t 539additionaldata_rrsig(ARGS_ADDLDATA) { 540 REQUIRE(rdata->type == dns_rdatatype_rrsig); 541 542 UNUSED(rdata); 543 UNUSED(add); 544 UNUSED(arg); 545 546 return (ISC_R_SUCCESS); 547} 548 549static isc_result_t 550digest_rrsig(ARGS_DIGEST) { 551 REQUIRE(rdata->type == dns_rdatatype_rrsig); 552 553 UNUSED(rdata); 554 UNUSED(digest); 555 UNUSED(arg); 556 557 return (ISC_R_NOTIMPLEMENTED); 558} 559 560static dns_rdatatype_t 561covers_rrsig(dns_rdata_t *rdata) { 562 dns_rdatatype_t type; 563 isc_region_t r; 564 565 REQUIRE(rdata->type == dns_rdatatype_rrsig); 566 567 dns_rdata_toregion(rdata, &r); 568 type = uint16_fromregion(&r); 569 570 return (type); 571} 572 573static bool 574checkowner_rrsig(ARGS_CHECKOWNER) { 575 REQUIRE(type == dns_rdatatype_rrsig); 576 577 UNUSED(name); 578 UNUSED(type); 579 UNUSED(rdclass); 580 UNUSED(wildcard); 581 582 return (true); 583} 584 585static bool 586checknames_rrsig(ARGS_CHECKNAMES) { 587 REQUIRE(rdata->type == dns_rdatatype_rrsig); 588 589 UNUSED(rdata); 590 UNUSED(owner); 591 UNUSED(bad); 592 593 return (true); 594} 595 596static int 597casecompare_rrsig(ARGS_COMPARE) { 598 isc_region_t r1; 599 isc_region_t r2; 600 dns_name_t name1; 601 dns_name_t name2; 602 int order; 603 604 REQUIRE(rdata1->type == rdata2->type); 605 REQUIRE(rdata1->rdclass == rdata2->rdclass); 606 REQUIRE(rdata1->type == dns_rdatatype_rrsig); 607 REQUIRE(rdata1->length != 0); 608 REQUIRE(rdata2->length != 0); 609 610 dns_rdata_toregion(rdata1, &r1); 611 dns_rdata_toregion(rdata2, &r2); 612 613 INSIST(r1.length > 18); 614 INSIST(r2.length > 18); 615 r1.length = 18; 616 r2.length = 18; 617 order = isc_region_compare(&r1, &r2); 618 if (order != 0) { 619 return (order); 620 } 621 622 dns_name_init(&name1, NULL); 623 dns_name_init(&name2, NULL); 624 dns_rdata_toregion(rdata1, &r1); 625 dns_rdata_toregion(rdata2, &r2); 626 isc_region_consume(&r1, 18); 627 isc_region_consume(&r2, 18); 628 dns_name_fromregion(&name1, &r1); 629 dns_name_fromregion(&name2, &r2); 630 order = dns_name_rdatacompare(&name1, &name2); 631 if (order != 0) { 632 return (order); 633 } 634 635 isc_region_consume(&r1, name_length(&name1)); 636 isc_region_consume(&r2, name_length(&name2)); 637 638 return (isc_region_compare(&r1, &r2)); 639} 640 641#endif /* RDATA_GENERIC_RRSIG_46_C */ 642