OpenDNSSEC-signer 1.2.1
|
00001 /* 00002 * $Id: signconf.c 4294 2011-01-13 19:58:29Z jakob $ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00034 #include "parser/confparser.h" 00035 #include "parser/signconfparser.h" 00036 #include "scheduler/task.h" 00037 #include "signer/backup.h" 00038 #include "signer/se_key.h" 00039 #include "signer/signconf.h" 00040 #include "util/duration.h" 00041 #include "util/file.h" 00042 #include "util/log.h" 00043 #include "util/se_malloc.h" 00044 00049 signconf_type* 00050 signconf_create(void) 00051 { 00052 signconf_type* sc = (signconf_type*) se_malloc(sizeof(signconf_type)); 00053 00054 /* Signatures */ 00055 sc->sig_resign_interval = NULL; 00056 sc->sig_refresh_interval = NULL; 00057 sc->sig_validity_default = NULL; 00058 sc->sig_validity_denial = NULL; 00059 sc->sig_jitter = NULL; 00060 sc->sig_inception_offset = NULL; 00061 /* Denial of existence */ 00062 sc->nsec_type = 0; 00063 sc->nsec3_optout = 0; 00064 sc->nsec3_algo = 0; 00065 sc->nsec3_iterations = 0; 00066 sc->nsec3_salt = NULL; 00067 /* Keys */ 00068 sc->dnskey_ttl = NULL; 00069 sc->keys = NULL; 00070 /* Source of authority */ 00071 sc->soa_ttl = NULL; 00072 sc->soa_min = NULL; 00073 sc->soa_serial = NULL; 00074 /* Other useful information */ 00075 sc->last_modified = 0; 00076 sc->audit = 0; 00077 00078 return sc; 00079 } 00080 00081 00086 signconf_type* 00087 signconf_read(const char* filename, time_t last_modified) 00088 { 00089 signconf_type* signconf; 00090 const char* rngfile = ODS_SE_RNGDIR "/signconf.rng"; 00091 FILE* scfd = NULL; 00092 time_t st_mtime = 0; 00093 00094 st_mtime = se_file_lastmodified(filename); 00095 if (st_mtime <= last_modified) { 00096 se_log_debug("signconf file %s is unchanged", 00097 filename?filename:"(null)"); 00098 return NULL; 00099 } 00100 00101 if (parse_file_check(filename, rngfile) != 0) { 00102 se_log_error("unable to parse signconf file %s", 00103 filename?filename:"(null)"); 00104 return NULL; 00105 } 00106 00107 scfd = se_fopen(filename, NULL, "r"); 00108 if (scfd) { 00109 signconf = signconf_create(); 00110 signconf->filename = se_strdup(filename); 00111 signconf->sig_resign_interval = parse_sc_sig_resign_interval(filename); 00112 signconf->sig_refresh_interval = parse_sc_sig_refresh_interval(filename); 00113 signconf->sig_validity_default = parse_sc_sig_validity_default(filename); 00114 signconf->sig_validity_denial = parse_sc_sig_validity_denial(filename); 00115 signconf->sig_jitter = parse_sc_sig_jitter(filename); 00116 signconf->sig_inception_offset = parse_sc_sig_inception_offset(filename); 00117 signconf->nsec_type = parse_sc_nsec_type(filename); 00118 if (signconf->nsec_type == LDNS_RR_TYPE_NSEC3) { 00119 signconf->nsec3_optout = parse_sc_nsec3_optout(filename); 00120 signconf->nsec3_algo = parse_sc_nsec3_algorithm(filename); 00121 signconf->nsec3_iterations = parse_sc_nsec3_iterations(filename); 00122 signconf->nsec3_salt = parse_sc_nsec3_salt(filename); 00123 } 00124 signconf->keys = parse_sc_keys(filename); 00125 signconf->dnskey_ttl = parse_sc_dnskey_ttl(filename); 00126 signconf->soa_ttl = parse_sc_soa_ttl(filename); 00127 signconf->soa_min = parse_sc_soa_min(filename); 00128 signconf->soa_serial = parse_sc_soa_serial(filename); 00129 signconf->audit = parse_sc_audit(filename); 00130 signconf->last_modified = st_mtime; 00131 00132 se_fclose(scfd); 00133 return signconf; 00134 } 00135 00136 se_log_error("unable to read signconf file %s", filename?filename:"(null)"); 00137 return NULL; 00138 } 00139 00140 00145 signconf_type* 00146 signconf_recover_from_backup(const char* filename) 00147 { 00148 signconf_type* signconf = NULL; 00149 const char* zonename = NULL; 00150 FILE* scfd = NULL; 00151 00152 scfd = se_fopen(filename, NULL, "r"); 00153 if (scfd) { 00154 signconf = signconf_create(); 00155 00156 if (!backup_read_check_str(scfd, ODS_SE_FILE_MAGIC) || 00157 !backup_read_check_str(scfd, ";name:") || 00158 !backup_read_str(scfd, &zonename) || 00159 !backup_read_check_str(scfd, ";filename:") || 00160 !backup_read_str(scfd, &signconf->filename) || 00161 !backup_read_check_str(scfd, ";last_modified:") || 00162 !backup_read_time_t(scfd, &signconf->last_modified) || 00163 !backup_read_check_str(scfd, ";sig_resign_interval:") || 00164 !backup_read_duration(scfd, &signconf->sig_resign_interval) || 00165 !backup_read_check_str(scfd, ";sig_refresh_interval:") || 00166 !backup_read_duration(scfd, &signconf->sig_refresh_interval) || 00167 !backup_read_check_str(scfd, ";sig_validity_default:") || 00168 !backup_read_duration(scfd, &signconf->sig_validity_default) || 00169 !backup_read_check_str(scfd, ";sig_validity_denial:") || 00170 !backup_read_duration(scfd, &signconf->sig_validity_denial) || 00171 !backup_read_check_str(scfd, ";sig_jitter:") || 00172 !backup_read_duration(scfd, &signconf->sig_jitter) || 00173 !backup_read_check_str(scfd, ";sig_inception_offset:") || 00174 !backup_read_duration(scfd, &signconf->sig_inception_offset) || 00175 !backup_read_check_str(scfd, ";nsec_type:") || 00176 !backup_read_rr_type(scfd, &signconf->nsec_type) || 00177 !backup_read_check_str(scfd, ";dnskey_ttl:") || 00178 !backup_read_duration(scfd, &signconf->dnskey_ttl) || 00179 !backup_read_check_str(scfd, ";soa_ttl:") || 00180 !backup_read_duration(scfd, &signconf->soa_ttl) || 00181 !backup_read_check_str(scfd, ";soa_min:") || 00182 !backup_read_duration(scfd, &signconf->soa_min) || 00183 !backup_read_check_str(scfd, ";soa_serial:") || 00184 !backup_read_str(scfd, &signconf->soa_serial) || 00185 !backup_read_check_str(scfd, ";audit:") || 00186 !backup_read_int(scfd, &signconf->audit) || 00187 !backup_read_check_str(scfd, ODS_SE_FILE_MAGIC)) 00188 { 00189 se_log_error("unable to recover signconf backup file %s: corrupt " 00190 "backup file ", filename?filename:"(null)"); 00191 signconf_cleanup(signconf); 00192 signconf = NULL; 00193 } 00194 00195 if (zonename) { 00196 se_free((void*) zonename); 00197 } 00198 se_fclose(scfd); 00199 return signconf; 00200 } 00201 00202 se_log_debug("unable to recover signconf backup file %s", 00203 filename?filename:"(null)"); 00204 return NULL; 00205 } 00206 00207 00212 static void 00213 signconf_backup_duration(FILE* fd, const char* opt, duration_type* duration) 00214 { 00215 char* str = duration2string(duration); 00216 fprintf(fd, ";%s: %s\n", opt, str); 00217 se_free((void*) str); 00218 return; 00219 } 00220 00221 00222 00227 void 00228 signconf_backup(signconf_type* sc) 00229 { 00230 FILE* fd = NULL; 00231 char* filename = NULL; 00232 00233 se_log_assert(sc); 00234 00235 filename = se_build_path(sc->name, ".sc", 0); 00236 fd = se_fopen(filename, NULL, "w"); 00237 if (fd) { 00238 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00239 fprintf(fd, ";name: %s\n", sc->name?sc->name:"(null)"); 00240 fprintf(fd, ";filename: %s\n", sc->filename?sc->filename:"(null)"); 00241 fprintf(fd, ";last_modified: %u\n", (uint32_t) sc->last_modified); 00242 00243 signconf_backup_duration(fd, "sig_resign_interval", 00244 sc->sig_resign_interval); 00245 signconf_backup_duration(fd, "sig_refresh_interval", 00246 sc->sig_refresh_interval); 00247 signconf_backup_duration(fd, "sig_validity_default", 00248 sc->sig_validity_default); 00249 signconf_backup_duration(fd, "sig_validity_denial", 00250 sc->sig_validity_denial); 00251 signconf_backup_duration(fd, "sig_jitter", 00252 sc->sig_jitter); 00253 signconf_backup_duration(fd, "sig_inception_offset", 00254 sc->sig_inception_offset); 00255 00256 fprintf(fd, ";nsec_type: %u\n", (unsigned int) sc->nsec_type); 00257 00258 signconf_backup_duration(fd, "dnskey_ttl", sc->dnskey_ttl); 00261 signconf_backup_duration(fd, "soa_ttl", sc->soa_ttl); 00262 signconf_backup_duration(fd, "soa_min", sc->soa_min); 00263 fprintf(fd, ";soa_serial: %s\n", 00264 sc->soa_serial?sc->soa_serial:"(null)"); 00265 00266 fprintf(fd, ";audit: %i\n", sc->audit); 00267 00268 fprintf(fd, "%s\n", ODS_SE_FILE_MAGIC); 00269 se_fclose(fd); 00270 } else { 00271 se_log_warning("cannot backup signconf: cannot open file " 00272 "%s for writing", filename?filename:"(null)"); 00273 } 00274 se_free((void*) filename); 00275 return; 00276 } 00277 00278 00283 static int 00284 signconf_soa_serial_check(const char* serial) { 00285 if (!serial) { 00286 return 1; 00287 } 00288 00289 if (strlen(serial) == 4 && strncmp(serial, "keep", 4) == 0) { 00290 return 0; 00291 } 00292 if (strlen(serial) == 7 && strncmp(serial, "counter", 7) == 0) { 00293 return 0; 00294 } 00295 if (strlen(serial) == 8 && strncmp(serial, "unixtime", 8) == 0) { 00296 return 0; 00297 } 00298 if (strlen(serial) == 11 && strncmp(serial, "datecounter", 11) == 0) { 00299 return 0; 00300 } 00301 return 1; 00302 } 00303 00308 int 00309 signconf_check(signconf_type* sc) 00310 { 00311 int ret = 0; 00312 00313 if (!sc->sig_resign_interval) { 00314 se_log_error("signconf-check: no signature resign interval found"); 00315 ret = 1; 00316 } 00317 if (!sc->sig_refresh_interval) { 00318 se_log_error("signconf-check: no signature resign interval found"); 00319 ret = 1; 00320 } 00321 if (!sc->sig_validity_default) { 00322 se_log_error("signconf-check: no signature default validity found"); 00323 ret = 1; 00324 } 00325 if (!sc->sig_validity_denial) { 00326 se_log_error("signconf-check: no signature denial validity found"); 00327 ret = 1; 00328 } 00329 if (!sc->sig_jitter) { 00330 se_log_error("signconf-check: no signature jitter found"); 00331 ret = 1; 00332 } 00333 if (!sc->sig_inception_offset) { 00334 se_log_error("signconf-check: no signature inception offset found"); 00335 ret = 1; 00336 } 00337 if (sc->nsec_type == LDNS_RR_TYPE_NSEC3) { 00338 if (sc->nsec3_algo == 0) { 00339 se_log_error("signconf-check: no nsec3 algorithm found"); 00340 ret = 1; 00341 } 00342 /* iterations */ 00343 /* salt */ 00344 /* optout */ 00345 } else if (sc->nsec_type != LDNS_RR_TYPE_NSEC) { 00346 se_log_error("signconf-check: wrong nsec type %i", sc->nsec_type); 00347 ret = 1; 00348 } 00349 if (!sc->keys || sc->keys->count == 0) { 00350 se_log_error("signconf-check: no keys found"); 00351 ret = 1; 00352 } 00353 if (!sc->dnskey_ttl) { 00354 se_log_error("signconf-check: no dnskey ttl found"); 00355 ret = 1; 00356 } 00357 if (!sc->soa_ttl) { 00358 se_log_error("signconf-check: no soa ttl found"); 00359 ret = 1; 00360 } 00361 if (!sc->soa_min) { 00362 se_log_error("signconf-check: no soa minimum found"); 00363 ret = 1; 00364 } 00365 if (signconf_soa_serial_check(sc->soa_serial) != 0) { 00366 se_log_error("signconf-check: wrong soa serial type %s", 00367 sc->soa_serial?sc->soa_serial:"(null)"); 00368 ret = 1; 00369 } 00370 00371 if (!ret) { 00372 se_log_debug("signer configuration settings ok"); 00373 } 00374 return ret; 00375 00376 } 00377 00378 00383 int 00384 signconf_compare(signconf_type* a, signconf_type* b, int* update) 00385 { 00386 int new_task = TASK_SIGN; 00387 00388 se_log_assert(a); 00389 se_log_assert(b); 00390 00391 if (a->nsec_type != b->nsec_type) { 00392 new_task = TASK_READ; 00393 *update = 1; 00394 } else if (a->nsec_type == LDNS_RR_TYPE_NSEC3) { 00395 if ((se_strcmp(a->nsec3_salt, b->nsec3_salt) != 0) || 00396 (a->nsec3_algo != b->nsec3_algo) || 00397 (a->nsec3_iterations != b->nsec3_iterations) || 00398 (a->nsec3_optout != b->nsec3_optout)) { 00399 00400 new_task = TASK_READ; 00401 *update = 1; 00402 } 00403 } 00404 00405 if (duration_compare(a->soa_min, b->soa_min) != 0) { 00406 new_task = TASK_READ; 00407 *update = 1; 00408 } 00409 00410 if (keylist_compare(a->keys, b->keys) != 0) { 00411 new_task = TASK_READ; 00412 } 00413 00414 /* not like python: reschedule if resign/refresh differs */ 00415 /* this needs review, tasks correct on signconf changes? */ 00416 00417 return new_task; 00418 } 00419 00424 void 00425 signconf_cleanup(signconf_type* sc) 00426 { 00427 if (sc) { 00428 if (sc->sig_resign_interval) { 00429 duration_cleanup(sc->sig_resign_interval); 00430 sc->sig_resign_interval = NULL; 00431 } 00432 if (sc->sig_refresh_interval) { 00433 duration_cleanup(sc->sig_refresh_interval); 00434 sc->sig_refresh_interval = NULL; 00435 } 00436 if (sc->sig_validity_default) { 00437 duration_cleanup(sc->sig_validity_default); 00438 sc->sig_validity_default = NULL; 00439 } 00440 if (sc->sig_validity_denial) { 00441 duration_cleanup(sc->sig_validity_denial); 00442 sc->sig_validity_denial = NULL; 00443 } 00444 if (sc->sig_jitter) { 00445 duration_cleanup(sc->sig_jitter); 00446 sc->sig_jitter = NULL; 00447 } 00448 if (sc->sig_inception_offset) { 00449 duration_cleanup(sc->sig_inception_offset); 00450 sc->sig_inception_offset = NULL; 00451 } 00452 if (sc->dnskey_ttl) { 00453 duration_cleanup(sc->dnskey_ttl); 00454 sc->dnskey_ttl = NULL; 00455 } 00456 if (sc->soa_ttl) { 00457 duration_cleanup(sc->soa_ttl); 00458 sc->soa_ttl = NULL; 00459 } 00460 if (sc->soa_min) { 00461 duration_cleanup(sc->soa_min); 00462 sc->soa_min = NULL; 00463 } 00464 if (sc->keys) { 00465 keylist_cleanup(sc->keys); 00466 sc->keys = NULL; 00467 } 00468 if (sc->nsec3_salt) { 00469 se_free((void*)sc->nsec3_salt); 00470 sc->nsec3_salt = NULL; 00471 } 00472 if (sc->soa_serial) { 00473 se_free((void*)sc->soa_serial); 00474 sc->soa_serial = NULL; 00475 } 00476 if (sc->filename) { 00477 se_free((void*)sc->filename); 00478 sc->filename = NULL; 00479 } 00480 se_free((void*)sc); 00481 } else { 00482 se_log_warning("cleanup empty signconf"); 00483 } 00484 } 00485 00486 00491 void 00492 signconf_print(FILE* out, signconf_type* sc, const char* name) 00493 { 00494 char* s = NULL; 00495 00496 fprintf(out, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"); 00497 00498 if (sc) { 00499 fprintf(out, "<SignerConfiguration>\n"); 00500 fprintf(out, "\t<Zone name=\"%s\">\n", name?name:"(null)"); 00501 00502 /* Signatures */ 00503 fprintf(out, "\t\t<Signatures>\n"); 00504 s = duration2string(sc->sig_resign_interval); 00505 fprintf(out, "\t\t\t<Resign>%s</Resign>\n", s?s:"(null)"); 00506 se_free((void*)s); 00507 00508 s = duration2string(sc->sig_refresh_interval); 00509 fprintf(out, "\t\t\t<Refresh>%s</Refresh>\n", s?s:"(null)"); 00510 se_free((void*)s); 00511 00512 fprintf(out, "\t\t\t<Validity>\n"); 00513 00514 s = duration2string(sc->sig_validity_default); 00515 fprintf(out, "\t\t\t\t<Default>%s</Default>\n", s?s:"(null)"); 00516 se_free((void*)s); 00517 00518 s = duration2string(sc->sig_validity_denial); 00519 fprintf(out, "\t\t\t\t<Denial>%s</Denial>\n", s?s:"(null)"); 00520 se_free((void*)s); 00521 00522 fprintf(out, "\t\t\t</Validity>\n"); 00523 00524 s = duration2string(sc->sig_jitter); 00525 fprintf(out, "\t\t\t<Jitter>%s</Jitter>\n", s?s:"(null)"); 00526 se_free((void*)s); 00527 00528 s = duration2string(sc->sig_inception_offset); 00529 fprintf(out, "\t\t\t<InceptionOffset>%s</InceptionOffset>\n", 00530 s?s:"(null)"); 00531 se_free((void*)s); 00532 00533 fprintf(out, "\t\t</Signatures>\n"); 00534 fprintf(out, "\n"); 00535 00536 /* Denial */ 00537 fprintf(out, "\t\t<Denial>\n"); 00538 if (sc->nsec_type == LDNS_RR_TYPE_NSEC) { 00539 fprintf(out, "\t\t\t<NSEC />\n"); 00540 } else if (sc->nsec_type == LDNS_RR_TYPE_NSEC3) { 00541 fprintf(out, "\t\t\t<NSEC3>\n"); 00542 if (sc->nsec3_optout) { 00543 fprintf(out, "\t\t\t\t<OptOut />\n"); 00544 } 00545 fprintf(out, "\t\t\t\t<Hash>\n"); 00546 fprintf(out, "\t\t\t\t\t<Algorithm>%i</Algorithm>\n", 00547 sc->nsec3_algo); 00548 fprintf(out, "\t\t\t\t\t<Iterations>%i</Iterations>\n", 00549 sc->nsec3_iterations); 00550 fprintf(out, "\t\t\t\t\t<Salt>%s</Salt>\n", 00551 sc->nsec3_salt?sc->nsec3_salt:"(null)"); 00552 fprintf(out, "\t\t\t\t</Hash>\n"); 00553 fprintf(out, "\t\t\t</NSEC3>\n"); 00554 } 00555 fprintf(out, "\t\t</Denial>\n"); 00556 fprintf(out, "\n"); 00557 00558 /* Keys */ 00559 fprintf(out, "\t\t<Keys>\n"); 00560 s = duration2string(sc->dnskey_ttl); 00561 fprintf(out, "\t\t\t<TTL>%s</TTL>\n", s?s:"(null)"); 00562 se_free((void*)s); 00563 fprintf(out, "\n"); 00564 keylist_print(out, sc->keys); 00565 fprintf(out, "\t\t</Keys>\n"); 00566 fprintf(out, "\n"); 00567 00568 /* SOA */ 00569 fprintf(out, "\t\t<SOA>\n"); 00570 s = duration2string(sc->soa_ttl); 00571 fprintf(out, "\t\t\t<TTL>%s</TTL>\n", s?s:"(null)"); 00572 se_free((void*)s); 00573 00574 s = duration2string(sc->soa_min); 00575 fprintf(out, "\t\t\t<Minimum>%s</Minimum>\n", s?s:"(null)"); 00576 se_free((void*)s); 00577 00578 fprintf(out, "\t\t\t<Serial>%s</Serial>\n", 00579 sc->soa_serial?sc->soa_serial:"(null)"); 00580 fprintf(out, "\t\t</SOA>\n"); 00581 fprintf(out, "\n"); 00582 00583 /* Audit */ 00584 if (sc->audit) { 00585 fprintf(out, "\t\t<Audit />\n"); 00586 fprintf(out, "\n"); 00587 } 00588 00589 fprintf(out, "\t</Zone>\n"); 00590 fprintf(out, "</SignerConfiguration>\n"); 00591 } 00592 00593 return; 00594 }