From c02149960459e4406d9e50fb1867433e7f0e8f0d Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 26 Oct 2009 21:18:24 +0000 Subject: [PATCH] 2731. [func] Additional work on change 2709. The key parser will now ignore unrecognized fields when the minor version number of the private key format has been increased. It will reject any key with the major version number increased. [RT #20310] --- CHANGES | 6 ++++++ bin/dnssec/dnssec-revoke.c | 15 +++++++------ bin/dnssec/dnssec-settime.c | 25 +++++++--------------- bin/dnssec/dnssectool.c | 42 ++++++++++++++++++++++++++++++++++++- bin/dnssec/dnssectool.h | 8 ++++++- lib/dns/dnssec.c | 4 +++- lib/dns/dst_parse.c | 16 +++++++------- lib/dns/dst_parse.h | 5 +---- lib/dns/include/dst/dst.h | 24 ++++++++++++++++++++- 9 files changed, 106 insertions(+), 39 deletions(-) diff --git a/CHANGES b/CHANGES index 159108b04d..2b9eb3e9fc 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,9 @@ +2731. [func] Additional work on change 2709. The key parser + will now ignore unrecognized fields when the + minor version number of the private key format + has been increased. It will reject any key with + the major version number increased. [RT #20310] + 2730. [func] Have dnssec-keygen display a progress indication a la 'openssl genrsa' on standard error. Note when the first '.' is followed by a long stop diff --git a/bin/dnssec/dnssec-revoke.c b/bin/dnssec/dnssec-revoke.c index 34798f8b98..a04cabeecb 100644 --- a/bin/dnssec/dnssec-revoke.c +++ b/bin/dnssec/dnssec-revoke.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-revoke.c,v 1.16 2009/10/12 20:48:10 each Exp $ */ +/* $Id: dnssec-revoke.c,v 1.17 2009/10/26 21:18:24 each Exp $ */ /*! \file */ @@ -179,18 +179,21 @@ main(int argc, char **argv) { fatal("Invalid keyfile name %s: %s", filename, isc_result_totext(result)); - if (verbose > 2) { - char keystr[DST_KEY_FORMATSIZE]; + dst_key_format(key, keystr, sizeof(keystr)); - dst_key_format(key, keystr, sizeof(keystr)); + if (verbose > 2) fprintf(stderr, "%s: %s\n", program, keystr); - } + + if (force) + set_keyversion(key); + else + check_keyversion(key, keystr); + flags = dst_key_flags(key); if ((flags & DNS_KEYFLAG_REVOKE) == 0) { isc_stdtime_t now; - if ((flags & DNS_KEYFLAG_KSK) == 0) fprintf(stderr, "%s: warning: Key is not flagged " "as a KSK. Revoking a ZSK is " diff --git a/bin/dnssec/dnssec-settime.c b/bin/dnssec/dnssec-settime.c index 7371955a25..4a7f04811c 100644 --- a/bin/dnssec/dnssec-settime.c +++ b/bin/dnssec/dnssec-settime.c @@ -14,7 +14,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssec-settime.c,v 1.17 2009/10/12 20:48:10 each Exp $ */ +/* $Id: dnssec-settime.c,v 1.18 2009/10/26 21:18:24 each Exp $ */ /*! \file */ @@ -131,7 +131,6 @@ main(int argc, char **argv) { isc_entropy_t *ectx = NULL; dst_key_t *key = NULL; isc_buffer_t buf; - int major, minor; isc_stdtime_t now; isc_stdtime_t pub = 0, act = 0, rev = 0, inact = 0, del = 0; isc_boolean_t setpub = ISC_FALSE, setact = ISC_FALSE; @@ -143,7 +142,7 @@ main(int argc, char **argv) { isc_boolean_t printcreate = ISC_FALSE, printpub = ISC_FALSE; isc_boolean_t printact = ISC_FALSE, printrev = ISC_FALSE; isc_boolean_t printinact = ISC_FALSE, printdel = ISC_FALSE; - isc_boolean_t forceupdate = ISC_FALSE; + isc_boolean_t force = ISC_FALSE; isc_boolean_t epoch = ISC_FALSE; isc_boolean_t changed = ISC_FALSE; @@ -167,7 +166,7 @@ main(int argc, char **argv) { engine = isc_commandline_argument; break; case 'f': - forceupdate = ISC_TRUE; + force = ISC_TRUE; break; case 'p': p = isc_commandline_argument; @@ -346,20 +345,10 @@ main(int argc, char **argv) { dst_key_format(key, keystr, sizeof(keystr)); - /* Is this an old-style key? */ - dst_key_getprivateformat(key, &major, &minor); - if (major <= 1 && minor <= 2) { - if (forceupdate) { - /* - * Updating to new-style key: set - * Private-key-format to 1.3 - */ - dst_key_setprivateformat(key, 1, 3); - dst_key_settime(key, DST_TIME_CREATED, now); - } else - fatal("Incompatible key %s, " - "use -f to force update.", keystr); - } + if (force) + set_keyversion(key); + else + check_keyversion(key, keystr); if (verbose > 2) fprintf(stderr, "%s: %s\n", program, keystr); diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c index 541dda0b12..d8c4ea4865 100644 --- a/bin/dnssec/dnssectool.c +++ b/bin/dnssec/dnssectool.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssectool.c,v 1.56 2009/10/24 00:00:06 each Exp $ */ +/* $Id: dnssectool.c,v 1.57 2009/10/26 21:18:24 each Exp $ */ /*! \file */ @@ -362,3 +362,43 @@ try_dir(const char *dirname) { } return (result); } + +/* + * Check private key version compatibility. + */ +void +check_keyversion(dst_key_t *key, char *keystr) { + int major, minor; + dst_key_getprivateformat(key, &major, &minor); + INSIST(major <= DST_MAJOR_VERSION); /* invalid private key */ + + if (major < DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) + fatal("Key %s has incompatible format version %d.%d, " + "use -f to force upgrade to new version.", + keystr, major, minor); + if (minor > DST_MINOR_VERSION) + fatal("Key %s has incompatible format version %d.%d, " + "use -f to force downgrade to current version.", + keystr, major, minor); +} + +void +set_keyversion(dst_key_t *key) { + int major, minor; + dst_key_getprivateformat(key, &major, &minor); + INSIST(major <= DST_MAJOR_VERSION); + + if (major != DST_MAJOR_VERSION || minor != DST_MINOR_VERSION) + dst_key_setprivateformat(key, DST_MAJOR_VERSION, + DST_MINOR_VERSION); + + /* + * If the key is from a version older than 1.3, set + * set the creation date + */ + if (major < 1 || (major == 1 && minor <= 2)) { + isc_stdtime_t now; + isc_stdtime_get(&now); + dst_key_settime(key, DST_TIME_CREATED, now); + } +} diff --git a/bin/dnssec/dnssectool.h b/bin/dnssec/dnssectool.h index c1a0ee1767..249d7054e6 100644 --- a/bin/dnssec/dnssectool.h +++ b/bin/dnssec/dnssectool.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dnssectool.h,v 1.28 2009/10/24 00:00:06 each Exp $ */ +/* $Id: dnssectool.h,v 1.29 2009/10/26 21:18:24 each Exp $ */ #ifndef DNSSECTOOL_H #define DNSSECTOOL_H 1 @@ -70,4 +70,10 @@ strtoclass(const char *str); isc_result_t try_dir(const char *dirname); + +void +check_keyversion(dst_key_t *key, char *keystr); + +void +set_keyversion(dst_key_t *key); #endif /* DNSSEC_DNSSECTOOL_H */ diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index 9c90215bed..5a40d2e80a 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -16,7 +16,7 @@ */ /* - * $Id: dnssec.c,v 1.106 2009/10/16 23:47:54 tbox Exp $ + * $Id: dnssec.c,v 1.107 2009/10/26 21:18:24 each Exp $ */ /*! \file */ @@ -985,6 +985,8 @@ dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey, /* Is this an old-style key? */ result = dst_key_getprivateformat(dk->key, &major, &minor); + + /* Smart signing started with key format 1.3 */ dk->legacy = ISC_TF(major == 1 && minor <= 2); ISC_LINK_INIT(dk, link); diff --git a/lib/dns/dst_parse.c b/lib/dns/dst_parse.c index c5dc612f41..5fc5638193 100644 --- a/lib/dns/dst_parse.c +++ b/lib/dns/dst_parse.c @@ -31,7 +31,7 @@ /*% * Principal Author: Brian Wellington - * $Id: dst_parse.c,v 1.22 2009/10/22 02:21:30 each Exp $ + * $Id: dst_parse.c,v 1.23 2009/10/26 21:18:24 each Exp $ */ #include @@ -385,9 +385,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, goto fail; } - if (major > MAJOR_VERSION || - (major == MAJOR_VERSION && minor > MINOR_VERSION)) - { + if (major > DST_MAJOR_VERSION) { ret = DST_R_INVALIDPRIVATEKEY; goto fail; } @@ -476,10 +474,13 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, /* Key data */ tag = find_value(DST_AS_STR(token), alg); - if (tag < 0) { + if (tag < 0 && minor > DST_MINOR_VERSION) + goto next; + else if (tag < 0) { ret = DST_R_INVALIDPRIVATEKEY; goto fail; } + priv->elements[n].tag = tag; data = (unsigned char *) isc_mem_get(mctx, MAXFIELDSIZE); @@ -490,6 +491,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex, ret = isc_base64_tobuffer(lex, &b, -1); if (ret != ISC_R_SUCCESS) goto fail; + isc_buffer_usedregion(&b, &r); priv->elements[n].length = r.length; priv->elements[n].data = r.base; @@ -550,8 +552,8 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv, dst_key_getprivateformat(key, &major, &minor); if (major == 0 && minor == 0) { - major = MAJOR_VERSION; - minor = MINOR_VERSION; + major = DST_MAJOR_VERSION; + minor = DST_MINOR_VERSION; } /* XXXDCL return value should be checked for full filesystem */ diff --git a/lib/dns/dst_parse.h b/lib/dns/dst_parse.h index d893c2dc2a..ceb8b188bd 100644 --- a/lib/dns/dst_parse.h +++ b/lib/dns/dst_parse.h @@ -29,7 +29,7 @@ * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst_parse.h,v 1.14 2009/09/02 06:29:01 each Exp $ */ +/* $Id: dst_parse.h,v 1.15 2009/10/26 21:18:24 each Exp $ */ /*! \file */ #ifndef DST_DST_PARSE_H @@ -39,9 +39,6 @@ #include -#define MAJOR_VERSION 1 -#define MINOR_VERSION 3 - #define MAXFIELDSIZE 512 /* diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 2217139e3d..1f6020a3bf 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: dst.h,v 1.24 2009/10/24 09:46:19 fdupont Exp $ */ +/* $Id: dst.h,v 1.25 2009/10/26 21:18:24 each Exp $ */ #ifndef DST_DST_H #define DST_DST_H 1 @@ -100,6 +100,28 @@ typedef struct dst_context dst_context_t; #define DST_NUM_ROLLPERIOD 3 #define DST_MAX_NUMERIC 3 +/* + * Current format version number of the private key parser. + * + * When parsing a key file with the same major number but a higher minor + * number, the key parser will ignore any fields it does not recognize. + * Thus, DST_MINOR_VERSION should be incremented whenever new + * fields are added to the private key file (such as new metadata). + * + * When rewriting these keys, those fields will be dropped, and the + * format version set back to the current one.. + * + * When a key is seen with a higher major number, the key parser will + * reject it as invalid. Thus, DST_MAJOR_VERSION should be incremented + * and DST_MINOR_VERSION set to zero whenever there is a format change + * which is not backward compatible to previous versions of the dst_key + * parser, such as change in the syntax of an existing field, the removal + * of a currently mandatory field, or a new field added which would + * alter the functioning of the key if it were absent. + */ +#define DST_MAJOR_VERSION 1 +#define DST_MINOR_VERSION 3 + /*** *** Functions ***/ -- GitLab