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 
31 static void
32 isc_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 
43 static inline isc_result_t
44 totext_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 
194 static inline isc_result_t
195 fromwire_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 
210 static inline isc_result_t
211 towire_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