/* * ldns-signzone signs a zone file * * (c) NLnet Labs, 2005 - 2008 * See the file LICENSE for the license */ #include "config.h" #include #include #include #include #include #include #ifdef HAVE_SSL #include #include #endif /* HAVE_SSL */ #define MAX_FILENAME_LEN 250 int verbosity = 1; #ifdef HAVE_SSL #include static void usage(FILE *fp, const char *prog) { fprintf(fp, "%s [OPTIONS] zonefile key [key [key]]\n", prog); fprintf(fp, " signs the zone with the given key(s)\n"); fprintf(fp, " -d\t\tused keys are not added to the zone\n"); fprintf(fp, " -e \texpiration date\n"); fprintf(fp, " -f \toutput zone to file (default .signed)\n"); fprintf(fp, " -i \tinception date\n"); fprintf(fp, " -l\t\tLeave old DNSSEC RRSIGS and NSEC(3) records intact\n"); fprintf(fp, " -o \torigin for the zone\n"); fprintf(fp, " -v\t\tprint version and exit\n"); fprintf(fp, " -A\t\tsign DNSKEY with all keys instead of minimal\n"); fprintf(fp, " -E \tuse as the crypto engine for signing\n"); fprintf(fp, " \tThis can have a lot of extra options, see the manual page for more info\n"); fprintf(fp, " -k ,\tuse key id with algorithm int from engine\n"); fprintf(fp, " -K ,\tuse key id with algorithm int from engine as KSK\n"); fprintf(fp, "\t\tif no key is given (but an external one is used through the engine support, it might be necessary to provide the right algorithm number.\n"); fprintf(fp, " -n\t\tuse NSEC3 instead of NSEC.\n"); fprintf(fp, "\t\tIf you use NSEC3, you can specify the following extra options:\n"); fprintf(fp, "\t\t-a [algorithm] hashing algorithm\n"); fprintf(fp, "\t\t-t [number] number of hash iterations\n"); fprintf(fp, "\t\t-s [string] salt\n"); fprintf(fp, "\t\t-p set the opt-out flag on all nsec3 rrs\n"); fprintf(fp, "\n"); fprintf(fp, " keys must be specified by their base name (usually K++),\n"); fprintf(fp, " i.e. WITHOUT the .private extension.\n"); fprintf(fp, " If the public part of the key is not present in the zone, the DNSKEY RR\n"); fprintf(fp, " will be read from the file called .key. If that does not exist,\n"); fprintf(fp, " a default DNSKEY will be generated from the private key and added to the zone.\n"); fprintf(fp, " A date can be a timestamp (seconds since the epoch), or of\n the form \n"); } void usage_openssl(FILE *fp, const char *prog) { fprintf(fp, "Special commands for openssl engines:\n"); fprintf(fp, "-c \tOpenSSL config file\n"); } static void check_tm(struct tm tm) { if (tm.tm_year < 70) { fprintf(stderr, "You cannot specify dates before 1970\n"); exit(EXIT_FAILURE); } if (tm.tm_mon < 0 || tm.tm_mon > 11) { fprintf(stderr, "The month must be in the range 1 to 12\n"); exit(EXIT_FAILURE); } if (tm.tm_mday < 1 || tm.tm_mday > 31) { fprintf(stderr, "The day must be in the range 1 to 31\n"); exit(EXIT_FAILURE); } if (tm.tm_hour < 0 || tm.tm_hour > 23) { fprintf(stderr, "The hour must be in the range 0-23\n"); exit(EXIT_FAILURE); } if (tm.tm_min < 0 || tm.tm_min > 59) { fprintf(stderr, "The minute must be in the range 0-59\n"); exit(EXIT_FAILURE); } if (tm.tm_sec < 0 || tm.tm_sec > 59) { fprintf(stderr, "The second must be in the range 0-59\n"); exit(EXIT_FAILURE); } } /* * if the ttls are different, make them equal * if one of the ttls equals LDNS_DEFAULT_TTL, that one is changed * otherwise, rr2 will get the ttl of rr1 * * prints a warning if a non-default TTL is changed */ static void equalize_ttls(ldns_rr *rr1, ldns_rr *rr2, uint32_t default_ttl) { uint32_t ttl1, ttl2; ttl1 = ldns_rr_ttl(rr1); ttl2 = ldns_rr_ttl(rr2); if (ttl1 != ttl2) { if (ttl1 == default_ttl) { ldns_rr_set_ttl(rr1, ttl2); } else if (ttl2 == default_ttl) { ldns_rr_set_ttl(rr2, ttl1); } else { ldns_rr_set_ttl(rr2, ttl1); fprintf(stderr, "warning: changing non-default TTL %u to %u\n", (unsigned int) ttl2, (unsigned int) ttl1); } } } static void equalize_ttls_rr_list(ldns_rr_list *rr_list, ldns_rr *rr, uint32_t default_ttl) { size_t i; ldns_rr *cur_rr; for (i = 0; i < ldns_rr_list_rr_count(rr_list); i++) { cur_rr = ldns_rr_list_rr(rr_list, i); if (ldns_rr_compare_no_rdata(cur_rr, rr) == 0) { equalize_ttls(cur_rr, rr, default_ttl); } } } static ldns_rr * find_key_in_zone(ldns_rr *pubkey_gen, ldns_zone *zone) { size_t key_i; ldns_rr *pubkey; for (key_i = 0; key_i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); key_i++) { pubkey = ldns_rr_list_rr(ldns_zone_rrs(zone), key_i); if (ldns_rr_get_type(pubkey) == LDNS_RR_TYPE_DNSKEY && (ldns_calc_keytag(pubkey) == ldns_calc_keytag(pubkey_gen) || /* KSK has gen-keytag + 1 */ ldns_calc_keytag(pubkey) == ldns_calc_keytag(pubkey_gen) + 1) ) { if (verbosity >= 2) { fprintf(stderr, "Found it in the zone!\n"); } return pubkey; } } return NULL; } static ldns_rr * find_key_in_file(const char *keyfile_name_base, ldns_key *key, uint32_t zone_ttl) { char *keyfile_name; FILE *keyfile; int line_nr; uint32_t default_ttl = zone_ttl; ldns_rr *pubkey = NULL; keyfile_name = LDNS_XMALLOC(char, strlen(keyfile_name_base) + 5); snprintf(keyfile_name, strlen(keyfile_name_base) + 5, "%s.key", keyfile_name_base); if (verbosity >= 2) { fprintf(stderr, "Trying to read %s\n", keyfile_name); } keyfile = fopen(keyfile_name, "r"); line_nr = 0; if (keyfile) { if (ldns_rr_new_frm_fp_l(&pubkey, keyfile, &default_ttl, NULL, NULL, &line_nr) == LDNS_STATUS_OK) { if (verbosity >= 2) { printf("Key found in file: %s\n", keyfile_name); } } fclose(keyfile); } LDNS_FREE(keyfile_name); return pubkey; } /* this function tries to find the specified keys either in the zone that * has been read, or in a .key file. If the key is not found, * a public key is generated, and it is assumed the key is a ZSK * * if add_keys is true; the DNSKEYs are added to the zone prior to signing * if it is false, they are not added. * Even if keys are not added, the function is still needed, to check * whether keys of which we only have key data are KSKs or ZSKS */ static ldns_status find_or_create_pubkey(const char *keyfile_name_base, ldns_key *key, ldns_zone *orig_zone, bool add_keys, uint32_t default_ttl) { ldns_rr *pubkey_gen, *pubkey; int key_in_zone; if (default_ttl == LDNS_DEFAULT_TTL) { default_ttl = ldns_rr_ttl(ldns_zone_soa(orig_zone)); } if (!ldns_key_pubkey_owner(key)) { ldns_key_set_pubkey_owner(key, ldns_rdf_clone(ldns_rr_owner(ldns_zone_soa(orig_zone)))); } /* find the public key in the zone, or in a * seperate file * we 'generate' one anyway, * then match that to any present in the zone, * if it matches, we drop our own. If not, * we try to see if there is a .key file present. * If not, we use our own generated one, with * some default values * * Even if -d (do-not-add-keys) is specified, * we still need to do this, because we need * to have any key flags that are set this way */ pubkey_gen = ldns_key2rr(key); ldns_rr_set_ttl(pubkey_gen, default_ttl); if (verbosity >= 2) { fprintf(stderr, "Looking for key with keytag %u or %u\n", (unsigned int) ldns_calc_keytag(pubkey_gen), (unsigned int) ldns_calc_keytag(pubkey_gen)+1 ); } pubkey = find_key_in_zone(pubkey_gen, orig_zone); key_in_zone = 1; if (!pubkey) { key_in_zone = 0; /* it was not in the zone, try to read a .key file */ pubkey = find_key_in_file(keyfile_name_base, key, default_ttl); if (!pubkey && !(ldns_key_flags(key) & LDNS_KEY_SEP_KEY)) { /* maybe it is a ksk? */ ldns_key_set_keytag(key, ldns_key_keytag(key) + 1); pubkey = find_key_in_file(keyfile_name_base, key, default_ttl); if (!pubkey) { /* ok, no file, set back to ZSK */ ldns_key_set_keytag(key, ldns_key_keytag(key) - 1); } } if(pubkey && ldns_dname_compare(ldns_rr_owner(pubkey), ldns_rr_owner(ldns_zone_soa(orig_zone))) != 0) { fprintf(stderr, "Error %s.key has wrong name: %s\n", keyfile_name_base, ldns_rdf2str(ldns_rr_owner(pubkey))); exit(EXIT_FAILURE); /* leak rdf2str, but we exit */ } } if (!pubkey) { /* okay, no public key found, just use our generated one */ pubkey = pubkey_gen; if (verbosity >= 2) { fprintf(stderr, "Not in zone, no .key file, generating ZSK DNSKEY from private key data\n"); } } else { ldns_rr_free(pubkey_gen); } ldns_key_set_flags(key, ldns_rdf2native_int16(ldns_rr_rdf(pubkey, 0))); ldns_key_set_keytag(key, ldns_calc_keytag(pubkey)); if (add_keys && !key_in_zone) { equalize_ttls_rr_list(ldns_zone_rrs(orig_zone), pubkey, default_ttl); ldns_zone_push_rr(orig_zone, pubkey); } return LDNS_STATUS_OK; } void strip_dnssec_records(ldns_zone *zone) { ldns_rr_list *new_list; ldns_rr *cur_rr; new_list = ldns_rr_list_new(); while ((cur_rr = ldns_rr_list_pop_rr(ldns_zone_rrs(zone)))) { if (ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_RRSIG || ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_NSEC || ldns_rr_get_type(cur_rr) == LDNS_RR_TYPE_NSEC3 ) { ldns_rr_free(cur_rr); } else { ldns_rr_list_push_rr(new_list, cur_rr); } } ldns_rr_list_free(ldns_zone_rrs(zone)); ldns_zone_set_rrs(zone, new_list); } int main(int argc, char *argv[]) { const char *zonefile_name; FILE *zonefile = NULL; int line_nr = 0; int c; int argi; ENGINE *engine = NULL; ldns_zone *orig_zone; ldns_rr_list *orig_rrs = NULL; ldns_rr *orig_soa = NULL; ldns_dnssec_zone *signed_zone; char *keyfile_name_base; char *keyfile_name = NULL; FILE *keyfile = NULL; ldns_key *key = NULL; ldns_key_list *keys; ldns_status s; size_t i; ldns_rr_list *added_rrs; ldns_status status; bool leave_old_dnssec_data = false; char *outputfile_name = NULL; FILE *outputfile; /* tmp vars for engine keys */ char *eng_key_l; size_t eng_key_id_len; char *eng_key_id; int eng_key_algo; bool use_nsec3 = false; int signflags = 0; /* Add the given keys to the zone if they are not yet present */ bool add_keys = true; uint8_t nsec3_algorithm = 1; uint8_t nsec3_flags = 0; size_t nsec3_iterations_cmd = 1; uint16_t nsec3_iterations = 1; uint8_t nsec3_salt_length = 0; uint8_t *nsec3_salt = NULL; /* we need to know the origin before reading ksk's, * so keep an array of filenames until we know it */ struct tm tm; uint32_t inception; uint32_t expiration; ldns_rdf *origin = NULL; uint32_t ttl = LDNS_DEFAULT_TTL; ldns_rr_class class = LDNS_RR_CLASS_IN; char *prog = strdup(argv[0]); ldns_status result; inception = 0; expiration = 0; keys = ldns_key_list_new(); OPENSSL_config(NULL); while ((c = getopt(argc, argv, "a:de:f:i:k:lno:ps:t:vAE:K:")) != -1) { switch (c) { case 'a': nsec3_algorithm = (uint8_t) atoi(optarg); break; case 'd': add_keys = false; break; case 'e': /* try to parse YYYYMMDD first, * if that doesn't work, it * should be a timestamp (seconds since epoch) */ memset(&tm, 0, sizeof(tm)); if (strlen(optarg) == 8 && sscanf(optarg, "%4d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday) ) { tm.tm_year -= 1900; tm.tm_mon--; check_tm(tm); expiration = (uint32_t) mktime_from_utc(&tm); } else if (strlen(optarg) == 14 && sscanf(optarg, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) ) { tm.tm_year -= 1900; tm.tm_mon--; check_tm(tm); expiration = (uint32_t) mktime_from_utc(&tm); } else { expiration = (uint32_t) atol(optarg); } break; case 'f': outputfile_name = LDNS_XMALLOC(char, MAX_FILENAME_LEN); strncpy(outputfile_name, optarg, MAX_FILENAME_LEN); break; case 'i': memset(&tm, 0, sizeof(tm)); if (strlen(optarg) == 8 && sscanf(optarg, "%4d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday) ) { tm.tm_year -= 1900; tm.tm_mon--; check_tm(tm); inception = (uint32_t) mktime_from_utc(&tm); } else if (strlen(optarg) == 14 && sscanf(optarg, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) ) { tm.tm_year -= 1900; tm.tm_mon--; check_tm(tm); inception = (uint32_t) mktime_from_utc(&tm); } else { inception = (uint32_t) atol(optarg); } break; case 'l': leave_old_dnssec_data = true; break; case 'n': use_nsec3 = true; break; case 'o': if (ldns_str2rdf_dname(&origin, optarg) != LDNS_STATUS_OK) { fprintf(stderr, "Bad origin, not a correct domain name\n"); usage(stderr, prog); exit(EXIT_FAILURE); } break; case 'p': nsec3_flags = nsec3_flags | LDNS_NSEC3_VARS_OPTOUT_MASK; break; case 'v': printf("zone signer version %s (ldns version %s)\n", LDNS_VERSION, ldns_version()); exit(EXIT_SUCCESS); break; case 'A': signflags |= LDNS_SIGN_DNSKEY_WITH_ZSK; break; case 'E': ENGINE_load_builtin_engines(); ENGINE_load_dynamic(); ENGINE_load_cryptodev(); engine = ENGINE_by_id(optarg); if (!engine) { printf("No such engine: %s\n", optarg); engine = ENGINE_get_first(); printf("Available engines:\n"); while (engine) { printf("%s\n", ENGINE_get_id(engine)); engine = ENGINE_get_next(engine); } exit(EXIT_FAILURE); } else { if (!ENGINE_init(engine)) { printf("The engine couldn't initialize\n"); exit(EXIT_FAILURE); } ENGINE_set_default_RSA(engine); ENGINE_set_default_DSA(engine); ENGINE_set_default(engine, 0); } break; case 'k': eng_key_l = strchr(optarg, ','); if (eng_key_l && strlen(eng_key_l) > 1) { if (eng_key_l > optarg) { eng_key_id_len = (size_t) (eng_key_l - optarg); eng_key_id = malloc(eng_key_id_len + 1); memcpy(eng_key_id, optarg, eng_key_id_len); eng_key_id[eng_key_id_len] = '\0'; } else { /* no id given, use default from engine */ eng_key_id = NULL; } eng_key_algo = atoi(eng_key_l + 1); printf("Engine key id: %s, algo %d\n", eng_key_id, eng_key_algo); if (expiration != 0) { ldns_key_set_expiration(key, expiration); } if (inception != 0) { ldns_key_set_inception(key, inception); } s = ldns_key_new_frm_engine(&key, engine, eng_key_id, eng_key_algo); if (s == LDNS_STATUS_OK) { /* must be dnssec key */ switch (ldns_key_algorithm(key)) { case LDNS_SIGN_RSAMD5: case LDNS_SIGN_RSASHA1: case LDNS_SIGN_RSASHA1_NSEC3: case LDNS_SIGN_RSASHA256: case LDNS_SIGN_RSASHA512: case LDNS_SIGN_DSA: case LDNS_SIGN_DSA_NSEC3: case LDNS_SIGN_ECC_GOST: #ifdef USE_ECDSA case LDNS_SIGN_ECDSAP256SHA256: case LDNS_SIGN_ECDSAP384SHA384: #endif ldns_key_list_push_key(keys, key); /*printf("Added key at %p:\n", key);*/ /*ldns_key_print(stdout, key);*/ break; default: fprintf(stderr, "Warning, key not suitable for signing, ignoring key with algorithm %u\n", ldns_key_algorithm(key)); break; } } else { printf("Error reading key '%s' from engine: %s\n", eng_key_id, ldns_get_errorstr_by_id(s)); #ifdef HAVE_SSL if (ERR_peek_error()) { ERR_load_crypto_strings(); ERR_print_errors_fp(stderr); ERR_free_strings(); } #endif exit(EXIT_FAILURE); } if (eng_key_id) { free(eng_key_id); } } else { printf("Error: bad engine key specification (should be: -k ,)).\n"); exit(EXIT_FAILURE); } break; case 'K': printf("Not implemented yet\n"); exit(EXIT_FAILURE); break; case 's': if (strlen(optarg) % 2 != 0) { fprintf(stderr, "Salt value is not valid hex data, not a multiple of 2 characters\n"); exit(EXIT_FAILURE); } nsec3_salt_length = (uint8_t) strlen(optarg) / 2; nsec3_salt = LDNS_XMALLOC(uint8_t, nsec3_salt_length); for (c = 0; c < (int) strlen(optarg); c += 2) { if (isxdigit((int) optarg[c]) && isxdigit((int) optarg[c+1])) { nsec3_salt[c/2] = (uint8_t) ldns_hexdigit_to_int(optarg[c]) * 16 + ldns_hexdigit_to_int(optarg[c+1]); } else { fprintf(stderr, "Salt value is not valid hex data.\n"); exit(EXIT_FAILURE); } } break; case 't': nsec3_iterations_cmd = (size_t) atol(optarg); if (nsec3_iterations_cmd > LDNS_NSEC3_MAX_ITERATIONS) { fprintf(stderr, "Iterations count can not exceed %u, quitting\n", LDNS_NSEC3_MAX_ITERATIONS); exit(EXIT_FAILURE); } nsec3_iterations = (uint16_t) nsec3_iterations_cmd; break; default: usage(stderr, prog); exit(EXIT_SUCCESS); } } argc -= optind; argv += optind; if (argc < 1) { printf("Error: not enough arguments\n"); usage(stdout, prog); exit(EXIT_FAILURE); } else { zonefile_name = argv[0]; } /* read zonefile first to find origin if not specified */ if (strncmp(zonefile_name, "-", 2) == 0) { s = ldns_zone_new_frm_fp_l(&orig_zone, stdin, origin, ttl, class, &line_nr); if (s != LDNS_STATUS_OK) { fprintf(stderr, "Zone not read, error: %s at stdin line %d\n", ldns_get_errorstr_by_id(s), line_nr); exit(EXIT_FAILURE); } else { orig_soa = ldns_zone_soa(orig_zone); if (!orig_soa) { fprintf(stderr, "Error reading zonefile: missing SOA record\n"); exit(EXIT_FAILURE); } orig_rrs = ldns_zone_rrs(orig_zone); if (!orig_rrs) { fprintf(stderr, "Error reading zonefile: no resource records\n"); exit(EXIT_FAILURE); } } } else { zonefile = fopen(zonefile_name, "r"); if (!zonefile) { fprintf(stderr, "Error: unable to read %s (%s)\n", zonefile_name, strerror(errno)); exit(EXIT_FAILURE); } else { s = ldns_zone_new_frm_fp_l(&orig_zone, zonefile, origin, ttl, class, &line_nr); if (s != LDNS_STATUS_OK) { fprintf(stderr, "Zone not read, error: %s at %s line %d\n", ldns_get_errorstr_by_id(s), zonefile_name, line_nr); exit(EXIT_FAILURE); } else { orig_soa = ldns_zone_soa(orig_zone); if (!orig_soa) { fprintf(stderr, "Error reading zonefile: missing SOA record\n"); exit(EXIT_FAILURE); } orig_rrs = ldns_zone_rrs(orig_zone); if (!orig_rrs) { fprintf(stderr, "Error reading zonefile: no resource records\n"); exit(EXIT_FAILURE); } } fclose(zonefile); } } if (!origin) { origin = ldns_rr_owner(orig_soa); } /* read the ZSKs */ argi = 1; while (argi < argc) { keyfile_name_base = argv[argi]; keyfile_name = LDNS_XMALLOC(char, strlen(keyfile_name_base) + 9); snprintf(keyfile_name, strlen(keyfile_name_base) + 9, "%s.private", keyfile_name_base); keyfile = fopen(keyfile_name, "r"); line_nr = 0; if (!keyfile) { fprintf(stderr, "Error: unable to read %s: %s\n", keyfile_name, strerror(errno)); } else { s = ldns_key_new_frm_fp_l(&key, keyfile, &line_nr); fclose(keyfile); if (s == LDNS_STATUS_OK) { /* set times in key? they will end up in the rrsigs */ if (expiration != 0) { ldns_key_set_expiration(key, expiration); } if (inception != 0) { ldns_key_set_inception(key, inception); } LDNS_FREE(keyfile_name); ldns_key_list_push_key(keys, key); } else { fprintf(stderr, "Error reading key from %s at line %d: %s\n", argv[argi], line_nr, ldns_get_errorstr_by_id(s)); } } /* and, if not unset by -p, find or create the corresponding DNSKEY record */ if (key) { status = find_or_create_pubkey(keyfile_name_base, key, orig_zone, add_keys, ttl); } argi++; } if (ldns_key_list_key_count(keys) < 1) { fprintf(stderr, "Error: no keys to sign with. Aborting.\n\n"); usage(stderr, prog); exit(EXIT_FAILURE); } signed_zone = ldns_dnssec_zone_new(); if (ldns_dnssec_zone_add_rr(signed_zone, ldns_zone_soa(orig_zone)) != LDNS_STATUS_OK) { fprintf(stderr, "Error adding SOA to dnssec zone, skipping record\n"); } for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(orig_zone)); i++) { if (ldns_dnssec_zone_add_rr(signed_zone, ldns_rr_list_rr(ldns_zone_rrs(orig_zone), i)) != LDNS_STATUS_OK) { fprintf(stderr, "Error adding RR to dnssec zone"); fprintf(stderr, ", skipping record:\n"); ldns_rr_print(stderr, ldns_rr_list_rr(ldns_zone_rrs(orig_zone), i)); } } /* list to store newly created rrs, so we can free them later */ added_rrs = ldns_rr_list_new(); if (use_nsec3) { result = ldns_dnssec_zone_sign_nsec3_flg(signed_zone, added_rrs, keys, ldns_dnssec_default_replace_signatures, NULL, nsec3_algorithm, nsec3_flags, nsec3_iterations, nsec3_salt_length, nsec3_salt, signflags); } else { result = ldns_dnssec_zone_sign_flg(signed_zone, added_rrs, keys, ldns_dnssec_default_replace_signatures, NULL, signflags); } if (result != LDNS_STATUS_OK) { fprintf(stderr, "Error signing zone: %s\n", ldns_get_errorstr_by_id(result)); } if (!outputfile_name) { outputfile_name = LDNS_XMALLOC(char, MAX_FILENAME_LEN); snprintf(outputfile_name, MAX_FILENAME_LEN, "%s.signed", zonefile_name); } if (signed_zone) { if (strncmp(outputfile_name, "-", 2) == 0) { ldns_dnssec_zone_print(stdout, signed_zone); } else { outputfile = fopen(outputfile_name, "w"); if (!outputfile) { fprintf(stderr, "Unable to open %s for writing: %s\n", outputfile_name, strerror(errno)); } else { ldns_dnssec_zone_print(outputfile, signed_zone); fclose(outputfile); } } } else { fprintf(stderr, "Error signing zone.\n"); #ifdef HAVE_SSL if (ERR_peek_error()) { ERR_load_crypto_strings(); ERR_print_errors_fp(stderr); ERR_free_strings(); } #endif exit(EXIT_FAILURE); } ldns_key_list_free(keys); /* since the ldns_rr records are pointed to in both the ldns_zone * and the ldns_dnssec_zone, we can either deep_free the * dnssec_zone and 'shallow' free the original zone and added * records, or the other way around */ ldns_dnssec_zone_free(signed_zone); ldns_zone_deep_free(orig_zone); ldns_rr_list_deep_free(added_rrs); LDNS_FREE(outputfile_name); CRYPTO_cleanup_all_ex_data(); free(prog); exit(EXIT_SUCCESS); } #else int main(int argc, char **argv) { fprintf(stderr, "ldns-signzone needs OpenSSL support, which has not been compiled in\n"); return 1; } #endif /* HAVE_SSL */