/src/bind9/lib/dns/rdata/generic/key_25.c
Line | Count | Source (jump to first uncovered line) |
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 | | #define RRTYPE_KEY_ATTRIBUTES \ |
22 | 14.4k | (DNS_RDATATYPEATTR_ATCNAME | DNS_RDATATYPEATTR_ZONECUTAUTH) |
23 | | |
24 | | /* |
25 | | * RFC 2535 section 3.1.2 says that if bits 0-1 of the Flags field are |
26 | | * both set, it means there is no key information and the RR stops after |
27 | | * the algorithm octet. However, this only applies to KEY records, as |
28 | | * indicated by the specifications of the RR types based on KEY: |
29 | | * |
30 | | * CDNSKEY - RFC 7344 |
31 | | * DNSKEY - RFC 4034 |
32 | | * RKEY - draft-reid-dnsext-rkey-00 |
33 | | */ |
34 | | static bool |
35 | 18.2k | generic_key_nokey(dns_rdatatype_t type, unsigned int flags) { |
36 | 18.2k | switch (type) { |
37 | 3.15k | case dns_rdatatype_cdnskey: |
38 | 9.57k | case dns_rdatatype_dnskey: |
39 | 11.7k | case dns_rdatatype_rkey: |
40 | 11.7k | return false; |
41 | 6.53k | case dns_rdatatype_key: |
42 | 6.53k | default: |
43 | 6.53k | return (flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY; |
44 | 18.2k | } |
45 | 18.2k | } |
46 | | |
47 | | static isc_result_t |
48 | 3.91k | generic_fromtext_key(ARGS_FROMTEXT) { |
49 | 3.91k | isc_token_t token; |
50 | 3.91k | dns_secalg_t alg; |
51 | 3.91k | dns_secproto_t proto; |
52 | 3.91k | dns_keyflags_t flags; |
53 | 3.91k | unsigned int used; |
54 | | |
55 | 3.91k | UNUSED(rdclass); |
56 | 3.91k | UNUSED(origin); |
57 | 3.91k | UNUSED(options); |
58 | 3.91k | UNUSED(callbacks); |
59 | | |
60 | | /* flags */ |
61 | 3.91k | RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, |
62 | 3.91k | false)); |
63 | 3.89k | RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion)); |
64 | 3.70k | if (type == dns_rdatatype_rkey && flags != 0U) { |
65 | 33 | RETTOK(DNS_R_FORMERR); |
66 | 33 | } |
67 | 3.67k | RETERR(uint16_tobuffer(flags, target)); |
68 | | |
69 | | /* protocol */ |
70 | 3.67k | RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, |
71 | 3.67k | false)); |
72 | 3.62k | RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion)); |
73 | 3.51k | RETERR(mem_tobuffer(target, &proto, 1)); |
74 | | |
75 | | /* algorithm */ |
76 | 3.51k | RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string, |
77 | 3.51k | false)); |
78 | 3.49k | RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion)); |
79 | 3.47k | RETERR(mem_tobuffer(target, &alg, 1)); |
80 | | |
81 | | /* No Key? */ |
82 | 3.47k | if (generic_key_nokey(type, flags)) { |
83 | 383 | return ISC_R_SUCCESS; |
84 | 383 | } |
85 | | |
86 | | /* |
87 | | * Save the current used value. It will become the current |
88 | | * value when we parse the keydata field. |
89 | | */ |
90 | 3.09k | used = isc_buffer_usedlength(target); |
91 | | |
92 | 3.09k | RETERR(isc_base64_tobuffer(lexer, target, -2)); |
93 | | |
94 | 3.01k | if (alg == DNS_KEYALG_PRIVATEDNS || alg == DNS_KEYALG_PRIVATEOID) { |
95 | 167 | isc_buffer_t b; |
96 | | |
97 | | /* |
98 | | * Set up 'b' so that the key data can be parsed. |
99 | | */ |
100 | 167 | b = *target; |
101 | 167 | b.active = b.used; |
102 | 167 | b.current = used; |
103 | | |
104 | 167 | RETERR(check_private(&b, alg)); |
105 | 167 | } |
106 | | |
107 | 2.98k | return ISC_R_SUCCESS; |
108 | 3.01k | } |
109 | | |
110 | | static isc_result_t |
111 | 6.66k | generic_totext_key(ARGS_TOTEXT) { |
112 | 6.66k | isc_region_t sr; |
113 | 6.66k | char buf[sizeof("[key id = 64000]")]; |
114 | 6.66k | unsigned int flags; |
115 | 6.66k | unsigned char algorithm; |
116 | 6.66k | char algbuf[DNS_NAME_FORMATSIZE]; |
117 | 6.66k | const char *keyinfo; |
118 | 6.66k | isc_region_t tmpr; |
119 | | |
120 | 6.66k | REQUIRE(rdata->length != 0); |
121 | | |
122 | 6.66k | dns_rdata_toregion(rdata, &sr); |
123 | | |
124 | | /* flags */ |
125 | 6.66k | flags = uint16_fromregion(&sr); |
126 | 6.66k | isc_region_consume(&sr, 2); |
127 | 6.66k | snprintf(buf, sizeof(buf), "%u", flags); |
128 | 6.66k | RETERR(str_totext(buf, target)); |
129 | 6.66k | RETERR(str_totext(" ", target)); |
130 | 6.66k | if ((flags & DNS_KEYFLAG_KSK) != 0) { |
131 | 2.49k | if (flags & DNS_KEYFLAG_REVOKE) { |
132 | 681 | keyinfo = "revoked KSK"; |
133 | 1.81k | } else { |
134 | 1.81k | keyinfo = "KSK"; |
135 | 1.81k | } |
136 | 4.17k | } else { |
137 | 4.17k | keyinfo = "ZSK"; |
138 | 4.17k | } |
139 | | |
140 | | /* protocol */ |
141 | 6.66k | snprintf(buf, sizeof(buf), "%u", sr.base[0]); |
142 | 6.66k | isc_region_consume(&sr, 1); |
143 | 6.66k | RETERR(str_totext(buf, target)); |
144 | 6.66k | RETERR(str_totext(" ", target)); |
145 | | |
146 | | /* algorithm */ |
147 | 6.66k | algorithm = sr.base[0]; |
148 | 6.66k | snprintf(buf, sizeof(buf), "%u", algorithm); |
149 | 6.66k | isc_region_consume(&sr, 1); |
150 | 6.66k | RETERR(str_totext(buf, target)); |
151 | | |
152 | | /* No Key? */ |
153 | 6.66k | if (generic_key_nokey(rdata->type, flags)) { |
154 | 1.02k | return ISC_R_SUCCESS; |
155 | 1.02k | } |
156 | | |
157 | 5.64k | if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 && |
158 | 5.64k | algorithm == DNS_KEYALG_PRIVATEDNS) |
159 | 44 | { |
160 | 44 | dns_name_t name; |
161 | 44 | dns_name_init(&name); |
162 | 44 | dns_name_fromregion(&name, &sr); |
163 | 44 | dns_name_format(&name, algbuf, sizeof(algbuf)); |
164 | 5.59k | } else if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 && |
165 | 5.59k | algorithm == DNS_KEYALG_PRIVATEOID) |
166 | 24 | { |
167 | 24 | const unsigned char *in = sr.base + 1; |
168 | 24 | ASN1_OBJECT *obj = d2i_ASN1_OBJECT(NULL, &in, *sr.base); |
169 | 24 | INSIST(obj != NULL); |
170 | 24 | int n = i2t_ASN1_OBJECT(algbuf, sizeof(buf), obj); |
171 | 24 | ASN1_OBJECT_free(obj); |
172 | 24 | if (n == -1 || (size_t)n >= sizeof(algbuf)) { |
173 | 0 | dns_secalg_format((dns_secalg_t)algorithm, algbuf, |
174 | 0 | sizeof(algbuf)); |
175 | 0 | } |
176 | 5.57k | } else { |
177 | 5.57k | dns_secalg_format((dns_secalg_t)algorithm, algbuf, |
178 | 5.57k | sizeof(algbuf)); |
179 | 5.57k | } |
180 | | |
181 | | /* key */ |
182 | 5.64k | if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { |
183 | 117 | RETERR(str_totext(" (", target)); |
184 | 117 | } |
185 | 5.64k | RETERR(str_totext(tctx->linebreak, target)); |
186 | | |
187 | 5.64k | if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) { |
188 | 5.64k | if (tctx->width == 0) { /* No splitting */ |
189 | 0 | RETERR(isc_base64_totext(&sr, 60, "", target)); |
190 | 5.64k | } else { |
191 | 5.64k | RETERR(isc_base64_totext(&sr, tctx->width - 2, |
192 | 5.64k | tctx->linebreak, target)); |
193 | 5.64k | } |
194 | 5.64k | } else { |
195 | 0 | dns_rdata_toregion(rdata, &tmpr); |
196 | 0 | snprintf(buf, sizeof(buf), "[key id = %u]", |
197 | 0 | dst_region_computeid(&tmpr)); |
198 | 0 | RETERR(str_totext(buf, target)); |
199 | 0 | } |
200 | | |
201 | 5.64k | if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) { |
202 | 117 | RETERR(str_totext(tctx->linebreak, target)); |
203 | 5.52k | } else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { |
204 | 0 | RETERR(str_totext(" ", target)); |
205 | 0 | } |
206 | | |
207 | 5.64k | if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) { |
208 | 117 | RETERR(str_totext(")", target)); |
209 | 117 | } |
210 | | |
211 | 5.64k | if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) { |
212 | 117 | if (rdata->type == dns_rdatatype_dnskey || |
213 | 117 | rdata->type == dns_rdatatype_cdnskey) |
214 | 71 | { |
215 | 71 | RETERR(str_totext(" ; ", target)); |
216 | 71 | RETERR(str_totext(keyinfo, target)); |
217 | 71 | } |
218 | 117 | RETERR(str_totext("; alg = ", target)); |
219 | 117 | RETERR(str_totext(algbuf, target)); |
220 | 117 | RETERR(str_totext(" ; key id = ", target)); |
221 | 117 | dns_rdata_toregion(rdata, &tmpr); |
222 | 117 | snprintf(buf, sizeof(buf), "%u", dst_region_computeid(&tmpr)); |
223 | 117 | RETERR(str_totext(buf, target)); |
224 | 117 | } |
225 | 5.64k | return ISC_R_SUCCESS; |
226 | 5.64k | } |
227 | | |
228 | | static isc_result_t |
229 | 8.23k | generic_fromwire_key(ARGS_FROMWIRE) { |
230 | 8.23k | unsigned char algorithm; |
231 | 8.23k | uint16_t flags; |
232 | 8.23k | isc_region_t sr; |
233 | | |
234 | 8.23k | UNUSED(rdclass); |
235 | 8.23k | UNUSED(dctx); |
236 | | |
237 | 8.23k | isc_buffer_activeregion(source, &sr); |
238 | 8.23k | if (sr.length < 4) { |
239 | 27 | return ISC_R_UNEXPECTEDEND; |
240 | 27 | } |
241 | 8.21k | flags = (sr.base[0] << 8) | sr.base[1]; |
242 | | |
243 | 8.21k | if (type == dns_rdatatype_rkey && flags != 0U) { |
244 | 39 | return DNS_R_FORMERR; |
245 | 39 | } |
246 | | |
247 | 8.17k | algorithm = sr.base[3]; |
248 | 8.17k | RETERR(mem_tobuffer(target, sr.base, 4)); |
249 | 8.10k | isc_region_consume(&sr, 4); |
250 | 8.10k | isc_buffer_forward(source, 4); |
251 | | |
252 | 8.10k | if (generic_key_nokey(type, flags)) { |
253 | 1.02k | return ISC_R_SUCCESS; |
254 | 1.02k | } |
255 | 7.08k | if (sr.length == 0) { |
256 | 16 | return ISC_R_UNEXPECTEDEND; |
257 | 16 | } |
258 | | |
259 | 7.06k | if (algorithm == DNS_KEYALG_PRIVATEDNS || |
260 | 7.06k | algorithm == DNS_KEYALG_PRIVATEOID) |
261 | 685 | { |
262 | 685 | isc_buffer_t b = *source; |
263 | 685 | RETERR(check_private(&b, algorithm)); |
264 | 685 | } |
265 | | |
266 | 6.95k | isc_buffer_activeregion(source, &sr); |
267 | 6.95k | isc_buffer_forward(source, sr.length); |
268 | 6.95k | return mem_tobuffer(target, sr.base, sr.length); |
269 | 7.06k | } |
270 | | |
271 | | static isc_result_t |
272 | 1.89k | fromtext_key(ARGS_FROMTEXT) { |
273 | 1.89k | REQUIRE(type == dns_rdatatype_key); |
274 | | |
275 | 1.89k | return generic_fromtext_key(CALL_FROMTEXT); |
276 | 1.89k | } |
277 | | |
278 | | static isc_result_t |
279 | 2.27k | totext_key(ARGS_TOTEXT) { |
280 | 2.27k | REQUIRE(rdata != NULL); |
281 | 2.27k | REQUIRE(rdata->type == dns_rdatatype_key); |
282 | | |
283 | 2.27k | return generic_totext_key(CALL_TOTEXT); |
284 | 2.27k | } |
285 | | |
286 | | static isc_result_t |
287 | 2.59k | fromwire_key(ARGS_FROMWIRE) { |
288 | 2.59k | REQUIRE(type == dns_rdatatype_key); |
289 | | |
290 | 2.59k | return generic_fromwire_key(CALL_FROMWIRE); |
291 | 2.59k | } |
292 | | |
293 | | static isc_result_t |
294 | 1.18k | towire_key(ARGS_TOWIRE) { |
295 | 1.18k | isc_region_t sr; |
296 | | |
297 | 1.18k | REQUIRE(rdata != NULL); |
298 | 1.18k | REQUIRE(rdata->type == dns_rdatatype_key); |
299 | 1.18k | REQUIRE(rdata->length != 0); |
300 | | |
301 | 1.18k | UNUSED(cctx); |
302 | | |
303 | 1.18k | dns_rdata_toregion(rdata, &sr); |
304 | 1.18k | return mem_tobuffer(target, sr.base, sr.length); |
305 | 1.18k | } |
306 | | |
307 | | static int |
308 | 2.87k | compare_key(ARGS_COMPARE) { |
309 | 2.87k | isc_region_t r1; |
310 | 2.87k | isc_region_t r2; |
311 | | |
312 | 2.87k | REQUIRE(rdata1 != NULL); |
313 | 2.87k | REQUIRE(rdata2 != NULL); |
314 | 2.87k | REQUIRE(rdata1->type == rdata2->type); |
315 | 2.87k | REQUIRE(rdata1->rdclass == rdata2->rdclass); |
316 | 2.87k | REQUIRE(rdata1->type == dns_rdatatype_key); |
317 | 2.87k | REQUIRE(rdata1->length != 0); |
318 | 2.87k | REQUIRE(rdata2->length != 0); |
319 | | |
320 | 2.87k | dns_rdata_toregion(rdata1, &r1); |
321 | 2.87k | dns_rdata_toregion(rdata2, &r2); |
322 | 2.87k | return isc_region_compare(&r1, &r2); |
323 | 2.87k | } |
324 | | |
325 | | static isc_result_t |
326 | 0 | generic_fromstruct_key(ARGS_FROMSTRUCT) { |
327 | 0 | dns_rdata_key_t *key = source; |
328 | |
|
329 | 0 | REQUIRE(key != NULL); |
330 | 0 | REQUIRE(key->common.rdtype == type); |
331 | 0 | REQUIRE(key->common.rdclass == rdclass); |
332 | |
|
333 | 0 | UNUSED(type); |
334 | 0 | UNUSED(rdclass); |
335 | |
|
336 | 0 | if (type == dns_rdatatype_rkey) { |
337 | 0 | INSIST(key->flags == 0U); |
338 | 0 | } |
339 | | |
340 | | /* Flags */ |
341 | 0 | RETERR(uint16_tobuffer(key->flags, target)); |
342 | | |
343 | | /* Protocol */ |
344 | 0 | RETERR(uint8_tobuffer(key->protocol, target)); |
345 | | |
346 | | /* Algorithm */ |
347 | 0 | RETERR(uint8_tobuffer(key->algorithm, target)); |
348 | | |
349 | | /* Data */ |
350 | 0 | return mem_tobuffer(target, key->data, key->datalen); |
351 | 0 | } |
352 | | |
353 | | static isc_result_t |
354 | 218 | generic_tostruct_key(ARGS_TOSTRUCT) { |
355 | 218 | dns_rdata_key_t *key = target; |
356 | 218 | isc_region_t sr; |
357 | | |
358 | 218 | REQUIRE(key != NULL); |
359 | 218 | REQUIRE(rdata->length >= 4U); |
360 | | |
361 | 218 | REQUIRE(key != NULL); |
362 | 218 | REQUIRE(key->common.rdclass == rdata->rdclass); |
363 | 218 | REQUIRE(key->common.rdtype == rdata->type); |
364 | | |
365 | 218 | dns_rdata_toregion(rdata, &sr); |
366 | | |
367 | | /* Flags */ |
368 | 218 | key->flags = uint16_fromregion(&sr); |
369 | 218 | isc_region_consume(&sr, 2); |
370 | | |
371 | | /* Protocol */ |
372 | 218 | key->protocol = uint8_fromregion(&sr); |
373 | 218 | isc_region_consume(&sr, 1); |
374 | | |
375 | | /* Algorithm */ |
376 | 218 | key->algorithm = uint8_fromregion(&sr); |
377 | 218 | isc_region_consume(&sr, 1); |
378 | | |
379 | | /* Data */ |
380 | 218 | key->datalen = sr.length; |
381 | 218 | key->data = mem_maybedup(mctx, sr.base, key->datalen); |
382 | 218 | key->mctx = mctx; |
383 | 218 | return ISC_R_SUCCESS; |
384 | 218 | } |
385 | | |
386 | | static void |
387 | 0 | generic_freestruct_key(ARGS_FREESTRUCT) { |
388 | 0 | dns_rdata_key_t *key = (dns_rdata_key_t *)source; |
389 | |
|
390 | 0 | REQUIRE(key != NULL); |
391 | |
|
392 | 0 | if (key->mctx == NULL) { |
393 | 0 | return; |
394 | 0 | } |
395 | | |
396 | 0 | if (key->data != NULL) { |
397 | 0 | isc_mem_free(key->mctx, key->data); |
398 | 0 | } |
399 | 0 | key->mctx = NULL; |
400 | 0 | } |
401 | | |
402 | | static isc_result_t |
403 | 0 | fromstruct_key(ARGS_FROMSTRUCT) { |
404 | 0 | REQUIRE(type == dns_rdatatype_key); |
405 | |
|
406 | 0 | return generic_fromstruct_key(CALL_FROMSTRUCT); |
407 | 0 | } |
408 | | |
409 | | static isc_result_t |
410 | 121 | tostruct_key(ARGS_TOSTRUCT) { |
411 | 121 | dns_rdata_key_t *key = target; |
412 | | |
413 | 121 | REQUIRE(key != NULL); |
414 | 121 | REQUIRE(rdata != NULL); |
415 | 121 | REQUIRE(rdata->type == dns_rdatatype_key); |
416 | | |
417 | 121 | DNS_RDATACOMMON_INIT(key, rdata->type, rdata->rdclass); |
418 | | |
419 | 121 | return generic_tostruct_key(CALL_TOSTRUCT); |
420 | 121 | } |
421 | | |
422 | | static void |
423 | 0 | freestruct_key(ARGS_FREESTRUCT) { |
424 | 0 | dns_rdata_key_t *key = (dns_rdata_key_t *)source; |
425 | |
|
426 | 0 | REQUIRE(key != NULL); |
427 | 0 | REQUIRE(key->common.rdtype == dns_rdatatype_key); |
428 | |
|
429 | 0 | generic_freestruct_key(source); |
430 | 0 | } |
431 | | |
432 | | static isc_result_t |
433 | 0 | additionaldata_key(ARGS_ADDLDATA) { |
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(add); |
440 | 0 | UNUSED(arg); |
441 | |
|
442 | 0 | return ISC_R_SUCCESS; |
443 | 0 | } |
444 | | |
445 | | static isc_result_t |
446 | 0 | digest_key(ARGS_DIGEST) { |
447 | 0 | isc_region_t r; |
448 | |
|
449 | 0 | REQUIRE(rdata != NULL); |
450 | 0 | REQUIRE(rdata->type == dns_rdatatype_key); |
451 | |
|
452 | 0 | dns_rdata_toregion(rdata, &r); |
453 | |
|
454 | 0 | return (digest)(arg, &r); |
455 | 0 | } |
456 | | |
457 | | static bool |
458 | 0 | checkowner_key(ARGS_CHECKOWNER) { |
459 | 0 | REQUIRE(type == dns_rdatatype_key); |
460 | |
|
461 | 0 | UNUSED(name); |
462 | 0 | UNUSED(type); |
463 | 0 | UNUSED(rdclass); |
464 | 0 | UNUSED(wildcard); |
465 | |
|
466 | 0 | return true; |
467 | 0 | } |
468 | | |
469 | | static bool |
470 | 0 | checknames_key(ARGS_CHECKNAMES) { |
471 | 0 | REQUIRE(rdata != NULL); |
472 | 0 | REQUIRE(rdata->type == dns_rdatatype_key); |
473 | |
|
474 | 0 | UNUSED(rdata); |
475 | 0 | UNUSED(owner); |
476 | 0 | UNUSED(bad); |
477 | |
|
478 | 0 | return true; |
479 | 0 | } |
480 | | |
481 | | static int |
482 | 0 | casecompare_key(ARGS_COMPARE) { |
483 | 0 | return compare_key(rdata1, rdata2); |
484 | 0 | } |
485 | | |
486 | | #endif /* RDATA_GENERIC_KEY_25_C */ |