]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Update dst key code to maintain key state
authorMatthijs Mekking <matthijs@isc.org>
Wed, 11 Sep 2019 14:29:33 +0000 (16:29 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Wed, 6 Nov 2019 21:31:45 +0000 (22:31 +0100)
Add a number of metadata variables (lifetime, ksk and zsk role).

For the roles we add a new type of metadata (booleans).

Add a function to write the state of the key to a separate file.

Only write out known metadata to private file.  With the
introduction of the numeric metadata "Lifetime", adjust the write
private key file functionality to only write out metadata it knows
about.

lib/dns/dst_api.c
lib/dns/dst_internal.h
lib/dns/dst_parse.c
lib/dns/include/dst/dst.h
lib/dns/win32/libdns.def.in

index e874639f8d087acfff68ddaadb6fe0470331d916..97cc044da0eb852a63c8aadd434c99069dba2028 100644 (file)
@@ -83,6 +83,8 @@ static dst_key_t *    get_key_struct(const dns_name_t *name,
                                       isc_mem_t *mctx);
 static isc_result_t    write_public_key(const dst_key_t *key, int type,
                                         const char *directory);
+static isc_result_t    write_key_state(const dst_key_t *key, int type,
+                                        const char *directory);
 static isc_result_t    buildfilename(dns_name_t *name,
                                      dns_keytag_t id,
                                      unsigned int alg,
@@ -372,24 +374,35 @@ dst_key_tofile(const dst_key_t *key, int type, const char *directory) {
 
        REQUIRE(dst_initialized == true);
        REQUIRE(VALID_KEY(key));
-       REQUIRE((type & (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC)) != 0);
+       REQUIRE((type &
+               (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE)) != 0);
 
        CHECKALG(key->key_alg);
 
-       if (key->func->tofile == NULL)
+       if (key->func->tofile == NULL) {
                return (DST_R_UNSUPPORTEDALG);
+       }
 
        if ((type & DST_TYPE_PUBLIC) != 0) {
                ret = write_public_key(key, type, directory);
-               if (ret != ISC_R_SUCCESS)
+               if (ret != ISC_R_SUCCESS) {
+                       return (ret);
+               }
+       }
+
+       if ((type & DST_TYPE_STATE) != 0) {
+               ret = write_key_state(key, type, directory);
+               if (ret != ISC_R_SUCCESS) {
                        return (ret);
+               }
        }
 
        if (((type & DST_TYPE_PRIVATE) != 0) &&
            (key->key_flags & DNS_KEYFLAG_TYPEMASK) != DNS_KEYTYPE_NOKEY)
+       {
                return (key->func->tofile(key, directory));
-       else
-               return (ret);
+       }
+       return (ISC_R_SUCCESS);
 }
 
 void
@@ -884,14 +897,45 @@ dst_key_generate(const dns_name_t *name, unsigned int alg,
        return (ISC_R_SUCCESS);
 }
 
+isc_result_t
+dst_key_getbool(const dst_key_t *key, int type, bool *valuep)
+{
+       REQUIRE(VALID_KEY(key));
+       REQUIRE(valuep != NULL);
+       REQUIRE(type <= DST_MAX_BOOLEAN);
+       if (!key->boolset[type]) {
+               return (ISC_R_NOTFOUND);
+       }
+       *valuep = key->bools[type];
+       return (ISC_R_SUCCESS);
+}
+
+void
+dst_key_setbool(dst_key_t *key, int type, bool value)
+{
+       REQUIRE(VALID_KEY(key));
+       REQUIRE(type <= DST_MAX_BOOLEAN);
+       key->bools[type] = value;
+       key->boolset[type] = true;
+}
+
+void
+dst_key_unsetbool(dst_key_t *key, int type)
+{
+       REQUIRE(VALID_KEY(key));
+       REQUIRE(type <= DST_MAX_BOOLEAN);
+       key->boolset[type] = false;
+}
+
 isc_result_t
 dst_key_getnum(const dst_key_t *key, int type, uint32_t *valuep)
 {
        REQUIRE(VALID_KEY(key));
        REQUIRE(valuep != NULL);
        REQUIRE(type <= DST_MAX_NUMERIC);
-       if (!key->numset[type])
+       if (!key->numset[type]) {
                return (ISC_R_NOTFOUND);
+       }
        *valuep = key->nums[type];
        return (ISC_R_SUCCESS);
 }
@@ -918,8 +962,9 @@ dst_key_gettime(const dst_key_t *key, int type, isc_stdtime_t *timep) {
        REQUIRE(VALID_KEY(key));
        REQUIRE(timep != NULL);
        REQUIRE(type <= DST_MAX_TIMES);
-       if (!key->timeset[type])
+       if (!key->timeset[type]) {
                return (ISC_R_NOTFOUND);
+       }
        *timep = key->times[type];
        return (ISC_R_SUCCESS);
 }
@@ -939,6 +984,36 @@ dst_key_unsettime(dst_key_t *key, int type) {
        key->timeset[type] = false;
 }
 
+isc_result_t
+dst_key_getstate(const dst_key_t *key, int type, dst_key_state_t *statep)
+{
+       REQUIRE(VALID_KEY(key));
+       REQUIRE(statep != NULL);
+       REQUIRE(type <= DST_MAX_KEYSTATES);
+       if (!key->keystateset[type]) {
+               return (ISC_R_NOTFOUND);
+       }
+       *statep = key->keystates[type];
+       return (ISC_R_SUCCESS);
+}
+
+void
+dst_key_setstate(dst_key_t *key, int type, dst_key_state_t state)
+{
+       REQUIRE(VALID_KEY(key));
+       REQUIRE(type <= DST_MAX_KEYSTATES);
+       key->keystates[type] = state;
+       key->keystateset[type] = true;
+}
+
+void
+dst_key_unsetstate(dst_key_t *key, int type)
+{
+       REQUIRE(VALID_KEY(key));
+       REQUIRE(type <= DST_MAX_KEYSTATES);
+       key->keystateset[type] = false;
+}
+
 isc_result_t
 dst_key_getprivateformat(const dst_key_t *key, int *majorp, int *minorp) {
        REQUIRE(VALID_KEY(key));
@@ -1116,7 +1191,7 @@ dst_key_buildfilename(const dst_key_t *key, int type,
 
        REQUIRE(VALID_KEY(key));
        REQUIRE(type == DST_TYPE_PRIVATE || type == DST_TYPE_PUBLIC ||
-               type == 0);
+               type == DST_TYPE_STATE || type == 0);
 
        return (buildfilename(key->key_name, key->key_id, key->key_alg,
                              type, directory, out));
@@ -1476,6 +1551,36 @@ issymmetric(const dst_key_t *key) {
        }
 }
 
+/*%
+ * Write key boolean metadata to a file pointer, preceded by 'tag'
+ */
+static void
+printbool(const dst_key_t *key, int type, const char *tag, FILE *stream) {
+       isc_result_t result;
+       bool value = 0;
+
+       result = dst_key_getbool(key, type, &value);
+       if (result != ISC_R_SUCCESS) {
+               return;
+       }
+       fprintf(stream, "%s: %s\n", tag, value ? "yes" : "no");
+}
+
+/*%
+ * Write key numeric metadata to a file pointer, preceded by 'tag'
+ */
+static void
+printnum(const dst_key_t *key, int type, const char *tag, FILE *stream) {
+       isc_result_t result;
+       uint32_t value = 0;
+
+       result = dst_key_getnum(key, type, &value);
+       if (result != ISC_R_SUCCESS) {
+               return;
+       }
+       fprintf(stream, "%s: %u\n", tag, value);
+}
+
 /*%
  * Write key timing metadata to a file pointer, preceded by 'tag'
  */
@@ -1517,6 +1622,77 @@ printtime(const dst_key_t *key, int type, const char *tag, FILE *stream) {
        fprintf(stream, "%s: (set, unable to display)\n", tag);
 }
 
+/*%
+ * Writes a key state to disk.
+ */
+static isc_result_t
+write_key_state(const dst_key_t *key, int type, const char *directory) {
+       FILE *fp;
+       isc_buffer_t fileb;
+       char filename[NAME_MAX];
+       isc_result_t ret;
+       isc_fsaccess_t access;
+
+       REQUIRE(VALID_KEY(key));
+
+       /*
+        * Make the filename.
+        */
+       isc_buffer_init(&fileb, filename, sizeof(filename));
+       ret = dst_key_buildfilename(key, DST_TYPE_STATE, directory, &fileb);
+       if (ret != ISC_R_SUCCESS) {
+               return (ret);
+       }
+
+       /*
+        * Create public key file.
+        */
+       if ((fp = fopen(filename, "w")) == NULL) {
+               return (DST_R_WRITEERROR);
+       }
+
+       if (issymmetric(key)) {
+               access = 0;
+               isc_fsaccess_add(ISC_FSACCESS_OWNER,
+                                ISC_FSACCESS_READ | ISC_FSACCESS_WRITE,
+                                &access);
+               (void)isc_fsaccess_set(filename, access);
+       }
+
+       /* Write key state */
+       if ((type & DST_TYPE_KEY) == 0) {
+               fprintf(fp, "; This is the state of key %d, for ",
+                       key->key_id);
+               ret = dns_name_print(key->key_name, fp);
+               if (ret != ISC_R_SUCCESS) {
+                       fclose(fp);
+                       return (ret);
+               }
+               fputc('\n', fp);
+
+               printtime(key, DST_TIME_CREATED, "Generated", fp);
+               printtime(key, DST_TIME_PUBLISH, "Published", fp);
+               printtime(key, DST_TIME_ACTIVATE, "Active", fp);
+               printtime(key, DST_TIME_INACTIVE, "Retired", fp);
+               printtime(key, DST_TIME_REVOKE, "Revoked", fp);
+               printtime(key, DST_TIME_DELETE, "Removed", fp);
+
+               printnum(key, DST_NUM_LIFETIME, "Lifetime", fp);
+               fprintf(fp, "Algorithm: %u\n", key->key_alg);
+               fprintf(fp, "Length: %u\n", key->key_size);
+
+               printbool(key, DST_BOOL_KSK, "KSK", fp);
+               printbool(key, DST_BOOL_ZSK, "ZSK", fp);
+       }
+
+       fflush(fp);
+       if (ferror(fp))
+               ret = DST_R_WRITEERROR;
+       fclose(fp);
+
+       return (ret);
+}
+
 /*%
  * Writes a public key to disk in DNS format.
  */
@@ -1540,33 +1716,38 @@ write_public_key(const dst_key_t *key, int type, const char *directory) {
        isc_buffer_init(&classb, class_array, sizeof(class_array));
 
        ret = dst_key_todns(key, &keyb);
-       if (ret != ISC_R_SUCCESS)
+       if (ret != ISC_R_SUCCESS) {
                return (ret);
+       }
 
        isc_buffer_usedregion(&keyb, &r);
        dns_rdata_fromregion(&rdata, key->key_class, dns_rdatatype_dnskey, &r);
 
        ret = dns_rdata_totext(&rdata, (dns_name_t *) NULL, &textb);
-       if (ret != ISC_R_SUCCESS)
+       if (ret != ISC_R_SUCCESS) {
                return (DST_R_INVALIDPUBLICKEY);
+       }
 
        ret = dns_rdataclass_totext(key->key_class, &classb);
-       if (ret != ISC_R_SUCCESS)
+       if (ret != ISC_R_SUCCESS) {
                return (DST_R_INVALIDPUBLICKEY);
+       }
 
        /*
         * Make the filename.
         */
        isc_buffer_init(&fileb, filename, sizeof(filename));
        ret = dst_key_buildfilename(key, DST_TYPE_PUBLIC, directory, &fileb);
-       if (ret != ISC_R_SUCCESS)
+       if (ret != ISC_R_SUCCESS) {
                return (ret);
+       }
 
        /*
         * Create public key file.
         */
-       if ((fp = fopen(filename, "w")) == NULL)
+       if ((fp = fopen(filename, "w")) == NULL) {
                return (DST_R_WRITEERROR);
+       }
 
        if (issymmetric(key)) {
                access = 0;
@@ -1641,10 +1822,14 @@ buildfilename(dns_name_t *name, dns_keytag_t id,
        isc_result_t result;
 
        REQUIRE(out != NULL);
-       if ((type & DST_TYPE_PRIVATE) != 0)
+       if ((type & DST_TYPE_PRIVATE) != 0) {
                suffix = ".private";
-       else if (type == DST_TYPE_PUBLIC)
+       } else if ((type & DST_TYPE_PUBLIC) != 0) {
                suffix = ".key";
+       } else if ((type & DST_TYPE_STATE) != 0) {
+               suffix = ".state";
+       }
+
        if (directory != NULL) {
                if (isc_buffer_availablelength(out) < strlen(directory))
                        return (ISC_R_NOSPACE);
index 86709135ac4454cc36d6a56c06df3ae15d6ba935..463954fa53ab9de369ae243bd6f6476f03abdfba 100644 (file)
@@ -107,11 +107,13 @@ struct dst_key {
        } keydata;                      /*%< pointer to key in crypto pkg fmt */
 
        isc_stdtime_t   times[DST_MAX_TIMES + 1];    /*%< timing metadata */
-       bool    timeset[DST_MAX_TIMES + 1];  /*%< data set? */
+       bool            timeset[DST_MAX_TIMES + 1];  /*%< data set? */
        uint32_t        nums[DST_MAX_NUMERIC + 1];   /*%< numeric metadata */
-       bool    numset[DST_MAX_NUMERIC + 1]; /*%< data set? */
-       bool    inactive;      /*%< private key not present as it is
-                                           inactive */
+       bool            numset[DST_MAX_NUMERIC + 1]; /*%< data set? */
+       bool            bools[DST_MAX_BOOLEAN + 1];   /*%< boolean metadata */
+       bool            boolset[DST_MAX_BOOLEAN + 1]; /*%< data set? */
+
+       bool    inactive;      /*%< private key not present as it is inactive */
        bool    external;      /*%< external key */
 
        int             fmt_major;     /*%< private key format, major version */
index 4b83617a2126f23406ba546b2955800c64e0937a..7130c29501f3e2c665a7a72f0eef6cd9f6ae5582 100644 (file)
@@ -734,7 +734,9 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
                        result = dst_key_getnum(key, i, &value);
                        if (result != ISC_R_SUCCESS)
                                continue;
-                       fprintf(fp, "%s %u\n", numerictags[i], value);
+                       if (numerictags[i] != NULL) {
+                               fprintf(fp, "%s %u\n", numerictags[i], value);
+                       }
                }
                for (i = 0; i < TIMING_NTAGS; i++) {
                        result = dst_key_gettime(key, i, &when);
@@ -750,8 +752,10 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
 
                        isc_buffer_usedregion(&b, &r);
 
-                       fprintf(fp, "%s %.*s\n", timetags[i], (int)r.length,
-                               r.base);
+                       if (timetags[i] != NULL) {
+                               fprintf(fp, "%s %.*s\n", timetags[i],
+                                       (int)r.length, r.base);
+                       }
                }
        }
 
index 52d4d3319e494acf9052d62d827f2bf1f5526bab..f747619a40ef9d0362a0aaefe4592da894a5f6aa 100644 (file)
@@ -85,6 +85,7 @@ typedef struct dst_context    dst_context_t;
 #define DST_TYPE_KEY           0x1000000       /* KEY key */
 #define DST_TYPE_PRIVATE       0x2000000
 #define DST_TYPE_PUBLIC                0x4000000
+#define DST_TYPE_STATE         0x8000000
 
 /* Key timing metadata definitions */
 #define DST_TIME_CREATED       0
@@ -103,7 +104,13 @@ typedef struct dst_context         dst_context_t;
 #define DST_NUM_SUCCESSOR      1
 #define DST_NUM_MAXTTL         2
 #define DST_NUM_ROLLPERIOD     3
-#define DST_MAX_NUMERIC                3
+#define DST_NUM_LIFETIME       4
+#define DST_MAX_NUMERIC                4
+
+/* Boolean metadata definitions */
+#define DST_BOOL_KSK           0
+#define DST_BOOL_ZSK           1
+#define DST_MAX_BOOLEAN                1
 
 /*
  * Current format version number of the private key parser.
@@ -811,6 +818,37 @@ dst_key_setflags(dst_key_t *key, uint32_t flags);
  *     "key" is a valid key.
  */
 
+isc_result_t
+dst_key_getbool(const dst_key_t *key, int type, bool *valuep);
+/*%<
+ * Get a member of the boolean metadata array and place it in '*valuep'.
+ *
+ * Requires:
+ *     "key" is a valid key.
+ *     "type" is no larger than DST_MAX_BOOLEAN
+ *     "valuep" is not null.
+ */
+
+void
+dst_key_setbool(dst_key_t *key, int type, bool value);
+/*%<
+ * Set a member of the boolean metadata array.
+ *
+ * Requires:
+ *     "key" is a valid key.
+ *     "type" is no larger than DST_MAX_BOOLEAN
+ */
+
+void
+dst_key_unsetbool(dst_key_t *key, int type);
+/*%<
+ * Flag a member of the boolean metadata array as "not set".
+ *
+ * Requires:
+ *     "key" is a valid key.
+ *     "type" is no larger than DST_MAX_BOOLEAN
+ */
+
 isc_result_t
 dst_key_getnum(const dst_key_t *key, int type, uint32_t *valuep);
 /*%<
index ce6e55b00c16f6178edb595587c835542b72401c..2016d204ae33fa9e11ca5846c3b7fa2f47757b2e 100644 (file)
@@ -1400,6 +1400,7 @@ dst_key_fromlabel
 dst_key_fromnamedfile
 dst_key_generate
 dst_key_getbits
+dst_key_getbool
 dst_key_getfilename
 dst_key_getgssctx
 dst_key_getnum
@@ -1422,6 +1423,7 @@ dst_key_restore
 dst_key_rid
 dst_key_secretsize
 dst_key_setbits
+dst_key_setbool
 dst_key_setexternal
 dst_key_setflags
 dst_key_setinactive
@@ -1435,6 +1437,7 @@ dst_key_tkeytoken
 dst_key_tobuffer
 dst_key_todns
 dst_key_tofile
+dst_key_unsetbool
 dst_key_unsetnum
 dst_key_unsettime
 dst_lib_destroy