chiark / gitweb /
server/keyexch.c: Use high-resolution `struct timeval' timers.
[tripe] / server / keyexch.c
index 8577d91e3f9dd3e93f69f43d3bf66243f0810153..c27d69fd7cff61df15db5c9c9ef7d58afb8551d0 100644 (file)
@@ -1,13 +1,11 @@
 /* -*-c-*-
- *
- * $Id$
  *
  * Key exchange protocol
  *
  * (c) 2001 Straylight/Edgeware
  */
 
-/*----- Licensing notice --------------------------------------------------* 
+/*----- Licensing notice --------------------------------------------------*
  *
  * This file is part of Trivial IP Encryption (TrIPE).
  *
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * TrIPE is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with TrIPE; if not, write to the Free Software Foundation,
  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  * %$r_A = g^{\rho_A}$%                        Alice's challenge
  * %$c_A = H(\cookie{cookie}, r_A)$%   Alice's cookie
  * %$v_A = \rho_A \xor H(\cookie{expected-reply}, a, r_A, r_B, b^{\rho_A})$%
- *                                     Alice's challenge check value
+ *                                     Alice's challenge check value
  * %$r_B^\alpha = a^{\rho_B}$%         Alice's reply
  * %$K = r_B^{\rho_A} = r_B^{\rho_A} = g^{\rho_A\rho_B}$%
- *                                     Alice and Bob's shared secret key
+ *                                     Alice and Bob's shared secret key
  * %$w_A = H(\cookie{switch-request}, c_A, c_B)$%
- *                                     Alice's switch request value
+ *                                     Alice's switch request value
  * %$u_A = H(\cookie{switch-confirm}, c_A, c_B)$%
- *                                     Alice's switch confirm value
+ *                                     Alice's switch confirm value
  *
  * The messages are then:
  *
  *
  * %$\cookie{kx-switch-ok}, E_K(u_A))$%
  *     Switch received.  Committed; send data; move to @KXS_SWITCH@.
- */ 
-
-/*----- Tunable parameters ------------------------------------------------*/
-
-#define T_VALID MIN(2)                 /* Challenge validity period */
-#define T_RETRY SEC(10)                        /* Challenge retransmit interval */
-
-#define VALIDP(kx, now) ((now) < (kx)->t_valid)
+ */
 
 /*----- Static tables -----------------------------------------------------*/
 
 static const char *const pkname[] = {
-  "pre-challenge", "cookie", "challenge",
-  "reply", "switch-rq", "switch-ok"
+  "pre-challenge", "challenge", "reply", "switch-rq", "switch-ok"
 };
 
 /*----- Various utilities -------------------------------------------------*/
 
+/* --- @VALIDP@ --- *
+ *
+ * Arguments:  @const keyexch *kx@ = key exchange state
+ *             @time_t now@ = current time in seconds
+ *
+ * Returns:    Whether the challenge in the key-exchange state is still
+ *             valid or should be regenerated.
+ */
+
+#define VALIDP(kx, now) ((now) < (kx)->t_valid)
+
 /* --- @hashge@ --- *
  *
  * Arguments:  @ghash *h@ = pointer to hash context
@@ -264,21 +265,17 @@ static void timer(struct timeval *tv, void *v)
 /* --- @settimer@ --- *
  *
  * Arguments:  @keyexch *kx@ = pointer to key exchange context
- *             @time_t t@ = when to set the timer for
+ *             @struct timeval *tv@ = when to set the timer for
  *
  * Returns:    ---
  *
  * Use:                Sets the timer for the next key exchange attempt.
  */
 
-static void settimer(keyexch *kx, time_t t)
+static void settimer(keyexch *kx, struct timeval *tv)
 {
-  struct timeval tv;
-  if (kx->f & KXF_TIMER)
-    sel_rmtimer(&kx->t);
-  tv.tv_sec = t;
-  tv.tv_usec = 0;
-  sel_addtimer(&sel, &kx->t, &tv, timer, kx);
+  if (kx->f & KXF_TIMER) sel_rmtimer(&kx->t);
+  sel_addtimer(&sel, &kx->t, tv, timer, kx);
   kx->f |= KXF_TIMER;
 }
 
@@ -598,7 +595,7 @@ static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
       goto badcheck;
 
     /* --- Fill in a new challenge block --- */
-    
+
     kxc = kxc_new(kx);
     G_COPY(gg, kxc->c, c);
     G_COPY(gg, kxc->r, r);
@@ -606,7 +603,7 @@ static kxchal *respond(keyexch *kx, unsigned msg, buf *b)
     h = GH_INIT(algs.h);
     HASH_STRING(h, "tripe-check-hash");
     GH_HASH(h, ck, indexsz);
-    GH_DONE(h, kxc->hc);
+    GH_DONE(h, kxc->ck);
     GH_DESTROY(h);
 
     h = GH_INIT(algs.h);
@@ -678,7 +675,7 @@ bad:
   G_DESTROY(gg, cc);
   G_DESTROY(gg, r);
   mp_drop(cv);
-  return (0);  
+  return (0);
 }
 
 /* --- @dochallenge@ --- *
@@ -727,6 +724,7 @@ static void resend(keyexch *kx)
   kxchal *kxc;
   buf bb;
   stats *st = p_stats(kx->p);
+  struct timeval tv;
   buf *b;
 
   switch (kx->s) {
@@ -769,8 +767,11 @@ static void resend(keyexch *kx)
     p_txend(kx->p);
   }
 
-  if (kx->s < KXS_SWITCH)
-    settimer(kx, time(0) + T_RETRY);
+  if (kx->s < KXS_SWITCH) {
+    gettimeofday(&tv, 0);
+    tv.tv_sec += T_RETRY;
+    settimer(kx, &tv);
+  }
 }
 
 /* --- @decryptrest@ --- *
@@ -795,6 +796,7 @@ static int decryptrest(keyexch *kx, kxchal *kxc, unsigned msg, buf *b)
     a_warn("KX", "?PEER", kx->p, "decrypt-failed", "%s", pkname[msg], A_END);
     return (-1);
   }
+  if (!BOK(&bb)) return (-1);
   buf_init(b, BBASE(&bb), BLEN(&bb));
   return (0);
 }
@@ -857,7 +859,7 @@ static void commit(keyexch *kx, kxchal *kxc)
   kx->r[0] = kxc;
   kx->nr = 1;
   kxc_stoptimer(kxc);
-  ksl_link(kx->ks, kxc->ks);  
+  ksl_link(kx->ks, kxc->ks);
 }
 
 /* --- @doreply@ --- *
@@ -886,7 +888,7 @@ static int doreply(keyexch *kx, buf *b)
   if (BLEFT(b)) {
     a_warn("KX", "?PEER", kx->p, "invalid", "reply", A_END);
     goto bad;
-  }    
+  }
   if (kx->s == KXS_CHAL) {
     commit(kx, kxc);
     kx->s = KXS_COMMIT;
@@ -910,8 +912,12 @@ bad:
 static void kxfinish(keyexch *kx)
 {
   kxchal *kxc = kx->r[0];
+  struct timeval tv;
+
   ks_activate(kxc->ks);
-  settimer(kx, ks_tregen(kxc->ks));
+  gettimeofday(&tv, 0);
+  tv.tv_sec += T_REGEN;
+  settimer(kx, &tv);
   kx->s = KXS_SWITCH;
   a_notify("KXDONE", "?PEER", kx->p, A_END);
   p_stats(kx->p)->t_kx = time(0);
@@ -1012,7 +1018,7 @@ static int doswitchok(keyexch *kx, buf *b)
   return (0);
 
 bad:
-  return (-1);  
+  return (-1);
 }
 
 /*----- Main code ---------------------------------------------------------*/
@@ -1067,7 +1073,7 @@ static void start(keyexch *kx, time_t now)
 
   assert(kx->f & KXF_DEAD);
 
-  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);
@@ -1158,19 +1164,26 @@ void kx_start(keyexch *kx, int forcep)
 
 void kx_message(keyexch *kx, unsigned msg, buf *b)
 {
-  time_t now = time(0);
+  struct timeval now, tv;
   stats *st = p_stats(kx->p);
   size_t sz = BSZ(b);
   int rc;
 
+  gettimeofday(&now, 0);
+  if (kx->f & KXF_CORK) {
+    start(kx, now.tv_sec);
+    TV_ADDL(&tv, &now, T_RETRY, 0);
+    settimer(kx, &tv);
+    a_notify("KXSTART", A_END);
+  }
+
   if (checkpub(kx))
     return;
 
-  if (!VALIDP(kx, now)) {
+  if (!VALIDP(kx, now.tv_sec)) {
     stop(kx);
-    start(kx, now);
+    start(kx, now.tv_sec);
   }
-
   T( trace(T_KEYEXCH, "keyexch: processing %s packet from `%s'",
           msg < KX_NMSG ? pkname[msg] : "unknown", p_name(kx->p)); )
 
@@ -1233,7 +1246,7 @@ void kx_free(keyexch *kx)
 
 void kx_newkeys(keyexch *kx)
 {
-  if (km_getpubkey(p_name(kx->p), kx->kpub, &kx->texp_kpub))
+  if (km_getpubkey(p_tag(kx->p), kx->kpub, &kx->texp_kpub))
     return;
   kx->f |= KXF_PUBKEY;
   if ((kx->f & KXF_DEAD) || kx->s != KXS_SWITCH) {
@@ -1250,6 +1263,7 @@ void kx_newkeys(keyexch *kx)
  * Arguments:  @keyexch *kx@ = pointer to key exchange context
  *             @peer *p@ = pointer to peer context
  *             @keyset **ks@ = pointer to keyset list
+ *             @unsigned f@ = various useful flags
  *
  * Returns:    Zero if OK, nonzero if it failed.
  *
@@ -1258,19 +1272,21 @@ void kx_newkeys(keyexch *kx)
  *             exchange.
  */
 
-int kx_init(keyexch *kx, peer *p, keyset **ks)
+int kx_init(keyexch *kx, peer *p, keyset **ks, unsigned f)
 {
   kx->ks = ks;
   kx->p = p;
   kx->kpub = G_CREATE(gg);
-  if (km_getpubkey(p_name(p), kx->kpub, &kx->texp_kpub)) {
+  if (km_getpubkey(p_tag(p), kx->kpub, &kx->texp_kpub)) {
     G_DESTROY(gg, kx->kpub);
     return (-1);
   }
-  kx->f = KXF_DEAD | KXF_PUBKEY;
-  start(kx, time(0));
-  resend(kx);
-  /* Don't notify here: the ADD message hasn't gone out yet. */
+  kx->f = KXF_DEAD | KXF_PUBKEY | f;
+  if (!(kx->f & KXF_CORK)) {
+    start(kx, time(0));
+    resend(kx);
+    /* Don't notify here: the ADD message hasn't gone out yet. */
+  }
   return (0);
 }