1 /* $NetBSD: ds_43.c,v 1.1 2024/02/18 20:57:41 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 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 203 static isc_result_t 204 fromwire_ds(ARGS_FROMWIRE) { 205 REQUIRE(type == dns_rdatatype_ds); 206 207 return (generic_fromwire_ds(CALL_FROMWIRE)); 208 } 209 210 static isc_result_t 211 towire_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 223 static int 224 compare_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 239 static isc_result_t 240 generic_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 269 static isc_result_t 270 fromstruct_ds(ARGS_FROMSTRUCT) { 271 REQUIRE(type == dns_rdatatype_ds); 272 273 return (generic_fromstruct_ds(CALL_FROMSTRUCT)); 274 } 275 276 static isc_result_t 277 generic_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 306 static isc_result_t 307 tostruct_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 320 static void 321 freestruct_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 337 static isc_result_t 338 additionaldata_ds(ARGS_ADDLDATA) { 339 REQUIRE(rdata->type == dns_rdatatype_ds); 340 341 UNUSED(rdata); 342 UNUSED(add); 343 UNUSED(arg); 344 345 return (ISC_R_SUCCESS); 346 } 347 348 static isc_result_t 349 digest_ds(ARGS_DIGEST) { 350 isc_region_t r; 351 352 REQUIRE(rdata->type == dns_rdatatype_ds); 353 354 dns_rdata_toregion(rdata, &r); 355 356 return ((digest)(arg, &r)); 357 } 358 359 static bool 360 checkowner_ds(ARGS_CHECKOWNER) { 361 REQUIRE(type == dns_rdatatype_ds); 362 363 UNUSED(name); 364 UNUSED(type); 365 UNUSED(rdclass); 366 UNUSED(wildcard); 367 368 return (true); 369 } 370 371 static bool 372 checknames_ds(ARGS_CHECKNAMES) { 373 REQUIRE(rdata->type == dns_rdatatype_ds); 374 375 UNUSED(rdata); 376 UNUSED(owner); 377 UNUSED(bad); 378 379 return (true); 380 } 381 382 static int 383 casecompare_ds(ARGS_COMPARE) { 384 return (compare_ds(rdata1, rdata2)); 385 } 386 387 #endif /* RDATA_GENERIC_DS_43_C */ 388