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 663b9176f48986833b2531e329aa1924b47c1ea2..ee67e9a367c660e93e26d74eed398c6e76a7782d 100644 (file)
@@ -214,7 +214,8 @@ Additional attributes to set on the parameters
 as
 .IB key = value
 pairs separated by spaces.
 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
 .TP
 .I kx-expire
 Expiry time for generated keys.  Default is
index f1279ad79eaac0e4d358243a4255cedd6172503b..81d2ff707a38243fca6ff9b555579dbe62e5bcf5 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']]),
                                             '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'),
                ('kx-expire', 'now + 1 year'),
                ('kx-warn-days', '28'),
                ('bulk', 'iiv'),
index bbaa123074e14605b795825960eb3f3440b816ad..314da5e487d36f7955e1f7dc0bc371b26c9b6f78 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)
 
   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); }
 #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;
   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;
 
 } 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);
   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,
 }
 
 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); })
 
       { 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;
 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)
 }
 
 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) {
   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;
       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;
       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) {
 
   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;
       rc = buf_putmp(b, t);
       break;
-    case DHFMT_STD:
+    case DHFMT_STD: std:
       if ((p = buf_get(b, g->gesz)) == 0)
        rc = -1;
       else {
       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;
   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;
 
 } 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;
 {
   ecdh_grp *g;
   ec_info ei;
+  int ser;
   const char *err;
 
   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);
   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);
   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,
 }
 
 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);
       { 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;
 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)
 }
 
 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) {
   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();
   }
     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) {
 
   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);
     default: abort();
   }
   EC_DESTROY(&T);
index de3bfcb12f6109bc733f239a6184fb24dbc07b16..e15a66ac75e4b437360ccc3b5d8af5bffdd37934 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
 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
 .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 33f07b5222fdf1804097bb9b6c316088e33a1387..bdac42185e3f6077a1a77a7671ed4b8d4f6c0c94 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.
 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
 .SS "Using SLIP interfaces"
 Though not for the faint of heart, it is possible to get
 .B tripe
index cf6f32af826e3ea94a6d4475c48d3f4516868b9d..ff32d9ee77719c130fa553050004e02ce7d68941 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