From a60bf97f9f7dcde6f4ca6e8188245fb0866200db Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 27 Feb 2014 16:25:32 -0800 Subject: [PATCH] [master] dnssec-keyfromlabel -S and -i 3764. [bug] The dnssec-keygen/settime -S and -i options (to set up a successor key and set the prepublication interval) were missing from dnssec-keyfromlabel. [RT #35394] --- CHANGES | 5 + bin/dnssec/dnssec-keyfromlabel.c | 259 ++++++++++++++++++------- bin/dnssec/dnssec-keyfromlabel.docbook | 56 +++++- 3 files changed, 245 insertions(+), 75 deletions(-) diff --git a/CHANGES b/CHANGES index 4b1df31c4e..d01988be49 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +3764. [bug] The dnssec-keygen/settime -S and -i options + (to set up a successor key and set the prepublication + interval) were missing from dnssec-keyfromlabel. + [RT #35394] + 3763. [bug] delve: Cache DNSSEC records to avoid the need to re-fetch them when restarting validation. [RT #35476] diff --git a/bin/dnssec/dnssec-keyfromlabel.c b/bin/dnssec/dnssec-keyfromlabel.c index 3609be5a22..8bd2ea3af3 100644 --- a/bin/dnssec/dnssec-keyfromlabel.c +++ b/bin/dnssec/dnssec-keyfromlabel.c @@ -108,6 +108,11 @@ usage(void) { fprintf(stderr, " -G: generate key only; do not set -P or -A\n"); fprintf(stderr, " -C: generate a backward-compatible key, omitting" " all dates\n"); + fprintf(stderr, " -S : generate a successor to an existing " + "key\n"); + fprintf(stderr, " -i : prepublication interval for " + "successor key " + "(default: 30 days)\n"); fprintf(stderr, "Output:\n"); fprintf(stderr, " K++.key, " "K++.private\n"); @@ -120,6 +125,8 @@ main(int argc, char **argv) { char *algname = NULL, *freeit = NULL; char *nametype = NULL, *type = NULL; const char *directory = NULL; + const char *predecessor = NULL; + dst_key_t *prevkey = NULL; #ifdef USE_PKCS11 const char *engine = PKCS11_ENGINE; #else @@ -149,6 +156,7 @@ main(int argc, char **argv) { isc_stdtime_t publish = 0, activate = 0, revoke = 0; isc_stdtime_t inactive = 0, delete = 0; isc_stdtime_t now; + int prepub = -1; isc_boolean_t setpub = ISC_FALSE, setact = ISC_FALSE; isc_boolean_t setrev = ISC_FALSE, setinact = ISC_FALSE; isc_boolean_t setdel = ISC_FALSE, setttl = ISC_FALSE; @@ -172,9 +180,8 @@ main(int argc, char **argv) { isc_stdtime_get(&now); - while ((ch = isc_commandline_parse(argc, argv, - "3a:Cc:E:f:K:kl:L:n:p:t:v:yFhGP:A:R:I:D:")) != -1) - { +#define CMDLINE_FLAGS "3A:a:Cc:D:E:Ff:GhI:i:kK:L:l:n:P:p:R:S:t:v:y" + while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { switch (ch) { case '3': use_nsec3 = ISC_TRUE; @@ -281,6 +288,12 @@ main(int argc, char **argv) { now, now, &setdel); unsetdel = !setdel; break; + case 'S': + predecessor = isc_commandline_argument; + break; + case 'i': + prepub = strtottl(isc_commandline_argument); + break; case 'F': /* Reserved for FIPS mode */ /* FALLTHROUGH */ @@ -309,77 +322,179 @@ main(int argc, char **argv) { setup_logging(verbose, mctx, &log); - if (label == NULL) - fatal("the key label was not specified"); - if (argc < isc_commandline_index + 1) - fatal("the key name was not specified"); - if (argc > isc_commandline_index + 1) - fatal("extraneous arguments"); + if (predecessor == NULL) { + if (label == NULL) + fatal("the key label was not specified"); + if (argc < isc_commandline_index + 1) + fatal("the key name was not specified"); + if (argc > isc_commandline_index + 1) + fatal("extraneous arguments"); - if (strchr(label, ':') == NULL) { - char *l; - int len; + if (strchr(label, ':') == NULL) { + char *l; + int len; - len = strlen(label) + 8; - l = isc_mem_allocate(mctx, len); - if (l == NULL) - fatal("cannot allocate memory"); - snprintf(l, len, "pkcs11:%s", label); - isc_mem_free(mctx, label); - label = l; - } - - if (algname == NULL) { - if (use_nsec3) - algname = strdup(DEFAULT_NSEC3_ALGORITHM); - else - algname = strdup(DEFAULT_ALGORITHM); - if (algname == NULL) - fatal("strdup failed"); - freeit = algname; - if (verbose > 0) - fprintf(stderr, "no algorithm specified; " - "defaulting to %s\n", algname); - } - - if (strcasecmp(algname, "RSA") == 0) { - fprintf(stderr, "The use of RSA (RSAMD5) is not recommended.\n" - "If you still wish to use RSA (RSAMD5) please " - "specify \"-a RSAMD5\"\n"); - if (freeit != NULL) - free(freeit); - return (1); - } else { - r.base = algname; - r.length = strlen(algname); - ret = dns_secalg_fromtext(&alg, &r); - if (ret != ISC_R_SUCCESS) - fatal("unknown algorithm %s", algname); - if (alg == DST_ALG_DH) - options |= DST_TYPE_KEY; - } - - if (use_nsec3 && - alg != DST_ALG_NSEC3DSA && alg != DST_ALG_NSEC3RSASHA1 && - alg != DST_ALG_RSASHA256 && alg != DST_ALG_RSASHA512 && - alg != DST_ALG_ECCGOST && - alg != DST_ALG_ECDSA256 && alg != DST_ALG_ECDSA384) { - fatal("%s is incompatible with NSEC3; " - "do not use the -3 option", algname); - } - - if (type != NULL && (options & DST_TYPE_KEY) != 0) { - if (strcasecmp(type, "NOAUTH") == 0) - flags |= DNS_KEYTYPE_NOAUTH; - else if (strcasecmp(type, "NOCONF") == 0) - flags |= DNS_KEYTYPE_NOCONF; - else if (strcasecmp(type, "NOAUTHCONF") == 0) { - flags |= (DNS_KEYTYPE_NOAUTH | DNS_KEYTYPE_NOCONF); + len = strlen(label) + 8; + l = isc_mem_allocate(mctx, len); + if (l == NULL) + fatal("cannot allocate memory"); + snprintf(l, len, "pkcs11:%s", label); + isc_mem_free(mctx, label); + label = l; } - else if (strcasecmp(type, "AUTHCONF") == 0) - /* nothing */; - else - fatal("invalid type %s", type); + + if (algname == NULL) { + if (use_nsec3) + algname = strdup(DEFAULT_NSEC3_ALGORITHM); + else + algname = strdup(DEFAULT_ALGORITHM); + if (algname == NULL) + fatal("strdup failed"); + freeit = algname; + if (verbose > 0) + fprintf(stderr, "no algorithm specified; " + "defaulting to %s\n", algname); + } + + if (strcasecmp(algname, "RSA") == 0) { + fprintf(stderr, "The use of RSA (RSAMD5) is not " + "recommended.\nIf you still wish to " + "use RSA (RSAMD5) please specify " + "\"-a RSAMD5\"\n"); + if (freeit != NULL) + free(freeit); + return (1); + } else { + r.base = algname; + r.length = strlen(algname); + ret = dns_secalg_fromtext(&alg, &r); + if (ret != ISC_R_SUCCESS) + fatal("unknown algorithm %s", algname); + if (alg == DST_ALG_DH) + options |= DST_TYPE_KEY; + } + + if (use_nsec3 && + alg != DST_ALG_NSEC3DSA && alg != DST_ALG_NSEC3RSASHA1 && + alg != DST_ALG_RSASHA256 && alg != DST_ALG_RSASHA512 && + alg != DST_ALG_ECCGOST && + alg != DST_ALG_ECDSA256 && alg != DST_ALG_ECDSA384) { + fatal("%s is incompatible with NSEC3; " + "do not use the -3 option", algname); + } + + if (type != NULL && (options & DST_TYPE_KEY) != 0) { + if (strcasecmp(type, "NOAUTH") == 0) + flags |= DNS_KEYTYPE_NOAUTH; + else if (strcasecmp(type, "NOCONF") == 0) + flags |= DNS_KEYTYPE_NOCONF; + else if (strcasecmp(type, "NOAUTHCONF") == 0) + flags |= (DNS_KEYTYPE_NOAUTH | + DNS_KEYTYPE_NOCONF); + else if (strcasecmp(type, "AUTHCONF") == 0) + /* nothing */; + else + fatal("invalid type %s", type); + } + + if (!oldstyle && prepub > 0) { + if (setpub && setact && (activate - prepub) < publish) + fatal("Activation and publication dates " + "are closer together than the\n\t" + "prepublication interval."); + + if (!setpub && !setact) { + setpub = setact = ISC_TRUE; + publish = now; + activate = now + prepub; + } else if (setpub && !setact) { + setact = ISC_TRUE; + activate = publish + prepub; + } else if (setact && !setpub) { + setpub = ISC_TRUE; + publish = activate - prepub; + } + + if ((activate - prepub) < now) + fatal("Time until activation is shorter " + "than the\n\tprepublication interval."); + } + } else { + char keystr[DST_KEY_FORMATSIZE]; + isc_stdtime_t when; + int major, minor; + + if (prepub == -1) + prepub = (30 * 86400); + + if (algname != NULL) + fatal("-S and -a cannot be used together"); + if (nametype != NULL) + fatal("-S and -n cannot be used together"); + if (type != NULL) + fatal("-S and -t cannot be used together"); + if (setpub || unsetpub) + fatal("-S and -P cannot be used together"); + if (setact || unsetact) + fatal("-S and -A cannot be used together"); + if (use_nsec3) + fatal("-S and -3 cannot be used together"); + if (oldstyle) + fatal("-S and -C cannot be used together"); + if (genonly) + fatal("-S and -G cannot be used together"); + + ret = dst_key_fromnamedfile(predecessor, directory, + DST_TYPE_PUBLIC | DST_TYPE_PRIVATE, + mctx, &prevkey); + if (ret != ISC_R_SUCCESS) + fatal("Invalid keyfile %s: %s", + predecessor, isc_result_totext(ret)); + if (!dst_key_isprivate(prevkey)) + fatal("%s is not a private key", predecessor); + + name = dst_key_name(prevkey); + alg = dst_key_alg(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("Key %s has incompatible format version %d.%d\n\t" + "It is not possible to generate a successor key.", + keystr, major, minor); + + ret = dst_key_gettime(prevkey, DST_TIME_ACTIVATE, &when); + if (ret != ISC_R_SUCCESS) + fatal("Key %s has no activation date.\n\t" + "You must use dnssec-settime -A to set one " + "before generating a successor.", keystr); + + ret = dst_key_gettime(prevkey, DST_TIME_INACTIVE, &activate); + if (ret != ISC_R_SUCCESS) + fatal("Key %s has no inactivation date.\n\t" + "You must use dnssec-settime -I to set one " + "before generating a successor.", keystr); + + publish = activate - prepub; + if (publish < now) + fatal("Key %s becomes inactive\n\t" + "sooner than the prepublication period " + "for the new key ends.\n\t" + "Either change the inactivation date with " + "dnssec-settime -I,\n\t" + "or use the -i option to set a shorter " + "prepublication interval.", keystr); + + ret = dst_key_gettime(prevkey, DST_TIME_DELETE, &when); + if (ret != ISC_R_SUCCESS) + fprintf(stderr, "%s: WARNING: Key %s has no removal " + "date;\n\t it will remain in the zone " + "indefinitely after rollover.\n\t " + "You can use dnssec-settime -D to " + "change this.\n", program, keystr); + + setpub = setact = ISC_TRUE; } if (nametype == NULL) { @@ -551,6 +666,8 @@ main(int argc, char **argv) { isc_result_totext(ret)); printf("%s\n", filename); dst_key_free(&key); + if (prevkey != NULL) + dst_key_free(&prevkey); cleanup_logging(&log); cleanup_entropy(&ectx); diff --git a/bin/dnssec/dnssec-keyfromlabel.docbook b/bin/dnssec/dnssec-keyfromlabel.docbook index 5353f2d8a6..b75737f037 100644 --- a/bin/dnssec/dnssec-keyfromlabel.docbook +++ b/bin/dnssec/dnssec-keyfromlabel.docbook @@ -19,7 +19,7 @@ - February 06, 2014 + February 27, 2014 @@ -58,6 +58,7 @@ + @@ -65,6 +66,7 @@ + @@ -75,9 +77,12 @@ DESCRIPTION dnssec-keyfromlabel - gets keys with the given label from a crypto hardware and builds - key files for DNSSEC (Secure DNS), as defined in RFC 2535 - and RFC 4034. + generates a key pair of files that referencing a key object stored + in a cryptographic hardware service module (HSM). The private key + file can be used for DNSSEC signing of zone data as if it were a + conventional signing key created by dnssec-keygen, + but the key material is stored within the HSM, and the actual signing + takes place there. The of the key is specified on the command @@ -293,6 +298,21 @@ + + -S key + + + Generate a key as an explicit successor to an existing key. + The name, algorithm, size, and type of the key will be set + to match the predecessor. The activation date of the new + key will be set to the inactivation date of the existing + one. The publication date will be set to the activation + date minus the prepublication interval, which defaults to + 30 days. + + + + -t type @@ -402,6 +422,34 @@ + + + -i interval + + + Sets the prepublication interval for a key. If set, then + the publication and activation dates must be separated by at least + this much time. If the activation date is specified but the + publication date isn't, then the publication date will default + to this much time before the activation date; conversely, if + the publication date is specified but activation date isn't, + then activation will be set to this much time after publication. + + + If the key is being created as an explicit successor to another + key, then the default prepublication interval is 30 days; + otherwise it is zero. + + + As with date offsets, if the argument is followed by one of + the suffixes 'y', 'mo', 'w', 'd', 'h', or 'mi', then the + interval is measured in years, months, weeks, days, hours, + or minutes, respectively. Without a suffix, the interval is + measured in seconds. + + + +