1/*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14 * PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef GENERIC_KEYDATA_65533_C
18#define GENERIC_KEYDATA_65533_C 1
19
20#include <time.h>
21
22#include <dst/dst.h>
23
24/*
25 * ISC_FORMATHTTPTIMESTAMP_SIZE needs to be 30 in C locale and potentially
26 * more for other locales to handle longer national abbreviations when
27 * expanding strftime's %a and %b.
28 */
29#define ISC_FORMATHTTPTIMESTAMP_SIZE 50
30
31static void
32isc_time_formathttptimestamp(const struct timespec *t, char *buf, size_t len) {
33	size_t flen;
34	/*
35	 * 5 spaces, 1 comma, 3 GMT, 2 %d, 4 %Y, 8 %H:%M:%S, 3+ %a, 3+ %b (29+)
36	 */
37
38	flen = strftime(buf, len, "%a, %d %b %Y %H:%M:%S GMT",
39	    gmtime(&t->tv_sec));
40	INSIST(flen < len);
41}
42
43static inline isc_result_t
44totext_keydata(ARGS_TOTEXT) {
45	isc_region_t sr;
46	char buf[sizeof("64000")];
47	unsigned int flags;
48	unsigned char algorithm;
49	unsigned long refresh, add, deltime;
50	char algbuf[DNS_NAME_FORMATSIZE];
51	const char *keyinfo;
52
53	REQUIRE(rdata->type == dns_rdatatype_keydata);
54
55	if ((tctx->flags & DNS_STYLEFLAG_KEYDATA) == 0 || rdata->length < 16)
56		return (unknown_totext(rdata, tctx, target));
57
58	dns_rdata_toregion(rdata, &sr);
59
60	/* refresh timer */
61	refresh = uint32_fromregion(&sr);
62	isc_region_consume(&sr, 4);
63	RETERR(dns_time32_totext(refresh, target));
64	RETERR(isc_str_tobuffer(" ", target));
65
66	/* add hold-down */
67	add = uint32_fromregion(&sr);
68	isc_region_consume(&sr, 4);
69	RETERR(dns_time32_totext(add, target));
70	RETERR(isc_str_tobuffer(" ", target));
71
72	/* remove hold-down */
73	deltime = uint32_fromregion(&sr);
74	isc_region_consume(&sr, 4);
75	RETERR(dns_time32_totext(deltime, target));
76	RETERR(isc_str_tobuffer(" ", target));
77
78	/* flags */
79	flags = uint16_fromregion(&sr);
80	isc_region_consume(&sr, 2);
81	snprintf(buf, sizeof(buf), "%u", flags);
82	RETERR(isc_str_tobuffer(buf, target));
83	RETERR(isc_str_tobuffer(" ", target));
84	if ((flags & DNS_KEYFLAG_KSK) != 0) {
85		if (flags & DNS_KEYFLAG_REVOKE)
86			keyinfo = "revoked KSK";
87		else
88			keyinfo = "KSK";
89	} else
90		keyinfo = "ZSK";
91
92	/* protocol */
93	snprintf(buf, sizeof(buf), "%u", sr.base[0]);
94	isc_region_consume(&sr, 1);
95	RETERR(isc_str_tobuffer(buf, target));
96	RETERR(isc_str_tobuffer(" ", target));
97
98	/* algorithm */
99	algorithm = sr.base[0];
100	snprintf(buf, sizeof(buf), "%u", algorithm);
101	isc_region_consume(&sr, 1);
102	RETERR(isc_str_tobuffer(buf, target));
103
104	/* No Key? */
105	if ((flags & 0xc000) == 0xc000)
106		return (ISC_R_SUCCESS);
107
108	/* key */
109	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
110		RETERR(isc_str_tobuffer(" (", target));
111	RETERR(isc_str_tobuffer(tctx->linebreak, target));
112	if (tctx->width == 0)   /* No splitting */
113		RETERR(isc_base64_totext(&sr, 60, "", target));
114	else
115		RETERR(isc_base64_totext(&sr, tctx->width - 2,
116					 tctx->linebreak, target));
117
118	if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0)
119		RETERR(isc_str_tobuffer(tctx->linebreak, target));
120	else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
121		RETERR(isc_str_tobuffer(" ", target));
122
123	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
124		RETERR(isc_str_tobuffer(")", target));
125
126	if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) {
127		isc_region_t tmpr;
128		char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
129		char abuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
130		char dbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
131		struct timespec t;
132
133		RETERR(isc_str_tobuffer(" ; ", target));
134		RETERR(isc_str_tobuffer(keyinfo, target));
135		dns_secalg_format((dns_secalg_t) algorithm, algbuf,
136				  sizeof(algbuf));
137		RETERR(isc_str_tobuffer("; alg = ", target));
138		RETERR(isc_str_tobuffer(algbuf, target));
139		RETERR(isc_str_tobuffer("; key id = ", target));
140		dns_rdata_toregion(rdata, &tmpr);
141		/* Skip over refresh, addhd, and removehd */
142		isc_region_consume(&tmpr, 12);
143		snprintf(buf, sizeof(buf), "%u",
144			 dst_region_computeid(&tmpr, algorithm));
145		RETERR(isc_str_tobuffer(buf, target));
146
147		if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0) {
148			time_t now;
149
150			time(&now);
151
152			RETERR(isc_str_tobuffer(tctx->linebreak, target));
153			RETERR(isc_str_tobuffer("; next refresh: ", target));
154			t.tv_sec = refresh;
155			t.tv_nsec = 0;
156			isc_time_formathttptimestamp(&t, rbuf, sizeof(rbuf));
157			RETERR(isc_str_tobuffer(rbuf, target));
158
159			if (add == 0U) {
160				RETERR(isc_str_tobuffer(tctx->linebreak, target));
161				RETERR(isc_str_tobuffer("; no trust", target));
162			} else {
163				RETERR(isc_str_tobuffer(tctx->linebreak, target));
164				if ((time_t)add < now) {
165					RETERR(isc_str_tobuffer("; trusted since: ",
166							  target));
167				} else {
168					RETERR(isc_str_tobuffer("; trust pending: ",
169							  target));
170				}
171				t.tv_sec = add;
172				t.tv_nsec = 0;
173				isc_time_formathttptimestamp(&t, abuf,
174							     sizeof(abuf));
175				RETERR(isc_str_tobuffer(abuf, target));
176			}
177
178			if (deltime != 0U) {
179				RETERR(isc_str_tobuffer(tctx->linebreak, target));
180				RETERR(isc_str_tobuffer("; removal pending: ",
181						  target));
182				t.tv_sec = deltime;
183				t.tv_nsec = 0;
184				isc_time_formathttptimestamp(&t, dbuf,
185							     sizeof(dbuf));
186				RETERR(isc_str_tobuffer(dbuf, target));
187			}
188		}
189
190	}
191	return (ISC_R_SUCCESS);
192}
193
194static inline isc_result_t
195fromwire_keydata(ARGS_FROMWIRE) {
196	isc_region_t sr;
197
198	REQUIRE(type == dns_rdatatype_keydata);
199
200	UNUSED(type);
201	UNUSED(rdclass);
202	UNUSED(dctx);
203	UNUSED(options);
204
205	isc_buffer_activeregion(source, &sr);
206	isc_buffer_forward(source, sr.length);
207	return (isc_mem_tobuffer(target, sr.base, sr.length));
208}
209
210static inline isc_result_t
211towire_keydata(ARGS_TOWIRE) {
212	isc_region_t sr;
213
214	REQUIRE(rdata->type == dns_rdatatype_keydata);
215
216	UNUSED(cctx);
217
218	dns_rdata_toregion(rdata, &sr);
219	return (isc_mem_tobuffer(target, sr.base, sr.length));
220}
221
222#endif /* GENERIC_KEYDATA_65533_C */
223