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