update to 9.7.1-P2
[tridge/bind9.git] / lib / dns / dst_parse.c
index 2da72ae6415a19becc3fe4d46b0d692f26890a2d..0a78b5ba953eb45fbcca9e2f9dd6db718ecf2b75 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Portions Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2004-2010  Internet Systems Consortium, Inc. ("ISC")
  * Portions Copyright (C) 1999-2002  Internet Software Consortium.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -31,7 +31,7 @@
 
 /*%
  * Principal Author: Brian Wellington
- * $Id: dst_parse.c,v 1.14.120.2 2009/03/02 23:47:11 tbox Exp $
+ * $Id: dst_parse.c,v 1.23.36.3 2010/01/13 19:31:52 each Exp $
  */
 
 #include <config.h>
 #include <isc/fsaccess.h>
 #include <isc/lex.h>
 #include <isc/mem.h>
+#include <isc/stdtime.h>
 #include <isc/string.h>
 #include <isc/util.h>
 
+#include <dns/time.h>
+
 #include "dst_internal.h"
 #include "dst_parse.h"
 #include "dst/result.h"
 #define PRIVATE_KEY_STR "Private-key-format:"
 #define ALGORITHM_STR "Algorithm:"
 
+#define TIMING_NTAGS (DST_MAX_TIMES + 1)
+static const char *timetags[TIMING_NTAGS] = {
+       "Created:",
+       "Publish:",
+       "Activate:",
+       "Revoke:",
+       "Inactive:",
+       "Delete:",
+       "DSPublish:"
+};
+
+#define NUMERIC_NTAGS (DST_MAX_NUMERIC + 1)
+static const char *numerictags[NUMERIC_NTAGS] = {
+       "Predecessor:",
+       "Successor:",
+       "MaxTTL:",
+       "RollPeriod:"
+};
+
 struct parse_map {
        const int value;
        const char *tag;
@@ -107,13 +129,12 @@ static int
 find_value(const char *s, const unsigned int alg) {
        int i;
 
-       for (i = 0; ; i++) {
-               if (map[i].tag == NULL)
-                       return (-1);
-               else if (strcasecmp(s, map[i].tag) == 0 &&
-                        TAG_ALG(map[i].value) == alg)
+       for (i = 0; map[i].tag != NULL; i++) {
+               if (strcasecmp(s, map[i].tag) == 0 &&
+                   (TAG_ALG(map[i].value) == alg))
                        return (map[i].value);
        }
+       return (-1);
 }
 
 static const char *
@@ -128,6 +149,28 @@ find_tag(const int value) {
        }
 }
 
+static int
+find_metadata(const char *s, const char *tags[], int ntags) {
+       int i;
+
+       for (i = 0; i < ntags; i++) {
+               if (strcasecmp(s, tags[i]) == 0)
+                       return (i);
+       }
+
+       return (-1);
+}
+
+static int
+find_timedata(const char *s) {
+       return (find_metadata(s, timetags, TIMING_NTAGS));
+}
+
+static int
+find_numericdata(const char *s) {
+       return (find_metadata(s, numerictags, NUMERIC_NTAGS));
+}
+
 static int
 check_rsa(const dst_private_t *priv) {
        int i, j;
@@ -285,7 +328,7 @@ dst__privstruct_free(dst_private_t *priv, isc_mem_t *mctx) {
        priv->nelements = 0;
 }
 
-int
+isc_result_t
 dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
                      isc_mem_t *mctx, dst_private_t *priv)
 {
@@ -294,6 +337,7 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
        isc_token_t token;
        unsigned char *data = NULL;
        unsigned int opt = ISC_LEXOPT_EOL;
+       isc_stdtime_t when;
        isc_result_t ret;
 
        REQUIRE(priv != NULL);
@@ -341,13 +385,16 @@ 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;
        }
 
+       /*
+        * Store the private key format version number
+        */
+       dst_key_setprivateformat(key, major, minor);
+
        READLINE(lex, opt, &token);
 
        /*
@@ -377,7 +424,6 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
        for (n = 0; n < MAXFIELDS; n++) {
                int tag;
                isc_region_t r;
-
                do {
                        ret = isc_lex_gettoken(lex, opt, &token);
                        if (ret == ISC_R_EOF)
@@ -391,11 +437,50 @@ dst__privstruct_parse(dst_key_t *key, unsigned int alg, isc_lex_t *lex,
                        goto fail;
                }
 
+               /* Numeric metadata */
+               tag = find_numericdata(DST_AS_STR(token));
+               if (tag >= 0) {
+                       INSIST(tag < NUMERIC_NTAGS);
+
+                       NEXTTOKEN(lex, opt | ISC_LEXOPT_NUMBER, &token);
+                       if (token.type != isc_tokentype_number) {
+                               ret = DST_R_INVALIDPRIVATEKEY;
+                               goto fail;
+                       }
+
+                       dst_key_setnum(key, tag, token.value.as_ulong);
+                       goto next;
+               }
+
+               /* Timing metadata */
+               tag = find_timedata(DST_AS_STR(token));
+               if (tag >= 0) {
+                       INSIST(tag < TIMING_NTAGS);
+
+                       NEXTTOKEN(lex, opt, &token);
+                       if (token.type != isc_tokentype_string) {
+                               ret = DST_R_INVALIDPRIVATEKEY;
+                               goto fail;
+                       }
+
+                       ret = dns_time32_fromtext(DST_AS_STR(token), &when);
+                       if (ret != ISC_R_SUCCESS)
+                               goto fail;
+
+                       dst_key_settime(key, tag, when);
+
+                       goto next;
+               }
+
+               /* Key data */
                tag = find_value(DST_AS_STR(token), alg);
-               if (tag < 0 || TAG_ALG(tag) != alg) {
+               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);
@@ -406,23 +491,23 @@ 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;
+               priv->nelements++;
 
+         next:
                READLINE(lex, opt, &token);
                data = NULL;
        }
  done:
-       priv->nelements = n;
-
        if (check_data(priv, alg, ISC_TRUE) < 0)
                goto fail;
 
        return (ISC_R_SUCCESS);
 
 fail:
-       priv->nelements = n;
        dst__privstruct_free(priv, mctx);
        if (data != NULL)
                isc_mem_put(mctx, data, MAXFIELDSIZE);
@@ -430,17 +515,21 @@ fail:
        return (ret);
 }
 
-int
+isc_result_t
 dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
                          const char *directory)
 {
        FILE *fp;
        int ret, i;
-       isc_result_t iret;
+       isc_result_t result;
        char filename[ISC_DIR_NAMEMAX];
        char buffer[MAXFIELDSIZE * 2];
-       isc_buffer_t b;
        isc_fsaccess_t access;
+       isc_stdtime_t when;
+       isc_uint32_t value;
+       isc_buffer_t b;
+       isc_region_t r;
+       int major, minor;
 
        REQUIRE(priv != NULL);
 
@@ -461,11 +550,17 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
                         &access);
        (void)isc_fsaccess_set(filename, access);
 
+       dst_key_getprivateformat(key, &major, &minor);
+       if (major == 0 && minor == 0) {
+               major = DST_MAJOR_VERSION;
+               minor = DST_MINOR_VERSION;
+       }
+
        /* XXXDCL return value should be checked for full filesystem */
-       fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, MAJOR_VERSION,
-               MINOR_VERSION);
+       fprintf(fp, "%s v%d.%d\n", PRIVATE_KEY_STR, major, minor);
 
        fprintf(fp, "%s %d ", ALGORITHM_STR, dst_key_alg(key));
+
        /* XXXVIX this switch statement is too sparse to gen a jump table. */
        switch (dst_key_alg(key)) {
        case DST_ALG_RSAMD5:
@@ -480,6 +575,18 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
        case DST_ALG_RSASHA1:
                fprintf(fp, "(RSASHA1)\n");
                break;
+       case DST_ALG_NSEC3RSASHA1:
+               fprintf(fp, "(NSEC3RSASHA1)\n");
+               break;
+       case DST_ALG_NSEC3DSA:
+               fprintf(fp, "(NSEC3DSA)\n");
+               break;
+       case DST_ALG_RSASHA256:
+               fprintf(fp, "(RSASHA256)\n");
+               break;
+       case DST_ALG_RSASHA512:
+               fprintf(fp, "(RSASHA512)\n");
+               break;
        case DST_ALG_HMACMD5:
                fprintf(fp, "(HMAC_MD5)\n");
                break;
@@ -504,8 +611,6 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
        }
 
        for (i = 0; i < priv->nelements; i++) {
-               isc_buffer_t b;
-               isc_region_t r;
                const char *s;
 
                s = find_tag(priv->elements[i].tag);
@@ -513,22 +618,48 @@ dst__privstruct_writefile(const dst_key_t *key, const dst_private_t *priv,
                r.base = priv->elements[i].data;
                r.length = priv->elements[i].length;
                isc_buffer_init(&b, buffer, sizeof(buffer));
-               iret = isc_base64_totext(&r, sizeof(buffer), "", &b);
-               if (iret != ISC_R_SUCCESS) {
+               result = isc_base64_totext(&r, sizeof(buffer), "", &b);
+               if (result != ISC_R_SUCCESS) {
                        fclose(fp);
                        return (DST_R_INVALIDPRIVATEKEY);
                }
                isc_buffer_usedregion(&b, &r);
 
                fprintf(fp, "%s ", s);
-               fwrite(r.base, 1, r.length, fp);
+               isc_util_fwrite(r.base, 1, r.length, fp);
                fprintf(fp, "\n");
        }
 
+       /* Add the metadata tags */
+       if (major > 1 || (major == 1 && minor >= 3)) {
+               for (i = 0; i < NUMERIC_NTAGS; i++) {
+                       result = dst_key_getnum(key, i, &value);
+                       if (result != ISC_R_SUCCESS)
+                               continue;
+                       fprintf(fp, "%s %u\n", numerictags[i], value);
+               }
+               for (i = 0; i < TIMING_NTAGS; i++) {
+                       result = dst_key_gettime(key, i, &when);
+                       if (result != ISC_R_SUCCESS)
+                               continue;
+
+                       isc_buffer_init(&b, buffer, sizeof(buffer));
+                       result = dns_time32_totext(when, &b);
+                       if (result != ISC_R_SUCCESS)
+                               continue;
+
+                       isc_buffer_usedregion(&b, &r);
+
+                       fprintf(fp, "%s ", timetags[i]);
+                       isc_util_fwrite(r.base, 1, r.length, fp);
+                       fprintf(fp, "\n");
+               }
+       }
+
        fflush(fp);
-       iret = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS;
+       result = ferror(fp) ? DST_R_WRITEERROR : ISC_R_SUCCESS;
        fclose(fp);
-       return (iret);
+       return (result);
 }
 
 /*! \file */