/src/bind9/lib/dns/rdata/generic/key_25.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 | | /* RFC2535 */ |
15 | | |
16 | | #ifndef RDATA_GENERIC_KEY_25_C |
17 | | #define RDATA_GENERIC_KEY_25_C |
18 | | |
19 | | #include <dst/dst.h> |
20 | | |
21 | 13.3k | #define RRTYPE_KEY_ATTRIBUTES (0) |
22 | | |
23 | | static isc_result_t |
24 | 3.60k | generic_fromtext_key(ARGS_FROMTEXT) { |
25 | 3.60k | isc_token_t token; |
26 | 3.60k | dns_secalg_t alg; |
27 | 3.60k | dns_secproto_t proto; |
28 | 3.60k | dns_keyflags_t flags; |
29 | 3.60k | unsigned int used; |
30 | | |
31 | 3.60k | UNUSED(rdclass); |
32 | 3.60k | UNUSED(origin); |
33 | 3.60k | UNUSED(options); |
34 | 3.60k | UNUSED(callbacks); |
35 | | |
36 | | /* flags */ |
37 | 3.60k | RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, |
38 | 3.60k | false)); |
39 | 3.58k | RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion)); |
40 | 3.45k | if (type == dns_rdatatype_rkey && flags != 0U) { |
41 | 14 | RETTOK(DNS_R_FORMERR); |
42 | 14 | } |
43 | 3.44k | RETERR(uint16_tobuffer(flags, target)); |
44 | | |
45 | | /* protocol */ |
46 | 3.44k | RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, |
47 | 3.44k | false)); |
48 | 3.40k | RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion)); |
49 | 3.25k | RETERR(mem_tobuffer(target, &proto, 1)); |
50 | | |
51 | | /* algorithm */ |
52 | 3.25k | RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, |
53 | 3.25k | false)); |
54 | 3.24k | RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion)); |
55 | 3.23k | RETERR(mem_tobuffer(target, &alg, 1)); |
56 | | |
57 | | /* |
58 | | * Save the current used value. It will become the current |
59 | | * value when we parse the keydata field. |
60 | | */ |
61 | 3.23k | used = isc_buffer_usedlength(target); |
62 | | |
63 | 3.23k | RETERR(isc_base64_tobuffer(lexer, target, isc_one_or_more)); |
64 | | |
65 | 3.21k | if (alg == DNS_KEYALG_PRIVATEDNS || alg == DNS_KEYALG_PRIVATEOID) { |
66 | 222 | isc_buffer_t b; |
67 | | |
68 | | /* |
69 | | * Set up 'b' so that the key data can be parsed. |
70 | | */ |
71 | 222 | b = *target; |
72 | 222 | b.active = b.used; |
73 | 222 | b.current = used; |
74 | | |
75 | 222 | RETERR(check_private(&b, alg)); |
76 | 179 | } |
77 | | |
78 | 3.16k | return ISC_R_SUCCESS; |
79 | 3.21k | } |
80 | | |
81 | | static isc_result_t |
82 | 5.65k | generic_totext_key(ARGS_TOTEXT) { |
83 | 5.65k | isc_region_t sr; |
84 | 5.65k | char buf[sizeof("[key id = 64000]")]; |
85 | 5.65k | unsigned int flags; |
86 | 5.65k | unsigned char algorithm; |
87 | 5.65k | char algbuf[DNS_NAME_FORMATSIZE]; |
88 | 5.65k | const char *keyinfo; |
89 | 5.65k | isc_region_t tmpr; |
90 | | |
91 | 5.65k | REQUIRE(rdata->length != 0); |
92 | | |
93 | 5.65k | dns_rdata_toregion(rdata, &sr); |
94 | | |
95 | | /* flags */ |
96 | 5.65k | flags = uint16_fromregion(&sr); |
97 | 5.65k | isc_region_consume(&sr, 2); |
98 | 5.65k | snprintf(buf, sizeof(buf), "%u", flags); |
99 | 5.65k | RETERR(str_totext(buf, target)); |
100 | 5.65k | RETERR(str_totext(" ", target)); |
101 | 5.65k | if ((flags & DNS_KEYFLAG_KSK) != 0) { |
102 | 2.04k | if (flags & DNS_KEYFLAG_REVOKE) { |
103 | 731 | keyinfo = "revoked KSK"; |
104 | 1.30k | } else { |
105 | 1.30k | keyinfo = "KSK"; |
106 | 1.30k | } |
107 | 3.61k | } else { |
108 | 3.61k | keyinfo = "ZSK"; |
109 | 3.61k | } |
110 | | |
111 | | /* protocol */ |
112 | 5.65k | snprintf(buf, sizeof(buf), "%u", sr.base[0]); |
113 | 5.65k | isc_region_consume(&sr, 1); |
114 | 5.65k | RETERR(str_totext(buf, target)); |
115 | 5.65k | RETERR(str_totext(" ", target)); |
116 | | |
117 | | /* algorithm */ |
118 | 5.65k | algorithm = sr.base[0]; |
119 | 5.65k | snprintf(buf, sizeof(buf), "%u", algorithm); |
120 | 5.65k | isc_region_consume(&sr, 1); |
121 | 5.65k | RETERR(str_totext(buf, target)); |
122 | | |
123 | 5.65k | if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 && |
124 | 144 | algorithm == DNS_KEYALG_PRIVATEDNS) |
125 | 53 | { |
126 | 53 | dns_name_t name; |
127 | 53 | dns_name_init(&name); |
128 | 53 | dns_name_fromregion(&name, &sr); |
129 | 53 | dns_name_format(&name, algbuf, sizeof(algbuf)); |
130 | 5.59k | } else if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 && |
131 | 91 | algorithm == DNS_KEYALG_PRIVATEOID) |
132 | 34 | { |
133 | 34 | const unsigned char *in = sr.base + 1; |
134 | 34 | ASN1_OBJECT *obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base); |
135 | 34 | INSIST(obj != NULL); |
136 | 34 | int n = i2t_ASN1_OBJECT(algbuf, sizeof(algbuf), obj); |
137 | 34 | ASN1_OBJECT_free(obj); |
138 | 34 | if (n == -1 || (size_t)n >= sizeof(algbuf)) { |
139 | 0 | dns_secalg_format((dns_secalg_t)algorithm, algbuf, |
140 | 0 | sizeof(algbuf)); |
141 | 0 | } |
142 | 5.56k | } else { |
143 | 5.56k | dns_secalg_format((dns_secalg_t)algorithm, algbuf, |
144 | 5.56k | sizeof(algbuf)); |
145 | 5.56k | } |
146 | | |
147 | | /* key */ |
148 | 5.65k | if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { |
149 | 144 | RETERR(str_totext(" (", target)); |
150 | 144 | } |
151 | 5.65k | RETERR(str_totext(tctx->linebreak, target)); |
152 | | |
153 | 5.65k | if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) { |
154 | 5.65k | if (tctx->width == 0) { /* No splitting */ |
155 | 0 | RETERR(isc_base64_totext(&sr, 60, "", target)); |
156 | 5.65k | } else { |
157 | 5.65k | RETERR(isc_base64_totext(&sr, tctx->width - 2, |
158 | 5.65k | tctx->linebreak, target)); |
159 | 5.65k | } |
160 | 5.65k | } else { |
161 | 0 | dns_rdata_toregion(rdata, &tmpr); |
162 | 0 | snprintf(buf, sizeof(buf), "[key id = %u]", |
163 | 0 | dst_region_computeid(&tmpr)); |
164 | 0 | RETERR(str_totext(buf, target)); |
165 | 0 | } |
166 | | |
167 | 5.65k | if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) { |
168 | 144 | RETERR(str_totext(tctx->linebreak, target)); |
169 | 5.50k | } else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { |
170 | 0 | RETERR(str_totext(" ", target)); |
171 | 0 | } |
172 | | |
173 | 5.65k | if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { |
174 | 144 | RETERR(str_totext(")", target)); |
175 | 144 | } |
176 | | |
177 | 5.65k | if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) { |
178 | 144 | if (rdata->type == dns_rdatatype_dnskey || |
179 | 118 | rdata->type == dns_rdatatype_cdnskey) |
180 | 67 | { |
181 | 67 | RETERR(str_totext(" ; ", target)); |
182 | 67 | RETERR(str_totext(keyinfo, target)); |
183 | 67 | } |
184 | 144 | RETERR(str_totext("; alg = ", target)); |
185 | 144 | RETERR(str_totext(algbuf, target)); |
186 | 144 | RETERR(str_totext(" ; key id = ", target)); |
187 | 144 | dns_rdata_toregion(rdata, &tmpr); |
188 | 144 | snprintf(buf, sizeof(buf), "%u", dst_region_computeid(&tmpr)); |
189 | 144 | RETERR(str_totext(buf, target)); |
190 | 144 | } |
191 | 5.65k | return ISC_R_SUCCESS; |
192 | 5.65k | } |
193 | | |
194 | | static isc_result_t |
195 | 7.91k | generic_fromwire_key(ARGS_FROMWIRE) { |
196 | 7.91k | unsigned char algorithm; |
197 | 7.91k | uint16_t flags; |
198 | 7.91k | isc_region_t sr; |
199 | | |
200 | 7.91k | UNUSED(rdclass); |
201 | 7.91k | UNUSED(dctx); |
202 | | |
203 | 7.91k | isc_buffer_activeregion(source, &sr); |
204 | 7.91k | if (sr.length < 4) { |
205 | 46 | return ISC_R_UNEXPECTEDEND; |
206 | 46 | } |
207 | 7.86k | flags = (sr.base[0] << 8) | sr.base[1]; |
208 | | |
209 | 7.86k | if (type == dns_rdatatype_rkey && flags != 0U) { |
210 | 18 | return DNS_R_FORMERR; |
211 | 18 | } |
212 | | |
213 | 7.84k | algorithm = sr.base[3]; |
214 | 7.84k | RETERR(mem_tobuffer(target, sr.base, 4)); |
215 | 7.77k | isc_region_consume(&sr, 4); |
216 | 7.77k | isc_buffer_forward(source, 4); |
217 | | |
218 | 7.77k | if (sr.length == 0) { |
219 | 15 | return ISC_R_UNEXPECTEDEND; |
220 | 15 | } |
221 | | |
222 | 7.75k | if (algorithm == DNS_KEYALG_PRIVATEDNS || |
223 | 7.45k | algorithm == DNS_KEYALG_PRIVATEOID) |
224 | 453 | { |
225 | 453 | isc_buffer_t b = *source; |
226 | 453 | RETERR(check_private(&b, algorithm)); |
227 | 413 | } |
228 | | |
229 | 7.71k | isc_buffer_activeregion(source, &sr); |
230 | 7.71k | isc_buffer_forward(source, sr.length); |
231 | 7.71k | return mem_tobuffer(target, sr.base, sr.length); |
232 | 7.75k | } |
233 | | |
234 | | static isc_result_t |
235 | 1.69k | fromtext_key(ARGS_FROMTEXT) { |
236 | 1.69k | REQUIRE(type == dns_rdatatype_key); |
237 | | |
238 | 1.69k | return generic_fromtext_key(CALL_FROMTEXT); |
239 | 1.69k | } |
240 | | |
241 | | static isc_result_t |
242 | 1.87k | totext_key(ARGS_TOTEXT) { |
243 | 1.87k | REQUIRE(rdata != NULL); |
244 | 1.87k | REQUIRE(rdata->type == dns_rdatatype_key); |
245 | | |
246 | 1.87k | return generic_totext_key(CALL_TOTEXT); |
247 | 1.87k | } |
248 | | |
249 | | static isc_result_t |
250 | 2.14k | fromwire_key(ARGS_FROMWIRE) { |
251 | 2.14k | REQUIRE(type == dns_rdatatype_key); |
252 | | |
253 | 2.14k | return generic_fromwire_key(CALL_FROMWIRE); |
254 | 2.14k | } |
255 | | |
256 | | static isc_result_t |
257 | 944 | towire_key(ARGS_TOWIRE) { |
258 | 944 | isc_region_t sr; |
259 | | |
260 | 944 | REQUIRE(rdata != NULL); |
261 | 944 | REQUIRE(rdata->type == dns_rdatatype_key); |
262 | 944 | REQUIRE(rdata->length != 0); |
263 | | |
264 | 944 | UNUSED(cctx); |
265 | | |
266 | 944 | dns_rdata_toregion(rdata, &sr); |
267 | 944 | return mem_tobuffer(target, sr.base, sr.length); |
268 | 944 | } |
269 | | |
270 | | static int |
271 | 180k | compare_key(ARGS_COMPARE) { |
272 | 180k | isc_region_t r1; |
273 | 180k | isc_region_t r2; |
274 | | |
275 | 180k | REQUIRE(rdata1 != NULL); |
276 | 180k | REQUIRE(rdata2 != NULL); |
277 | 180k | REQUIRE(rdata1->type == rdata2->type); |
278 | 180k | REQUIRE(rdata1->rdclass == rdata2->rdclass); |
279 | 180k | REQUIRE(rdata1->type == dns_rdatatype_key); |
280 | 180k | REQUIRE(rdata1->length != 0); |
281 | 180k | REQUIRE(rdata2->length != 0); |
282 | | |
283 | 180k | dns_rdata_toregion(rdata1, &r1); |
284 | 180k | dns_rdata_toregion(rdata2, &r2); |
285 | 180k | return isc_region_compare(&r1, &r2); |
286 | 180k | } |
287 | | |
288 | | static isc_result_t |
289 | 0 | generic_fromstruct_key(ARGS_FROMSTRUCT) { |
290 | 0 | dns_rdata_key_t *key = source; |
291 | |
|
292 | 0 | REQUIRE(key != NULL); |
293 | 0 | REQUIRE(key->common.rdtype == type); |
294 | 0 | REQUIRE(key->common.rdclass == rdclass); |
295 | |
|
296 | 0 | UNUSED(type); |
297 | 0 | UNUSED(rdclass); |
298 | |
|
299 | 0 | if (type == dns_rdatatype_rkey) { |
300 | 0 | INSIST(key->flags == 0U); |
301 | 0 | } |
302 | | |
303 | | /* Flags */ |
304 | 0 | RETERR(uint16_tobuffer(key->flags, target)); |
305 | | |
306 | | /* Protocol */ |
307 | 0 | RETERR(uint8_tobuffer(key->protocol, target)); |
308 | | |
309 | | /* Algorithm */ |
310 | 0 | RETERR(uint8_tobuffer(key->algorithm, target)); |
311 | | |
312 | | /* Data */ |
313 | 0 | return mem_tobuffer(target, key->data, key->datalen); |
314 | 0 | } |
315 | | |
316 | | static isc_result_t |
317 | 229 | generic_tostruct_key(ARGS_TOSTRUCT) { |
318 | 229 | dns_rdata_key_t *key = target; |
319 | 229 | isc_region_t sr; |
320 | | |
321 | 229 | REQUIRE(key != NULL); |
322 | 229 | REQUIRE(rdata->length >= 4U); |
323 | | |
324 | 229 | REQUIRE(key != NULL); |
325 | 229 | REQUIRE(key->common.rdclass == rdata->rdclass); |
326 | 229 | REQUIRE(key->common.rdtype == rdata->type); |
327 | | |
328 | 229 | dns_rdata_toregion(rdata, &sr); |
329 | | |
330 | | /* Flags */ |
331 | 229 | key->flags = uint16_fromregion(&sr); |
332 | 229 | isc_region_consume(&sr, 2); |
333 | | |
334 | | /* Protocol */ |
335 | 229 | key->protocol = uint8_fromregion(&sr); |
336 | 229 | isc_region_consume(&sr, 1); |
337 | | |
338 | | /* Algorithm */ |
339 | 229 | key->algorithm = uint8_fromregion(&sr); |
340 | 229 | isc_region_consume(&sr, 1); |
341 | | |
342 | | /* Data */ |
343 | 229 | key->datalen = sr.length; |
344 | 229 | key->data = mem_maybedup(mctx, sr.base, key->datalen); |
345 | 229 | key->mctx = mctx; |
346 | 229 | return ISC_R_SUCCESS; |
347 | 229 | } |
348 | | |
349 | | static void |
350 | 0 | generic_freestruct_key(ARGS_FREESTRUCT) { |
351 | 0 | dns_rdata_key_t *key = (dns_rdata_key_t *)source; |
352 | |
|
353 | 0 | REQUIRE(key != NULL); |
354 | |
|
355 | 0 | if (key->mctx == NULL) { |
356 | 0 | return; |
357 | 0 | } |
358 | | |
359 | 0 | if (key->data != NULL) { |
360 | 0 | isc_mem_free(key->mctx, key->data); |
361 | 0 | } |
362 | 0 | key->mctx = NULL; |
363 | 0 | } |
364 | | |
365 | | static isc_result_t |
366 | 0 | fromstruct_key(ARGS_FROMSTRUCT) { |
367 | 0 | REQUIRE(type == dns_rdatatype_key); |
368 | |
|
369 | 0 | return generic_fromstruct_key(CALL_FROMSTRUCT); |
370 | 0 | } |
371 | | |
372 | | static isc_result_t |
373 | 126 | tostruct_key(ARGS_TOSTRUCT) { |
374 | 126 | dns_rdata_key_t *key = target; |
375 | | |
376 | 126 | REQUIRE(key != NULL); |
377 | 126 | REQUIRE(rdata != NULL); |
378 | 126 | REQUIRE(rdata->type == dns_rdatatype_key); |
379 | | |
380 | 126 | DNS_RDATACOMMON_INIT(key, rdata->type, rdata->rdclass); |
381 | | |
382 | 126 | return generic_tostruct_key(CALL_TOSTRUCT); |
383 | 126 | } |
384 | | |
385 | | static void |
386 | 0 | freestruct_key(ARGS_FREESTRUCT) { |
387 | 0 | dns_rdata_key_t *key = (dns_rdata_key_t *)source; |
388 | |
|
389 | 0 | REQUIRE(key != NULL); |
390 | 0 | REQUIRE(key->common.rdtype == dns_rdatatype_key); |
391 | |
|
392 | 0 | generic_freestruct_key(source); |
393 | 0 | } |
394 | | |
395 | | static isc_result_t |
396 | 0 | additionaldata_key(ARGS_ADDLDATA) { |
397 | 0 | REQUIRE(rdata != NULL); |
398 | 0 | REQUIRE(rdata->type == dns_rdatatype_key); |
399 | |
|
400 | 0 | UNUSED(rdata); |
401 | 0 | UNUSED(owner); |
402 | 0 | UNUSED(add); |
403 | 0 | UNUSED(arg); |
404 | |
|
405 | 0 | return ISC_R_SUCCESS; |
406 | 0 | } |
407 | | |
408 | | static isc_result_t |
409 | 0 | digest_key(ARGS_DIGEST) { |
410 | 0 | isc_region_t r; |
411 | |
|
412 | 0 | REQUIRE(rdata != NULL); |
413 | 0 | REQUIRE(rdata->type == dns_rdatatype_key); |
414 | |
|
415 | 0 | dns_rdata_toregion(rdata, &r); |
416 | |
|
417 | 0 | return (digest)(arg, &r); |
418 | 0 | } |
419 | | |
420 | | static bool |
421 | 0 | checkowner_key(ARGS_CHECKOWNER) { |
422 | 0 | REQUIRE(type == dns_rdatatype_key); |
423 | |
|
424 | 0 | UNUSED(name); |
425 | 0 | UNUSED(type); |
426 | 0 | UNUSED(rdclass); |
427 | 0 | UNUSED(wildcard); |
428 | |
|
429 | 0 | return true; |
430 | 0 | } |
431 | | |
432 | | static bool |
433 | 0 | checknames_key(ARGS_CHECKNAMES) { |
434 | 0 | REQUIRE(rdata != NULL); |
435 | 0 | REQUIRE(rdata->type == dns_rdatatype_key); |
436 | |
|
437 | 0 | UNUSED(rdata); |
438 | 0 | UNUSED(owner); |
439 | 0 | UNUSED(bad); |
440 | |
|
441 | 0 | return true; |
442 | 0 | } |
443 | | |
444 | | static int |
445 | 0 | casecompare_key(ARGS_COMPARE) { |
446 | 0 | return compare_key(rdata1, rdata2); |
447 | 0 | } |
448 | | |
449 | | #endif /* RDATA_GENERIC_KEY_25_C */ |