OpenDNSSEC-signer  1.4.1
signconf.c
Go to the documentation of this file.
1 /*
2  * $Id: signconf.c 7142 2013-06-06 09:03:30Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
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  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "parser/signconfparser.h"
35 #include "shared/duration.h"
36 #include "shared/file.h"
37 #include "shared/log.h"
38 #include "shared/status.h"
39 #include "signer/signconf.h"
40 
41 static const char* sc_str = "signconf";
42 
43 
50 {
51  signconf_type* sc = NULL;
52  allocator_type* allocator = allocator_create(malloc, free);
53  if (!allocator) {
54  ods_log_error("[%s] unable to create signconf: allocator_create() "
55  " failed", sc_str);
56  return NULL;
57  }
58  sc = (signconf_type*) allocator_alloc(allocator, sizeof(signconf_type));
59  if (!sc) {
60  ods_log_error("[%s] unable to create signconf: allocator_alloc() "
61  " failed", sc_str);
62  allocator_cleanup(allocator);
63  return NULL;
64  }
65  sc->allocator = allocator;
66  sc->filename = NULL;
67  /* Signatures */
68  sc->sig_resign_interval = NULL;
69  sc->sig_refresh_interval = NULL;
70  sc->sig_validity_default = NULL;
71  sc->sig_validity_denial = NULL;
72  sc->sig_jitter = NULL;
73  sc->sig_inception_offset = NULL;
74  /* Denial of existence */
75  sc->nsec_type = 0;
76  sc->nsec3_optout = 0;
77  sc->nsec3_algo = 0;
78  sc->nsec3_iterations = 0;
79  sc->nsec3_salt = NULL;
80  sc->nsec3params = NULL;
81  /* Keys */
82  sc->dnskey_ttl = NULL;
83  sc->keys = NULL;
84  /* Source of authority */
85  sc->soa_ttl = NULL;
86  sc->soa_min = NULL;
87  sc->soa_serial = NULL;
88  /* Other useful information */
89  sc->last_modified = 0;
90  return sc;
91 }
92 
93 
98 static ods_status
99 signconf_read(signconf_type* signconf, const char* scfile)
100 {
101  const char* rngfile = ODS_SE_RNGDIR "/signconf.rng";
102  ods_status status = ODS_STATUS_OK;
103  FILE* fd = NULL;
104 
105  if (!scfile || !signconf) {
106  return ODS_STATUS_ASSERT_ERR;
107  }
108  ods_log_debug("[%s] read signconf file %s", sc_str, scfile);
109  status = parse_file_check(scfile, rngfile);
110  if (status != ODS_STATUS_OK) {
111  ods_log_error("[%s] unable to read signconf: parse error in "
112  "file %s (%s)", sc_str, scfile, ods_status2str(status));
113  return status;
114  }
115  fd = ods_fopen(scfile, NULL, "r");
116  if (fd) {
117  signconf->filename = allocator_strdup(signconf->allocator, scfile);
122  signconf->sig_jitter = parse_sc_sig_jitter(scfile);
124  signconf->nsec_type = parse_sc_nsec_type(scfile);
125  if (signconf->nsec_type == LDNS_RR_TYPE_NSEC3) {
126  signconf->nsec3_optout = parse_sc_nsec3_optout(scfile);
127  signconf->nsec3_algo = parse_sc_nsec3_algorithm(scfile);
128  signconf->nsec3_iterations = parse_sc_nsec3_iterations(scfile);
129  signconf->nsec3_salt = parse_sc_nsec3_salt(signconf->allocator,
130  scfile);
131  signconf->nsec3params = nsec3params_create((void*) signconf,
132  (uint8_t) signconf->nsec3_algo, (uint8_t) signconf->nsec3_optout,
133  (uint16_t)signconf->nsec3_iterations, signconf->nsec3_salt);
134  if (!signconf->nsec3params) {
135  ods_log_error("[%s] unable to read signconf %s: "
136  "nsec3params_create() failed", sc_str, scfile);
137  ods_fclose(fd);
138  return ODS_STATUS_MALLOC_ERR;
139  }
140  }
141  signconf->keys = parse_sc_keys((void*) signconf, scfile);
142  signconf->dnskey_ttl = parse_sc_dnskey_ttl(scfile);
143  signconf->soa_ttl = parse_sc_soa_ttl(scfile);
144  signconf->soa_min = parse_sc_soa_min(scfile);
145  signconf->soa_serial = parse_sc_soa_serial(signconf->allocator,
146  scfile);
147  ods_fclose(fd);
148  return ODS_STATUS_OK;
149  }
150  ods_log_error("[%s] unable to read signconf: failed to open file %s",
151  sc_str, scfile);
152  return ODS_STATUS_ERR;
153 }
154 
155 
161 signconf_update(signconf_type** signconf, const char* scfile,
162  time_t last_modified)
163 {
164  signconf_type* new_sc = NULL;
165  time_t st_mtime = 0;
166  ods_status status = ODS_STATUS_OK;
167 
168  if (!scfile || !signconf) {
169  return ODS_STATUS_UNCHANGED;
170  }
171  /* is the file updated? */
172  st_mtime = ods_file_lastmodified(scfile);
173  if (st_mtime <= last_modified) {
174  return ODS_STATUS_UNCHANGED;
175  }
176  /* if so, read the new signer configuration */
177  new_sc = signconf_create();
178  if (!new_sc) {
179  ods_log_error("[%s] unable to update signconf: signconf_create() "
180  "failed", sc_str);
181  return ODS_STATUS_ERR;
182  }
183  status = signconf_read(new_sc, scfile);
184  if (status == ODS_STATUS_OK) {
185  new_sc->last_modified = st_mtime;
186  if (signconf_check(new_sc) != ODS_STATUS_OK) {
187  ods_log_error("[%s] unable to update signconf: signconf %s has "
188  "errors", sc_str, scfile);
189  signconf_cleanup(new_sc);
190  return ODS_STATUS_CFG_ERR;
191  }
192  *signconf = new_sc;
193  } else {
194  ods_log_error("[%s] unable to update signconf: failed to read file "
195  "%s (%s)", sc_str, scfile, ods_status2str(status));
196  signconf_cleanup(new_sc);
197  }
198  return status;
199 }
200 
201 
206 static void
207 signconf_backup_duration(FILE* fd, const char* opt, duration_type* duration)
208 {
209  char* str = duration2string(duration);
210  fprintf(fd, "%s %s ", opt, str);
211  free((void*) str);
212  return;
213 }
214 
215 
216 
221 void
222 signconf_backup(FILE* fd, signconf_type* sc, const char* version)
223 {
224  if (!fd || !sc) {
225  return;
226  }
227  fprintf(fd, ";;Signconf: lastmod %u ", (unsigned) sc->last_modified);
228  if (strcmp(version, ODS_SE_FILE_MAGIC_V2) &&
229  strcmp(version, ODS_SE_FILE_MAGIC_V1)) {
230  /* version 3 and up */
231  fprintf(fd, "maxzonettl 0 "); /* prepare for enforcer ng */
232  }
233  signconf_backup_duration(fd, "resign", sc->sig_resign_interval);
234  signconf_backup_duration(fd, "refresh", sc->sig_refresh_interval);
235  signconf_backup_duration(fd, "valid", sc->sig_validity_default);
236  signconf_backup_duration(fd, "denial", sc->sig_validity_denial);
237  signconf_backup_duration(fd, "jitter", sc->sig_jitter);
238  signconf_backup_duration(fd, "offset", sc->sig_inception_offset);
239  fprintf(fd, "nsec %u ", (unsigned) sc->nsec_type);
240  signconf_backup_duration(fd, "dnskeyttl", sc->dnskey_ttl);
241  signconf_backup_duration(fd, "soattl", sc->soa_ttl);
242  signconf_backup_duration(fd, "soamin", sc->soa_min);
243  fprintf(fd, "serial %s ", sc->soa_serial?sc->soa_serial:"(null)");
244  if (strcmp(version, ODS_SE_FILE_MAGIC_V2) == 0) {
245  fprintf(fd, "audit 0");
246  }
247  fprintf(fd, "\n");
248  return;
249 }
250 
251 
256 static int
257 signconf_soa_serial_check(const char* serial) {
258  if (!serial) {
259  return 1;
260  }
261 
262  if (strlen(serial) == 4 && strncmp(serial, "keep", 4) == 0) {
263  return 0;
264  }
265  if (strlen(serial) == 7 && strncmp(serial, "counter", 7) == 0) {
266  return 0;
267  }
268  if (strlen(serial) == 8 && strncmp(serial, "unixtime", 8) == 0) {
269  return 0;
270  }
271  if (strlen(serial) == 11 && strncmp(serial, "datecounter", 11) == 0) {
272  return 0;
273  }
274  return 1;
275 }
276 
277 
284 {
285  ods_status status = ODS_STATUS_OK;
286 
287  if (!sc->sig_resign_interval) {
288  ods_log_error("[%s] check failed: no signature resign interval found",
289  sc_str);
290  status = ODS_STATUS_CFG_ERR;
291  }
292  if (!sc->sig_refresh_interval) {
293  ods_log_error("[%s] check failed: no signature resign interval found",
294  sc_str);
295  status = ODS_STATUS_CFG_ERR;
296  }
297  if (!sc->sig_validity_default) {
298  ods_log_error("[%s] check failed: no signature default validity found",
299  sc_str);
300  status = ODS_STATUS_CFG_ERR;
301  }
302  if (!sc->sig_validity_denial) {
303  ods_log_error("[%s] check failed: no signature denial validity found",
304  sc_str);
305  status = ODS_STATUS_CFG_ERR;
306  }
307  if (!sc->sig_jitter) {
308  ods_log_error("[%s] check failed: no signature jitter found", sc_str);
309  status = ODS_STATUS_CFG_ERR;
310  }
311  if (!sc->sig_inception_offset) {
312  ods_log_error("[%s] check failed: no signature inception offset found",
313  sc_str);
314  status = ODS_STATUS_CFG_ERR;
315  }
316  if (sc->nsec_type == LDNS_RR_TYPE_NSEC3) {
317  if (sc->nsec3_algo != LDNS_SHA1) {
318  ods_log_error("[%s] check failed: invalid nsec3 algorithm",
319  sc_str);
320  status = ODS_STATUS_CFG_ERR;
321  }
322  /* iterations */
323  /* salt */
324  /* optout */
325  } else if (sc->nsec_type != LDNS_RR_TYPE_NSEC) {
326  ods_log_error("[%s] check failed: wrong nsec type %i", sc_str,
327  sc->nsec_type);
328  status = ODS_STATUS_CFG_ERR;
329  }
330  if (!sc->keys || sc->keys->count == 0) {
331  ods_log_error("[%s] check failed: no keys found", sc_str);
332  status = ODS_STATUS_CFG_ERR;
333  }
334  if (!sc->dnskey_ttl) {
335  ods_log_error("[%s] check failed: no dnskey ttl found", sc_str);
336  status = ODS_STATUS_CFG_ERR;
337  }
338  if (!sc->soa_ttl) {
339  ods_log_error("[%s] check failed: no soa ttl found", sc_str);
340  status = ODS_STATUS_CFG_ERR;
341  }
342  if (!sc->soa_min) {
343  ods_log_error("[%s] check failed: no soa minimum found", sc_str);
344  status = ODS_STATUS_CFG_ERR;
345  }
346  if (!sc->soa_serial) {
347  ods_log_error("[%s] check failed: no soa serial type found", sc_str);
348  status = ODS_STATUS_CFG_ERR;
349  } else if (signconf_soa_serial_check(sc->soa_serial) != 0) {
350  ods_log_error("[%s] check failed: wrong soa serial type %s", sc_str,
351  sc->soa_serial);
352  status = ODS_STATUS_CFG_ERR;
353  }
354  return status;
355 }
356 
357 
362 task_id
364 {
365  task_id new_task = TASK_NONE;
366  if (!a || !b) {
367  return TASK_NONE;
368  }
369  ods_log_assert(a);
370  ods_log_assert(b);
371 
372  if (duration_compare(a->soa_min, b->soa_min)) {
373  new_task = TASK_NSECIFY;
374  } else if (a->nsec_type != b->nsec_type) {
375  new_task = TASK_NSECIFY;
376  } else if (a->nsec_type == LDNS_RR_TYPE_NSEC3) {
377  if ((ods_strcmp(a->nsec3_salt, b->nsec3_salt) != 0) ||
378  (a->nsec3_algo != b->nsec3_algo) ||
379  (a->nsec3_iterations != b->nsec3_iterations) ||
380  (a->nsec3_optout != b->nsec3_optout)) {
381 
382  new_task = TASK_NSECIFY;
383  }
384  }
385  return new_task;
386 }
387 
388 
393 void
394 signconf_print(FILE* out, signconf_type* sc, const char* name)
395 {
396  char* s = NULL;
397 
398  fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
399  if (sc) {
400  fprintf(out, "<SignerConfiguration>\n");
401  fprintf(out, "\t<Zone name=\"%s\">\n", name?name:"(null)");
402  /* Signatures */
403  fprintf(out, "\t\t<Signatures>\n");
405  fprintf(out, "\t\t\t<Resign>%s</Resign>\n", s?s:"(null)");
406  free((void*)s);
408  fprintf(out, "\t\t\t<Refresh>%s</Refresh>\n", s?s:"(null)");
409  free((void*)s);
410  fprintf(out, "\t\t\t<Validity>\n");
412  fprintf(out, "\t\t\t\t<Default>%s</Default>\n", s?s:"(null)");
413  free((void*)s);
415  fprintf(out, "\t\t\t\t<Denial>%s</Denial>\n", s?s:"(null)");
416  free((void*)s);
417  fprintf(out, "\t\t\t</Validity>\n");
418  s = duration2string(sc->sig_jitter);
419  fprintf(out, "\t\t\t<Jitter>%s</Jitter>\n", s?s:"(null)");
420  free((void*)s);
422  fprintf(out, "\t\t\t<InceptionOffset>%s</InceptionOffset>\n",
423  s?s:"(null)");
424  free((void*)s);
425  fprintf(out, "\t\t</Signatures>\n");
426  fprintf(out, "\n");
427  /* Denial */
428  fprintf(out, "\t\t<Denial>\n");
429  if (sc->nsec_type == LDNS_RR_TYPE_NSEC) {
430  fprintf(out, "\t\t\t<NSEC />\n");
431  } else if (sc->nsec_type == LDNS_RR_TYPE_NSEC3) {
432  fprintf(out, "\t\t\t<NSEC3>\n");
433  if (sc->nsec3_optout) {
434  fprintf(out, "\t\t\t\t<OptOut />\n");
435  }
436  fprintf(out, "\t\t\t\t<Hash>\n");
437  fprintf(out, "\t\t\t\t\t<Algorithm>%i</Algorithm>\n",
438  sc->nsec3_algo);
439  fprintf(out, "\t\t\t\t\t<Iterations>%i</Iterations>\n",
440  sc->nsec3_iterations);
441  fprintf(out, "\t\t\t\t\t<Salt>%s</Salt>\n",
442  sc->nsec3_salt?sc->nsec3_salt:"(null)");
443  fprintf(out, "\t\t\t\t</Hash>\n");
444  fprintf(out, "\t\t\t</NSEC3>\n");
445  }
446  fprintf(out, "\t\t</Denial>\n");
447  fprintf(out, "\n");
448  /* Keys */
449  fprintf(out, "\t\t<Keys>\n");
450  s = duration2string(sc->dnskey_ttl);
451  fprintf(out, "\t\t\t<TTL>%s</TTL>\n", s?s:"(null)");
452  free((void*)s);
453  fprintf(out, "\n");
454  keylist_print(out, sc->keys);
455  fprintf(out, "\t\t</Keys>\n");
456  fprintf(out, "\n");
457  /* SOA */
458  fprintf(out, "\t\t<SOA>\n");
459  s = duration2string(sc->soa_ttl);
460  fprintf(out, "\t\t\t<TTL>%s</TTL>\n", s?s:"(null)");
461  free((void*)s);
462  s = duration2string(sc->soa_min);
463  fprintf(out, "\t\t\t<Minimum>%s</Minimum>\n", s?s:"(null)");
464  free((void*)s);
465  fprintf(out, "\t\t\t<Serial>%s</Serial>\n",
466  sc->soa_serial?sc->soa_serial:"(null)");
467  fprintf(out, "\t\t</SOA>\n");
468  fprintf(out, "\n");
469  fprintf(out, "\t</Zone>\n");
470  fprintf(out, "</SignerConfiguration>\n");
471  }
472  return;
473 }
474 
475 
480 void
481 signconf_log(signconf_type* sc, const char* name)
482 {
483  char* resign = NULL;
484  char* refresh = NULL;
485  char* validity = NULL;
486  char* denial = NULL;
487  char* jitter = NULL;
488  char* offset = NULL;
489  char* dnskeyttl = NULL;
490  char* soattl = NULL;
491  char* soamin = NULL;
492 
493  if (sc) {
494  resign = duration2string(sc->sig_resign_interval);
495  refresh = duration2string(sc->sig_refresh_interval);
496  validity = duration2string(sc->sig_validity_default);
497  denial = duration2string(sc->sig_validity_denial);
498  jitter = duration2string(sc->sig_jitter);
500  dnskeyttl = duration2string(sc->dnskey_ttl);
501  soattl = duration2string(sc->soa_ttl);
502  soamin = duration2string(sc->soa_min);
503  /* signconf */
504  ods_log_info("[%s] zone %s signconf: RESIGN[%s] REFRESH[%s] "
505  "VALIDITY[%s] DENIAL[%s] JITTER[%s] OFFSET[%s] NSEC[%i] "
506  "DNSKEYTTL[%s] SOATTL[%s] MINIMUM[%s] SERIAL[%s]",
507  sc_str, name?name:"(null)", resign?resign:"(null)",
508  refresh?refresh:"(null)", validity?validity:"(null)",
509  denial?denial:"(null)", jitter?jitter:"(null)",
510  offset?offset:"(null)", (int) sc->nsec_type,
511  dnskeyttl?dnskeyttl:"(null)", soattl?soattl:"(null)",
512  soamin?soamin:"(null)", sc->soa_serial?sc->soa_serial:"(null)");
513  /* nsec3 parameters */
514  if (sc->nsec_type == LDNS_RR_TYPE_NSEC3) {
515  ods_log_debug("[%s] zone %s nsec3: OPTOUT[%i] ALGORITHM[%u] "
516  "ITERATIONS[%u] SALT[%s]", sc_str, name, sc->nsec3_optout,
517  sc->nsec3_algo, sc->nsec3_iterations,
518  sc->nsec3_salt?sc->nsec3_salt:"(null)");
519  }
520  /* keys */
521  keylist_log(sc->keys, name);
522  /* cleanup */
523  free((void*)resign);
524  free((void*)refresh);
525  free((void*)validity);
526  free((void*)denial);
527  free((void*)jitter);
528  free((void*)offset);
529  free((void*)dnskeyttl);
530  free((void*)soattl);
531  free((void*)soamin);
532  }
533  return;
534 }
535 
536 
541 void
543 {
544  allocator_type* allocator = NULL;
545  if (!sc) {
546  return;
547  }
557  keylist_cleanup(sc->keys);
559  allocator = sc->allocator;
560  allocator_deallocate(allocator, (void*) sc->filename);
561  allocator_deallocate(allocator, (void*) sc->nsec3_salt);
562  allocator_deallocate(allocator, (void*) sc->soa_serial);
563  allocator_deallocate(allocator, (void*) sc);
564  allocator_cleanup(allocator);
565  return;
566 }