1 /* $NetBSD: zonemd_63.c,v 1.5 2022/09/23 12:15: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 /* 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
fromtext_zonemd(ARGS_FROMTEXT)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
totext_zonemd(ARGS_TOTEXT)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
fromwire_zonemd(ARGS_FROMWIRE)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 UNUSED(options);
154
155 isc_buffer_activeregion(source, &sr);
156
157 /*
158 * If we do not recognize the digest type, ensure that the digest
159 * meets minimum length (12).
160 *
161 * If we do recognize the digest type, ensure that the digest is of the
162 * correct length.
163 */
164 if (sr.length < 18) {
165 return (ISC_R_UNEXPECTEDEND);
166 }
167
168 switch (sr.base[5]) {
169 case DNS_ZONEMD_DIGEST_SHA384:
170 digestlen = ISC_SHA384_DIGESTLENGTH;
171 break;
172 case DNS_ZONEMD_DIGEST_SHA512:
173 digestlen = ISC_SHA512_DIGESTLENGTH;
174 break;
175 default:
176 break;
177 }
178
179 if (digestlen != 0 && sr.length < 6 + digestlen) {
180 return (ISC_R_UNEXPECTEDEND);
181 }
182
183 /*
184 * Only specify the number of octets to consume if we recognize the
185 * digest type.
186 *
187 * If there is extra data, dns_rdata_fromwire() will detect that.
188 */
189 if (digestlen != 0) {
190 sr.length = 6 + digestlen;
191 }
192
193 isc_buffer_forward(source, sr.length);
194 return (mem_tobuffer(target, sr.base, sr.length));
195 }
196
197 static isc_result_t
towire_zonemd(ARGS_TOWIRE)198 towire_zonemd(ARGS_TOWIRE) {
199 isc_region_t sr;
200
201 REQUIRE(rdata->type == dns_rdatatype_zonemd);
202 REQUIRE(rdata->length != 0);
203
204 UNUSED(cctx);
205
206 dns_rdata_toregion(rdata, &sr);
207 return (mem_tobuffer(target, sr.base, sr.length));
208 }
209
210 static int
compare_zonemd(ARGS_COMPARE)211 compare_zonemd(ARGS_COMPARE) {
212 isc_region_t r1;
213 isc_region_t r2;
214
215 REQUIRE(rdata1->type == rdata2->type);
216 REQUIRE(rdata1->rdclass == rdata2->rdclass);
217 REQUIRE(rdata1->type == dns_rdatatype_zonemd);
218 REQUIRE(rdata1->length != 0);
219 REQUIRE(rdata2->length != 0);
220
221 dns_rdata_toregion(rdata1, &r1);
222 dns_rdata_toregion(rdata2, &r2);
223 return (isc_region_compare(&r1, &r2));
224 }
225
226 static isc_result_t
fromstruct_zonemd(ARGS_FROMSTRUCT)227 fromstruct_zonemd(ARGS_FROMSTRUCT) {
228 dns_rdata_zonemd_t *zonemd = source;
229
230 REQUIRE(zonemd != NULL);
231 REQUIRE(zonemd->common.rdtype == type);
232 REQUIRE(zonemd->common.rdclass == rdclass);
233
234 UNUSED(type);
235 UNUSED(rdclass);
236
237 switch (zonemd->digest_type) {
238 case DNS_ZONEMD_DIGEST_SHA384:
239 REQUIRE(zonemd->length == ISC_SHA384_DIGESTLENGTH);
240 break;
241 case DNS_ZONEMD_DIGEST_SHA512:
242 REQUIRE(zonemd->length == ISC_SHA512_DIGESTLENGTH);
243 break;
244 }
245
246 RETERR(uint32_tobuffer(zonemd->serial, target));
247 RETERR(uint8_tobuffer(zonemd->scheme, target));
248 RETERR(uint8_tobuffer(zonemd->digest_type, target));
249
250 return (mem_tobuffer(target, zonemd->digest, zonemd->length));
251 }
252
253 static isc_result_t
tostruct_zonemd(ARGS_TOSTRUCT)254 tostruct_zonemd(ARGS_TOSTRUCT) {
255 dns_rdata_zonemd_t *zonemd = target;
256 isc_region_t region;
257
258 REQUIRE(rdata->type == dns_rdatatype_zonemd);
259 REQUIRE(zonemd != NULL);
260 REQUIRE(rdata->length != 0);
261
262 zonemd->common.rdclass = rdata->rdclass;
263 zonemd->common.rdtype = rdata->type;
264 ISC_LINK_INIT(&zonemd->common, link);
265
266 dns_rdata_toregion(rdata, ®ion);
267
268 zonemd->serial = uint32_fromregion(®ion);
269 isc_region_consume(®ion, 4);
270 zonemd->scheme = uint8_fromregion(®ion);
271 isc_region_consume(®ion, 1);
272 zonemd->digest_type = uint8_fromregion(®ion);
273 isc_region_consume(®ion, 1);
274 zonemd->length = region.length;
275
276 zonemd->digest = mem_maybedup(mctx, region.base, region.length);
277 if (zonemd->digest == NULL) {
278 return (ISC_R_NOMEMORY);
279 }
280
281 zonemd->mctx = mctx;
282 return (ISC_R_SUCCESS);
283 }
284
285 static void
freestruct_zonemd(ARGS_FREESTRUCT)286 freestruct_zonemd(ARGS_FREESTRUCT) {
287 dns_rdata_zonemd_t *zonemd = source;
288
289 REQUIRE(zonemd != NULL);
290 REQUIRE(zonemd->common.rdtype == dns_rdatatype_zonemd);
291
292 if (zonemd->mctx == NULL) {
293 return;
294 }
295
296 if (zonemd->digest != NULL) {
297 isc_mem_free(zonemd->mctx, zonemd->digest);
298 }
299 zonemd->mctx = NULL;
300 }
301
302 static isc_result_t
additionaldata_zonemd(ARGS_ADDLDATA)303 additionaldata_zonemd(ARGS_ADDLDATA) {
304 REQUIRE(rdata->type == dns_rdatatype_zonemd);
305
306 UNUSED(rdata);
307 UNUSED(add);
308 UNUSED(arg);
309
310 return (ISC_R_SUCCESS);
311 }
312
313 static isc_result_t
digest_zonemd(ARGS_DIGEST)314 digest_zonemd(ARGS_DIGEST) {
315 isc_region_t r;
316
317 REQUIRE(rdata->type == dns_rdatatype_zonemd);
318
319 dns_rdata_toregion(rdata, &r);
320
321 return ((digest)(arg, &r));
322 }
323
324 static bool
checkowner_zonemd(ARGS_CHECKOWNER)325 checkowner_zonemd(ARGS_CHECKOWNER) {
326 REQUIRE(type == dns_rdatatype_zonemd);
327
328 UNUSED(name);
329 UNUSED(type);
330 UNUSED(rdclass);
331 UNUSED(wildcard);
332
333 return (true);
334 }
335
336 static bool
checknames_zonemd(ARGS_CHECKNAMES)337 checknames_zonemd(ARGS_CHECKNAMES) {
338 REQUIRE(rdata->type == dns_rdatatype_zonemd);
339
340 UNUSED(rdata);
341 UNUSED(owner);
342 UNUSED(bad);
343
344 return (true);
345 }
346
347 static int
casecompare_zonemd(ARGS_COMPARE)348 casecompare_zonemd(ARGS_COMPARE) {
349 return (compare_zonemd(rdata1, rdata2));
350 }
351
352 #endif /* RDATA_GENERIC_ZONEMD_63_C */
353