1135446Strhodes/*
2262706Serwin * Copyright (C) 2004, 2005, 2007, 2009, 2011-2013  Internet Systems Consortium, Inc. ("ISC")
3135446Strhodes * Copyright (C) 2003  Internet Software Consortium.
4135446Strhodes *
5193149Sdougb * Permission to use, copy, modify, and/or distribute this software for any
6135446Strhodes * purpose with or without fee is hereby granted, provided that the above
7135446Strhodes * copyright notice and this permission notice appear in all copies.
8135446Strhodes *
9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11135446Strhodes * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15135446Strhodes * PERFORMANCE OF THIS SOFTWARE.
16135446Strhodes */
17135446Strhodes
18234010Sdougb/* $Id$ */
19135446Strhodes
20135446Strhodes/*
21135446Strhodes * Reviewed: Wed Mar 15 16:47:10 PST 2000 by halley.
22135446Strhodes */
23135446Strhodes
24170222Sdougb/* RFC2535 */
25135446Strhodes
26135446Strhodes#ifndef RDATA_GENERIC_DNSKEY_48_C
27135446Strhodes#define RDATA_GENERIC_DNSKEY_48_C
28135446Strhodes
29135446Strhodes#include <dst/dst.h>
30135446Strhodes
31135446Strhodes#define RRTYPE_DNSKEY_ATTRIBUTES (DNS_RDATATYPEATTR_DNSSEC)
32135446Strhodes
33135446Strhodesstatic inline isc_result_t
34135446Strhodesfromtext_dnskey(ARGS_FROMTEXT) {
35262706Serwin	isc_result_t result;
36135446Strhodes	isc_token_t token;
37135446Strhodes	dns_secalg_t alg;
38135446Strhodes	dns_secproto_t proto;
39135446Strhodes	dns_keyflags_t flags;
40135446Strhodes
41135446Strhodes	REQUIRE(type == 48);
42135446Strhodes
43135446Strhodes	UNUSED(type);
44135446Strhodes	UNUSED(rdclass);
45135446Strhodes	UNUSED(origin);
46135446Strhodes	UNUSED(options);
47135446Strhodes	UNUSED(callbacks);
48135446Strhodes
49135446Strhodes	/* flags */
50135446Strhodes	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
51135446Strhodes				      ISC_FALSE));
52135446Strhodes	RETTOK(dns_keyflags_fromtext(&flags, &token.value.as_textregion));
53135446Strhodes	RETERR(uint16_tobuffer(flags, target));
54135446Strhodes
55135446Strhodes	/* protocol */
56135446Strhodes	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
57135446Strhodes				      ISC_FALSE));
58135446Strhodes	RETTOK(dns_secproto_fromtext(&proto, &token.value.as_textregion));
59135446Strhodes	RETERR(mem_tobuffer(target, &proto, 1));
60135446Strhodes
61135446Strhodes	/* algorithm */
62135446Strhodes	RETERR(isc_lex_getmastertoken(lexer, &token, isc_tokentype_string,
63135446Strhodes				      ISC_FALSE));
64135446Strhodes	RETTOK(dns_secalg_fromtext(&alg, &token.value.as_textregion));
65135446Strhodes	RETERR(mem_tobuffer(target, &alg, 1));
66135446Strhodes
67135446Strhodes	/* No Key? */
68135446Strhodes	if ((flags & 0xc000) == 0xc000)
69135446Strhodes		return (ISC_R_SUCCESS);
70135446Strhodes
71262706Serwin	result = isc_base64_tobuffer(lexer, target, -1);
72262706Serwin	if (result != ISC_R_SUCCESS)
73262706Serwin		return (result);
74262706Serwin
75262706Serwin	/* Ensure there's at least enough data to compute a key ID for MD5 */
76262706Serwin	if (alg == DST_ALG_RSAMD5 && isc_buffer_usedlength(target) < 7)
77262706Serwin		return (ISC_R_UNEXPECTEDEND);
78262706Serwin
79262706Serwin	return (ISC_R_SUCCESS);
80135446Strhodes}
81135446Strhodes
82135446Strhodesstatic inline isc_result_t
83135446Strhodestotext_dnskey(ARGS_TOTEXT) {
84135446Strhodes	isc_region_t sr;
85135446Strhodes	char buf[sizeof("64000")];
86135446Strhodes	unsigned int flags;
87135446Strhodes	unsigned char algorithm;
88254897Serwin	char algbuf[DNS_NAME_FORMATSIZE];
89254897Serwin	const char *keyinfo;
90135446Strhodes
91135446Strhodes	REQUIRE(rdata->type == 48);
92135446Strhodes	REQUIRE(rdata->length != 0);
93135446Strhodes
94135446Strhodes	dns_rdata_toregion(rdata, &sr);
95135446Strhodes
96135446Strhodes	/* flags */
97135446Strhodes	flags = uint16_fromregion(&sr);
98135446Strhodes	isc_region_consume(&sr, 2);
99135446Strhodes	sprintf(buf, "%u", flags);
100135446Strhodes	RETERR(str_totext(buf, target));
101135446Strhodes	RETERR(str_totext(" ", target));
102254897Serwin	if ((flags & DNS_KEYFLAG_KSK) != 0) {
103254897Serwin		if (flags & DNS_KEYFLAG_REVOKE)
104254897Serwin			keyinfo = "revoked KSK";
105254897Serwin		else
106254897Serwin			keyinfo = "KSK";
107254897Serwin	} else
108254897Serwin		keyinfo = "ZSK";
109135446Strhodes
110135446Strhodes	/* protocol */
111135446Strhodes	sprintf(buf, "%u", sr.base[0]);
112135446Strhodes	isc_region_consume(&sr, 1);
113135446Strhodes	RETERR(str_totext(buf, target));
114135446Strhodes	RETERR(str_totext(" ", target));
115135446Strhodes
116135446Strhodes	/* algorithm */
117135446Strhodes	algorithm = sr.base[0];
118135446Strhodes	sprintf(buf, "%u", algorithm);
119135446Strhodes	isc_region_consume(&sr, 1);
120135446Strhodes	RETERR(str_totext(buf, target));
121135446Strhodes
122135446Strhodes	/* No Key? */
123135446Strhodes	if ((flags & 0xc000) == 0xc000)
124135446Strhodes		return (ISC_R_SUCCESS);
125135446Strhodes
126254897Serwin	if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0 &&
127224092Sdougb	     algorithm == DNS_KEYALG_PRIVATEDNS) {
128224092Sdougb		dns_name_t name;
129224092Sdougb		dns_name_init(&name, NULL);
130224092Sdougb		dns_name_fromregion(&name, &sr);
131254897Serwin		dns_name_format(&name, algbuf, sizeof(algbuf));
132254897Serwin	} else {
133254897Serwin		dns_secalg_format((dns_secalg_t) algorithm, algbuf,
134254897Serwin				  sizeof(algbuf));
135254897Serwin	}
136224092Sdougb
137135446Strhodes	/* key */
138135446Strhodes	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
139135446Strhodes		RETERR(str_totext(" (", target));
140135446Strhodes	RETERR(str_totext(tctx->linebreak, target));
141254897Serwin	if (tctx->width == 0)   /* No splitting */
142254897Serwin		RETERR(isc_base64_totext(&sr, 0, "", target));
143254897Serwin	else
144254897Serwin		RETERR(isc_base64_totext(&sr, tctx->width - 2,
145254897Serwin					 tctx->linebreak, target));
146135446Strhodes
147254897Serwin	if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0)
148135446Strhodes		RETERR(str_totext(tctx->linebreak, target));
149135446Strhodes	else if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
150135446Strhodes		RETERR(str_totext(" ", target));
151135446Strhodes
152135446Strhodes	if ((tctx->flags & DNS_STYLEFLAG_MULTILINE) != 0)
153135446Strhodes		RETERR(str_totext(")", target));
154135446Strhodes
155254897Serwin	if ((tctx->flags & DNS_STYLEFLAG_RRCOMMENT) != 0) {
156135446Strhodes		isc_region_t tmpr;
157135446Strhodes
158254897Serwin		RETERR(str_totext(" ; ", target));
159254897Serwin		RETERR(str_totext(keyinfo, target));
160254897Serwin		RETERR(str_totext("; alg = ", target));
161254897Serwin		RETERR(str_totext(algbuf, target));
162254897Serwin		RETERR(str_totext("; key id = ", target));
163135446Strhodes		dns_rdata_toregion(rdata, &tmpr);
164135446Strhodes		sprintf(buf, "%u", dst_region_computeid(&tmpr, algorithm));
165135446Strhodes		RETERR(str_totext(buf, target));
166135446Strhodes	}
167135446Strhodes	return (ISC_R_SUCCESS);
168135446Strhodes}
169135446Strhodes
170135446Strhodesstatic inline isc_result_t
171135446Strhodesfromwire_dnskey(ARGS_FROMWIRE) {
172224092Sdougb	unsigned char algorithm;
173135446Strhodes	isc_region_t sr;
174135446Strhodes
175135446Strhodes	REQUIRE(type == 48);
176135446Strhodes
177135446Strhodes	UNUSED(type);
178135446Strhodes	UNUSED(rdclass);
179135446Strhodes	UNUSED(dctx);
180135446Strhodes	UNUSED(options);
181135446Strhodes
182135446Strhodes	isc_buffer_activeregion(source, &sr);
183135446Strhodes	if (sr.length < 4)
184135446Strhodes		return (ISC_R_UNEXPECTEDEND);
185135446Strhodes
186224092Sdougb	algorithm = sr.base[3];
187224092Sdougb	RETERR(mem_tobuffer(target, sr.base, 4));
188224092Sdougb	isc_region_consume(&sr, 4);
189224092Sdougb	isc_buffer_forward(source, 4);
190224092Sdougb
191224092Sdougb	if (algorithm == DNS_KEYALG_PRIVATEDNS) {
192224092Sdougb		dns_name_t name;
193224092Sdougb		dns_decompress_setmethods(dctx, DNS_COMPRESS_NONE);
194224092Sdougb		dns_name_init(&name, NULL);
195224092Sdougb		RETERR(dns_name_fromwire(&name, source, dctx, options, target));
196224092Sdougb	}
197262706Serwin
198262706Serwin	/*
199262706Serwin	 * RSAMD5 computes key ID differently from other
200262706Serwin	 * algorithms: we need to ensure there's enough data
201262706Serwin	 * present for the computation
202262706Serwin	 */
203262706Serwin	if (algorithm == DST_ALG_RSAMD5 && sr.length < 3)
204262706Serwin		return (ISC_R_UNEXPECTEDEND);
205262706Serwin
206224092Sdougb	isc_buffer_activeregion(source, &sr);
207135446Strhodes	isc_buffer_forward(source, sr.length);
208135446Strhodes	return (mem_tobuffer(target, sr.base, sr.length));
209135446Strhodes}
210135446Strhodes
211135446Strhodesstatic inline isc_result_t
212135446Strhodestowire_dnskey(ARGS_TOWIRE) {
213135446Strhodes	isc_region_t sr;
214135446Strhodes
215135446Strhodes	REQUIRE(rdata->type == 48);
216135446Strhodes	REQUIRE(rdata->length != 0);
217135446Strhodes
218135446Strhodes	UNUSED(cctx);
219135446Strhodes
220135446Strhodes	dns_rdata_toregion(rdata, &sr);
221135446Strhodes	return (mem_tobuffer(target, sr.base, sr.length));
222135446Strhodes}
223135446Strhodes
224135446Strhodesstatic inline int
225135446Strhodescompare_dnskey(ARGS_COMPARE) {
226135446Strhodes	isc_region_t r1;
227135446Strhodes	isc_region_t r2;
228135446Strhodes
229135446Strhodes	REQUIRE(rdata1->type == rdata2->type);
230135446Strhodes	REQUIRE(rdata1->rdclass == rdata2->rdclass);
231135446Strhodes	REQUIRE(rdata1->type == 48);
232135446Strhodes	REQUIRE(rdata1->length != 0);
233135446Strhodes	REQUIRE(rdata2->length != 0);
234135446Strhodes
235135446Strhodes	dns_rdata_toregion(rdata1, &r1);
236135446Strhodes	dns_rdata_toregion(rdata2, &r2);
237135446Strhodes	return (isc_region_compare(&r1, &r2));
238135446Strhodes}
239135446Strhodes
240135446Strhodesstatic inline isc_result_t
241135446Strhodesfromstruct_dnskey(ARGS_FROMSTRUCT) {
242135446Strhodes	dns_rdata_dnskey_t *dnskey = source;
243135446Strhodes
244135446Strhodes	REQUIRE(type == 48);
245135446Strhodes	REQUIRE(source != NULL);
246135446Strhodes	REQUIRE(dnskey->common.rdtype == type);
247135446Strhodes	REQUIRE(dnskey->common.rdclass == rdclass);
248135446Strhodes
249135446Strhodes	UNUSED(type);
250135446Strhodes	UNUSED(rdclass);
251135446Strhodes
252135446Strhodes	/* Flags */
253135446Strhodes	RETERR(uint16_tobuffer(dnskey->flags, target));
254135446Strhodes
255135446Strhodes	/* Protocol */
256135446Strhodes	RETERR(uint8_tobuffer(dnskey->protocol, target));
257135446Strhodes
258135446Strhodes	/* Algorithm */
259135446Strhodes	RETERR(uint8_tobuffer(dnskey->algorithm, target));
260135446Strhodes
261135446Strhodes	/* Data */
262135446Strhodes	return (mem_tobuffer(target, dnskey->data, dnskey->datalen));
263135446Strhodes}
264135446Strhodes
265135446Strhodesstatic inline isc_result_t
266135446Strhodestostruct_dnskey(ARGS_TOSTRUCT) {
267135446Strhodes	dns_rdata_dnskey_t *dnskey = target;
268135446Strhodes	isc_region_t sr;
269135446Strhodes
270135446Strhodes	REQUIRE(rdata->type == 48);
271135446Strhodes	REQUIRE(target != NULL);
272135446Strhodes	REQUIRE(rdata->length != 0);
273135446Strhodes
274135446Strhodes	dnskey->common.rdclass = rdata->rdclass;
275135446Strhodes	dnskey->common.rdtype = rdata->type;
276135446Strhodes	ISC_LINK_INIT(&dnskey->common, link);
277135446Strhodes
278135446Strhodes	dns_rdata_toregion(rdata, &sr);
279135446Strhodes
280135446Strhodes	/* Flags */
281135446Strhodes	if (sr.length < 2)
282135446Strhodes		return (ISC_R_UNEXPECTEDEND);
283135446Strhodes	dnskey->flags = uint16_fromregion(&sr);
284135446Strhodes	isc_region_consume(&sr, 2);
285135446Strhodes
286135446Strhodes	/* Protocol */
287135446Strhodes	if (sr.length < 1)
288135446Strhodes		return (ISC_R_UNEXPECTEDEND);
289135446Strhodes	dnskey->protocol = uint8_fromregion(&sr);
290135446Strhodes	isc_region_consume(&sr, 1);
291135446Strhodes
292135446Strhodes	/* Algorithm */
293135446Strhodes	if (sr.length < 1)
294135446Strhodes		return (ISC_R_UNEXPECTEDEND);
295135446Strhodes	dnskey->algorithm = uint8_fromregion(&sr);
296135446Strhodes	isc_region_consume(&sr, 1);
297135446Strhodes
298135446Strhodes	/* Data */
299135446Strhodes	dnskey->datalen = sr.length;
300135446Strhodes	dnskey->data = mem_maybedup(mctx, sr.base, dnskey->datalen);
301135446Strhodes	if (dnskey->data == NULL)
302135446Strhodes		return (ISC_R_NOMEMORY);
303135446Strhodes
304135446Strhodes	dnskey->mctx = mctx;
305135446Strhodes	return (ISC_R_SUCCESS);
306135446Strhodes}
307135446Strhodes
308135446Strhodesstatic inline void
309135446Strhodesfreestruct_dnskey(ARGS_FREESTRUCT) {
310135446Strhodes	dns_rdata_dnskey_t *dnskey = (dns_rdata_dnskey_t *) source;
311135446Strhodes
312135446Strhodes	REQUIRE(source != NULL);
313135446Strhodes	REQUIRE(dnskey->common.rdtype == 48);
314135446Strhodes
315135446Strhodes	if (dnskey->mctx == NULL)
316135446Strhodes		return;
317135446Strhodes
318135446Strhodes	if (dnskey->data != NULL)
319135446Strhodes		isc_mem_free(dnskey->mctx, dnskey->data);
320135446Strhodes	dnskey->mctx = NULL;
321135446Strhodes}
322135446Strhodes
323135446Strhodesstatic inline isc_result_t
324135446Strhodesadditionaldata_dnskey(ARGS_ADDLDATA) {
325135446Strhodes	REQUIRE(rdata->type == 48);
326135446Strhodes
327135446Strhodes	UNUSED(rdata);
328135446Strhodes	UNUSED(add);
329135446Strhodes	UNUSED(arg);
330135446Strhodes
331135446Strhodes	return (ISC_R_SUCCESS);
332135446Strhodes}
333135446Strhodes
334135446Strhodesstatic inline isc_result_t
335135446Strhodesdigest_dnskey(ARGS_DIGEST) {
336135446Strhodes	isc_region_t r;
337135446Strhodes
338135446Strhodes	REQUIRE(rdata->type == 48);
339135446Strhodes
340135446Strhodes	dns_rdata_toregion(rdata, &r);
341135446Strhodes
342135446Strhodes	return ((digest)(arg, &r));
343135446Strhodes}
344135446Strhodes
345135446Strhodesstatic inline isc_boolean_t
346135446Strhodescheckowner_dnskey(ARGS_CHECKOWNER) {
347135446Strhodes
348135446Strhodes	REQUIRE(type == 48);
349135446Strhodes
350135446Strhodes	UNUSED(name);
351135446Strhodes	UNUSED(type);
352135446Strhodes	UNUSED(rdclass);
353135446Strhodes	UNUSED(wildcard);
354135446Strhodes
355135446Strhodes	return (ISC_TRUE);
356135446Strhodes}
357135446Strhodes
358135446Strhodesstatic inline isc_boolean_t
359135446Strhodeschecknames_dnskey(ARGS_CHECKNAMES) {
360135446Strhodes
361135446Strhodes	REQUIRE(rdata->type == 48);
362135446Strhodes
363135446Strhodes	UNUSED(rdata);
364135446Strhodes	UNUSED(owner);
365135446Strhodes	UNUSED(bad);
366135446Strhodes
367135446Strhodes	return (ISC_TRUE);
368135446Strhodes}
369135446Strhodes
370224092Sdougbstatic inline int
371224092Sdougbcasecompare_dnskey(ARGS_COMPARE) {
372224092Sdougb
373224092Sdougb	/*
374224092Sdougb	 * Treat ALG 253 (private DNS) subtype name case sensistively.
375224092Sdougb	 */
376224092Sdougb	return (compare_dnskey(rdata1, rdata2));
377224092Sdougb}
378224092Sdougb
379135446Strhodes#endif	/* RDATA_GENERIC_DNSKEY_48_C */
380