chiark / gitweb /
Support elliptic curve key exchange.
authormdw <mdw>
Sat, 3 Apr 2004 12:35:13 +0000 (12:35 +0000)
committermdw <mdw>
Sat, 3 Apr 2004 12:35:13 +0000 (12:35 +0000)
debian/changelog
debian/control
doc/tripe.8
ethereal/packet-tripe.c
keyexch.c
keymgmt.c
mallory.c
servutil.c
tripe-init.in
tripe.conf
tripe.h

index a19e8839664381cdf88e819433ec3d720e6677d1..9a02285d4f8597009d71debc448ebcd54e63e518 100644 (file)
@@ -1,5 +1,7 @@
 tripe (1.0.0pre6) experimental; urgency=low
 
   * Debianization!
 tripe (1.0.0pre6) experimental; urgency=low
 
   * Debianization!
+  * Don't report uninteresting errors when accepting connections.
+  * Support elliptic curve keys.
 
 
- -- Mark Wooding <mdw@nsict.org>  Sat, 22 Nov 2003 18:35:50 +0000
+ -- Mark Wooding <mdw@nsict.org>  Sat,  3 Apr 2004 11:23:40 +0100
index d4482636287f5304387fb124d58333634dfc7d4f..1fb7fdf75d5235bbe0dcb27fbb3c7e5751b8a6c5 100644 (file)
@@ -2,7 +2,7 @@ Source: tripe
 Section: net
 Priority: extra
 Maintainer: Mark Wooding <mdw@nsict.org>
 Section: net
 Priority: extra
 Maintainer: Mark Wooding <mdw@nsict.org>
-Build-Depends: catacomb-dev (>= 2.0.1), mlib-dev (>= 2.0.2),
+Build-Depends: catacomb-dev (>= 2.1.0), mlib-dev (>= 2.0.3),
  ethereal-dev, debhelper (>= 4.0.2)
 Standards-Version: 3.1.1
 
  ethereal-dev, debhelper (>= 4.0.2)
 Standards-Version: 3.1.1
 
index 262b23448ac6fec64fd8c21329030a6fa24e2289..b6da8d814a32d3bfbca123203f0cf0932eaccca6 100644 (file)
@@ -409,6 +409,41 @@ server to talk to
 .hP 7.
 Congratulations.  The two servers will exchange keys and begin sending
 packets almost immediately.  You've set up a virtual private network.
 .hP 7.
 Congratulations.  The two servers will exchange keys and begin sending
 packets almost immediately.  You've set up a virtual private network.
+.SS "Using elliptic curve keys"
+The
+.B tripe
+server can use elliptic curve Diffie-Hellman for key exchange, rather
+than traditional integer Diffie-Hellman.  Given current public
+knowledge, elliptic curves can provide similar or better security to
+systems based on integer discrete log problems, faster, and with less
+transmitted data.  It's a matter of controversy whether this will
+continue to be the case.  The author uses elliptic curves.
+.PP
+The server works out which it
+should be doing based on the key type, which is either
+.B tripe\-dh
+for standard Diffie-Hellman, or
+.B tripe\-ec
+for elliptic curves.  To create elliptic curve keys, say something like
+.VS
+key add \-aec\-param \-Cnist-p192 \-eforever \e
+       \-tparam tripe\-ec\-param
+.VE
+to construct a parameters key, using your preferred elliptic curve in
+the
+.B \-C
+option (see
+.BR key (1)
+for details); and create the private keys by
+.VS
+key add \-aec \-pparam \-talice \e
+       \-e"now + 1 year" tripe\-ec
+.VE
+Now start
+.B tripe
+with the
+.B \-ttripe\-ec
+option, and all should be well.
 .SS "About the name"
 The program's name is
 .BR tripe ,
 .SS "About the name"
 The program's name is
 .BR tripe ,
index 93f1e0e041f4ee87737e7368ef9d75760055e4cd..386f383cb868f2e484a01bd4106b97afd8d4fd7c 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: packet-tripe.c,v 1.1 2003/10/15 09:30:19 mdw Exp $
+ * $Id: packet-tripe.c,v 1.2 2004/04/03 12:35:13 mdw Exp $
  *
  * TrIPE protocol dissector for Ethereal
  *
  *
  * TrIPE protocol dissector for Ethereal
  *
@@ -29,6 +29,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: packet-tripe.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: packet-tripe.c,v $
+ * Revision 1.2  2004/04/03 12:35:13  mdw
+ * Support elliptic curve key exchange.
+ *
  * Revision 1.1  2003/10/15 09:30:19  mdw
  * Add support for Ethereal protocol analysis.
  *
  * Revision 1.1  2003/10/15 09:30:19  mdw
  * Add support for Ethereal protocol analysis.
  *
 
 static int proto_tripe = -1;
 
 
 static int proto_tripe = -1;
 
-typedef struct hfmp { int hf, hf_len, hf_val, tt; } hfmp;
+typedef struct hfmp {
+  int hf, hf_len, hf_val, tt;
+} hfmp;
+typedef struct hfge {
+  int hf, hf_len, hf_val, hfx_len, hfx_val, hfy_len, hfy_val, tt;
+} hfge;
 
 static int hf_tripe_cat = -1;
 static int hf_tripe_packet_type = -1;
 
 static int hf_tripe_cat = -1;
 static int hf_tripe_packet_type = -1;
@@ -71,7 +79,7 @@ static int hf_tripe_ct_iv = -1;
 static int hf_tripe_ct_cbc = -1;
 static int hf_tripe_ct_mac = -1;
 static int hf_tripe_kx_type = -1;
 static int hf_tripe_ct_cbc = -1;
 static int hf_tripe_ct_mac = -1;
 static int hf_tripe_kx_type = -1;
-static hfmp hf_tripe_kx_mychal = { -1, -1, -1, -1 };
+static hfge hf_tripe_kx_mychal = { -1, -1, -1, -1, -1, -1, -1, -1 };
 static int hf_tripe_kx_mycookie = -1;
 static int hf_tripe_kx_yourcookie = -1;
 static hfmp hf_tripe_kx_check = { -1, -1, -1, -1 };
 static int hf_tripe_kx_mycookie = -1;
 static int hf_tripe_kx_yourcookie = -1;
 static hfmp hf_tripe_kx_check = { -1, -1, -1, -1 };
@@ -100,6 +108,31 @@ static gint getmp(proto_tree *tt, const hfmp *hf, tvbuff_t *b, gint off)
   return (off + 2 + len);
 }
 
   return (off + 2 + len);
 }
 
+static gint getge(proto_tree *tt, const hfge *hf, tvbuff_t *b, gint off)
+{
+  guint16 len = tvb_get_ntohs(b, off), len2;
+  guint r;
+  proto_item *ti;
+  r = tvb_length_remaining(b, off);
+  if (r < 4 + len ||
+      (len2 = tvb_get_ntohs(b, off + 2 + len), r < 4 + len + len2)) {
+    ti = proto_tree_add_item(tt, hf->hf, b, off, len + 2, FALSE);
+    tt = proto_item_add_subtree(ti, hf->tt);
+    proto_tree_add_item(tt, hf->hf_len, b, off, 2, FALSE);
+    proto_tree_add_item(tt, hf->hf_val, b, off + 2, len, FALSE);
+    r = off + len + 2;
+  } else {
+    ti = proto_tree_add_item(tt, hf->hf, b, off, len + len2 + 4, FALSE);
+    tt = proto_item_add_subtree(ti, hf->tt);
+    proto_tree_add_item(tt, hf->hfx_len, b, off, 2, FALSE);
+    proto_tree_add_item(tt, hf->hfx_val, b, off + 2, len, FALSE);
+    proto_tree_add_item(tt, hf->hfy_len, b, off + 2 + len, 2, FALSE);
+    proto_tree_add_item(tt, hf->hfy_val, b, off + 4 + len, len2, FALSE);
+    r = off + len + len2 + 4;
+  }    
+  return (r);
+}
+
 static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t)
 {
   proto_item *ti;
 static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t)
 {
   proto_item *ti;
@@ -186,14 +219,14 @@ static void dissect_tripe(tvbuff_t *b, packet_info *p, proto_tree *t)
        proto_tree_add_item(tt, hf_tripe_kx_type, b, 0, 1, FALSE);
        switch (ty & MSG_TYPEMASK) {
          case KX_PRECHAL:
        proto_tree_add_item(tt, hf_tripe_kx_type, b, 0, 1, FALSE);
        switch (ty & MSG_TYPEMASK) {
          case KX_PRECHAL:
-           off = getmp(tt, &hf_tripe_kx_mychal, b, off);
+           off = getge(tt, &hf_tripe_kx_mychal, b, off);
            goto tail;
          case KX_COOKIE:
            goto tail;
          case KX_COOKIE:
-           off = getmp(tt, &hf_tripe_kx_mychal, b, off);
+           off = getge(tt, &hf_tripe_kx_mychal, b, off);
            off = gethash(tt, hf_tripe_kx_yourcookie, b, off);
            goto tail;
          case KX_CHAL:
            off = gethash(tt, hf_tripe_kx_yourcookie, b, off);
            goto tail;
          case KX_CHAL:
-           off = getmp(tt, &hf_tripe_kx_mychal, b, off);
+           off = getge(tt, &hf_tripe_kx_mychal, b, off);
            off = gethash(tt, hf_tripe_kx_yourcookie, b, off);
            off = getmp(tt, &hf_tripe_kx_check, b, off);
            goto tail;
            off = gethash(tt, hf_tripe_kx_yourcookie, b, off);
            off = getmp(tt, &hf_tripe_kx_check, b, off);
            goto tail;
@@ -295,17 +328,37 @@ void proto_register_tripe(void)
     &hf_tripe_kx_mychal.hf, {
       "Sender's challenge data", "tripe.kx.mychal",
       FT_BYTES, BASE_NONE, 0, 0,
     &hf_tripe_kx_mychal.hf, {
       "Sender's challenge data", "tripe.kx.mychal",
       FT_BYTES, BASE_NONE, 0, 0,
-      "This is the sender's challenge value."
+      "This is the sender's challenge."
     },
     &hf_tripe_kx_mychal.hf_len, {
       "Challenge length", "tripe.kx.mychal.len",
       FT_UINT16, BASE_DEC, 0, 0,
     },
     &hf_tripe_kx_mychal.hf_len, {
       "Challenge length", "tripe.kx.mychal.len",
       FT_UINT16, BASE_DEC, 0, 0,
-      "This is the length of the sender's challenge value."
+      "This is the length of the sender's challenge."
     },
     &hf_tripe_kx_mychal.hf_val, {
     },
     &hf_tripe_kx_mychal.hf_val, {
-      "Challenge value", "tripe.kx.mychal.val",
+      "Challenge", "tripe.kx.mychal.val",
+      FT_BYTES, BASE_NONE, 0, 0,
+      "This is the value of the sender's challenge."
+    },
+    &hf_tripe_kx_mychal.hfx_len, {
+      "Challenge x length", "tripe.kx.mychal.x.len",
+      FT_UINT16, BASE_DEC, 0, 0,
+      "This is the length of the sender's challenge x-coordinate."
+    },
+    &hf_tripe_kx_mychal.hfy_val, {
+      "Challenge x value", "tripe.kx.mychal.x.val",
+      FT_BYTES, BASE_NONE, 0, 0,
+      "This is the value of the sender's challenge x-coordinate."
+    },
+    &hf_tripe_kx_mychal.hfy_len, {
+      "Challenge y length", "tripe.kx.mychal.y.len",
+      FT_UINT16, BASE_DEC, 0, 0,
+      "This is the length of the sender's challenge x-coordinate."
+    },
+    &hf_tripe_kx_mychal.hfx_val, {
+      "Challenge y value", "tripe.kx.mychal.y.val",
       FT_BYTES, BASE_NONE, 0, 0,
       FT_BYTES, BASE_NONE, 0, 0,
-      "This is the value of the sender's challenge value."
+      "This is the value of the sender's challenge x-coordinate."
     },
     &hf_tripe_kx_mycookie, {
       "Sender's hashed cookie", "tripe.kx.mycookie",
     },
     &hf_tripe_kx_mycookie, {
       "Sender's hashed cookie", "tripe.kx.mycookie",
index 35f027ecaca2a809b58d71a276fb5ace76bf0fa0..ea503583f976b50cfc536ba7fe6966487583b67f 100644 (file)
--- a/keyexch.c
+++ b/keyexch.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: keyexch.c,v 1.10 2003/10/15 09:29:38 mdw Exp $
+ * $Id: keyexch.c,v 1.11 2004/04/03 12:35:13 mdw Exp $
  *
  * Key exchange protocol
  *
  *
  * Key exchange protocol
  *
@@ -29,6 +29,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: keyexch.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: keyexch.c,v $
+ * Revision 1.11  2004/04/03 12:35:13  mdw
+ * Support elliptic curve key exchange.
+ *
  * Revision 1.10  2003/10/15 09:29:38  mdw
  * Cosmetic fix to changelog comment.
  *
  * Revision 1.10  2003/10/15 09:29:38  mdw
  * Cosmetic fix to changelog comment.
  *
 
 /*----- Various utilities -------------------------------------------------*/
 
 
 /*----- Various utilities -------------------------------------------------*/
 
-/* --- @hashmp@ --- *
+/* --- @hashge@ --- *
  *
  * Arguments:  @HASH_CTX *r@ = pointer to hash context
  *
  * Arguments:  @HASH_CTX *r@ = pointer to hash context
- *             @mp *m@ = pointer to multiprecision integer
+ *             @ge *x@ = pointer to group element
  *
  * Returns:    ---
  *
  *
  * Returns:    ---
  *
- * Use:                Adds the hash of a multiprecision integer to the context.
- *             Corrupts @buf_t@.
+ * Use:                Adds the hash of a group element to the context.  Corrupts
+ *             @buf_t@.
  */
 
  */
 
-static void hashmp(HASH_CTX *r, mp *m)
+static void hashge(HASH_CTX *r, ge *x)
 {
   buf b;
   buf_init(&b, buf_t, sizeof(buf_t));
 {
   buf b;
   buf_init(&b, buf_t, sizeof(buf_t));
-  buf_putmp(&b, m);
+  G_TOBUF(gg, &b, x);
   assert(BOK(&b));
   HASH(r, BBASE(&b), BLEN(&b));
 }
   assert(BOK(&b));
   HASH(r, BBASE(&b), BLEN(&b));
 }
@@ -158,9 +161,10 @@ static void hashmp(HASH_CTX *r, mp *m)
  *
  * Returns:    The encrypted/decrypted integer.
  *
  *
  * Returns:    The encrypted/decrypted integer.
  *
- * Use:                Encrypts (or decrypts) a multiprecision integer using another
- *             multiprecision integer as the key.  This is a slightly grotty
- *             way to do this, but it's easier than the alternatives.
+ * Use:                Encrypts (or decrypts) a multiprecision integer.  In fact,
+ *             the title is a bit of a misnomer: we actually compute
+ *             %$x \xor H(k)$%, so it's a random oracle thing rather than an
+ *             encryption thing.
  */
 
 static mp *mpcrypt(mp *d, mp *x, size_t sz, const octet *k, size_t ksz)
  */
 
 static mp *mpcrypt(mp *d, mp *x, size_t sz, const octet *k, size_t ksz)
@@ -240,8 +244,8 @@ static void kxc_destroy(kxchal *kxc)
 {
   if (kxc->f & KXF_TIMER)
     sel_rmtimer(&kxc->t);
 {
   if (kxc->f & KXF_TIMER)
     sel_rmtimer(&kxc->t);
-  mp_drop(kxc->c);
-  mp_drop(kxc->r);
+  G_DESTROY(gg, kxc->c);
+  if (kxc->r) G_DESTROY(gg, kxc->r);
   mp_drop(kxc->ck);
   ks_drop(kxc->ks);
   DESTROY(kxc);
   mp_drop(kxc->ck);
   ks_drop(kxc->ks);
   DESTROY(kxc);
@@ -291,9 +295,9 @@ static kxchal *kxc_new(keyexch *kx)
   /* --- Fill in the new structure --- */
 
   kxc = CREATE(kxchal);
   /* --- Fill in the new structure --- */
 
   kxc = CREATE(kxchal);
-  kxc->c = 0;
+  kxc->c = G_CREATE(gg);
   kxc->r = 0;
   kxc->r = 0;
-  kxc->ck = 0;
+  kxc->ck = MP_NEW;
   kxc->ks = 0;
   kxc->kx = kx;
   kxc->f = 0;
   kxc->ks = 0;
   kxc->kx = kx;
   kxc->f = 0;
@@ -304,19 +308,19 @@ static kxchal *kxc_new(keyexch *kx)
 /* --- @kxc_bychal@ --- *
  *
  * Arguments:  @keyexch *kx@ = pointer to key exchange block
 /* --- @kxc_bychal@ --- *
  *
  * Arguments:  @keyexch *kx@ = pointer to key exchange block
- *             @mp *c@ = challenge from remote host
+ *             @ge *c@ = challenge from remote host
  *
  * Returns:    Pointer to the challenge block, or null.
  *
  * Use:                Finds a challenge block, given its challenge.
  */
 
  *
  * Returns:    Pointer to the challenge block, or null.
  *
  * Use:                Finds a challenge block, given its challenge.
  */
 
-static kxchal *kxc_bychal(keyexch *kx, mp *c)
+static kxchal *kxc_bychal(keyexch *kx, ge *c)
 {
   unsigned i;
 
   for (i = 0; i < kx->nr; i++) {
 {
   unsigned i;
 
   for (i = 0; i < kx->nr; i++) {
-    if (MP_EQ(c, kx->r[i]->c))
+    if (G_EQ(gg, c, kx->r[i]->c))
       return (kx->r[i]);
   }
   return (0);
       return (kx->r[i]);
   }
   return (0);
@@ -373,7 +377,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc)
   /* --- Build the reply packet --- */
 
   if (!kxc->r)
   /* --- Build the reply packet --- */
 
   if (!kxc->r)
-    buf_putmp(b, kx->c);
+    G_TOBUF(gg, b, kx->c);
   else
     buf_put(b, kx->hc, HASHSZ);
   buf_put(b, kxc->hc, HASHSZ);
   else
     buf_put(b, kx->hc, HASHSZ);
   buf_put(b, kxc->hc, HASHSZ);
@@ -387,7 +391,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc)
   } else {
     T( trace(T_KEYEXCH, "keyexch: sending reply to `%s'", p_name(kx->p)); )
     buf_init(&bb, buf_i, sizeof(buf_i));
   } else {
     T( trace(T_KEYEXCH, "keyexch: sending reply to `%s'", p_name(kx->p)); )
     buf_init(&bb, buf_i, sizeof(buf_i));
-    buf_putmp(&bb, kxc->r);
+    G_TOBUF(gg, &bb, kxc->r);
     buf_flip(&bb);
     ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_REPLY, &bb, b);
   }
     buf_flip(&bb);
     ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_REPLY, &bb, b);
   }
@@ -415,7 +419,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc)
 /* --- @getreply@ --- *
  *
  * Arguments:  @keyexch *kx@ = pointer to key exchange context
 /* --- @getreply@ --- *
  *
  * Arguments:  @keyexch *kx@ = pointer to key exchange context
- *             @mp *c@ = a challenge
+ *             @ge *c@ = a challenge
  *             @mp *ck@ = the supplied expected-reply check value
  *
  * Returns:    A pointer to the reply, or null if the reply-hash was wrong.
  *             @mp *ck@ = the supplied expected-reply check value
  *
  * Returns:    A pointer to the reply, or null if the reply-hash was wrong.
@@ -423,38 +427,42 @@ static void kxc_answer(keyexch *kx, kxchal *kxc)
  * Use:                Computes replies to challenges.
  */
 
  * Use:                Computes replies to challenges.
  */
 
-static mp *getreply(keyexch *kx, mp *c, mp *ck)
+static ge *getreply(keyexch *kx, ge *c, mp *ck)
 {
 {
-  mp *r = mpmont_exp(&mg, MP_NEW, c, kpriv.x);
-  mp *a;
+  ge *r = G_CREATE(gg);
+  ge *y = G_CREATE(gg);
+  mp *a = MP_NEW;
   HASH_CTX h;
   octet buf[HASHSZ];  
   int ok;
 
   HASH_CTX h;
   octet buf[HASHSZ];  
   int ok;
 
+  G_EXP(gg, r, c, kpriv);
   HASH_INIT(&h);
   HASH_STRING(&h, "tripe-expected-reply");
   HASH_INIT(&h);
   HASH_STRING(&h, "tripe-expected-reply");
-  hashmp(&h, c);
-  hashmp(&h, kx->c);
-  hashmp(&h, r);
+  hashge(&h, c);
+  hashge(&h, kx->c);
+  hashge(&h, r);
   HASH_DONE(&h, buf);
 
   HASH_DONE(&h, buf);
 
-  a = mpcrypt(MP_NEW, ck, mp_octets(kpriv.dp.q), buf, sizeof(buf));
+  a = mpcrypt(MP_NEW, ck, mp_octets(gg->r), buf, sizeof(buf));
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-    trace(T_CRYPTO, "crypto: computed reply = %s", mpstr(r));
+    trace(T_CRYPTO, "crypto: computed reply = %s", gestr(gg, r));
     trace_block(T_CRYPTO, "crypto: computed reply hash", buf, HASHSZ);
     trace(T_CRYPTO, "crypto: recovered log = %s", mpstr(a));
   }))
     trace_block(T_CRYPTO, "crypto: computed reply hash", buf, HASHSZ);
     trace(T_CRYPTO, "crypto: recovered log = %s", mpstr(a));
   }))
-  a = mpmont_exp(&mg, a, kpriv.dp.g, a);
-  ok = mp_eq(a, c);
+  G_EXP(gg, y, gg->g, a);
+  ok = G_EQ(gg, y, c);
   if (!ok) {
     a_warn("invalid expected-reply check from `%s'", p_name(kx->p));
     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
   if (!ok) {
     a_warn("invalid expected-reply check from `%s'", p_name(kx->p));
     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-      trace(T_CRYPTO, "crypto: computed challenge = %s", mpstr(a));
+      trace(T_CRYPTO, "crypto: computed challenge = %s", gestr(gg, y));
     }))
     }))
-    mp_drop(r);
+    G_DESTROY(gg, r);
+    r = 0;
   }
   mp_drop(a);
   }
   mp_drop(a);
-  return (ok ? r : 0);
+  G_DESTROY(gg, y);
+  return (r);
 }
 
 /* --- @dochallenge@ --- *
 }
 
 /* --- @dochallenge@ --- *
@@ -470,7 +478,8 @@ static mp *getreply(keyexch *kx, mp *c, mp *ck)
 
 static int dochallenge(keyexch *kx, unsigned msg, buf *b)
 {
 
 static int dochallenge(keyexch *kx, unsigned msg, buf *b)
 {
-  mp *c = 0, *ck = 0;
+  ge *c = G_CREATE(gg);
+  mp *ck = MP_NEW;
   const octet *hc = 0;
   kxchal *kxc;
   HASH_CTX h;
   const octet *hc = 0;
   kxchal *kxc;
   HASH_CTX h;
@@ -485,7 +494,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b)
 
   /* --- Unpack the packet --- */
 
 
   /* --- Unpack the packet --- */
 
-  if ((c = buf_getmp(b)) == 0 ||
+  if (G_FROMBUF(gg, b, c) ||
       (msg >= KX_COOKIE && (hc = buf_get(b, HASHSZ)) == 0) ||
       (msg >= KX_CHAL && (ck = buf_getmp(b)) == 0) ||
       BLEFT(b)) {
       (msg >= KX_COOKIE && (hc = buf_get(b, HASHSZ)) == 0) ||
       (msg >= KX_CHAL && (ck = buf_getmp(b)) == 0) ||
       BLEFT(b)) {
@@ -494,7 +503,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b)
   }
 
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
   }
 
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-    trace(T_CRYPTO, "crypto: challenge = %s", mpstr(c));
+    trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, c));
     if (hc) trace_block(T_CRYPTO, "crypto: cookie", hc, HASHSZ);
     if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck));
   }))
     if (hc) trace_block(T_CRYPTO, "crypto: cookie", hc, HASHSZ);
     if (ck) trace(T_CRYPTO, "crypto: check value = %s", mpstr(ck));
   }))
@@ -507,10 +516,10 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b)
   if (!hc && kx->nr >= KX_THRESH) {
     T( trace(T_KEYEXCH, "keyexch: too many challenges -- sending cookie"); )
     b = p_txstart(kx->p, MSG_KEYEXCH | KX_COOKIE);
   if (!hc && kx->nr >= KX_THRESH) {
     T( trace(T_KEYEXCH, "keyexch: too many challenges -- sending cookie"); )
     b = p_txstart(kx->p, MSG_KEYEXCH | KX_COOKIE);
-    buf_putmp(b, kx->c);
+    G_TOBUF(gg, b, kx->c);
     HASH_INIT(&h);
     HASH_STRING(&h, "tripe-cookie");
     HASH_INIT(&h);
     HASH_STRING(&h, "tripe-cookie");
-    hashmp(&h, c);
+    hashge(&h, c);
     HASH_DONE(&h, buf_get(b, HASHSZ));
     p_txend(kx->p);
     goto tidy;
     HASH_DONE(&h, buf_get(b, HASHSZ));
     p_txend(kx->p);
     goto tidy;
@@ -530,7 +539,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b)
 
   if ((kxc = kxc_bychal(kx, c)) == 0) {
     size_t x, y, z;
 
   if ((kxc = kxc_bychal(kx, c)) == 0) {
     size_t x, y, z;
-    mp *r;
+    ge *r;
 
     /* --- Be careful here --- *
      *
 
     /* --- Be careful here --- *
      *
@@ -547,47 +556,46 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b)
       kxc = kxc_new(kx);
       kxc->r = r;
     }
       kxc = kxc_new(kx);
       kxc->r = r;
     }
-    kxc->c = mp_copy(c);
+    kxc->c = G_CREATE(gg);
+    G_COPY(gg, kxc->c, c);
 
     /* --- Work out the cookie for this challenge --- */
 
     HASH_INIT(&h);
     HASH_STRING(&h, "tripe-cookie");
 
     /* --- Work out the cookie for this challenge --- */
 
     HASH_INIT(&h);
     HASH_STRING(&h, "tripe-cookie");
-    hashmp(&h, kxc->c);
+    hashge(&h, kxc->c);
     HASH_DONE(&h, kxc->hc);    
 
     /* --- Compute the expected-reply hash --- */
 
     HASH_INIT(&h);
     HASH_STRING(&h, "tripe-expected-reply");
     HASH_DONE(&h, kxc->hc);    
 
     /* --- Compute the expected-reply hash --- */
 
     HASH_INIT(&h);
     HASH_STRING(&h, "tripe-expected-reply");
-    hashmp(&h, kx->c);
-    hashmp(&h, kxc->c);
-    hashmp(&h, kx->rx);
+    hashge(&h, kx->c);
+    hashge(&h, kxc->c);
+    hashge(&h, kx->rx);
     HASH_DONE(&h, buf);
     HASH_DONE(&h, buf);
-    kxc->ck = mpcrypt(MP_NEW, kx->alpha, mp_octets(kpriv.dp.q),
+    kxc->ck = mpcrypt(MP_NEW, kx->alpha, mp_octets(gg->r),
                      buf, sizeof(buf));
 
     /* --- Work out the shared key --- */
 
                      buf, sizeof(buf));
 
     /* --- Work out the shared key --- */
 
-    trace(T_CRYPTO, "debug: c = %s", mpstr(c));
-    trace(T_CRYPTO, "debug: alpha = %s", mpstr(kx->alpha));
-    r = mpmont_exp(&mg, MP_NEW, c, kx->alpha);
-    trace(T_CRYPTO, "debug: r = %s", mpstr(r));
+    r = G_CREATE(gg);
+    G_EXP(gg, r, c, kx->alpha);
 
     /* --- Compute the switch messages --- */
 
     HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-request");
 
     /* --- Compute the switch messages --- */
 
     HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-request");
-    hashmp(&h, kx->c); hashmp(&h, kxc->c);
+    hashge(&h, kx->c); hashge(&h, kxc->c);
     HASH_DONE(&h, kxc->hswrq_out);
     HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-confirm");
     HASH_DONE(&h, kxc->hswrq_out);
     HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-confirm");
-    hashmp(&h, kx->c); hashmp(&h, kxc->c);
+    hashge(&h, kx->c); hashge(&h, kxc->c);
     HASH_DONE(&h, kxc->hswok_out);
 
     HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-request");
     HASH_DONE(&h, kxc->hswok_out);
 
     HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-request");
-    hashmp(&h, kxc->c); hashmp(&h, kx->c);
+    hashge(&h, kxc->c); hashge(&h, kx->c);
     HASH_DONE(&h, kxc->hswrq_in);
     HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-confirm");
     HASH_DONE(&h, kxc->hswrq_in);
     HASH_INIT(&h); HASH_STRING(&h, "tripe-switch-confirm");
-    hashmp(&h, kxc->c); hashmp(&h, kx->c);
+    hashge(&h, kxc->c); hashge(&h, kx->c);
     HASH_DONE(&h, kxc->hswok_in);
 
     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
     HASH_DONE(&h, kxc->hswok_in);
 
     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
@@ -595,7 +603,7 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b)
       trace_block(T_CRYPTO, "crypto: expected-reply hash",
                  buf, HASHSZ);
       trace(T_CRYPTO, "crypto: my reply check = %s", mpstr(kxc->ck));
       trace_block(T_CRYPTO, "crypto: expected-reply hash",
                  buf, HASHSZ);
       trace(T_CRYPTO, "crypto: my reply check = %s", mpstr(kxc->ck));
-      trace(T_CRYPTO, "crypto: shared secret = %s", mpstr(r));
+      trace(T_CRYPTO, "crypto: shared secret = %s", gestr(gg, r));
       trace_block(T_CRYPTO, "crypto: outbound switch request",
                  kxc->hswrq_out, HASHSZ);
       trace_block(T_CRYPTO, "crypto: outbound switch confirm",
       trace_block(T_CRYPTO, "crypto: outbound switch request",
                  kxc->hswrq_out, HASHSZ);
       trace_block(T_CRYPTO, "crypto: outbound switch confirm",
@@ -609,19 +617,19 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b)
     /* --- Create a new symmetric keyset --- */
 
     buf_init(b, buf_o, sizeof(buf_o));
     /* --- Create a new symmetric keyset --- */
 
     buf_init(b, buf_o, sizeof(buf_o));
-    buf_putmp(b, kx->c); x = BLEN(b);
-    buf_putmp(b, kxc->c); y = BLEN(b);
-    buf_putmp(b, r); z = BLEN(b);
+    G_TOBUF(gg, b, kx->c); x = BLEN(b);
+    G_TOBUF(gg, b, kxc->c); y = BLEN(b);
+    G_TOBUF(gg, b, r); z = BLEN(b);
     assert(BOK(b));
 
     kxc->ks = ks_gen(BBASE(b), x, y, z, kx->p);
     assert(BOK(b));
 
     kxc->ks = ks_gen(BBASE(b), x, y, z, kx->p);
-    mp_drop(r);
+    G_DESTROY(gg, r);
   }
 
   /* --- Answer the challenge if we need to --- */
 
   if (ck && !kxc->r) {
   }
 
   /* --- Answer the challenge if we need to --- */
 
   if (ck && !kxc->r) {
-    mp *r;
+    ge *r;
     if ((r = getreply(kx, c, ck)) == 0)
       goto bad;
     kxc->r = r;
     if ((r = getreply(kx, c, ck)) == 0)
       goto bad;
     kxc->r = r;
@@ -632,12 +640,12 @@ static int dochallenge(keyexch *kx, unsigned msg, buf *b)
   /* --- Tidy up and go home --- */
 
 tidy:
   /* --- Tidy up and go home --- */
 
 tidy:
-  mp_drop(c);
+  G_DESTROY(gg, c);
   mp_drop(ck);
   return (0);
 
 bad:
   mp_drop(ck);
   return (0);
 
 bad:
-  mp_drop(c);
+  G_DESTROY(gg, c);
   mp_drop(ck);
   return (-1);
 }
   mp_drop(ck);
   return (-1);
 }
@@ -663,7 +671,7 @@ static void resend(keyexch *kx)
       T( trace(T_KEYEXCH, "keyexch: sending prechallenge to `%s'",
               p_name(kx->p)); )
       b = p_txstart(kx->p, MSG_KEYEXCH | KX_PRECHAL);
       T( trace(T_KEYEXCH, "keyexch: sending prechallenge to `%s'",
               p_name(kx->p)); )
       b = p_txstart(kx->p, MSG_KEYEXCH | KX_PRECHAL);
-      buf_putmp(b, kx->c);
+      G_TOBUF(gg, b, kx->c);
       break;
     case KXS_COMMIT:
       T( trace(T_KEYEXCH, "keyexch: sending switch request to `%s'",
       break;
     case KXS_COMMIT:
       T( trace(T_KEYEXCH, "keyexch: sending switch request to `%s'",
@@ -673,7 +681,7 @@ static void resend(keyexch *kx)
       buf_put(b, kx->hc, HASHSZ);
       buf_put(b, kxc->hc, HASHSZ);
       buf_init(&bb, buf_i, sizeof(buf_i));
       buf_put(b, kx->hc, HASHSZ);
       buf_put(b, kxc->hc, HASHSZ);
       buf_init(&bb, buf_i, sizeof(buf_i));
-      buf_putmp(&bb, kxc->r);
+      G_TOBUF(gg, &bb, kxc->r);
       buf_put(&bb, kxc->hswrq_out, HASHSZ);
       buf_flip(&bb);
       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b);
       buf_put(&bb, kxc->hswrq_out, HASHSZ);
       buf_flip(&bb);
       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b);
@@ -724,7 +732,7 @@ static kxchal *matchreply(keyexch *kx, unsigned ty, const octet *hc_in,
 {
   kxchal *kxc;
   buf bb;
 {
   kxchal *kxc;
   buf bb;
-  mp *r = 0;
+  ge *r = 0;
 
   /* --- Check the plaintext portions of the data --- */
 
 
   /* --- Check the plaintext portions of the data --- */
 
@@ -763,25 +771,26 @@ static kxchal *matchreply(keyexch *kx, unsigned ty, const octet *hc_in,
     goto bad;
   }
   buf_init(b, BBASE(&bb), BLEN(&bb));
     goto bad;
   }
   buf_init(b, BBASE(&bb), BLEN(&bb));
-  if ((r = buf_getmp(b)) == 0) {
+  r = G_CREATE(gg);
+  if (G_FROMBUF(gg, b, r)) {
     a_warn("invalid reply packet from `%s'", p_name(kx->p));
     goto bad;
   }
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
     a_warn("invalid reply packet from `%s'", p_name(kx->p));
     goto bad;
   }
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-    trace(T_CRYPTO, "crypto: reply = %s", mpstr(r));
+    trace(T_CRYPTO, "crypto: reply = %s", gestr(gg, r));
   }))
   }))
-  if (!mp_eq(r, kx->rx)) {
+  if (!G_EQ(gg, r, kx->rx)) {
     a_warn("incorrect reply from `%s'", p_name(kx->p));
     goto bad;
   }
 
   /* --- Done --- */
 
     a_warn("incorrect reply from `%s'", p_name(kx->p));
     goto bad;
   }
 
   /* --- Done --- */
 
-  mp_drop(r);
+  G_DESTROY(gg, r);
   return (kxc);
 
 bad:
   return (kxc);
 
 bad:
-  mp_drop(r);
+  if (r) G_DESTROY(gg, r);
   return (0);
 }
 
   return (0);
 }
 
@@ -983,8 +992,8 @@ static void stop(keyexch *kx)
   for (i = 0; i < kx->nr; i++)
     kxc_destroy(kx->r[i]);
   mp_drop(kx->alpha);
   for (i = 0; i < kx->nr; i++)
     kxc_destroy(kx->r[i]);
   mp_drop(kx->alpha);
-  mp_drop(kx->c);
-  mp_drop(kx->rx);
+  G_DESTROY(gg, kx->c);
+  G_DESTROY(gg, kx->rx);
   kx->t_valid = 0;
   kx->f |= KXF_DEAD;
   kx->f &= ~KXF_TIMER;
   kx->t_valid = 0;
   kx->f |= KXF_DEAD;
   kx->f &= ~KXF_TIMER;
@@ -1009,23 +1018,23 @@ static void start(keyexch *kx, time_t now)
 
   kx->f &= ~KXF_DEAD;
   kx->nr = 0;
 
   kx->f &= ~KXF_DEAD;
   kx->nr = 0;
-  kx->alpha = mprand_range(MP_NEW, kpriv.dp.q, &rand_global, 0);
-  kx->c = mpmont_exp(&mg, MP_NEW, kpriv.dp.g, kx->alpha);
-  kx->rx = mpmont_exp(&mg, MP_NEW, kx->kpub.y, kx->alpha);
+  kx->alpha = mprand_range(MP_NEW, gg->r, &rand_global, 0);
+  kx->c = G_CREATE(gg); G_EXP(gg, kx->c, gg->g, kx->alpha);
+  kx->rx = G_CREATE(gg); G_EXP(gg, kx->rx, kx->kpub, kx->alpha);
   kx->s = KXS_CHAL;
   kx->t_valid = now + T_VALID;
 
   HASH_INIT(&h);
   HASH_STRING(&h, "tripe-cookie");
   kx->s = KXS_CHAL;
   kx->t_valid = now + T_VALID;
 
   HASH_INIT(&h);
   HASH_STRING(&h, "tripe-cookie");
-  hashmp(&h, kx->c);
+  hashge(&h, kx->c);
   HASH_DONE(&h, kx->hc);
 
   IF_TRACING(T_KEYEXCH, {
     trace(T_KEYEXCH, "keyexch: creating new challenge");
     IF_TRACING(T_CRYPTO, {
       trace(T_CRYPTO, "crypto: secret = %s", mpstr(kx->alpha));
   HASH_DONE(&h, kx->hc);
 
   IF_TRACING(T_KEYEXCH, {
     trace(T_KEYEXCH, "keyexch: creating new challenge");
     IF_TRACING(T_CRYPTO, {
       trace(T_CRYPTO, "crypto: secret = %s", mpstr(kx->alpha));
-      trace(T_CRYPTO, "crypto: challenge = %s", mpstr(kx->c));
-      trace(T_CRYPTO, "crypto: expected response = %s", mpstr(kx->rx));
+      trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, kx->c));
+      trace(T_CRYPTO, "crypto: expected response = %s", gestr(gg, kx->rx));
       trace_block(T_CRYPTO, "crypto: challenge cookie", kx->hc, HASHSZ);
     })
   })
       trace_block(T_CRYPTO, "crypto: challenge cookie", kx->hc, HASHSZ);
     })
   })
@@ -1050,7 +1059,7 @@ static int checkpub(keyexch *kx)
   if (KEY_EXPIRED(now, kx->texp_kpub)) {
     stop(kx);
     a_warn("public key for `%s' has expired", p_name(kx->p));
   if (KEY_EXPIRED(now, kx->texp_kpub)) {
     stop(kx);
     a_warn("public key for `%s' has expired", p_name(kx->p));
-    dh_pubfree(&kx->kpub);
+    G_COPY(gg, kx->kpub, gg->i);
     kx->f &= ~KXF_PUBKEY;
     return (-1);
   }
     kx->f &= ~KXF_PUBKEY;
     return (-1);
   }
@@ -1160,8 +1169,7 @@ void kx_message(keyexch *kx, unsigned msg, buf *b)
 void kx_free(keyexch *kx)
 {
   stop(kx);
 void kx_free(keyexch *kx)
 {
   stop(kx);
-  if (kx->f & KXF_PUBKEY)
-    dh_pubfree(&kx->kpub);
+  G_DESTROY(gg, kx->kpub);
 }
 
 /* --- @kx_newkeys@ --- *
 }
 
 /* --- @kx_newkeys@ --- *
@@ -1178,13 +1186,8 @@ void kx_free(keyexch *kx)
 
 void kx_newkeys(keyexch *kx)
 {
 
 void kx_newkeys(keyexch *kx)
 {
-  dh_pub dp;
-
-  if (km_getpubkey(p_name(kx->p), &dp, &kx->texp_kpub))
+  if (km_getpubkey(p_name(kx->p), kx->kpub, &kx->texp_kpub))
     return;
     return;
-  if (kx->f & KXF_PUBKEY)
-    dh_pubfree(&kx->kpub);
-  kx->kpub = dp;
   kx->f |= KXF_PUBKEY;
   if ((kx->f & KXF_DEAD) || kx->s != KXS_SWITCH) {
     T( trace(T_KEYEXCH, "keyexch: restarting key negotiation with `%s'",
   kx->f |= KXF_PUBKEY;
   if ((kx->f & KXF_DEAD) || kx->s != KXS_SWITCH) {
     T( trace(T_KEYEXCH, "keyexch: restarting key negotiation with `%s'",
@@ -1212,8 +1215,11 @@ int kx_init(keyexch *kx, peer *p, keyset **ks)
 {
   kx->ks = ks;
   kx->p = p;
 {
   kx->ks = ks;
   kx->p = p;
-  if (km_getpubkey(p_name(p), &kx->kpub, &kx->texp_kpub))
+  kx->kpub = G_CREATE(gg);
+  if (km_getpubkey(p_name(p), kx->kpub, &kx->texp_kpub)) {
+    G_DESTROY(gg, kx->kpub);
     return (-1);
     return (-1);
+  }
   kx->f = KXF_DEAD | KXF_PUBKEY;
   start(kx, time(0));
   resend(kx);
   kx->f = KXF_DEAD | KXF_PUBKEY;
   start(kx, time(0));
   resend(kx);
index 54a31b0b981e6fb686a0cf4779743d9ef8f85459..a10971344fdf6356404d08c1ee975dcb34c4dc1d 100644 (file)
--- a/keymgmt.c
+++ b/keymgmt.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: keymgmt.c,v 1.3 2001/06/22 19:40:36 mdw Exp $
+ * $Id: keymgmt.c,v 1.4 2004/04/03 12:35:13 mdw Exp $
  *
  * Key loading and storing
  *
  *
  * Key loading and storing
  *
@@ -29,6 +29,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: keymgmt.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: keymgmt.c,v $
+ * Revision 1.4  2004/04/03 12:35:13  mdw
+ * Support elliptic curve key exchange.
+ *
  * Revision 1.3  2001/06/22 19:40:36  mdw
  * Support expiry of other peers' public keys.
  *
  * Revision 1.3  2001/06/22 19:40:36  mdw
  * Support expiry of other peers' public keys.
  *
@@ -46,8 +49,8 @@
 
 /*----- Global variables --------------------------------------------------*/
 
 
 /*----- Global variables --------------------------------------------------*/
 
-mpmont mg;
-dh_priv kpriv;
+group *gg;
+mp *kpriv;
 
 /*----- Static variables --------------------------------------------------*/
 
 
 /*----- Static variables --------------------------------------------------*/
 
@@ -55,6 +58,124 @@ static key_file *kf_pub;
 static const char *kr_priv, *kr_pub, *tag_priv;
 static fwatch w_priv, w_pub;
 
 static const char *kr_priv, *kr_pub, *tag_priv;
 static fwatch w_priv, w_pub;
 
+/*----- Key groups --------------------------------------------------------*/
+
+typedef struct kgops {
+  const char *ty;
+  const char *(*loadpriv)(key_data *, group **, mp **, dstr *);
+  const char *(*loadpub)(key_data *, group **, ge **, dstr *);
+} kgops;
+
+/* --- Diffie-Hellman --- */
+
+static const char *kgdh_priv(key_data *kd, group **g, mp **x, dstr *t)
+{
+  key_packstruct kps[DH_PRIVFETCHSZ];
+  key_packdef *kp;
+  dh_priv dp;
+  const char *e;
+  int rc;
+
+  kp = key_fetchinit(dh_privfetch, kps, &dp);
+  if ((rc = key_unpack(kp, kd, t)) != 0) {
+    e = key_strerror(rc);
+    goto done;
+  }
+  *g = group_prime(&dp.dp);
+  *x = MP_COPY(dp.x);
+  e = 0;
+done:
+  key_fetchdone(kp);
+  return (e);
+}
+
+static const char *kgdh_pub(key_data *kd, group **g, ge **p, dstr *t)
+{
+  key_packstruct kps[DH_PUBFETCHSZ];
+  key_packdef *kp;
+  dh_pub dp;
+  const char *e;
+  int rc;
+
+  kp = key_fetchinit(dh_pubfetch, kps, &dp);
+  if ((rc = key_unpack(kp, kd, t)) != 0) {
+    e = key_strerror(rc);
+    goto done;
+  }
+  *g = group_prime(&dp.dp);
+  *p = G_CREATE(*g);
+  if (G_FROMINT(*g, *p, dp.y)) {
+    e = "bad public value";
+    goto done;
+  }
+  e = 0;
+done:
+  key_fetchdone(kp);
+  return (e);
+}
+
+static const kgops kgdh_ops = { "tripe-dh", kgdh_priv, kgdh_pub };
+
+/* --- Elliptic curve --- */
+
+static const char *kgec_priv(key_data *kd, group **g, mp **x, dstr *t)
+{
+  key_packstruct kps[EC_PRIVFETCHSZ];
+  key_packdef *kp;
+  ec_priv ep;
+  ec_info ei;
+  const char *e;
+  int rc;
+
+  kp = key_fetchinit(ec_privfetch, kps, &ep);
+  if ((rc = key_unpack(kp, kd, t)) != 0) {
+    e = key_strerror(rc);
+    goto done;
+  }
+  if ((e = ec_getinfo(&ei, ep.cstr)) != 0)
+    goto done;
+  *g = group_ec(&ei);
+  *x = MP_COPY(ep.x);
+  e = 0;
+done:
+  key_fetchdone(kp);
+  return (e);
+}
+
+static const char *kgec_pub(key_data *kd, group **g, ge **p, dstr *t)
+{
+  key_packstruct kps[EC_PUBFETCHSZ];
+  key_packdef *kp;
+  ec_pub ep;
+  ec_info ei;
+  const char *e;
+  int rc;
+
+  kp = key_fetchinit(ec_pubfetch, kps, &ep);
+  if ((rc = key_unpack(kp, kd, t)) != 0) {
+    e = key_strerror(rc);
+    goto done;
+  }
+  if ((e = ec_getinfo(&ei, ep.cstr)) != 0)
+    goto done;
+  *g = group_ec(&ei);
+  *p = G_CREATE(*g);
+  if (G_FROMEC(*g, *p, &ep.p)) {
+    e = "bad public point";
+    goto done;
+  }
+  e = 0;
+done:
+  key_fetchdone(kp);
+  return (e);
+}
+
+static const kgops kgec_ops = { "tripe-ec", kgec_priv, kgec_pub };
+
+/* --- Table of supported key types --- */
+
+static const kgops *kgtab[] = { &kgdh_ops, &kgec_ops, 0 };
+
 /*----- Main code ---------------------------------------------------------*/
 
 /* --- @keymoan@ --- *
 /*----- Main code ---------------------------------------------------------*/
 
 /* --- @keymoan@ --- *
@@ -70,60 +191,112 @@ static fwatch w_priv, w_pub;
  */
 
 static void keymoan(const char *file, int line, const char *msg, void *p)
  */
 
 static void keymoan(const char *file, int line, const char *msg, void *p)
-{
-  a_warn("%s:%i: error: %s", file, line, msg);
-}
+  { a_warn("%s:%i: error: %s", file, line, msg); }
 
 /* --- @loadpriv@ --- *
  *
  * Arguments:  @dstr *d@ = string to write errors in
 
 /* --- @loadpriv@ --- *
  *
  * Arguments:  @dstr *d@ = string to write errors in
- *             @dh_priv *dh@ = where to store the key
  *
  * Returns:    Zero if OK, nonzero on error.
  *
  * Use:                Loads the private key from its keyfile.
  */
 
  *
  * Returns:    Zero if OK, nonzero on error.
  *
  * Use:                Loads the private key from its keyfile.
  */
 
-static int loadpriv(dstr *d, dh_priv *dh)
+static int loadpriv(dstr *d)
 {
   key_file kf;
 {
   key_file kf;
-  key_packstruct kps[DH_PRIVFETCHSZ];
-  key_packdef *kp;
-  dh_priv mydh;
-  int rc = 0;
-  int e;
+  key *k;
+  key_data *kd;
+  dstr t = DSTR_INIT;
+  group *g = 0;
+  mp *x = 0;
+  int rc = -1;
+  const kgops **ko;
+  const char *e;
+
+  /* --- Open the private key file --- */
 
   if (key_open(&kf, kr_priv, KOPEN_READ, keymoan, 0)) {
     dstr_putf(d, "error reading private keyring `%s': %s",
              kr_priv, strerror(errno));
 
   if (key_open(&kf, kr_priv, KOPEN_READ, keymoan, 0)) {
     dstr_putf(d, "error reading private keyring `%s': %s",
              kr_priv, strerror(errno));
-    rc = -1;
-  } else {
-    T( trace(T_KEYMGMT, "keymgmt: loaded private keyring `%s'", kr_priv); )
-    kp = key_fetchinit(dh_privfetch, kps, &mydh);
-    if ((e = key_fetchbyname(kp, &kf, tag_priv)) != 0) {
-      dstr_putf(d, "error loading private key `%s': %s",
-               tag_priv, key_strerror(e));
-      rc = -1;
-    } else {
-      dh->dp.p = MP_COPY(mydh.dp.p);
-      dh->dp.q = MP_COPY(mydh.dp.q);
-      dh->dp.g = MP_COPY(mydh.dp.g);
-      dh->x = MP_COPY(mydh.x);
-      dh->y = MP_COPY(mydh.y);      
-      IF_TRACING(T_KEYMGMT, {
-       trace(T_KEYMGMT, "keymgmt: extracted private key `%s'", tag_priv);
-       IF_TRACING(T_CRYPTO, {
-         trace(T_CRYPTO, "crypto: p = %s", mpstr(kpriv.dp.p));
-         trace(T_CRYPTO, "crypto: q = %s", mpstr(kpriv.dp.q));
-         trace(T_CRYPTO, "crypto: g = %s", mpstr(kpriv.dp.g));
-         trace(T_CRYPTO, "crypto: x = %s", mpstr(kpriv.x));
-         trace(T_CRYPTO, "crypto: g^x = %s", mpstr(kpriv.y));
-       })
-      })
+    goto done_0;
+  }
+
+  /* --- Find the private key --- */
+
+  if (key_qtag(&kf, tag_priv, &t, &k, &kd)) {
+    dstr_putf(d, "private key `%s' not found in keyring `%s'",
+             tag_priv, kr_priv);
+    goto done_1;
+  }
+
+  /* --- Look up the key type in the table --- */
+
+  for (ko = kgtab; *ko; ko++) {
+    if (strcmp((*ko)->ty, k->type) == 0)
+      goto tymatch;
+  }
+  dstr_putf(d, "private key `%s' has unknown type `%s'", t.buf, k->type);
+  goto done_1;
+tymatch:;
+
+  /* --- Load the key --- */
+
+  if ((e = (*ko)->loadpriv(kd, &g, &x, &t)) != 0) {
+    dstr_putf(d, "error reading private key `%s': %s", t.buf, e);
+    goto done_1;
+  }
+
+  /* --- Check that the key is sensible --- */
+
+  if ((e = G_CHECK(g, &rand_global)) != 0) {
+    dstr_putf(d, "bad group in private key `%s': %s", t.buf, e);
+    goto done_1;
+  }
+
+  /* --- Good, we're happy --- *
+   *
+   * Dodginess!  We change the group over here, but don't free any old group
+   * elements.  This assumes that the new group is basically the same as the
+   * old one, and will happily adopt the existing elements.  If it isn't,
+   * then we lose badly.  Check this, then.
+   */
+
+  if (gg) {
+    if (!group_samep(g, gg)) {
+      dstr_putf(d, "private key `%s' has different group", t.buf);
+      goto done_1;
     }
     }
-    key_fetchdone(kp);
-    key_close(&kf);
+    G_DESTROYGROUP(gg);
   }
   }
+  if (kpriv)
+    mp_drop(kpriv);
+
+  /* --- Dump out the group --- */
+
+  IF_TRACING(T_KEYMGMT, {
+    trace(T_KEYMGMT, "keymgmt: extracted private key `%s'", t.buf);
+    IF_TRACING(T_CRYPTO, {
+      trace(T_CRYPTO, "crypto: r = %s", mpstr(g->r));
+      trace(T_CRYPTO, "crypto: h = %s", mpstr(g->h));
+      trace(T_CRYPTO, "crypto: x = %s", mpstr(x));
+    })
+  })
+
+  /* --- Success! --- */
+
+  gg = g; g = 0;
+  kpriv = x; x = 0;
+  rc = 0;
+
+  /* --- Tidy up --- */
+
+done_1:
+  key_close(&kf);
+done_0:
+  dstr_destroy(&t);
+  if (x) mp_drop(x);
+  if (g) G_DESTROYGROUP(g);
   return (rc);
 }
 
   return (rc);
 }
 
@@ -163,7 +336,6 @@ static int loadpub(dstr *d)
 int km_interval(void)
 {
   dstr d = DSTR_INIT;
 int km_interval(void)
 {
   dstr d = DSTR_INIT;
-  dh_priv dh;
   key_file *kf;
   int reload = 0;
 
   key_file *kf;
   int reload = 0;
 
@@ -172,15 +344,10 @@ int km_interval(void)
   if (fwatch_update(&w_priv, kr_priv)) {
     T( trace(T_KEYMGMT, "keymgmt: private keyring updated: reloading..."); )
     DRESET(&d);
   if (fwatch_update(&w_priv, kr_priv)) {
     T( trace(T_KEYMGMT, "keymgmt: private keyring updated: reloading..."); )
     DRESET(&d);
-    if (loadpriv(&d, &dh))
+    if (loadpriv(&d))
       a_warn("%s -- ignoring changes", d.buf);
       a_warn("%s -- ignoring changes", d.buf);
-    else {
+    else
       reload = 1;
       reload = 1;
-      mpmont_destroy(&mg);
-      dh_privfree(&kpriv);
-      kpriv = dh;
-      mpmont_create(&mg, kpriv.dp.p);
-    }
   }
 
   /* --- Now check the public keys --- */
   }
 
   /* --- Now check the public keys --- */
@@ -225,9 +392,8 @@ void km_init(const char *priv, const char *pub, const char *tag)
   fwatch_init(&w_pub, kr_pub);
 
   DRESET(&d);
   fwatch_init(&w_pub, kr_pub);
 
   DRESET(&d);
-  if (loadpriv(&d, &kpriv))
+  if (loadpriv(&d))
     die(EXIT_FAILURE, "%s", d.buf);
     die(EXIT_FAILURE, "%s", d.buf);
-  mpmont_create(&mg, kpriv.dp.p);
   if (loadpub(&d))
     die(EXIT_FAILURE, "%s", d.buf);
 }
   if (loadpub(&d))
     die(EXIT_FAILURE, "%s", d.buf);
 }
@@ -235,7 +401,7 @@ void km_init(const char *priv, const char *pub, const char *tag)
 /* --- @km_getpubkey@ --- *
  *
  * Arguments:  @const char *tag@ = public key tag to load
 /* --- @km_getpubkey@ --- *
  *
  * Arguments:  @const char *tag@ = public key tag to load
- *             @dh_pub *kpub@ = where to put the public key
+ *             @ge *kpub@ = where to put the public key
  *             @time_t *t_exp@ = where to put the expiry time
  *
  * Returns:    Zero if OK, nonzero if it failed.
  *             @time_t *t_exp@ = where to put the expiry time
  *
  * Returns:    Zero if OK, nonzero if it failed.
@@ -243,45 +409,79 @@ void km_init(const char *priv, const char *pub, const char *tag)
  * Use:                Fetches a public key from the keyring.
  */
 
  * Use:                Fetches a public key from the keyring.
  */
 
-int km_getpubkey(const char *tag, dh_pub *kpub, time_t *t_exp)
+int km_getpubkey(const char *tag, ge *kpub, time_t *t_exp)
 {
 {
-  key_packstruct kps[DH_PUBFETCHSZ];
-  key_packdef *kp;
   key *k;
   key *k;
-  dh_pub dp;
-  int e;
+  key_data *kd;
+  dstr t = DSTR_INIT;
+  const kgops **ko;
+  const char *e;
+  group *g = 0;
+  ge *p = 0;
+  int rc = -1;
+
+  /* --- Find the key --- */
+
+  if (key_qtag(kf_pub, tag, &t, &k, &kd)) {
+    a_warn("private key `%s' not found in keyring `%s'", tag_priv, kr_priv);
+    goto done;
+  }
 
 
-  kp = key_fetchinit(dh_pubfetch, kps, &dp);
-  if ((k = key_bytag(kf_pub, tag)) == 0)
-    e = KERR_NOTFOUND;
-  else
-    e = key_fetch(kp, k);
-  key_fetchdone(kp);
-  if (e) {
-    a_warn("error loading public key `%s': %s", tag, key_strerror(e));
-    return (-1);
+  /* --- Look up the key type in the table --- */
+
+  for (ko = kgtab; *ko; ko++) {
+    if (strcmp((*ko)->ty, k->type) == 0)
+      goto tymatch;
+  }
+  a_warn("public key `%s' has unknown type `%s'", t.buf, k->type);
+  goto done;
+tymatch:;
+
+  /* --- Load the key --- */
+
+  if ((e = (*ko)->loadpub(kd, &g, &p, &t)) != 0) {
+    a_warn("error reading public key `%s': %s", t.buf, e);
+    goto done;
+  }
+
+  /* --- Ensure that the group is correct --- *
+   *
+   * Dodginess!  We assume that if this works, our global group is willing to
+   * adopt this public element.  Probably reasonable.
+   */
+
+  if (!group_samep(gg, g)) {
+    a_warn("public key `%s' has incorrect group", t.buf);
+    goto done;
+  }
+
+  /* --- Check the public group element --- */
+
+  if (group_check(gg, p)) {
+    a_warn("public key `%s' has bad public group element", t.buf);
+    goto done;
   }
   }
+
+  /* --- Dump the public key --- */
+
   IF_TRACING(T_KEYMGMT, {
   IF_TRACING(T_KEYMGMT, {
-    trace(T_KEYMGMT, "keymgmt: extracted public key `%s'", tag);
-    IF_TRACING(T_CRYPTO, {
-      trace(T_CRYPTO, "crypto: p = %s", mpstr(dp.dp.p));
-      trace(T_CRYPTO, "crypto: q = %s", mpstr(dp.dp.q));
-      trace(T_CRYPTO, "crypto: g = %s", mpstr(dp.dp.g));
-      trace(T_CRYPTO, "crypto: g^x = %s", mpstr(dp.y));
-    })
+    trace(T_KEYMGMT, "keymgmt: extracted public key `%s'", t.buf);
+    trace(T_CRYPTO, "crypto: p = %s", gestr(gg, p));
   })
   })
-  if (!mp_eq(dp.dp.p, kpriv.dp.p) ||
-      !mp_eq(dp.dp.q, kpriv.dp.q) ||
-      !mp_eq(dp.dp.g, kpriv.dp.g)) {
-    a_warn("public key `%s' has different group from private key", tag);
-    return (-1);
-  }
-  kpub->dp.p = MP_COPY(dp.dp.p);
-  kpub->dp.q = MP_COPY(dp.dp.q);
-  kpub->dp.g = MP_COPY(dp.dp.g);
-  kpub->y = MP_COPY(dp.y);
+
+  /* --- OK, accept the public key --- */
+
   *t_exp = k->exp;
   *t_exp = k->exp;
-  return (0);
+  G_COPY(gg, kpub, p);
+  rc = 0;
+
+  /* --- Tidy up --- */
+
+done:
+  if (p) G_DESTROY(g, p);
+  if (g) G_DESTROYGROUP(g);
+  dstr_destroy(&t);
+  return (rc);
 }
 
 /*----- That's all, folks -------------------------------------------------*/
 }
 
 /*----- That's all, folks -------------------------------------------------*/
index c66b45f4b703363f951d8f72d93dc01119ce8496..bca2cff16595be20f5e98c7174c36f6a0540e04c 100644 (file)
--- a/mallory.c
+++ b/mallory.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: mallory.c,v 1.2 2003/10/15 09:31:06 mdw Exp $
+ * $Id: mallory.c,v 1.3 2004/04/03 12:35:13 mdw Exp $
  *
  * An evil proxy for TrIPE
  *
  *
  * An evil proxy for TrIPE
  *
@@ -29,6 +29,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: mallory.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: mallory.c,v $
+ * Revision 1.3  2004/04/03 12:35:13  mdw
+ * Support elliptic curve key exchange.
+ *
  * Revision 1.2  2003/10/15 09:31:06  mdw
  * Make forking work properly.
  *
  * Revision 1.2  2003/10/15 09:31:06  mdw
  * Make forking work properly.
  *
@@ -73,7 +76,6 @@
 #include <catacomb/key.h>
 
 #include <catacomb/mp.h>
 #include <catacomb/key.h>
 
 #include <catacomb/mp.h>
-#include <catacomb/mpmont.h>
 #include <catacomb/mprand.h>
 #include <catacomb/dh.h>
 
 #include <catacomb/mprand.h>
 #include <catacomb/dh.h>
 
index dac92b7bbfcdfa79bc953ca7eba04c3f54ff6521..c3465e79b93c2398b5735882b583e3088743c1eb 100644 (file)
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: servutil.c,v 1.3 2001/06/19 22:08:11 mdw Exp $
+ * $Id: servutil.c,v 1.4 2004/04/03 12:35:13 mdw Exp $
  *
  * Various handy server-only utilities
  *
  *
  * Various handy server-only utilities
  *
@@ -29,6 +29,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: servutil.c,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: servutil.c,v $
+ * Revision 1.4  2004/04/03 12:35:13  mdw
+ * Support elliptic curve key exchange.
+ *
  * Revision 1.3  2001/06/19 22:08:11  mdw
  * Use magic number for packet size.
  *
  * Revision 1.3  2001/06/19 22:08:11  mdw
  * Use magic number for packet size.
  *
@@ -68,6 +71,24 @@ const char *mpstr(mp *m)
   return ((const char *)buf_t);
 }
 
   return ((const char *)buf_t);
 }
 
+/* --- @gestr@ --- *
+ *
+ * Arguments:  @group *g@ = a group
+ *             @ge *x@ = a group element
+ *
+ * Returns:    A pointer to the element's textual representation.
+ *
+ * Use:                Converts a group element to a string.  Corrupts
+ *             @buf_t@.
+ */
+
+const char *gestr(group *g, ge *x)
+{
+  if (group_writestring(g, x, (char *)buf_t, sizeof(buf_t)))
+    return ("<failed>");
+  return ((const char *)buf_t);
+}
+
 /* --- @timestr@ --- *
  *
  * Arguments:  @time_t t@ = a time to convert
 /* --- @timestr@ --- *
  *
  * Arguments:  @time_t t@ = a time to convert
index db9cb35f63351eaf0e2aa60ddf5a811696d69c03..8c4730e5ae2f25cd8ed93837d1ed444b029e8050 100755 (executable)
@@ -105,6 +105,7 @@ case "$1" in
     $tripectl -D -s -p$tripe \
       -f${logfile-@logfile@} \
       -P${pidfile-@pidfile@} \
     $tripectl -D -s -p$tripe \
       -f${logfile-@logfile@} \
       -P${pidfile-@pidfile@} \
+      ${keytag+-S-t}$keytag \
       ${addr+-S-b}$addr \
       ${port+-S-p}${port} \
       ${user+-S-u}${user} \
       ${addr+-S-b}$addr \
       ${port+-S-p}${port} \
       ${user+-S-u}${user} \
index 36bb132669c13bc0c50b616e82b0dd67934e045d..dd2de57e710931c9087529d54db544640d782371 100644 (file)
@@ -6,6 +6,11 @@
 # keyrings, and where its admin socket and logfile are kept.
 # TRIPEDIR=/etc/tripe
 
 # keyrings, and where its admin socket and logfile are kept.
 # TRIPEDIR=/etc/tripe
 
+# The name of the private key to use.  This is usually `tripe-dh' for
+# integer Diffie-Hellman keys (the default) or `tripe-ec' for elliptic
+# curve keys.
+# keytag=tripe-dh
+
 # The address you want tripe to bind to.  By default, tripe will accept
 # packets to any address acceptable to the host, and send packets from the
 # most appropriate address for the destination; setting this means it will
 # The address you want tripe to bind to.  By default, tripe will accept
 # packets to any address acceptable to the host, and send packets from the
 # most appropriate address for the destination; setting this means it will
diff --git a/tripe.h b/tripe.h
index 385c45a24ca07a5c4790a607777e0dc4899e7482..2929200c74bde7348fcc1886a8e04c3581695983 100644 (file)
--- a/tripe.h
+++ b/tripe.h
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
 /* -*-c-*-
  *
- * $Id: tripe.h,v 1.17 2003/10/15 09:30:18 mdw Exp $
+ * $Id: tripe.h,v 1.18 2004/04/03 12:35:13 mdw Exp $
  *
  * Main header file for TrIPE
  *
  *
  * Main header file for TrIPE
  *
@@ -29,6 +29,9 @@
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: tripe.h,v $
 /*----- Revision history --------------------------------------------------* 
  *
  * $Log: tripe.h,v $
+ * Revision 1.18  2004/04/03 12:35:13  mdw
+ * Support elliptic curve key exchange.
+ *
  * Revision 1.17  2003/10/15 09:30:18  mdw
  * Add support for Ethereal protocol analysis.
  *
  * Revision 1.17  2003/10/15 09:30:18  mdw
  * Add support for Ethereal protocol analysis.
  *
 #include <catacomb/rand.h>
 
 #include <catacomb/mp.h>
 #include <catacomb/rand.h>
 
 #include <catacomb/mp.h>
-#include <catacomb/mpmont.h>
 #include <catacomb/mprand.h>
 #include <catacomb/dh.h>
 #include <catacomb/mprand.h>
 #include <catacomb/dh.h>
+#include <catacomb/ec.h>
+#include <catacomb/ec-keys.h>
+#include <catacomb/group.h>
 
 #include "tripe-protocol.h"
 #include "util.h"
 
 #include "tripe-protocol.h"
 #include "util.h"
@@ -278,8 +283,8 @@ typedef struct keyset {
 
 typedef struct kxchal {
   struct keyexch *kx;                  /* Pointer back to key exchange */
 
 typedef struct kxchal {
   struct keyexch *kx;                  /* Pointer back to key exchange */
-  mp *c;                               /* Responder's challenge */
-  mp *r;                               /* My reply to the challenge */
+  ge *c;                               /* Responder's challenge */
+  ge *r;                               /* My reply to the challenge */
   keyset *ks;                          /* Pointer to temporary keyset */
   unsigned f;                          /* Various useful flags */
   sel_timer t;                         /* Response timer for challenge */
   keyset *ks;                          /* Pointer to temporary keyset */
   unsigned f;                          /* Various useful flags */
   sel_timer t;                         /* Response timer for challenge */
@@ -297,11 +302,11 @@ typedef struct keyexch {
   unsigned f;                          /* Various useful flags */
   unsigned s;                          /* Current state in exchange */
   sel_timer t;                         /* Timer for next exchange */
   unsigned f;                          /* Various useful flags */
   unsigned s;                          /* Current state in exchange */
   sel_timer t;                         /* Timer for next exchange */
-  dh_pub kpub;                         /* Peer's public key */
+  ge *kpub;                            /* Peer's public key */
   time_t texp_kpub;                    /* Expiry time for public key */
   mp *alpha;                           /* My temporary secret */
   time_t texp_kpub;                    /* Expiry time for public key */
   mp *alpha;                           /* My temporary secret */
-  mp *c;                               /* My challenge */
-  mp *rx;                              /* The expected response */
+  ge *c;                               /* My challenge */
+  ge *rx;                              /* The expected response */
   unsigned nr;                         /* Number of extant responses */
   time_t t_valid;                      /* When this exchange goes bad */
   octet hc[HASHSZ];                    /* Hash of my challenge */
   unsigned nr;                         /* Number of extant responses */
   time_t t_valid;                      /* When this exchange goes bad */
   octet hc[HASHSZ];                    /* Hash of my challenge */
@@ -415,8 +420,8 @@ typedef struct admin {
 /*----- Global variables --------------------------------------------------*/
 
 extern sel_state sel;                  /* Global I/O event state */
 /*----- Global variables --------------------------------------------------*/
 
 extern sel_state sel;                  /* Global I/O event state */
-extern dh_priv kpriv;                  /* Our private key */
-extern mpmont mg;                      /* Montgomery context for DH group */
+extern group *gg;                      /* The group we work in */
+extern mp *kpriv;                      /* Our private key */
 extern octet buf_i[PKBUFSZ], buf_o[PKBUFSZ], buf_t[PKBUFSZ];
 
 #ifndef NTRACE
 extern octet buf_i[PKBUFSZ], buf_o[PKBUFSZ], buf_t[PKBUFSZ];
 
 #ifndef NTRACE
@@ -458,7 +463,7 @@ extern void km_init(const char */*kr_priv*/, const char */*kr_pub*/,
 /* --- @km_getpubkey@ --- *
  *
  * Arguments:  @const char *tag@ = public key tag to load
 /* --- @km_getpubkey@ --- *
  *
  * Arguments:  @const char *tag@ = public key tag to load
- *             @dh_pub *kpub@ = where to put the public key
+ *             @ge *kpub@ = where to put the public key
  *             @time_t *t_exp@ = where to put the expiry time
  *
  * Returns:    Zero if OK, nonzero if it failed.
  *             @time_t *t_exp@ = where to put the expiry time
  *
  * Returns:    Zero if OK, nonzero if it failed.
@@ -466,7 +471,7 @@ extern void km_init(const char */*kr_priv*/, const char */*kr_pub*/,
  * Use:                Fetches a public key from the keyring.
  */
 
  * Use:                Fetches a public key from the keyring.
  */
 
-extern int km_getpubkey(const char */*tag*/, dh_pub */*kpub*/,
+extern int km_getpubkey(const char */*tag*/, ge */*kpub*/,
                        time_t */*t_exp*/);
 
 /*----- Key exchange ------------------------------------------------------*/
                        time_t */*t_exp*/);
 
 /*----- Key exchange ------------------------------------------------------*/
@@ -988,6 +993,19 @@ extern void tun_destroy(tunnel */*t*/);
 
 extern const char *mpstr(mp */*m*/);
 
 
 extern const char *mpstr(mp */*m*/);
 
+/* --- @gestr@ --- *
+ *
+ * Arguments:  @group *g@ = a group
+ *             @ge *x@ = a group element
+ *
+ * Returns:    A pointer to the element's textual representation.
+ *
+ * Use:                Converts a group element to a string.  Corrupts
+ *             @buf_t@.
+ */
+
+extern const char *gestr(group */*g*/, ge */*x*/);
+
 /* --- @timestr@ --- *
  *
  * Arguments:  @time_t t@ = a time to convert
 /* --- @timestr@ --- *
  *
  * Arguments:  @time_t t@ = a time to convert