chiark / gitweb /
Allow different peer associations to use different private keys.
[tripe] / server / keyset.c
index 9dd17facc3af65fa364905f595a71f26cd6cb944..898c55a4ccd9a8de84d42a4e912bfc6d74c85b78 100644 (file)
 
 /*----- Tunable parameters ------------------------------------------------*/
 
-/* --- Note on size limits --- *
- *
- * For a 64-bit block cipher (e.g., Blowfish), the probability of a collision
- * occurring after 32 MB is less than %$2^{-21}$%, and the probability of a
- * collision occurring after 64 MB is less than %$2^{-19}$%.  These could be
- * adjusted dependent on the encryption scheme, but it's too much pain.
- */
-
 #define T_EXP MIN(60)                  /* Expiry time for a key */
 #define T_REGEN MIN(45)                        /* Regeneration time for a key */
-#define SZ_EXP MEG(64)                 /* Expiry data size for a key */
-#define SZ_REGEN MEG(32)               /* Data size threshold for regen */
 
 /*----- Handy macros ------------------------------------------------------*/
 
@@ -153,7 +143,7 @@ static int doencrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
     nsz = osz - sz;
   else
     nsz = 0;
-  if (osz >= SZ_REGEN && nsz < SZ_REGEN) {
+  if (osz >= ks->sz_regen && ks->sz_regen > nsz) {
     T( trace(T_KEYSET, "keyset: keyset %u data regen limit exceeded -- "
             "forcing exchange", ks->seq); )
     rc = KSERR_REGEN;
@@ -198,7 +188,7 @@ static int dodecrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq)
 
   if (psz < ivsz + SEQSZ + tagsz) {
     T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); )
-    return (KSERR_DECRYPT);
+    return (KSERR_MALFORMED);
   }
   sz = psz - ivsz - SEQSZ - tagsz;
   pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz;
@@ -303,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); )
@@ -318,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);                                                       \
@@ -357,13 +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 = SZ_EXP;
+  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);
 }
 
@@ -430,7 +422,7 @@ int ks_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
  *             @buf *b@ = pointer to an input buffer
  *             @buf *bb@ = pointer to an output buffer
  *
- * Returns:    Zero on success; @KSERR_DECRYPT@ on failure.  Also returns
+ * Returns:    Zero on success; @KSERR_...@ on failure.  Also returns
  *             zero if there was insufficient buffer (but the output buffer
  *             is broken in this case).
  *
@@ -443,12 +435,12 @@ int ks_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb)
 {
   time_t now = time(0);
   uint32 seq;
+  int err;
 
-  if (!KEYOK(ks, now) ||
-      buf_ensure(bb, BLEN(b)) ||
-      dodecrypt(ks, ty, b, bb, &seq) ||
-      seq_check(&ks->iseq, seq, "SYMM"))
-    return (KSERR_DECRYPT);
+  if (!KEYOK(ks, now)) return (KSERR_DECRYPT);
+  if (buf_ensure(bb, BLEN(b))) return (0);
+  if ((err = dodecrypt(ks, ty, b, bb, &seq)) != 0) return (err);
+  if (seq_check(&ks->iseq, seq, "SYMM")) return (KSERR_SEQ);
   return (0);
 }
 
@@ -583,24 +575,26 @@ int ksl_decrypt(keyset **ksroot, unsigned ty, buf *b, buf *bb)
   time_t now = time(0);
   keyset *ks;
   uint32 seq;
+  int err;
 
   if (buf_ensure(bb, BLEN(b)))
-    return (KSERR_DECRYPT);
+    return (0);
 
   for (ks = *ksroot; ks; ks = ks->next) {
     if (!KEYOK(ks, now))
       continue;
-    if (!dodecrypt(ks, ty, b, bb, &seq)) {
+    if ((err = dodecrypt(ks, ty, b, bb, &seq)) == 0) {
       if (ks->f & KSF_LISTEN) {
        T( trace(T_KEYSET, "keyset: implicitly activating keyset %u",
                 ks->seq); )
        ks->f &= ~KSF_LISTEN;
       }
       if (seq_check(&ks->iseq, seq, "SYMM"))
-       return (KSERR_DECRYPT);
+       return (KSERR_SEQ);
       else
        return (0);
     }
+    if (err != KSERR_DECRYPT) return (err);
   }
   T( trace(T_KEYSET, "keyset: no matching keys, or incorrect MAC"); )
   return (KSERR_DECRYPT);