1/* $NetBSD: ds_43.c,v 1.11 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/* RFC3658 */ 17 18#ifndef RDATA_GENERIC_DS_43_C 19#define RDATA_GENERIC_DS_43_C 20 21#define RRTYPE_DS_ATTRIBUTES \ 22 (DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH | \ 23 DNS_RDATATYPEATTR_ATPARENT) 24 25#include <isc/md.h> 26 27#include <dns/ds.h> 28 29static isc_result_t 30generic_fromtext_ds(ARGS_FROMTEXT) { 31 isc_token_t token; 32 unsigned char c; 33 int length; 34 35 UNUSED(type); 36 UNUSED(rdclass); 37 UNUSED(origin); 38 UNUSED(options); 39 UNUSED(callbacks); 40 41 /* 42 * Key tag. 43 */ 44 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 45 false)); 46 if (token.value.as_ulong > 0xffffU) { 47 RETTOK(ISC_R_RANGE); 48 } 49 RETERR(uint16_tobuffer(token.value.as_ulong, target)); 50 51 /* 52 * Algorithm. 53 */ 54 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 55 false)); 56 RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion)); 57 RETERR(mem_tobuffer(target, &c, 1)); 58 59 /* 60 * Digest type. 61 */ 62 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, 63 false)); 64 RETTOK(dns_dsdigest_fromtext(&c, &token.value.as_textregion)); 65 RETERR(mem_tobuffer(target, &c, 1)); 66 67 /* 68 * Digest. 69 */ 70 switch (c) { 71 case DNS_DSDIGEST_SHA1: 72 length = ISC_SHA1_DIGESTLENGTH; 73 break; 74 case DNS_DSDIGEST_SHA256: 75 length = ISC_SHA256_DIGESTLENGTH; 76 break; 77 case DNS_DSDIGEST_SHA384: 78 length = ISC_SHA384_DIGESTLENGTH; 79 break; 80 default: 81 length = -2; 82 break; 83 } 84 return (isc_hex_tobuffer(lexer, target, length)); 85} 86 87static isc_result_t 88fromtext_ds(ARGS_FROMTEXT) { 89 REQUIRE(type == dns_rdatatype_ds); 90 91 return (generic_fromtext_ds(CALL_FROMTEXT)); 92} 93 94static isc_result_t 95generic_totext_ds(ARGS_TOTEXT) { 96 isc_region_t sr; 97 char buf[sizeof("64000 ")]; 98 unsigned int n; 99 100 REQUIRE(rdata->length != 0); 101 102 UNUSED(tctx); 103 104 dns_rdata_toregion(rdata, &sr); 105 106 /* 107 * Key tag. 108 */ 109 n = uint16_fromregion(&sr); 110 isc_region_consume(&sr, 2); 111 snprintf(buf, sizeof(buf), "%u ", n); 112 RETERR(str_totext(buf, target)); 113 114 /* 115 * Algorithm. 116 */ 117 n = uint8_fromregion(&sr); 118 isc_region_consume(&sr, 1); 119 snprintf(buf, sizeof(buf), "%u ", n); 120 RETERR(str_totext(buf, target)); 121 122 /* 123 * Digest type. 124 */ 125 n = uint8_fromregion(&sr); 126 isc_region_consume(&sr, 1); 127 snprintf(buf, sizeof(buf), "%u", n); 128 RETERR(str_totext(buf, target)); 129 130 /* 131 * Digest. 132 */ 133 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 134 RETERR(str_totext(" (", target)); 135 } 136 RETERR(str_totext(tctx->linebreak, target)); 137 if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) { 138 if (tctx->width == 0) { /* No splitting */ 139 RETERR(isc_hex_totext(&sr, 0, "", target)); 140 } else { 141 RETERR(isc_hex_totext(&sr, tctx->width - 2, 142 tctx->linebreak, target)); 143 } 144 } else { 145 RETERR(str_totext("[omitted]", target)); 146 } 147 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 148 RETERR(str_totext(" )", target)); 149 } 150 return (ISC_R_SUCCESS); 151} 152 153static isc_result_t 154totext_ds(ARGS_TOTEXT) { 155 REQUIRE(rdata != NULL); 156 REQUIRE(rdata->type == dns_rdatatype_ds); 157 158 return (generic_totext_ds(CALL_TOTEXT)); 159} 160 161static isc_result_t 162generic_fromwire_ds(ARGS_FROMWIRE) { 163 isc_region_t sr; 164 165 UNUSED(type); 166 UNUSED(rdclass); 167 UNUSED(dctx); 168 UNUSED(options); 169 170 isc_buffer_activeregion(source, &sr); 171 172 /* 173 * Check digest lengths if we know them. 174 */ 175 if (sr.length < 5 || 176 (sr.base[3] == DNS_DSDIGEST_SHA1 && 177 sr.length < 4 + ISC_SHA1_DIGESTLENGTH) || 178 (sr.base[3] == DNS_DSDIGEST_SHA256 && 179 sr.length < 4 + ISC_SHA256_DIGESTLENGTH) || 180 (sr.base[3] == DNS_DSDIGEST_SHA384 && 181 sr.length < 4 + ISC_SHA384_DIGESTLENGTH)) 182 { 183 return (ISC_R_UNEXPECTEDEND); 184 } 185 186 /* 187 * Only copy digest lengths if we know them. 188 * If there is extra data dns_rdata_fromwire() will 189 * detect that. 190 */ 191 if (sr.base[3] == DNS_DSDIGEST_SHA1) { 192 sr.length = 4 + ISC_SHA1_DIGESTLENGTH; 193 } else if (sr.base[3] == DNS_DSDIGEST_SHA256) { 194 sr.length = 4 + ISC_SHA256_DIGESTLENGTH; 195 } else if (sr.base[3] == DNS_DSDIGEST_SHA384) { 196 sr.length = 4 + ISC_SHA384_DIGESTLENGTH; 197 } 198 199 isc_buffer_forward(source, sr.length); 200 return (mem_tobuffer(target, sr.base, sr.length)); 201} 202 203static isc_result_t 204fromwire_ds(ARGS_FROMWIRE) { 205 REQUIRE(type == dns_rdatatype_ds); 206 207 return (generic_fromwire_ds(CALL_FROMWIRE)); 208} 209 210static isc_result_t 211towire_ds(ARGS_TOWIRE) { 212 isc_region_t sr; 213 214 REQUIRE(rdata->type == dns_rdatatype_ds); 215 REQUIRE(rdata->length != 0); 216 217 UNUSED(cctx); 218 219 dns_rdata_toregion(rdata, &sr); 220 return (mem_tobuffer(target, sr.base, sr.length)); 221} 222 223static int 224compare_ds(ARGS_COMPARE) { 225 isc_region_t r1; 226 isc_region_t r2; 227 228 REQUIRE(rdata1->type == rdata2->type); 229 REQUIRE(rdata1->rdclass == rdata2->rdclass); 230 REQUIRE(rdata1->type == dns_rdatatype_ds); 231 REQUIRE(rdata1->length != 0); 232 REQUIRE(rdata2->length != 0); 233 234 dns_rdata_toregion(rdata1, &r1); 235 dns_rdata_toregion(rdata2, &r2); 236 return (isc_region_compare(&r1, &r2)); 237} 238 239static isc_result_t 240generic_fromstruct_ds(ARGS_FROMSTRUCT) { 241 dns_rdata_ds_t *ds = source; 242 243 REQUIRE(ds != NULL); 244 REQUIRE(ds->common.rdtype == type); 245 REQUIRE(ds->common.rdclass == rdclass); 246 247 UNUSED(type); 248 UNUSED(rdclass); 249 250 switch (ds->digest_type) { 251 case DNS_DSDIGEST_SHA1: 252 REQUIRE(ds->length == ISC_SHA1_DIGESTLENGTH); 253 break; 254 case DNS_DSDIGEST_SHA256: 255 REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH); 256 break; 257 case DNS_DSDIGEST_SHA384: 258 REQUIRE(ds->length == ISC_SHA384_DIGESTLENGTH); 259 break; 260 } 261 262 RETERR(uint16_tobuffer(ds->key_tag, target)); 263 RETERR(uint8_tobuffer(ds->algorithm, target)); 264 RETERR(uint8_tobuffer(ds->digest_type, target)); 265 266 return (mem_tobuffer(target, ds->digest, ds->length)); 267} 268 269static isc_result_t 270fromstruct_ds(ARGS_FROMSTRUCT) { 271 REQUIRE(type == dns_rdatatype_ds); 272 273 return (generic_fromstruct_ds(CALL_FROMSTRUCT)); 274} 275 276static isc_result_t 277generic_tostruct_ds(ARGS_TOSTRUCT) { 278 dns_rdata_ds_t *ds = target; 279 isc_region_t region; 280 281 REQUIRE(ds != NULL); 282 REQUIRE(rdata->length != 0); 283 REQUIRE(ds->common.rdtype == rdata->type); 284 REQUIRE(ds->common.rdclass == rdata->rdclass); 285 REQUIRE(!ISC_LINK_LINKED(&ds->common, link)); 286 287 dns_rdata_toregion(rdata, ®ion); 288 289 ds->key_tag = uint16_fromregion(®ion); 290 isc_region_consume(®ion, 2); 291 ds->algorithm = uint8_fromregion(®ion); 292 isc_region_consume(®ion, 1); 293 ds->digest_type = uint8_fromregion(®ion); 294 isc_region_consume(®ion, 1); 295 ds->length = region.length; 296 297 ds->digest = mem_maybedup(mctx, region.base, region.length); 298 if (ds->digest == NULL) { 299 return (ISC_R_NOMEMORY); 300 } 301 302 ds->mctx = mctx; 303 return (ISC_R_SUCCESS); 304} 305 306static isc_result_t 307tostruct_ds(ARGS_TOSTRUCT) { 308 dns_rdata_ds_t *ds = target; 309 310 REQUIRE(rdata->type == dns_rdatatype_ds); 311 REQUIRE(ds != NULL); 312 313 ds->common.rdclass = rdata->rdclass; 314 ds->common.rdtype = rdata->type; 315 ISC_LINK_INIT(&ds->common, link); 316 317 return (generic_tostruct_ds(CALL_TOSTRUCT)); 318} 319 320static void 321freestruct_ds(ARGS_FREESTRUCT) { 322 dns_rdata_ds_t *ds = source; 323 324 REQUIRE(ds != NULL); 325 REQUIRE(ds->common.rdtype == dns_rdatatype_ds); 326 327 if (ds->mctx == NULL) { 328 return; 329 } 330 331 if (ds->digest != NULL) { 332 isc_mem_free(ds->mctx, ds->digest); 333 } 334 ds->mctx = NULL; 335} 336 337static isc_result_t 338additionaldata_ds(ARGS_ADDLDATA) { 339 REQUIRE(rdata->type == dns_rdatatype_ds); 340 341 UNUSED(rdata); 342 UNUSED(owner); 343 UNUSED(add); 344 UNUSED(arg); 345 346 return (ISC_R_SUCCESS); 347} 348 349static isc_result_t 350digest_ds(ARGS_DIGEST) { 351 isc_region_t r; 352 353 REQUIRE(rdata->type == dns_rdatatype_ds); 354 355 dns_rdata_toregion(rdata, &r); 356 357 return ((digest)(arg, &r)); 358} 359 360static bool 361checkowner_ds(ARGS_CHECKOWNER) { 362 REQUIRE(type == dns_rdatatype_ds); 363 364 UNUSED(name); 365 UNUSED(type); 366 UNUSED(rdclass); 367 UNUSED(wildcard); 368 369 return (true); 370} 371 372static bool 373checknames_ds(ARGS_CHECKNAMES) { 374 REQUIRE(rdata->type == dns_rdatatype_ds); 375 376 UNUSED(rdata); 377 UNUSED(owner); 378 UNUSED(bad); 379 380 return (true); 381} 382 383static int 384casecompare_ds(ARGS_COMPARE) { 385 return (compare_ds(rdata1, rdata2)); 386} 387 388#endif /* RDATA_GENERIC_DS_43_C */ 389