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