1/*	$NetBSD: rrsig_46.c,v 1.1 2024/02/18 20:57:44 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_RRSIG_46_C
19#define RDATA_GENERIC_RRSIG_46_C
20
21#define RRTYPE_RRSIG_ATTRIBUTES                                     \
22	(DNS_RDATATYPEATTR_DNSSEC | DNS_RDATATYPEATTR_ZONECUTAUTH | \
23	 DNS_RDATATYPEATTR_ATCNAME)
24
25static isc_result_t
26fromtext_rrsig(ARGS_FROMTEXT) {
27	isc_token_t token;
28	unsigned char c;
29	long i;
30	dns_rdatatype_t covered;
31	char *e;
32	isc_result_t result;
33	dns_name_t name;
34	isc_buffer_t buffer;
35	uint32_t time_signed, time_expire;
36
37	REQUIRE(type == dns_rdatatype_rrsig);
38
39	UNUSED(type);
40	UNUSED(rdclass);
41	UNUSED(callbacks);
42
43	/*
44	 * Type covered.
45	 */
46	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
47				      false));
48	result = dns_rdatatype_fromtext(&covered, &token.value.as_textregion);
49	if (result != ISC_R_SUCCESS && result != ISC_R_NOTIMPLEMENTED) {
50		i = strtol(DNS_AS_STR(token), &e, 10);
51		if (i < 0 || i > 65535) {
52			RETTOK(ISC_R_RANGE);
53		}
54		if (*e != 0) {
55			RETTOK(result);
56		}
57		covered = (dns_rdatatype_t)i;
58	}
59	RETERR(uint16_tobuffer(covered, target));
60
61	/*
62	 * Algorithm.
63	 */
64	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
65				      false));
66	RETTOK(dns_secalg_fromtext(&c, &token.value.as_textregion));
67	RETERR(mem_tobuffer(target, &c, 1));
68
69	/*
70	 * Labels.
71	 */
72	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
73				      false));
74	if (token.value.as_ulong > 0xffU) {
75		RETTOK(ISC_R_RANGE);
76	}
77	c = (unsigned char)token.value.as_ulong;
78	RETERR(mem_tobuffer(target, &c, 1));
79
80	/*
81	 * Original ttl.
82	 */
83	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
84				      false));
85	RETERR(uint32_tobuffer(token.value.as_ulong, target));
86
87	/*
88	 * Signature expiration.
89	 */
90	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
91				      false));
92	if (strlen(DNS_AS_STR(token)) <= 10U && *DNS_AS_STR(token) != '-' &&
93	    *DNS_AS_STR(token) != '+')
94	{
95		char *end;
96		unsigned long u;
97		uint64_t u64;
98
99		u64 = u = strtoul(DNS_AS_STR(token), &end, 10);
100		if (u == ULONG_MAX || *end != 0) {
101			RETTOK(DNS_R_SYNTAX);
102		}
103		if (u64 > 0xffffffffUL) {
104			RETTOK(ISC_R_RANGE);
105		}
106		time_expire = u;
107	} else {
108		RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_expire));
109	}
110	RETERR(uint32_tobuffer(time_expire, target));
111
112	/*
113	 * Time signed.
114	 */
115	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
116				      false));
117	if (strlen(DNS_AS_STR(token)) <= 10U && *DNS_AS_STR(token) != '-' &&
118	    *DNS_AS_STR(token) != '+')
119	{
120		char *end;
121		unsigned long u;
122		uint64_t u64;
123
124		u64 = u = strtoul(DNS_AS_STR(token), &end, 10);
125		if (u == ULONG_MAX || *end != 0) {
126			RETTOK(DNS_R_SYNTAX);
127		}
128		if (u64 > 0xffffffffUL) {
129			RETTOK(ISC_R_RANGE);
130		}
131		time_signed = u;
132	} else {
133		RETTOK(dns_time32_fromtext(DNS_AS_STR(token), &time_signed));
134	}
135	RETERR(uint32_tobuffer(time_signed, target));
136
137	/*
138	 * Key footprint.
139	 */
140	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_number,
141				      false));
142	RETERR(uint16_tobuffer(token.value.as_ulong, target));
143
144	/*
145	 * Signer.
146	 */
147	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
148				      false));
149	dns_name_init(&name, NULL);
150	buffer_fromregion(&buffer, &token.value.as_region);
151	if (origin == NULL) {
152		origin = dns_rootname;
153	}
154	RETTOK(dns_name_fromtext(&name, &buffer, origin, options, target));
155
156	/*
157	 * Sig.
158	 */
159	return (isc_base64_tobuffer(lexer, target, -2));
160}
161
162static isc_result_t
163totext_rrsig(ARGS_TOTEXT) {
164	isc_region_t sr;
165	char buf[sizeof("4294967295")]; /* Also TYPE65000. */
166	dns_rdatatype_t covered;
167	unsigned long ttl;
168	unsigned long when;
169	unsigned long exp;
170	unsigned long foot;
171	dns_name_t name;
172
173	REQUIRE(rdata->type == dns_rdatatype_rrsig);
174	REQUIRE(rdata->length != 0);
175
176	dns_rdata_toregion(rdata, &sr);
177
178	/*
179	 * Type covered.
180	 */
181	covered = uint16_fromregion(&sr);
182	isc_region_consume(&sr, 2);
183	/*
184	 * XXXAG We should have something like dns_rdatatype_isknown()
185	 * that does the right thing with type 0.
186	 */
187	if (dns_rdatatype_isknown(covered) && covered != 0) {
188		RETERR(dns_rdatatype_totext(covered, target));
189	} else {
190		snprintf(buf, sizeof(buf), "TYPE%u", covered);
191		RETERR(str_totext(buf, target));
192	}
193	RETERR(str_totext(" ", target));
194
195	/*
196	 * Algorithm.
197	 */
198	snprintf(buf, sizeof(buf), "%u", sr.base[0]);
199	isc_region_consume(&sr, 1);
200	RETERR(str_totext(buf, target));
201	RETERR(str_totext(" ", target));
202
203	/*
204	 * Labels.
205	 */
206	snprintf(buf, sizeof(buf), "%u", sr.base[0]);
207	isc_region_consume(&sr, 1);
208	RETERR(str_totext(buf, target));
209	RETERR(str_totext(" ", target));
210
211	/*
212	 * Ttl.
213	 */
214	ttl = uint32_fromregion(&sr);
215	isc_region_consume(&sr, 4);
216	snprintf(buf, sizeof(buf), "%lu", ttl);
217	RETERR(str_totext(buf, target));
218
219	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
220		RETERR(str_totext(" (", target));
221	}
222	RETERR(str_totext(tctx->linebreak, target));
223
224	/*
225	 * Sig exp.
226	 */
227	exp = uint32_fromregion(&sr);
228	isc_region_consume(&sr, 4);
229	RETERR(dns_time32_totext(exp, target));
230	RETERR(str_totext(" ", target));
231
232	/*
233	 * Time signed.
234	 */
235	when = uint32_fromregion(&sr);
236	isc_region_consume(&sr, 4);
237	RETERR(dns_time32_totext(when, target));
238	RETERR(str_totext(" ", target));
239
240	/*
241	 * Footprint.
242	 */
243	foot = uint16_fromregion(&sr);
244	isc_region_consume(&sr, 2);
245	snprintf(buf, sizeof(buf), "%lu", foot);
246	RETERR(str_totext(buf, target));
247	RETERR(str_totext(" ", target));
248
249	/*
250	 * Signer.
251	 */
252	dns_name_init(&name, NULL);
253	dns_name_fromregion(&name, &sr);
254	isc_region_consume(&sr, name_length(&name));
255	RETERR(dns_name_totext(&name, false, target));
256
257	/*
258	 * Sig.
259	 */
260	RETERR(str_totext(tctx->linebreak, target));
261	if ((tctx->flags & DNS_STYLEFLAG_NOCRYPTO) == 0) {
262		if (tctx->width == 0) { /* No splitting */
263			RETERR(isc_base64_totext(&sr, 60, "", target));
264		} else {
265			RETERR(isc_base64_totext(&sr, tctx->width - 2,
266						 tctx->linebreak, target));
267		}
268	} else {
269		RETERR(str_totext("[omitted]", target));
270	}
271
272	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
273		RETERR(str_totext(" )", target));
274	}
275
276	return (ISC_R_SUCCESS);
277}
278
279static isc_result_t
280fromwire_rrsig(ARGS_FROMWIRE) {
281	isc_region_t sr;
282	dns_name_t name;
283
284	REQUIRE(type == dns_rdatatype_rrsig);
285
286	UNUSED(type);
287	UNUSED(rdclass);
288
289	dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
290
291	isc_buffer_activeregion(source, &sr);
292	/*
293	 * type covered: 2
294	 * algorithm: 1
295	 * labels: 1
296	 * original ttl: 4
297	 * signature expiration: 4
298	 * time signed: 4
299	 * key footprint: 2
300	 */
301	if (sr.length < 18) {
302		return (ISC_R_UNEXPECTEDEND);
303	}
304
305	isc_buffer_forward(source, 18);
306	RETERR(mem_tobuffer(target, sr.base, 18));
307
308	/*
309	 * Signer.
310	 */
311	dns_name_init(&name, NULL);
312	RETERR(dns_name_fromwire(&name, source, dctx, options, target));
313
314	/*
315	 * Sig.
316	 */
317	isc_buffer_activeregion(source, &sr);
318	if (sr.length < 1) {
319		return (DNS_R_FORMERR);
320	}
321	isc_buffer_forward(source, sr.length);
322	return (mem_tobuffer(target, sr.base, sr.length));
323}
324
325static isc_result_t
326towire_rrsig(ARGS_TOWIRE) {
327	isc_region_t sr;
328	dns_name_t name;
329	dns_offsets_t offsets;
330
331	REQUIRE(rdata->type == dns_rdatatype_rrsig);
332	REQUIRE(rdata->length != 0);
333
334	dns_compress_setmethods(cctx, DNS_COMPRESS_NONE);
335	dns_rdata_toregion(rdata, &sr);
336	/*
337	 * type covered: 2
338	 * algorithm: 1
339	 * labels: 1
340	 * original ttl: 4
341	 * signature expiration: 4
342	 * time signed: 4
343	 * key footprint: 2
344	 */
345	RETERR(mem_tobuffer(target, sr.base, 18));
346	isc_region_consume(&sr, 18);
347
348	/*
349	 * Signer.
350	 */
351	dns_name_init(&name, offsets);
352	dns_name_fromregion(&name, &sr);
353	isc_region_consume(&sr, name_length(&name));
354	RETERR(dns_name_towire(&name, cctx, target));
355
356	/*
357	 * Signature.
358	 */
359	return (mem_tobuffer(target, sr.base, sr.length));
360}
361
362static int
363compare_rrsig(ARGS_COMPARE) {
364	isc_region_t r1;
365	isc_region_t r2;
366
367	REQUIRE(rdata1->type == rdata2->type);
368	REQUIRE(rdata1->rdclass == rdata2->rdclass);
369	REQUIRE(rdata1->type == dns_rdatatype_rrsig);
370	REQUIRE(rdata1->length != 0);
371	REQUIRE(rdata2->length != 0);
372
373	dns_rdata_toregion(rdata1, &r1);
374	dns_rdata_toregion(rdata2, &r2);
375	return (isc_region_compare(&r1, &r2));
376}
377
378static isc_result_t
379fromstruct_rrsig(ARGS_FROMSTRUCT) {
380	dns_rdata_rrsig_t *sig = source;
381
382	REQUIRE(type == dns_rdatatype_rrsig);
383	REQUIRE(sig != NULL);
384	REQUIRE(sig->common.rdtype == type);
385	REQUIRE(sig->common.rdclass == rdclass);
386	REQUIRE(sig->signature != NULL || sig->siglen == 0);
387
388	UNUSED(type);
389	UNUSED(rdclass);
390
391	/*
392	 * Type covered.
393	 */
394	RETERR(uint16_tobuffer(sig->covered, target));
395
396	/*
397	 * Algorithm.
398	 */
399	RETERR(uint8_tobuffer(sig->algorithm, target));
400
401	/*
402	 * Labels.
403	 */
404	RETERR(uint8_tobuffer(sig->labels, target));
405
406	/*
407	 * Original TTL.
408	 */
409	RETERR(uint32_tobuffer(sig->originalttl, target));
410
411	/*
412	 * Expire time.
413	 */
414	RETERR(uint32_tobuffer(sig->timeexpire, target));
415
416	/*
417	 * Time signed.
418	 */
419	RETERR(uint32_tobuffer(sig->timesigned, target));
420
421	/*
422	 * Key ID.
423	 */
424	RETERR(uint16_tobuffer(sig->keyid, target));
425
426	/*
427	 * Signer name.
428	 */
429	RETERR(name_tobuffer(&sig->signer, target));
430
431	/*
432	 * Signature.
433	 */
434	return (mem_tobuffer(target, sig->signature, sig->siglen));
435}
436
437static isc_result_t
438tostruct_rrsig(ARGS_TOSTRUCT) {
439	isc_region_t sr;
440	dns_rdata_rrsig_t *sig = target;
441	dns_name_t signer;
442
443	REQUIRE(rdata->type == dns_rdatatype_rrsig);
444	REQUIRE(sig != NULL);
445	REQUIRE(rdata->length != 0);
446
447	sig->common.rdclass = rdata->rdclass;
448	sig->common.rdtype = rdata->type;
449	ISC_LINK_INIT(&sig->common, link);
450
451	dns_rdata_toregion(rdata, &sr);
452
453	/*
454	 * Type covered.
455	 */
456	sig->covered = uint16_fromregion(&sr);
457	isc_region_consume(&sr, 2);
458
459	/*
460	 * Algorithm.
461	 */
462	sig->algorithm = uint8_fromregion(&sr);
463	isc_region_consume(&sr, 1);
464
465	/*
466	 * Labels.
467	 */
468	sig->labels = uint8_fromregion(&sr);
469	isc_region_consume(&sr, 1);
470
471	/*
472	 * Original TTL.
473	 */
474	sig->originalttl = uint32_fromregion(&sr);
475	isc_region_consume(&sr, 4);
476
477	/*
478	 * Expire time.
479	 */
480	sig->timeexpire = uint32_fromregion(&sr);
481	isc_region_consume(&sr, 4);
482
483	/*
484	 * Time signed.
485	 */
486	sig->timesigned = uint32_fromregion(&sr);
487	isc_region_consume(&sr, 4);
488
489	/*
490	 * Key ID.
491	 */
492	sig->keyid = uint16_fromregion(&sr);
493	isc_region_consume(&sr, 2);
494
495	dns_name_init(&signer, NULL);
496	dns_name_fromregion(&signer, &sr);
497	dns_name_init(&sig->signer, NULL);
498	RETERR(name_duporclone(&signer, mctx, &sig->signer));
499	isc_region_consume(&sr, name_length(&sig->signer));
500
501	/*
502	 * Signature.
503	 */
504	sig->siglen = sr.length;
505	sig->signature = mem_maybedup(mctx, sr.base, sig->siglen);
506	if (sig->signature == NULL) {
507		goto cleanup;
508	}
509
510	sig->mctx = mctx;
511	return (ISC_R_SUCCESS);
512
513cleanup:
514	if (mctx != NULL) {
515		dns_name_free(&sig->signer, mctx);
516	}
517	return (ISC_R_NOMEMORY);
518}
519
520static void
521freestruct_rrsig(ARGS_FREESTRUCT) {
522	dns_rdata_rrsig_t *sig = (dns_rdata_rrsig_t *)source;
523
524	REQUIRE(sig != NULL);
525	REQUIRE(sig->common.rdtype == dns_rdatatype_rrsig);
526
527	if (sig->mctx == NULL) {
528		return;
529	}
530
531	dns_name_free(&sig->signer, sig->mctx);
532	if (sig->signature != NULL) {
533		isc_mem_free(sig->mctx, sig->signature);
534	}
535	sig->mctx = NULL;
536}
537
538static isc_result_t
539additionaldata_rrsig(ARGS_ADDLDATA) {
540	REQUIRE(rdata->type == dns_rdatatype_rrsig);
541
542	UNUSED(rdata);
543	UNUSED(add);
544	UNUSED(arg);
545
546	return (ISC_R_SUCCESS);
547}
548
549static isc_result_t
550digest_rrsig(ARGS_DIGEST) {
551	REQUIRE(rdata->type == dns_rdatatype_rrsig);
552
553	UNUSED(rdata);
554	UNUSED(digest);
555	UNUSED(arg);
556
557	return (ISC_R_NOTIMPLEMENTED);
558}
559
560static dns_rdatatype_t
561covers_rrsig(dns_rdata_t *rdata) {
562	dns_rdatatype_t type;
563	isc_region_t r;
564
565	REQUIRE(rdata->type == dns_rdatatype_rrsig);
566
567	dns_rdata_toregion(rdata, &r);
568	type = uint16_fromregion(&r);
569
570	return (type);
571}
572
573static bool
574checkowner_rrsig(ARGS_CHECKOWNER) {
575	REQUIRE(type == dns_rdatatype_rrsig);
576
577	UNUSED(name);
578	UNUSED(type);
579	UNUSED(rdclass);
580	UNUSED(wildcard);
581
582	return (true);
583}
584
585static bool
586checknames_rrsig(ARGS_CHECKNAMES) {
587	REQUIRE(rdata->type == dns_rdatatype_rrsig);
588
589	UNUSED(rdata);
590	UNUSED(owner);
591	UNUSED(bad);
592
593	return (true);
594}
595
596static int
597casecompare_rrsig(ARGS_COMPARE) {
598	isc_region_t r1;
599	isc_region_t r2;
600	dns_name_t name1;
601	dns_name_t name2;
602	int order;
603
604	REQUIRE(rdata1->type == rdata2->type);
605	REQUIRE(rdata1->rdclass == rdata2->rdclass);
606	REQUIRE(rdata1->type == dns_rdatatype_rrsig);
607	REQUIRE(rdata1->length != 0);
608	REQUIRE(rdata2->length != 0);
609
610	dns_rdata_toregion(rdata1, &r1);
611	dns_rdata_toregion(rdata2, &r2);
612
613	INSIST(r1.length > 18);
614	INSIST(r2.length > 18);
615	r1.length = 18;
616	r2.length = 18;
617	order = isc_region_compare(&r1, &r2);
618	if (order != 0) {
619		return (order);
620	}
621
622	dns_name_init(&name1, NULL);
623	dns_name_init(&name2, NULL);
624	dns_rdata_toregion(rdata1, &r1);
625	dns_rdata_toregion(rdata2, &r2);
626	isc_region_consume(&r1, 18);
627	isc_region_consume(&r2, 18);
628	dns_name_fromregion(&name1, &r1);
629	dns_name_fromregion(&name2, &r2);
630	order = dns_name_rdatacompare(&name1, &name2);
631	if (order != 0) {
632		return (order);
633	}
634
635	isc_region_consume(&r1, name_length(&name1));
636	isc_region_consume(&r2, name_length(&name2));
637
638	return (isc_region_compare(&r1, &r2));
639}
640
641#endif /* RDATA_GENERIC_RRSIG_46_C */
642