1/*
2 * validator/val_kentry.c - validator key entry definition.
3 *
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5 *
6 * This software is open source.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36/**
37 * \file
38 *
39 * This file contains functions for dealing with validator key entries.
40 */
41#include "config.h"
42#include "validator/val_kentry.h"
43#include "util/data/packed_rrset.h"
44#include "util/data/dname.h"
45#include "util/storage/lookup3.h"
46#include "util/regional.h"
47#include "util/net_help.h"
48#include "sldns/rrdef.h"
49#include "sldns/keyraw.h"
50
51size_t
52key_entry_sizefunc(void* key, void* data)
53{
54	struct key_entry_key* kk = (struct key_entry_key*)key;
55	struct key_entry_data* kd = (struct key_entry_data*)data;
56	size_t s = sizeof(*kk) + kk->namelen;
57	s += sizeof(*kd) + lock_get_mem(&kk->entry.lock);
58	if(kd->rrset_data)
59		s += packed_rrset_sizeof(kd->rrset_data);
60	if(kd->reason)
61		s += strlen(kd->reason)+1;
62	if(kd->algo)
63		s += strlen((char*)kd->algo)+1;
64	return s;
65}
66
67int
68key_entry_compfunc(void* k1, void* k2)
69{
70	struct key_entry_key* n1 = (struct key_entry_key*)k1;
71	struct key_entry_key* n2 = (struct key_entry_key*)k2;
72	if(n1->key_class != n2->key_class) {
73		if(n1->key_class < n2->key_class)
74			return -1;
75		return 1;
76	}
77	return query_dname_compare(n1->name, n2->name);
78}
79
80void
81key_entry_delkeyfunc(void* key, void* ATTR_UNUSED(userarg))
82{
83	struct key_entry_key* kk = (struct key_entry_key*)key;
84	if(!key)
85		return;
86	lock_rw_destroy(&kk->entry.lock);
87	free(kk->name);
88	free(kk);
89}
90
91void
92key_entry_deldatafunc(void* data, void* ATTR_UNUSED(userarg))
93{
94	struct key_entry_data* kd = (struct key_entry_data*)data;
95	free(kd->reason);
96	free(kd->rrset_data);
97	free(kd->algo);
98	free(kd);
99}
100
101void
102key_entry_hash(struct key_entry_key* kk)
103{
104	kk->entry.hash = 0x654;
105	kk->entry.hash = hashlittle(&kk->key_class, sizeof(kk->key_class),
106		kk->entry.hash);
107	kk->entry.hash = dname_query_hash(kk->name, kk->entry.hash);
108}
109
110struct key_entry_key*
111key_entry_copy_toregion(struct key_entry_key* kkey, struct regional* region)
112{
113	struct key_entry_key* newk;
114	newk = regional_alloc_init(region, kkey, sizeof(*kkey));
115	if(!newk)
116		return NULL;
117	newk->name = regional_alloc_init(region, kkey->name, kkey->namelen);
118	if(!newk->name)
119		return NULL;
120	newk->entry.key = newk;
121	if(newk->entry.data) {
122		/* copy data element */
123		struct key_entry_data *d = (struct key_entry_data*)
124			kkey->entry.data;
125		struct key_entry_data *newd;
126		newd = regional_alloc_init(region, d, sizeof(*d));
127		if(!newd)
128			return NULL;
129		/* copy rrset */
130		if(d->rrset_data) {
131			newd->rrset_data = regional_alloc_init(region,
132				d->rrset_data,
133				packed_rrset_sizeof(d->rrset_data));
134			if(!newd->rrset_data)
135				return NULL;
136			packed_rrset_ptr_fixup(newd->rrset_data);
137		}
138		if(d->reason) {
139			newd->reason = regional_strdup(region, d->reason);
140			if(!newd->reason)
141				return NULL;
142		}
143		if(d->algo) {
144			newd->algo = (uint8_t*)regional_strdup(region,
145				(char*)d->algo);
146			if(!newd->algo)
147				return NULL;
148		}
149		newk->entry.data = newd;
150	}
151	return newk;
152}
153
154struct key_entry_key*
155key_entry_copy(struct key_entry_key* kkey, int copy_reason)
156{
157	struct key_entry_key* newk;
158	if(!kkey)
159		return NULL;
160	newk = memdup(kkey, sizeof(*kkey));
161	if(!newk)
162		return NULL;
163	newk->name = memdup(kkey->name, kkey->namelen);
164	if(!newk->name) {
165		free(newk);
166		return NULL;
167	}
168	lock_rw_init(&newk->entry.lock);
169	newk->entry.key = newk;
170	if(newk->entry.data) {
171		/* copy data element */
172		struct key_entry_data *d = (struct key_entry_data*)
173			kkey->entry.data;
174		struct key_entry_data *newd;
175		newd = memdup(d, sizeof(*d));
176		if(!newd) {
177			free(newk->name);
178			free(newk);
179			return NULL;
180		}
181		/* copy rrset */
182		if(d->rrset_data) {
183			newd->rrset_data = memdup(d->rrset_data,
184				packed_rrset_sizeof(d->rrset_data));
185			if(!newd->rrset_data) {
186				free(newd);
187				free(newk->name);
188				free(newk);
189				return NULL;
190			}
191			packed_rrset_ptr_fixup(newd->rrset_data);
192		}
193		if(copy_reason && d->reason && *d->reason != 0) {
194			newd->reason = strdup(d->reason);
195			if(!newd->reason) {
196				free(newd->rrset_data);
197				free(newd);
198				free(newk->name);
199				free(newk);
200				return NULL;
201			}
202		} else {
203			newd->reason = NULL;
204		}
205		if(d->algo) {
206			newd->algo = (uint8_t*)strdup((char*)d->algo);
207			if(!newd->algo) {
208				free(newd->rrset_data);
209				free(newd->reason);
210				free(newd);
211				free(newk->name);
212				free(newk);
213				return NULL;
214			}
215		}
216		newk->entry.data = newd;
217	}
218	return newk;
219}
220
221int
222key_entry_isnull(struct key_entry_key* kkey)
223{
224	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
225	return (!d->isbad && d->rrset_data == NULL);
226}
227
228int
229key_entry_isgood(struct key_entry_key* kkey)
230{
231	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
232	return (!d->isbad && d->rrset_data != NULL);
233}
234
235int
236key_entry_isbad(struct key_entry_key* kkey)
237{
238	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
239	return (int)(d->isbad);
240}
241
242char*
243key_entry_get_reason(struct key_entry_key* kkey)
244{
245	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
246	return d->reason;
247}
248
249sldns_ede_code
250key_entry_get_reason_bogus(struct key_entry_key* kkey)
251{
252	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
253	return d->reason_bogus;
254
255}
256
257/** setup key entry in region */
258static int
259key_entry_setup(struct regional* region,
260	uint8_t* name, size_t namelen, uint16_t dclass,
261	struct key_entry_key** k, struct key_entry_data** d)
262{
263	*k = regional_alloc(region, sizeof(**k));
264	if(!*k)
265		return 0;
266	memset(*k, 0, sizeof(**k));
267	(*k)->entry.key = *k;
268	(*k)->name = regional_alloc_init(region, name, namelen);
269	if(!(*k)->name)
270		return 0;
271	(*k)->namelen = namelen;
272	(*k)->key_class = dclass;
273	*d = regional_alloc(region, sizeof(**d));
274	if(!*d)
275		return 0;
276	(*k)->entry.data = *d;
277	return 1;
278}
279
280struct key_entry_key*
281key_entry_create_null(struct regional* region,
282	uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
283	sldns_ede_code reason_bogus, const char* reason,
284	time_t now)
285{
286	struct key_entry_key* k;
287	struct key_entry_data* d;
288	if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
289		return NULL;
290	d->ttl = now + ttl;
291	d->isbad = 0;
292	d->reason = (!reason || *reason == 0)
293		?NULL :(char*)regional_strdup(region, reason);
294		/* On allocation error we don't store the reason string */
295	d->reason_bogus = reason_bogus;
296	d->rrset_type = LDNS_RR_TYPE_DNSKEY;
297	d->rrset_data = NULL;
298	d->algo = NULL;
299	return k;
300}
301
302struct key_entry_key*
303key_entry_create_rrset(struct regional* region,
304	uint8_t* name, size_t namelen, uint16_t dclass,
305	struct ub_packed_rrset_key* rrset, uint8_t* sigalg,
306	sldns_ede_code reason_bogus, const char* reason,
307	time_t now)
308{
309	struct key_entry_key* k;
310	struct key_entry_data* d;
311	struct packed_rrset_data* rd = (struct packed_rrset_data*)
312		rrset->entry.data;
313	if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
314		return NULL;
315	d->ttl = rd->ttl + now;
316	d->isbad = 0;
317	d->reason = (!reason || *reason == 0)
318		?NULL :(char*)regional_strdup(region, reason);
319		/* On allocation error we don't store the reason string */
320	d->reason_bogus = reason_bogus;
321	d->rrset_type = ntohs(rrset->rk.type);
322	d->rrset_data = (struct packed_rrset_data*)regional_alloc_init(region,
323		rd, packed_rrset_sizeof(rd));
324	if(!d->rrset_data)
325		return NULL;
326	if(sigalg) {
327		d->algo = (uint8_t*)regional_strdup(region, (char*)sigalg);
328		if(!d->algo)
329			return NULL;
330	} else d->algo = NULL;
331	packed_rrset_ptr_fixup(d->rrset_data);
332	return k;
333}
334
335struct key_entry_key*
336key_entry_create_bad(struct regional* region,
337	uint8_t* name, size_t namelen, uint16_t dclass, time_t ttl,
338	sldns_ede_code reason_bogus, const char* reason,
339	time_t now)
340{
341	struct key_entry_key* k;
342	struct key_entry_data* d;
343	if(!key_entry_setup(region, name, namelen, dclass, &k, &d))
344		return NULL;
345	d->ttl = now + ttl;
346	d->isbad = 1;
347	d->reason = (!reason || *reason == 0)
348		?NULL :(char*)regional_strdup(region, reason);
349		/* On allocation error we don't store the reason string */
350	d->reason_bogus = reason_bogus;
351	d->rrset_type = LDNS_RR_TYPE_DNSKEY;
352	d->rrset_data = NULL;
353	d->algo = NULL;
354	return k;
355}
356
357struct ub_packed_rrset_key*
358key_entry_get_rrset(struct key_entry_key* kkey, struct regional* region)
359{
360	struct key_entry_data* d = (struct key_entry_data*)kkey->entry.data;
361	struct ub_packed_rrset_key* rrk;
362	struct packed_rrset_data* rrd;
363	if(!d || !d->rrset_data)
364		return NULL;
365	rrk = regional_alloc(region, sizeof(*rrk));
366	if(!rrk)
367		return NULL;
368	memset(rrk, 0, sizeof(*rrk));
369	rrk->rk.dname = regional_alloc_init(region, kkey->name, kkey->namelen);
370	if(!rrk->rk.dname)
371		return NULL;
372	rrk->rk.dname_len = kkey->namelen;
373	rrk->rk.type = htons(d->rrset_type);
374	rrk->rk.rrset_class = htons(kkey->key_class);
375	rrk->entry.key = rrk;
376	rrd = regional_alloc_init(region, d->rrset_data,
377		packed_rrset_sizeof(d->rrset_data));
378	if(!rrd)
379		return NULL;
380	rrk->entry.data = rrd;
381	packed_rrset_ptr_fixup(rrd);
382	return rrk;
383}
384
385/** Get size of key in keyset */
386static size_t
387dnskey_get_keysize(struct packed_rrset_data* data, size_t idx)
388{
389	unsigned char* pk;
390	unsigned int pklen = 0;
391	int algo;
392	if(data->rr_len[idx] < 2+5)
393		return 0;
394	algo = (int)data->rr_data[idx][2+3];
395	pk = (unsigned char*)data->rr_data[idx]+2+4;
396	pklen = (unsigned)data->rr_len[idx]-2-4;
397	return sldns_rr_dnskey_key_size_raw(pk, pklen, algo);
398}
399
400/** get dnskey flags from data */
401static uint16_t
402kd_get_flags(struct packed_rrset_data* data, size_t idx)
403{
404	uint16_t f;
405	if(data->rr_len[idx] < 2+2)
406		return 0;
407	memmove(&f, data->rr_data[idx]+2, 2);
408	f = ntohs(f);
409	return f;
410}
411
412size_t
413key_entry_keysize(struct key_entry_key* kkey)
414{
415	struct packed_rrset_data* d;
416	/* compute size of smallest ZSK key in the rrset */
417	size_t i;
418	size_t bits = 0;
419	if(!key_entry_isgood(kkey))
420		return 0;
421	d = ((struct key_entry_data*)kkey->entry.data)->rrset_data;
422	for(i=0; i<d->count; i++) {
423		if(!(kd_get_flags(d, i) & DNSKEY_BIT_ZSK))
424			continue;
425		if(i==0 || dnskey_get_keysize(d, i) < bits)
426			bits = dnskey_get_keysize(d, i);
427	}
428	return bits;
429}
430