From 07bdda1fdf877d00dd63d53ebd5159b5edd1df29 Mon Sep 17 00:00:00 2001 Message-Id: <07bdda1fdf877d00dd63d53ebd5159b5edd1df29.1714159931.git.mdw@distorted.org.uk> From: Mark Wooding Date: Thu, 26 May 2016 09:26:09 +0100 Subject: [PATCH] server/, keys/: Alternative serialization formats for hashing. Organization: Straylight/Edgeware From: Mark Wooding 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 | 3 +- keys/tripe-keys.in | 2 +- server/dh.c | 61 +++++++++++++++++++++++++++++---------- server/tripe-admin.5.in | 6 ++++ server/tripe.8.in | 14 +++++++++ t/keyring-beta-new | 8 ++--- 6 files changed, 73 insertions(+), 21 deletions(-) diff --git a/keys/tripe-keys.conf.5.in b/keys/tripe-keys.conf.5.in index 663b9176..ee67e9a3 100644 --- a/keys/tripe-keys.conf.5.in +++ b/keys/tripe-keys.conf.5.in @@ -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 diff --git a/keys/tripe-keys.in b/keys/tripe-keys.in index f1279ad7..81d2ff70 100644 --- a/keys/tripe-keys.in +++ b/keys/tripe-keys.in @@ -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'), diff --git a/server/dh.c b/server/dh.c index bbaa1230..314da5e4 100644 --- a/server/dh.c +++ b/server/dh.c @@ -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); diff --git a/server/tripe-admin.5.in b/server/tripe-admin.5.in index de3bfcb1..e15a66ac 100644 --- a/server/tripe-admin.5.in +++ b/server/tripe-admin.5.in @@ -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 diff --git a/server/tripe.8.in b/server/tripe.8.in index 33f07b52..bdac4218 100644 --- a/server/tripe.8.in +++ b/server/tripe.8.in @@ -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 diff --git a/t/keyring-beta-new b/t/keyring-beta-new index cf6f32af..ff32d9ee 100644 --- a/t/keyring-beta-new +++ b/t/keyring-beta-new @@ -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 -- [mdw]