1 /* $NetBSD: ds_43.c,v 1.12 2025/01/26 16:25: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 /* 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 29 static isc_result_t 30 generic_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 87 static isc_result_t 88 fromtext_ds(ARGS_FROMTEXT) { 89 REQUIRE(type == dns_rdatatype_ds); 90 91 return generic_fromtext_ds(CALL_FROMTEXT); 92 } 93 94 static isc_result_t 95 generic_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 153 static isc_result_t 154 totext_ds(ARGS_TOTEXT) { 155 REQUIRE(rdata != NULL); 156 REQUIRE(rdata->type == dns_rdatatype_ds); 157 158 return generic_totext_ds(CALL_TOTEXT); 159 } 160 161 static isc_result_t 162 generic_fromwire_ds(ARGS_FROMWIRE) { 163 isc_region_t sr; 164 165 UNUSED(type); 166 UNUSED(rdclass); 167 UNUSED(dctx); 168 169 isc_buffer_activeregion(source, &sr); 170 171 /* 172 * Check digest lengths if we know them. 173 */ 174 if (sr.length < 5 || 175 (sr.base[3] == DNS_DSDIGEST_SHA1 && 176 sr.length < 4 + ISC_SHA1_DIGESTLENGTH) || 177 (sr.base[3] == DNS_DSDIGEST_SHA256 && 178 sr.length < 4 + ISC_SHA256_DIGESTLENGTH) || 179 (sr.base[3] == DNS_DSDIGEST_SHA384 && 180 sr.length < 4 + ISC_SHA384_DIGESTLENGTH)) 181 { 182 return ISC_R_UNEXPECTEDEND; 183 } 184 185 /* 186 * Only copy digest lengths if we know them. 187 * If there is extra data dns_rdata_fromwire() will 188 * detect that. 189 */ 190 if (sr.base[3] == DNS_DSDIGEST_SHA1) { 191 sr.length = 4 + ISC_SHA1_DIGESTLENGTH; 192 } else if (sr.base[3] == DNS_DSDIGEST_SHA256) { 193 sr.length = 4 + ISC_SHA256_DIGESTLENGTH; 194 } else if (sr.base[3] == DNS_DSDIGEST_SHA384) { 195 sr.length = 4 + ISC_SHA384_DIGESTLENGTH; 196 } 197 198 isc_buffer_forward(source, sr.length); 199 return mem_tobuffer(target, sr.base, sr.length); 200 } 201 202 static isc_result_t 203 fromwire_ds(ARGS_FROMWIRE) { 204 REQUIRE(type == dns_rdatatype_ds); 205 206 return generic_fromwire_ds(CALL_FROMWIRE); 207 } 208 209 static isc_result_t 210 towire_ds(ARGS_TOWIRE) { 211 isc_region_t sr; 212 213 REQUIRE(rdata->type == dns_rdatatype_ds); 214 REQUIRE(rdata->length != 0); 215 216 UNUSED(cctx); 217 218 dns_rdata_toregion(rdata, &sr); 219 return mem_tobuffer(target, sr.base, sr.length); 220 } 221 222 static int 223 compare_ds(ARGS_COMPARE) { 224 isc_region_t r1; 225 isc_region_t r2; 226 227 REQUIRE(rdata1->type == rdata2->type); 228 REQUIRE(rdata1->rdclass == rdata2->rdclass); 229 REQUIRE(rdata1->type == dns_rdatatype_ds); 230 REQUIRE(rdata1->length != 0); 231 REQUIRE(rdata2->length != 0); 232 233 dns_rdata_toregion(rdata1, &r1); 234 dns_rdata_toregion(rdata2, &r2); 235 return isc_region_compare(&r1, &r2); 236 } 237 238 static isc_result_t 239 generic_fromstruct_ds(ARGS_FROMSTRUCT) { 240 dns_rdata_ds_t *ds = source; 241 242 REQUIRE(ds != NULL); 243 REQUIRE(ds->common.rdtype == type); 244 REQUIRE(ds->common.rdclass == rdclass); 245 246 UNUSED(type); 247 UNUSED(rdclass); 248 249 switch (ds->digest_type) { 250 case DNS_DSDIGEST_SHA1: 251 REQUIRE(ds->length == ISC_SHA1_DIGESTLENGTH); 252 break; 253 case DNS_DSDIGEST_SHA256: 254 REQUIRE(ds->length == ISC_SHA256_DIGESTLENGTH); 255 break; 256 case DNS_DSDIGEST_SHA384: 257 REQUIRE(ds->length == ISC_SHA384_DIGESTLENGTH); 258 break; 259 } 260 261 RETERR(uint16_tobuffer(ds->key_tag, target)); 262 RETERR(uint8_tobuffer(ds->algorithm, target)); 263 RETERR(uint8_tobuffer(ds->digest_type, target)); 264 265 return mem_tobuffer(target, ds->digest, ds->length); 266 } 267 268 static isc_result_t 269 fromstruct_ds(ARGS_FROMSTRUCT) { 270 REQUIRE(type == dns_rdatatype_ds); 271 272 return generic_fromstruct_ds(CALL_FROMSTRUCT); 273 } 274 275 static isc_result_t 276 generic_tostruct_ds(ARGS_TOSTRUCT) { 277 dns_rdata_ds_t *ds = target; 278 isc_region_t region; 279 280 REQUIRE(ds != NULL); 281 REQUIRE(rdata->length != 0); 282 REQUIRE(ds->common.rdtype == rdata->type); 283 REQUIRE(ds->common.rdclass == rdata->rdclass); 284 REQUIRE(!ISC_LINK_LINKED(&ds->common, link)); 285 286 dns_rdata_toregion(rdata, ®ion); 287 288 ds->key_tag = uint16_fromregion(®ion); 289 isc_region_consume(®ion, 2); 290 ds->algorithm = uint8_fromregion(®ion); 291 isc_region_consume(®ion, 1); 292 ds->digest_type = uint8_fromregion(®ion); 293 isc_region_consume(®ion, 1); 294 ds->length = region.length; 295 296 ds->digest = mem_maybedup(mctx, region.base, region.length); 297 ds->mctx = mctx; 298 return ISC_R_SUCCESS; 299 } 300 301 static isc_result_t 302 tostruct_ds(ARGS_TOSTRUCT) { 303 dns_rdata_ds_t *ds = target; 304 305 REQUIRE(rdata->type == dns_rdatatype_ds); 306 REQUIRE(ds != NULL); 307 308 ds->common.rdclass = rdata->rdclass; 309 ds->common.rdtype = rdata->type; 310 ISC_LINK_INIT(&ds->common, link); 311 312 return generic_tostruct_ds(CALL_TOSTRUCT); 313 } 314 315 static void 316 freestruct_ds(ARGS_FREESTRUCT) { 317 dns_rdata_ds_t *ds = source; 318 319 REQUIRE(ds != NULL); 320 REQUIRE(ds->common.rdtype == dns_rdatatype_ds); 321 322 if (ds->mctx == NULL) { 323 return; 324 } 325 326 if (ds->digest != NULL) { 327 isc_mem_free(ds->mctx, ds->digest); 328 } 329 ds->mctx = NULL; 330 } 331 332 static isc_result_t 333 additionaldata_ds(ARGS_ADDLDATA) { 334 REQUIRE(rdata->type == dns_rdatatype_ds); 335 336 UNUSED(rdata); 337 UNUSED(owner); 338 UNUSED(add); 339 UNUSED(arg); 340 341 return ISC_R_SUCCESS; 342 } 343 344 static isc_result_t 345 digest_ds(ARGS_DIGEST) { 346 isc_region_t r; 347 348 REQUIRE(rdata->type == dns_rdatatype_ds); 349 350 dns_rdata_toregion(rdata, &r); 351 352 return (digest)(arg, &r); 353 } 354 355 static bool 356 checkowner_ds(ARGS_CHECKOWNER) { 357 REQUIRE(type == dns_rdatatype_ds); 358 359 UNUSED(name); 360 UNUSED(type); 361 UNUSED(rdclass); 362 UNUSED(wildcard); 363 364 return true; 365 } 366 367 static bool 368 checknames_ds(ARGS_CHECKNAMES) { 369 REQUIRE(rdata->type == dns_rdatatype_ds); 370 371 UNUSED(rdata); 372 UNUSED(owner); 373 UNUSED(bad); 374 375 return true; 376 } 377 378 static int 379 casecompare_ds(ARGS_COMPARE) { 380 return compare_ds(rdata1, rdata2); 381 } 382 383 #endif /* RDATA_GENERIC_DS_43_C */ 384