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
generic_fromtext_ds(ARGS_FROMTEXT)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
fromtext_ds(ARGS_FROMTEXT)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
generic_totext_ds(ARGS_TOTEXT)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
totext_ds(ARGS_TOTEXT)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
generic_fromwire_ds(ARGS_FROMWIRE)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
fromwire_ds(ARGS_FROMWIRE)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
towire_ds(ARGS_TOWIRE)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
compare_ds(ARGS_COMPARE)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
generic_fromstruct_ds(ARGS_FROMSTRUCT)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
fromstruct_ds(ARGS_FROMSTRUCT)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
generic_tostruct_ds(ARGS_TOSTRUCT)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
tostruct_ds(ARGS_TOSTRUCT)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
freestruct_ds(ARGS_FREESTRUCT)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
additionaldata_ds(ARGS_ADDLDATA)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
digest_ds(ARGS_DIGEST)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
checkowner_ds(ARGS_CHECKOWNER)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
checknames_ds(ARGS_CHECKNAMES)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
casecompare_ds(ARGS_COMPARE)383 casecompare_ds(ARGS_COMPARE) {
384 return (compare_ds(rdata1, rdata2));
385 }
386
387 #endif /* RDATA_GENERIC_DS_43_C */
388