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