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