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