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 #include "dnscore/dnscore-config.h"
48 
49 #define DNSCORE_DNSKEY_C 1
50 
51 #include <arpa/inet.h>
52 #include <ctype.h>
53 #include <sys/stat.h>
54 #include <dnscore/dns_resource_record.h>
55 #include "dnscore/openssl.h"
56 #include "dnscore/dnsname.h"
57 #include "dnscore/dnskey.h"
58 #include "dnscore/dnskey_rsa.h"
59 #include "dnscore/dnskey_dsa.h"
60 #if HAS_ECDSA_SUPPORT
61 #include "dnscore/dnskey_ecdsa.h"
62 #endif
63 #if HAS_EDDSA_SUPPORT
64 #include "dnscore/dnskey_eddsa.h"
65 #endif
66 #ifdef DNSKEY_ALGORITHM_DUMMY
67 #include "dnscore/dnskey_dummy.h"
68 #endif
69 #include "dnscore/digest.h"
70 #include "dnscore/base64.h"
71 #include "dnscore/string_set.h"
72 #include "dnscore/file_input_stream.h"
73 #include "dnscore/file_output_stream.h"
74 #include "dnscore/buffer_output_stream.h"
75 #include "dnscore/parser.h"
76 #include "dnscore/zalloc.h"
77 #include "dnscore/logger.h"
78 #include "dnscore/fdtools.h"
79 #include "dnscore/mutex.h"
80 #include "dnscore/timeformat.h"
81 
82 extern logger_handle* g_system_logger;
83 #define MODULE_MSG_HANDLE g_system_logger
84 
85 #define ZDB_DNSKEY_TAG          0x59454b534e44
86 #define ZDB_DNSKEY_NAME_TAG     0x454d414e59454b
87 
88 #define ORIGNDUP_TAG 0x5055444e4749524f
89 #define DNSKRAWB_TAG 0x425741524b534e44
90 
91 // dumps key acquisition/release
92 #define DUMP_ACQUIRE_RELEASE_STACK_TRACE 0
93 
94 static string_set dnssec_key_load_private_keywords_set = STRING_SET_EMPTY;
95 
96 #define DNSKEY_FIELD_ALGORITHM 1
97 #define DNSKEY_FIELD_FORMAT    2
98 #define DNSKEY_FIELD_CREATED   3
99 #define DNSKEY_FIELD_PUBLISH   4
100 #define DNSKEY_FIELD_ACTIVATE  5
101 
102 #define DNSKEY_FIELD_INACTIVE  7
103 #define DNSKEY_FIELD_DELETE    8
104 #define DNSKEY_FIELD_ENGINE    9
105 
106 static value_name_table dnssec_key_load_private_keywords_common_names[] =
107 {
108     {DNSKEY_FIELD_ALGORITHM,    "Algorithm"},
109     {DNSKEY_FIELD_FORMAT,       "Private-key-format"},
110     {DNSKEY_FIELD_CREATED,      "Created"},
111     {DNSKEY_FIELD_PUBLISH,      "Publish"},
112     {DNSKEY_FIELD_ACTIVATE,     "Activate"},
113 
114     {DNSKEY_FIELD_INACTIVE,     "Inactive"},
115     {DNSKEY_FIELD_DELETE,       "Delete"},
116     {DNSKEY_FIELD_ENGINE,       "Engine"},
117     {0, NULL}
118 };
119 
120 static group_mutex_t dnskey_rc_mtx = GROUP_MUTEX_INITIALIZER;
121 
122 static const char *rsamd5_names[] = {DNSKEY_ALGORITHM_RSAMD5_NAME,"1", NULL};
123 static const char *dsasha1_names[] = {DNSKEY_ALGORITHM_DSASHA1_NAME,"3", NULL};
124 static const char *rsasha1_names[] = {DNSKEY_ALGORITHM_RSASHA1_NAME,"5", NULL};
125 static const char *dsasha1nsec3_names[] = {DNSKEY_ALGORITHM_DSASHA1_NSEC3_NAME,"6", NULL};
126 static const char *rsasha1nsec3_names[] = {DNSKEY_ALGORITHM_RSASHA1_NSEC3_NAME,"7", NULL};
127 static const char *rsasha256_names[] = {DNSKEY_ALGORITHM_RSASHA256_NSEC3_NAME,"8", NULL};
128 static const char *rsasha512_names[] = {DNSKEY_ALGORITHM_RSASHA512_NSEC3_NAME,"10", NULL};
129 #if HAS_ECDSA_SUPPORT
130 static const char *ecdsap256sha256_names[] = {DNSKEY_ALGORITHM_ECDSAP256SHA256_NAME,"13", NULL};
131 static const char *ecdsap384sha384_names[] = {DNSKEY_ALGORITHM_ECDSAP384SHA384_NAME,"14", NULL};
132 #endif
133 #if HAS_EDDSA_SUPPORT
134 static const char *ed25619_names[] = { DNSKEY_ALGORITHM_ED25519_NAME, "15", NULL};
135 static const char *ed448_names[] = { DNSKEY_ALGORITHM_ED448_NAME, "16", NULL};
136 #endif
137 #ifdef DNSKEY_ALGORITHM_DUMMY
138 static const char *dnskey_dummy_names[] = {DNSKEY_ALGORITHM_DUMMY_NAME,"254", NULL};
139 #endif
140 //static const char *empty_names[] = {NULL};
141 
142 static const struct dnskey_features dnskey_supported_algorithms[] =
143 {
144     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 0
145     {
146         rsamd5_names,
147         512,4096,
148         2048,
149         1024,
150         1,
151         DNSKEY_ALGORITHM_RSAMD5,
152         DNSKEY_FEATURE_ZONE_NSEC
153     },
154     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 2
155     {
156         dsasha1_names,
157         512,1024,
158         1024,
159         1024,
160         64,
161         DNSKEY_ALGORITHM_DSASHA1,
162         DNSKEY_FEATURE_ZONE_NSEC
163     },
164     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 4
165     {
166         rsasha1_names,
167         512,4096,
168         2048,
169         1024,
170         1,
171         DNSKEY_ALGORITHM_RSASHA1,
172         DNSKEY_FEATURE_ZONE_NSEC
173     },
174     {
175         dsasha1nsec3_names,
176         512,1024,
177         1024,
178         1024,
179         64,
180         DNSKEY_ALGORITHM_DSASHA1_NSEC3,
181         DNSKEY_FEATURE_ZONE_NSEC3
182     },
183     {
184         rsasha1nsec3_names,
185         512,4096,
186         2048,
187         1024,
188         1,
189         DNSKEY_ALGORITHM_RSASHA1_NSEC3,
190         DNSKEY_FEATURE_ZONE_NSEC3
191     },
192     {
193         rsasha256_names,
194         512,4096,
195         2048,
196         1024,
197         1,
198         DNSKEY_ALGORITHM_RSASHA256_NSEC3,
199         DNSKEY_FEATURE_ZONE_MODERN
200     },
201     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 9
202     {
203         rsasha512_names,
204         1024,4096,
205         2048,
206         1024,
207         1,
208         DNSKEY_ALGORITHM_RSASHA512_NSEC3,
209         DNSKEY_FEATURE_ZONE_MODERN
210     },
211     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 11
212     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 12
213 #if HAS_ECDSA_SUPPORT
214     {
215         ecdsap256sha256_names,
216         256,256,
217         256,
218         256,
219         1,
220         DNSKEY_ALGORITHM_ECDSAP256SHA256,
221         DNSKEY_FEATURE_ZONE_MODERN
222     },
223     {
224         ecdsap384sha384_names,
225         384,384,
226         384,
227         384,
228         1,
229         DNSKEY_ALGORITHM_ECDSAP384SHA384,
230         DNSKEY_FEATURE_ZONE_MODERN
231     },
232 #else
233     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 13
234     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 14
235 #endif
236 #if HAS_EDDSA_SUPPORT
237         {
238         ed25619_names,
239         0,0,
240         0,
241         0,
242         1,
243         DNSKEY_ALGORITHM_ED25519,
244         DNSKEY_FEATURE_ZONE_MODERN
245     },
246     {
247         ed448_names,
248         0,0,
249         0,
250         0,
251         1,
252         DNSKEY_ALGORITHM_ED448,
253         DNSKEY_FEATURE_ZONE_MODERN
254     },
255 #else
256     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 15
257     //{NULL, 0, 0, 0, 0, 0, 0, 0}, // 16
258 #endif
259 #ifdef DNSKEY_ALGORITHM_DUMMY
260     {
261         dnskey_dummy_names,
262         16,16,
263         16,
264         16,
265         16,
266         DNSKEY_ALGORITHM_DUMMY,
267         DNSKEY_FEATURE_ZONE_MODERN
268     },
269 #endif
270     /*
271     {   // terminator
272         empty_names,
273         0,0,
274         0,
275         0,
276         0,
277         0
278     }*/
279 };
280 
281 static const char *
dnskey_get_algorithm_name_from_value(int alg)282 dnskey_get_algorithm_name_from_value(int alg)
283 {
284     switch(alg)
285     {
286         case DNSKEY_ALGORITHM_RSAMD5:
287             return "RSAMD5";
288         case DNSKEY_ALGORITHM_DIFFIE_HELLMAN:
289             return "DH";
290         case DNSKEY_ALGORITHM_DSASHA1:
291             return "DSASHA1";
292         case DNSKEY_ALGORITHM_RSASHA1:
293             return "RSASHA1";
294         case DNSKEY_ALGORITHM_DSASHA1_NSEC3:
295             return "NSEC3DSA";
296         case DNSKEY_ALGORITHM_RSASHA1_NSEC3:
297             return "NSEC3RSASHA1";
298         case DNSKEY_ALGORITHM_RSASHA256_NSEC3:
299             return "RSASHA256";
300         case DNSKEY_ALGORITHM_RSASHA512_NSEC3:
301             return "RSASHA512";
302         case DNSKEY_ALGORITHM_GOST:
303             return "ECCGOST";
304         case DNSKEY_ALGORITHM_ECDSAP256SHA256:
305             return "ECDSAP256SHA256";
306         case DNSKEY_ALGORITHM_ECDSAP384SHA384:
307             return "ECDSAP384SHA384";
308         case DNSKEY_ALGORITHM_ED25519:
309             return "ED25519";
310         case DNSKEY_ALGORITHM_ED448:
311             return "ED448";
312 #ifdef DNSKEY_ALGORITHM_DUMMY
313         case DNSKEY_ALGORITHM_DUMMY:
314             return "DUMMY";
315 #endif
316         default:
317             return "?";
318     }
319 }
320 
321 static ya_result
dnskey_field_parser_dummy_parse_field(struct dnskey_field_parser * parser,struct parser_s * p)322 dnskey_field_parser_dummy_parse_field(struct dnskey_field_parser *parser, struct parser_s *p)
323 {
324     (void)parser;
325     (void)p;
326     return FEATURE_NOT_IMPLEMENTED_ERROR;
327 }
328 
329 static ya_result
dnskey_field_parser_dummy_set_key(struct dnskey_field_parser * parser,dnssec_key * key)330 dnskey_field_parser_dummy_set_key(struct dnskey_field_parser *parser, dnssec_key *key)
331 {
332     (void)parser;
333     (void)key;
334     return FEATURE_NOT_IMPLEMENTED_ERROR;
335 }
336 
337 static void
dnskey_field_parser_dummy_finalize_method(struct dnskey_field_parser * parser)338 dnskey_field_parser_dummy_finalize_method(struct dnskey_field_parser *parser)
339 {
340     (void)parser;
341 }
342 
343 struct dnskey_field_parser_vtbl dnskey_field_dummy_parser =
344 {
345     dnskey_field_parser_dummy_parse_field,
346     dnskey_field_parser_dummy_set_key,
347     dnskey_field_parser_dummy_finalize_method,
348     "DUMMY"
349 };
350 
351 ya_result
dnskey_field_access_parse(const struct dnskey_field_access * sd,void * base,parser_s * p)352 dnskey_field_access_parse(const struct dnskey_field_access *sd, void *base, parser_s *p)
353 {
354     ya_result ret = INVALID_STATE_ERROR;
355 
356     u32 label_len = parser_text_length(p);
357     const char *label = parser_text(p);
358     bool parsed_it = FALSE;
359     u8 tmp_out[DNSSEC_MAXIMUM_KEY_SIZE_BYTES];
360 
361     for(; sd->type != STRUCTDESCRIPTOR_NONE; sd++)
362     {
363         switch(sd->type)
364         {
365             case STRUCTDESCRIPTOR_BN:
366             {
367                 if(memcmp(label, sd->name, label_len) == 0)
368                 {
369                     BIGNUM **bnp = (BIGNUM**)(((u8*)base) + sd->relative);
370 
371                     ret = parser_next_word(p);
372 
373                     if((*bnp != NULL) || FAIL(ret))
374                     {
375                         return ret;
376                     }
377 
378                     u32 word_len = parser_text_length(p);
379                     const char *word = parser_text(p);
380 
381                     ya_result n = base64_decode(word, word_len, tmp_out);
382 
383                     if(FAIL(n))
384                     {
385                         log_err("dnskey: unable to decode field %s", sd->name);
386                         return n;
387                     }
388 
389                     *bnp = BN_bin2bn(tmp_out, n, NULL);
390 
391                     if(*bnp == NULL)
392                     {
393                         log_err("dnskey: unable to get big number from field %s", sd->name);
394                         return DNSSEC_ERROR_BNISNULL;
395                     }
396 
397                     parsed_it = TRUE;
398 
399                     goto dnskey_field_access_parse_loop_exit;
400                 }
401 
402                 break;
403             }
404             case STRUCTDESCRIPTOR_RAW:
405             {
406                 if(memcmp(label, sd->name, label_len) == 0)
407                 {
408                     dnskey_raw_field_t *raw = (dnskey_raw_field_t*)(((u8*)base) + sd->relative);
409 
410                     ret = parser_next_word(p);
411 
412                     if((raw->buffer != NULL) || FAIL(ret))
413                     {
414                         return ret;
415                     }
416 
417                     u32 word_len = parser_text_length(p);
418                     const char *word = parser_text(p);
419 
420                     ya_result n = base64_decode(word, word_len, tmp_out);
421 
422                     if(FAIL(n))
423                     {
424                         log_err("dnskey: unable to decode field %s", sd->name);
425                         return n;
426                     }
427 
428                     ZALLOC_OBJECT_ARRAY_OR_DIE(raw->buffer, u8, n, DNSKRAWB_TAG);
429                     memcpy(raw->buffer, tmp_out, n);
430                     raw->size = n;
431 
432                     parsed_it = TRUE;
433 
434                     goto dnskey_field_access_parse_loop_exit;
435                 }
436                 break;
437             }
438         }
439     } /* for each possible field */
440 dnskey_field_access_parse_loop_exit:
441     if(!parsed_it)
442     {
443         return SUCCESS; // unknown keyword (ignore)
444     }
445 
446     return ret;
447 }
448 
449 ya_result
dnskey_field_access_print(const struct dnskey_field_access * sd,const void * base,output_stream * os)450 dnskey_field_access_print(const struct dnskey_field_access *sd, const void *base, output_stream *os)
451 {
452     ya_result ret = SUCCESS;
453 
454     for(; sd->type != STRUCTDESCRIPTOR_NONE; sd++)
455     {
456         switch(sd->type)
457         {
458             case STRUCTDESCRIPTOR_BN:
459             {
460                 const u8 *bn_ptr_ptr = (((const u8*)base) + sd->relative);
461                 const BIGNUM **bn = (const BIGNUM**)bn_ptr_ptr;
462 
463                 if(bn != NULL)
464                 {
465                     osformat(os, "%s: ", sd->name);
466                     dnskey_write_bignum_as_base64_to_stream(*bn, os);
467                     osprintln(os, "");
468                 }
469                 break;
470             }
471             case STRUCTDESCRIPTOR_RAW:
472             {
473                 const u8 *bn_ptr_ptr = (((const u8*)base) + sd->relative);
474                 const dnskey_raw_field_t *raw = (const dnskey_raw_field_t *)bn_ptr_ptr;
475 
476                 osformat(os, "%s: ", sd->name);
477 
478                 char buffer[1024];
479                 u32 encoded_size = BASE64_ENCODED_SIZE(raw->size);
480                 if(encoded_size > sizeof(buffer))
481                 {
482                     return BUFFER_WOULD_OVERFLOW;
483                 }
484                 u32 n = base64_encode(raw->buffer, raw->size, buffer);
485                 output_stream_write(os, buffer, n);
486                 osprintln(os, "");
487                 break;
488             }
489             case STRUCTDESCRIPTOR_U16:
490             {
491                 const u8 *bn_ptr_ptr = (((const u8*)base) + sd->relative);
492                 const u16 *valuep = (const u16 *)bn_ptr_ptr;
493                 osformat(os, "%s: %hu", sd->name, *valuep);
494                 break;
495             }
496         }
497     }
498 
499     return ret;
500 }
501 
502 /*
503 
504 unsigned long ac;     * assumed to be 32 bits or larger *
505 int i;                * loop index *
506 
507 for ( ac = 0, i = 0; i < keysize; ++i )
508        ac += (i & 1) ? key[i] : key[i] << 8;
509 ac += (ac >> 16) & 0xFFFF;
510 return ac & 0xFFFF;
511 
512 =>
513 
514 s=0;
515 s+=key[0]
516 s+=key[1]<<8
517 s+=key[2]
518 s+=key[3]<<8
519 
520 Basically it's a sum of little-endian unsigned 16 bits words
521 And the reference implementation does not match the definition.
522 
523 "ignoring any carry bits" Yes ? So this is wrong : ac += (i & 1) ? key[i] : key[i] << 8;
524 The least significant byte will have the add carry bit carried to the most signiticant byte.
525 
526  */
527 
528 /**
529  * Generates a key tag from the DNSKEY RDATA wire
530  *
531  * @param dnskey_rdata
532  * @param dnskey_rdata_size
533  * @return
534  */
535 
536 u16
dnskey_get_tag_from_rdata(const u8 * dnskey_rdata,u32 dnskey_rdata_size)537 dnskey_get_tag_from_rdata(const u8* dnskey_rdata, u32 dnskey_rdata_size)
538 {
539     u32 sum = 0;
540     u32 sumh = 0;
541     while(dnskey_rdata_size > 1)
542     {
543         sumh += *dnskey_rdata++;
544         sum += *dnskey_rdata++;
545         dnskey_rdata_size -= 2;
546     }
547     if(dnskey_rdata_size != 0)
548     {
549         sumh += *dnskey_rdata++;
550     }
551     sum += sumh << 8;
552     sum += sum >> 16;
553 
554     return (u16)sum;
555 }
556 
557 
558 
559 /**
560  * Initialises the context for a key algorithm.
561  *
562  * @param ctx
563  * @param algorithm
564  * @return
565  */
566 
567 ya_result
dnskey_digest_init(digest_s * ctx,u8 algorithm)568 dnskey_digest_init(digest_s *ctx, u8 algorithm)
569 {
570     switch(algorithm)
571     {
572         case DNSKEY_ALGORITHM_DSASHA1:
573         case DNSKEY_ALGORITHM_RSASHA1:
574         case DNSKEY_ALGORITHM_DSASHA1_NSEC3:
575         case DNSKEY_ALGORITHM_RSASHA1_NSEC3:
576             digest_sha1_init(ctx);
577             break;
578         case DNSKEY_ALGORITHM_RSASHA256_NSEC3:
579         case DNSKEY_ALGORITHM_ECDSAP256SHA256:
580             digest_sha256_init(ctx);
581             break;
582         case DNSKEY_ALGORITHM_ECDSAP384SHA384:
583             digest_sha384_init(ctx);
584             break;
585         case DNSKEY_ALGORITHM_RSASHA512_NSEC3:
586             digest_sha512_init(ctx);
587             break;
588 #if HAS_EDDSA_SUPPORT
589         case DNSKEY_ALGORITHM_ED25519:
590         case DNSKEY_ALGORITHM_ED448:
591             digest_rawdata_init(ctx);
592             break;
593 #endif
594 #ifdef DNSKEY_ALGORITHM_DUMMY
595         case DNSKEY_ALGORITHM_DUMMY:
596             break;
597 #endif
598         default:
599             return DNSSEC_ERROR_UNSUPPORTEDKEYALGORITHM;
600     }
601 
602     return SUCCESS;
603 }
604 
605 /**
606  * Generate the RDATA of a DS records using the RDATA from a DSNKEY record
607  *
608  * @param digest_type the type of DS
609  * @param dnskey_fqdn the domain of the record
610  * @param dnskey_rdata the rdata of the DNSKEY
611  * @param dnskey_rdata_size the size of the rdata of the DNSKEY
612  * @param out_rdata the output buffer that has to be the right size (known given digest_type)
613  * @return
614  */
615 
616 ya_result
dnskey_generate_ds_rdata(u8 digest_type,const u8 * dnskey_fqdn,const u8 * dnskey_rdata,u16 dnskey_rdata_size,u8 * out_rdata)617 dnskey_generate_ds_rdata(u8 digest_type, const u8 *dnskey_fqdn, const u8 *dnskey_rdata,u16 dnskey_rdata_size, u8 *out_rdata)
618 {
619     digest_s ctx;
620 
621     s32 digest_size;
622 
623     switch(digest_type)
624     {
625         case DS_DIGEST_SHA1:
626             digest_sha1_init(&ctx);
627             break;
628         case DS_DIGEST_SHA256:
629             digest_sha256_init(&ctx);
630             break;
631         default:
632             return DNSSEC_ERROR_UNSUPPORTEDDIGESTALGORITHM;
633     }
634 
635     digest_size = digest_get_size(&ctx);
636 
637     u16 tag = dnskey_get_tag_from_rdata(dnskey_rdata, dnskey_rdata_size);
638     u8 algorithm = dnskey_rdata[3];
639 
640     digest_update(&ctx, dnskey_fqdn, dnsname_len(dnskey_fqdn));
641     digest_update(&ctx, dnskey_rdata, dnskey_rdata_size);
642 
643     out_rdata[0] = tag >> 8;
644     out_rdata[1] = tag;
645     out_rdata[2] = algorithm;
646     out_rdata[3] = digest_type;
647 
648     digest_final_copy_bytes(&ctx, &out_rdata[4], digest_size); // generates DS record : safe use
649 
650     return 4 + digest_size;
651 }
652 
653 /**
654  * Sanitises an text origin and returns a zallocated copy of it
655  *
656  * @param origin
657  * @return a sanitized zallocated copy of origin
658  */
659 
660 static char*
dnskey_origin_zdup_sanitize(const char * origin)661 dnskey_origin_zdup_sanitize(const char* origin)
662 {
663     char* ret;
664 
665     if(origin == NULL)
666     {
667         ZALLOC_OBJECT_ARRAY_OR_DIE(ret, char, 2, ORIGNDUP_TAG);
668         ret[0] = '.';
669         ret[1] = '\0';
670         return ret;
671     }
672 
673     int origin_len = strlen(origin);
674 
675     if(origin_len == 0)
676     {
677         ZALLOC_OBJECT_ARRAY_OR_DIE(ret, char, 2, ORIGNDUP_TAG);
678         ret[0] = '.';
679         ret[1] = '\0';
680         return ret;
681     }
682 
683     if(origin[origin_len - 1] == '.')
684     {
685         origin_len++;
686         ZALLOC_OBJECT_ARRAY_OR_DIE(ret, char, origin_len, ORIGNDUP_TAG);
687         //MEMCOPY(ret, origin, origin_len);
688         for(int i = 0; i < origin_len; i++)
689         {
690             ret[i] = tolower(origin[i]);
691         }
692     }
693     else
694     {
695         ZALLOC_OBJECT_ARRAY_OR_DIE(ret, char, (origin_len + 2), ORIGNDUP_TAG);
696         //MEMCOPY(ret, origin, origin_len);
697         for(int i = 0; i < origin_len; i++)
698         {
699             ret[i] = tolower(origin[i]);
700         }
701         ret[origin_len++] = '.'; // VS false positive (nonsense)
702         ret[origin_len] = '\0';
703     }
704 
705     return ret;
706 }
707 
708 /**
709  * Initialises an empty instance of a DNSKEY
710  * No cryptographic content is put in the key.
711  * Needs further setup.
712  *
713  * @param algorithm the algorithm of the key.
714  * @param flags the flags of the key
715  * @param origin the origin of the key
716  *
717  * @return a pointer to an empty instance (no real key attached) of a key.
718  */
719 
720 dnssec_key*
dnskey_newemptyinstance(u8 algorithm,u16 flags,const char * origin)721 dnskey_newemptyinstance(u8 algorithm, u16 flags, const char *origin)
722 {
723     yassert(origin != NULL);
724 
725     char *origin_copy = dnskey_origin_zdup_sanitize(origin);
726 
727     u8 *owner_name = dnsname_zdup_from_name(origin_copy);
728     if(owner_name == NULL)
729     {
730         log_err("dnskey_newemptyinstance(%hhu, %hx, %s = '%s'): origin parameter is not a domain name", algorithm, flags, origin, origin_copy);
731         ZFREE_ARRAY(origin_copy, strlen(origin_copy) + 1);
732         return NULL;
733     }
734 
735     dnssec_key* key;
736 
737     ZALLOC_OBJECT_OR_DIE( key, dnssec_key, ZDB_DNSKEY_TAG);
738     ZEROMEMORY(key, sizeof(dnssec_key));
739 
740     key->origin = origin_copy;
741 
742     /* origin is allocated with ZALLOC using ZALLOC_STRING_OR_DIE
743      * In this mode, the byte before the pointer is the size of the string.
744      */
745 
746     key->owner_name = owner_name;
747 
748     key->rc = 1;
749 
750     key->epoch_created = 0;
751     key->epoch_publish = 0;
752     key->epoch_activate = 0;
753 
754     /*
755     key->epoch_inactive = 0;
756     key->epoch_delete = 0;
757     */
758     key->flags = flags;
759     key->algorithm = algorithm;
760     /*key->status = 0;*/
761     /*key->key.X=....*/
762     /*key->tag=00000*/
763     /*key->is_private=TRUE;*/
764 
765     log_debug("dnskey_newemptyinstance: %{dnsname} +%03d+-----/%d status=%x rc=%i (%p)", dnskey_get_domain(key), key->algorithm, ntohs(key->flags), key->status, key->rc, key);
766 
767     return key;
768 }
769 
770 /**
771  * Increases the reference count on a dnssec_key
772  *
773  * @param key
774  */
775 
776 #if DUMP_ACQUIRE_RELEASE_STACK_TRACE
dnskey_acquire_debug()777 static void dnskey_acquire_debug()
778 {
779     stacktrace st = debug_stacktrace_get();
780     debug_stacktrace_log_with_prefix(MODULE_MSG_HANDLE, MSG_DEBUG, st, "dnskey_acquire: ");
781 }
782 
dnskey_release_debug()783 static void dnskey_release_debug()
784 {
785     stacktrace st = debug_stacktrace_get();
786     debug_stacktrace_log_with_prefix(MODULE_MSG_HANDLE, MSG_DEBUG, st, "dnskey_release: ");
787 }
788 #endif
789 
790 void
dnskey_acquire(dnssec_key * key)791 dnskey_acquire(dnssec_key *key)
792 {
793     yassert(key->rc > 0);
794     log_debug("dnskey_acquire: %{dnsname} +%03d+%05d/%d status=%x rc=%i (%p)", dnskey_get_domain(key), key->algorithm, key->tag, ntohs(key->flags), key->status, key->rc + 1, key);
795     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
796     ++key->rc;
797 #if DUMP_ACQUIRE_RELEASE_STACK_TRACE
798     dnskey_acquire_debug();
799 #endif
800     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
801 }
802 
803 /**
804  * Releases the reference count on a dnssec_key.
805  * If the reference count reaches zero, destroys the key.
806  *
807  * @param a
808  * @param b
809  */
810 
811 void
dnskey_release(dnssec_key * key)812 dnskey_release(dnssec_key *key)
813 {
814     yassert(key != NULL && key->rc > 0);
815 
816     log_debug("dnskey_release: %{dnsname} +%03d+%05d/%d status=%x rc=%i (%p)", dnskey_get_domain(key), key->algorithm, key->tag, ntohs(key->flags), key->status, key->rc - 1, key);
817 
818 #if DUMP_ACQUIRE_RELEASE_STACK_TRACE
819     dnskey_release_debug();
820 #endif
821 
822     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
823     if(--key->rc == 0)
824     {
825         group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
826 
827 #if DEBUG
828         if(key->next != NULL)
829         {
830             // log_err("dnskey_release(%p): a key should be detached from its list before destruction", key);
831             logger_flush();
832             abort();
833         }
834 #endif
835 
836         if(key->vtbl != NULL)
837         {
838             key->vtbl->dnssec_key_free(key);
839         }
840 
841         ZFREE_ARRAY(key->origin, strlen(key->origin) + 1); // +1 because the 0 has to be taken in account too (duh!)
842         dnsname_zfree(key->owner_name);
843 #if DEBUG
844         memset(key, 0xfe, sizeof(dnssec_key));
845 #endif
846         ZFREE(key, dnssec_key);
847     }
848     else
849     {
850         group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
851     }
852 }
853 
854 /**
855  * Generate a (public) key using the RDATA
856  *
857  * RC ok
858  *
859  * @param rdata
860  * @param rdata_size
861  * @param origin
862  * @param out_key points to  a pointer for the instantiated key
863  *
864  * @return an error code (success or error)
865  */
866 
867 ya_result
dnskey_new_from_rdata(const u8 * rdata,u16 rdata_size,const u8 * fqdn,dnssec_key ** out_key)868 dnskey_new_from_rdata(const u8 *rdata, u16 rdata_size, const u8 *fqdn, dnssec_key **out_key)
869 {
870     if(out_key == NULL)
871     {
872         return UNEXPECTED_NULL_ARGUMENT_ERROR;
873     }
874 
875     ya_result return_value;
876     u8 algorithm = rdata[3];
877     char origin[MAX_DOMAIN_LENGTH];
878 
879     dnsname_to_cstr(origin, fqdn);
880 
881     *out_key = NULL;
882 
883     switch(algorithm)
884     {
885         case DNSKEY_ALGORITHM_RSASHA1:
886         case DNSKEY_ALGORITHM_RSASHA1_NSEC3:
887         case DNSKEY_ALGORITHM_RSASHA256_NSEC3:
888         case DNSKEY_ALGORITHM_RSASHA512_NSEC3:
889             return_value = dnskey_rsa_loadpublic(rdata, rdata_size, origin, out_key); // RC
890             break;
891 
892         case DNSKEY_ALGORITHM_DSASHA1:
893         case DNSKEY_ALGORITHM_DSASHA1_NSEC3:
894             return_value = dnskey_dsa_loadpublic(rdata, rdata_size, origin, out_key); // RC
895             break;
896 #if HAS_ECDSA_SUPPORT
897         case DNSKEY_ALGORITHM_ECDSAP256SHA256:
898         case DNSKEY_ALGORITHM_ECDSAP384SHA384:
899             return_value = dnskey_ecdsa_loadpublic(rdata, rdata_size, origin, out_key); // RC
900             break;
901 #endif
902 #if HAS_EDDSA_SUPPORT
903         case DNSKEY_ALGORITHM_ED25519:
904         case DNSKEY_ALGORITHM_ED448:
905             return_value = dnskey_eddsa_loadpublic(rdata, rdata_size, origin, out_key); // RC
906             break;
907 #endif
908 #ifdef DNSKEY_ALGORITHM_DUMMY
909         case DNSKEY_ALGORITHM_DUMMY:
910             return_value = dnskey_dummy_loadpublic(rdata, rdata_size, origin, out_key);
911             break;
912 #endif
913         default:
914             return_value = DNSSEC_ERROR_UNSUPPORTEDKEYALGORITHM;
915             break;
916     }
917 
918     return return_value;
919 }
920 
921 /**
922  * Writes a BIGNUM integer to a stream
923  */
924 
925 ya_result
dnskey_write_bignum_as_base64_to_stream(const BIGNUM * num,output_stream * os)926 dnskey_write_bignum_as_base64_to_stream(const BIGNUM *num, output_stream *os)
927 {
928     u8 *buffer;
929     char *buffer2;
930     u8 buffer_[4096];
931     char buffer2_[4096];
932 
933     if(num == NULL)
934     {
935         return DNSSEC_ERROR_BNISNULL;
936     }
937 
938     u32 n = BN_num_bytes(num);
939     u32 m = BASE64_ENCODED_SIZE(n);
940 
941     if(n <= sizeof(buffer_))
942     {
943         buffer = buffer_;
944     }
945     else
946     {
947         MALLOC_OBJECT_ARRAY_OR_DIE(buffer, u8, n, TMPBUFFR_TAG);
948         //buffer = (u8*)malloc(n);
949     }
950 
951     if(m <= sizeof(buffer2_))
952     {
953         buffer2 = buffer2_;
954     }
955     else
956     {
957         MALLOC_OBJECT_ARRAY_OR_DIE(buffer2, char, m, TMPBUFFR_TAG);
958         //buffer2 = (char*)malloc(m);
959     }
960 
961     BN_bn2bin(num, buffer);
962 
963     u32 o = base64_encode(buffer,n,buffer2);
964 
965     yassert(o <= m);
966 
967     output_stream_write(os, buffer2, o);
968 
969     if(buffer != buffer_) free(buffer);
970     if(buffer2 != buffer2_) free(buffer2);
971 
972     return SUCCESS;
973 }
974 
975 /**
976  * Returns the most relevant publication time.
977  *
978  * publish > activate > created > now
979  *
980  * @param key
981  * @return
982  */
983 
984 time_t
dnskey_get_publish_epoch(const dnssec_key * key)985 dnskey_get_publish_epoch(const dnssec_key *key)
986 {
987     u32 ret;
988 
989     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
990 
991     if(key->epoch_publish != 0)
992     {
993         ret = key->epoch_publish;
994     }
995     else if(key->epoch_activate != 0)
996     {
997         ret = key->epoch_activate;
998     }
999     else if(key->epoch_created != 0)
1000     {
1001         ret = key->epoch_created;
1002     }
1003     else
1004     {
1005         ret = 0; // of course, the last if/else could be replaced by ret = key->epoch_created
1006     }
1007 
1008     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
1009 
1010     return ret;
1011 }
1012 
1013 void
dnskey_set_created_epoch(dnssec_key * key,time_t t)1014 dnskey_set_created_epoch(dnssec_key *key, time_t t)
1015 {
1016     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1017     key->epoch_created = t;
1018     key->status |= DNSKEY_KEY_HAS_SMART_FIELD_CREATED;
1019     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1020 }
1021 
1022 void
dnskey_set_publish_epoch(dnssec_key * key,time_t t)1023 dnskey_set_publish_epoch(dnssec_key *key, time_t t)
1024 {
1025     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1026     key->epoch_publish = t;
1027     key->status |= DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH;
1028     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1029 }
1030 
1031 /**
1032  * Returns the most relevant activation time.
1033  *
1034  * activate > publish > created > now
1035  *
1036  * @param key
1037  * @return
1038  */
1039 
1040 time_t
dnskey_get_activate_epoch(const dnssec_key * key)1041 dnskey_get_activate_epoch(const dnssec_key *key)
1042 {
1043     u32 ret;
1044 
1045     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1046 
1047     if(key->epoch_activate != 0)
1048     {
1049         ret = key->epoch_activate;
1050     }
1051     else if(key->epoch_publish != 0)
1052     {
1053         ret = key->epoch_publish;
1054     }
1055     else if(key->epoch_created != 0)
1056     {
1057         ret = key->epoch_created;
1058     }
1059     else
1060     {
1061         ret = 0;
1062     }
1063 
1064     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1065 
1066     return ret;
1067 }
1068 
1069 void
dnskey_set_activate_epoch(dnssec_key * key,time_t t)1070 dnskey_set_activate_epoch(dnssec_key *key, time_t t)
1071 {
1072     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1073     key->epoch_activate = t;
1074     key->status |= DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE;
1075     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1076 }
1077 
1078 
1079 
1080 
1081 /**
1082  * Returns the most relevant inactivation time.
1083  *
1084  * inactive > delete > never
1085  *
1086  * @param key
1087  * @return
1088  */
1089 
1090 time_t
dnskey_get_inactive_epoch(const dnssec_key * key)1091 dnskey_get_inactive_epoch(const dnssec_key *key)
1092 {
1093     u32 ret;
1094 
1095     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1096 
1097     if(key->epoch_inactive != 0)
1098     {
1099         ret = key->epoch_inactive;
1100     }
1101     else if(key->epoch_activate != 0)
1102     {
1103         // if activation was a lie, inactivation is one too anyway
1104         if((key->epoch_created != 0) && (key->epoch_delete > key->epoch_created))
1105         {
1106             s64 leniency = (key->epoch_delete - key->epoch_created) / 4;
1107 
1108             if(leniency > 86400)
1109             {
1110                 leniency = 86400;
1111             }
1112 
1113             s64 inactive_epoch = key->epoch_delete - leniency;
1114 
1115             if(inactive_epoch > MAX_S32) inactive_epoch = MAX_S32;
1116             ret = (s32)inactive_epoch;
1117         }
1118         else
1119         {
1120             ret = MAX_S32;
1121         }
1122     }
1123     else
1124     {
1125         ret = MAX_S32; // don't use MAX_U32 here
1126     }
1127 
1128     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1129 
1130     return ret;
1131 }
1132 
1133 void
dnskey_set_inactive_epoch(dnssec_key * key,time_t t)1134 dnskey_set_inactive_epoch(dnssec_key *key, time_t t)
1135 {
1136     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1137     key->epoch_inactive = t;
1138     key->status |= DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE;
1139     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1140 }
1141 
1142 /**
1143  * Returns the most relevant delete time.
1144  *
1145  * delete > inactive > never
1146  *
1147  * @param key
1148  * @return
1149  */
1150 
1151 time_t
dnskey_get_delete_epoch(const dnssec_key * key)1152 dnskey_get_delete_epoch(const dnssec_key *key)
1153 {
1154     u32 ret;
1155 
1156     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
1157 
1158     if(key->epoch_delete != 0)
1159     {
1160         ret = key->epoch_delete;
1161     }
1162     else if(key->epoch_publish == 0)
1163     {
1164         // if publication was a lie, delete is one too anyway
1165         if((key->epoch_created != 0) && (key->epoch_inactive > key->epoch_activate))
1166         {
1167             s64 leniency = (key->epoch_inactive - key->epoch_activate) / 4;
1168 
1169             if(leniency > 86400)
1170             {
1171                 leniency = 86400;
1172             }
1173 
1174             s64 delete_epoch = key->epoch_inactive + leniency;
1175 
1176             if(delete_epoch > MAX_S32) delete_epoch = MAX_S32;
1177             ret = (s32)delete_epoch;
1178         }
1179         else
1180         {
1181             ret = MAX_S32;
1182         }
1183     }
1184     else
1185     {
1186         ret = MAX_S32; // don't use MAX_U32 here
1187     }
1188 
1189     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
1190 
1191     return ret;
1192 }
1193 
1194 void
dnskey_set_delete_epoch(dnssec_key * key,time_t t)1195 dnskey_set_delete_epoch(dnssec_key *key, time_t t)
1196 {
1197     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1198     key->epoch_delete= t;
1199     key->status |= DNSKEY_KEY_HAS_SMART_FIELD_DELETE;
1200     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1201 }
1202 
1203 /**
1204  *
1205  * Compares two keys for equality on a cryptographic point of view
1206  * Uses the tag, flags, algorithm, origin and key content.
1207  *
1208  * @param a
1209  * @param b
1210  *
1211  * @return TRUE iff the keys are the same.
1212  */
1213 
1214 bool
dnskey_equals(const dnssec_key * a,const dnssec_key * b)1215 dnskey_equals(const dnssec_key* a, const dnssec_key* b)
1216 {
1217     if(a == b)
1218     {
1219         return TRUE;
1220     }
1221 
1222     if(dnssec_key_tag_field_set(a) && dnssec_key_tag_field_set(b))
1223     {
1224        if(a->tag != b->tag)
1225        {
1226            return FALSE;
1227        }
1228     }
1229 
1230     if((a->flags == b->flags) && (a->algorithm == b->algorithm))
1231     {
1232         /* Compare the origin */
1233 
1234         if(strcmp(a->origin, b->origin) == 0)
1235         {
1236             /* Compare the content of the key */
1237 
1238             return a->vtbl->dnssec_key_equals(a, b);
1239         }
1240     }
1241 
1242     return FALSE;
1243 }
1244 
1245 /**
1246  *
1247  * Compares two keys for equality on a cryptographic point of view
1248  * Uses the tag, flags, algorithm, origin and public key content.
1249  *
1250  * @param a
1251  * @param b
1252  *
1253  * @return TRUE iff the keys are the same.
1254  */
1255 
1256 bool
dnskey_public_equals(const dnssec_key * a,const dnssec_key * b)1257 dnskey_public_equals(const dnssec_key *a, const dnssec_key *b)
1258 {
1259     if(a == b)
1260     {
1261         return TRUE;
1262     }
1263 
1264     if(dnssec_key_tag_field_set(a) && dnssec_key_tag_field_set(b))
1265     {
1266        if(a->tag != b->tag)
1267        {
1268            return FALSE;
1269        }
1270     }
1271 
1272     if((a->flags == b->flags) && (a->algorithm == b->algorithm))
1273     {
1274         /* Compare the origin */
1275 
1276         if(strcmp(a->origin, b->origin) == 0)
1277         {
1278             /* Compare the content of the key */
1279 
1280             u8 rdata_a[4096];
1281             u8 rdata_b[4096];
1282 
1283             u32 rdata_a_size = a->vtbl->dnssec_key_writerdata(a, rdata_a, sizeof(rdata_a));
1284             u32 rdata_b_size = b->vtbl->dnssec_key_writerdata(b, rdata_b, sizeof(rdata_b));
1285 
1286             if(rdata_a_size == rdata_b_size)
1287             {
1288                 bool ret = (memcmp(rdata_a, rdata_b, rdata_a_size) == 0);
1289                 return ret;
1290             }
1291         }
1292     }
1293 
1294     return FALSE;
1295 }
1296 
1297 /**
1298  * Returns TRUE if the tag and algorithm of the rdata are matching the ones of the key.
1299  *
1300  * @param key
1301  * @param rdata
1302  * @param rdata_size
1303  * @return
1304  */
1305 
1306 bool
dnskey_matches_rdata(const dnssec_key * key,const u8 * rdata,u16 rdata_size)1307 dnskey_matches_rdata(const dnssec_key *key, const u8 *rdata, u16 rdata_size)
1308 {
1309      if(dnskey_get_algorithm(key) == rdata[3])
1310      {
1311         u16 key_tag = dnskey_get_tag_const(key);
1312         u16 rdata_tag = dnskey_get_tag_from_rdata(rdata, rdata_size);
1313 
1314         return key_tag == rdata_tag;
1315      }
1316 
1317      return FALSE;
1318 }
1319 
1320 u16
dnskey_get_tag(dnssec_key * key)1321 dnskey_get_tag(dnssec_key *key)
1322 {
1323     if((dnskey_state_get(key) & DNSKEY_KEY_TAG_SET) == 0)
1324     {
1325         u8 rdata[2048];
1326 
1327         u32 rdata_size = key->vtbl->dnssec_key_writerdata(key, rdata, sizeof(rdata));
1328 
1329         yassert(rdata_size <= 2048);
1330 
1331         u16 tag = dnskey_get_tag_from_rdata(rdata, rdata_size);
1332 
1333         group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1334         key->tag = tag;
1335         key->status |= DNSKEY_KEY_TAG_SET;
1336         group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
1337     }
1338 
1339     return key->tag;
1340 }
1341 
1342 u16
dnskey_get_tag_const(const dnssec_key * key)1343 dnskey_get_tag_const(const dnssec_key *key)
1344 {
1345     u16 tag;
1346 
1347     if(key->status & DNSKEY_KEY_TAG_SET)
1348     {
1349         tag = key->tag;
1350     }
1351     else
1352     {
1353         u8 rdata[2048];
1354 
1355         u32 rdata_size = key->vtbl->dnssec_key_writerdata(key, rdata, sizeof(rdata));
1356 
1357         yassert(rdata_size <= 2048);
1358 
1359         tag = dnskey_get_tag_from_rdata(rdata, rdata_size);
1360     }
1361 
1362     return tag;
1363 }
1364 
1365 u8
dnskey_get_algorithm(const dnssec_key * key)1366 dnskey_get_algorithm(const dnssec_key *key)
1367 {
1368     return key->algorithm;
1369 }
1370 
1371 const u8 *
dnskey_get_domain(const dnssec_key * key)1372 dnskey_get_domain(const dnssec_key *key)
1373 {
1374     if(key != NULL)
1375     {
1376         return key->owner_name;
1377     }
1378     else
1379     {
1380         return (const u8*)"\004NULL";
1381     }
1382 }
1383 
1384 bool
dnskey_is_private(const dnssec_key * key)1385 dnskey_is_private(const dnssec_key *key)
1386 {
1387     return (key->status & DNSKEY_KEY_IS_PRIVATE) != 0;
1388 }
1389 
1390 /**
1391  * Adds/Remove a key from a key chain.
1392  * The 'next' field of the key is used.
1393  * A key can only be in one chain at a time.
1394  * This is meant to be used in the keystore.
1395  *
1396  * RC ok
1397  *
1398  * @param keyp
1399  */
1400 
1401 void
dnskey_add_to_chain(dnssec_key * key,dnssec_key ** prevp)1402 dnskey_add_to_chain(dnssec_key *key, dnssec_key **prevp)
1403 {
1404     yassert(key->next == NULL);
1405 
1406     u16 key_tag = dnskey_get_tag(key);
1407 
1408     while(*prevp != NULL)
1409     {
1410         if(dnskey_get_tag(*prevp) > key_tag)
1411         {
1412             key->next = *prevp;
1413             *prevp = key;
1414             dnskey_acquire(key);
1415             return;
1416         }
1417 
1418         prevp = &((*prevp)->next);
1419     }
1420 
1421     // append
1422 
1423     *prevp = key;
1424 
1425     dnskey_acquire(key);
1426 
1427     key->next = NULL;
1428 }
1429 
1430 /**
1431  * Adds/Remove a key from a key chain.
1432  * The 'next' field of the key is used.
1433  * A key can only be in one chain at a time.
1434  * This is meant to be used in the keystore.
1435  *
1436  * RC ok
1437  *
1438  * @param keyp
1439  */
1440 
1441 void
dnskey_remove_from_chain(dnssec_key * key,dnssec_key ** prevp)1442 dnskey_remove_from_chain(dnssec_key *key, dnssec_key **prevp)
1443 {
1444     u16 key_tag = dnskey_get_tag(key);
1445 
1446     while(*prevp != NULL)
1447     {
1448         u16 tag;
1449         if((tag = dnskey_get_tag(*prevp)) >= key_tag)
1450         {
1451             if(tag == key_tag)
1452             {
1453                 dnssec_key *key_to_release = *prevp;
1454                 *prevp = (*prevp)->next;
1455                 // now (and only now) the next field can (and must) be cleared
1456                 key_to_release->next = NULL;
1457                 dnskey_release(key_to_release);
1458             }
1459 
1460             break;
1461         }
1462 
1463         prevp = &((*prevp)->next);
1464     }
1465 }
1466 
1467 ya_result
dnskey_new_public_key_from_stream(input_stream * is,dnssec_key ** keyp)1468 dnskey_new_public_key_from_stream(input_stream *is, dnssec_key** keyp)
1469 {
1470     parser_s parser;
1471     ya_result ret;
1472     u16 rclass;
1473     u16 rtype;
1474     u16 flags;
1475     u16 rdata_size;
1476     char origin[MAX_DOMAIN_LENGTH + 1];
1477     u8 fqdn[MAX_DOMAIN_LENGTH];
1478     u8 rdata[1024 + 4];
1479 
1480     parser_init(&parser, "\"\"''", "()", ";#", "\040\t\r", "\\");
1481     parser.close_last_stream = FALSE;
1482     parser_push_stream(&parser, is);
1483 
1484     for(;;)
1485     {
1486         if(ISOK(ret = parser_next_token(&parser)))
1487         {
1488             if(!(ret & PARSER_WORD))
1489             {
1490                 if(ret & (PARSER_COMMENT|PARSER_EOL))
1491                 {
1492                     continue;
1493                 }
1494 
1495                 if(ret & PARSER_EOF)
1496                 {
1497                     input_stream *completed_stream = parser_pop_stream(&parser);
1498                     input_stream_close(completed_stream);
1499                     ret = UNEXPECTED_EOF;
1500                     break;
1501                 }
1502                 continue;
1503             }
1504         }
1505 
1506         const char *text = parser_text(&parser);
1507         u32 text_len = parser_text_length(&parser);
1508         memcpy(origin, text, text_len);
1509         origin[text_len] = '\0';
1510 
1511         if(FAIL(ret = cstr_to_dnsname_with_check_len(fqdn, text, text_len)))
1512         {
1513             break;
1514         }
1515 
1516         if(FAIL(ret = parser_copy_next_class(&parser, &rclass)))
1517         {
1518             break;
1519         }
1520 
1521         if(rclass != CLASS_IN)
1522         {
1523             // not IN
1524             ret = DNSSEC_ERROR_EXPECTED_CLASS_IN;
1525             break;
1526         }
1527 
1528         if(FAIL(ret = parser_copy_next_type(&parser, &rtype)))
1529         {
1530             break;
1531         }
1532 
1533         if(rtype != TYPE_DNSKEY)
1534         {
1535             // not DNSKEY
1536             ret = DNSSEC_ERROR_EXPECTED_TYPE_DNSKEY;
1537             break;
1538         }
1539 
1540         if(FAIL(ret = parser_copy_next_u16(&parser, &flags)))
1541         {
1542             break;
1543         }
1544 
1545         flags = htons(flags); // need to fix the endianness
1546         SET_U16_AT_P(rdata, flags);
1547 
1548         // protocol (8 bits integer)
1549 
1550         if(FAIL(ret = parser_copy_next_u8(&parser, &rdata[2])))
1551         {
1552             break;
1553         }
1554 
1555         // algorithm (8 bits integer)
1556 
1557         if(FAIL(ret = parser_copy_next_u8(&parser, &rdata[3])))
1558         {
1559             break;
1560         }
1561 
1562         // key (base64)
1563 
1564         if(FAIL(ret = parser_concat_next_tokens_nospace(&parser)))
1565         {
1566             break;
1567         }
1568 
1569         if(BASE64_DECODED_SIZE(ret) > (int)sizeof(rdata) - 4)
1570         {
1571             // overflow
1572             ret = DNSSEC_ERROR_UNEXPECTEDKEYSIZE;
1573             break;
1574         }
1575 
1576         if(FAIL(ret = base64_decode(parser_text(&parser), parser_text_length(&parser), &rdata[4])))
1577         {
1578             break;
1579         }
1580 
1581         if(ret > 1024)
1582         {
1583             ret = DNSSEC_ERROR_KEYISTOOBIG;
1584             break;
1585         }
1586 
1587         rdata_size = 4 + ret;
1588 
1589         ret = dnskey_new_from_rdata(rdata, rdata_size, fqdn, keyp); // RC
1590 
1591         break;
1592     }
1593 
1594     parser_finalize(&parser);
1595 
1596     return ret;
1597 }
1598 
1599 /**
1600  * Loads a public key from a file.
1601  *
1602  * ie: Keu.+007+12345.key
1603  *
1604  * RC ok
1605  *
1606  * @param filename
1607  * @param keyp
1608  * @return
1609  */
1610 
1611 ya_result
dnskey_new_public_key_from_file(const char * filename,dnssec_key ** keyp)1612 dnskey_new_public_key_from_file(const char *filename, dnssec_key** keyp)
1613 {
1614     input_stream is;
1615     ya_result ret;
1616 
1617 
1618     if(keyp == NULL)
1619     {
1620         return UNEXPECTED_NULL_ARGUMENT_ERROR;
1621     }
1622 
1623     *keyp = NULL;
1624 
1625     if(ISOK(ret = file_input_stream_open(&is, filename)))
1626     {
1627         ret = dnskey_new_public_key_from_stream(&is, keyp);
1628         input_stream_close(&is);
1629     }
1630 
1631     return ret;
1632 }
1633 
1634 ya_result
dnskey_add_private_key_from_stream(input_stream * is,dnssec_key * key,const char * path,u8 algorithm)1635 dnskey_add_private_key_from_stream(input_stream *is, dnssec_key *key, const char* path, u8 algorithm)
1636 {
1637     dnskey_field_parser dnskey_parser = {NULL, &dnskey_field_dummy_parser};
1638     parser_s parser;
1639     s64 timestamp;
1640     u32 smart_fields = 0;
1641     ya_result ret;
1642     u8 parsed_algorithm;
1643 
1644     if(path == NULL)
1645     {
1646         path = "";
1647     }
1648 
1649     // in case of error, the timestamp is set to 0
1650 
1651     fd_mtime(fd_input_stream_get_filedescriptor(is), &timestamp);
1652 
1653     if(ISOK(ret = parser_init(&parser,
1654                               "",      // by 2
1655                               "",      // by 2
1656                               "#;",    // by 1
1657                               " \t\r:", // by 1
1658                               ""       // by 1
1659     )))
1660     {
1661         parser.close_last_stream = FALSE;
1662 
1663         parser_push_stream(&parser, is);
1664 
1665         for(;;)
1666         {
1667             // get the next token
1668 
1669             if(ISOK(ret = parser_next_token(&parser)))
1670             {
1671                 if(!(ret & PARSER_WORD))
1672                 {
1673                     if(ret & (PARSER_COMMENT|PARSER_EOL))
1674                     {
1675                         continue;
1676                     }
1677                 }
1678                 if(ret & PARSER_EOF)
1679                 {
1680                     break;
1681                 }
1682             }
1683 
1684             // u32 label_len = parser_text_length(&parser);
1685             const char *label = parser_text(&parser);
1686             // makes the word asciiz (need to be undone)
1687             parser_text_asciiz(&parser);
1688 #if DEBUG
1689             log_debug("dnskey: parsing %s::%s", path, label);
1690 #endif
1691             string_node *node = string_set_find(&dnssec_key_load_private_keywords_set, label);
1692             // makes the word asciiz (need to be undone)
1693             parser_text_unasciiz(&parser);
1694 
1695             if(node != NULL)
1696             {
1697                 // push to management
1698 
1699                 // parse next word
1700 
1701                 if(FAIL(ret = parser_next_word(&parser)))
1702                 {
1703                     break;
1704                 }
1705 
1706                 u32 word_len = parser_text_length(&parser);
1707                 const char *word = parser_text(&parser);
1708 
1709                 switch(node->value)
1710                 {
1711                     case DNSKEY_FIELD_ALGORITHM:
1712                     {
1713                         if(ISOK(ret = parser_get_u8(word, word_len, &parsed_algorithm)))
1714                         {
1715                             if(algorithm == 0)
1716                             {
1717                                 algorithm = parsed_algorithm;
1718                             }
1719                             else if(parsed_algorithm != algorithm)
1720                             {
1721                                 log_err("dnssec: error parsing %s: expected algorithm version %i, got %i", path, algorithm, parsed_algorithm);
1722                                 ret = DNSSEC_ERROR_UNSUPPORTEDKEYALGORITHM;
1723                             }
1724 
1725                             parser_expect_eol(&parser);
1726                         }
1727                         break;
1728                     }
1729                     case DNSKEY_FIELD_FORMAT:
1730                     {
1731                         ret = DNSSEC_ERROR_FILE_FORMAT_VERSION;
1732 
1733                         if(word[0] == 'v')
1734                         {
1735                             if(word[1] == '1')
1736                             {
1737                                 if(word[2] == '.')
1738                                 {
1739                                     // let's assume all 1.x are compatible
1740                                     ret = SUCCESS;
1741                                     break;
1742                                 }
1743                             }
1744                         }
1745 
1746                         // makes the word asciiz (need to be undone)
1747                         parser_text_asciiz(&parser);
1748                         log_err("dnssec: error parsing %s: expected format v1.x, got %s", path, word);
1749                         parser_text_unasciiz(&parser);
1750                         break;
1751                     }
1752                     case DNSKEY_FIELD_CREATED:
1753                     {
1754                         if(ISOK(ret = parse_yyyymmddhhmmss_check_range_len(word, word_len, &key->epoch_created)))
1755                         {
1756                             smart_fields |= DNSKEY_KEY_HAS_SMART_FIELD_CREATED;
1757                         }
1758                         break;
1759                     }
1760                     case DNSKEY_FIELD_PUBLISH:
1761                     {
1762                         if(ISOK(ret = parse_yyyymmddhhmmss_check_range_len(word, word_len, &key->epoch_publish)))
1763                         {
1764                             smart_fields |= DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH;
1765                         }
1766                         break;
1767                     }
1768                     case DNSKEY_FIELD_ACTIVATE:
1769                     {
1770                         if(ISOK(ret = parse_yyyymmddhhmmss_check_range_len(word, word_len, &key->epoch_activate)))
1771                         {
1772                             smart_fields |= DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE;
1773                         }
1774                         break;
1775                     }
1776 
1777                     case DNSKEY_FIELD_INACTIVE:
1778                     {
1779                         if(ISOK(ret = parse_yyyymmddhhmmss_check_range_len(word, word_len, &key->epoch_inactive)))
1780                         {
1781                             smart_fields |= DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE;
1782                         }
1783                         break;
1784                     }
1785                     case DNSKEY_FIELD_DELETE:
1786                     {
1787                         if(ISOK(ret = parse_yyyymmddhhmmss_check_range_len(word, word_len, &key->epoch_delete)))
1788                         {
1789                             smart_fields |= DNSKEY_KEY_HAS_SMART_FIELD_DELETE;
1790                         }
1791                         break;
1792                     }
1793                     case DNSKEY_FIELD_ENGINE:
1794                     {
1795                         // a base64 encoded null-terminated engine name (ie: "pkcs11")
1796 
1797                         break;
1798                     }
1799                     default:
1800                     {
1801                         log_err("dnssec: internal error: %s set as %i defined but not handled", node->key, node->value);
1802                         ret = DNSSEC_ERROR_FIELD_NOT_HANDLED;
1803                     }
1804                 }
1805 
1806                 if(FAIL(ret))
1807                 {
1808                     if(ret != /**/ ERROR)
1809                     {
1810                         log_err("dnssec: error parsing %s: failed to parse value of field %s: %r", path, node->key, ret);
1811                     }
1812                     break;
1813                 }
1814 
1815                 while(FAIL(parser_expect_eol(&parser)))
1816                 {
1817                     log_warn("dnssec: expected end of line");
1818                 }
1819             }
1820             else
1821             {
1822                 if(dnskey_parser.data == NULL)
1823                 {
1824                     switch(algorithm)
1825                     {
1826                         case DNSKEY_ALGORITHM_RSASHA1:
1827                         case DNSKEY_ALGORITHM_RSASHA1_NSEC3:
1828                         case DNSKEY_ALGORITHM_RSASHA256_NSEC3:
1829                         case DNSKEY_ALGORITHM_RSASHA512_NSEC3:
1830                         {
1831                             dnskey_rsa_parse_init(&dnskey_parser);
1832                             break;
1833                         }
1834                         case DNSKEY_ALGORITHM_DSASHA1:
1835                         case DNSKEY_ALGORITHM_DSASHA1_NSEC3:
1836                         {
1837                             dnskey_dsa_parse_init(&dnskey_parser);
1838                             break;
1839                         }
1840 #if HAS_ECDSA_SUPPORT
1841                         case DNSKEY_ALGORITHM_ECDSAP256SHA256:
1842                         case DNSKEY_ALGORITHM_ECDSAP384SHA384:
1843                         {
1844                             dnskey_ecdsa_parse_init(&dnskey_parser);
1845                             break;
1846                         }
1847 #endif
1848 #if HAS_EDDSA_SUPPORT
1849                         case DNSKEY_ALGORITHM_ED25519:
1850                         case DNSKEY_ALGORITHM_ED448:
1851                         {
1852                             dnskey_eddsa_parse_init(&dnskey_parser);
1853                             break;
1854                         }
1855 #endif
1856 #ifdef DNSKEY_ALGORITHM_DUMMY
1857                         case DNSKEY_ALGORITHM_DUMMY:
1858                         {
1859                             dnskey_dummy_parse_init(&dnskey_parser);
1860                             break;
1861                         }
1862 #endif
1863                         default:
1864                         {
1865                             ret = DNSSEC_ERROR_UNSUPPORTEDKEYALGORITHM;
1866                             goto dnskey_new_private_key_from_file_failure;  /// *** GOTO *** ///
1867 //                              break;
1868                         }
1869                     }
1870                 }
1871 
1872                 ret = dnskey_parser.vtbl->parse_field(&dnskey_parser, &parser);
1873 
1874                 if(FAIL(ret))
1875                 {
1876                     log_err("dnssec: error parsing key %s: %r", path, ret);
1877                     break;
1878                 }
1879 
1880                 while(FAIL(parser_expect_eol(&parser)))
1881                 {
1882                     log_warn("dnssec: expected end of line");
1883                 }
1884             }
1885 
1886             // if failed push to expected algorithm
1887             // else issue a warning
1888             // note the last modification time of the file, for management
1889             // close
1890         } // for(;;)
1891 
1892         if(ISOK(ret))
1893         {
1894             if(FAIL(ret = dnskey_parser.vtbl->set_key(&dnskey_parser, key)))
1895             {
1896                 log_err("dnssec: %s cannot be read as a private key", path);
1897             }
1898 
1899             key->status |= smart_fields;
1900 
1901             switch(smart_fields & (DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH|DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE))
1902             {
1903                 case DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH:
1904                 {
1905                     key->epoch_activate = key->epoch_publish;
1906                     break;
1907                 }
1908                 case DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE:
1909                 {
1910                     key->epoch_publish = key->epoch_activate;
1911                     break;
1912                 }
1913             }
1914         }
1915 
1916         dnskey_new_private_key_from_file_failure:
1917 
1918         dnskey_parser.vtbl->finalise(&dnskey_parser);
1919         parser_finalize(&parser);   // also closes the stream
1920 
1921         if(ISOK(ret))
1922         {
1923             if(!dnskey_is_private(key))
1924             {
1925                 log_err("dnssec: %s is not a valid private key", path);
1926                 ret = DNSSEC_ERROR_KEYRING_KEY_IS_NOT_PRIVATE;
1927             }
1928         }
1929 
1930         if(ISOK(ret))
1931         {
1932             key->timestamp = timestamp;
1933         }
1934         else
1935         {
1936             dnskey_release(key);
1937             key = NULL;
1938         }
1939    }
1940 
1941     return ret;
1942 }
1943 
1944 /**
1945  * Loads a private key from a file.
1946  *
1947  * ie: Keu.+007+12345.private
1948  *
1949  * The public key must be in the same folder as the private key.
1950  *
1951  * ie: Keu.+007+12345.key
1952  *
1953  * RC ok
1954  *
1955  * @param filename
1956  * @param keyp
1957  * @return
1958  */
1959 
1960 ya_result
dnskey_new_private_key_from_file(const char * filename,dnssec_key ** keyp)1961 dnskey_new_private_key_from_file(const char *filename, dnssec_key **keyp)
1962 {
1963     dnssec_key *key;
1964 
1965     ya_result ret;
1966     //u32 smart_fields = 0;
1967     int path_len;
1968     int algorithm = -1;
1969     int tag;
1970     //u8 parsed_algorithm;
1971     //bool ext_is_private;
1972     char extension[16];
1973     char domain[256];
1974     u8 origin[256];
1975     char path[PATH_MAX];
1976 
1977     if(keyp == NULL)
1978     {
1979         return INVALID_ARGUMENT_ERROR;
1980     }
1981 
1982     const char *name = strrchr(filename,'/');
1983     if(name == NULL)
1984     {
1985         name = filename;
1986     }
1987     else
1988     {
1989         ++name;
1990     }
1991 
1992     if(sscanf(name, "K%255[^+]+%03d+%05d.%15s", domain, &algorithm, &tag, extension) != 4)
1993     {
1994         log_err("dnssec: don't know how to parse key file name: '%s'", filename);
1995         return PARSESTRING_ERROR;
1996     }
1997 
1998     if(FAIL(ret = cstr_to_dnsname_with_check(origin, domain)))
1999     {
2000         log_err("dnssec: could not parse domain name from file name: '%s': %r", filename, ret);
2001         return ret;
2002     }
2003 
2004     path_len = strlen(filename);
2005 
2006     if(memcmp(extension, "private", 7) == 0)
2007     {
2008         //ext_is_private = TRUE;
2009         path_len -= 7;
2010     }
2011     else if(memcmp(extension, "key", 3) == 0)
2012     {
2013         //ext_is_private = FALSE;
2014         path_len -= 3;
2015     }
2016     else
2017     {
2018         log_err("dnssec: expected .private or .key extension for the file: '%s'", filename);
2019         return INVALID_STATE_ERROR;
2020     }
2021 
2022     memcpy(path, filename, path_len);
2023 
2024     // first open the public key file, to get the flags
2025 
2026     memcpy(&path[path_len], "key", 4);
2027     if(FAIL(ret = dnskey_new_public_key_from_file(path, &key))) // RC
2028     {
2029         return ret;
2030     }
2031 
2032     // then open the private key file
2033 
2034     key->nid = 0; // else it will not be editable // scan-build false positive. key cannot be NULL.
2035 
2036     memcpy(&path[path_len], "private", 8);
2037 
2038     // open parser
2039     input_stream is;
2040     if(ISOK(ret = file_input_stream_open(&is, filename)))
2041     {
2042         ret = dnskey_add_private_key_from_stream(&is, key, path, algorithm);
2043         input_stream_close(&is);
2044     }
2045 
2046     *keyp = key;
2047 
2048     return ret;
2049 }
2050 
2051 /**
2052  *
2053  * Save the private part of a key to a stream
2054  *
2055  * @param key
2056  * @param filename
2057  * @return
2058  */
2059 
2060 void
dnskey_store_private_key_to_stream(dnssec_key * key,output_stream * os)2061 dnskey_store_private_key_to_stream(dnssec_key *key, output_stream *os)
2062 {
2063     yassert(os != NULL);
2064     yassert(key != NULL);
2065 
2066     const char *key_algorithm_name = dnskey_get_algorithm_name_from_value(key->algorithm);
2067 
2068     // basic fields
2069 
2070     osformatln(os, "Private-key-format: v1.3");
2071     osformatln(os, "Algorithm: %i (%s)", key->algorithm, key_algorithm_name);
2072 
2073     // internal fields
2074 
2075     key->vtbl->dnssec_key_print_fields(key, os);
2076 
2077     // time fields : all are stored as an UTC YYYYMMDDhhmmss
2078 
2079     format_writer epoch = {packedepoch_format_handler_method, NULL};
2080 
2081     if(key->epoch_created != 0)
2082     {
2083         epoch.value = (void*)(intptr)key->epoch_created;
2084         osformatln(os, "Created: %w", &epoch);
2085     }
2086 
2087     if(key->epoch_publish != 0)
2088     {
2089         epoch.value = (void*)(intptr)key->epoch_publish;
2090         osformatln(os, "Publish: %w", &epoch);
2091     }
2092 
2093     if(key->epoch_activate != 0)
2094     {
2095         epoch.value = (void*)(intptr)key->epoch_activate;
2096         osformatln(os, "Activate: %w", &epoch);
2097     }
2098 
2099     if(key->epoch_inactive != 0)
2100     {
2101         epoch.value = (void*)(intptr)key->epoch_inactive;
2102         osformatln(os, "Inactive: %w", &epoch);
2103     }
2104 
2105     if(key->epoch_delete != 0)
2106     {
2107         epoch.value = (void*)(intptr)key->epoch_delete;
2108         osformatln(os, "Delete: %w", &epoch);
2109     }
2110 
2111 }
2112 
2113 /**
2114  *
2115  * Save the private part of a key to a file with the given name
2116  *
2117  * @param key
2118  * @param filename
2119  * @return
2120  */
2121 
2122 ya_result
dnskey_store_private_key_to_file(dnssec_key * key,const char * filename)2123 dnskey_store_private_key_to_file(dnssec_key *key, const char *filename)
2124 {
2125     yassert(filename != NULL);
2126     yassert(key != NULL);
2127 
2128     output_stream os;
2129     ya_result ret;
2130 
2131     if(ISOK(ret = file_output_stream_create(&os, filename, 0644)))
2132     {
2133         buffer_output_stream_init(&os, &os, 4096);
2134 
2135         dnskey_store_private_key_to_stream(key, &os);
2136 
2137         output_stream_close(&os);
2138 
2139         ret = SUCCESS;
2140     }
2141 
2142     return ret;
2143 }
2144 
2145 /**
2146  *
2147  * Save the public part of a key to a stream
2148  *
2149  * @param key
2150  * @param filename
2151  * @return
2152  */
2153 
2154 ya_result
dnskey_store_public_key_to_stream(dnssec_key * key,output_stream * os)2155 dnskey_store_public_key_to_stream(dnssec_key *key, output_stream *os)
2156 {
2157     u8 rdata[2048];
2158 
2159     if(key->vtbl->dnssec_key_rdatasize(key) < sizeof(rdata))
2160     {
2161         int rdata_size = key->vtbl->dnssec_key_writerdata(key, rdata, sizeof(rdata));
2162         rdata_desc dnskeyrdata = {TYPE_DNSKEY, rdata_size, rdata};
2163 
2164         osformatln(os, "; This is a key, keyid %d, for domain %{dnsname}", dnskey_get_tag(key), key->owner_name);
2165         osformatln(os, "%{dnsname} IN %{typerdatadesc}", key->owner_name, &dnskeyrdata);
2166 
2167         return SUCCESS;
2168     }
2169     else
2170     {
2171         return BUFFER_WOULD_OVERFLOW;
2172     }
2173 }
2174 
2175 /**
2176  *
2177  * Save the public part of a key to a file with the given name
2178  *
2179  * @param key
2180  * @param filename
2181  * @return
2182  */
2183 
2184 ya_result
dnskey_store_public_key_to_file(dnssec_key * key,const char * filename)2185 dnskey_store_public_key_to_file(dnssec_key *key, const char *filename)
2186 {
2187     ya_result ret;
2188 
2189     if(key->vtbl->dnssec_key_rdatasize(key) < 2048)
2190     {
2191         output_stream os;
2192 
2193         if(ISOK(ret = file_output_stream_create(&os, filename, 0644)))
2194         {
2195             if(FAIL(ret = dnskey_store_public_key_to_stream(key, &os)))
2196             {
2197                 unlink(filename);
2198             }
2199             output_stream_close(&os);
2200         }
2201     }
2202     else
2203     {
2204         ret = DNSSEC_ERROR_KEYISTOOBIG; // key too big (should never happen)
2205     }
2206 
2207     return ret;
2208 }
2209 
2210 /**
2211  * Save the private part of a key to a dir
2212  *
2213  * @param key
2214  * @param dirname
2215  * @return
2216  */
2217 
2218 ya_result
dnskey_store_private_key_to_dir(dnssec_key * key,const char * dirname)2219 dnskey_store_private_key_to_dir(dnssec_key *key, const char *dirname)
2220 {
2221     ya_result ret;
2222     char filename[PATH_MAX];
2223 
2224     if(ISOK(ret = snformat(filename, sizeof(filename), "%s/K%{dnsname}+%03d+%05d.private",
2225             dirname,
2226             key->owner_name,
2227             key->algorithm,
2228             dnskey_get_tag(key)
2229             )))
2230     {
2231         ret = file_exists(filename);
2232 
2233         if(ret == 0)
2234         {
2235             ret = dnskey_store_private_key_to_file(key, filename);
2236         }
2237         else
2238         {
2239             // cannot create the file because it exists already or the path is not accessible
2240             ret = DNSSEC_ERROR_CANNOT_WRITE_NEW_FILE;
2241         }
2242     }
2243 
2244     return ret;
2245 }
2246 
2247 /**
2248  *
2249  * Saves the public part of the key in a dir
2250  *
2251  * @param key
2252  * @param dirname
2253  * @return
2254  */
2255 
2256 ya_result
dnskey_store_public_key_to_dir(dnssec_key * key,const char * dirname)2257 dnskey_store_public_key_to_dir(dnssec_key *key, const char *dirname)
2258 {
2259     ya_result ret;
2260     char filename[PATH_MAX];
2261 
2262     if(ISOK(ret = snformat(filename, sizeof(filename), "%s/K%{dnsname}+%03d+%05d.key",
2263             dirname,
2264             key->owner_name,
2265             key->algorithm,
2266             dnskey_get_tag(key)
2267             )))
2268     {
2269         ret = file_exists(filename);
2270 
2271         if(ret == 0)
2272         {
2273             ret = dnskey_store_public_key_to_file(key, filename);
2274         }
2275         else
2276         {
2277             // cannot create the file because it exists already or the path is not accessible
2278             ret = DNSSEC_ERROR_CANNOT_WRITE_NEW_FILE;
2279         }
2280     }
2281 
2282     return ret;
2283 }
2284 
2285 /**
2286  * Save both parts of the key to the directory.
2287  *
2288  * @param key
2289  * @param dir
2290  *
2291  * @return an error code
2292  */
2293 
2294 ya_result
dnskey_store_keypair_to_dir(dnssec_key * key,const char * dir)2295 dnskey_store_keypair_to_dir(dnssec_key *key, const char *dir)
2296 {
2297     ya_result ret;
2298 
2299     if(ISOK(ret = dnskey_store_public_key_to_dir(key, dir)))
2300     {
2301         ret = dnskey_store_private_key_to_dir(key, dir);
2302     }
2303 
2304     return ret;
2305 }
2306 
2307 ya_result
dnskey_delete_public_key_from_dir(dnssec_key * key,const char * dirname)2308 dnskey_delete_public_key_from_dir(dnssec_key *key, const char *dirname)
2309 {
2310     ya_result ret;
2311     char filename[PATH_MAX];
2312 
2313     if(ISOK(ret = snformat(filename, sizeof(filename), "%s/K%{dnsname}+%03d+%05d.key",
2314                            dirname,
2315                            key->owner_name,
2316                            key->algorithm,
2317                            dnskey_get_tag(key)
2318     )))
2319     {
2320         unlink(filename);
2321         ret = ERRNO_ERROR;
2322     }
2323 
2324     return ret;
2325 }
2326 
2327 ya_result
dnskey_delete_private_key_from_dir(dnssec_key * key,const char * dirname)2328 dnskey_delete_private_key_from_dir(dnssec_key *key, const char *dirname)
2329 {
2330     ya_result ret;
2331     char filename[PATH_MAX];
2332 
2333     if(ISOK(ret = snformat(filename, sizeof(filename), "%s/K%{dnsname}+%03d+%05d.private",
2334                            dirname,
2335                            key->owner_name,
2336                            key->algorithm,
2337                            dnskey_get_tag(key)
2338     )))
2339     {
2340         unlink(filename);
2341         ret = ERRNO_ERROR;
2342     }
2343 
2344     return ret;
2345 }
2346 
2347 ya_result
dnskey_delete_keypair_from_dir(dnssec_key * key,const char * dirname)2348 dnskey_delete_keypair_from_dir(dnssec_key *key, const char *dirname)
2349 {
2350     ya_result ret1 = dnskey_delete_public_key_from_dir(key, dirname);
2351     ya_result ret2 = dnskey_delete_private_key_from_dir(key, dirname);
2352     if((ret1 != MAKE_ERRNO_ERROR(EACCES)) && (ret2 != MAKE_ERRNO_ERROR(EACCES)))
2353     {
2354         return SUCCESS;
2355     }
2356     else
2357     {
2358         return MAKE_ERRNO_ERROR(EACCES);
2359     }
2360 }
2361 
2362 bool
dnskey_is_expired(const dnssec_key * key,time_t now)2363 dnskey_is_expired(const dnssec_key *key, time_t now)
2364 {
2365     return (key->epoch_delete != 0 && key->epoch_delete < now) || (key->epoch_inactive != 0 && key->epoch_inactive < now);
2366 }
2367 
2368 bool
dnskey_is_expired_now(const dnssec_key * key)2369 dnskey_is_expired_now(const dnssec_key *key)
2370 {
2371     time_t now = time(NULL);
2372     bool ret = dnskey_is_expired(key, now);
2373     return ret;
2374 }
2375 
2376 int
dnskey_get_size(const dnssec_key * key)2377 dnskey_get_size(const dnssec_key *key)
2378 {
2379     int bits_size = key->vtbl->dnssec_key_size(key);
2380     return bits_size;
2381 }
2382 
2383 u16
dnskey_get_flags(const dnssec_key * key)2384 dnskey_get_flags(const dnssec_key *key)
2385 {
2386     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2387     u16 flags = key->flags;
2388     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2389     return flags;
2390 }
2391 
2392 void
dnskey_state_enable(dnssec_key * key,u32 status)2393 dnskey_state_enable(dnssec_key *key, u32 status)
2394 {
2395     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
2396     key->status |= status;
2397     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
2398 }
2399 
2400 void
dnskey_state_disable(dnssec_key * key,u32 status)2401 dnskey_state_disable(dnssec_key *key, u32 status)
2402 {
2403     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
2404     key->status &= ~status;
2405     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
2406 }
2407 
2408 u32
dnskey_state_get(const dnssec_key * key)2409 dnskey_state_get(const dnssec_key *key)
2410 {
2411     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2412     u32 state = key->status;
2413     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2414     return state;
2415 }
2416 
2417 /**
2418  * Initialises internal info.
2419  */
2420 
2421 void
dnskey_init()2422 dnskey_init()
2423 {
2424     if(dnssec_key_load_private_keywords_set == STRING_SET_EMPTY)
2425     {
2426         for(int i = 0; dnssec_key_load_private_keywords_common_names[i].data != NULL; i++)
2427         {
2428             string_node *node = string_set_insert(&dnssec_key_load_private_keywords_set, dnssec_key_load_private_keywords_common_names[i].data);
2429             node->value = dnssec_key_load_private_keywords_common_names[i].id;
2430         }
2431     }
2432 }
2433 
2434 void
dnskey_finalize()2435 dnskey_finalize()
2436 {
2437     string_set_destroy(&dnssec_key_load_private_keywords_set);
2438 }
2439 
2440 /**
2441  * Returns true if the key is supposed to have been added in the zone at the chosen time already.
2442  *
2443  * @param key
2444  * @param t
2445  * @return
2446  */
2447 
2448 bool
dnskey_is_published(const dnssec_key * key,time_t t)2449 dnskey_is_published(const dnssec_key *key, time_t t)
2450 {
2451     // there is a publish time and it has occurred
2452 
2453     if(dnskey_has_explicit_publish(key) && (key->epoch_publish <= t))
2454     {
2455         bool ret = !dnskey_is_unpublished(key, t);
2456         return ret;
2457     }
2458 
2459     // there is no publish time
2460 
2461     return !dnskey_is_unpublished(key, t);
2462 }
2463 
2464 /**
2465  * Returns true if the key is supposed to have been removed from the zone at the chosen time already.
2466  *
2467  * @param key
2468  * @param t
2469  * @return
2470  */
2471 
2472 bool
dnskey_is_unpublished(const dnssec_key * key,time_t t)2473 dnskey_is_unpublished(const dnssec_key *key, time_t t)
2474 {
2475     // true if and only if there is a removal time that occurred already
2476 
2477     return dnskey_has_explicit_delete(key) && (key->epoch_delete <= t);
2478 }
2479 
2480 /**
2481  * Returns true if the key is supposed to be used for signatures.
2482  *
2483  * @param key
2484  * @param t
2485  * @return
2486  */
2487 
2488 bool
dnskey_is_activated(const dnssec_key * key,time_t t)2489 dnskey_is_activated(const dnssec_key *key, time_t t)
2490 {
2491     // there is a active time and it has occurred
2492 
2493     if(dnskey_has_explicit_activate(key))
2494     {
2495         group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2496         time_t epoch_activate = key->epoch_activate;
2497         group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2498         if(epoch_activate <= t) // activation time passed
2499         {
2500             bool ret = !dnskey_is_deactivated(key, t);  // not deactivated yet ?
2501             return ret;
2502         }
2503 
2504         return FALSE;   // not active yet
2505     }
2506     else
2507     {
2508         // no activation defined : active at publication time but only until deactivation
2509 
2510         return dnskey_is_published(key, t) && !dnskey_is_deactivated(key, t);
2511     }
2512 }
2513 
2514 /**
2515  * Assumes we are in 'leniency' seconds in the future for activation (and in the present for deactivation)
2516  */
2517 
2518 bool
dnskey_is_activated_lenient(const dnssec_key * key,time_t t,u32 leniency)2519 dnskey_is_activated_lenient(const dnssec_key *key, time_t t, u32 leniency)
2520 {
2521     // there is a active time and it has occurred
2522 
2523     if(dnskey_has_explicit_activate(key))
2524     {
2525         group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2526         time_t epoch_activate = key->epoch_activate;
2527         group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2528         if(epoch_activate <= t + leniency) // activation time passed
2529         {
2530             bool ret = !dnskey_is_deactivated(key, t);  // not deactivated yet ?
2531             return ret;
2532         }
2533 
2534         return FALSE;   // not active yet
2535     }
2536     else
2537     {
2538         // no activation defined : active at publication time but only until deactivation
2539 
2540         return dnskey_is_published(key, t) && !dnskey_is_deactivated(key, t);
2541     }
2542 }
2543 
2544 /**
2545  * Returns true if the key must not be used for signatures anymore.
2546  *
2547  * @param key
2548  * @param t
2549  * @return
2550  */
2551 
2552 bool
dnskey_is_deactivated(const dnssec_key * key,time_t t)2553 dnskey_is_deactivated(const dnssec_key *key, time_t t)
2554 {
2555     // there is a inactive time and it has occurred
2556 
2557     group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2558     time_t epoch_inactive = key->epoch_inactive;
2559     group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_READ);
2560 
2561     if(epoch_inactive > 0)
2562     {
2563         return (epoch_inactive <= t);
2564     }
2565     else
2566     {
2567         // the key has to be activated and not deleted
2568 
2569         return dnskey_is_unpublished(key, t);
2570     }
2571 }
2572 
2573 bool
dnskey_has_explicit_publish(const dnssec_key * key)2574 dnskey_has_explicit_publish(const dnssec_key *key)
2575 {
2576     return (dnskey_state_get(key) & DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH) != 0;
2577 }
2578 
2579 bool
dnskey_has_explicit_delete(const dnssec_key * key)2580 dnskey_has_explicit_delete(const dnssec_key *key)
2581 {
2582     return (dnskey_state_get(key) & DNSKEY_KEY_HAS_SMART_FIELD_DELETE) != 0;
2583 }
2584 
2585 bool
dnskey_has_explicit_publish_or_delete(const dnssec_key * key)2586 dnskey_has_explicit_publish_or_delete(const dnssec_key *key)
2587 {
2588     return (dnskey_state_get(key) & (DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH|DNSKEY_KEY_HAS_SMART_FIELD_DELETE)) != 0;
2589 }
2590 
2591 bool
dnskey_has_explicit_publish_and_delete(const dnssec_key * key)2592 dnskey_has_explicit_publish_and_delete(const dnssec_key *key)
2593 {
2594     return (dnskey_state_get(key) & (DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH|DNSKEY_KEY_HAS_SMART_FIELD_DELETE)) == (DNSKEY_KEY_HAS_SMART_FIELD_PUBLISH|DNSKEY_KEY_HAS_SMART_FIELD_DELETE);
2595 }
2596 
2597 bool
dnskey_has_explicit_activate(const dnssec_key * key)2598 dnskey_has_explicit_activate(const dnssec_key *key)
2599 {
2600     return (dnskey_state_get(key) & DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE) != 0;
2601 }
2602 
2603 bool
dnskey_has_explicit_deactivate(const dnssec_key * key)2604 dnskey_has_explicit_deactivate(const dnssec_key *key)
2605 {
2606     return (dnskey_state_get(key) & DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE) != 0;
2607 }
2608 
2609 bool
dnskey_has_activate_and_deactivate(const dnssec_key * key)2610 dnskey_has_activate_and_deactivate(const dnssec_key *key)
2611 {
2612     return (dnskey_state_get(key) & (DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE|DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE)) == (DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE|DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE);
2613 }
2614 
2615 bool
dnskey_has_activate_or_deactivate(const dnssec_key * key)2616 dnskey_has_activate_or_deactivate(const dnssec_key *key)
2617 {
2618     return (dnskey_state_get(key) & (DNSKEY_KEY_HAS_SMART_FIELD_ACTIVATE|DNSKEY_KEY_HAS_SMART_FIELD_INACTIVE)) != 0;
2619 }
2620 
2621 u8
dnskey_supported_algorithm_count()2622 dnskey_supported_algorithm_count()
2623 {
2624     return sizeof(dnskey_supported_algorithms)/sizeof(dnskey_supported_algorithms[0]);
2625 }
2626 
2627 const dnskey_features*
dnskey_supported_algorithm_by_index(u8 index)2628 dnskey_supported_algorithm_by_index(u8 index)
2629 {
2630     if(index < dnskey_supported_algorithm_count())
2631     {
2632         const dnskey_features* ret = &dnskey_supported_algorithms[index];
2633         return ret;
2634     }
2635 
2636     return NULL;
2637 }
2638 
2639 const dnskey_features*
dnskey_supported_algorithm(u8 algorithm)2640 dnskey_supported_algorithm(u8 algorithm)
2641 {
2642     for(int i = 0; i < dnskey_supported_algorithm_count(); ++i)
2643     {
2644         const dnskey_features* ret = &dnskey_supported_algorithms[i];
2645         if(ret->algorithm == algorithm)
2646         {
2647             return ret;
2648         }
2649     }
2650 
2651     return NULL;
2652 }
2653 
dnskey_newinstance(u32 size,u8 algorithm,u16 flags,const char * origin,dnssec_key ** out_key)2654 ya_result dnskey_newinstance(u32 size, u8 algorithm, u16 flags, const char* origin, dnssec_key** out_key)
2655 {
2656     if(size > DNSSEC_MAXIMUM_KEY_SIZE)
2657     {
2658         return DNSSEC_ERROR_KEYISTOOBIG;
2659     }
2660 
2661     ya_result ret;
2662 
2663     switch(algorithm)
2664     {
2665         case DNSKEY_ALGORITHM_RSASHA1:
2666         case DNSKEY_ALGORITHM_RSASHA1_NSEC3:
2667         case DNSKEY_ALGORITHM_RSASHA256_NSEC3:
2668         case DNSKEY_ALGORITHM_RSASHA512_NSEC3:
2669             ret = dnskey_rsa_newinstance(size, algorithm, flags, origin, out_key);
2670             break;
2671         case DNSKEY_ALGORITHM_DSASHA1:
2672         case DNSKEY_ALGORITHM_DSASHA1_NSEC3:
2673             ret = dnskey_dsa_newinstance(size, algorithm, flags, origin, out_key);
2674             break;
2675 #if HAS_ECDSA_SUPPORT
2676         case DNSKEY_ALGORITHM_ECDSAP256SHA256:
2677         case DNSKEY_ALGORITHM_ECDSAP384SHA384:
2678             ret = dnskey_ecdsa_newinstance(size, algorithm, flags, origin, out_key);
2679             break;
2680 #endif
2681 #if HAS_EDDSA_SUPPORT
2682         case DNSKEY_ALGORITHM_ED25519:
2683         case DNSKEY_ALGORITHM_ED448:
2684             ret = dnskey_eddsa_newinstance(size, algorithm, flags, origin, out_key);
2685             break;
2686 #endif
2687 #ifdef DNSKEY_ALGORITHM_DUMMY
2688         case DNSKEY_ALGORITHM_DUMMY:
2689             ret = dnskey_dummy_newinstance(size, algorithm, flags, origin, out_key);
2690             break;
2691 #endif
2692         default:
2693             ret = DNSSEC_ERROR_UNSUPPORTEDKEYALGORITHM;
2694             break;
2695     }
2696 
2697     if(ISOK(ret))
2698     {
2699         time_t now = time(NULL);
2700         group_mutex_lock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
2701         (*out_key)->epoch_created = now;
2702         (*out_key)->status |= DNSKEY_KEY_HAS_SMART_FIELD_CREATED;
2703         group_mutex_unlock(&dnskey_rc_mtx, GROUP_MUTEX_WRITE);
2704     }
2705 
2706     return ret;
2707 }
2708 
2709 void
dnskey_init_dns_resource_record(dnssec_key * key,s32 ttl,dns_resource_record * rr)2710 dnskey_init_dns_resource_record(dnssec_key *key, s32 ttl, dns_resource_record *rr)
2711 {
2712     u8 rdata[8191];
2713     u32 rdata_size = key->vtbl->dnssec_key_writerdata(key, rdata, sizeof(rdata));
2714     dns_resource_record_init_record(rr, dnskey_get_domain(key), TYPE_DNSKEY, CLASS_IN, ttl, rdata_size, rdata);
2715 }
2716 
2717 /** @} */
2718