1 /* $NetBSD: zonemd_63.c,v 1.7 2025/01/26 16:25:34 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 /* RFC 8976 */ 17 18 #ifndef RDATA_GENERIC_ZONEMD_63_C 19 #define RDATA_GENERIC_ZONEMD_63_C 20 21 #define RRTYPE_ZONEMD_ATTRIBUTES 0 22 23 static isc_result_t 24 fromtext_zonemd(ARGS_FROMTEXT) { 25 isc_token_t token; 26 int digest_type, length; 27 isc_buffer_t save; 28 isc_result_t result; 29 30 UNUSED(type); 31 UNUSED(rdclass); 32 UNUSED(origin); 33 UNUSED(options); 34 UNUSED(callbacks); 35 36 /* 37 * Zone Serial. 38 */ 39 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 40 false)); 41 RETERR(uint32_tobuffer(token.value.as_ulong, target)); 42 43 /* 44 * Digest Scheme. 45 */ 46 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 47 false)); 48 RETERR(uint8_tobuffer(token.value.as_ulong, target)); 49 50 /* 51 * Digest Type. 52 */ 53 RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number, 54 false)); 55 digest_type = token.value.as_ulong; 56 RETERR(uint8_tobuffer(digest_type, target)); 57 58 /* 59 * Digest. 60 */ 61 switch (digest_type) { 62 case DNS_ZONEMD_DIGEST_SHA384: 63 length = ISC_SHA384_DIGESTLENGTH; 64 break; 65 case DNS_ZONEMD_DIGEST_SHA512: 66 length = ISC_SHA512_DIGESTLENGTH; 67 break; 68 default: 69 length = -2; 70 break; 71 } 72 73 save = *target; 74 result = isc_hex_tobuffer(lexer, target, length); 75 /* Minimum length of digest is 12 octets. */ 76 if (isc_buffer_usedlength(target) - isc_buffer_usedlength(&save) < 12) { 77 return ISC_R_UNEXPECTEDEND; 78 } 79 return result; 80 } 81 82 static isc_result_t 83 totext_zonemd(ARGS_TOTEXT) { 84 isc_region_t sr; 85 char buf[sizeof("0123456789")]; 86 unsigned long num; 87 88 REQUIRE(rdata->length > 6); 89 90 UNUSED(tctx); 91 92 dns_rdata_toregion(rdata, &sr); 93 94 /* 95 * Zone Serial. 96 */ 97 num = uint32_fromregion(&sr); 98 isc_region_consume(&sr, 4); 99 snprintf(buf, sizeof(buf), "%lu", num); 100 RETERR(str_totext(buf, target)); 101 102 RETERR(str_totext(" ", target)); 103 104 /* 105 * Digest scheme. 106 */ 107 num = uint8_fromregion(&sr); 108 isc_region_consume(&sr, 1); 109 snprintf(buf, sizeof(buf), "%lu", num); 110 RETERR(str_totext(buf, target)); 111 112 RETERR(str_totext(" ", target)); 113 114 /* 115 * Digest type. 116 */ 117 num = uint8_fromregion(&sr); 118 isc_region_consume(&sr, 1); 119 snprintf(buf, sizeof(buf), "%lu", num); 120 RETERR(str_totext(buf, target)); 121 122 /* 123 * Digest. 124 */ 125 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 126 RETERR(str_totext(" (", target)); 127 } 128 RETERR(str_totext(tctx->linebreak, target)); 129 if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) { 130 if (tctx->width == 0) { /* No splitting */ 131 RETERR(isc_hex_totext(&sr, 0, "", target)); 132 } else { 133 RETERR(isc_hex_totext(&sr, tctx->width - 2, 134 tctx->linebreak, target)); 135 } 136 } else { 137 RETERR(str_totext("[omitted]", target)); 138 } 139 if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { 140 RETERR(str_totext(" )", target)); 141 } 142 return ISC_R_SUCCESS; 143 } 144 145 static isc_result_t 146 fromwire_zonemd(ARGS_FROMWIRE) { 147 isc_region_t sr; 148 size_t digestlen = 0; 149 150 UNUSED(type); 151 UNUSED(rdclass); 152 UNUSED(dctx); 153 154 isc_buffer_activeregion(source, &sr); 155 156 /* 157 * If we do not recognize the digest type, ensure that the digest 158 * meets minimum length (12). 159 * 160 * If we do recognize the digest type, ensure that the digest is of the 161 * correct length. 162 */ 163 if (sr.length < 18) { 164 return ISC_R_UNEXPECTEDEND; 165 } 166 167 switch (sr.base[5]) { 168 case DNS_ZONEMD_DIGEST_SHA384: 169 digestlen = ISC_SHA384_DIGESTLENGTH; 170 break; 171 case DNS_ZONEMD_DIGEST_SHA512: 172 digestlen = ISC_SHA512_DIGESTLENGTH; 173 break; 174 default: 175 break; 176 } 177 178 if (digestlen != 0 && sr.length < 6 + digestlen) { 179 return ISC_R_UNEXPECTEDEND; 180 } 181 182 /* 183 * Only specify the number of octets to consume if we recognize the 184 * digest type. 185 * 186 * If there is extra data, dns_rdata_fromwire() will detect that. 187 */ 188 if (digestlen != 0) { 189 sr.length = 6 + digestlen; 190 } 191 192 isc_buffer_forward(source, sr.length); 193 return mem_tobuffer(target, sr.base, sr.length); 194 } 195 196 static isc_result_t 197 towire_zonemd(ARGS_TOWIRE) { 198 isc_region_t sr; 199 200 REQUIRE(rdata->type == dns_rdatatype_zonemd); 201 REQUIRE(rdata->length != 0); 202 203 UNUSED(cctx); 204 205 dns_rdata_toregion(rdata, &sr); 206 return mem_tobuffer(target, sr.base, sr.length); 207 } 208 209 static int 210 compare_zonemd(ARGS_COMPARE) { 211 isc_region_t r1; 212 isc_region_t r2; 213 214 REQUIRE(rdata1->type == rdata2->type); 215 REQUIRE(rdata1->rdclass == rdata2->rdclass); 216 REQUIRE(rdata1->type == dns_rdatatype_zonemd); 217 REQUIRE(rdata1->length != 0); 218 REQUIRE(rdata2->length != 0); 219 220 dns_rdata_toregion(rdata1, &r1); 221 dns_rdata_toregion(rdata2, &r2); 222 return isc_region_compare(&r1, &r2); 223 } 224 225 static isc_result_t 226 fromstruct_zonemd(ARGS_FROMSTRUCT) { 227 dns_rdata_zonemd_t *zonemd = source; 228 229 REQUIRE(zonemd != NULL); 230 REQUIRE(zonemd->common.rdtype == type); 231 REQUIRE(zonemd->common.rdclass == rdclass); 232 233 UNUSED(type); 234 UNUSED(rdclass); 235 236 switch (zonemd->digest_type) { 237 case DNS_ZONEMD_DIGEST_SHA384: 238 REQUIRE(zonemd->length == ISC_SHA384_DIGESTLENGTH); 239 break; 240 case DNS_ZONEMD_DIGEST_SHA512: 241 REQUIRE(zonemd->length == ISC_SHA512_DIGESTLENGTH); 242 break; 243 } 244 245 RETERR(uint32_tobuffer(zonemd->serial, target)); 246 RETERR(uint8_tobuffer(zonemd->scheme, target)); 247 RETERR(uint8_tobuffer(zonemd->digest_type, target)); 248 249 return mem_tobuffer(target, zonemd->digest, zonemd->length); 250 } 251 252 static isc_result_t 253 tostruct_zonemd(ARGS_TOSTRUCT) { 254 dns_rdata_zonemd_t *zonemd = target; 255 isc_region_t region; 256 257 REQUIRE(rdata->type == dns_rdatatype_zonemd); 258 REQUIRE(zonemd != NULL); 259 REQUIRE(rdata->length != 0); 260 261 zonemd->common.rdclass = rdata->rdclass; 262 zonemd->common.rdtype = rdata->type; 263 ISC_LINK_INIT(&zonemd->common, link); 264 265 dns_rdata_toregion(rdata, ®ion); 266 267 zonemd->serial = uint32_fromregion(®ion); 268 isc_region_consume(®ion, 4); 269 zonemd->scheme = uint8_fromregion(®ion); 270 isc_region_consume(®ion, 1); 271 zonemd->digest_type = uint8_fromregion(®ion); 272 isc_region_consume(®ion, 1); 273 zonemd->length = region.length; 274 275 zonemd->digest = mem_maybedup(mctx, region.base, region.length); 276 zonemd->mctx = mctx; 277 return ISC_R_SUCCESS; 278 } 279 280 static void 281 freestruct_zonemd(ARGS_FREESTRUCT) { 282 dns_rdata_zonemd_t *zonemd = source; 283 284 REQUIRE(zonemd != NULL); 285 REQUIRE(zonemd->common.rdtype == dns_rdatatype_zonemd); 286 287 if (zonemd->mctx == NULL) { 288 return; 289 } 290 291 if (zonemd->digest != NULL) { 292 isc_mem_free(zonemd->mctx, zonemd->digest); 293 } 294 zonemd->mctx = NULL; 295 } 296 297 static isc_result_t 298 additionaldata_zonemd(ARGS_ADDLDATA) { 299 REQUIRE(rdata->type == dns_rdatatype_zonemd); 300 301 UNUSED(rdata); 302 UNUSED(owner); 303 UNUSED(add); 304 UNUSED(arg); 305 306 return ISC_R_SUCCESS; 307 } 308 309 static isc_result_t 310 digest_zonemd(ARGS_DIGEST) { 311 isc_region_t r; 312 313 REQUIRE(rdata->type == dns_rdatatype_zonemd); 314 315 dns_rdata_toregion(rdata, &r); 316 317 return (digest)(arg, &r); 318 } 319 320 static bool 321 checkowner_zonemd(ARGS_CHECKOWNER) { 322 REQUIRE(type == dns_rdatatype_zonemd); 323 324 UNUSED(name); 325 UNUSED(type); 326 UNUSED(rdclass); 327 UNUSED(wildcard); 328 329 return true; 330 } 331 332 static bool 333 checknames_zonemd(ARGS_CHECKNAMES) { 334 REQUIRE(rdata->type == dns_rdatatype_zonemd); 335 336 UNUSED(rdata); 337 UNUSED(owner); 338 UNUSED(bad); 339 340 return true; 341 } 342 343 static int 344 casecompare_zonemd(ARGS_COMPARE) { 345 return compare_zonemd(rdata1, rdata2); 346 } 347 348 #endif /* RDATA_GENERIC_ZONEMD_63_C */ 349