1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /**
36 * @defgroup dnskey DNSSEC keys functions
37 * @ingroup dnsdbdnssec
38 * @addtogroup dnskey DNSKEY functions
39 * @brief
40 *
41 *
42 * @{
43 */
44 /*------------------------------------------------------------------------------
45 *
46 * USE INCLUDES */
47
48 /*
49 #include <arpa/inet.h>
50 #include <ctype.h>
51 */
52
53 #include "dnscore/dnscore-config.h"
54 #include "dnscore/dnskey-keyring.h"
55 #include "dnscore/logger.h"
56 #include "dnscore/message.h"
57 #include "dnscore/packet_reader.h"
58
59 extern logger_handle *g_system_logger;
60 #define MODULE_MSG_HANDLE g_system_logger
61
62 ya_result
dnskey_keyring_init(dnskey_keyring * ks)63 dnskey_keyring_init(dnskey_keyring *ks)
64 {
65 u32_set_init(&ks->tag_to_key);
66 mutex_init(&ks->mtx);
67 return SUCCESS;
68 }
69
70 static void
dnskey_keyring_finalize_callback(u32_node * node)71 dnskey_keyring_finalize_callback(u32_node *node)
72 {
73 dnssec_key* key;
74 key = (dnssec_key*)node->value;
75 dnskey_release(key);
76 node->value = NULL;
77 }
78
79 void
dnskey_keyring_finalize(dnskey_keyring * ks)80 dnskey_keyring_finalize(dnskey_keyring *ks)
81 {
82 u32_set_callback_and_destroy(&ks->tag_to_key, dnskey_keyring_finalize_callback);
83 mutex_destroy(&ks->mtx);
84 }
85
86 ya_result
dnskey_keyring_add(dnskey_keyring * ks,dnssec_key * key)87 dnskey_keyring_add(dnskey_keyring *ks, dnssec_key* key)
88 {
89 u32 hash = key->algorithm;
90 hash <<= 16;
91 hash |= key->tag;
92
93 mutex_lock(&ks->mtx);
94 u32_node *node = u32_set_insert(&ks->tag_to_key, hash);
95
96 if(node->value == NULL)
97 {
98 dnskey_acquire(key);
99 node->value = key;
100
101 mutex_unlock(&ks->mtx);
102
103 return SUCCESS;
104 }
105 else
106 {
107 mutex_unlock(&ks->mtx);
108
109 return DNSSEC_ERROR_KEYRING_ALGOTAG_COLLISION;
110 }
111 }
112
113 ya_result
dnskey_keyring_add_from_nameserver(dnskey_keyring * ks,const host_address * ha,const u8 * domain)114 dnskey_keyring_add_from_nameserver(dnskey_keyring *ks, const host_address *ha, const u8 *domain)
115 {
116 message_data *query = message_new_instance();
117 ya_result ret;
118
119 log_debug("%{dnsname}: fetching public keys from %{hostaddr}", domain, ha);
120
121 message_make_query(query, (u16)rand(), domain, TYPE_DNSKEY, CLASS_IN);
122
123 if(ISOK(ret = message_query(query, ha)))
124 {
125 if(message_get_rcode(query) == RCODE_OK)
126 {
127 log_debug("%{dnsname}: %{hostaddr} answered", domain, ha);
128
129 if(message_get_query_count(query) == 1)
130 {
131 u16 answers;
132
133 if((answers = message_get_answer_count(query)) > 0)
134 {
135 // extract all keys
136 packet_unpack_reader_data purd;
137 packet_reader_init_from_message(&purd, query);
138
139 packet_reader_skip_fqdn(&purd); // checked below
140 packet_reader_skip(&purd, 4); // checked below
141
142 if(!packet_reader_eof(&purd))
143 {
144 int keys_added = 0;
145
146 for(u16 i = 0; i < answers; ++i)
147 {
148 dnssec_key *key = NULL;
149 u16 rtype;
150 u16 rclass;
151 s32 rttl;
152 u16 rdata_size;
153 u8 rdata[1024];
154
155 if(FAIL(packet_reader_read_fqdn(&purd, rdata, sizeof(rdata))))
156 {
157 log_info("%{dnsname}: %{hostaddr} message FORMERR)", domain, ha);
158 keys_added = MAKE_DNSMSG_ERROR(RCODE_FORMERR);
159 break;
160 }
161
162 if(dnslabel_equals_ignorecase_left(domain, rdata))
163 {
164 if(packet_reader_available(&purd) <= 10)
165 {
166 log_info("%{dnsname}: %{hostaddr} message FORMERR)", domain, ha);
167 keys_added = MAKE_DNSMSG_ERROR(RCODE_FORMERR);
168 break;
169 }
170
171 // unchecked because we did just that
172
173 packet_reader_read_u16_unchecked(&purd, &rtype); // checked
174 packet_reader_read_u16_unchecked(&purd, &rclass); // checked
175 packet_reader_read_s32_unchecked(&purd, &rttl); // checked
176 packet_reader_read_u16_unchecked(&purd, &rdata_size); // checked
177
178 rdata_size = ntohs(rdata_size);
179
180 if(rtype == TYPE_DNSKEY)
181 {
182 if(ISOK(ret = packet_reader_read_rdata(&purd, rtype, rdata_size, rdata, rdata_size)))
183 {
184 if(ISOK(ret = dnskey_new_from_rdata(rdata, rdata_size, domain, &key)))
185 {
186 if(ISOK(ret = dnskey_keyring_add(ks, key)))
187 {
188 log_info("%{dnsname}: %{hostaddr} added dnskey %{dnsname}: +%03d+%05d/%d added",
189 domain, ha,
190 dnskey_get_domain(key), dnskey_get_algorithm(key),
191 dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)));
192
193 ++keys_added;
194 }
195 else
196 {
197 log_warn("%{dnsname}: %{hostaddr} failed to add dnskey %{dnsname}: +%03d+%05d/%d: %r",
198 domain, ha,
199 dnskey_get_domain(key), dnskey_get_algorithm(key),
200 dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)), ret);
201 }
202
203 dnskey_release(key);
204 }
205 else
206 {
207 log_warn("%{dnsname}: %{hostaddr} cannot convert rdata to a dnskey: %r", domain, ha, ret);
208 }
209 }
210 else
211 {
212 log_warn("%{dnsname}: %{hostaddr} cannot parse rdata: %r", domain, ha, ret);
213 }
214 }
215 else
216 {
217 // not a DNSKEY: skip
218
219 if(FAIL(packet_reader_skip(&purd, rdata_size)))
220 {
221 log_info("%{dnsname}: %{hostaddr} message FORMERR)", domain, ha);
222 keys_added = MAKE_DNSMSG_ERROR(RCODE_FORMERR);
223 break;
224 }
225 }
226 }
227 else
228 {
229 log_warn("%{dnsname}: %{hostaddr} wrong domain for key: %{dnsname}", domain, ha, rdata);
230 }
231 } // for all records in answer
232
233 ret = keys_added;
234 }
235 else
236 {
237 ret = MAKE_DNSMSG_ERROR(RCODE_FORMERR);
238 }
239 }
240 else
241 {
242 log_debug("%{dnsname}: %{hostaddr} has no keys", domain, ha);
243 }
244 }
245 else
246 {
247 log_err("%{dnsname}: %{hostaddr} message is broken (QR != 1)", domain, ha);
248 }
249 }
250 else
251 {
252 log_err("%{dnsname}: %{hostaddr} answered with rcode %s", domain, ha, dns_message_rcode_get_name(message_get_rcode(query)));
253 }
254 }
255 else
256 {
257 log_err("%{dnsname}: %{hostaddr} query error: %r", domain, ha, ret);
258 }
259
260 message_free(query);
261
262 return ret;
263 }
264
265 bool
dnskey_keyring_remove(dnskey_keyring * ks,u8 algorithm,u16 tag,const u8 * domain)266 dnskey_keyring_remove(dnskey_keyring *ks, u8 algorithm, u16 tag, const u8 *domain)
267 {
268 u32 hash = algorithm;
269 hash <<= 16;
270 hash |= tag;
271
272 mutex_lock(&ks->mtx);
273
274 u32_node *node = u32_set_find(&ks->tag_to_key, hash);
275
276 if(node != NULL)
277 {
278 dnssec_key *key = (dnssec_key*)node->value;
279
280 if((key != NULL) && dnsname_equals(key->owner_name, domain))
281 {
282 dnskey_release(key);
283 u32_set_delete(&ks->tag_to_key, hash);
284 mutex_unlock(&ks->mtx);
285
286 return TRUE;
287 }
288 }
289
290 mutex_unlock(&ks->mtx);
291
292 return FALSE;
293 }
294
295 dnssec_key*
dnskey_keyring_acquire(dnskey_keyring * ks,u8 algorithm,u16 tag,const u8 * domain)296 dnskey_keyring_acquire(dnskey_keyring *ks, u8 algorithm, u16 tag, const u8 *domain)
297 {
298 u32 hash = algorithm;
299 hash <<= 16;
300 hash |= tag;
301
302 mutex_lock(&ks->mtx);
303
304 u32_node *node = u32_set_find(&ks->tag_to_key, hash);
305
306 if(node != NULL)
307 {
308 dnssec_key *key = (dnssec_key*)node->value;
309
310 if((key != NULL) && dnsname_equals(key->owner_name, domain))
311 {
312 dnskey_acquire(key);
313 mutex_unlock(&ks->mtx);
314 return key;
315 }
316 }
317
318 mutex_unlock(&ks->mtx);
319
320 return NULL;
321 }
322
323 dnssec_key*
dnskey_keyring_acquire_by_index(dnskey_keyring * ks,u8 algorithm,u16 tag,const u8 * domain)324 dnskey_keyring_acquire_by_index(dnskey_keyring *ks, u8 algorithm, u16 tag, const u8 *domain)
325 {
326 u32 hash = algorithm;
327 hash <<= 16;
328 hash |= tag;
329
330 mutex_lock(&ks->mtx);
331
332 u32_node *node = u32_set_find(&ks->tag_to_key, hash);
333
334 if(node != NULL)
335 {
336 dnssec_key *key = (dnssec_key*)node->value;
337
338 if((key != NULL) && dnsname_equals(key->owner_name, domain))
339 {
340 dnskey_acquire(key);
341 mutex_unlock(&ks->mtx);
342 return key;
343 }
344 }
345
346 mutex_unlock(&ks->mtx);
347
348 return NULL;
349 }
350
351 /**
352 *
353 * Returns TRUE iff the keyring contains a key matching the parameters
354 *
355 * @param ks
356 * @param algorithm
357 * @param tag
358 * @param domain
359 * @return
360 */
361
362 bool
dnskey_keyring_has_key(dnskey_keyring * ks,u8 algorithm,u16 tag,const u8 * domain)363 dnskey_keyring_has_key(dnskey_keyring *ks, u8 algorithm, u16 tag, const u8 *domain)
364 {
365 u32 hash = algorithm;
366 hash <<= 16;
367 hash |= tag;
368
369 mutex_lock(&ks->mtx);
370
371 u32_node *node = u32_set_find(&ks->tag_to_key, hash);
372
373 if(node != NULL)
374 {
375 dnssec_key *key = (dnssec_key*)node->value;
376
377 if((key != NULL) && dnsname_equals(key->owner_name, domain))
378 {
379 mutex_unlock(&ks->mtx);
380 return TRUE;
381 }
382 }
383
384 mutex_unlock(&ks->mtx);
385
386 return FALSE;
387 }
388
389 static void
dnskey_keyring_destroy_callback(u32_node * node)390 dnskey_keyring_destroy_callback(u32_node *node)
391 {
392 /// @note mutex has been locked by the caller
393
394 dnssec_key *key = (dnssec_key*)node->value;
395 dnskey_release(key);
396 }
397
398 void
dnskey_keyring_destroy(dnskey_keyring * ks)399 dnskey_keyring_destroy(dnskey_keyring *ks)
400 {
401 mutex_lock(&ks->mtx);
402 u32_set_callback_and_destroy(&ks->tag_to_key, dnskey_keyring_destroy_callback);
403 mutex_unlock(&ks->mtx);
404
405 mutex_destroy(&ks->mtx);
406 }
407
408 bool
dnskey_keyring_isempty(dnskey_keyring * ks)409 dnskey_keyring_isempty(dnskey_keyring *ks)
410 {
411 mutex_lock(&ks->mtx);
412 bool ret = u32_set_isempty(&ks->tag_to_key);
413 mutex_unlock(&ks->mtx);
414 return ret;
415 }
416
417 dnssec_key *
dnskey_keyring_acquire_key_at_index(dnskey_keyring * ks,int index)418 dnskey_keyring_acquire_key_at_index(dnskey_keyring *ks, int index)
419 {
420 u32_set_iterator iter;
421 u32_set_iterator_init(&ks->tag_to_key, &iter);
422 while(u32_set_iterator_hasnext(&iter))
423 {
424 u32_node *node = u32_set_iterator_next_node(&iter);
425 if(--index < 0)
426 {
427 dnssec_key *key = (dnssec_key*)node->value;
428 dnskey_acquire(key);
429 return key;
430 }
431 }
432 return NULL;
433 }
434
435 /** @} */
436