mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-22 01:59:26 +00:00
The OpenSSL 1.x Engines support has been deprecated in the OpenSSL 3.x and is going to be removed. Remove the OpenSSL Engine support in favor of OpenSSL Providers.
963 lines
24 KiB
C
963 lines
24 KiB
C
/*
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#include <errno.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#include <isc/attributes.h>
|
|
#include <isc/buffer.h>
|
|
#include <isc/commandline.h>
|
|
#include <isc/file.h>
|
|
#include <isc/hash.h>
|
|
#include <isc/mem.h>
|
|
#include <isc/result.h>
|
|
#include <isc/string.h>
|
|
#include <isc/time.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dns/keyvalues.h>
|
|
#include <dns/log.h>
|
|
|
|
#include <dst/dst.h>
|
|
|
|
#include "dnssectool.h"
|
|
|
|
const char *program = "dnssec-settime";
|
|
|
|
static isc_mem_t *mctx = NULL;
|
|
|
|
noreturn static void
|
|
usage(void);
|
|
|
|
static void
|
|
usage(void) {
|
|
fprintf(stderr, "Usage:\n");
|
|
fprintf(stderr, " %s [options] keyfile\n\n", program);
|
|
fprintf(stderr, "Version: %s\n", PACKAGE_VERSION);
|
|
fprintf(stderr, "General options:\n");
|
|
fprintf(stderr, " -f: force update of old-style "
|
|
"keys\n");
|
|
fprintf(stderr, " -K directory: set key file location\n");
|
|
fprintf(stderr, " -L ttl: set default key TTL\n");
|
|
fprintf(stderr, " -v level: set level of verbosity\n");
|
|
fprintf(stderr, " -V: print version information\n");
|
|
fprintf(stderr, " -h: help\n");
|
|
fprintf(stderr, "Timing options:\n");
|
|
fprintf(stderr, " -P date/[+-]offset/none: set/unset key "
|
|
"publication date\n");
|
|
fprintf(stderr, " -P ds date/[+-]offset/none: set/unset "
|
|
"DS publication date\n");
|
|
fprintf(stderr, " -P sync date/[+-]offset/none: set/unset "
|
|
"CDS and CDNSKEY publication date\n");
|
|
fprintf(stderr, " -A date/[+-]offset/none: set/unset key "
|
|
"activation date\n");
|
|
fprintf(stderr, " -R date/[+-]offset/none: set/unset key "
|
|
"revocation date\n");
|
|
fprintf(stderr, " -I date/[+-]offset/none: set/unset key "
|
|
"inactivation date\n");
|
|
fprintf(stderr, " -D date/[+-]offset/none: set/unset key "
|
|
"deletion date\n");
|
|
fprintf(stderr, " -D ds date/[+-]offset/none: set/unset "
|
|
"DS deletion date\n");
|
|
fprintf(stderr, " -D sync date/[+-]offset/none: set/unset "
|
|
"CDS and CDNSKEY deletion date\n");
|
|
fprintf(stderr, " -S <key>: generate a successor to an existing "
|
|
"key\n");
|
|
fprintf(stderr, " -i <interval>: prepublication interval for "
|
|
"successor key "
|
|
"(default: 30 days)\n");
|
|
fprintf(stderr, "Key state options:\n");
|
|
fprintf(stderr, " -s: update key state file (default no)\n");
|
|
fprintf(stderr, " -g state: set the goal state for this key\n");
|
|
fprintf(stderr, " -d state date/[+-]offset: set the DS state\n");
|
|
fprintf(stderr, " -k state date/[+-]offset: set the DNSKEY state\n");
|
|
fprintf(stderr, " -r state date/[+-]offset: set the RRSIG (KSK) "
|
|
"state\n");
|
|
fprintf(stderr, " -z state date/[+-]offset: set the RRSIG (ZSK) "
|
|
"state\n");
|
|
fprintf(stderr, "Printing options:\n");
|
|
fprintf(stderr, " -p C/P/Psync/A/R/I/D/Dsync/all: print a "
|
|
"particular time value or values\n");
|
|
fprintf(stderr, " -u: print times in unix epoch "
|
|
"format\n");
|
|
fprintf(stderr, "Output:\n");
|
|
fprintf(stderr, " K<name>+<alg>+<new id>.key, "
|
|
"K<name>+<alg>+<new id>.private\n");
|
|
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
static void
|
|
printtime(dst_key_t *key, int type, const char *tag, bool epoch, FILE *stream) {
|
|
isc_result_t result;
|
|
isc_stdtime_t when;
|
|
|
|
if (tag != NULL) {
|
|
fprintf(stream, "%s: ", tag);
|
|
}
|
|
|
|
result = dst_key_gettime(key, type, &when);
|
|
if (result == ISC_R_NOTFOUND) {
|
|
fprintf(stream, "UNSET\n");
|
|
} else if (epoch) {
|
|
fprintf(stream, "%d\n", (int)when);
|
|
} else {
|
|
time_t now = when;
|
|
struct tm t, *tm = localtime_r(&now, &t);
|
|
unsigned int flen;
|
|
char timebuf[80];
|
|
|
|
if (tm == NULL) {
|
|
fprintf(stream, "INVALID\n");
|
|
return;
|
|
}
|
|
|
|
flen = strftime(timebuf, sizeof(timebuf),
|
|
"%a %b %e %H:%M:%S %Y", tm);
|
|
INSIST(flen > 0U && flen < sizeof(timebuf));
|
|
fprintf(stream, "%s\n", timebuf);
|
|
}
|
|
}
|
|
|
|
static void
|
|
writekey(dst_key_t *key, const char *directory, bool write_state) {
|
|
char newname[1024];
|
|
char keystr[DST_KEY_FORMATSIZE];
|
|
isc_buffer_t buf;
|
|
isc_result_t result;
|
|
int options = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE;
|
|
|
|
if (write_state) {
|
|
options |= DST_TYPE_STATE;
|
|
}
|
|
|
|
isc_buffer_init(&buf, newname, sizeof(newname));
|
|
result = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &buf);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("Failed to build public key filename: %s",
|
|
isc_result_totext(result));
|
|
}
|
|
|
|
result = dst_key_tofile(key, options, directory);
|
|
if (result != ISC_R_SUCCESS) {
|
|
dst_key_format(key, keystr, sizeof(keystr));
|
|
fatal("Failed to write key %s: %s", keystr,
|
|
isc_result_totext(result));
|
|
}
|
|
printf("%s\n", newname);
|
|
|
|
isc_buffer_clear(&buf);
|
|
result = dst_key_buildfilename(key, DST_TYPE_PRIVATE, directory, &buf);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("Failed to build private key filename: %s",
|
|
isc_result_totext(result));
|
|
}
|
|
printf("%s\n", newname);
|
|
|
|
if (write_state) {
|
|
isc_buffer_clear(&buf);
|
|
result = dst_key_buildfilename(key, DST_TYPE_STATE, directory,
|
|
&buf);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("Failed to build key state filename: %s",
|
|
isc_result_totext(result));
|
|
}
|
|
printf("%s\n", newname);
|
|
}
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv) {
|
|
isc_result_t result;
|
|
const char *filename = NULL;
|
|
char *directory = NULL;
|
|
char keystr[DST_KEY_FORMATSIZE];
|
|
char *endp, *p;
|
|
int ch;
|
|
const char *predecessor = NULL;
|
|
dst_key_t *prevkey = NULL;
|
|
dst_key_t *key = NULL;
|
|
dns_name_t *name = NULL;
|
|
dns_secalg_t alg = 0;
|
|
unsigned int size = 0;
|
|
uint16_t flags = 0;
|
|
int prepub = -1;
|
|
int options;
|
|
dns_ttl_t ttl = 0;
|
|
isc_stdtime_t dstime = 0, dnskeytime = 0;
|
|
isc_stdtime_t krrsigtime = 0, zrrsigtime = 0;
|
|
isc_stdtime_t pub = 0, act = 0, rev = 0, inact = 0, del = 0;
|
|
isc_stdtime_t prevact = 0, previnact = 0, prevdel = 0;
|
|
dst_key_state_t goal = DST_KEY_STATE_NA;
|
|
dst_key_state_t ds = DST_KEY_STATE_NA;
|
|
dst_key_state_t dnskey = DST_KEY_STATE_NA;
|
|
dst_key_state_t krrsig = DST_KEY_STATE_NA;
|
|
dst_key_state_t zrrsig = DST_KEY_STATE_NA;
|
|
bool setgoal = false, setds = false, setdnskey = false;
|
|
bool setkrrsig = false, setzrrsig = false;
|
|
bool setdstime = false, setdnskeytime = false;
|
|
bool setkrrsigtime = false, setzrrsigtime = false;
|
|
bool setpub = false, setact = false;
|
|
bool setrev = false, setinact = false;
|
|
bool setdel = false, setttl = false;
|
|
bool unsetpub = false, unsetact = false;
|
|
bool unsetrev = false, unsetinact = false;
|
|
bool unsetdel = false;
|
|
bool printcreate = false, printpub = false;
|
|
bool printact = false, printrev = false;
|
|
bool printinact = false, printdel = false;
|
|
bool force = false;
|
|
bool epoch = false;
|
|
bool changed = false;
|
|
bool write_state = false;
|
|
isc_log_t *log = NULL;
|
|
isc_stdtime_t syncadd = 0, syncdel = 0;
|
|
bool unsetsyncadd = false, setsyncadd = false;
|
|
bool unsetsyncdel = false, setsyncdel = false;
|
|
bool printsyncadd = false, printsyncdel = false;
|
|
isc_stdtime_t dsadd = 0, dsdel = 0;
|
|
bool unsetdsadd = false, setdsadd = false;
|
|
bool unsetdsdel = false, setdsdel = false;
|
|
bool printdsadd = false, printdsdel = false;
|
|
isc_stdtime_t now = isc_stdtime_now();
|
|
|
|
options = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE;
|
|
|
|
if (argc == 1) {
|
|
usage();
|
|
}
|
|
|
|
isc_mem_create(&mctx);
|
|
|
|
setup_logging(mctx, &log);
|
|
|
|
isc_commandline_errprint = false;
|
|
|
|
#define CMDLINE_FLAGS "A:D:d:E:fg:hI:i:K:k:L:P:p:R:r:S:suv:Vz:"
|
|
while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
|
|
switch (ch) {
|
|
case 'A':
|
|
if (setact || unsetact) {
|
|
fatal("-A specified more than once");
|
|
}
|
|
|
|
changed = true;
|
|
act = strtotime(isc_commandline_argument, now, now,
|
|
&setact);
|
|
unsetact = !setact;
|
|
break;
|
|
case 'D':
|
|
/* -Dsync ? */
|
|
if (isoptarg("sync", argv, usage)) {
|
|
if (unsetsyncdel || setsyncdel) {
|
|
fatal("-D sync specified more than "
|
|
"once");
|
|
}
|
|
|
|
changed = true;
|
|
syncdel = strtotime(isc_commandline_argument,
|
|
now, now, &setsyncdel);
|
|
unsetsyncdel = !setsyncdel;
|
|
break;
|
|
}
|
|
/* -Dds ? */
|
|
if (isoptarg("ds", argv, usage)) {
|
|
if (unsetdsdel || setdsdel) {
|
|
fatal("-D ds specified more than once");
|
|
}
|
|
|
|
changed = true;
|
|
dsdel = strtotime(isc_commandline_argument, now,
|
|
now, &setdsdel);
|
|
unsetdsdel = !setdsdel;
|
|
break;
|
|
}
|
|
/* -Ddnskey ? */
|
|
(void)isoptarg("dnskey", argv, usage);
|
|
if (setdel || unsetdel) {
|
|
fatal("-D specified more than once");
|
|
}
|
|
|
|
changed = true;
|
|
del = strtotime(isc_commandline_argument, now, now,
|
|
&setdel);
|
|
unsetdel = !setdel;
|
|
break;
|
|
case 'd':
|
|
if (setds) {
|
|
fatal("-d specified more than once");
|
|
}
|
|
|
|
ds = strtokeystate(isc_commandline_argument);
|
|
setds = true;
|
|
/* time */
|
|
(void)isoptarg(isc_commandline_argument, argv, usage);
|
|
dstime = strtotime(isc_commandline_argument, now, now,
|
|
&setdstime);
|
|
break;
|
|
case 'E':
|
|
fatal("%s", isc_result_totext(DST_R_NOENGINE));
|
|
break;
|
|
case 'f':
|
|
force = true;
|
|
break;
|
|
case 'g':
|
|
if (setgoal) {
|
|
fatal("-g specified more than once");
|
|
}
|
|
|
|
goal = strtokeystate(isc_commandline_argument);
|
|
if (goal != DST_KEY_STATE_NA &&
|
|
goal != DST_KEY_STATE_HIDDEN &&
|
|
goal != DST_KEY_STATE_OMNIPRESENT)
|
|
{
|
|
fatal("-g must be either none, hidden, or "
|
|
"omnipresent");
|
|
}
|
|
setgoal = true;
|
|
break;
|
|
case '?':
|
|
if (isc_commandline_option != '?') {
|
|
fprintf(stderr, "%s: invalid argument -%c\n",
|
|
program, isc_commandline_option);
|
|
}
|
|
FALLTHROUGH;
|
|
case 'h':
|
|
/* Does not return. */
|
|
usage();
|
|
case 'I':
|
|
if (setinact || unsetinact) {
|
|
fatal("-I specified more than once");
|
|
}
|
|
|
|
changed = true;
|
|
inact = strtotime(isc_commandline_argument, now, now,
|
|
&setinact);
|
|
unsetinact = !setinact;
|
|
break;
|
|
case 'i':
|
|
prepub = strtottl(isc_commandline_argument);
|
|
break;
|
|
case 'K':
|
|
/*
|
|
* We don't have to copy it here, but do it to
|
|
* simplify cleanup later
|
|
*/
|
|
directory = isc_mem_strdup(mctx,
|
|
isc_commandline_argument);
|
|
break;
|
|
case 'k':
|
|
if (setdnskey) {
|
|
fatal("-k specified more than once");
|
|
}
|
|
|
|
dnskey = strtokeystate(isc_commandline_argument);
|
|
setdnskey = true;
|
|
/* time */
|
|
(void)isoptarg(isc_commandline_argument, argv, usage);
|
|
dnskeytime = strtotime(isc_commandline_argument, now,
|
|
now, &setdnskeytime);
|
|
break;
|
|
case 'L':
|
|
ttl = strtottl(isc_commandline_argument);
|
|
setttl = true;
|
|
break;
|
|
case 'P':
|
|
/* -Psync ? */
|
|
if (isoptarg("sync", argv, usage)) {
|
|
if (unsetsyncadd || setsyncadd) {
|
|
fatal("-P sync specified more than "
|
|
"once");
|
|
}
|
|
|
|
changed = true;
|
|
syncadd = strtotime(isc_commandline_argument,
|
|
now, now, &setsyncadd);
|
|
unsetsyncadd = !setsyncadd;
|
|
break;
|
|
}
|
|
/* -Pds ? */
|
|
if (isoptarg("ds", argv, usage)) {
|
|
if (unsetdsadd || setdsadd) {
|
|
fatal("-P ds specified more than once");
|
|
}
|
|
|
|
changed = true;
|
|
dsadd = strtotime(isc_commandline_argument, now,
|
|
now, &setdsadd);
|
|
unsetdsadd = !setdsadd;
|
|
break;
|
|
}
|
|
/* -Pdnskey ? */
|
|
(void)isoptarg("dnskey", argv, usage);
|
|
if (setpub || unsetpub) {
|
|
fatal("-P specified more than once");
|
|
}
|
|
|
|
changed = true;
|
|
pub = strtotime(isc_commandline_argument, now, now,
|
|
&setpub);
|
|
unsetpub = !setpub;
|
|
break;
|
|
case 'p':
|
|
p = isc_commandline_argument;
|
|
if (!strcasecmp(p, "all")) {
|
|
printcreate = true;
|
|
printpub = true;
|
|
printact = true;
|
|
printrev = true;
|
|
printinact = true;
|
|
printdel = true;
|
|
printsyncadd = true;
|
|
printsyncdel = true;
|
|
printdsadd = true;
|
|
printdsdel = true;
|
|
break;
|
|
}
|
|
|
|
do {
|
|
switch (*p++) {
|
|
case 'A':
|
|
printact = true;
|
|
break;
|
|
case 'C':
|
|
printcreate = true;
|
|
break;
|
|
case 'D':
|
|
if (!strncmp(p, "sync", 4)) {
|
|
p += 4;
|
|
printsyncdel = true;
|
|
break;
|
|
}
|
|
if (!strncmp(p, "ds", 2)) {
|
|
p += 2;
|
|
printdsdel = true;
|
|
break;
|
|
}
|
|
printdel = true;
|
|
break;
|
|
case 'I':
|
|
printinact = true;
|
|
break;
|
|
case 'P':
|
|
if (!strncmp(p, "sync", 4)) {
|
|
p += 4;
|
|
printsyncadd = true;
|
|
break;
|
|
}
|
|
if (!strncmp(p, "ds", 2)) {
|
|
p += 2;
|
|
printdsadd = true;
|
|
break;
|
|
}
|
|
printpub = true;
|
|
break;
|
|
case 'R':
|
|
printrev = true;
|
|
break;
|
|
case ' ':
|
|
break;
|
|
default:
|
|
usage();
|
|
break;
|
|
}
|
|
} while (*p != '\0');
|
|
break;
|
|
case 'R':
|
|
if (setrev || unsetrev) {
|
|
fatal("-R specified more than once");
|
|
}
|
|
|
|
changed = true;
|
|
rev = strtotime(isc_commandline_argument, now, now,
|
|
&setrev);
|
|
unsetrev = !setrev;
|
|
break;
|
|
case 'r':
|
|
if (setkrrsig) {
|
|
fatal("-r specified more than once");
|
|
}
|
|
|
|
krrsig = strtokeystate(isc_commandline_argument);
|
|
setkrrsig = true;
|
|
/* time */
|
|
(void)isoptarg(isc_commandline_argument, argv, usage);
|
|
krrsigtime = strtotime(isc_commandline_argument, now,
|
|
now, &setkrrsigtime);
|
|
break;
|
|
case 'S':
|
|
predecessor = isc_commandline_argument;
|
|
break;
|
|
case 's':
|
|
write_state = true;
|
|
break;
|
|
case 'u':
|
|
epoch = true;
|
|
break;
|
|
case 'V':
|
|
/* Does not return. */
|
|
version(program);
|
|
case 'v':
|
|
verbose = strtol(isc_commandline_argument, &endp, 0);
|
|
if (*endp != '\0') {
|
|
fatal("-v must be followed by a number");
|
|
}
|
|
break;
|
|
case 'z':
|
|
if (setzrrsig) {
|
|
fatal("-z specified more than once");
|
|
}
|
|
|
|
zrrsig = strtokeystate(isc_commandline_argument);
|
|
setzrrsig = true;
|
|
(void)isoptarg(isc_commandline_argument, argv, usage);
|
|
zrrsigtime = strtotime(isc_commandline_argument, now,
|
|
now, &setzrrsigtime);
|
|
break;
|
|
|
|
default:
|
|
fprintf(stderr, "%s: unhandled option -%c\n", program,
|
|
isc_commandline_option);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
|
|
if (argc < isc_commandline_index + 1 ||
|
|
argv[isc_commandline_index] == NULL)
|
|
{
|
|
fatal("The key file name was not specified");
|
|
}
|
|
if (argc > isc_commandline_index + 1) {
|
|
fatal("Extraneous arguments");
|
|
}
|
|
|
|
if ((setgoal || setds || setdnskey || setkrrsig || setzrrsig) &&
|
|
!write_state)
|
|
{
|
|
fatal("Options -g, -d, -k, -r and -z require -s to be set");
|
|
}
|
|
|
|
result = dst_lib_init(mctx);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("Could not initialize dst: %s",
|
|
isc_result_totext(result));
|
|
}
|
|
|
|
if (predecessor != NULL) {
|
|
int major, minor;
|
|
|
|
if (prepub == -1) {
|
|
prepub = (30 * 86400);
|
|
}
|
|
|
|
if (setpub || unsetpub) {
|
|
fatal("-S and -P cannot be used together");
|
|
}
|
|
if (setact || unsetact) {
|
|
fatal("-S and -A cannot be used together");
|
|
}
|
|
|
|
result = dst_key_fromnamedfile(predecessor, directory, options,
|
|
mctx, &prevkey);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("Invalid keyfile %s: %s", filename,
|
|
isc_result_totext(result));
|
|
}
|
|
if (!dst_key_isprivate(prevkey) && !dst_key_isexternal(prevkey))
|
|
{
|
|
fatal("%s is not a private key", filename);
|
|
}
|
|
|
|
name = dst_key_name(prevkey);
|
|
alg = dst_key_alg(prevkey);
|
|
size = dst_key_size(prevkey);
|
|
flags = dst_key_flags(prevkey);
|
|
|
|
dst_key_format(prevkey, keystr, sizeof(keystr));
|
|
dst_key_getprivateformat(prevkey, &major, &minor);
|
|
if (major != DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) {
|
|
fatal("Predecessor has incompatible format "
|
|
"version %d.%d\n\t",
|
|
major, minor);
|
|
}
|
|
|
|
result = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &prevact);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("Predecessor has no activation date. "
|
|
"You must set one before\n\t"
|
|
"generating a successor.");
|
|
}
|
|
|
|
result = dst_key_gettime(prevkey, DST_TIME_INACTIVE,
|
|
&previnact);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("Predecessor has no inactivation date. "
|
|
"You must set one before\n\t"
|
|
"generating a successor.");
|
|
}
|
|
|
|
pub = previnact - prepub;
|
|
act = previnact;
|
|
|
|
if ((previnact - prepub) < now && prepub != 0) {
|
|
fatal("Time until predecessor inactivation is\n\t"
|
|
"shorter than the prepublication interval. "
|
|
"Either change\n\t"
|
|
"predecessor inactivation date, or use the -i "
|
|
"option to set\n\t"
|
|
"a shorter prepublication interval.");
|
|
}
|
|
|
|
result = dst_key_gettime(prevkey, DST_TIME_DELETE, &prevdel);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fprintf(stderr,
|
|
"%s: warning: Predecessor has no "
|
|
"removal date;\n\t"
|
|
"it will remain in the zone "
|
|
"indefinitely after rollover.\n",
|
|
program);
|
|
} else if (prevdel < previnact) {
|
|
fprintf(stderr,
|
|
"%s: warning: Predecessor is "
|
|
"scheduled to be deleted\n\t"
|
|
"before it is scheduled to be "
|
|
"inactive.\n",
|
|
program);
|
|
}
|
|
|
|
changed = setpub = setact = true;
|
|
} else {
|
|
if (prepub < 0) {
|
|
prepub = 0;
|
|
}
|
|
|
|
if (prepub > 0) {
|
|
if (setpub && setact && (act - prepub) < pub) {
|
|
fatal("Activation and publication dates "
|
|
"are closer together than the\n\t"
|
|
"prepublication interval.");
|
|
}
|
|
|
|
if (setpub && !setact) {
|
|
setact = true;
|
|
act = pub + prepub;
|
|
} else if (setact && !setpub) {
|
|
setpub = true;
|
|
pub = act - prepub;
|
|
}
|
|
|
|
if ((act - prepub) < now) {
|
|
fatal("Time until activation is shorter "
|
|
"than the\n\tprepublication interval.");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (directory != NULL) {
|
|
filename = argv[isc_commandline_index];
|
|
} else {
|
|
result = isc_file_splitpath(mctx, argv[isc_commandline_index],
|
|
&directory, &filename);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("cannot process filename %s: %s",
|
|
argv[isc_commandline_index],
|
|
isc_result_totext(result));
|
|
}
|
|
}
|
|
|
|
result = dst_key_fromnamedfile(filename, directory, options, mctx,
|
|
&key);
|
|
if (result != ISC_R_SUCCESS) {
|
|
fatal("Invalid keyfile %s: %s", filename,
|
|
isc_result_totext(result));
|
|
}
|
|
|
|
if (!dst_key_isprivate(key) && !dst_key_isexternal(key)) {
|
|
fatal("%s is not a private key", filename);
|
|
}
|
|
|
|
dst_key_format(key, keystr, sizeof(keystr));
|
|
|
|
if (predecessor != NULL) {
|
|
if (!dns_name_equal(name, dst_key_name(key))) {
|
|
fatal("Key name mismatch");
|
|
}
|
|
if (alg != dst_key_alg(key)) {
|
|
fatal("Key algorithm mismatch");
|
|
}
|
|
if (size != dst_key_size(key)) {
|
|
fatal("Key size mismatch");
|
|
}
|
|
if (flags != dst_key_flags(key)) {
|
|
fatal("Key flags mismatch");
|
|
}
|
|
}
|
|
|
|
prevdel = previnact = 0;
|
|
if ((setdel && setinact && del < inact) ||
|
|
(dst_key_gettime(key, DST_TIME_INACTIVE, &previnact) ==
|
|
ISC_R_SUCCESS &&
|
|
setdel && !setinact && !unsetinact && del < previnact) ||
|
|
(dst_key_gettime(key, DST_TIME_DELETE, &prevdel) == ISC_R_SUCCESS &&
|
|
setinact && !setdel && !unsetdel && prevdel < inact) ||
|
|
(!setdel && !unsetdel && !setinact && !unsetinact && prevdel != 0 &&
|
|
prevdel < previnact))
|
|
{
|
|
fprintf(stderr,
|
|
"%s: warning: Key is scheduled to "
|
|
"be deleted before it is\n\t"
|
|
"scheduled to be inactive.\n",
|
|
program);
|
|
}
|
|
|
|
if (force) {
|
|
set_keyversion(key);
|
|
} else {
|
|
check_keyversion(key, keystr);
|
|
}
|
|
|
|
if (verbose > 2) {
|
|
fprintf(stderr, "%s: %s\n", program, keystr);
|
|
}
|
|
|
|
/*
|
|
* Set time values.
|
|
*/
|
|
if (setpub) {
|
|
dst_key_settime(key, DST_TIME_PUBLISH, pub);
|
|
} else if (unsetpub) {
|
|
dst_key_unsettime(key, DST_TIME_PUBLISH);
|
|
}
|
|
|
|
if (setact) {
|
|
dst_key_settime(key, DST_TIME_ACTIVATE, act);
|
|
} else if (unsetact) {
|
|
dst_key_unsettime(key, DST_TIME_ACTIVATE);
|
|
}
|
|
|
|
if (setrev) {
|
|
if ((dst_key_flags(key) & DNS_KEYFLAG_REVOKE) != 0) {
|
|
fprintf(stderr,
|
|
"%s: warning: Key %s is already "
|
|
"revoked; changing the revocation date "
|
|
"will not affect this.\n",
|
|
program, keystr);
|
|
}
|
|
if ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0) {
|
|
fprintf(stderr,
|
|
"%s: warning: Key %s is not flagged as "
|
|
"a KSK, but -R was used. Revoking a "
|
|
"ZSK is legal, but undefined.\n",
|
|
program, keystr);
|
|
}
|
|
dst_key_settime(key, DST_TIME_REVOKE, rev);
|
|
} else if (unsetrev) {
|
|
if ((dst_key_flags(key) & DNS_KEYFLAG_REVOKE) != 0) {
|
|
fprintf(stderr,
|
|
"%s: warning: Key %s is already "
|
|
"revoked; removing the revocation date "
|
|
"will not affect this.\n",
|
|
program, keystr);
|
|
}
|
|
dst_key_unsettime(key, DST_TIME_REVOKE);
|
|
}
|
|
|
|
if (setinact) {
|
|
dst_key_settime(key, DST_TIME_INACTIVE, inact);
|
|
} else if (unsetinact) {
|
|
dst_key_unsettime(key, DST_TIME_INACTIVE);
|
|
}
|
|
|
|
if (setdel) {
|
|
dst_key_settime(key, DST_TIME_DELETE, del);
|
|
} else if (unsetdel) {
|
|
dst_key_unsettime(key, DST_TIME_DELETE);
|
|
}
|
|
|
|
if (setsyncadd) {
|
|
dst_key_settime(key, DST_TIME_SYNCPUBLISH, syncadd);
|
|
} else if (unsetsyncadd) {
|
|
dst_key_unsettime(key, DST_TIME_SYNCPUBLISH);
|
|
}
|
|
|
|
if (setsyncdel) {
|
|
dst_key_settime(key, DST_TIME_SYNCDELETE, syncdel);
|
|
} else if (unsetsyncdel) {
|
|
dst_key_unsettime(key, DST_TIME_SYNCDELETE);
|
|
}
|
|
|
|
if (setdsadd) {
|
|
dst_key_settime(key, DST_TIME_DSPUBLISH, dsadd);
|
|
} else if (unsetdsadd) {
|
|
dst_key_unsettime(key, DST_TIME_DSPUBLISH);
|
|
}
|
|
|
|
if (setdsdel) {
|
|
dst_key_settime(key, DST_TIME_DSDELETE, dsdel);
|
|
} else if (unsetdsdel) {
|
|
dst_key_unsettime(key, DST_TIME_DSDELETE);
|
|
}
|
|
|
|
if (setttl) {
|
|
dst_key_setttl(key, ttl);
|
|
}
|
|
|
|
if (predecessor != NULL && prevkey != NULL) {
|
|
dst_key_setnum(prevkey, DST_NUM_SUCCESSOR, dst_key_id(key));
|
|
dst_key_setnum(key, DST_NUM_PREDECESSOR, dst_key_id(prevkey));
|
|
}
|
|
|
|
/*
|
|
* No metadata changes were made but we're forcing an upgrade
|
|
* to the new format anyway: use "-P now -A now" as the default
|
|
*/
|
|
if (force && !changed) {
|
|
dst_key_settime(key, DST_TIME_PUBLISH, now);
|
|
dst_key_settime(key, DST_TIME_ACTIVATE, now);
|
|
changed = true;
|
|
}
|
|
|
|
/*
|
|
* Make sure the key state goals are written.
|
|
*/
|
|
if (write_state) {
|
|
if (setgoal) {
|
|
if (goal == DST_KEY_STATE_NA) {
|
|
dst_key_unsetstate(key, DST_KEY_GOAL);
|
|
} else {
|
|
dst_key_setstate(key, DST_KEY_GOAL, goal);
|
|
}
|
|
changed = true;
|
|
}
|
|
if (setds) {
|
|
if (ds == DST_KEY_STATE_NA) {
|
|
dst_key_unsetstate(key, DST_KEY_DS);
|
|
dst_key_unsettime(key, DST_TIME_DS);
|
|
} else {
|
|
dst_key_setstate(key, DST_KEY_DS, ds);
|
|
dst_key_settime(key, DST_TIME_DS, dstime);
|
|
}
|
|
changed = true;
|
|
}
|
|
if (setdnskey) {
|
|
if (dnskey == DST_KEY_STATE_NA) {
|
|
dst_key_unsetstate(key, DST_KEY_DNSKEY);
|
|
dst_key_unsettime(key, DST_TIME_DNSKEY);
|
|
} else {
|
|
dst_key_setstate(key, DST_KEY_DNSKEY, dnskey);
|
|
dst_key_settime(key, DST_TIME_DNSKEY,
|
|
dnskeytime);
|
|
}
|
|
changed = true;
|
|
}
|
|
if (setkrrsig) {
|
|
if (krrsig == DST_KEY_STATE_NA) {
|
|
dst_key_unsetstate(key, DST_KEY_KRRSIG);
|
|
dst_key_unsettime(key, DST_TIME_KRRSIG);
|
|
} else {
|
|
dst_key_setstate(key, DST_KEY_KRRSIG, krrsig);
|
|
dst_key_settime(key, DST_TIME_KRRSIG,
|
|
krrsigtime);
|
|
}
|
|
changed = true;
|
|
}
|
|
if (setzrrsig) {
|
|
if (zrrsig == DST_KEY_STATE_NA) {
|
|
dst_key_unsetstate(key, DST_KEY_ZRRSIG);
|
|
dst_key_unsettime(key, DST_TIME_ZRRSIG);
|
|
} else {
|
|
dst_key_setstate(key, DST_KEY_ZRRSIG, zrrsig);
|
|
dst_key_settime(key, DST_TIME_ZRRSIG,
|
|
zrrsigtime);
|
|
}
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
if (!changed && setttl) {
|
|
changed = true;
|
|
}
|
|
|
|
/*
|
|
* Print out time values, if -p was used.
|
|
*/
|
|
if (printcreate) {
|
|
printtime(key, DST_TIME_CREATED, "Created", epoch, stdout);
|
|
}
|
|
|
|
if (printpub) {
|
|
printtime(key, DST_TIME_PUBLISH, "Publish", epoch, stdout);
|
|
}
|
|
|
|
if (printact) {
|
|
printtime(key, DST_TIME_ACTIVATE, "Activate", epoch, stdout);
|
|
}
|
|
|
|
if (printrev) {
|
|
printtime(key, DST_TIME_REVOKE, "Revoke", epoch, stdout);
|
|
}
|
|
|
|
if (printinact) {
|
|
printtime(key, DST_TIME_INACTIVE, "Inactive", epoch, stdout);
|
|
}
|
|
|
|
if (printdel) {
|
|
printtime(key, DST_TIME_DELETE, "Delete", epoch, stdout);
|
|
}
|
|
|
|
if (printsyncadd) {
|
|
printtime(key, DST_TIME_SYNCPUBLISH, "SYNC Publish", epoch,
|
|
stdout);
|
|
}
|
|
|
|
if (printsyncdel) {
|
|
printtime(key, DST_TIME_SYNCDELETE, "SYNC Delete", epoch,
|
|
stdout);
|
|
}
|
|
|
|
if (printdsadd) {
|
|
printtime(key, DST_TIME_DSPUBLISH, "DS Publish", epoch, stdout);
|
|
}
|
|
|
|
if (printdsdel) {
|
|
printtime(key, DST_TIME_DSDELETE, "DS Delete", epoch, stdout);
|
|
}
|
|
|
|
if (changed) {
|
|
writekey(key, directory, write_state);
|
|
if (predecessor != NULL && prevkey != NULL) {
|
|
writekey(prevkey, directory, write_state);
|
|
}
|
|
}
|
|
|
|
if (prevkey != NULL) {
|
|
dst_key_free(&prevkey);
|
|
}
|
|
dst_key_free(&key);
|
|
dst_lib_destroy();
|
|
if (verbose > 10) {
|
|
isc_mem_stats(mctx, stdout);
|
|
}
|
|
cleanup_logging(&log);
|
|
isc_mem_free(mctx, directory);
|
|
isc_mem_destroy(&mctx);
|
|
|
|
return (0);
|
|
}
|