chiark / gitweb /
server/keymgmt.c: Refactor key loading.
[tripe] / server / keymgmt.c
index 0ef633c..d80b81e 100644 (file)
@@ -42,135 +42,124 @@ typedef struct kgops {
   int (*loadpub)(key_data *, kdata *, dstr *, dstr *);
 } kgops;
 
-/* --- Diffie-Hellman --- */
-
-static int kgdh_priv(key_data *d, kdata *kd, dstr *t, dstr *e)
-{
-  key_packstruct kps[DH_PRIVFETCHSZ];
-  key_packdef *kp;
-  dh_priv dp;
-  int rc;
-
-  kp = key_fetchinit(dh_privfetch, kps, &dp);
-  if ((rc = key_unpack(kp, d, t)) != 0) {
-    a_format(e, "unpack-failed", "%s", key_strerror(rc), A_END);
-    goto fail_0;
-  }
-  kd->g = group_prime(&dp.dp);
-  kd->kpriv = MP_COPY(dp.x);
-  rc = 0;
-  goto done;
-fail_0:
-  rc = -1;
-done:
-  key_fetchdone(kp);
-  return (rc);
-}
-
-static int kgdh_pub(key_data *d, kdata *kd, dstr *t, dstr *e)
-{
-  key_packstruct kps[DH_PUBFETCHSZ];
-  key_packdef *kp;
-  dh_pub dp;
-  int rc;
-
-  kp = key_fetchinit(dh_pubfetch, kps, &dp);
-  if ((rc = key_unpack(kp, d, t)) != 0) {
-    a_format(e, "unpack-failed", "%s", key_strerror(rc), A_END);
-    goto fail_0;
-  }
-  kd->g = group_prime(&dp.dp);
-  kd->kpub = G_CREATE(kd->g);
-  if (G_FROMINT(kd->g, kd->kpub, dp.y)) {
-    a_format(e, "bad-public-vector", A_END);
-    goto fail_1;
-  }
-  rc = 0;
-  goto done;
-fail_1:
-  G_DESTROY(kd->g, kd->kpub);
-  G_DESTROYGROUP(kd->g);
-fail_0:
-  rc = -1;
-done:
-  key_fetchdone(kp);
-  return (rc);
-}
-
-static const kgops kgdh_ops = { "dh", kgdh_priv, kgdh_pub };
-
-/* --- Elliptic curve --- */
-
-static int kgec_priv(key_data *d, kdata *kd, dstr *t, dstr *e)
-{
-  key_packstruct kps[EC_PRIVFETCHSZ];
-  key_packdef *kp;
-  ec_priv ep;
-  ec_info ei;
-  const char *err;
-  int rc;
+/* --- @KLOAD@ --- *
+ *
+ * Arguments:  @ty@, @TY@ = key type name (lower- and upper-case)
+ *             @which@, @WHICH@ = `pub' or `priv' (and upper-case)
+ *             @setgroup@ = code to initialize @kd->g@
+ *             @setpriv@ = code to initialize @kd->kpriv@
+ *             @setpub@ = code to initialize @kd->kpub@
+ *
+ * Use:                Generates the body of one of the (rather tedious) key loading
+ *             functions.  See the description of @KEYTYPES@ below for the
+ *             details.
+ */
 
-  kp = key_fetchinit(ec_privfetch, kps, &ep);
-  if ((rc = key_unpack(kp, d, t)) != 0) {
-    a_format(e, "unpack-failed", "%s", key_strerror(rc), A_END);
-    goto fail_0;
-  }
-  if ((err = ec_getinfo(&ei, ep.cstr)) != 0) {
-    a_format(e, "decode-failed", "%s", err, A_END);
-    goto fail_0;
-  }
-  kd->g = group_ec(&ei);
-  kd->kpriv = MP_COPY(ep.x);
-  rc = 0;
-  goto done;
-fail_0:
-  rc = -1;
-done:
-  key_fetchdone(kp);
-  return (rc);
+#define KLOAD(ty, TY, which, WHICH, setgroup, setpriv, setpub)         \
+static int kg##ty##_##which(key_data *d, kdata *kd, dstr *t, dstr *e)  \
+{                                                                      \
+  key_packstruct kps[TY##_##WHICH##FETCHSZ];                           \
+  key_packdef *kp;                                                     \
+  ty##_##which p;                                                      \
+  int rc;                                                              \
+                                                                       \
+  /* --- Initialize things we've not set up yet --- */                 \
+                                                                       \
+  kd->g = 0; kd->kpub = 0;                                             \
+                                                                       \
+  /* --- Unpack the key --- */                                         \
+                                                                       \
+  kp = key_fetchinit(ty##_##which##fetch, kps, &p);                    \
+  if ((rc = key_unpack(kp, d, t)) != 0) {                              \
+    a_format(e, "unpack-failed", "%s", key_strerror(rc), A_END);       \
+    goto fail;                                                         \
+  }                                                                    \
+                                                                       \
+  /* --- Extract the pieces of the key --- */                          \
+                                                                       \
+  setgroup;                                                            \
+  setpriv;                                                             \
+  kd->kpub = G_CREATE(kd->g);                                          \
+  setpub;                                                              \
+                                                                       \
+  /* --- We win --- */                                                 \
+                                                                       \
+  rc = 0;                                                              \
+  goto done;                                                           \
+                                                                       \
+fail:                                                                  \
+  if (kd->kpub) G_DESTROY(kd->g, kd->kpub);                            \
+  if (kd->g) G_DESTROYGROUP(kd->g);                                    \
+  rc = -1;                                                             \
+                                                                       \
+done:                                                                  \
+  key_fetchdone(kp);                                                   \
+  return (rc);                                                         \
 }
 
-static int kgec_pub(key_data *d, kdata *kd, dstr *t, dstr *e)
-{
-  key_packstruct kps[EC_PUBFETCHSZ];
-  key_packdef *kp;
-  ec_pub ep;
-  ec_info ei;
-  const char *err;
-  int rc;
+/* --- @KEYTYPES@ --- *
+ *
+ * A list of the various key types, and how to unpack them.  Each entry in
+ * the list has the form
+ *
+ *     _(ty, TY, setgroup, setpriv, setpub)
+ *
+ * The @ty@ and @TY@ are lower- and upper-case versions of the key type name,
+ * and there should be @key_fetchdef@s called @ty_{priv,pub}fetch@.
+ *
+ * The @setgroup@, @setpriv@ and @setpub@ items are code fragments which are
+ * passed to @KLOAD@ to build appropriate key-loading methods.  By the time
+ * these code fragments are run, the key has been unpacked from the incoming
+ * key data using @ty_whichfetch@ into a @ty_which@ structure named @p@.
+ * They can report errors by writing an appropriate token sequence to @e@ and
+ * jumping to @fail@.
+ */
 
-  kp = key_fetchinit(ec_pubfetch, kps, &ep);
-  if ((rc = key_unpack(kp, d, t)) != 0) {
-    a_format(e, "unpack-failed", "%s", key_strerror(rc), A_END);
-    goto fail_0;
-  }
-  if ((err = ec_getinfo(&ei, ep.cstr)) != 0) {
-    a_format(e, "decode-failed", "%s", err, A_END);
-    goto fail_0;
-  }
-  kd->g = group_ec(&ei);
-  kd->kpub = G_CREATE(kd->g);
-  if (G_FROMEC(kd->g, kd->kpub, &ep.p)) {
-    a_format(e, "bad-public-vector", A_END);
-    goto fail_1;
-  }
-  rc = 0;
-  goto done;
-fail_1:
-  G_DESTROY(kd->g, kd->kpub);
-  G_DESTROYGROUP(kd->g);
-fail_0:
-  rc = -1;
-done:
-  key_fetchdone(kp);
-  return (rc);
-}
+#define KEYTYPES(_)                                                    \
+                                                                       \
+  /* --- Diffie-Hellman --- */                                         \
+                                                                       \
+  _(dh, DH,                                                            \
+    { kd->g = group_prime(&p.dp); },                                   \
+    { kd->kpriv = MP_COPY(p.x); },                                     \
+    { if (G_FROMINT(kd->g, kd->kpub, p.y)) {                           \
+       a_format(e, "bad-public-vector", A_END);                        \
+       goto fail;                                                      \
+      }                                                                        \
+    })                                                                 \
+                                                                       \
+  /* --- Elliptic curves --- */                                                \
+                                                                       \
+  _(ec, EC,                                                            \
+    { ec_info ei; const char *err;                                     \
+      if ((err = ec_getinfo(&ei, p.cstr)) != 0) {                      \
+       a_format(e, "decode-failed", "%s", err, A_END);                 \
+       goto fail;                                                      \
+      }                                                                        \
+      kd->g = group_ec(&ei);                                           \
+    },                                                                 \
+    { kd->kpriv = MP_COPY(p.x); },                                     \
+    { if (G_FROMEC(kd->g, kd->kpub, &p.p)) {                           \
+       a_format(e, "bad-public-vector", A_END);                        \
+       goto fail;                                                      \
+      }                                                                        \
+    })
 
-static const kgops kgec_ops = { "ec", kgec_priv, kgec_pub };
+#define KEYTYPE_DEF(ty, TY, setgroup, setpriv, setpub)                 \
+  KLOAD(ty, TY, priv, PRIV, setgroup, setpriv,                         \
+       { G_EXP(kd->g, kd->kpub, kd->g->g, kd->kpriv); })               \
+  KLOAD(ty, TY, pub, PUB, setgroup, { }, setpub)                       \
+  static const kgops kg##ty##_ops = { #ty, kg##ty##_priv, kg##ty##_pub };
+KEYTYPES(KEYTYPE_DEF)
 
 /* --- Table of supported key types --- */
 
-static const kgops *kgtab[] = { &kgdh_ops, &kgec_ops, 0 };
+static const kgops *kgtab[] = {
+#define KEYTYPE_ENTRY(ty, TY, setgroup, setpriv, setpub) &kg##ty##_ops,
+  KEYTYPES(KEYTYPE_ENTRY)
+#undef KEYTYPE_ENTRY
+  0
+};
 
 /*----- Algswitch stuff ---------------------------------------------------*/
 
@@ -404,12 +393,11 @@ static int kh_loadpriv(const kgops *ko, key_data *d, kdata *kd,
     a_format(e, "bad-group", "%s", err, A_END);
     goto fail_1;
   }
-  kd->kpub = G_CREATE(kd->g);
-  G_EXP(kd->g, kd->kpub, kd->g->g, kd->kpriv);
   return (0);
 
 fail_1:
   mp_drop(kd->kpriv);
+  G_DESTROY(kd->g, kd->kpub);
   G_DESTROYGROUP(kd->g);
 fail_0:
   return (-1);