chiark / gitweb /
server: Use the new kdata system.
authorMark Wooding <mdw@distorted.org.uk>
Wed, 25 Jan 2012 23:18:20 +0000 (23:18 +0000)
committerMark Wooding <mdw@distorted.org.uk>
Mon, 7 May 2012 14:35:11 +0000 (15:35 +0100)
Challenges use the algorithms associated with the master key.  This will
continue to be the case, since there isn't a specific private or public
key to associate with the challenge.

It looks like the keyexch subsystem has been turned upside-down, but
apart from the initialization and key refresh it's all just a matter of
adding the necessary indirections into group and algorithm lookups.

Since algorithms are now (logically, at least) distinct for different
peer associations, allow a `peer' argument to the ALGS command, and pass
the correct information to the ifup script so that it can calculate the
MTU properly.

At this point, we no longer need the compatibility interface in keymgmt,
so remove it, and the molly-guard preventing updates to the master key.

py/tripe.py.in
server/admin.c
server/chal.c
server/keyexch.c
server/keymgmt.c
server/keyset.c
server/tripe-admin.5.in
server/tripe.h
svc/watch.in

index cefb667f0e291c6225a566e76648e16e01c2f3ae..78a305b86a570b1c6b057c8c19ed3029e4fda8b4 100644 (file)
@@ -836,8 +836,9 @@ class TripeCommandDispatcher (TripeConnection):
                               list(addr)))
   def addr(me, peer):
     return _oneline(me.command('ADDR', peer))
-  def algs(me):
-    return _keyvals(me.command('ALGS'))
+  def algs(me, peer = None):
+    return _keyvals(me.command('ALGS',
+                               *((peer is not None and [peer]) or [])))
   def checkchal(me, chal):
     return _simple(me.command('CHECKCHAL', chal))
   def daemon(me):
index e892054773a14a6acce73f951a762ec7428bc604..0fb57cd8645e6061f02bf8624ed1c8af6d2e0b41 100644 (file)
@@ -1697,28 +1697,42 @@ static void acmd_bgcancel(admin *a, unsigned ac, char *av[])
 
 static void acmd_algs(admin *a, unsigned ac, char *av[])
 {
+  peer *p;
+  const kdata *kd;
+  const group *g;
+  const algswitch *algs;
+
+  if (!ac)
+    kd = master;
+  else {
+    if ((p = a_findpeer(a, av[0])) == 0) return;
+    kd = p->kx.kpriv;
+  }
+  g = kd->g;
+  algs = &kd->algs;
+
   a_info(a,
-        "kx-group=%s", gg->ops->name,
-        "kx-group-order-bits=%lu", (unsigned long)mp_bits(gg->r),
-        "kx-group-elt-bits=%lu", (unsigned long)gg->nbits,
+        "kx-group=%s", g->ops->name,
+        "kx-group-order-bits=%lu", (unsigned long)mp_bits(g->r),
+        "kx-group-elt-bits=%lu", (unsigned long)g->nbits,
         A_END);
   a_info(a,
-        "hash=%s", algs.h->name,
-        "mgf=%s", algs.mgf->name,
-        "hash-sz=%lu", (unsigned long)algs.h->hashsz,
+        "hash=%s", algs->h->name,
+        "mgf=%s", algs->mgf->name,
+        "hash-sz=%lu", (unsigned long)algs->h->hashsz,
         A_END);
   a_info(a,
-        "cipher=%s", algs.c->name,
-        "cipher-keysz=%lu", (unsigned long)algs.cksz,
-        "cipher-blksz=%lu", (unsigned long)algs.c->blksz,
+        "cipher=%s", algs->c->name,
+        "cipher-keysz=%lu", (unsigned long)algs->cksz,
+        "cipher-blksz=%lu", (unsigned long)algs->c->blksz,
         A_END);
   a_info(a,
-        "cipher-data-limit=%lu", (unsigned long)algs.expsz,
+        "cipher-data-limit=%lu", (unsigned long)algs->expsz,
         A_END);
   a_info(a,
-        "mac=%s", algs.m->name,
-        "mac-keysz=%lu", (unsigned long)algs.mksz,
-        "mac-tagsz=%lu", (unsigned long)algs.tagsz,
+        "mac=%s", algs->m->name,
+        "mac-keysz=%lu", (unsigned long)algs->mksz,
+        "mac-tagsz=%lu", (unsigned long)algs->tagsz,
         A_END);
   a_ok(a);
 }
@@ -1924,7 +1938,7 @@ static void acmd_help(admin */*a*/, unsigned /*ac*/, char */*av*/[]);
 static const acmd acmdtab[] = {
   { "add",     "[OPTIONS] PEER ADDR ...", 2,   0xffff, acmd_add },
   { "addr",    "PEER",                 1,      1,      acmd_addr },
-  { "algs",    0,                      0,      0,      acmd_algs },
+  { "algs",    "[PEER]",               0,      1,      acmd_algs },
   { "bgcancel",        "TAG",                  1,      1,      acmd_bgcancel },
   { "checkchal", "CHAL",               1,      1,      acmd_checkchal },
   { "daemon",  0,                      0,      0,      acmd_daemon },
index 3824bb6312ce91b0bab0ba8f6c38b2bd93ddd0bf..12b64e21ab4a7676c8a6182c794be8560ebdc864 100644 (file)
@@ -47,16 +47,16 @@ static seqwin iseq;
 
 static void c_genkey(void)
 {
-  if (mac && GM_CLASS(mac) == algs.m && oseq < 0x07ffffff) return;
+  if (mac && GM_CLASS(mac) == master->algs.m && oseq < 0x07ffffff) return;
   if (mac) GM_DESTROY(mac);
-  assert(algs.mksz < sizeof(buf_t));
-  rand_get(RAND_GLOBAL, buf_t, algs.mksz);
-  mac = GM_KEY(algs.m, buf_t, algs.mksz);
+  assert(master->algs.mksz < sizeof(buf_t));
+  rand_get(RAND_GLOBAL, buf_t, master->algs.mksz);
+  mac = GM_KEY(master->algs.m, buf_t, master->algs.mksz);
   oseq = 0;
   seq_reset(&iseq);
   IF_TRACING(T_CHAL, {
     trace(T_CHAL, "chal: generated new challenge key");
-    trace_block(T_CRYPTO, "chal: new key", buf_t, algs.mksz);
+    trace_block(T_CRYPTO, "chal: new key", buf_t, master->algs.mksz);
   })
 }
 
@@ -79,7 +79,7 @@ int c_new(buf *b)
   if (buf_putu32(b, oseq++)) return (-1);
   h = GM_INIT(mac);
   GH_HASH(h, p, BCUR(b) - p);
-  buf_put(b, GH_DONE(h, 0), algs.tagsz);
+  buf_put(b, GH_DONE(h, 0), master->algs.tagsz);
   GH_DESTROY(h);
   if (BBAD(b)) return (-1);
   IF_TRACING(T_CHAL, {
@@ -101,7 +101,7 @@ int c_new(buf *b)
 int c_check(buf *b)
 {
   const octet *p;
-  size_t sz = 4 + algs.tagsz;
+  size_t sz = 4 + master->algs.tagsz;
   uint32 seq;
   ghash *h;
   int ok;
@@ -117,7 +117,7 @@ int c_check(buf *b)
   }
   h = GM_INIT(mac);
   GH_HASH(h, p, 4);
-  ok = (memcmp(GH_DONE(h, 0), p + 4, algs.tagsz) == 0);
+  ok = (memcmp(GH_DONE(h, 0), p + 4, master->algs.tagsz) == 0);
   GH_DESTROY(h);
   if (!ok) {
     a_warn("CHAL", "incorrect-tag", A_END);
index 4280f86e04b9089cf2beed291fc4dfcedee31a24..1527a297f8e1fcc4ad71b3cbe3e913b2d661b594 100644 (file)
@@ -93,6 +93,7 @@ static const char *const pkname[] = {
 /* --- @hashge@ --- *
  *
  * Arguments:  @ghash *h@ = pointer to hash context
+ *             @group *g@ = pointer to group
  *             @ge *x@ = pointer to group element
  *
  * Returns:    ---
@@ -101,11 +102,12 @@ static const char *const pkname[] = {
  *             @buf_t@.
  */
 
-static void hashge(ghash *h, ge *x)
+static void hashge(ghash *h, group *g, ge *x)
 {
   buf b;
+
   buf_init(&b, buf_t, sizeof(buf_t));
-  G_TOBUF(gg, &b, x);
+  G_TOBUF(g, &b, x);
   assert(BOK(&b));
   GH_HASH(h, BBASE(&b), BLEN(&b));
 }
@@ -115,6 +117,7 @@ static void hashge(ghash *h, ge *x)
  * Arguments:  @buf *b@ = output buffer
  *             @mp *x@ = the plaintext integer
  *             @size_t n@ = the expected size of the plaintext
+ *             @gcipher *mgfc@ = mask-generating function to use
  *             @const octet *k@ = pointer to key material
  *             @size_t ksz@ = size of the key
  *
@@ -124,14 +127,15 @@ static void hashge(ghash *h, ge *x)
  *             it's a random oracle thing rather than an encryption thing.
  */
 
-static octet *mpmask(buf *b, mp *x, size_t n, const octet *k, size_t ksz)
+static octet *mpmask(buf *b, mp *x, size_t n,
+                    const gccipher *mgfc, const octet *k, size_t ksz)
 {
   gcipher *mgf;
   octet *p;
 
   if ((p = buf_get(b, n)) == 0)
     return (0);
-  mgf = GC_INIT(algs.mgf, k, ksz);
+  mgf = GC_INIT(mgfc, k, ksz);
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
     trace(T_CRYPTO, "crypto: masking index = %s", mpstr(x));
     trace_block(T_CRYPTO, "crypto: masking key", k, ksz);
@@ -151,6 +155,7 @@ static octet *mpmask(buf *b, mp *x, size_t n, const octet *k, size_t ksz)
  * Arguments:  @mp *d@ = the output integer
  *             @const octet *p@ = pointer to the ciphertext
  *             @size_t n@ = the size of the ciphertext
+ *             @gcipher *mgfc@ = mask-generating function to use
  *             @const octet *k@ = pointer to key material
  *             @size_t ksz@ = size of the key
  *
@@ -160,11 +165,11 @@ static octet *mpmask(buf *b, mp *x, size_t n, const octet *k, size_t ksz)
  */
 
 static mp *mpunmask(mp *d, const octet *p, size_t n,
-                   const octet *k, size_t ksz)
+                   const gccipher *mgfc, const octet *k, size_t ksz)
 {
   gcipher *mgf;
 
-  mgf = GC_INIT(algs.mgf, k, ksz);
+  mgf = GC_INIT(mgfc, k, ksz);
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
     trace_block(T_CRYPTO, "crypto: unmasking key", k, ksz);
     trace_block(T_CRYPTO, "crypto: masked ciphertext", p, n);
@@ -181,7 +186,8 @@ static mp *mpunmask(mp *d, const octet *p, size_t n,
 
 /* --- @hashcheck@ --- *
  *
- * Arguments:  @ge *kpub@ = sender's public key
+ * Arguments:  @keyexch *kx@ = pointer to key-exchange block
+ *             @ge *kpub@ = sender's public key
  *             @ge *cc@ = receiver's challenge
  *             @ge *c@ = sender's challenge
  *             @ge *y@ = reply to sender's challenge
@@ -198,23 +204,24 @@ static mp *mpunmask(mp *d, const octet *p, size_t n,
  *             key-exchange is deniable.
  */
 
-static const octet *hashcheck(ge *kpub, ge *cc, ge *c, ge *y)
+static const octet *hashcheck(keyexch *kx, ge *kpub, ge *cc, ge *c, ge *y)
 {
-  ghash *h = GH_INIT(algs.h);
+  ghash *h = GH_INIT(kx->kpriv->algs.h);
+  group *g = kx->kpriv->g;
 
   HASH_STRING(h, "tripe-expected-reply");
-  hashge(h, kpub);
-  hashge(h, cc);
-  hashge(h, c);
-  hashge(h, y);
+  hashge(h, g, kpub);
+  hashge(h, g, cc);
+  hashge(h, g, c);
+  hashge(h, g, y);
   GH_DONE(h, buf_t);
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
     trace(T_CRYPTO, "crypto: computing challenge check hash");
-    trace(T_CRYPTO, "crypto: public key = %s", gestr(gg, kpub));
-    trace(T_CRYPTO, "crypto: receiver challenge = %s", gestr(gg, cc));
-    trace(T_CRYPTO, "crypto: sender challenge = %s", gestr(gg, c));
-    trace(T_CRYPTO, "crypto: sender reply = %s", gestr(gg, y));
-    trace_block(T_CRYPTO, "crypto: hash output", buf_t, algs.hashsz);
+    trace(T_CRYPTO, "crypto: public key = %s", gestr(g, kpub));
+    trace(T_CRYPTO, "crypto: receiver challenge = %s", gestr(g, cc));
+    trace(T_CRYPTO, "crypto: sender challenge = %s", gestr(g, c));
+    trace(T_CRYPTO, "crypto: sender reply = %s", gestr(g, y));
+    trace_block(T_CRYPTO, "crypto: hash output", buf_t, kx->kpriv->algs.hashsz);
   }))
   GH_DESTROY(h);
   return (buf_t);
@@ -234,10 +241,11 @@ static const octet *hashcheck(ge *kpub, ge *cc, ge *c, ge *y)
 
 static void sendchallenge(keyexch *kx, buf *b, ge *c, const octet *hc)
 {
-  G_TOBUF(gg, b, kx->c);
-  buf_put(b, hc, algs.hashsz);
-  mpmask(b, kx->alpha, indexsz,
-        hashcheck(kpub, c, kx->c, kx->rx), algs.hashsz);
+  G_TOBUF(kx->kpriv->g, b, kx->c);
+  buf_put(b, hc, kx->kpriv->algs.hashsz);
+  mpmask(b, kx->alpha, kx->kpriv->indexsz, kx->kpriv->algs.mgf,
+        hashcheck(kx, kx->kpriv->kpub, c, kx->c, kx->rx),
+        kx->kpriv->algs.hashsz);
 }
 
 /* --- @timer@ --- *
@@ -307,8 +315,8 @@ static void kxc_destroy(kxchal *kxc)
 {
   if (kxc->f & KXF_TIMER)
     sel_rmtimer(&kxc->t);
-  G_DESTROY(gg, kxc->c);
-  G_DESTROY(gg, kxc->r);
+  G_DESTROY(kxc->kx->kpriv->g, kxc->c);
+  G_DESTROY(kxc->kx->kpriv->g, kxc->r);
   ks_drop(kxc->ks);
   DESTROY(kxc);
 }
@@ -357,8 +365,8 @@ static kxchal *kxc_new(keyexch *kx)
   /* --- Fill in the new structure --- */
 
   kxc = CREATE(kxchal);
-  kxc->c = G_CREATE(gg);
-  kxc->r = G_CREATE(gg);
+  kxc->c = G_CREATE(kx->kpriv->g);
+  kxc->r = G_CREATE(kx->kpriv->g);
   kxc->ks = 0;
   kxc->kx = kx;
   kxc->f = 0;
@@ -381,7 +389,7 @@ static kxchal *kxc_bychal(keyexch *kx, ge *c)
   unsigned i;
 
   for (i = 0; i < kx->nr; i++) {
-    if (G_EQ(gg, c, kx->r[i]->c))
+    if (G_EQ(kx->kpriv->g, c, kx->r[i]->c))
       return (kx->r[i]);
   }
   return (0);
@@ -402,7 +410,7 @@ static kxchal *kxc_byhc(keyexch *kx, const octet *hc)
   unsigned i;
 
   for (i = 0; i < kx->nr; i++) {
-    if (memcmp(hc, kx->r[i]->hc, algs.hashsz) == 0)
+    if (memcmp(hc, kx->r[i]->hc, kx->kpriv->algs.hashsz) == 0)
       return (kx->r[i]);
   }
   return (0);
@@ -440,7 +448,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc)
   T( trace(T_KEYEXCH, "keyexch: sending reply to `%s'", p_name(kx->p)); )
   sendchallenge(kx, b, kxc->c, kxc->hc);
   buf_init(&bb, buf_i, sizeof(buf_i));
-  G_TORAW(gg, &bb, kxc->r);
+  G_TORAW(kx->kpriv->g, &bb, kxc->r);
   buf_flip(&bb);
   ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_REPLY, &bb, b);
 
@@ -477,7 +485,7 @@ static void kxc_answer(keyexch *kx, kxchal *kxc)
 static int doprechallenge(keyexch *kx, buf *b)
 {
   stats *st = p_stats(kx->p);
-  ge *c = G_CREATE(gg);
+  ge *c = G_CREATE(kx->kpriv->g);
   ghash *h;
 
   /* --- Ensure that we're in a sensible state --- */
@@ -489,19 +497,19 @@ static int doprechallenge(keyexch *kx, buf *b)
 
   /* --- Unpack the packet --- */
 
-  if (G_FROMBUF(gg, b, c) || BLEFT(b))
+  if (G_FROMBUF(kx->kpriv->g, b, c) || BLEFT(b))
     goto bad;
 
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-    trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, c));
+    trace(T_CRYPTO, "crypto: challenge = %s", gestr(kx->kpriv->g, c));
   }))
 
   /* --- Send out a full challenge by return --- */
 
   b = p_txstart(kx->p, MSG_KEYEXCH | KX_CHAL);
-  h = GH_INIT(algs.h);
+  h = GH_INIT(kx->kpriv->algs.h);
   HASH_STRING(h, "tripe-cookie");
-  hashge(h, c);
+  hashge(h, kx->kpriv->g, c);
   sendchallenge(kx, b, c, GH_DONE(h, 0));
   GH_DESTROY(h);
   st->n_kxout++;
@@ -510,11 +518,11 @@ static int doprechallenge(keyexch *kx, buf *b)
 
   /* --- Done --- */
 
-  G_DESTROY(gg, c);
+  G_DESTROY(kx->kpriv->g, c);
   return (0);
 
 bad:
-  if (c) G_DESTROY(gg, c);
+  if (c) G_DESTROY(kx->kpriv->g, c);
   return (-1);
 }
 
@@ -532,9 +540,12 @@ bad:
 
 static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
 {
-  ge *c = G_CREATE(gg);
-  ge *r = G_CREATE(gg);
-  ge *cc = G_CREATE(gg);
+  group *g = kx->kpriv->g;
+  const algswitch *algs = &kx->kpriv->algs;
+  size_t ixsz = kx->kpriv->indexsz;
+  ge *c = G_CREATE(g);
+  ge *r = G_CREATE(g);
+  ge *cc = G_CREATE(g);
   const octet *hc, *ck;
   size_t x, y, z;
   mp *cv = 0;
@@ -545,21 +556,21 @@ static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
 
   /* --- Unpack the packet --- */
 
-  if (G_FROMBUF(gg, b, c) ||
-      (hc = buf_get(b, algs.hashsz)) == 0 ||
-      (ck = buf_get(b, indexsz)) == 0) {
+  if (G_FROMBUF(g, b, c) ||
+      (hc = buf_get(b, algs->hashsz)) == 0 ||
+      (ck = buf_get(b, ixsz)) == 0) {
     a_warn("KX", "?PEER", kx->p, "invalid", "%s", pkname[msg], A_END);
     goto bad;
   }
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-    trace(T_CRYPTO, "crypto: challenge = %s", gestr(gg, c));
-    trace_block(T_CRYPTO, "crypto: cookie", hc, algs.hashsz);
-    trace_block(T_CRYPTO, "crypto: check-value", ck, indexsz);
+    trace(T_CRYPTO, "crypto: challenge = %s", gestr(g, c));
+    trace_block(T_CRYPTO, "crypto: cookie", hc, algs->hashsz);
+    trace_block(T_CRYPTO, "crypto: check-value", ck, ixsz);
   }))
 
   /* --- Discard a packet with an invalid cookie --- */
 
-  if (hc && memcmp(hc, kx->hc, algs.hashsz) != 0) {
+  if (hc && memcmp(hc, kx->hc, algs->hashsz) != 0) {
     a_warn("KX", "?PEER", kx->p, "incorrect", "cookie", A_END);
     goto bad;
   }
@@ -573,97 +584,96 @@ static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
    */
 
   if ((kxc = kxc_bychal(kx, c)) != 0) {
-    h = GH_INIT(algs.h);
+    h = GH_INIT(algs->h);
     HASH_STRING(h, "tripe-check-hash");
-    GH_HASH(h, ck, indexsz);
-    ok = !memcmp(kxc->ck, GH_DONE(h, 0), algs.hashsz);
+    GH_HASH(h, ck, ixsz);
+    ok = !memcmp(kxc->ck, GH_DONE(h, 0), algs->hashsz);
     GH_DESTROY(h);
     if (!ok) goto badcheck;
   } else {
 
     /* --- Compute the reply, and check the magic --- */
 
-    G_EXP(gg, r, c, kpriv);
-    cv = mpunmask(MP_NEW, ck, indexsz,
-                 hashcheck(kx->kpub, kx->c, c, r), algs.hashsz);
+    G_EXP(g, r, c, kx->kpriv->kpriv);
+    cv = mpunmask(MP_NEW, ck, ixsz, algs->mgf,
+                 hashcheck(kx, kx->kpub->kpub, kx->c, c, r),
+                 algs->hashsz);
     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-      trace(T_CRYPTO, "crypto: computed reply = %s", gestr(gg, r));
+      trace(T_CRYPTO, "crypto: computed reply = %s", gestr(g, r));
       trace(T_CRYPTO, "crypto: recovered log = %s", mpstr(cv));
     }))
-    if (MP_CMP(cv, >, gg->r) ||
-       (G_EXP(gg, cc, gg->g, cv), !G_EQ(gg, c, cc)))
+    if (MP_CMP(cv, >, g->r) ||
+       (G_EXP(g, cc, g->g, cv),
+        !G_EQ(g, c, cc)))
       goto badcheck;
 
     /* --- Fill in a new challenge block --- */
 
     kxc = kxc_new(kx);
-    G_COPY(gg, kxc->c, c);
-    G_COPY(gg, kxc->r, r);
+    G_COPY(g, kxc->c, c);
+    G_COPY(g, kxc->r, r);
 
-    h = GH_INIT(algs.h);
-    HASH_STRING(h, "tripe-check-hash");
-    GH_HASH(h, ck, indexsz);
-    GH_DONE(h, kxc->ck);
-    GH_DESTROY(h);
+    h = GH_INIT(algs->h); HASH_STRING(h, "tripe-check-hash");
+    GH_HASH(h, ck, ixsz);
+    GH_DONE(h, kxc->ck); GH_DESTROY(h);
 
-    h = GH_INIT(algs.h);
-    HASH_STRING(h, "tripe-cookie");
-    hashge(h, kxc->c);
-    GH_DONE(h, kxc->hc);
-    GH_DESTROY(h);
+    h = GH_INIT(algs->h); HASH_STRING(h, "tripe-cookie");
+    hashge(h, g, kxc->c);
+    GH_DONE(h, kxc->hc); GH_DESTROY(h);
 
     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-      trace_block(T_CRYPTO, "crypto: computed cookie", kxc->hc, algs.hashsz);
+      trace_block(T_CRYPTO, "crypto: computed cookie",
+                 kxc->hc, algs->hashsz);
     }))
 
     /* --- Work out the shared key --- */
 
-    G_EXP(gg, r, c, kx->alpha);
+    G_EXP(g, r, c, kx->alpha);
     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-      trace(T_CRYPTO, "crypto: shared secret = %s", gestr(gg, r));
+      trace(T_CRYPTO, "crypto: shared secret = %s", gestr(g, r));
     }))
 
     /* --- Compute the switch messages --- */
 
-    h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-request");
-    hashge(h, kx->c); hashge(h, kxc->c);
+    h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-request");
+    hashge(h, g, kx->c); hashge(h, g, kxc->c);
     GH_DONE(h, kxc->hswrq_out); GH_DESTROY(h);
-    h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-confirm");
-    hashge(h, kx->c); hashge(h, kxc->c);
+    h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-confirm");
+    hashge(h, g, kx->c); hashge(h, g, kxc->c);
     GH_DONE(h, kxc->hswok_out); GH_DESTROY(h);
 
-    h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-request");
-    hashge(h, kxc->c); hashge(h, kx->c);
+    h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-request");
+    hashge(h, g, kxc->c); hashge(h, g, kx->c);
     GH_DONE(h, kxc->hswrq_in); GH_DESTROY(h);
-    h = GH_INIT(algs.h); HASH_STRING(h, "tripe-switch-confirm");
-    hashge(h, kxc->c); hashge(h, kx->c);
+    h = GH_INIT(algs->h); HASH_STRING(h, "tripe-switch-confirm");
+    hashge(h, g, kxc->c); hashge(h, g, kx->c);
     GH_DONE(h, kxc->hswok_in); GH_DESTROY(h);
 
     IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
       trace_block(T_CRYPTO, "crypto: outbound switch request",
-                 kxc->hswrq_out, algs.hashsz);
+                 kxc->hswrq_out, algs->hashsz);
       trace_block(T_CRYPTO, "crypto: outbound switch confirm",
-                 kxc->hswok_out, algs.hashsz);
+                 kxc->hswok_out, algs->hashsz);
       trace_block(T_CRYPTO, "crypto: inbound switch request",
-                 kxc->hswrq_in, algs.hashsz);
+                 kxc->hswrq_in, algs->hashsz);
       trace_block(T_CRYPTO, "crypto: inbound switch confirm",
-                 kxc->hswok_in, algs.hashsz);
+                 kxc->hswok_in, algs->hashsz);
     }))
 
     /* --- Create a new symmetric keyset --- */
 
     buf_init(&bb, buf_o, sizeof(buf_o));
-    G_TOBUF(gg, &bb, kx->c); x = BLEN(&bb);
-    G_TOBUF(gg, &bb, kxc->c); y = BLEN(&bb);
-    G_TOBUF(gg, &bb, r); z = BLEN(&bb);
+    G_TOBUF(g, &bb, kx->c); x = BLEN(&bb);
+    G_TOBUF(g, &bb, kxc->c); y = BLEN(&bb);
+    G_TOBUF(g, &bb, r); z = BLEN(&bb);
     assert(BOK(&bb));
 
     kxc->ks = ks_gen(BBASE(&bb), x, y, z, kx->p);
   }
 
-  G_DESTROY(gg, c);
-  G_DESTROY(gg, cc);
-  G_DESTROY(gg, r);
+  G_DESTROY(g, c);
+  G_DESTROY(g, cc);
+  G_DESTROY(g, r);
   mp_drop(cv);
   return (kxc);
 
@@ -671,9 +681,9 @@ badcheck:
   a_warn("KX", "?PEER", kx->p, "bad-expected-reply-log", A_END);
   goto bad;
 bad:
-  G_DESTROY(gg, c);
-  G_DESTROY(gg, cc);
-  G_DESTROY(gg, r);
+  G_DESTROY(g, c);
+  G_DESTROY(g, cc);
+  G_DESTROY(g, r);
   mp_drop(cv);
   return (0);
 }
@@ -731,18 +741,18 @@ 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);
-      G_TOBUF(gg, b, kx->c);
+      G_TOBUF(kx->kpriv->g, b, kx->c);
       break;
     case KXS_COMMIT:
       T( trace(T_KEYEXCH, "keyexch: sending switch request to `%s'",
               p_name(kx->p)); )
       kxc = kx->r[0];
       b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCH);
-      buf_put(b, kx->hc, algs.hashsz);
-      buf_put(b, kxc->hc, algs.hashsz);
+      buf_put(b, kx->hc, kx->kpriv->algs.hashsz);
+      buf_put(b, kxc->hc, kx->kpriv->algs.hashsz);
       buf_init(&bb, buf_i, sizeof(buf_i));
-      G_TORAW(gg, &bb, kxc->r);
-      buf_put(&bb, kxc->hswrq_out, algs.hashsz);
+      G_TORAW(kx->kpriv->g, &bb, kxc->r);
+      buf_put(&bb, kxc->hswrq_out, kx->kpriv->algs.hashsz);
       buf_flip(&bb);
       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCH, &bb, b);
       break;
@@ -752,7 +762,7 @@ static void resend(keyexch *kx)
       kxc = kx->r[0];
       b = p_txstart(kx->p, MSG_KEYEXCH | KX_SWITCHOK);
       buf_init(&bb, buf_i, sizeof(buf_i));
-      buf_put(&bb, kxc->hswok_out, algs.hashsz);
+      buf_put(&bb, kxc->hswok_out, kx->kpriv->algs.hashsz);
       buf_flip(&bb);
       ks_encrypt(kxc->ks, MSG_KEYEXCH | KX_SWITCHOK, &bb, b);
       break;
@@ -811,25 +821,26 @@ static int decryptrest(keyexch *kx, kxchal *kxc, unsigned msg, buf *b)
 
 static int checkresponse(keyexch *kx, unsigned msg, buf *b)
 {
-  ge *r = G_CREATE(gg);
+  group *g = kx->kpriv->g;
+  ge *r = G_CREATE(g);
 
-  if (G_FROMRAW(gg, b, r)) {
+  if (G_FROMRAW(g, b, r)) {
     a_warn("KX", "?PEER", kx->p, "invalid", "%s", pkname[msg], A_END);
     goto bad;
   }
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-    trace(T_CRYPTO, "crypto: reply = %s", gestr(gg, r));
+    trace(T_CRYPTO, "crypto: reply = %s", gestr(g, r));
   }))
-  if (!G_EQ(gg, r, kx->rx)) {
+  if (!G_EQ(g, r, kx->rx)) {
     a_warn("KX", "?PEER", kx->p, "incorrect", "response", A_END);
     goto bad;
   }
 
-  G_DESTROY(gg, r);
+  G_DESTROY(g, r);
   return (0);
 
 bad:
-  G_DESTROY(gg, r);
+  G_DESTROY(g, r);
   return (-1);
 }
 
@@ -927,34 +938,35 @@ static void kxfinish(keyexch *kx)
 
 static int doswitch(keyexch *kx, buf *b)
 {
+  size_t hsz = kx->kpriv->algs.hashsz;
   const octet *hc_in, *hc_out, *hswrq;
   kxchal *kxc;
 
-  if ((hc_in = buf_get(b, algs.hashsz)) == 0 ||
-      (hc_out = buf_get(b, algs.hashsz)) == 0) {
+  if ((hc_in = buf_get(b, hsz)) == 0 ||
+      (hc_out = buf_get(b, hsz)) == 0) {
     a_warn("KX", "?PEER", kx->p, "invalid", "switch-rq", A_END);
     goto bad;
   }
   IF_TRACING(T_KEYEXCH, IF_TRACING(T_CRYPTO, {
-    trace_block(T_CRYPTO, "crypto: challenge", hc_in, algs.hashsz);
-    trace_block(T_CRYPTO, "crypto: cookie", hc_out, algs.hashsz);
+    trace_block(T_CRYPTO, "crypto: challenge", hc_in, hsz);
+    trace_block(T_CRYPTO, "crypto: cookie", hc_out, hsz);
   }))
   if ((kxc = kxc_byhc(kx, hc_in)) == 0 ||
-      memcmp(hc_out, kx->hc, algs.hashsz) != 0) {
+      memcmp(hc_out, kx->hc, hsz) != 0) {
     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-rq", A_END);
     goto bad;
   }
   if (decryptrest(kx, kxc, KX_SWITCH, b) ||
       checkresponse(kx, KX_SWITCH, b))
     goto bad;
-  if ((hswrq = buf_get(b, algs.hashsz)) == 0 || BLEFT(b)) {
+  if ((hswrq = buf_get(b, hsz)) == 0 || BLEFT(b)) {
     a_warn("KX", "?PEER", kx->p, "invalid", "switch-rq", A_END);
     goto bad;
   }
   IF_TRACING(T_KEYEXCH, {
-    trace_block(T_CRYPTO, "crypto: switch request hash", hswrq, algs.hashsz);
+    trace_block(T_CRYPTO, "crypto: switch request hash", hswrq, hsz);
   })
-  if (memcmp(hswrq, kxc->hswrq_in, algs.hashsz) != 0) {
+  if (memcmp(hswrq, kxc->hswrq_in, hsz) != 0) {
     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-rq", A_END);
     goto bad;
   }
@@ -981,6 +993,7 @@ bad:
 
 static int doswitchok(keyexch *kx, buf *b)
 {
+  size_t hsz = kx->kpriv->algs.hashsz;
   const octet *hswok;
   kxchal *kxc;
   buf bb;
@@ -993,15 +1006,15 @@ static int doswitchok(keyexch *kx, buf *b)
   buf_init(&bb, buf_o, sizeof(buf_o));
   if (decryptrest(kx, kxc, KX_SWITCHOK, b))
     goto bad;
-  if ((hswok = buf_get(b, algs.hashsz)) == 0 || BLEFT(b)) {
+  if ((hswok = buf_get(b, hsz)) == 0 || BLEFT(b)) {
     a_warn("KX", "?PEER", kx->p, "invalid", "switch-ok", A_END);
     goto bad;
   }
   IF_TRACING(T_KEYEXCH, {
     trace_block(T_CRYPTO, "crypto: switch confirmation hash",
-               hswok, algs.hashsz);
+               hswok, hsz);
   })
-  if (memcmp(hswok, kxc->hswok_in, algs.hashsz) != 0) {
+  if (memcmp(hswok, kxc->hswok_in, hsz) != 0) {
     a_warn("KX", "?PEER", kx->p, "incorrect", "switch-ok", A_END);
     goto bad;
   }
@@ -1041,8 +1054,8 @@ static void stop(keyexch *kx)
   for (i = 0; i < kx->nr; i++)
     kxc_destroy(kx->r[i]);
   mp_drop(kx->alpha);
-  G_DESTROY(gg, kx->c);
-  G_DESTROY(gg, kx->rx);
+  G_DESTROY(kx->kpriv->g, kx->c);
+  G_DESTROY(kx->kpriv->g, kx->rx);
   kx->t_valid = 0;
   kx->f |= KXF_DEAD;
   kx->f &= ~KXF_TIMER;
@@ -1061,21 +1074,23 @@ static void stop(keyexch *kx)
 
 static void start(keyexch *kx, time_t now)
 {
+  algswitch *algs = &kx->kpriv->algs;
+  group *g = kx->kpriv->g;
   ghash *h;
 
   assert(kx->f & KXF_DEAD);
 
   kx->f &= ~(KXF_DEAD | KXF_CORK);
   kx->nr = 0;
-  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->alpha = mprand_range(MP_NEW, g->r, &rand_global, 0);
+  kx->c = G_CREATE(g); G_EXP(g, kx->c, g->g, kx->alpha);
+  kx->rx = G_CREATE(g); G_EXP(g, kx->rx, kx->kpub->kpub, kx->alpha);
   kx->s = KXS_CHAL;
   kx->t_valid = now + T_VALID;
 
-  h = GH_INIT(algs.h);
+  h = GH_INIT(algs->h);
   HASH_STRING(h, "tripe-cookie");
-  hashge(h, kx->c);
+  hashge(h, g, kx->c);
   GH_DONE(h, kx->hc);
   GH_DESTROY(h);
 
@@ -1083,9 +1098,10 @@ static void start(keyexch *kx, time_t now)
     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", gestr(gg, kx->c));
-      trace(T_CRYPTO, "crypto: expected response = %s", gestr(gg, kx->rx));
-      trace_block(T_CRYPTO, "crypto: challenge cookie", kx->hc, algs.hashsz);
+      trace(T_CRYPTO, "crypto: challenge = %s", gestr(g, kx->c));
+      trace(T_CRYPTO, "crypto: expected response = %s", gestr(g, kx->rx));
+      trace_block(T_CRYPTO, "crypto: challenge cookie",
+                 kx->hc, algs->hashsz);
     })
   })
 }
@@ -1103,13 +1119,17 @@ static void start(keyexch *kx, time_t now)
 static int checkpub(keyexch *kx)
 {
   time_t now;
+  unsigned f = 0;
+
   if (kx->f & KXF_DEAD)
     return (-1);
   now = time(0);
-  if (KEY_EXPIRED(now, kx->texp_kpub)) {
+  if (KEY_EXPIRED(now, kx->kpriv->t_exp)) f |= 1;
+  if (KEY_EXPIRED(now, kx->kpub->t_exp)) f |= 2;
+  if (f) {
     stop(kx);
-    a_warn("KX", "?PEER", kx->p, "public-key-expired", A_END);
-    G_COPY(gg, kx->kpub, gg->i);
+    if (f & 1) a_warn("KX", "?PEER", kx->p, "private-key-expired", A_END);
+    if (f & 2) a_warn("KX", "?PEER", kx->p, "public-key-expired", A_END);
     kx->f &= ~KXF_PUBKEY;
     return (-1);
   }
@@ -1219,7 +1239,8 @@ void kx_message(keyexch *kx, unsigned msg, buf *b)
 void kx_free(keyexch *kx)
 {
   stop(kx);
-  G_DESTROY(gg, kx->kpub);
+  km_unref(kx->kpub);
+  km_unref(kx->kpriv);
 }
 
 /* --- @kx_newkeys@ --- *
@@ -1236,13 +1257,111 @@ void kx_free(keyexch *kx)
 
 void kx_newkeys(keyexch *kx)
 {
-  if (km_getpubkey(p_tag(kx->p), kx->kpub, &kx->texp_kpub))
-    return;
+  kdata *kpriv, *kpub;
+  unsigned i;
+  int switchp;
+  time_t now = time(0);
+
+  T( trace(T_KEYEXCH, "keyexch: checking new keys for `%s'",
+          p_name(kx->p)); )
+
+  /* --- Find out whether we can use new keys --- *
+   *
+   * Try each available combination of new and old, public and private,
+   * except both old (which is status quo anyway).  The selection is encoded
+   * in @i@, with bit 0 for the private key and bit 1 for public key; a set
+   * bit means to use the old value, and a clear bit means to use the new
+   * one.
+   *
+   * This means that we currently prefer `old private and new public' over
+   * `new private and old public'.  I'm not sure which way round this should
+   * actually be.
+   */
+
+  for (i = 0; i < 3; i++) {
+
+    /* --- Select the keys we're going to examine --- *
+     *
+     * If we're meant to have a new key and don't, then skip this
+     * combination.
+     */
+
+    T( trace(T_KEYEXCH, "keyexch: checking %s private, %s public",
+            i & 1 ? "old" : "new", i & 2 ? "old" : "new"); )
+
+    if (i & 1) kpriv = kx->kpriv;
+    else if (kx->kpriv->kn->kd != kx->kpriv) kpriv = kx->kpriv->kn->kd;
+    else {
+      T( trace(T_KEYEXCH, "keyexch: private key unchanged, skipping"); )
+      continue;
+    }
+
+    if (i & 2) kpub = kx->kpub;
+    else if (kx->kpub->kn->kd != kx->kpub) kpub = kx->kpub->kn->kd;
+    else {
+      T( trace(T_KEYEXCH, "keyexch: public key unchanged, skipping"); )
+      continue;
+    }
+
+    /* --- Skip if either key is expired --- *
+     *
+     * We're not going to get far with expired keys, and this simplifies the
+     * logic below.
+     */
+
+    if (KEY_EXPIRED(now, kx->kpriv->t_exp) ||
+       KEY_EXPIRED(now, kx->kpub->t_exp)) {
+      T( trace(T_KEYEXCH, "keyexch: %s expired, skipping",
+              !KEY_EXPIRED(now, kx->kpriv->t_exp) ? "public key" :
+              !KEY_EXPIRED(now, kx->kpub->t_exp) ? "private key" :
+              "both keys"); )
+      continue;
+    }
+
+    /* --- If the groups don't match then we can't use this pair --- */
+
+    if (!km_samealgsp(kpriv, kpub)) {
+      T( trace(T_KEYEXCH, "keyexch: peer `%s' group mismatch; "
+              "%s priv `%s' and %s pub `%s'", p_name(kx->p),
+              i & 1 ? "old" : "new", km_tag(kx->kpriv),
+              i & 2 ? "old" : "new", km_tag(kx->kpub)); )
+      continue;
+    }
+    goto newkeys;
+  }
+  T( trace(T_KEYEXCH, "keyexch: peer `%s' continuing with old keys",
+          p_name(kx->p)); )
+  return;
+
+  /* --- We've chosen new keys --- *
+   *
+   * Switch the new ones into place.  Neither of the keys we're switching to
+   * is expired (we checked that above), so we should just crank everything
+   * up.
+   *
+   * A complication arises: we don't really want to force a new key exchange
+   * unless we have to.  If the group is unchanged, and we're currently
+   * running OK, then we should just let things lie.
+   */
+
+newkeys:
+  switchp = ((kx->f & KXF_DEAD) ||
+            kx->s != KXS_SWITCH ||
+            !group_samep(kx->kpriv->g, kpriv->g));
+
+  T( trace(T_KEYEXCH, "keyexch: peer `%s' adopting "
+          "%s priv `%s' and %s pub `%s'; %sforcing exchange", p_name(kx->p),
+          i & 1 ? "old" : "new", km_tag(kx->kpriv),
+          i & 2 ? "old" : "new", km_tag(kx->kpub),
+          switchp ? "" : "not "); )
+
+  if (switchp) stop(kx);
+  km_ref(kpriv); km_unref(kx->kpriv); kx->kpriv = kpriv;
+  km_ref(kpub);  km_unref(kx->kpub);  kx->kpub  = kpub;
   kx->f |= KXF_PUBKEY;
-  if ((kx->f & KXF_DEAD) || kx->s != KXS_SWITCH) {
+  if (switchp) {
     T( trace(T_KEYEXCH, "keyexch: restarting key negotiation with `%s'",
             p_name(kx->p)); )
-    stop(kx);
     start(kx, time(0));
     resend(kx);
   }
@@ -1264,13 +1383,18 @@ void kx_newkeys(keyexch *kx)
 
 int kx_init(keyexch *kx, peer *p, keyset **ks, unsigned f)
 {
+  if ((kx->kpriv = km_findpriv(tag_priv)) == 0) goto fail_0;
+  if ((kx->kpub = km_findpub(p_tag(p))) == 0) goto fail_1;
+  if (!km_samealgsp(kx->kpriv, kx->kpub)) {
+    a_warn("KX", "?PEER", kx->p, "algorithms-mismatch",
+          "local-private-key", "%s", tag_priv,
+          "peer-public-key", "%s", p_tag(p),
+          A_END);
+    goto fail_2;
+  }
+
   kx->ks = ks;
   kx->p = p;
-  kx->kpub = G_CREATE(gg);
-  if (km_getpubkey(p_tag(p), kx->kpub, &kx->texp_kpub)) {
-    G_DESTROY(gg, kx->kpub);
-    return (-1);
-  }
   kx->f = KXF_DEAD | KXF_PUBKEY | f;
   if (!(kx->f & KXF_CORK)) {
     start(kx, time(0));
@@ -1278,6 +1402,13 @@ int kx_init(keyexch *kx, peer *p, keyset **ks, unsigned f)
     /* Don't notify here: the ADD message hasn't gone out yet. */
   }
   return (0);
+
+fail_2:
+  km_unref(kx->kpub);
+fail_1:
+  km_unref(kx->kpriv);
+fail_0:
+  return (-1);
 }
 
 /*----- That's all, folks -------------------------------------------------*/
index 69ea74a5e53e22b39a4f70e7eb34d85c93204585..ef4f6a6bb1325ff0ac9f0f6361fa6e6b7fac34aa 100644 (file)
@@ -727,46 +727,6 @@ static int kh_refresh(keyhalf *kh)
 const char *tag_priv;
 kdata *master;
 
-group *gg;
-mp *kpriv;
-ge *kpub;
-algswitch algs;
-size_t indexsz;
-
-/* --- @update_compat@ --- *
- *
- * Arguments:  @kdata *kd@ = proposed new master key
- *
- * Returns:    Zero on success, nonzero to refuse the replacement.
- *
- * Use:                Updates the exported private key variables for compatibility.
- */
-
-static int update_compat(kdata *kd)
-{
-  if (gg) {
-    if (!group_samep(kd->g, gg)) {
-      a_warn("KEYMGMT", "private-keyring",
-            "%s", kd->kn->kh->kr, "key", "%s", kd->tag,
-            "changed-group", A_END);
-      return (-1);
-    }
-    G_DESTROYGROUP(gg);
-  }
-  gg = kd->g;
-
-  if (kpriv) mp_drop(kpriv);
-  kpriv = MP_COPY(kd->kpriv);
-  if (kpub) G_DESTROY(gg, kpub);
-  kpub = G_CREATE(gg);
-  G_COPY(gg, kpub, kd->kpub);
-
-  algs = kd->algs;
-  indexsz = kd->indexsz;
-
-  return (0);
-}
-
 /* --- @km_init@ --- *
  *
  * Arguments:  @const char *privkr@ = private keyring file
@@ -795,8 +755,6 @@ void km_init(const char *privkr, const char *pubkr, const char *ptag)
 
   tag_priv = ptag;
   if ((master = km_findpriv(ptag)) == 0) exit(EXIT_FAILURE);
-
-  if (update_compat(master)) exit(EXIT_FAILURE);
 }
 
 /* --- @km_reload@ --- *
@@ -816,7 +774,7 @@ int km_reload(void)
   if (kh_refresh(&priv)) {
     changep = 1;
     kd = master->kn->kd;
-    if (kd != master && !update_compat(kd)) {
+    if (kd != master) {
       km_unref(master);
       km_ref(kd);
       master = kd;
@@ -885,38 +843,4 @@ void km_unref(kdata *kd)
   G_DESTROYGROUP(kd->g);
 }
 
-/* --- @km_getpubkey@ --- *
- *
- * Arguments:  @const char *tag@ = public key tag to load
- *             @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.
- *
- * Use:                Fetches a public key from the keyring.  (Temporary
- *             compatibility hack.)
- */
-
-int km_getpubkey(const char *tag, ge *kpub, time_t *t_exp)
-{
-  kdata *kd;
-  int rc = -1;
-
-  if ((kd = km_findpub(tag)) == 0)
-    goto done_0;
-  if (!km_samealgsp(kd, master)) {
-    a_warn("KEYMGMT", "public-keyring",
-          "%s", kd->kn->kh->kr, "key", "%s", kd->tag,
-          "algorithm-mismatch", A_END);
-    goto done_1;
-  }
-  G_COPY(gg, kpub, kd->kpub);
-  *t_exp = kd->t_exp;
-  rc = 0;
-done_1:
-  km_unref(kd);
-done_0:
-  return (rc);
-}
-
 /*----- That's all, folks -------------------------------------------------*/
index 1f580ff7b79830ee107c6f897653e896a0b4c94b..898c55a4ccd9a8de84d42a4e912bfc6d74c85b78 100644 (file)
@@ -293,6 +293,7 @@ keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p)
   keyset *ks = CREATE(keyset);
   time_t now = time(0);
   const octet *pp = k;
+  const algswitch *algs = &p->kx.kpriv->algs;
   T( static unsigned seq = 0; )
 
   T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); )
@@ -308,21 +309,21 @@ keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p)
 
 #define HASH_in MINE; YOURS; OURS
 #define HASH_out YOURS; MINE; OURS
-#define INIT_c(k) GC_INIT(algs.c, (k), algs.cksz)
-#define INIT_m(k) GM_KEY(algs.m, (k), algs.mksz)
+#define INIT_c(k) GC_INIT(algs->c, (k), algs->cksz)
+#define INIT_m(k) GM_KEY(algs->m, (k), algs->mksz)
 #define STR_c "encryption"
 #define STR_m "integrity"
 #define STR_in "incoming"
 #define STR_out "outgoing"
 
 #define SETKEY(a, dir) do {                                            \
-  h = GH_INIT(algs.h);                                                 \
+  h = GH_INIT(algs->h);                                                        \
   HASH_STRING(h, "tripe-" STR_##a);                                    \
   HASH_##dir;                                                          \
   hh = GH_DONE(h, 0);                                                  \
   IF_TRACING(T_KEYSET, {                                               \
     trace_block(T_CRYPTO, "crypto: " STR_##dir " key " STR_##a,                \
-               hh, algs.a##ksz);                                       \
+               hh, algs->a##ksz);                                      \
   })                                                                   \
   ks->a##dir = INIT_##a(hh);                                           \
   GH_DESTROY(h);                                                       \
@@ -347,14 +348,14 @@ keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p)
   T( ks->seq = seq++; )
   ks->ref = 1;
   ks->t_exp = now + T_EXP;
-  ks->sz_exp = algs.expsz;
-  ks->sz_regen = algs.expsz/2;
+  ks->sz_exp = algs->expsz;
+  ks->sz_regen = algs->expsz/2;
   ks->oseq = 0;
   seq_reset(&ks->iseq);
   ks->next = 0;
   ks->p = p;
   ks->f = KSF_LISTEN;
-  ks->tagsz = algs.tagsz;
+  ks->tagsz = algs->tagsz;
   return (ks);
 }
 
index 0ab6711bdedc71862e80f58a2e4f11ea3ec70356..a27179d8f28ae78898b2cd1144c98ebec187cb7d 100644 (file)
@@ -375,10 +375,15 @@ Emits an
 line reporting the IP address and port number stored for
 .IR peer .
 .SP
-.B "ALGS"
+.BI "ALGS \fR[" peer \fR]
 Emits information about the cryptographic algorithms in use, in
-key-value form.  The keys are as follows.
+key-value form.  If a
+.I peer
+is given, then describe the algorithms used in the association with that
+peer; otherwise describe the default algorithms.
 .RS
+.PP
+The keys are as follows.
 .TP
 .B kx-group
 Type of key-exchange group in use, currently either
@@ -1306,6 +1311,12 @@ is one of the tokens
 or
 .BR switch-ok .
 .SP
+.BI "KX " peer " algorithms-mismatch local-private-key " privtag " peer-public-key " pubtag
+The algorithms specified in the peer's public key
+.I pubtag
+don't match the ones described in the private key
+.IR privtag .
+.SP
 .BI "KX " peer " bad-expected-reply-log"
 The challenges
 .B tripe
@@ -1329,9 +1340,11 @@ A message didn't contain the right magic data.  This may be a replay of
 some old exchange, or random packets being sent in an attempt to waste
 CPU.
 .SP
-.BI "KX " peer " public-key-expired"
-The peer's public key has expired.  It's maintainer should have given
-you a replacement before now.
+.BI "KX " peer " " which "-key-expired"
+The local private key or the peer's public key (distinguished by
+.IR which )
+has expired.  Either you or the peer's maintainer should have arranged
+for a replacement before now.
 .SP
 .BI "KX " peer " sending-cookie"
 We've received too many bogus pre-challenge messages.  Someone is trying
index 217a88dfd00ab4c9760ca767640f9f351a68f135..b22dccce4830a8d8e4431a95f1477602b4a994e6 100644 (file)
@@ -153,8 +153,6 @@ typedef struct algswitch {
   size_t cksz, mksz;                   /* Key lengths for @c@ and @m@ */
 } algswitch;
 
-extern algswitch algs;
-
 typedef struct kdata {
   unsigned ref;                                /* Reference counter */
   struct knode *kn;                    /* Pointer to cache entry */
@@ -277,12 +275,12 @@ typedef struct kxchal {
 
 typedef struct keyexch {
   struct peer *p;                      /* Pointer back to the peer */
+  kdata *kpriv;                                /* Private key and related info */
+  kdata *kpub;                         /* Peer's public key */
   keyset **ks;                         /* Peer's list of keysets */
   unsigned f;                          /* Various useful flags */
   unsigned s;                          /* Current state in exchange */
   sel_timer t;                         /* Timer for next exchange */
-  ge *kpub;                            /* Peer's public key */
-  time_t texp_kpub;                    /* Expiry time for public key */
   mp *alpha;                           /* My temporary secret */
   ge *c;                               /* My challenge */
   ge *rx;                              /* The expected response */
@@ -519,10 +517,6 @@ typedef struct admin {
 /*----- Global variables --------------------------------------------------*/
 
 extern sel_state sel;                  /* Global I/O event state */
-extern group *gg;                      /* The group we work in */
-extern size_t indexsz;                 /* Size of exponent for the group */
-extern mp *kpriv;                      /* Our private key */
-extern ge *kpub;                       /* Our public key */
 extern octet buf_i[PKBUFSZ], buf_o[PKBUFSZ], buf_t[PKBUFSZ], buf_u[PKBUFSZ];
 extern const tunnel_ops *tunnels[];    /* Table of tunnels (0-term) */
 extern const tunnel_ops *tun_default;  /* Default tunnel to use */
@@ -621,21 +615,6 @@ extern void km_unref(kdata */*kd*/);
 
 extern const char *km_tag(kdata */*kd*/);
 
-/* --- @km_getpubkey@ --- *
- *
- * Arguments:  @const char *tag@ = public key tag to load
- *             @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.
- *
- * Use:                Fetches a public key from the keyring.  (Temporary
- *             compatibility hack.)
- */
-
-extern int km_getpubkey(const char */*tag*/, ge */*kpub*/,
-                       time_t */*t_exp*/);
-
 /*----- Key exchange ------------------------------------------------------*/
 
 /* --- @kx_start@ --- *
index 140f1fcee51821c2ea5e672ea1c9f89fe8a6e280..5917c79eb9c5405c610979472529519c1af3abf7 100644 (file)
@@ -577,15 +577,15 @@ def encode_envvars(env, prefix, vars):
     env[prefix + r_bad.sub('_', k.upper())] = v
 
 r_bad = RX.compile(r'[\W_]+')
-def envvars(info):
+def envvars(peer, info):
   """
-  Translate the database INFO dictionary for a peer into a dictionary of
+  Translate the database INFO dictionary for a PEER into a dictionary of
   environment variables with plausible upper-case names and a P_ prefix.
   Also collect the crypto information into A_ variables.
   """
   env = {}
   encode_envvars(env, 'P_', info)
-  encode_envvars(env, 'A_', S.algs())
+  encode_envvars(env, 'A_', S.algs(peer))
   return env
 
 def ifupdown(what, peer, info, *args):
@@ -602,7 +602,7 @@ def ifupdown(what, peer, info, *args):
   c = Command([what, peer], q, what,
               M.split(info[what], quotep = True)[0] +
               [peer] + list(args),
-              envvars(info))
+              envvars(peer, info))
   potwatch(what, peer, q)
 
 def addpeer(info, peer, ifname, *addr):