1/*	$NetBSD: tkey_249.c,v 1.9 2024/02/21 22:52:14 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/* draft-ietf-dnsext-tkey-01.txt */
17
18#ifndef RDATA_GENERIC_TKEY_249_C
19#define RDATA_GENERIC_TKEY_249_C
20
21#define RRTYPE_TKEY_ATTRIBUTES (DNS_RDATATYPEATTR_META)
22
23static isc_result_t
24fromtext_tkey(ARGS_FROMTEXT) {
25	isc_token_t token;
26	dns_rcode_t rcode;
27	dns_name_t name;
28	isc_buffer_t buffer;
29	long i;
30	char *e;
31
32	REQUIRE(type == dns_rdatatype_tkey);
33
34	UNUSED(type);
35	UNUSED(rdclass);
36	UNUSED(callbacks);
37
38	/*
39	 * Algorithm.
40	 */
41	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
42				      false));
43	dns_name_init(&name, NULL);
44	buffer_fromregion(&buffer, &token.value.as_region);
45	if (origin == NULL) {
46		origin = dns_rootname;
47	}
48	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
49
50	/*
51	 * Inception.
52	 */
53	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
54				      false));
55	RETERR(uint32_tobuffer(token.value.as_ulong, target));
56
57	/*
58	 * Expiration.
59	 */
60	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
61				      false));
62	RETERR(uint32_tobuffer(token.value.as_ulong, target));
63
64	/*
65	 * Mode.
66	 */
67	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
68				      false));
69	if (token.value.as_ulong > 0xffffU) {
70		RETTOK(ISC_R_RANGE);
71	}
72	RETERR(uint16_tobuffer(token.value.as_ulong, target));
73
74	/*
75	 * Error.
76	 */
77	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
78				      false));
79	if (dns_tsigrcode_fromtext(&rcode, &token.value.as_textregion) !=
80	    ISC_R_SUCCESS)
81	{
82		i = strtol(DNS_AS_STR(token), &e, 10);
83		if (*e != 0) {
84			RETTOK(DNS_R_UNKNOWN);
85		}
86		if (i < 0 || i > 0xffff) {
87			RETTOK(ISC_R_RANGE);
88		}
89		rcode = (dns_rcode_t)i;
90	}
91	RETERR(uint16_tobuffer(rcode, target));
92
93	/*
94	 * Key Size.
95	 */
96	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
97				      false));
98	if (token.value.as_ulong > 0xffffU) {
99		RETTOK(ISC_R_RANGE);
100	}
101	RETERR(uint16_tobuffer(token.value.as_ulong, target));
102
103	/*
104	 * Key Data.
105	 */
106	RETERR(isc_base64_tobuffer(lexer, target, (int)token.value.as_ulong));
107
108	/*
109	 * Other Size.
110	 */
111	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
112				      false));
113	if (token.value.as_ulong > 0xffffU) {
114		RETTOK(ISC_R_RANGE);
115	}
116	RETERR(uint16_tobuffer(token.value.as_ulong, target));
117
118	/*
119	 * Other Data.
120	 */
121	return (isc_base64_tobuffer(lexer, target, (int)token.value.as_ulong));
122}
123
124static isc_result_t
125totext_tkey(ARGS_TOTEXT) {
126	isc_region_t sr, dr;
127	char buf[sizeof("4294967295 ")];
128	unsigned long n;
129	dns_name_t name;
130	dns_name_t prefix;
131	bool sub;
132
133	REQUIRE(rdata->type == dns_rdatatype_tkey);
134	REQUIRE(rdata->length != 0);
135
136	dns_rdata_toregion(rdata, &sr);
137
138	/*
139	 * Algorithm.
140	 */
141	dns_name_init(&name, NULL);
142	dns_name_init(&prefix, NULL);
143	dns_name_fromregion(&name, &sr);
144	sub = name_prefix(&name, tctx->origin, &prefix);
145	RETERR(dns_name_totext(&prefix, sub, target));
146	RETERR(str_totext(" ", target));
147	isc_region_consume(&sr, name_length(&name));
148
149	/*
150	 * Inception.
151	 */
152	n = uint32_fromregion(&sr);
153	isc_region_consume(&sr, 4);
154	snprintf(buf, sizeof(buf), "%lu ", n);
155	RETERR(str_totext(buf, target));
156
157	/*
158	 * Expiration.
159	 */
160	n = uint32_fromregion(&sr);
161	isc_region_consume(&sr, 4);
162	snprintf(buf, sizeof(buf), "%lu ", n);
163	RETERR(str_totext(buf, target));
164
165	/*
166	 * Mode.
167	 */
168	n = uint16_fromregion(&sr);
169	isc_region_consume(&sr, 2);
170	snprintf(buf, sizeof(buf), "%lu ", n);
171	RETERR(str_totext(buf, target));
172
173	/*
174	 * Error.
175	 */
176	n = uint16_fromregion(&sr);
177	isc_region_consume(&sr, 2);
178	if (dns_tsigrcode_totext((dns_rcode_t)n, target) == ISC_R_SUCCESS) {
179		RETERR(str_totext(" ", target));
180	} else {
181		snprintf(buf, sizeof(buf), "%lu ", n);
182		RETERR(str_totext(buf, target));
183	}
184
185	/*
186	 * Key Size.
187	 */
188	n = uint16_fromregion(&sr);
189	isc_region_consume(&sr, 2);
190	snprintf(buf, sizeof(buf), "%lu", n);
191	RETERR(str_totext(buf, target));
192
193	/*
194	 * Key Data.
195	 */
196	REQUIRE(n <= sr.length);
197	dr = sr;
198	dr.length = n;
199	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
200		RETERR(str_totext(" (", target));
201	}
202	RETERR(str_totext(tctx->linebreak, target));
203	if (tctx->width == 0) { /* No splitting */
204		RETERR(isc_base64_totext(&dr, 60, "", target));
205	} else {
206		RETERR(isc_base64_totext(&dr, tctx->width - 2, tctx->linebreak,
207					 target));
208	}
209	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
210		RETERR(str_totext(" ) ", target));
211	} else {
212		RETERR(str_totext(" ", target));
213	}
214	isc_region_consume(&sr, n);
215
216	/*
217	 * Other Size.
218	 */
219	n = uint16_fromregion(&sr);
220	isc_region_consume(&sr, 2);
221	snprintf(buf, sizeof(buf), "%lu", n);
222	RETERR(str_totext(buf, target));
223
224	/*
225	 * Other Data.
226	 */
227	REQUIRE(n <= sr.length);
228	if (n != 0U) {
229		dr = sr;
230		dr.length = n;
231		if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
232			RETERR(str_totext(" (", target));
233		}
234		RETERR(str_totext(tctx->linebreak, target));
235		if (tctx->width == 0) { /* No splitting */
236			RETERR(isc_base64_totext(&dr, 60, "", target));
237		} else {
238			RETERR(isc_base64_totext(&dr, tctx->width - 2,
239						 tctx->linebreak, target));
240		}
241		if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
242			RETERR(str_totext(" )", target));
243		}
244	}
245	return (ISC_R_SUCCESS);
246}
247
248static isc_result_t
249fromwire_tkey(ARGS_FROMWIRE) {
250	isc_region_t sr;
251	unsigned long n;
252	dns_name_t name;
253
254	REQUIRE(type == dns_rdatatype_tkey);
255
256	UNUSED(type);
257	UNUSED(rdclass);
258
259	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
260
261	/*
262	 * Algorithm.
263	 */
264	dns_name_init(&name, NULL);
265	RETERR(dns_name_fromwire(&name, source, dctx, options, target));
266
267	/*
268	 * Inception: 4
269	 * Expiration: 4
270	 * Mode: 2
271	 * Error: 2
272	 */
273	isc_buffer_activeregion(source, &sr);
274	if (sr.length < 12) {
275		return (ISC_R_UNEXPECTEDEND);
276	}
277	RETERR(mem_tobuffer(target, sr.base, 12));
278	isc_region_consume(&sr, 12);
279	isc_buffer_forward(source, 12);
280
281	/*
282	 * Key Length + Key Data.
283	 */
284	if (sr.length < 2) {
285		return (ISC_R_UNEXPECTEDEND);
286	}
287	n = uint16_fromregion(&sr);
288	if (sr.length < n + 2) {
289		return (ISC_R_UNEXPECTEDEND);
290	}
291	RETERR(mem_tobuffer(target, sr.base, n + 2));
292	isc_region_consume(&sr, n + 2);
293	isc_buffer_forward(source, n + 2);
294
295	/*
296	 * Other Length + Other Data.
297	 */
298	if (sr.length < 2) {
299		return (ISC_R_UNEXPECTEDEND);
300	}
301	n = uint16_fromregion(&sr);
302	if (sr.length < n + 2) {
303		return (ISC_R_UNEXPECTEDEND);
304	}
305	isc_buffer_forward(source, n + 2);
306	return (mem_tobuffer(target, sr.base, n + 2));
307}
308
309static isc_result_t
310towire_tkey(ARGS_TOWIRE) {
311	isc_region_t sr;
312	dns_name_t name;
313	dns_offsets_t offsets;
314
315	REQUIRE(rdata->type == dns_rdatatype_tkey);
316	REQUIRE(rdata->length != 0);
317
318	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
319	/*
320	 * Algorithm.
321	 */
322	dns_rdata_toregion(rdata, &sr);
323	dns_name_init(&name, offsets);
324	dns_name_fromregion(&name, &sr);
325	RETERR(dns_name_towire(&name, cctx, target));
326	isc_region_consume(&sr, name_length(&name));
327
328	return (mem_tobuffer(target, sr.base, sr.length));
329}
330
331static int
332compare_tkey(ARGS_COMPARE) {
333	isc_region_t r1;
334	isc_region_t r2;
335	dns_name_t name1;
336	dns_name_t name2;
337	int order;
338
339	REQUIRE(rdata1->type == rdata2->type);
340	REQUIRE(rdata1->rdclass == rdata2->rdclass);
341	REQUIRE(rdata1->type == dns_rdatatype_tkey);
342	REQUIRE(rdata1->length != 0);
343	REQUIRE(rdata2->length != 0);
344
345	/*
346	 * Algorithm.
347	 */
348	dns_rdata_toregion(rdata1, &r1);
349	dns_rdata_toregion(rdata2, &r2);
350	dns_name_init(&name1, NULL);
351	dns_name_init(&name2, NULL);
352	dns_name_fromregion(&name1, &r1);
353	dns_name_fromregion(&name2, &r2);
354	if ((order = dns_name_rdatacompare(&name1, &name2)) != 0) {
355		return (order);
356	}
357	isc_region_consume(&r1, name_length(&name1));
358	isc_region_consume(&r2, name_length(&name2));
359	return (isc_region_compare(&r1, &r2));
360}
361
362static isc_result_t
363fromstruct_tkey(ARGS_FROMSTRUCT) {
364	dns_rdata_tkey_t *tkey = source;
365
366	REQUIRE(type == dns_rdatatype_tkey);
367	REQUIRE(tkey != NULL);
368	REQUIRE(tkey->common.rdtype == type);
369	REQUIRE(tkey->common.rdclass == rdclass);
370
371	UNUSED(type);
372	UNUSED(rdclass);
373
374	/*
375	 * Algorithm Name.
376	 */
377	RETERR(name_tobuffer(&tkey->algorithm, target));
378
379	/*
380	 * Inception: 32 bits.
381	 */
382	RETERR(uint32_tobuffer(tkey->inception, target));
383
384	/*
385	 * Expire: 32 bits.
386	 */
387	RETERR(uint32_tobuffer(tkey->expire, target));
388
389	/*
390	 * Mode: 16 bits.
391	 */
392	RETERR(uint16_tobuffer(tkey->mode, target));
393
394	/*
395	 * Error: 16 bits.
396	 */
397	RETERR(uint16_tobuffer(tkey->error, target));
398
399	/*
400	 * Key size: 16 bits.
401	 */
402	RETERR(uint16_tobuffer(tkey->keylen, target));
403
404	/*
405	 * Key.
406	 */
407	RETERR(mem_tobuffer(target, tkey->key, tkey->keylen));
408
409	/*
410	 * Other size: 16 bits.
411	 */
412	RETERR(uint16_tobuffer(tkey->otherlen, target));
413
414	/*
415	 * Other data.
416	 */
417	return (mem_tobuffer(target, tkey->other, tkey->otherlen));
418}
419
420static isc_result_t
421tostruct_tkey(ARGS_TOSTRUCT) {
422	dns_rdata_tkey_t *tkey = target;
423	dns_name_t alg;
424	isc_region_t sr;
425
426	REQUIRE(rdata->type == dns_rdatatype_tkey);
427	REQUIRE(tkey != NULL);
428	REQUIRE(rdata->length != 0);
429
430	tkey->common.rdclass = rdata->rdclass;
431	tkey->common.rdtype = rdata->type;
432	ISC_LINK_INIT(&tkey->common, link);
433
434	dns_rdata_toregion(rdata, &sr);
435
436	/*
437	 * Algorithm Name.
438	 */
439	dns_name_init(&alg, NULL);
440	dns_name_fromregion(&alg, &sr);
441	dns_name_init(&tkey->algorithm, NULL);
442	name_duporclone(&alg, mctx, &tkey->algorithm);
443	isc_region_consume(&sr, name_length(&tkey->algorithm));
444
445	/*
446	 * Inception.
447	 */
448	tkey->inception = uint32_fromregion(&sr);
449	isc_region_consume(&sr, 4);
450
451	/*
452	 * Expire.
453	 */
454	tkey->expire = uint32_fromregion(&sr);
455	isc_region_consume(&sr, 4);
456
457	/*
458	 * Mode.
459	 */
460	tkey->mode = uint16_fromregion(&sr);
461	isc_region_consume(&sr, 2);
462
463	/*
464	 * Error.
465	 */
466	tkey->error = uint16_fromregion(&sr);
467	isc_region_consume(&sr, 2);
468
469	/*
470	 * Key size.
471	 */
472	tkey->keylen = uint16_fromregion(&sr);
473	isc_region_consume(&sr, 2);
474
475	/*
476	 * Key.
477	 */
478	INSIST(tkey->keylen + 2U <= sr.length);
479	tkey->key = mem_maybedup(mctx, sr.base, tkey->keylen);
480	if (tkey->key == NULL) {
481		goto cleanup;
482	}
483	isc_region_consume(&sr, tkey->keylen);
484
485	/*
486	 * Other size.
487	 */
488	tkey->otherlen = uint16_fromregion(&sr);
489	isc_region_consume(&sr, 2);
490
491	/*
492	 * Other.
493	 */
494	INSIST(tkey->otherlen <= sr.length);
495	tkey->other = mem_maybedup(mctx, sr.base, tkey->otherlen);
496	if (tkey->other == NULL) {
497		goto cleanup;
498	}
499
500	tkey->mctx = mctx;
501	return (ISC_R_SUCCESS);
502
503cleanup:
504	if (mctx != NULL) {
505		dns_name_free(&tkey->algorithm, mctx);
506	}
507	if (mctx != NULL && tkey->key != NULL) {
508		isc_mem_free(mctx, tkey->key);
509	}
510	return (ISC_R_NOMEMORY);
511}
512
513static void
514freestruct_tkey(ARGS_FREESTRUCT) {
515	dns_rdata_tkey_t *tkey = (dns_rdata_tkey_t *)source;
516
517	REQUIRE(tkey != NULL);
518
519	if (tkey->mctx == NULL) {
520		return;
521	}
522
523	dns_name_free(&tkey->algorithm, tkey->mctx);
524	if (tkey->key != NULL) {
525		isc_mem_free(tkey->mctx, tkey->key);
526	}
527	if (tkey->other != NULL) {
528		isc_mem_free(tkey->mctx, tkey->other);
529	}
530	tkey->mctx = NULL;
531}
532
533static isc_result_t
534additionaldata_tkey(ARGS_ADDLDATA) {
535	REQUIRE(rdata->type == dns_rdatatype_tkey);
536
537	UNUSED(rdata);
538	UNUSED(owner);
539	UNUSED(add);
540	UNUSED(arg);
541
542	return (ISC_R_SUCCESS);
543}
544
545static isc_result_t
546digest_tkey(ARGS_DIGEST) {
547	UNUSED(rdata);
548	UNUSED(digest);
549	UNUSED(arg);
550
551	REQUIRE(rdata->type == dns_rdatatype_tkey);
552
553	return (ISC_R_NOTIMPLEMENTED);
554}
555
556static bool
557checkowner_tkey(ARGS_CHECKOWNER) {
558	REQUIRE(type == dns_rdatatype_tkey);
559
560	UNUSED(name);
561	UNUSED(type);
562	UNUSED(rdclass);
563	UNUSED(wildcard);
564
565	return (true);
566}
567
568static bool
569checknames_tkey(ARGS_CHECKNAMES) {
570	REQUIRE(rdata->type == dns_rdatatype_tkey);
571
572	UNUSED(rdata);
573	UNUSED(owner);
574	UNUSED(bad);
575
576	return (true);
577}
578
579static int
580casecompare_tkey(ARGS_COMPARE) {
581	return (compare_tkey(rdata1, rdata2));
582}
583#endif /* RDATA_GENERIC_TKEY_249_C */
584