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