chiark / gitweb /
server/, keys/: Alternative serialization formats for hashing.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 26 May 2016 08:26:09 +0000 (09:26 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sun, 14 May 2017 17:19:09 +0000 (18:19 +0100)
The old format was variable length, which leaks the length of the value
to local adversaries.  Provide a switch to use the better
constant-length encoding for hashing.

Make this the default when setting up new key distribution centres.

keys/tripe-keys.conf.5.in
keys/tripe-keys.in
server/dh.c
server/tripe-admin.5.in
server/tripe.8.in
t/keyring-beta-new

index 663b917..ee67e9a 100644 (file)
@@ -214,7 +214,8 @@ Additional attributes to set on the parameters
 as
 .IB key = value
 pairs separated by spaces.
-Default is empty.
+Default is
+.BR serialization=constlen .
 .TP
 .I kx-expire
 Expiry time for generated keys.  Default is
index f1279ad..81d2ff7 100644 (file)
@@ -244,7 +244,7 @@ def conf_defaults():
                                             'ec': 'ec-param'}[conf['kx']]),
                ('kx-param', lambda: {'dh': '-LS -b3072 -B256',
                                      'ec': '-Cnist-p256'}[conf['kx']]),
-               ('kx-attrs', ''),
+               ('kx-attrs', 'serialization=constlen'),
                ('kx-expire', 'now + 1 year'),
                ('kx-warn-days', '28'),
                ('bulk', 'iiv'),
index bbaa123..314da5e 100644 (file)
@@ -95,6 +95,19 @@ static void pre##_freege(const dhgrp *, dhge *); \
   KLOAD_HALF(pre, ty, TY, priv, PRIV, setgroup, setpriv, setpub)       \
   KLOAD_HALF(pre, ty, TY, pub, PUB, setgroup, { kd->k = 0; }, setpub)
 
+enum { DHSER_V0, DHSER_CONSTLEN };
+
+static int get_serialization(key_file *kf, key *k, dstr *e)
+{
+  const char *p = key_getattr(kf, k, "serialization");
+  if (!p || strcmp(p, "v0") == 0) return (DHSER_V0);
+  else if (strcmp(p, "constlen") == 0) return (DHSER_CONSTLEN);
+  else {
+    a_format(e, "unknown-serialization-format", "%s", p, A_END);
+    return (-1);
+  }
+}
+
 #ifndef NTRACE
 static void setupstr(mptext_stringctx *sc)
   { sc->buf = (char *)buf_u; sc->lim = sc->buf + sizeof(buf_u); }
@@ -132,14 +145,21 @@ typedef struct intdh_grp {
   mpmont mm;
   mp *q, *G;
   size_t gesz;
+  int ser;
 } intdh_grp;
 
 typedef struct intdh_sc { mp *x; } intdh_sc;
 typedef struct intdh_ge { mp *X; } intdh_ge;
 
-static dhgrp *intdh_mkgroup(const dh_param *dp)
+static dhgrp *intdh_mkgroup(key_file *kf, key *k,
+                           const dh_param *dp, dstr *e)
 {
-  intdh_grp *g = CREATE(intdh_grp);
+  intdh_grp *g;
+  int ser;
+
+  if ((ser = get_serialization(kf, k, e)) < 0) return (0);
+  g = CREATE(intdh_grp);
+  g->ser = ser;
   g->_g.scsz = mp_octets(dp->q);
   g->gesz = mp_octets(dp->p);
   mpmont_create(&g->mm, dp->p);
@@ -166,7 +186,7 @@ static dhge *intdh_mptoge(const dhgrp *gg, mp *z)
 }
 
 KLOAD(intdh, dh, DH,
-      { kd->grp = intdh_mkgroup(&p.dp); },
+      { if ((kd->grp = intdh_mkgroup(kf, k, &p.dp, e)) == 0) goto fail; },
       { kd->k = intdh_mptosc(kd->grp, p.x); },
       { kd->K = intdh_mptoge(kd->grp, p.y); })
 
@@ -211,7 +231,9 @@ static void intdh_tracegrp(const dhgrp *gg)
 static int intdh_samegrpp(const dhgrp *gg, const dhgrp *hh)
 {
   const intdh_grp *g = (const intdh_grp *)gg, *h = (const intdh_grp *)hh;
-  return (MP_EQ(g->mm.m, h->mm.m) && MP_EQ(g->q, h->q) && MP_EQ(g->G, h->G));
+  return (MP_EQ(g->mm.m, h->mm.m) &&
+         MP_EQ(g->q, h->q) && MP_EQ(g->G, h->G) &&
+         g->ser == h->ser);
 }
 
 static void intdh_freegrp(dhgrp *gg)
@@ -263,10 +285,11 @@ static dhge *intdh_ldge(const dhgrp *gg, buf *b, int fmt)
   const octet *p;
 
   switch (fmt) {
-    case DHFMT_VAR: case DHFMT_HASH:
+    case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
+    case DHFMT_VAR:
       if ((t = buf_getmp(b)) == 0) return (0);
       break;
-    case DHFMT_STD:
+    case DHFMT_STD: std:
       if ((p = buf_get(b, g->gesz)) == 0) return (0);
       t = mp_loadb(MP_NEW, p, g->gesz);
       break;
@@ -289,10 +312,11 @@ static int intdh_stge(const dhgrp *gg, buf *b, const dhge *YY, int fmt)
 
   t = mpmont_reduce(&g->mm, MP_NEW, Y->X);
   switch (fmt) {
-    case DHFMT_VAR: case DHFMT_HASH:
+    case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
+    case DHFMT_VAR:
       rc = buf_putmp(b, t);
       break;
-    case DHFMT_STD:
+    case DHFMT_STD: std:
       if ((p = buf_get(b, g->gesz)) == 0)
        rc = -1;
       else {
@@ -359,22 +383,26 @@ typedef struct ecdh_grp {
   dhgrp _g;
   ec_info ei;
   ec P;
+  int ser;
 } ecdh_grp;
 
 typedef struct ecdh_sc { mp *x; } ecdh_sc;
 typedef struct ecdh_ge { ec Q; } ecdh_ge;
 
-static dhgrp *ecdh_mkgroup(const char *cstr, dstr *e)
+static dhgrp *ecdh_mkgroup(key_file *kf, key *k, const char *cstr, dstr *e)
 {
   ecdh_grp *g;
   ec_info ei;
+  int ser;
   const char *err;
 
+  if ((ser = get_serialization(kf, k, e)) < 0) return (0);
   if ((err = ec_getinfo(&ei, cstr)) != 0) {
     a_format(e, "decode-failed", "%s", err, A_END);
     return (0);
   }
   g = CREATE(ecdh_grp);
+  g->ser = ser;
   g->ei = ei;
   EC_CREATE(&g->P); EC_IN(g->ei.c, &g->P, &g->ei.g);
   g->_g.scsz = mp_octets(g->ei.r);
@@ -400,7 +428,7 @@ static dhge *ecdh_ectoge(const dhgrp *gg, ec *Q)
 }
 
 KLOAD(ecdh, ec, EC,
-      { if ((kd->grp = ecdh_mkgroup(p.cstr, e)) == 0) goto fail; },
+      { if ((kd->grp = ecdh_mkgroup(kf, k, p.cstr, e)) == 0) goto fail; },
       { kd->k = ecdh_mptosc(kd->grp, p.x); },
       { if ((kd->K = ecdh_ectoge(kd->grp, &p.p)) == 0) {
          a_format(e, "bad-public-vector", A_END);
@@ -470,7 +498,8 @@ static void ecdh_tracegrp(const dhgrp *gg)
 static int ecdh_samegrpp(const dhgrp *gg, const dhgrp *hh)
 {
   const ecdh_grp *g = (const ecdh_grp *)gg, *h = (const ecdh_grp *)hh;
-  return (ec_sameinfop(&g->ei, &h->ei));
+  return (ec_sameinfop(&g->ei, &h->ei) &&
+         g->ser == h->ser);
 }
 
 static void ecdh_freegrp(dhgrp *gg)
@@ -522,8 +551,9 @@ static dhge *ecdh_ldge(const dhgrp *gg, buf *b, int fmt)
   ec T = EC_INIT;
 
   switch (fmt) {
-    case DHFMT_VAR: case DHFMT_HASH: if (buf_getec(b, &T)) return (0); break;
-    case DHFMT_STD: if (ec_getraw(g->ei.c, b, &T)) return (0); break;
+    case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
+    case DHFMT_VAR: if (buf_getec(b, &T)) return (0); break;
+    case DHFMT_STD: std: if (ec_getraw(g->ei.c, b, &T)) return (0); break;
     default:
       abort();
   }
@@ -541,8 +571,9 @@ static int ecdh_stge(const dhgrp *gg, buf *b, const dhge *YY, int fmt)
 
   EC_OUT(g->ei.c, &T, &Y->Q);
   switch (fmt) {
-    case DHFMT_VAR: case DHFMT_HASH: rc = buf_putec(b, &T); break;
-    case DHFMT_STD: rc = ec_putraw(g->ei.c, b, &T); break;
+    case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
+    case DHFMT_VAR: rc = buf_putec(b, &T); break;
+    case DHFMT_STD: std: rc = ec_putraw(g->ei.c, b, &T); break;
     default: abort();
   }
   EC_DESTROY(&T);
index de3bfcb..e15a66a 100644 (file)
@@ -1316,6 +1316,12 @@ The key specifies the use of an unknown symmetric encryption function
 for mask generation.  Maybe the key was generated wrongly, or maybe the
 version of Catacomb installed is too old.
 .SP
+.BI "KEYMGMT " which "-keyring " file " key " tag " unknown-serialization-format " ser
+The key specifies the use of an unknown serialization format
+.I ser
+for hashing group elements.  Maybe the key was generated wrongly, or
+maybe the version of Catacomb installed is too old.
+.SP
 .BI "KEYMGMT " which "-keyring " file " key " tag " no-hmac-for-hash " hash
 No message authentication code was given explicitly, and there's no
 implementation of HMAC for the selected hash function
index 33f07b5..bdac421 100644 (file)
@@ -412,6 +412,20 @@ more significantly, the transform is entirely deterministic, so (a) it
 doesn't need the (possibly slow) random number generator, and (b) it
 closes a kleptographic channel, over which a compromised implementation
 could leak secret information to a third party.
+.SS "Other key attributes"
+The following attributes can also be set on keys.
+.TP
+.B serialization
+Selects group-element serialization formats.
+The recommended setting is
+.BR constlen ,
+which selects a constant-length encoding when hashing group elements.
+The default,
+for backwards compatibility, is
+.BR v0 ;
+but this is deprecated.
+(The old format uses a variable length format for hashing,
+which can leak information through timing.)
 .SS "Using SLIP interfaces"
 Though not for the faint of heart, it is possible to get
 .B tripe
index cf6f32a..ff32d9e 100644 (file)
@@ -1,4 +1,4 @@
-000f1070:tripe-ec-param struct:[curve=string,shared:secp160r1] forever forever bulk=iiv
-63803f04:tripe-ec:carol struct:[p=ec,public:0x42a11d34a1e19a69222a67c6ec29ff1d421cb021,0xc7d35a6dc9c330a09ee8e30680397b8bf51c29de,private=struct:[x=integer,private,burn:964893088925854502228477969935127891578649410999],curve=string,shared:secp160r1] forever forever bulk=iiv
-4045911b:tripe-ec:bob struct:[p=ec,public:0xcfc0b74fe1c4f30ced726bb70fbe4592ed8456ba,0x351d4dcbc200ccd3f3b6f4ecc112ecbf2043402d,private=struct:[x=integer,private,burn:333869955870933965311262832506583263321304092611],curve=string,shared:secp160r1] forever forever bulk=iiv
-e1a55f0e:tripe-ec:alice struct:[p=ec,public:0xce3bdc518066042b19083e2d27b0ded1915cb6b9,0xadef0e2006072f7bf038ef608e039a47e5767070,private=struct:[x=integer,private,burn:184161721501402669384082492238940360070520035996],curve=string,shared:secp160r1] forever forever bulk=iiv
+000f1070:tripe-ec-param struct:[curve=string,shared:secp160r1] forever forever bulk=iiv&serialization=constlen
+63803f04:tripe-ec:carol struct:[p=ec,public:0x42a11d34a1e19a69222a67c6ec29ff1d421cb021,0xc7d35a6dc9c330a09ee8e30680397b8bf51c29de,private=struct:[x=integer,private,burn:964893088925854502228477969935127891578649410999],curve=string,shared:secp160r1] forever forever bulk=iiv&serialization=constlen
+4045911b:tripe-ec:bob struct:[p=ec,public:0xcfc0b74fe1c4f30ced726bb70fbe4592ed8456ba,0x351d4dcbc200ccd3f3b6f4ecc112ecbf2043402d,private=struct:[x=integer,private,burn:333869955870933965311262832506583263321304092611],curve=string,shared:secp160r1] forever forever bulk=iiv&serialization=constlen
+e1a55f0e:tripe-ec:alice struct:[p=ec,public:0xce3bdc518066042b19083e2d27b0ded1915cb6b9,0xadef0e2006072f7bf038ef608e039a47e5767070,private=struct:[x=integer,private,burn:184161721501402669384082492238940360070520035996],curve=string,shared:secp160r1] forever forever bulk=iiv&serialization=constlen