Generate, store and retreive elliptic curve keys.
[u/mdw/catacomb] / keyutil.c
index 80278ad..0911021 100644 (file)
--- a/keyutil.c
+++ b/keyutil.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: keyutil.c,v 1.13 2001/02/21 20:04:27 mdw Exp $
+ * $Id: keyutil.c,v 1.17 2004/03/28 01:58:47 mdw Exp $
  *
  * Simple key manager program
  *
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: keyutil.c,v $
+ * Revision 1.17  2004/03/28 01:58:47  mdw
+ * Generate, store and retreive elliptic curve keys.
+ *
+ * Revision 1.16  2003/10/15 09:31:45  mdw
+ * Fix help message.
+ *
+ * Revision 1.15  2003/05/15 23:23:24  mdw
+ * Fix behaviour with bogus trailing attributes.
+ *
+ * Revision 1.14  2001/02/23 09:03:27  mdw
+ * Simplify usage message by removing nonexistant options.
+ *
  * Revision 1.13  2001/02/21 20:04:27  mdw
  * Provide help on individual commands (some need it desparately).  Allow
  * atomic retagging of keys.
 #include "bbs.h"
 #include "dh.h"
 #include "dsa.h"
+#include "ec.h"
+#include "ec-keys.h"
+#include "ectab.h"
 #include "fibrand.h"
 #include "getdate.h"
 #include "key.h"
@@ -171,8 +186,11 @@ static void setattr(key_file *f, key *k, char *v[])
     int err;
     char *p = *v;
     size_t eq = strcspn(p, "=");
-    if (p[eq] == 0)
-      moan("invalid assignment: `%s'", p);
+    if (!p[eq]) {
+      moan("invalid assignment: `%s' (ignored)", p);
+      v++;
+      continue;
+    }
     p[eq] = 0;
     p += eq + 1;
     if ((err = key_putattr(f, k, *v, *p ? p : 0)) != 0)
@@ -191,6 +209,7 @@ typedef struct keyopts {
   dstr tag;                            /* Full tag name for the key */
   unsigned f;                          /* Flags for the new key */
   unsigned bits, qbits;                        /* Bit length for the new key */
+  const char *curve;                   /* Elliptic curve name/info */
   key *p;                              /* Parameters key-data */
 } keyopts;
 
@@ -385,7 +404,7 @@ static void alg_des(keyopts *k)
   int i;
 
   if (!k->bits)
-    k->bits = 112;
+    k->bits = 168;
   if (k->p)
     die(EXIT_FAILURE, "no shared parameters for DES keys");
   if (k->bits % 56 || k->bits > 168)
@@ -679,6 +698,87 @@ static void alg_bbs(keyopts *k)
   bbs_privfree(&bp);
 }
 
+static void alg_ecparam(keyopts *k)
+{
+  static const char *pl[] = { "curve", 0 };
+  if (!copyparam(k, pl)) {
+    ec_info ei;
+    const char *e;
+    key_data *kd = &k->k->k;
+
+    /* --- Decide on a curve --- */
+
+    if (!k->bits) k->bits = 256;
+    if (!k->curve) {
+      if (k->bits <= 56) k->curve = "secp112r1";
+      else if (k->bits <= 64) k->curve = "secp128r1";
+      else if (k->bits <= 80) k->curve = "secp160r1";
+      else if (k->bits <= 96) k->curve = "secp192r1";
+      else if (k->bits <= 112) k->curve = "secp224r1";
+      else if (k->bits <= 128) k->curve = "secp256r1";
+      else if (k->bits <= 192) k->curve = "secp384r1";
+      else if (k->bits <= 256) k->curve = "secp521r1";
+      else
+       die(EXIT_FAILURE, "no built-in curves provide %u-bit security",
+           k->bits);
+    }
+
+    /* --- Check it --- */
+
+    if ((e = ec_getinfo(&ei, k->curve)) != 0)
+      die(EXIT_FAILURE, "error in curve spec: %s", e);
+    if (!(k->f & f_quiet) && (e = ec_checkinfo(&ei, &rand_global)) != 0)
+      moan("WARNING!  curve check failed: %s", e);
+    ec_freeinfo(&ei);
+
+    /* --- Write out the answer --- */
+
+    key_structure(kd);
+    kd = key_structcreate(kd, "curve");
+    key_string(kd, k->curve);
+    kd->e |= KCAT_SHARE;
+  }
+}
+
+static void alg_ec(keyopts *k)
+{
+  key_data *kd = &k->k->k;
+  key_data *kkd;
+  mp *x = MP_NEW;
+  ec p = EC_INIT;
+  const char *e;
+  ec_info ei;
+
+  /* --- Get the curve --- */
+
+  alg_ecparam(k);
+  if ((kkd = key_structfind(kd, "curve")) == 0)
+    die(EXIT_FAILURE, "unexpected failure looking up subkey `curve')");
+  if ((kkd->e & KF_ENCMASK) != KENC_STRING)
+    die(EXIT_FAILURE, "subkey `curve' is not a string");
+  if ((e = ec_getinfo(&ei, kkd->u.p)) != 0)
+    die(EXIT_FAILURE, "error in curve spec: %s", e);
+
+  /* --- Invent a private exponent and compute the public key --- */
+
+  x = mprand_range(MP_NEWSEC, ei.r, &rand_global, 0);
+  ec_mul(ei.c, &p, &ei.g, x);
+
+  /* --- Store everything away --- */
+
+  kkd = key_structcreate(kd, "p");
+  key_ec(kkd, &p);
+  kkd->e |= KCAT_PUB;
+  kkd = key_structcreate(kd, "private");
+  key_structure(kkd);
+  mpkey(kkd, "x", x, KCAT_PRIV | KF_BURN);
+
+  /* --- Done --- */
+
+  ec_freeinfo(&ei);
+  mp_drop(x);
+}
+
 /* --- The algorithm tables --- */
 
 typedef struct keyalg {
@@ -696,6 +796,8 @@ static keyalg algtab[] = {
   { "dh",              alg_dh,         "Diffie-Hellman key exchange" },
   { "dh-param",                alg_dhparam,    "Diffie-Hellman parameters" },
   { "bbs",             alg_bbs,        "Blum-Blum-Shub generator" },
+  { "ec-param",                alg_ecparam,    "Elliptic curve parameters" },
+  { "ec",              alg_ec,         "Elliptic curve crypto" },
   { 0,                 0 }
 };
 
@@ -723,13 +825,14 @@ static int cmd_add(int argc, char *argv[])
       { "comment",     OPTF_ARGREQ,    0,      'c' },
       { "tag",         OPTF_ARGREQ,    0,      't' },
       { "rand-id",     OPTF_ARGREQ,    0,      'R' },
+      { "curve",       OPTF_ARGREQ,    0,      'C' },
       { "lock",                0,              0,      'l' },
       { "quiet",       0,              0,      'q' },
       { "lim-lee",     0,              0,      'L' },
       { "subgroup",    0,              0,      'S' },
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:lqrLS", opt, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+a:b:B:p:e:c:t:R:C:lqrLS", opt, 0, 0, 0);
     if (i < 0)
       break;
 
@@ -807,6 +910,19 @@ static int cmd_add(int argc, char *argv[])
        c = optarg;
        break;
 
+      /* --- Elliptic curve parameters --- */
+
+      case 'C':
+       if (strcmp(optarg, "list") == 0) {
+         const ecentry *ee;
+         printf("Built-in elliptic curves:\n");
+         for (ee = ectab; ee->name; ee++)
+           printf("  %s\n", ee->name);
+         exit(0);
+       }
+       k.curve = optarg;
+       break;
+
       /* --- Store tags --- */
 
       case 't':
@@ -1023,6 +1139,20 @@ static void showkeydata(key_data *k, int ind, listopts *o, dstr *d)
       putchar('\n');
       break;
 
+    /* --- Strings --- */
+
+    case KENC_STRING:
+      printf(" `%s'\n", k->u.p);
+      break;
+
+    /* --- Elliptic curve points --- */
+
+    case KENC_EC:
+      fputs(" 0x", stdout); mp_writefile(k->u.e.x, stdout, 16);
+      fputs(", 0x", stdout); mp_writefile(k->u.e.y, stdout, 16);
+      putchar('\n');
+      break;      
+
     /* --- Structured keys --- *
      *
      * Just iterate over the subkeys.
@@ -1611,6 +1741,7 @@ Options:\n\
 -b, --bits=N           Generate an N-bit key.\n\
 -B, --qbits=N          Use an N-bit subgroup or factors.\n\
 -p, --parameters=TAG   Get group parameters from TAG.\n\
+-C, --curve=CURVE      Use elliptic curve CURVE.\n\
 -e, --expire=TIME      Make the key expire after TIME.\n\
 -c, --comment=STRING   Attach the command STRING to the key.\n\
 -t, --tag=TAG          Tag the key with the name TAG.\n\
@@ -1693,7 +1824,7 @@ static cmd *findcmd(const char *name)
 
 void usage(FILE *fp)
 {
-  pquis(fp, "Usage: $ [-k file] [-i tag] [-t type] command [args]\n");
+  pquis(fp, "Usage: $ [-k keyring] command [args]\n");
 }
 
 void version(FILE *fp)
@@ -1709,14 +1840,12 @@ void help(FILE *fp, char **argv)
   fputc('\n', fp);
   if (*argv) {
     c = findcmd(*argv);
-    fprintf(fp, "Usage: %s [-options] %s\n", QUIS, c->usage);
+    fprintf(fp, "Usage: %s [-k keyring] %s\n", QUIS, c->usage);
     if (c->help) {
       fputc('\n', fp); 
       fputs(c->help, fp);
     }
   } else {
-    version(fp);
-    fputc('\n', fp);
     usage(fp);
     fputs("\n\
 Performs various simple key management operations.  Command line options\n\
@@ -1772,14 +1901,12 @@ int main(int argc, char *argv[])
       /* --- Real live useful options --- */
 
       { "keyring",     OPTF_ARGREQ,    0,      'k' },
-      { "id",          OPTF_ARGREQ,    0,      'i' },
-      { "type",                OPTF_ARGREQ,    0,      't' },
 
       /* --- Magic terminator --- */
 
       { 0,             0,              0,      0 }
     };
-    int i = mdwopt(argc, argv, "+hvu k:i:t:", opt, 0, 0, 0);
+    int i = mdwopt(argc, argv, "+hvu k:", opt, 0, 0, 0);
 
     if (i < 0)
       break;