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 /** @defgroup nsec3 NSEC3 functions
36  *  @ingroup dnsdbdnssec
37  *  @brief
38  *
39  *
40  *
41  * @{
42  */
43 /*------------------------------------------------------------------------------
44  *
45  * USE INCLUDES */
46 #include "dnsdb/dnsdb-config.h"
47 #include <stdio.h>
48 #include <stdlib.h>
49 
50 #include <dnscore/logger.h>
51 
52 #include "dnsdb/nsec3_item.h"
53 #include "dnsdb/nsec3_owner.h"
54 #include "dnsdb/nsec3_zone.h"
55 
56 #include "dnsdb/zdb_zone_label_iterator.h"
57 
58 #define MODULE_MSG_HANDLE g_dnssec_logger
59 
60 extern logger_handle *g_dnssec_logger;
61 
62 /******************************************************************************
63  *
64  * NSEC3 - tools : nsec3_zone (nsec3param's alter ego)
65  *
66  *****************************************************************************/
67 
68 /*
69  * Compares two nsec3_zone (binary compare <0 / = / >0 : less/equal/bigger)
70  */
71 
72 int
nsec3param_compare_by_rdata(const u8 * a_rdata,const u8 * b_rdata)73 nsec3param_compare_by_rdata(const u8 *a_rdata, const u8 *b_rdata)
74 {
75     int c;
76 
77     c = a_rdata[0];
78     c -= b_rdata[0];
79 
80     if(c == 0)
81     {
82         c = a_rdata[2];
83         c -= b_rdata[2];
84 
85         if(c == 0)
86         {
87             c = a_rdata[3];
88             c -= b_rdata[3];
89 
90             if(c == 0)
91             {
92                 c = a_rdata[4]; // size of the salt
93                 c -= b_rdata[4];
94 
95                 if(c == 0)
96                 {
97                     c = memcmp(&a_rdata[5], &b_rdata[5], a_rdata[4]);
98                 }
99             }
100         }
101     }
102 
103     return c;
104 }
105 
106 /*
107  * Compares two nsec3_zone (binary compare <0 / = / >0 : less/equal/bigger)
108  */
109 
110 
111 
112 int
nsec3_zone_compare(nsec3_zone * a,nsec3_zone * b)113 nsec3_zone_compare(nsec3_zone* a, nsec3_zone* b)
114 {
115     return nsec3param_compare_by_rdata(a->rdata, b->rdata);
116 }
117 
118 /*
119  * Retrieves the nsec3_zone* (NSEC3PARAM alter-ego) from an item.
120  *
121  * This is done by looking for the NSEC3 root then looking for which nsec3_zone
122  * contains the ptr.  It requires up to 30 moves. (slow)
123  *
124  * I could also mark the nsec3 records and store the mark on every record but
125  * it would be expensive (memory).
126  *
127  */
128 
129 nsec3_zone*
nsec3_zone_from_item(const zdb_zone * zone,const nsec3_zone_item * item)130 nsec3_zone_from_item(const zdb_zone* zone, const nsec3_zone_item* item)
131 {
132     const nsec3_zone_item* root = item;
133 
134     while(root->parent != NULL)
135     {
136         root = root->parent;
137     }
138 
139     nsec3_zone* n3 = zone->nsec.nsec3;
140 
141     while(n3 != NULL)
142     {
143         if(n3->items == root)
144         {
145             break;
146         }
147 
148         n3 = n3->next;
149     }
150 
151     return n3;
152 }
153 
154 /*
155  * Recursively empties nsec3_zone_item
156  *
157  * Does not destroys the nodes, only the payload : owners, stars, bitmap, rrsig
158  *
159  * This should be followed by the destruction of the items
160  */
161 
162 static void
nsec3_zone_item_empties_recursively(nsec3_zone_item * item)163 nsec3_zone_item_empties_recursively(nsec3_zone_item* item)
164 {
165     if(item != NULL)
166     {
167         nsec3_zone_item_empties(item);
168 
169         nsec3_zone_item_empties_recursively(item->children.lr.left);
170         nsec3_zone_item_empties_recursively(item->children.lr.right);
171     }
172 }
173 
174 /**
175  * Detaches an nsec3 chain from the zone.
176  *
177  * @param zone
178  * @param n3
179  * @return
180  */
181 
182 bool
nsec3_zone_detach(zdb_zone * zone,nsec3_zone * n3)183 nsec3_zone_detach(zdb_zone *zone, nsec3_zone *n3)
184 {
185     nsec3_zone *first = zone->nsec.nsec3;
186 
187     if(first == n3)
188     {
189         zone->nsec.nsec3 = n3->next;
190     }
191     else
192     {
193         while(first->next != n3)
194         {
195             first = first->next;
196 
197             if(first == NULL)
198             {
199                 return FALSE;
200             }
201         }
202 
203         first->next = n3->next;
204     }
205 
206     n3->next = NULL;
207 
208     return TRUE;
209 }
210 
211 /*
212  * Destroys the nsec3param alter-ego from the database.
213  *
214  * The zdb_rr_label are also affected by the call.
215  *
216  * The NSEC3PARAM record is not changed.
217  *
218  */
219 
220 void
nsec3_zone_destroy(zdb_zone * zone,nsec3_zone * n3)221 nsec3_zone_destroy(zdb_zone *zone, nsec3_zone *n3)
222 {
223     int n3_index = 0;
224 
225     /*
226      *
227      * Check for existence of n3 into zone
228      *
229      * For every nsec3 record found in zone:
230      *
231      *	    Get the self(s), unlink
232      *	    Get the star(s), unlink
233      *	    Destroy nsec3 record signature
234      *	    Destroy nsec3 record
235      */
236 
237     // get the pointer chaining to n3
238 
239     nsec3_zone **n3p = &zone->nsec.nsec3;
240 
241     yassert(*n3p != NULL);
242 
243     while(*n3p != n3)
244     {
245         ++n3_index;
246         n3p = &(*n3p)->next;
247 
248         yassert(*n3p != NULL);
249     }
250 
251     *n3p = n3->next;
252     n3->next = NULL;
253     nsec3_zone_item_empties_recursively(n3->items);
254     nsec3_destroy(&n3->items);
255     nsec3_zone_free(n3);
256 
257     // Every single label must have its chain updated
258 
259     zdb_zone_label_iterator label_iterator;
260     zdb_zone_label_iterator_init(&label_iterator, zone);
261 
262     if(n3_index == 0)
263     {
264         while(zdb_zone_label_iterator_hasnext(&label_iterator))
265         {
266             zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);
267 
268             if(label->nsec.nsec3 != NULL)
269             {
270                 struct nsec3_label_extension *n3_ext = label->nsec.nsec3;
271                 if(n3_ext != NULL)
272                 {
273                     label->nsec.nsec3 = nsec3_label_extension_next(n3_ext);
274                     yassert(nsec3_label_extension_self(n3_ext) == NULL && nsec3_label_extension_star(n3_ext) == NULL);
275                     nsec3_label_extension_free(n3_ext);
276                 }
277             }
278         }
279     }
280     else
281     {
282         while(zdb_zone_label_iterator_hasnext(&label_iterator))
283         {
284 #if DEBUG
285             u8 fqdn[256];
286             zdb_zone_label_iterator_nextname(&label_iterator, fqdn);
287 #endif
288 
289             zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);
290 
291             if(label->nsec.nsec3 != NULL)
292             {
293                 struct nsec3_label_extension **n3_extp = nsec3_label_extension_next_ptr(label->nsec.nsec3);
294                 struct nsec3_label_extension *n3_ext = *n3_extp;
295                 for(int i = 1; i < n3_index; ++i)
296                 {
297                     n3_extp = nsec3_label_extension_next_ptr(n3_ext);
298                     n3_ext = *n3_extp;
299                 }
300                 *n3_extp = nsec3_label_extension_next(n3_ext);
301 
302 #if DEBUG
303                 if(nsec3_label_extension_self(n3_ext) != NULL)
304                 {
305                     log_debug2("%{dnsname} self %{digest32h}", fqdn, nsec3_label_extension_self(n3_ext)->digest);
306                 }
307                 if(nsec3_label_extension_star(n3_ext) != NULL)
308                 {
309                     log_debug2("%{dnsname} star %{digest32h}", fqdn, nsec3_label_extension_star(n3_ext)->digest);
310                 }
311 #endif
312 
313                 yassert(nsec3_label_extension_self(n3_ext) == NULL && nsec3_label_extension_star(n3_ext) == NULL); // both are expected to be cleared
314                 nsec3_label_extension_free(n3_ext);
315             }
316         }
317     }
318 }
319 
320 
321 
322 /*
323  * Adds the nsec3_zone (NSEC3PARAM "alter-ego") to the zone.
324  *
325  * Updates labels flags + nsec3 item references placeholders
326  * using nsec3_insert_empty_nsec3
327  *
328  * Uses nsec3zone_compare
329  *
330  * Used by nsec3_add_nsec3param and nsec3_load_add_nsec3param
331  *
332  */
333 
334 nsec3_zone*
nsec3_zone_add_from_rdata(zdb_zone * zone,u16 nsec3param_rdata_size,const u8 * nsec3param_rdata)335 nsec3_zone_add_from_rdata(zdb_zone* zone, u16 nsec3param_rdata_size, const u8* nsec3param_rdata)
336 {
337     /* Check that the rdata is big enough */
338     yassert(nsec3param_rdata_size >= NSEC3PARAM_MINIMUM_LENGTH);
339 
340     nsec3_zone* n3 = nsec3_zone_get_from_rdata(zone, nsec3param_rdata_size, nsec3param_rdata);
341 
342     if(n3 == NULL)
343     {
344         n3 = nsec3_zone_new(nsec3param_rdata, nsec3param_rdata_size);
345 
346         /*
347          * Insertion has to be sorted on the Algorithm + Iterations + Salt_len + Salt
348          */
349 
350         nsec3_zone** current = &zone->nsec.nsec3;
351         nsec3_zone* next_n3 = zone->nsec.nsec3;
352         u32 n3_pos = 0;
353 
354         for(;;)
355         {
356             /*
357             if((next_n3 == NULL) || (nsec3_zone_compare(n3, next_n3) < 0))
358             */
359             if(next_n3 == NULL)
360             {
361                 n3->next = next_n3;
362 
363                 *current = n3;
364 
365                 /*
366                  * For every existing label in the database: add a nsec3 node for
367                  * the current n3 record (same position in the list).
368                  */
369 
370                 //nsec3_insert_empty_nsec3(zone, n3_pos);
371 
372                 break;
373             }
374 
375             current = &next_n3->next;
376             next_n3 = next_n3->next;
377             n3_pos++;
378         }
379     }
380 
381     return n3;
382 }
383 
384 nsec3_zone*
nsec3_zone_new(const u8 * nsec3param_rdata,u16 nsec3param_rdata_size)385 nsec3_zone_new(const u8 *nsec3param_rdata, u16 nsec3param_rdata_size)
386 {
387     nsec3_zone *n3;
388     u32 nsec3param_rdata_realsize = NSEC3PARAM_RDATA_SIZE_FROM_RDATA(nsec3param_rdata);
389     yassert(nsec3param_rdata_size >= nsec3param_rdata_realsize);
390     (void)nsec3param_rdata_size;
391     ZALLOC_ARRAY_OR_DIE(nsec3_zone*, n3, sizeof(nsec3_zone) + nsec3param_rdata_realsize, NSEC3_ZONE_TAG);
392     n3->next = NULL;
393     n3->items = NULL;
394     memcpy(n3->rdata, nsec3param_rdata, nsec3param_rdata_realsize);
395 
396     return n3;
397 }
398 
nsec3_zone_free(nsec3_zone * n3)399 void nsec3_zone_free(nsec3_zone *n3)
400 {
401     yassert(nsec3_isempty(&n3->items));
402     yassert(n3->next == NULL);
403     ZFREE_ARRAY(n3, sizeof(nsec3_zone) + NSEC3PARAM_MINIMUM_LENGTH + n3->rdata[4]);
404 }
405 
406 ya_result
nsec3_zone_chain_count(zdb_zone * zone)407 nsec3_zone_chain_count(zdb_zone* zone)
408 {
409     ya_result ret = 0;;
410     nsec3_zone* n3 = zone->nsec.nsec3;
411     while(n3 != NULL)
412     {
413         ++ret;
414         n3 = n3->next;
415     }
416     return ret;
417 }
418 
419 
420 /**
421  *
422  * Adds the nsec3_zone (NSEC3PARAM "alter-ego") to the zone.
423  *
424  * Updates labels flags + nsec3 item references placeholders
425  * using nsec3_insert_empty_nsec3
426  *
427  * Uses nsec3zone_compare
428  *
429  * Used by nsec3_add_nsec3param and nsec3_load_add_nsec3param
430  *
431  * @note Does not add the record.
432  *
433  * @param zone
434  * @param nsec3param_rdata
435  * @param nsec3param_rdata_size
436  *
437  * @return an error code
438  */
439 
440 ya_result
nsec3_zone_chain_add_with_rdata(zdb_zone * zone,const u8 * nsec3param_rdata,u16 nsec3param_rdata_size)441 nsec3_zone_chain_add_with_rdata(zdb_zone* zone, const u8* nsec3param_rdata, u16 nsec3param_rdata_size)
442 {
443     /* Check that the rdata is big enough */
444     yassert(nsec3param_rdata_size >= NSEC3PARAM_MINIMUM_LENGTH);
445     ya_result ret = 0;
446 
447     nsec3_zone* n3 = zone->nsec.nsec3;
448     nsec3_zone** n3p;
449     if(n3 != NULL)
450     {
451         if(memcmp(n3->rdata, nsec3param_rdata, nsec3param_rdata_size) == 0)
452         {
453             // duplicate
454             return ERROR;
455         }
456 
457         ++ret;
458 
459         while(n3->next != NULL)
460         {
461             n3 = n3->next;
462 
463             if(memcmp(n3->rdata, nsec3param_rdata, nsec3param_rdata_size) == 0)
464             {
465                 // duplicate
466                 return ERROR;
467             }
468 
469             ++ret;
470         }
471         // add after n3
472         n3p = &n3->next;
473     }
474     else
475     {
476         // create n3
477         n3p = &zone->nsec.nsec3;
478     }
479 
480     n3 = nsec3_zone_new(nsec3param_rdata, nsec3param_rdata_size);
481     *n3p = n3;
482 
483     return ret;
484 }
485 
486 /**
487  * Returns the index of an NSEC3PARAM in the zone, or an error code
488  *
489  * @param zone
490  * @param nsec3param_rdata
491  * @param nsec3param_rdata_size
492  * @return
493  */
494 
495 ya_result
nsec3_zone_chain_get_index_from_rdata(zdb_zone * zone,const u8 * nsec3param_rdata,u16 nsec3param_rdata_size)496 nsec3_zone_chain_get_index_from_rdata(zdb_zone* zone, const u8* nsec3param_rdata, u16 nsec3param_rdata_size)
497 {
498     /* Check that the rdata is big enough */
499     yassert(nsec3param_rdata_size >= NSEC3PARAM_MINIMUM_LENGTH);
500     ya_result ret = 0;
501 
502     nsec3_zone* n3 = zone->nsec.nsec3;
503 
504     while(n3 != NULL)
505     {
506         if(memcmp(n3->rdata, nsec3param_rdata, nsec3param_rdata_size) == 0)
507         {
508             // return the index of the match
509             return ret;
510         }
511 
512         ++ret;
513 
514         n3 = n3->next;
515     }
516 
517     return ERROR;
518 }
519 
520 /*
521  * Returns the zone's matching nsec3_zone* or NULL
522  *
523  * The rdata can be of an NSEC3PARAM or of an NSEC3
524  *
525  */
526 
527 nsec3_zone*
nsec3_zone_get_from_rdata(const zdb_zone * zone,u16 nsec3param_rdata_size,const u8 * nsec3param_rdata)528 nsec3_zone_get_from_rdata(const zdb_zone* zone, u16 nsec3param_rdata_size, const u8* nsec3param_rdata)
529 {
530     /* Check that the rdata is big enough */
531     yassert(nsec3param_rdata_size >= NSEC3PARAM_MINIMUM_LENGTH);
532     (void)nsec3param_rdata_size;
533 
534     nsec3_zone* n3;
535 
536     for(n3 = zone->nsec.nsec3; n3 != NULL; n3 = n3->next)
537     {
538         /* test the first 32 bits in one go */
539         u32 a = GET_U32_AT(n3->rdata[0]);
540         u32 b = GET_U32_AT(nsec3param_rdata[0]);
541 
542         a &= NU32(0xff00ffff);
543         b &= NU32(0xff00ffff);
544 
545         if(a == b)
546         {
547             u8 len = NSEC3_ZONE_SALT_LEN(n3);
548             if(NSEC3PARAM_RDATA_SALT_LEN(nsec3param_rdata) == len)
549             {
550                 if(memcmp(NSEC3_ZONE_SALT(n3), NSEC3PARAM_RDATA_SALT(nsec3param_rdata), len) == 0)
551                 {
552                     break;
553                 }
554             }
555         }
556     }
557 
558     return n3;
559 }
560 
561 /** @} */
562