Major and incompatible overhaul of key_data representation. Fix leaks.
authormdw <mdw>
Thu, 22 Sep 2005 11:03:20 +0000 (11:03 +0000)
committermdw <mdw>
Thu, 22 Sep 2005 11:03:20 +0000 (11:03 +0000)
19 files changed:
catcrypt.c
cc-sig.c
cookie.c
exp.h
key-attr.c
key-binary.c
key-data.c
key-data.h
key-fetch.c
key-file.c
key-io.c
key-misc.c
key-pack.c
key-pass.c
key-text.c
key.h
keyutil.c
mparena.c
rspit.c

index 967730a..4c343a4 100644 (file)
@@ -313,6 +313,7 @@ static int encrypt(int argc, char *argv[])
   freeenc(e);
   if (s) freesig(s);
   freekem(km);
+  if (fp != stdin) fclose(fp);
   if (of) fclose(ofp);
   key_close(&kf);
   dstr_destroy(&d);
@@ -459,6 +460,7 @@ static int decrypt(int argc, char *argv[])
       key_fulltag(sk, &d);
       printf("INFO good-signature %s\n", d.buf);
     }
+    freesig(s);
   } else if (verb)
     printf("INFO no-signature\n");
 
@@ -499,6 +501,7 @@ static int decrypt(int argc, char *argv[])
        printf("FAIL bad ciphertext chunk: authentication failure\n");
       exit(EXIT_FAILURE);
     }
+    GH_DESTROY(h);
     if (!BLEFT(&b))
       break;
     GC_DECRYPT(c, BCUR(&b), BCUR(&b), BLEFT(&b));
@@ -541,6 +544,7 @@ static int decrypt(int argc, char *argv[])
   GC_DESTROY(cx);
   GM_DESTROY(m);
   freekem(km);
+  if (fp != stdin) fclose(fp);
   if (of) fclose(ofp);
   key_close(&kf);
   dstr_destroy(&d);
index 027fa52..45679ce 100644 (file)
--- a/cc-sig.c
+++ b/cc-sig.c
@@ -382,6 +382,7 @@ static void dsa_sigdestroy(sig *s)
   G_DESTROY(ds->g.g, ds->g.p);
   mp_drop(ds->g.u);
   G_DESTROYGROUP(ds->g.g);
+  DESTROY(ds);
 }
 
 static const sigops dsa_sig = {
index 9b32389..c988541 100644 (file)
--- a/cookie.c
+++ b/cookie.c
@@ -188,9 +188,9 @@ static gmac *getmac(key *k, const char *app)
 
   /* --- Unlock the key --- */
 
-  kp.kd.e = KENC_BINARY;
+  kp.e = KENC_BINARY;
   kp.p = &kb;
-  if ((e = key_unpack(&kp, &k->k, &t)) != 0) {
+  if ((e = key_unpack(&kp, k->k, &t)) != 0) {
     die(EXIT_FAILURE, "error unpacking key `%s': %s",
        t.buf, key_strerror(e));
   }
diff --git a/exp.h b/exp.h
index a8b3812..e729e8c 100644 (file)
--- a/exp.h
+++ b/exp.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: exp.h,v 1.4 2004/04/08 01:36:15 mdw Exp $
+ * $Id$
  *
  * Generalized exponentiation
  *
@@ -397,6 +397,7 @@ exp_simul_done:                                                             \
   for (i = 1; i < vn; i++)                                             \
     EXP_DROP(v[i]);                                                    \
   xfree(v);                                                            \
+  xfree(e.s);                                                          \
 } while (0)
 
 /*----- Functions provided ------------------------------------------------*/
index 27f4490..2d33b9c 100644 (file)
@@ -179,6 +179,28 @@ int key_putattr(key_file *f, key *k, const char *n, const char *v)
   return (0);
 }
 
+/* --- @key_setkeydata@ --- *
+ *
+ * Arguments:  @key_file *kf@ = pointer to key file
+ *             @key *k@ = pointer to key
+ *             @key_data *kd@ = new key data
+ *
+ * Returns:    Zero on success, or a @KERR_@ error code on failure.
+ *
+ * Use:                Sets the key data for a key.
+ */
+
+int key_setkeydata(key_file *kf, key *k, key_data *kd)
+{
+  if (!(kf->f & KF_WRITE))
+    return (KERR_READONLY);
+  key_drop(k->k);
+  key_incref(kd);
+  k->k = kd;
+  kf->f |= KF_MODIFIED;
+  return (0);
+}
+
 /* --- @key_setcomment@ --- *
  *
  * Arguments:  @key_file *f@ = pointer to key file block
index dc8c701..087d992 100644 (file)
  *
  * Arguments:  @const void *p@ = pointer to buffer to read
  *             @size_t sz@ = size of the buffer
- *             @key_data *k@ = pointer to key data block to write to
  *
- * Returns:    Zero if everything worked, nonzero otherwise.
+ * Returns:    The newly-read key data, or null if it failed.
  *
  * Use:                Decodes a binary representation of a key.
  */
 
-int key_decode(const void *p, size_t sz, key_data *k)
+key_data *key_decode(const void *p, size_t sz)
 {
   const octet *q = p;
   size_t psz;
+  key_data *kd;
   unsigned e;
 
   /* --- Parse the header information --- *
@@ -70,8 +70,7 @@ int key_decode(const void *p, size_t sz, key_data *k)
   e = LOAD16(q);
   psz = LOAD16(q + 2);
   if (psz + 4 > sz)
-    return (-1);
-  k->e = e;
+    return (0);
 
   /* --- Now decide what to do --- */
 
@@ -81,51 +80,51 @@ int key_decode(const void *p, size_t sz, key_data *k)
 
     case KENC_BINARY:
     case KENC_ENCRYPT:
-      k->u.k.k = sub_alloc(psz);
-      memcpy(k->u.k.k, q + 4, psz);
-      k->u.k.sz = psz;
+      kd = key_newbinary(e, q + 4, psz);
       break;
 
     /* --- Multiprecision integer data --- */
 
     case KENC_MP:
-      k->u.m = mp_loadb(k->e & KF_BURN ? MP_NEWSEC : MP_NEW, q + 4, psz);
+      kd = key_newmp(e, mp_loadb(e & KF_BURN ? MP_NEWSEC : MP_NEW,
+                                q + 4, psz));
       break;
 
     /* --- String data --- */
 
     case KENC_STRING:
-      k->u.p = xmalloc(sz + 1);
-      memcpy(k->u.p, q + 4, sz);
-      k->u.p[sz] = 0;
+      kd = key_newraw(e);
+      kd->u.p = xmalloc(sz + 1);
+      memcpy(kd->u.p, q + 4, sz);
+      kd->u.p[sz] = 0;
       break;
 
     /* --- Elliptic curve point data --- */
 
     case KENC_EC: {
       size_t xsz, ysz;
-      EC_CREATE(&k->u.e);
+      kd = key_newraw(e);
+      EC_CREATE(&kd->u.e);
       if (!sz) break;
-      if (sz < 2) return (-1);
+      if (sz < 2) return (0);
       xsz = LOAD16(q + 4);
-      if (sz < xsz + 4) return (-1);
+      if (sz < xsz + 4) return (0);
       ysz = LOAD16(q + 6 + xsz);
-      if (sz < xsz + ysz + 4) return (-1);
-      k->u.e.x = mp_loadb(MP_NEW, q + 6, xsz);
-      k->u.e.y = mp_loadb(MP_NEW, q + 8 + xsz, ysz);
+      if (sz < xsz + ysz + 4) return (0);
+      kd->u.e.x = mp_loadb(MP_NEW, q + 6, xsz);
+      kd->u.e.y = mp_loadb(MP_NEW, q + 8 + xsz, ysz);
     } break;
 
     /* --- Structured key data --- */
 
     case KENC_STRUCT: {
       dstr d = DSTR_INIT;
-      key_struct *ks;
-      unsigned f;
+      key_data *nkd;
 
-      if ((k->e & ~KF_ENCMASK) || (psz & 3))
-       return (-1);
+      if ((e & ~KF_ENCMASK) || (psz & 3))
+       return (0);
       q += 4;
-      sym_create(&k->u.s);
+      kd = key_newstruct();
 
       while (psz) {
 
@@ -142,20 +141,15 @@ int key_decode(const void *p, size_t sz, key_data *k)
 
        /* --- Read the encoding and size --- */
 
-       e = LOAD16(q);
        sz = (LOAD16(q + 2) + 7) & ~3;
        if (sz > psz)
          goto fail;
 
        /* --- Create a table node and fill it in --- */
 
-       ks = sym_find(&k->u.s, d.buf, d.len, sizeof(*ks), &f);
-       if (f)
-         goto fail;
-       if (key_decode(q, sz, &ks->k)) {
-         sym_remove(&k->u.s, ks);
+       if ((nkd = key_decode(q, sz)) == 0)
          goto fail;
-       }
+       key_structsteal(kd, d.buf, nkd);
        psz -= sz;
        q += sz;
       }
@@ -166,19 +160,20 @@ int key_decode(const void *p, size_t sz, key_data *k)
 
     fail:
       dstr_destroy(&d);
-      key_destroy(k);
-      return (-1);
+      key_drop(kd);
+      return (0);
     } break;
 
     /* --- Everything else --- */
 
     default:
-      return (-1);
+      return (0);
   }
 
   /* --- OK, that was good --- */
 
-  return (0);
+  kd->e = e;
+  return (kd);
 }
 
 /* --- @key_encode@ --- *
@@ -297,7 +292,7 @@ int key_encode(key_data *k, dstr *d, const key_filter *kf)
          DPUTS(d, SYM_NAME(ks));
          while (d->len & 3)
            DPUTC(d, 0);
-         if (key_encode(&ks->k, d, kf))
+         if (key_encode(ks->k, d, kf))
            rc = 1;
          else
            d->len = o;
index 8bb9099..a0644a1 100644 (file)
 #include "mp.h"
 #include "mptext.h"
 
+/*----- Reference counting stuff ------------------------------------------*/
+
+/* --- @key_incref@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data
+ *
+ * Returns:    ---
+ *
+ * Use:                Increments the refcount on a key data block.
+ */
+
+void key_incref(key_data *k) { KEY_INCREF(k); }
+
+/* --- @key_destroy@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data to destroy
+ *
+ * Returns:    ---
+ *
+ * Use:                Destroys a block of key data, regardless of reference count.
+ *             Don't use this unless you know what you're doing.
+ */
+
+void key_destroy(key_data *k)
+{
+  switch (k->e & KF_ENCMASK) {
+    case KENC_BINARY:
+    case KENC_ENCRYPT:
+      if (k->u.k.k) {
+       if (k->e & KF_BURN)
+         memset(k->u.k.k, 0, k->u.k.sz);
+       sub_free(k->u.k.k, k->u.k.sz);
+      }
+      break;
+    case KENC_MP:
+      mp_drop(k->u.m);
+      break;
+    case KENC_STRING:
+      xfree(k->u.p);
+      break;
+    case KENC_EC:
+      EC_DESTROY(&k->u.e);
+      break;
+    case KENC_STRUCT: {
+      key_data *kd;
+      key_subkeyiter i;
+
+      for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, 0, &kd); )
+       KEY_DROP(kd);
+      sym_destroy(&k->u.s);
+    } break;
+    default:
+      abort();
+  }
+  DESTROY(k);
+}
+
+/* --- @key_drop@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data to destroy
+ *
+ * Returns:    ---
+ *
+ * Use:                Drops a reference to key data, destroying it if necessary.
+ */
+
+void key_drop(key_data *k) { KEY_DROP(k); }
+
+/* --- @key_split@ --- *
+ *
+ * Arguments:  @key_data **kk@ = address of pointer to key data block
+ *
+ * Returns:    ---
+ *
+ * Use:                Replaces @*kk@ with a pointer to the same key data, but with
+ *             just one reference.
+ */
+
+void key_split(key_data **kk)
+{
+  key_data *k = *kk;
+  
+  if (k->ref == 1)
+    return;
+  switch (k->e & KF_ENCMASK) {
+    case KENC_BINARY:
+      *kk = key_newbinary(k->e, k->u.k.k, k->u.k.sz);
+      break;
+    case KENC_ENCRYPT:
+      *kk = key_newencrypted(k->e, k->u.k.k, k->u.k.sz);
+      break;
+    case KENC_MP:
+      *kk = key_newmp(k->e, k->u.m);
+      break;
+    case KENC_STRING:
+      *kk = key_newstring(k->e, k->u.p);
+      break;
+    case KENC_EC:
+      *kk = key_newec(k->e, &k->u.e);
+      break;
+    case KENC_STRUCT: {
+      key_subkeyiter i;
+      const char *tag;
+      key_data *kd;
+
+      *kk = key_newstruct();
+      for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &kd); )
+       key_structset(*kk, tag, kd);
+    } break;
+    default:
+      abort();
+  }
+}
+
 /*----- Setting new values ------------------------------------------------*/
 
-/* --- @key_binary@ --- *
+/* --- @key_newraw@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  @unsigned e@ = encoding type to set
+ *
+ * Returns:    New key block, not filled in.
+ */
+
+key_data *key_newraw(unsigned e)
+{
+  key_data *k = CREATE(key_data);
+  k->e = e;
+  k->ref = 1;
+  return (k);
+}
+
+/* --- @key_newbinary@ --- *
+ *
+ * Arguments:  @unsigned e@ = other encoding flags
  *             @const void *p@ = pointer to key data
  *             @size_t sz@ = size of the key data
  *
- * Returns:    ---
- *
- * Use:                Sets a binary key in a key data block.
+ * Returns:    New key data object.
  */
 
-void key_binary(key_data *k, const void *p, size_t sz)
+key_data *key_newbinary(unsigned e, const void *p, size_t sz)
 {
-  key_destroy(k);
-  k->e |= KENC_BINARY;
+  key_data *k = key_newraw(KENC_BINARY | e);
   k->u.k.k = sub_alloc(sz);
   memcpy(k->u.k.k, p, sz);
   k->u.k.sz = sz;
+  return (k);
 }
 
-/* --- @key_encrypted@ --- *
+/* --- @key_newencrypted@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  @unsigned e@ = other encoding flags
  *             @const void *p@ = pointer to key data
  *             @size_t sz@ = size of the key data
  *
- * Returns:    ---
- *
- * Use:                Sets an encrypted key in a key data block.
+ * Returns:    New key data object.
  */
 
-void key_encrypted(key_data *k, const void *p, size_t sz)
+key_data *key_newencrypted(unsigned e, const void *p, size_t sz)
 {
-  key_destroy(k);
-  k->e |= KENC_ENCRYPT;
+  key_data *k = key_newraw(KENC_ENCRYPT | e);
   k->u.k.k = sub_alloc(sz);
   memcpy(k->u.k.k, p, sz);
   k->u.k.sz = sz;
+  return (k);
 }
 
-/* --- @key_mp@ --- *
+/* --- @key_mewmp@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  @unsigned e@ = other encoding flags
  *             @mp *m@ = pointer to the value to set
  *
- * Returns:    ---
- *
- * Use:                Sets a multiprecision integer key in a key block.
+ * Returns:    New key data object.
  */
 
-void key_mp(key_data *k, mp *m)
+key_data *key_newmp(unsigned e, mp *m)
 {
-  key_destroy(k);
-  k->e |= KENC_MP;
+  key_data *k = key_newraw(KENC_MP | e);
   k->u.m = MP_COPY(m);
+  return (k);
 }
 
-/* --- @key_string@ --- *
+/* --- @key_newstring@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  @unsigned e@ = other encoding flags
  *             @const char *p@ = pointer to the value to set
  *
- * Returns:    ---
- *
- * Use:                Sets a plain string in a key block.
+ * Returns:    New key data object.
  */
 
-void key_string(key_data *k, const char *p)
+key_data *key_newstring(unsigned e, const char *p)
 {
-  key_destroy(k);
-  k->e |= KENC_STRING;
+  key_data *k = key_newraw(KENC_STRING | e);
   k->u.p = xstrdup(p);
+  return (k);
 }
 
-/* --- @key_ec@ --- *
+/* --- @key_newec@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const ec *e@ = pointer to the value to set
+ * Arguments:  @unsigned e@ = other encoding flags
+ *             @const ec *pt@ = pointer to the value to set
  *
- * Returns:    ---
- *
- * Use:                Sets an elliptic curve point in a key block.
+ * Returns:    New key data object.
  */
 
-void key_ec(key_data *k, const ec *e)
-{ 
-  key_destroy(k);
-  k->e |= KENC_EC;
+key_data *key_newec(unsigned e, const ec *pt)
+{
+  key_data *k = key_newraw(KENC_EC | e);
   EC_CREATE(&k->u.e);
-  EC_COPY(&k->u.e, e);
+  EC_COPY(&k->u.e, pt);
+  return (k);
 }
 
-/* --- @key_structure@ --- *
+/* --- @key_newstruct@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
- *
- * Returns:    ---
+ * Arguments:  ---
  *
- * Use:                Initializes a structured key type.
+ * Returns:    New key data object.
  */
 
-void key_structure(key_data *k)
+key_data *key_newstruct(void)
 {
-  key_destroy(k);
-  k->e |= KENC_STRUCT;
+  key_data *k = key_newraw(KENC_STRUCT);
   sym_create(&k->u.s);
+  return (k);
 }
 
 /* --- @key_structfind@ --- *
@@ -171,79 +288,86 @@ key_data *key_structfind(key_data *k, const char *tag)
   ks = sym_find(&k->u.s, tag, -1, 0, 0);
   if (!ks)
     return (0);
-  return (&ks->k);
+  return (ks->k);
 }
 
-/* --- @key_structcreate@ --- *
+/* --- @key_mksubkeyiter@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const char *tag@ = pointer to tag string
+ * Arguments:  @key_subkeyiter *i@ = pointer to iterator block
+ *             @key_data *k@ = pointer to key data block
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes a subkey iterator.
+ */
+
+void key_mksubkeyiter(key_subkeyiter *i, key_data *k)
+{
+  assert(((void)"Key is not structured",
+         (k->e & KF_ENCMASK) == KENC_STRUCT));
+  sym_mkiter(&i->i, &k->u.s);
+}
+
+/* --- @key_nextsubkey@ --- *
  *
- * Returns:    Pointer to newly created key data.
+ * Arguments:  @key_structiter *i@ = pointer to iterator block
+ *             @const char **tag@ = where to put the tag pointer, or null
+ *             @key_data **kd@ = where to put the key data pointer, or null
  *
- * Use:                Creates a new uninitialized subkey.
+ * Returns:    Nonzero if there was another item, zero if we hit the
+ *             end-stop.
+ *
+ * Use:                Collects the next subkey of a structured key.
  */
 
-key_data *key_structcreate(key_data *k, const char *tag)
+int key_nextsubkey(key_subkeyiter *i, const char **tag, key_data **kd)
 {
   key_struct *ks;
-  unsigned f;
 
-  assert(((void)"Key is not structured", k->e == KENC_STRUCT));
-  ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f);
-  if (f)
-    key_destroy(&ks->k);
-  ks->k.e = 0;
-  ks->k.u.k.k = 0;
-  ks->k.u.k.sz = 0;
-  return (&ks->k);
+  if ((ks = sym_next(&i->i)) == 0)
+    return (0);
+  if (tag) *tag = SYM_NAME(ks);
+  if (kd) *kd = ks->k;
 }
 
-/*----- Miscellaneous operations ------------------------------------------*/
-
-/* --- @key_destroy@ --- *
+/* --- @key_structset@, @key_structsteal@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data to destroy
+ * Arguments:  @key_data *k@ = pointer to key data block
+ *             @const char *tag@ = pointer to tag string
+ *             @key_data *kd@ = new key data to store
  *
  * Returns:    ---
  *
- * Use:                Destroys a lump of key data.
+ * Use:                Creates a new subkey.  Stealing doesn't affect @kd@'s
+ *             refcount.  If @kd@ is null, the subkey is deleted.
  */
 
-void key_destroy(key_data *k)
+static void structset(key_data *k, int stealp,
+                     const char *tag, key_data *kd)
 {
-  switch (k->e & KF_ENCMASK) {
-    case KENC_BINARY:
-    case KENC_ENCRYPT:
-      if (k->u.k.k) {
-       if (k->e & KF_BURN)
-         memset(k->u.k.k, 0, k->u.k.sz);
-       sub_free(k->u.k.k, k->u.k.sz);
-      }
-      break;
-    case KENC_MP:
-      mp_drop(k->u.m);
-      break;
-    case KENC_STRING:
-      xfree(k->u.p);
-      break;
-    case KENC_EC:
-      EC_DESTROY(&k->u.e);
-      break;
-    case KENC_STRUCT: {
-      sym_iter i;
-      key_struct *ks;
+  key_struct *ks;
+  unsigned f;
 
-      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; )
-       key_destroy(&ks->k);
-      sym_destroy(&k->u.s);
-    } break;
-  }
-  k->e = (k->e & ~KF_ENCMASK);
-  k->u.k.k = 0;
-  k->u.k.sz = 0;
+  assert(((void)"Key is not structured", k->e == KENC_STRUCT));
+  if (!kd) {
+    ks = sym_find(&k->u.s, tag, -1, 0, 0);
+    if (ks) sym_remove(&k->u.s, ks);
+  } else {
+    ks = sym_find(&k->u.s, tag, -1, sizeof(*ks), &f);
+    if (f)
+      key_drop(ks->k);
+    if (!stealp) KEY_INCREF(kd);
+    ks->k = kd;
+  }  
 }
 
+void key_structset(key_data *k, const char *tag, key_data *kd)
+  { structset(k, 0, tag, kd); }
+void key_structsteal(key_data *k, const char *tag, key_data *kd)
+  { structset(k, 1, tag, kd); }
+
+/*----- Miscellaneous operations ------------------------------------------*/
+
 /* --- @key_do@ --- *
  *
  * Arguments:  @key_data *k@ = pointer to key data block
@@ -266,101 +390,23 @@ int key_do(key_data *k, const key_filter *kf, dstr *d,
   if ((k->e & KF_ENCMASK) != KENC_STRUCT)
     return (func(k, d, p));
   else {
-    sym_iter i;
-    key_struct *ks;
+    key_subkeyiter i;
+    const char *tag;
     size_t n = 0;
     int rc;
 
     if (d)
       n = d->len;
-    for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
+    for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &k); ) {
       if (d) {
        d->len = n;
-       dstr_putf(d, ".%s", SYM_NAME(ks));
+       dstr_putf(d, ".%s", tag);
       }
-      if ((rc = key_do(&ks->k, kf, d, func, p)) != 0)
+      if ((rc = key_do(k, kf, d, func, p)) != 0)
        return (rc);
     }
     return (0);
   }
 }
 
-/* --- @key_copy@ --- *
- *
- * Arguments:  @key_data *kd@ = pointer to destination data block
- *             @key_data *k@ = pointer to source data block
- *             @const key_filter *kf@ = pointer to filter block
- *
- * Returns:    Nonzero if an item was actually copied.
- *
- * Use:                Copies a chunk of key data from one place to another.
- */
-
-int key_copy(key_data *kd, key_data *k, const key_filter *kf)
-{
-  kd->e = k->e;
-
-  if (!KEY_MATCH(kd, kf))
-    return (0);
-  switch (k->e & KF_ENCMASK) {
-
-    /* --- Plain binary data --- */
-
-    case KENC_BINARY:
-    case KENC_ENCRYPT:
-      if (!k->u.k.k)
-       kd->u.k.k = 0;
-      else {
-       kd->u.k.k = sub_alloc(k->u.k.sz);
-       memcpy(kd->u.k.k, k->u.k.k, k->u.k.sz);
-      }
-      kd->u.k.sz = k->u.k.sz;
-      break;
-
-    /* --- Multiprecision integers --- */
-
-    case KENC_MP:
-      kd->u.m = MP_COPY(k->u.m);
-      break;
-
-    /* --- Strings --- */
-
-    case KENC_STRING:
-      kd->u.p = xstrdup(k->u.p);
-      break;
-
-    /* --- Elliptic curve points --- */
-
-    case KENC_EC:
-      EC_CREATE(&kd->u.e);
-      EC_COPY(&kd->u.e, &k->u.e);
-      break;
-
-    /* --- Structured key data --- */
-
-    case KENC_STRUCT: {
-      sym_iter i;
-      key_struct *ks;
-      int rc = 0;
-
-      sym_create(&kd->u.s);
-      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
-       unsigned f;
-       key_struct *kks = sym_find(&kd->u.s, SYM_NAME(ks), -1,
-                                  sizeof(*kks), &f);
-       assert(((void)"Duplicate subkey tags", !f));
-       if (key_copy(&kks->k, &ks->k, kf))
-         rc = 1;
-       else
-         sym_remove(&kd->u.s, kks);
-      }
-      if (!rc) {
-       sym_destroy(&kd->u.s);
-       return (0);
-      }
-    } break;
-  }
-  return (1);
-}
-
 /*----- That's all, folks -------------------------------------------------*/
index 5644834..2a8620a 100644 (file)
@@ -67,6 +67,7 @@ typedef struct key_bin {
 
 typedef struct key_data {
   unsigned e;                          /* Encoding type for key data */
+  unsigned ref;                                /* Reference counter */
   union {
     key_bin k;                         /* Binary key data */
     mp *m;                             /* Multiprecision integer */
@@ -78,14 +79,17 @@ typedef struct key_data {
 
 typedef struct key_struct {
   sym_base _b;
-  key_data k;
+  key_data *k;
 } key_struct;
 
+typedef struct key_subkeyiter { sym_iter i; } key_subkeyiter;
+
 /* --- Packing and unpacking --- */
 
 typedef struct key_packdef {
+  unsigned e;                          /* Key data encoding type */
   void *p;                             /* Pointer to the destination */
-  key_data kd;                         /* Key data block */
+  key_data *kd;                                /* Key data block */
 } key_packdef;
 
 typedef struct key_packstruct {
@@ -137,8 +141,7 @@ enum {
   /* --- Other flags --- */
 
   KF_BURN      = 0x10,                 /* Burn key after use */
-  KF_TEMP      = 0x20,                 /* Temporary copy flag */
-  KF_OPT       = 0x40,                 /* Optional key (for @key_unpack@) */
+  KF_OPT       = 0x20,                 /* Optional key (for @key_unpack@) */
 
   /* --- Tag end --- */
 
@@ -209,78 +212,77 @@ extern int key_match(key_data */*k*/, const key_filter */*kf*/);
 
 /*----- Setting new key data ----------------------------------------------*/
 
-/* --- @key_binary@ --- *
+/* --- @key_newraw@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  @unsigned e@ = encoding type to set
+ *
+ * Returns:    New key block, not filled in.
+ */
+
+extern key_data *key_newraw(unsigned /*e*/);
+
+/* --- @key_newbinary@ --- *
+ *
+ * Arguments:  @unsigned e@ = other encoding flags
  *             @const void *p@ = pointer to key data
  *             @size_t sz@ = size of the key data
  *
- * Returns:    ---
- *
- * Use:                Sets a binary key in a key data block.
+ * Returns:    New key data object.
  */
 
-extern void key_binary(key_data */*k*/, const void */*p*/, size_t /*sz*/);
+extern key_data *key_newbinary(unsigned /*e*/,
+                              const void */*p*/, size_t /*sz*/);
 
-/* --- @key_encrypted@ --- *
+/* --- @key_newencrypted@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  @unsigned e@ = other encoding flags
  *             @const void *p@ = pointer to key data
  *             @size_t sz@ = size of the key data
  *
- * Returns:    ---
- *
- * Use:                Sets an encrypted key in a key data block.
+ * Returns:    New key data object.
  */
 
-extern void key_encrypted(key_data */*k*/, const void */*p*/, size_t /*sz*/);
+extern key_data *key_newencrypted(unsigned /*e*/,
+                                 const void */*p*/, size_t /*sz*/);
 
-/* --- @key_mp@ --- *
+/* --- @key_mewmp@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  @unsigned e@ = other encoding flags
  *             @mp *m@ = pointer to the value to set
  *
- * Returns:    ---
- *
- * Use:                Sets a multiprecision integer key in a key block.
+ * Returns:    New key data object.
  */
 
-extern void key_mp(key_data */*k*/, mp */*m*/);
+extern key_data *key_newmp(unsigned /*e*/, mp */*m*/);
 
-/* --- @key_string@ --- *
+/* --- @key_newstring@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  @unsigned e@ = other encoding flags
  *             @const char *p@ = pointer to the value to set
  *
- * Returns:    ---
- *
- * Use:                Sets a plain string in a key block.
+ * Returns:    New key data object.
  */
 
-extern void key_string(key_data */*k*/, const char */*p*/);
+extern key_data *key_newstring(unsigned /*e*/, const char */*p*/);
 
-/* --- @key_ec@ --- *
+/* --- @key_newec@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
- *             @const ec *e@ = pointer to the value to set
+ * Arguments:  @unsigned e@ = other encoding flags
+ *             @const ec *pt@ = pointer to the value to set
  *
- * Returns:    ---
- *
- * Use:                Sets an elliptic curve point in a key block.
+ * Returns:    New key data object.
  */
 
-extern void key_ec(key_data */*k*/, const ec */*e*/);
+extern key_data *key_newec(unsigned /*e*/, const ec */*pt*/);
 
-/* --- @key_structure@ --- *
+/* --- @key_newstruct@ --- *
  *
- * Arguments:  @key_data *k@ = pointer to key data block
+ * Arguments:  ---
  *
- * Returns:    ---
- *
- * Use:                Initializes a structured key type.
+ * Returns:    New key data object.
  */
 
-extern void key_structure(key_data */*k*/);
+extern key_data *key_newstruct(void);
 
 /* --- @key_structfind@ --- *
  *
@@ -294,31 +296,106 @@ extern void key_structure(key_data */*k*/);
 
 extern key_data *key_structfind(key_data */*k*/, const char */*tag*/);
 
-/* --- @key_structcreate@ --- *
+/* --- @key_mksubkeyiter@ --- *
+ *
+ * Arguments:  @key_subkeyiter *i@ = pointer to iterator block
+ *             @key_data *k@ = pointer to key data block
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes a subkey iterator.
+ */
+
+extern void key_mksubkeyiter(key_subkeyiter */*i*/, key_data */*k*/);
+
+/* --- @key_nextsubkey@ --- *
+ *
+ * Arguments:  @key_structiter *i@ = pointer to iterator block
+ *             @const char **tag@ = where to put the tag pointer, or null
+ *             @key_data **kd@ = where to put the key data pointer, or null
+ *
+ * Returns:    Nonzero if there was another item, zero if we hit the
+ *             end-stop.
+ *
+ * Use:                Collects the next subkey of a structured key.
+ */
+
+extern int key_nextsubkey(key_subkeyiter */*i*/,
+                         const char **/*tag*/, key_data **/*kd*/);
+
+/* --- @key_structset@, @key_structsteal@ --- *
  *
  * Arguments:  @key_data *k@ = pointer to key data block
  *             @const char *tag@ = pointer to tag string
+ *             @key_data *kd@ = new key data to store
  *
- * Returns:    Pointer to newly created key data.
+ * Returns:    ---
  *
- * Use:                Creates a new uninitialized subkey.
+ * Use:                Creates a new subkey.  Stealing doesn't affect @kd@'s
+ *             refcount.  If @kd@ is null, the subkey is deleted.
  */
 
-extern key_data *key_structcreate(key_data */*k*/, const char */*tag*/);
+extern void key_structset(key_data */*k*/,
+                         const char */*tag*/, key_data */*kd*/);
+extern void key_structsteal(key_data */*k*/,
+                           const char */*tag*/, key_data */*kd*/);
+
+/* --- @key_split@ --- *
+ *
+ * Arguments:  @key_data **kk@ = address of pointer to key data block
+ *
+ * Returns:    ---
+ *
+ * Use:                Replaces @*kk@ with a pointer to the same key data, but with
+ *             just one reference.
+ */
+
+extern void key_split(key_data **/*kk*/);
 
 /*----- Miscellaneous operations ------------------------------------------*/
 
+/* --- @key_incref@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data
+ *
+ * Returns:    ---
+ *
+ * Use:                Increments the refcount on a key data block.
+ */
+
+#define KEY_INCREF(k) ((k)->ref++)
+extern void key_incref(key_data */*k*/);
+
 /* --- @key_destroy@ --- *
  *
  * Arguments:  @key_data *k@ = pointer to key data to destroy
  *
  * Returns:    ---
  *
- * Use:                Destroys a lump of key data.
+ * Use:                Destroys a block of key data, regardless of reference count.
+ *             Don't use this unless you know what you're doing.
  */
 
 extern void key_destroy(key_data */*k*/);
 
+/* --- @key_drop@ --- *
+ *
+ * Arguments:  @key_data *k@ = pointer to key data to destroy
+ *
+ * Returns:    ---
+ *
+ * Use:                Drops a reference to key data, destroying it if necessary.
+ */
+
+#define KEY_DROP(k) do {                                               \
+  key_data *_k = k;                                                    \
+  _k->ref--;                                                           \
+  if (_k->ref == 0)                                                    \
+    key_destroy(_k);                                                   \
+} while (0)
+  
+extern void key_drop(key_data */*k*/);
+
 /* --- @key_do@ --- *
  *
  * Arguments:  @key_data *k@ = pointer to key data block
@@ -337,34 +414,19 @@ extern int key_do(key_data */*k*/, const key_filter */*kf*/, dstr */*d*/,
                                  dstr */*d*/, void */*p*/),
                  void */*p*/);
 
-/* --- @key_copy@ --- *
- *
- * Arguments:  @key_data *kd@ = pointer to destination data block
- *             @key_data *k@ = pointer to source data block
- *             @const key_filter *kf@ = pointer to filter block
- *
- * Returns:    Nonzero if an item was actually copied.
- *
- * Use:                Copies a chunk of key data from one place to another.
- */
-
-extern int key_copy(key_data */*kd*/, key_data */*k*/,
-                   const key_filter */*kf*/);
-
 /*----- Textual encoding --------------------------------------------------*/
 
 /* --- @key_read@ --- *
  *
  * Arguments:  @const char *p@ = pointer to textual key representation
- *             @key_data *k@ = pointer to output block for key data
  *             @char **pp@ = where to store the end pointer
  *
- * Returns:    Zero if all went well, nonzero if there was a problem.
+ * Returns:    The newly-read key data, or null if it failed.
  *
  * Use:                Parses a textual key description.
  */
 
-extern int key_read(const char */*p*/, key_data */*k*/, char **/*pp*/);
+extern key_data *key_read(const char */*p*/, char **/*pp*/);
 
 /* --- @key_write@ --- *
  *
@@ -377,8 +439,7 @@ extern int key_read(const char */*p*/, key_data */*k*/, char **/*pp*/);
  * Use:                Writes a key in a textual encoding.
  */
 
-extern int key_write(key_data */*k*/, dstr */*d*/,
-                    const key_filter */*kf*/);
+extern int key_write(key_data */*k*/, dstr */*d*/, const key_filter */*kf*/);
 
 /*----- Key binary encoding -----------------------------------------------*/
 
@@ -386,14 +447,13 @@ extern int key_write(key_data */*k*/, dstr */*d*/,
  *
  * Arguments:  @const void *p@ = pointer to buffer to read
  *             @size_t sz@ = size of the buffer
- *             @key_data *k@ = pointer to key data block to write to
  *
- * Returns:    Zero if everything worked, nonzero otherwise.
+ * Returns:    The newly-read key data, or null if it failed.
  *
  * Use:                Decodes a binary representation of a key.
  */
 
-extern int key_decode(const void */*p*/, size_t /*sz*/, key_data */*k*/);
+extern key_data *key_decode(const void */*p*/, size_t /*sz*/);
 
 /* --- @key_encode@ --- *
  *
@@ -414,7 +474,7 @@ extern int key_encode(key_data */*k*/, dstr */*d*/,
 /* --- @key_pack@ --- *
  *
  * Arguments:  @key_packdef *kp@ = pointer to packing structure
- *             @key_data *kd@ = pointer to destination key data
+ *             @key_data **kd@ = where to put the key data pointer
  *             @dstr *d@ = pointer to tag string for the key data
  *
  * Returns:    Error code, or zero.
@@ -422,7 +482,7 @@ extern int key_encode(key_data */*k*/, dstr */*d*/,
  * Use:                Packs a key from a data structure.
  */
 
-extern int key_pack(key_packdef */*kp*/, key_data */*kd*/, dstr */*d*/);
+extern int key_pack(key_packdef */*kp*/, key_data **/*kd*/, dstr */*d*/);
 
 /* --- @key_unpack@ --- *
  *
@@ -453,8 +513,8 @@ extern void key_unpackdone(key_packdef */*kp*/);
 
 /* --- @key_lock@ --- *
  *
- * Arguments:  @key_data *kt@ = destination block
- *             @key_data *k@ = source key data block
+ * Arguments:  @key_data **kt@ = where to store the destination pointer
+ *             @key_data *k@ = source key data block or null to use @*kt@
  *             @const void *e@ = secret to encrypt key with
  *             @size_t esz@ = size of the secret
  *
@@ -463,13 +523,13 @@ extern void key_unpackdone(key_packdef */*kp*/);
  * Use:                Encrypts a key data block using a secret.
  */
 
-extern void key_lock(key_data */*kt*/, key_data */*k*/,
+extern void key_lock(key_data **/*kt*/, key_data */*k*/,
                     const void */*e*/, size_t /*esz*/);
 
 /* --- @key_unlock@ --- *
  *
- * Arguments:  @key_data *kt@ = target block
- *             @key_data *k@ = source key data block
+ * Arguments:  @key_data **kt@ = where to store the destination pointer
+ *             @key_data *k@ = source key data block or null to use @*kt@
  *             @const void *e@ = secret to decrypt the block with
  *             @size_t esz@ = size of the secret
  *
@@ -478,35 +538,36 @@ extern void key_lock(key_data */*kt*/, key_data */*k*/,
  * Use:                Unlocks a key using a secret.
  */
 
-extern int key_unlock(key_data */*kt*/, key_data */*k*/,
+extern int key_unlock(key_data **/*kt*/, key_data */*k*/,
                      const void */*e*/, size_t /*esz*/);
 
 /* --- @key_plock@ --- *
  *
- * Arguments:  @const char *tag@ = tag to use for passphrase
- *             @key_data *k@ = source key data block
- *             @key_data *kt@ = target key data block
+ * Arguments:  @key_data **kt@ = where to store the destination pointer
+ *             @key_data *k@ = source key data block or null to use @*kt@
+ *             @const char *tag@ = tag to use for passphrase
  *
  * Returns:    Zero if successful, a @KERR@ error code on failure.
  *
  * Use:                Locks a key by encrypting it with a passphrase.
  */
 
-extern int key_plock(const char */*tag*/, key_data */*k*/, key_data */*kt*/);
+extern int key_plock(key_data **/*kt*/, key_data */*k*/,
+                    const char */*tag*/);
 
 /* --- @key_punlock@ --- *
  *
- * Arguments:  @const char *tag@ = tag to use for passphrase
- *             @key_data *k@ = source key data block
- *             @key_data *kt@ = target key data block
+ * Arguments:  @key_data **kt@ = where to store the destination pointer
+ *             @key_data *k@ = source key data block or null to use @*kt@
+ *             @const char *tag@ = tag to use for passphrase
  *
  * Returns:    Zero if successful, a @KERR@ error code on failure.
  *
  * Use:                Unlocks a passphrase-locked key.
  */
 
-extern int key_punlock(const char */*tag*/,
-                      key_data */*k*/, key_data */*kt*/);
+extern int key_punlock(key_data **/*kt*/, key_data */*k*/,
+                      const char */*tag*/);
 
 /*----- That's all, folks -------------------------------------------------*/
 
index d80382f..e28b9b2 100644 (file)
@@ -80,8 +80,9 @@ key_packdef *key_fetchinit(const key_fetchdef *kf,
 
   /* --- Fill in the top part --- */
 
-  kp->kp.kd.e = KENC_STRUCT;
+  kp->kp.e = KENC_STRUCT;
   kp->kp.p = &kp[1];
+  kp->kp.kd = 0;
   kpd = &kp->kp;
 
   /* --- Initialize for the main loop --- */
@@ -107,7 +108,8 @@ key_packdef *key_fetchinit(const key_fetchdef *kf,
 
     while (kf->name) {
       kp->name = kf->name;
-      kp->kp.kd.e = kf->e;
+      kp->kp.e = kf->e;
+      kp->kp.kd = 0;
       if ((kf->e & KF_ENCMASK) != KENC_STRUCT)
        kp->kp.p = cp + kf->off;
       else {
@@ -153,7 +155,7 @@ int key_fetch(key_packdef *kp, key *k)
   int e;
 
   key_fulltag(k, &d);
-  e = key_unpack(kp, &k->k, &d);
+  e = key_unpack(kp, k->k, &d);
   dstr_destroy(&d);
   return (e);
 }
@@ -173,13 +175,13 @@ int key_fetch(key_packdef *kp, key *k)
 int key_fetchbyname(key_packdef *kp, key_file *kf, const char *tag)
 {
   dstr d = DSTR_INIT;
-  key_data *kd;
+  key_data **kd;
   int e;
 
   if (key_qtag(kf, tag, &d, 0, &kd))
     e = KERR_NOTFOUND;
   else
-    e = key_unpack(kp, kd, &d);
+    e = key_unpack(kp, *kd, &d);
   dstr_destroy(&d);
   return (e);
 }
@@ -196,8 +198,8 @@ int key_fetchbyname(key_packdef *kp, key_file *kf, const char *tag)
 
 void key_fetchdone(key_packdef *kp)
 {
-  key_packstruct *kps = (key_packstruct *)(((char *)kp) -
-                                          offsetof(key_packstruct, kp));
+  key_packstruct *kps =
+    (key_packstruct *)(((char *)kp) - offsetof(key_packstruct, kp));
   key_unpackdone(kp);
   if (kps->name)
     xfree(kps);
index 6e422b1..dc9efc0 100644 (file)
@@ -197,6 +197,9 @@ int key_save(key_file *f)
 
   unlink(n_new.buf);
   unlink(n_older.buf);
+  dstr_destroy(&n_new);
+  dstr_destroy(&n_old);
+  dstr_destroy(&n_older);
   return (KWRITE_OK);
 
   /* --- Failure while writing the new key file --- *
@@ -255,15 +258,15 @@ fail_shift:
   dstr_destroy(&n_older);
   return (rc);
   
-/* --- Failure during write of new data --- *
- *
- * Clean up the new file and return.  These errors can never cause
- * breakage.
- */
+  /* --- Failure during write of new data --- *
  *
  * Clean up the new file and return.  These errors can never cause
  * breakage.
  */
 
 fail_write:
   unlink(n_new.buf);
-  fail_open:
+fail_open:
   dstr_destroy(&n_new);
   return (rc);
 }
index 7ed0c2c..9d9b6ee 100644 (file)
--- a/key-io.c
+++ b/key-io.c
@@ -221,7 +221,7 @@ int key_merge(key_file *f, const char *file, FILE *fp,
 
     /* --- Extract the key data into the block --- */
 
-    if (key_read(vf[1], &k->k, 0)) {
+    if ((k->k = key_read(vf[1], 0)) == 0) {
       if (rep)
        rep(file, line, "bad key data", arg);
       goto skip_1;
@@ -239,12 +239,12 @@ int key_merge(key_file *f, const char *file, FILE *fp,
       char *qq;
 
       if (!q) {
-       if (k->k.e != KENC_BINARY) {
+       if (k->k->e != KENC_BINARY) {
          if (rep)
            rep(file, line, "new-style key encoding but no keyid", arg);
          goto skip_2;
        }
-       k->id = crc32(0, k->k.u.k.k, k->k.u.k.sz);
+       k->id = crc32(0, k->k->u.k.k, k->k->u.k.sz);
        k->type = xstrdup(vf[0]);
        k->tag = 0;
       } else {
@@ -313,7 +313,7 @@ int key_merge(key_file *f, const char *file, FILE *fp,
       xfree(k->tag);
     xfree(k->type);
   skip_2:
-    key_destroy(&k->k);
+    key_drop(k->k);
   skip_1:
     DESTROY(k);
   skip_0:;
@@ -347,14 +347,14 @@ int key_extract(key_file *f, key *k, FILE *fp, const key_filter *kf)
 
   /* --- Skip the key if it's deleted or unselected--- */
 
-  if (KEY_EXPIRED(t, k->del) || !key_match(&k->k, kf))
+  if (KEY_EXPIRED(t, k->del) || !key_match(k->k, kf))
     return (0);
 
   /* --- Encode the key and write the easy stuff --- */
 
   key_fulltag(k, &d);
   DPUTC(&d, ' ');
-  key_write(&k->k, &d, kf);
+  key_write(k->k, &d, kf);
   DPUTC(&d, ' ');
   dstr_write(&d, fp);
   DRESET(&d);
@@ -469,7 +469,7 @@ void key_discard(key_file *f)
     key_attr *a;
     key *k = (key *)b;
 
-    key_destroy(&k->k);
+    if (k->k) key_drop(k->k);
     xfree(k->type);
     xfree(k->tag);
     if (k->c)
@@ -514,10 +514,9 @@ int key_close(key_file *f)
  *             @uint32 id@ = keyid to set
  *             @const char *type@ = the type of this key
  *             @time_t exp@ = when the key expires
- *             @int *err@ = where to store the error condition
+ *             @key *kk@ = where to put the key pointer
  *
- * Returns:    Key block containing new data, or null if it couldn't be
- *             done.
+ * Returns:    Error code (one of the @KERR@ constants).
  *
  * Use:                Attaches a new key to a key file.  You must have a writable
  *             key file for this to work.
@@ -532,11 +531,9 @@ int key_close(key_file *f)
  *             key'.  Be careful with `forever' keys.  If I were you, I'd
  *             use a more sophisticated key management system than this for
  *             them.
- *
- *             You have to set the actual key yourself.
  */
 
-key *key_new(key_file *f, uint32 id, const char *type, time_t exp, int *err)
+int key_new(key_file *f, uint32 id, const char *type, time_t exp, key **kk)
 {
   key *k = 0;
   time_t t = time(0);
@@ -554,21 +551,21 @@ key *key_new(key_file *f, uint32 id, const char *type, time_t exp, int *err)
     k = CREATE(key);
     k->id = id;
     k->tag = 0;
-    k->type = xstrdup(type);
     k->exp = k->del = exp;
     k->c = 0;
-    k->k.e = 0;
+    k->type = type; /* temporarily */
     sym_create(&k->a);
-    if ((e = insert(f, k)) == 0)
-      f->f |= KF_MODIFIED;
-    else {
-      xfree(k->type);
+    if ((e = insert(f, k)) != 0)
       DESTROY(k);
-      k = 0;
+    else {
+      k->k = key_newstring(KCAT_SHARE, "<unset>");
+      k->type = xstrdup(type);
+      *kk = k;
+      f->f |= KF_MODIFIED;
     }
   }
-  *err = e;
-  return (k);
+  
+  return (e);
 }
 
 /*----- That's all, folks -------------------------------------------------*/
index 54fdc89..6e3b441 100644 (file)
@@ -177,7 +177,7 @@ key *key_bytag(key_file *f, const char *tag)
  *             @const char *tag@ = pointer to tag string
  *             @dstr *d@ = pointer to string for full tag name
  *             @key **k@ = where to store the key pointer
- *             @key_data **kd@ = where to store the key data pointer
+ *             @key_data ***kd@ = where to store the key data pointer
  *
  * Returns:    Zero if OK, nonzero if it failed.
  *
@@ -185,15 +185,15 @@ key *key_bytag(key_file *f, const char *tag)
  *             qualified by the names of subkeys, separated by dots.  Hence,
  *             a qualified tag is ID|TAG[.TAG...].  The various result
  *             pointers can be null to indicate that the result isn't
- *             interesting. 
+ *             interesting.
  */
 
-int key_qtag(key_file *f, const char *tag, dstr *d, key **k, key_data **kd)
+int key_qtag(key_file *f, const char *tag, dstr *d, key **k, key_data ***kd)
 {
   dstr dd = DSTR_INIT;
   const char *q;
   key *kk;
-  key_data *kkd;
+  key_data **kkd;
 
   /* --- Find the end of the base tag --- */
 
@@ -222,36 +222,42 @@ int key_qtag(key_file *f, const char *tag, dstr *d, key **k, key_data **kd)
 
   /* --- Now dig through the rest of the tag --- */
 
-  while (q && *q) {
-
-    /* --- Stick on the next bit of the fullqtag --- */
-
-    DRESET(&dd);
-    while (*q && *q != '.') {
-      DPUTC(&dd, *q);
-      q++;
+  if (q) {
+    while (*q) {
+      key_struct *ks;
+
+      /* --- Stick on the next bit of the fullqtag --- */
+
+      DRESET(&dd);
+      while (*q && *q != '.') {
+       DPUTC(&dd, *q);
+       q++;
+      }
+      DPUTZ(&dd);
+      if (d) {
+       DPUTC(d, '.');
+       DPUTD(d, &dd);
+      }
+
+      /* --- Look up the subkey --- */
+
+      if ((*kkd)->e != KENC_STRUCT) {
+       kkd = 0;
+       break;
+      }
+      if ((ks = sym_find(&(*kkd)->u.s, dd.buf, -1, 0, 0)) == 0) {
+       kkd = 0;
+       break;
+      }
+      kkd = &ks->k;
     }
-    DPUTZ(&dd);
-    if (d) {
-      DPUTC(d, '.');
-      DPUTD(d, &dd);
-    }
-
-    /* --- Look up the subkey --- */
-
-    if (kkd->e != KENC_STRUCT) {
-      kkd = 0;
-      break;
-    }
-    if ((kkd = key_structfind(kkd, dd.buf)) == 0)
-      break;
   }
 
   /* --- Return the results --- */
 
+  dstr_destroy(&dd);
   if (!kkd)
     return (-1);
-  dstr_destroy(&dd);
   if (kd)
     *kd = kkd;
   return (0);
@@ -374,7 +380,7 @@ int key_fingerprint(key *k, ghash *h, const key_filter *kf)
   size_t n, i;
   sym_iter ai;
 
-  if (!key_encode(&k->k, &d, kf))
+  if (!key_encode(k->k, &d, kf))
     goto done;
   rc = 1;
   GH_HASHSTR(h, "catacomb-key-fingerprint:");
index cc0f20a..0303dbc 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: key-pack.c,v 1.3 2004/04/08 01:36:15 mdw Exp $
+ * $Id$
  *
  * Packing and unpacking key data
  *
@@ -39,7 +39,7 @@
 /* --- @key_pack@ --- *
  *
  * Arguments:  @key_packdef *kp@ = pointer to packing structure
- *             @key_data *kd@ = pointer to destination key data
+ *             @key_data **kd@ = where to put the key data pointer
  *             @dstr *d@ = pointer to tag string for the key data
  *
  * Returns:    Error code, or zero.
  * Use:                Packs a key from a data structure.
  */
 
-int key_pack(key_packdef *kp, key_data *kd, dstr *d)
+int key_pack(key_packdef *kp, key_data **kd, dstr *d)
 {
-  switch (kp->kd.e & KF_ENCMASK) {
+  switch (kp->e & KF_ENCMASK) {
 
     /* --- Binary and integer keys are easy --- */
 
-    case KENC_BINARY:
-      kd->u.k = *(key_bin *)kp->p;
+    case KENC_BINARY: {
+      key_bin *b = kp->p;
+      *kd = key_newbinary(kp->e, b->k, b->sz);
       return (0);
+    }
     case KENC_MP:
-      kd->u.m = *(mp **)kp->p;
+      *kd = key_newmp(kp->e, *(mp **)kp->p);
       return (0);
     case KENC_STRING:
-      kd->u.p = *(char **)kp->p;
+      *kd = key_newstring(kp->e, *(char **)kp->p);
       return (0);
     case KENC_EC:
-      kd->u.e = *(ec *)kp->p;
+      *kd = key_newec(kp->e, (ec *)kp->p);
       return (0);
 
     /* --- Encrypted keys are a little tricky --- *
@@ -72,12 +74,11 @@ int key_pack(key_packdef *kp, key_data *kd, dstr *d)
      */
 
     case KENC_ENCRYPT: {
-      key_data kkd;
+      key_data *kkd;
       int err = key_pack(kp->p, &kkd, d);
       if (!err) {
-       if (key_plock(d->buf, &kkd, kd))
-         err = KERR_BADPASS;
-       key_destroy(&kkd);
+       err = key_plock(kd, kkd, d->buf);
+       key_drop(kkd);
       }
       return (err);
     }
@@ -89,25 +90,25 @@ int key_pack(key_packdef *kp, key_data *kd, dstr *d)
       key_packstruct *p;
       size_t l = d->len;
 
-      key_structure(kd);
+      *kd = key_newstruct();
       DPUTC(d, '.');
       for (p = kp->p; p->name; p++) {
        key_data *kkd;
        d->len = l + 1;
        DPUTS(d, p->name);
-       kkd = key_structcreate(kd, p->name);
-       if ((err = key_pack(&p->kp, kkd, d)) != 0) {
-         key_destroy(kd);
+       if ((err = key_pack(&p->kp, &kkd, d)) != 0) {
+         key_drop(*kd);
          return (err);
        }
+       key_structsteal(*kd, p->name, kkd);
       }
       d->len = l;
       d->buf[l] = 0;
       return (0);
     }
+    default:
+      abort();
   }
-
-  return (KERR_BADTYPE);
 }
 
 /* --- @key_unpack@ --- *
@@ -123,18 +124,15 @@ int key_pack(key_packdef *kp, key_data *kd, dstr *d)
 
 int key_unpack(key_packdef *kp, key_data *kd, dstr *d)
 {
-  unsigned e = kp->kd.e & KF_ENCMASK;
+  unsigned e = kp->e & KF_ENCMASK;
   int err;
 
   /* --- Decrypt the encrypted key --- */
 
-  while ((kd->e & KF_ENCMASK) == KENC_ENCRYPT) {
-    if (key_punlock(d->buf, kd, &kp->kd)) {
-      err = KERR_BADPASS;
+  if ((kd->e & KF_ENCMASK) == KENC_ENCRYPT) {
+    if ((err = key_punlock(&kp->kd, kd, d->buf)) != 0)
       goto fail;
-    }
-    kd = &kp->kd;
-    kd->e |= KF_TEMP;
+    kd = kp->kd;
   }
 
   /* --- Ensure that the key has the right type --- */
@@ -186,7 +184,7 @@ int key_unpack(key_packdef *kp, key_data *kd, dstr *d)
        /* --- Find and unpack the subkey --- */
 
        if ((kkd = key_structfind(kd, p->name)) == 0) {
-         if (!(p->kp.kd.e & KF_OPT)) {
+         if (!(p->kp.e & KF_OPT)) {
            err = KERR_NOTFOUND;
            goto tidy;
          }
@@ -209,6 +207,9 @@ int key_unpack(key_packdef *kp, key_data *kd, dstr *d)
        key_unpackdone(&q->kp);
       goto fail;
     }
+
+    default:
+      abort();
   }
 
   return (0);
@@ -216,8 +217,10 @@ int key_unpack(key_packdef *kp, key_data *kd, dstr *d)
   /* --- Something went wrong --- */
 
 fail:
-  if (kd == &kp->kd)
-    key_destroy(kd);
+  if (kp->kd) {
+    key_drop(kp->kd);
+    kp->kd = 0;
+  }
   return (err);
 }
 
@@ -233,9 +236,11 @@ fail:
 
 void key_unpackdone(key_packdef *kp)
 {
-  if (kp->kd.e & KF_TEMP)
-    key_destroy(&kp->kd);
-  if ((kp->kd.e & KF_ENCMASK) == KENC_STRUCT) {
+  if (kp->kd) {
+    key_drop(kp->kd);
+    kp->kd = 0;
+  }
+  if ((kp->e & KF_ENCMASK) == KENC_STRUCT) {
     key_packstruct *p;
     for (p = kp->p; p->name; p++)
       key_unpackdone(&p->kp);
index 1b0997a..4fd74b1 100644 (file)
@@ -56,8 +56,8 @@
 
 /* --- @key_lock@ --- *
  *
- * Arguments:  @key_data *kt@ = destination block
- *             @key_data *k@ = source key data block
+ * Arguments:  @key_data **kt@ = where to store the destination pointer
+ *             @key_data *k@ = source key data block or null to use @*kt@
  *             @const void *e@ = secret to encrypt key with
  *             @size_t esz@ = size of the secret
  *
@@ -66,7 +66,7 @@
  * Use:                Encrypts a key data block using a secret.
  */
 
-void key_lock(key_data *kt, key_data *k, const void *e, size_t esz)
+void key_lock(key_data **kt, key_data *k, const void *e, size_t esz)
 {
   dstr d = DSTR_INIT;
   octet b[RMD160_HASHSZ * 2];
@@ -79,6 +79,7 @@ void key_lock(key_data *kt, key_data *k, const void *e, size_t esz)
 
   /* --- Sanity check --- */
 
+  if (k) key_incref(k); else k = *kt;
   assert(((void)"Key data is already encrypted",
          (k->e & KF_ENCMASK) != KENC_ENCRYPT));
 
@@ -88,8 +89,6 @@ void key_lock(key_data *kt, key_data *k, const void *e, size_t esz)
   rand_get(RAND_GLOBAL, d.buf, RMD160_HASHSZ);
   d.len += RMD160_HASHSZ * 2;
   key_encode(k, &d, 0);
-  if (k == kt)
-    key_destroy(k);
   m = (octet *)d.buf + RMD160_HASHSZ * 2;
   msz = d.len - RMD160_HASHSZ * 2;
 
@@ -119,14 +118,15 @@ void key_lock(key_data *kt, key_data *k, const void *e, size_t esz)
   /* --- Done --- */
 
   BURN(b);
-  key_encrypted(kt, d.buf, d.len);
+  *kt = key_newencrypted(0, d.buf, d.len);
+  key_drop(k);
   dstr_destroy(&d);
 }
 
 /* --- @key_unlock@ --- *
  *
- * Arguments:  @key_data *kt@ = target block
- *             @key_data *k@ = source key data block
+ * Arguments:  @key_data **kt@ = where to store the destination pointer
+ *             @key_data *k@ = source key data block or null to use @*kt@
  *             @const void *e@ = secret to decrypt the block with
  *             @size_t esz@ = size of the secret
  *
@@ -135,11 +135,13 @@ void key_lock(key_data *kt, key_data *k, const void *e, size_t esz)
  * Use:                Unlocks a key using a secret.
  */
 
-int key_unlock(key_data *kt, key_data *k, const void *e, size_t esz)
+int key_unlock(key_data **kt, key_data *k, const void *e, size_t esz)
 {
   octet b[RMD160_HASHSZ * 2];
   octet *p = 0;
   int rc;
+  int drop = 0;
+  key_data *kd;
   rmd160_mgfctx r;
   blowfish_cbcctx c;
   rmd160_mackey mk;
@@ -148,6 +150,7 @@ int key_unlock(key_data *kt, key_data *k, const void *e, size_t esz)
 
   /* --- Sanity check --- */
 
+  if (!k) { k = *kt; drop = 1; }
   assert(((void)"Key data isn't encrypted",
          (k->e & KF_ENCMASK) == KENC_ENCRYPT));
 
@@ -191,16 +194,16 @@ int key_unlock(key_data *kt, key_data *k, const void *e, size_t esz)
 
   /* --- Decode the key data into the destination buffer --- */
 
-  if (k == kt)
-    key_destroy(k);
-  if (key_decode(p, sz, kt)) {
+  if ((kd = key_decode(p, sz)) == 0) {
     rc = KERR_MALFORMED;
     goto fail;
   }
+  *kt = kd;
 
   /* --- Done --- */
 
   xfree(p);
+  if (drop) key_drop(k);
   return (0);
 
   /* --- Tidy up if things went wrong --- */
@@ -213,16 +216,16 @@ fail:
 
 /* --- @key_plock@ --- *
  *
- * Arguments:  @const char *tag@ = tag to use for passphrase
- *             @key_data *k@ = source key data block
- *             @key_data *kt@ = target key data block
+ * Arguments:  @key_data **kt@ = where to store the destination pointer
+ *             @key_data *k@ = source key data block or null to use @*kt@
+ *             @const char *tag@ = tag to use for passphrase
  *
  * Returns:    Zero if successful, a @KERR@ error code on failure.
  *
  * Use:                Locks a key by encrypting it with a passphrase.
  */
 
-int key_plock(const char *tag, key_data *k, key_data *kt)
+int key_plock(key_data **kt, key_data *k, const char *tag)
 {
   char buf[256];
 
@@ -235,16 +238,16 @@ int key_plock(const char *tag, key_data *k, key_data *kt)
 
 /* --- @key_punlock@ --- *
  *
- * Arguments:  @const char *tag@ = tag to use for passphrase
- *             @key_data *k@ = source key data block
- *             @key_data *kt@ = target key data block
+ * Arguments:  @key_data **kt@ = where to store the destination pointer
+ *             @key_data *k@ = source key data block or null to use @*kt@
+ *             @const char *tag@ = tag to use for passphrase
  *
  * Returns:    Zero if it worked, a @KERR_@ error code on failure.
  *
  * Use:                Unlocks a passphrase-locked key.
  */
 
-int key_punlock(const char *tag, key_data *k, key_data *kt)
+int key_punlock(key_data **kt, key_data *k, const char *tag)
 {
   char buf[256];
   int rc;
@@ -253,7 +256,7 @@ int key_punlock(const char *tag, key_data *k, key_data *kt)
     return (KERR_IO);
   rc = key_unlock(kt, k, buf, strlen(buf));
   BURN(buf);
-  if (rc == KERR_BADPASS || k == kt)
+  if (rc == KERR_BADPASS || !k)
     passphrase_cancel(tag);
   return (rc);
 }
index dcfe354..b13f571 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: key-text.c,v 1.6 2004/04/08 01:36:15 mdw Exp $
+ * $Id$
  *
  * Key textual encoding
  *
 /* --- @key_read@ --- *
  *
  * Arguments:  @const char *p@ = pointer to textual key representation
- *             @key_data *k@ = pointer to output block for key data
  *             @char **pp@ = where to store the end pointer
  *
- * Returns:    Zero if all went well, nonzero if there was a problem.
+ * Returns:    The newly-read key data, or null if it failed.
  *
  * Use:                Parses a textual key description.
  */
 
-int key_read(const char *p, key_data *k, char **pp)
+key_data *key_read(const char *p, char **pp)
 {
   unsigned e;
+  key_data *kd;
 
   /* --- Read the encoding type --- *
    *
@@ -72,13 +72,12 @@ int key_read(const char *p, key_data *k, char **pp)
   else {
     char *q;
     if (key_readflags(p, &q, &e, 0))
-      return (-1);
+      return (0);
     p = q + 1;
   }
 
   /* --- Now scan the data based on the encoding type --- */
 
-  k->e = e;
   switch (e & KF_ENCMASK) {
 
     /* --- Binary encoding --- *
@@ -97,9 +96,7 @@ int key_read(const char *p, key_data *k, char **pp)
       base64_init(&b);
       base64_decode(&b, p, sz, &d);
       base64_decode(&b, 0, 0, &d);
-      k->u.k.k = sub_alloc(d.len);
-      k->u.k.sz = d.len;
-      memcpy(k->u.k.k, d.buf, d.len);
+      kd = key_newbinary(e, d.buf, d.len);
       dstr_destroy(&d);
       p += sz;
     } break;
@@ -111,10 +108,11 @@ int key_read(const char *p, key_data *k, char **pp)
 
     case KENC_MP: {
       char *q;
-      mp *m = mp_readstring(k->e & KF_BURN ? MP_NEWSEC : MP_NEW, p, &q, 0);
+      mp *m = mp_readstring(e & KF_BURN ? MP_NEWSEC : MP_NEW, p, &q, 0);
       if (!m)
-       return (-1);
-      k->u.m = m;
+       return (0);
+      kd = key_newmp(e, m);
+      MP_DROP(m);
       p = q;
     } break;
 
@@ -143,7 +141,7 @@ int key_read(const char *p, key_data *k, char **pp)
        p++;
       }
       DPUTZ(&d);
-      k->u.p = xstrdup(d.buf);
+      kd = key_newstring(e, d.buf);
       dstr_destroy(&d);
     } break;
 
@@ -154,12 +152,14 @@ int key_read(const char *p, key_data *k, char **pp)
      */
 
     case KENC_EC: {
+      ec pt = EC_INIT;
       qd_parse qd;
       qd.p = p;
       qd.e = 0;
-      EC_CREATE(&k->u.e);
-      if (!ec_ptparse(&qd, &k->u.e))
-       return (-1);
+      if (!ec_ptparse(&qd, &pt))
+       return (0);
+      kd = key_newec(e, &pt);
+      EC_DESTROY(&pt);
       p = qd.p;
     } break;
 
@@ -175,21 +175,20 @@ int key_read(const char *p, key_data *k, char **pp)
 
     case KENC_STRUCT: {
       dstr d = DSTR_INIT;
+      key_data *nkd;
       char *q;
 
       /* --- Read the opening bracket --- */
 
-      k->e &= KF_ENCMASK;
+      kd = key_newstruct();
       if (*p != '[')
-       return (-1);
+       return (0);
       p++;
-      sym_create(&k->u.s);
 
       /* --- Read named key subparts --- */
 
       for (;;) {
        size_t sz;
-       key_struct *ks;
 
        /* --- Stop if there's a close-bracket --- *
         *
@@ -212,24 +211,11 @@ int key_read(const char *p, key_data *k, char **pp)
        DPUTM(&d, p, sz);
        DPUTZ(&d);
 
-       /* --- Add an appropriate block to the key table --- *
-        *
-        * Simply destroy old data if there's already a match.
-        */
-
-       {
-         unsigned f;
-         ks = sym_find(&k->u.s, d.buf, d.len, sizeof(*ks), &f);
-         if (f)
-           key_destroy(&ks->k);
-       }
-
        /* --- Read the key data for the subkey --- */
 
-       if (key_read(q + 1, &ks->k, &q)) {
-         sym_remove(&k->u.s, ks);
+       if ((nkd = key_read(q + 1, &q)) == 0)
          goto fail;
-       }
+       key_structsteal(kd, d.buf, nkd);
        p = q;
 
        /* --- Read the comma or close-bracket --- */
@@ -252,21 +238,21 @@ int key_read(const char *p, key_data *k, char **pp)
 
     fail:
       dstr_destroy(&d);
-      key_destroy(k);
-      return (-1);
+      return (0);
     } break;
 
     /* --- Anything else is unknown --- */
 
     default:
-      return (-1);
+      return (0);
   }
 
   /* --- Return the end pointer --- */
 
+  kd->e = e;
   if (pp)
     *pp = (char *)p;
-  return (0);
+  return (kd);
 }
 
 /* --- @key_write@ --- *
@@ -327,19 +313,19 @@ int key_write(key_data *k, dstr *d, const key_filter *kf)
       rc = 1;
       break;
     case KENC_STRUCT: {
-      sym_iter i;
-      key_struct *ks;
+      key_subkeyiter i;
+      const char *tag;
       char del = 0;
       size_t n = d->len;
 
       DPUTS(d, "struct:[");
-      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
+      for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &k); ) {
        size_t o = d->len;
        if (del)
          DPUTC(d, del);
-       DPUTS(d, SYM_NAME(ks));
+       DPUTS(d, tag);
        DPUTC(d, '=');
-       if (!key_write(&ks->k, d, kf))
+       if (!key_write(k, d, kf))
          d->len = o;
        else {
          del = ',';
diff --git a/key.h b/key.h
index ff3f81d..1986e8c 100644 (file)
--- a/key.h
+++ b/key.h
@@ -97,7 +97,7 @@ typedef struct key {
 
   /* --- The key data itself --- */
 
-  key_data k;                          /* The actual key data */
+  key_data *k;                         /* The actual key data */
 
   /* --- Other attributes and commentary --- */
 
@@ -302,10 +302,9 @@ extern int key_lockfile(key_file */*f*/, const char */*file*/,
  *             @uint32 id@ = keyid to set
  *             @const char *type@ = the type of this key
  *             @time_t exp@ = when the key expires
- *             @int *err@ = where to store the error condition
+ *             @key *kk@ = where to put the key pointer
  *
- * Returns:    Key block containing new data, or null if it couldn't be
- *             done.
+ * Returns:    Error code (one of the @KERR@ constants).
  *
  * Use:                Attaches a new key to a key file.  You must have a writable
  *             key file for this to work.
@@ -324,8 +323,8 @@ extern int key_lockfile(key_file */*f*/, const char */*file*/,
  *             You have to set the actual key yourself.
  */
 
-extern key *key_new(key_file */*f*/, uint32 /*id*/, const char */*type*/,
-                   time_t /*exp*/, int */*err*/);
+extern int key_new(key_file */*f*/, uint32 /*id*/, const char */*type*/,
+                  time_t /*exp*/, key **/*kk*/);
 
 /* --- @key_delete@ --- *
  *
@@ -451,6 +450,19 @@ extern int key_setcomment(key_file */*f*/, key */*k*/, const char */*c*/);
 
 extern int key_settag(key_file */*f*/, key */*k*/, const char */*tag*/);
 
+/* --- @key_setkeydata@ --- *
+ *
+ * Arguments:  @key_file *kf@ = pointer to key file
+ *             @key *k@ = pointer to key
+ *             @key_data *kd@ = new key data
+ *
+ * Returns:    Zero on success, or a @KERR_@ error code on failure.
+ *
+ * Use:                Sets the key data for a key.
+ */
+
+extern int key_setkeydata(key_file */*kf*/, key */*k*/, key_data */*kd*/);
+
 /* --- @key_fulltag@ --- *
  *
  * Arguments:  @key *k@ = pointer to key
@@ -471,7 +483,7 @@ extern void key_fulltag(key */*k*/, dstr */*d*/);
  *             @const char *tag@ = pointer to tag string
  *             @dstr *d@ = pointer to string for full tag name
  *             @key **k@ = where to store the key pointer
- *             @key_data **kd@ = where to store the key data pointer
+ *             @key_data ***kd@ = where to store the key data pointer
  *
  * Returns:    Zero if OK, nonzero if it failed.
  *
@@ -483,7 +495,7 @@ extern void key_fulltag(key */*k*/, dstr */*d*/);
  */
 
 extern int key_qtag(key_file */*f*/, const char */*tag*/,
-                   dstr */*d*/, key **/*k*/, key_data **/*kd*/);
+                   dstr */*d*/, key **/*k*/, key_data ***/*kd*/);
 
 /* --- @key_getattr@ --- *
  *
index 3be95b3..1d4bbca 100644 (file)
--- a/keyutil.c
+++ b/keyutil.c
@@ -201,7 +201,7 @@ typedef struct keyopts {
 /* --- @dolock@ --- *
  *
  * Arguments:  @keyopts *k@ = key generation options
- *             @key_data *kd@ = pointer to key data to lock
+ *             @key_data **kd@ = pointer to key data to lock
  *             @const char *t@ = tag suffix or null
  *
  * Returns:    ---
@@ -209,35 +209,16 @@ typedef struct keyopts {
  * Use:                Does passphrase locking on new keys.
  */
 
-static void dolock(keyopts *k, key_data *kd, const char *t)
+static void dolock(keyopts *k, key_data **kd, const char *t)
 {
   if (!(k->f & f_lock))
     return;
   if (t)
     dstr_putf(&k->tag, ".%s", t);
-  if (key_plock(k->tag.buf, kd, kd))
+  if (key_plock(kd, 0, k->tag.buf))
     die(EXIT_FAILURE, "couldn't lock key");
 }
 
-/* --- @mpkey@ --- *
- *
- * Arguments:  @key_data *kd@ = pointer to parent key block
- *             @const char *tag@ = pointer to tag string
- *             @mp *m@ = integer to store
- *             @unsigned f@ = flags to set
- *
- * Returns:    ---
- *
- * Use:                Sets a multiprecision integer subkey.
- */
-
-static void mpkey(key_data *kd, const char *tag, mp *m, unsigned f)
-{
-  key_data *kkd = key_structcreate(kd, tag);
-  key_mp(kkd, m);
-  kkd->e |= f;
-}
-
 /* --- @copyparam@ --- *
  *
  * Arguments:  @keyopts *k@ = pointer to key options
@@ -263,7 +244,7 @@ static int copyparam(keyopts *k, const char **pp)
   /* --- Run through the checklist --- */
 
   while (*pp) {
-    key_data *kd = key_structfind(&k->p->k, *pp);
+    key_data *kd = key_structfind(k->p->k, *pp);
     if (!kd)
       die(EXIT_FAILURE, "bad parameter key: parameter `%s' not found", *pp);
     if ((kd->e & KF_CATMASK) != KCAT_SHARE)
@@ -275,8 +256,7 @@ static int copyparam(keyopts *k, const char **pp)
 
   kf.f = KCAT_SHARE;
   kf.m = KF_CATMASK;
-  if (!key_copy(&k->k->k, &k->p->k, &kf))
-    die(EXIT_FAILURE, "unexpected failure while copying parameters");
+  key_setkeydata(k->kf, k->k, k->p->k);
 
   /* --- Copy over attributes --- */
 
@@ -331,7 +311,8 @@ static void keyrand(key_file *kf, const char *id)
     k = key_bytype(kf, "catacomb-rand");
 
   if (k) {
-    key_data *kd = &k->k, kkd;
+    key_data *kd = k->k, *kkd;
+    key_incref(kd);
 
   again:
     switch (kd->e & KF_ENCMASK) {
@@ -340,10 +321,11 @@ static void keyrand(key_file *kf, const char *id)
       case KENC_ENCRYPT: {
        dstr d = DSTR_INIT;
        key_fulltag(k, &d);
-       if (key_punlock(d.buf, kd, &kkd))
+       if (key_punlock(&kkd, kd, d.buf))
          die(EXIT_FAILURE, "error unlocking key `%s'", d.buf);
        dstr_destroy(&d);
-       kd = &kkd;
+       key_drop(kd);
+       kd = kkd;
       } goto again;
       default: {
        dstr d = DSTR_INIT;
@@ -355,8 +337,7 @@ static void keyrand(key_file *kf, const char *id)
     /* --- Key the generator --- */
 
     rand_key(RAND_GLOBAL, kd->u.k.k, kd->u.k.sz);
-    if (kd == &kkd)
-      key_destroy(&kkd);
+    key_drop(kd);
   }
 }
 
@@ -366,6 +347,7 @@ static void alg_binary(keyopts *k)
 {
   unsigned sz;
   unsigned m;
+  key_data *kd;
   octet *p;
 
   if (!k->bits)
@@ -378,17 +360,19 @@ static void alg_binary(keyopts *k)
   m = (1 << (((k->bits - 1) & 7) + 1)) - 1;
   k->r->ops->fill(k->r, p, sz);
   *p &= m;
-  key_binary(&k->k->k, p, sz);
-  k->k->k.e |= KCAT_SYMM | KF_BURN;
+  kd = key_newbinary(KCAT_SYMM | KF_BURN, p, sz);
   memset(p, 0, sz);
+  dolock(k, &kd, 0);
+  key_setkeydata(k->kf, k->k, kd);
+  key_drop(kd);
   sub_free(p, sz);
-  dolock(k, &k->k->k, 0);
 }
 
 static void alg_des(keyopts *k)
 {
   unsigned sz;
   octet *p;
+  key_data *kd;
   int i;
 
   if (!k->bits)
@@ -408,17 +392,18 @@ static void alg_des(keyopts *k)
     x = x ^ (x >> 1);
     p[i] = (p[i] & 0xfe) | (x & 0x01);
   }
-  key_binary(&k->k->k, p, sz);
-  k->k->k.e |= KCAT_SYMM | KF_BURN;
+  kd = key_newbinary(KCAT_SYMM | KF_BURN, p, sz);
   memset(p, 0, sz);
+  dolock(k, &kd, 0);
+  key_setkeydata(k->kf, k->k, kd);
+  key_drop(kd);
   sub_free(p, sz);
-  dolock(k, &k->k->k, 0);
 }
 
 static void alg_rsa(keyopts *k)
 {
   rsa_priv rp;
-  key_data *kd;
+  key_data *kd, *kkd;
 
   /* --- Sanity checking --- */
 
@@ -455,21 +440,21 @@ static void alg_rsa(keyopts *k)
 
   /* --- Allrighty then --- */
 
-  kd = &k->k->k;
-  key_structure(kd);
-  mpkey(kd, "n", rp.n, KCAT_PUB);
-  mpkey(kd, "e", rp.e, KCAT_PUB);
-
-  kd = key_structcreate(kd, "private");
-  key_structure(kd);
-  mpkey(kd, "d", rp.d, KCAT_PRIV | KF_BURN);
-  mpkey(kd, "p", rp.p, KCAT_PRIV | KF_BURN);
-  mpkey(kd, "q", rp.q, KCAT_PRIV | KF_BURN);
-  mpkey(kd, "q-inv", rp.q_inv, KCAT_PRIV | KF_BURN);
-  mpkey(kd, "d-mod-p", rp.dp, KCAT_PRIV | KF_BURN);
-  mpkey(kd, "d-mod-q", rp.dq, KCAT_PRIV | KF_BURN);
-  dolock(k, kd, "private");
-
+  kd = key_newstruct();
+  key_structsteal(kd, "n", key_newmp(KCAT_PUB, rp.n));
+  key_structsteal(kd, "e", key_newmp(KCAT_PUB, rp.e));
+
+  kkd = key_newstruct();
+  key_structsteal(kkd, "d", key_newmp(KCAT_PRIV | KF_BURN, rp.d));
+  key_structsteal(kkd, "p", key_newmp(KCAT_PRIV | KF_BURN, rp.p));
+  key_structsteal(kkd, "q", key_newmp(KCAT_PRIV | KF_BURN, rp.q));
+  key_structsteal(kkd, "q-inv", key_newmp(KCAT_PRIV | KF_BURN, rp.q_inv));
+  key_structsteal(kkd, "d-mod-p", key_newmp(KCAT_PRIV | KF_BURN, rp.dp));
+  key_structsteal(kkd, "d-mod-q", key_newmp(KCAT_PRIV | KF_BURN, rp.dq));
+  dolock(k, &kkd, "private");
+  key_structsteal(kd, "private", kkd);
+  key_setkeydata(k->kf, k->k, kd);
+  key_drop(kd);
   rsa_privfree(&rp);
 }
 
@@ -482,7 +467,7 @@ static void alg_dsaparam(keyopts *k)
     size_t sz;
     dstr d = DSTR_INIT;
     base64_ctx c;
-    key_data *kd = &k->k->k;
+    key_data *kd;
     dsa_seed ds;
 
     /* --- Choose appropriate bit lengths if necessary --- */
@@ -490,7 +475,7 @@ static void alg_dsaparam(keyopts *k)
     if (!k->qbits)
       k->qbits = 160;
     if (!k->bits)
-      k->bits = 768;
+      k->bits = 1024;
 
     /* --- Allocate a seed block --- */
 
@@ -506,13 +491,15 @@ static void alg_dsaparam(keyopts *k)
 
     /* --- Store the parameters --- */
 
-    key_structure(kd);
-    mpkey(kd, "q", dp.q, KCAT_SHARE);
-    mpkey(kd, "p", dp.p, KCAT_SHARE);
-    mpkey(kd, "g", dp.g, KCAT_SHARE);
+    kd = key_newstruct();
+    key_structsteal(kd, "q", key_newmp(KCAT_SHARE, dp.q));
+    key_structsteal(kd, "p", key_newmp(KCAT_SHARE, dp.p));
+    key_structsteal(kd, "g", key_newmp(KCAT_SHARE, dp.g));
     mp_drop(dp.q);
     mp_drop(dp.p);
     mp_drop(dp.g);
+    key_setkeydata(k->kf, k->k, kd);
+    key_drop(kd);
 
     /* --- Store the seed for future verification --- */
 
@@ -521,6 +508,7 @@ static void alg_dsaparam(keyopts *k)
     c.indent = "";
     base64_encode(&c, ds.p, ds.sz, &d);
     base64_encode(&c, 0, 0, &d);
+    DPUTZ(&d);
     key_putattr(k->kf, k->k, "seed", d.buf);
     DRESET(&d);
     dstr_putf(&d, "%u", ds.count);
@@ -536,11 +524,12 @@ static void alg_dsa(keyopts *k)
   mp *q, *p, *g;
   mp *x, *y;
   mpmont mm;
-  key_data *kd = &k->k->k;
+  key_data *kd, *kkd;
 
   /* --- Get the shared parameters --- */
 
   alg_dsaparam(k);
+  key_split(&k->k->k); kd = k->k->k;
   q = getmp(kd, "q");
   p = getmp(kd, "p");
   g = getmp(kd, "g");
@@ -553,12 +542,12 @@ static void alg_dsa(keyopts *k)
 
   /* --- Store everything away --- */
 
-  mpkey(kd, "y", y, KCAT_PUB);
+  key_structsteal(kd, "y", key_newmp(KCAT_PUB, y));
 
-  kd = key_structcreate(kd, "private");
-  key_structure(kd);
-  mpkey(kd, "x", x, KCAT_PRIV | KF_BURN);
-  dolock(k, kd, "private");
+  kkd = key_newstruct();
+  key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
+  dolock(k, &kkd, "private");
+  key_structsteal(kd, "private", kkd);
 
   mp_drop(x); mp_drop(y);
 }
@@ -566,7 +555,7 @@ static void alg_dsa(keyopts *k)
 static void alg_dhparam(keyopts *k)
 {
   static const char *pl[] = { "p", "q", "g", 0 };
-  key_data *kd = &k->k->k;
+  key_data *kd;
   if (!copyparam(k, pl)) {
     dh_param dp;
     int rc;
@@ -628,13 +617,15 @@ static void alg_dhparam(keyopts *k)
       die(EXIT_FAILURE, "Diffie-Hellman parameter generation failed");
 
   done:
-    key_structure(kd);
-    mpkey(kd, "p", dp.p, KCAT_SHARE);
-    mpkey(kd, "q", dp.q, KCAT_SHARE);
-    mpkey(kd, "g", dp.g, KCAT_SHARE);
+    kd = key_newstruct();
+    key_structsteal(kd, "p", key_newmp(KCAT_SHARE, dp.p));
+    key_structsteal(kd, "q", key_newmp(KCAT_SHARE, dp.q));
+    key_structsteal(kd, "g", key_newmp(KCAT_SHARE, dp.g));
     mp_drop(dp.q);
     mp_drop(dp.p);
     mp_drop(dp.g);
+    key_setkeydata(k->kf, k->k, kd);
+    key_drop(kd);
   }
 }
 
@@ -643,11 +634,12 @@ static void alg_dh(keyopts *k)
   mp *x, *y;
   mp *p, *q, *g;
   mpmont mm;
-  key_data *kd = &k->k->k;
+  key_data *kd, *kkd;
 
   /* --- Get the shared parameters --- */
 
   alg_dhparam(k);
+  key_split(&k->k->k); kd = k->k->k;
   p = getmp(kd, "p");
   q = getmp(kd, "q");
   g = getmp(kd, "g");
@@ -667,12 +659,12 @@ static void alg_dh(keyopts *k)
 
   /* --- Store everything away --- */
 
-  mpkey(kd, "y", y, KCAT_PUB);
+  key_structsteal(kd, "y", key_newmp(KCAT_PUB, y));
 
-  kd = key_structcreate(kd, "private");
-  key_structure(kd);
-  mpkey(kd, "x", x, KCAT_PRIV | KF_BURN);
-  dolock(k, kd, "private");
+  kkd = key_newstruct();
+  key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
+  dolock(k, &kkd, "private");
+  key_structsteal(kd, "private", kkd);
 
   mp_drop(x); mp_drop(y);
 }
@@ -680,7 +672,7 @@ static void alg_dh(keyopts *k)
 static void alg_bbs(keyopts *k)
 {
   bbs_priv bp;
-  key_data *kd;
+  key_data *kd, *kkd;
 
   /* --- Sanity checking --- */
 
@@ -697,15 +689,16 @@ static void alg_bbs(keyopts *k)
 
   /* --- Allrighty then --- */
 
-  kd = &k->k->k;
-  key_structure(kd);
-  mpkey(kd, "n", bp.n, KCAT_PUB);
+  kd = key_newstruct();
+  key_structsteal(kd, "n", key_newmp(KCAT_PUB, bp.n));
 
-  kd = key_structcreate(kd, "private");
-  key_structure(kd);
-  mpkey(kd, "p", bp.p, KCAT_PRIV | KF_BURN);
-  mpkey(kd, "q", bp.q, KCAT_PRIV | KF_BURN);
-  dolock(k, kd, "private");
+  kkd = key_newstruct();
+  key_structsteal(kkd, "p", key_newmp(KCAT_PRIV | KF_BURN, bp.p));
+  key_structsteal(kkd, "q", key_newmp(KCAT_PRIV | KF_BURN, bp.q));
+  dolock(k, &kkd, "private");
+  key_structsteal(kd, "private", kkd);
+  key_setkeydata(k->kf, k->k, kd);
+  key_drop(kd);
 
   bbs_privfree(&bp);
 }
@@ -718,7 +711,7 @@ static void alg_binparam(keyopts *k)
     qd_parse qd;
     group *g;
     const char *e;
-    key_data *kd = &k->k->k;
+    key_data *kd;
 
     /* --- Decide on a field --- */
 
@@ -759,13 +752,15 @@ static void alg_binparam(keyopts *k)
 
     /* --- Write out the answer --- */
 
-    key_structure(kd);
-    mpkey(kd, "p", gb.p, KCAT_SHARE);
-    mpkey(kd, "q", gb.q, KCAT_SHARE);
-    mpkey(kd, "g", gb.g, KCAT_SHARE);
+    kd = key_newstruct();
+    key_structsteal(kd, "p", key_newmp(KCAT_SHARE, gb.p));
+    key_structsteal(kd, "q", key_newmp(KCAT_SHARE, gb.q));
+    key_structsteal(kd, "g", key_newmp(KCAT_SHARE, gb.g));
     mp_drop(gb.q);
     mp_drop(gb.p);
     mp_drop(gb.g);
+    key_setkeydata(k->kf, k->k, kd);
+    key_drop(kd);
   }
 }
 
@@ -774,11 +769,12 @@ static void alg_bin(keyopts *k)
   mp *x, *y;
   mp *p, *q, *g;
   gfreduce r;
-  key_data *kd = &k->k->k;
+  key_data *kd, *kkd;
 
   /* --- Get the shared parameters --- */
 
   alg_binparam(k);
+  key_split(&k->k->k); kd = k->k->k;
   p = getmp(kd, "p");
   q = getmp(kd, "q");
   g = getmp(kd, "g");
@@ -798,12 +794,12 @@ static void alg_bin(keyopts *k)
 
   /* --- Store everything away --- */
 
-  mpkey(kd, "y", y, KCAT_PUB);
+  key_structsteal(kd, "y", key_newmp(KCAT_PUB, y));
 
-  kd = key_structcreate(kd, "private");
-  key_structure(kd);
-  mpkey(kd, "x", x, KCAT_PRIV | KF_BURN);
-  dolock(k, kd, "private");
+  kkd = key_newstruct();
+  key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
+  dolock(k, &kkd, "private");
+  key_structsteal(kd, "private", kkd);
 
   mp_drop(x); mp_drop(y);
 }
@@ -814,7 +810,7 @@ static void alg_ecparam(keyopts *k)
   if (!copyparam(k, pl)) {
     ec_info ei;
     const char *e;
-    key_data *kd = &k->k->k;
+    key_data *kd;
 
     /* --- Decide on a curve --- */
 
@@ -849,16 +845,16 @@ static void alg_ecparam(keyopts *k)
 
     /* --- Write out the answer --- */
 
-    key_structure(kd);
-    kd = key_structcreate(kd, "curve");
-    key_string(kd, k->curve);
-    kd->e |= KCAT_SHARE;
+    kd = key_newstruct();
+    key_structsteal(kd, "curve", key_newstring(KCAT_SHARE, k->curve));
+    key_setkeydata(k->kf, k->k, kd);
+    key_drop(kd);
   }
 }
 
 static void alg_ec(keyopts *k)
 {
-  key_data *kd = &k->k->k;
+  key_data *kd;
   key_data *kkd;
   mp *x = MP_NEW;
   ec p = EC_INIT;
@@ -868,6 +864,7 @@ static void alg_ec(keyopts *k)
   /* --- Get the curve --- */
 
   alg_ecparam(k);
+  key_split(&k->k->k); kd = k->k->k;
   if ((kkd = key_structfind(kd, "curve")) == 0)
     die(EXIT_FAILURE, "unexpected failure looking up subkey `curve')");
   if ((kkd->e & KF_ENCMASK) != KENC_STRING)
@@ -882,13 +879,12 @@ static void alg_ec(keyopts *k)
 
   /* --- 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);
-  dolock(k, kkd, "private");
+  key_structsteal(kd, "p", key_newec(KCAT_PUB, &p));
+
+  kkd = key_newstruct();
+  key_structsteal(kkd, "x", key_newmp(KCAT_PRIV | KF_BURN, x));
+  dolock(k, &kkd, "private");
+  key_structsteal(kd, "private", kkd);
 
   /* --- Done --- */
 
@@ -1158,10 +1154,9 @@ static int cmd_add(int argc, char *argv[])
   for (;;) {
     uint32 id = rand_global.ops->word(&rand_global);
     int err;
-    k.k = key_new(&f, id, argv[optind], exp, &err);
-    if (k.k)
+    if ((err = key_new(&f, id, argv[optind], exp, &k.k)) == 0)
       break;
-    if (err != KERR_DUPID)
+    else if (err != KERR_DUPID)
       die(EXIT_FAILURE, "error adding new key: %s", key_strerror(err));
   }
 
@@ -1197,7 +1192,7 @@ static int cmd_add(int argc, char *argv[])
   if (ptag) {
     if ((k.p = key_bytag(&f, ptag)) == 0)
       die(EXIT_FAILURE, "parameter key `%s' not found", ptag);
-    if ((k.p->k.e & KF_ENCMASK) != KENC_STRUCT)
+    if ((k.p->k->e & KF_ENCMASK) != KENC_STRUCT)
       die(EXIT_FAILURE, "parameter key `%s' is not structured", ptag);
   }
 
@@ -1207,6 +1202,7 @@ static int cmd_add(int argc, char *argv[])
 
   /* --- Done --- */
 
+  dstr_destroy(&k.tag);
   doclose(&f);
   return (0);
 }
@@ -1289,13 +1285,13 @@ static void showkeydata(key_data *k, int ind, listopts *o, dstr *d)
       if (o->v <= 3)
        fputs(" encrypted\n", stdout);
       else {
-       key_data kd;
-       if (key_punlock(d->buf, k, &kd))
+       key_data *kd;
+       if (key_punlock(&kd, k, d->buf))
          printf(" <failed to unlock %s>\n", d->buf);
        else {
          fputs(" encrypted", stdout);
-         showkeydata(&kd, ind, o, d);
-         key_destroy(&kd);
+         showkeydata(kd, ind, o, d);
+         key_drop(kd);
        }
       }
       break;
@@ -1336,19 +1332,19 @@ static void showkeydata(key_data *k, int ind, listopts *o, dstr *d)
      */
 
     case KENC_STRUCT: {
-      sym_iter i;
-      key_struct *ks;
+      key_subkeyiter i;
+      const char *tag;
       size_t n = d->len;
 
       fputs(" {\n", stdout);
-      for (sym_mkiter(&i, &k->u.s); (ks = sym_next(&i)) != 0; ) {
-       if (!key_match(&ks->k, &o->kf))
+      for (key_mksubkeyiter(&i, k); key_nextsubkey(&i, &tag, &k); ) {
+       if (!key_match(k, &o->kf))
          continue;
        INDENT(ind + 2);
-       printf("%s =", SYM_NAME(ks));
+       printf("%s =", tag);
        d->len = n;
-       dstr_putf(d, ".%s", SYM_NAME(ks));
-       showkeydata(&ks->k, ind + 2, o, d);
+       dstr_putf(d, ".%s", tag);
+       showkeydata(k, ind + 2, o, d);
       }
       INDENT(ind);
       fputs("}\n", stdout);
@@ -1375,7 +1371,7 @@ static void showkey(key *k, listopts *o)
 
   /* --- Skip the key if the filter doesn't match --- */
 
-  if (!key_match(&k->k, &o->kf))
+  if (!key_match(k->k, &o->kf))
     return;
 
   /* --- Sort out the expiry and deletion times --- */
@@ -1447,7 +1443,7 @@ static void showkey(key *k, listopts *o)
     dstr d = DSTR_INIT;
     fputs("key:", stdout);
     key_fulltag(k, &d);
-    showkeydata(&k->k, 0, o, &d);
+    showkeydata(k->k, 0, o, &d);
     dstr_destroy(&d);
   }
     
@@ -1860,7 +1856,7 @@ static int cmd_lock(int argc, char *argv[])
 {
   key_file f;
   key *k;
-  key_data *kd;
+  key_data **kd;
   dstr d = DSTR_INIT;
 
   if (argc != 2)
@@ -1868,9 +1864,9 @@ static int cmd_lock(int argc, char *argv[])
   doopen(&f, KOPEN_WRITE);
   if (key_qtag(&f, argv[1], &d, &k, &kd))
     die(EXIT_FAILURE, "key `%s' not found", argv[1]);
-  if (kd->e == KENC_ENCRYPT && key_punlock(d.buf, kd, kd))
+  if ((*kd)->e == KENC_ENCRYPT && key_punlock(kd, 0, d.buf))
     die(EXIT_FAILURE, "couldn't unlock key `%s'", d.buf);
-  if (key_plock(d.buf, kd, kd))
+  if (key_plock(kd, 0, d.buf))
     die(EXIT_FAILURE, "failed to lock key `%s'", d.buf);
   f.f |= KF_MODIFIED;
   doclose(&f);
@@ -1883,7 +1879,7 @@ static int cmd_unlock(int argc, char *argv[])
 {
   key_file f;
   key *k;
-  key_data *kd;
+  key_data **kd;
   dstr d = DSTR_INIT;
 
   if (argc != 2)
@@ -1891,9 +1887,9 @@ static int cmd_unlock(int argc, char *argv[])
   doopen(&f, KOPEN_WRITE);
   if (key_qtag(&f, argv[1], &d, &k, &kd))
     die(EXIT_FAILURE, "key `%s' not found", argv[1]);
-  if (kd->e != KENC_ENCRYPT)
+  if ((*kd)->e != KENC_ENCRYPT)
     die(EXIT_FAILURE, "key `%s' is not encrypted", d.buf);
-  if (kd->e == KENC_ENCRYPT && key_punlock(d.buf, kd, kd))
+  if (key_punlock(kd, 0, d.buf))
     die(EXIT_FAILURE, "couldn't unlock key `%s'", d.buf);
   f.f |= KF_MODIFIED;
   doclose(&f);
index 49315f5..1f54c29 100644 (file)
--- a/mparena.c
+++ b/mparena.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: mparena.c,v 1.7 2004/04/08 01:36:15 mdw Exp $
+ * $Id$
  *
  * Allocation and freeing of MP buffers
  *
@@ -48,7 +48,7 @@
  * itself.
  */
 
-/* #define MPARENA_TRIVIAL */
+#define MPARENA_TRIVIAL
 
 /* --- @MPARENA_DEBUG@ --- *
  *
diff --git a/rspit.c b/rspit.c
index 34abb11..148a3d0 100644 (file)
--- a/rspit.c
+++ b/rspit.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: rspit.c,v 1.21 2004/04/21 00:37:32 mdw Exp $
+ * $Id$
  *
  * Spit out random numbers
  *
@@ -619,9 +619,9 @@ static grand *gen_bbs(unsigned i)
 
     /* --- Read the key data --- */
 
-    if ((kk->k.e & KF_ENCMASK) != KENC_STRUCT)
+    if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
       die(EXIT_FAILURE, "key is not structured");
-    if ((kd = key_structfind(&kk->k, "n")) == 0)
+    if ((kd = key_structfind(kk->k, "n")) == 0)
       die(EXIT_FAILURE, "key has no subkey `n'");
     if ((kd->e & KF_ENCMASK) != KENC_MP)
       die(EXIT_FAILURE, "incompatible subkey encoding");