From ef09dae1af4f84ae093aa071f475d9dd1fc6b1bc Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Thu, 24 Aug 2017 22:24:07 +0100 Subject: [PATCH] server/: Expose and enhance the bulk-key-derivation protocol. * Rename `struct rawkey' to `deriveargs', and document it; * make `ks_derivekey' private in `bulkcrypto.c', and rename it `derivekey'; * make the various contributions to the derived keys be optional and handle them not existing sensibly; and * cope with the idea that a caller might only want incoming or outgoing keys, but not both. This lays the groundwork for a separately usable public-key encryption scheme based on the existing machinery, but this will come a bit later. --- server/bulkcrypto.c | 107 ++++++++++++++++++++++++++++++++++++++++++---------- server/keyexch.c | 12 +++--- server/keyset.c | 76 ++++--------------------------------- server/tripe.h | 63 ++++++++++++------------------- 4 files changed, 126 insertions(+), 132 deletions(-) diff --git a/server/bulkcrypto.c b/server/bulkcrypto.c index 7d754cd7..fff2c825 100644 --- a/server/bulkcrypto.c +++ b/server/bulkcrypto.c @@ -49,6 +49,53 @@ trace_block(T_CRYPTO, "crypto: expected MAC", (pmac), (tagsz)); \ }) } while (0) +/* --- @derivekey@ --- * + * + * Arguments: @octet *k@ = pointer to an output buffer of at least + * @MAXHASHSZ@ bytes + * @size_t ksz@ = actual size wanted (for tracing) + * @const deriveargs@ = derivation parameters, as passed into + * @genkeys@ + * @int dir@ = direction for the key (@DIR_IN@ or @DIR_OUT@) + * @const char *what@ = label for the key (input to derivation) + * + * Returns: --- + * + * Use: Derives a session key, for use on incoming or outgoing data. + */ + +static void derivekey(octet *k, size_t ksz, const deriveargs *a, + int dir, const char *what) +{ + const gchash *hc = a->hc; + ghash *h; + + assert(ksz <= hc->hashsz); + assert(hc->hashsz <= MAXHASHSZ); + h = GH_INIT(hc); + GH_HASH(h, a->what, strlen(a->what)); GH_HASH(h, what, strlen(what) + 1); + switch (dir) { + case DIR_IN: + if (a->x) GH_HASH(h, a->k, a->x); + if (a->y != a->x) GH_HASH(h, a->k + a->x, a->y - a->x); + break; + case DIR_OUT: + if (a->y != a->x) GH_HASH(h, a->k + a->x, a->y - a->x); + if (a->x) GH_HASH(h, a->k, a->x); + break; + default: + abort(); + } + GH_HASH(h, a->k + a->y, a->z - a->y); + GH_DONE(h, k); + GH_DESTROY(h); + IF_TRACING(T_KEYSET, { IF_TRACING(T_CRYPTO, { + char _buf[32]; + sprintf(_buf, "crypto: %s key %s", dir ? "outgoing" : "incoming", what); + trace_block(T_CRYPTO, _buf, k, ksz); + }) }) +} + /*----- Common functionality for generic-composition transforms -----------*/ #define CHECK_MAC(h, pmac, tagsz) do { \ @@ -309,7 +356,7 @@ static size_t v0_overhead(const bulkalgs *aa) static size_t v0_expsz(const bulkalgs *aa) { const v0_algs *a = (const v0_algs *)aa; return (gencomp_expsz(&a->ga)); } -static bulkctx *v0_genkeys(const bulkalgs *aa, const struct rawkey *rk) +static bulkctx *v0_genkeys(const bulkalgs *aa, const deriveargs *da) { const v0_algs *a = (const v0_algs *)aa; v0_ctx *bc = CREATE(v0_ctx); @@ -318,9 +365,10 @@ static bulkctx *v0_genkeys(const bulkalgs *aa, const struct rawkey *rk) bc->tagsz = a->ga.tagsz; for (i = 0; i < NDIR; i++) { - ks_derivekey(k, a->ga.cksz, rk, i, "encryption"); + if (!(da->f&(1 << i))) { bc->d[i].c = 0; bc->d[i].m = 0; continue; } + derivekey(k, a->ga.cksz, da, i, "encryption"); bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz); - ks_derivekey(k, a->ga.mksz, rk, i, "integrity"); + derivekey(k, a->ga.mksz, da, i, "integrity"); bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz); } return (&bc->_b); @@ -344,8 +392,8 @@ static void v0_freectx(bulkctx *bbc) int i; for (i = 0; i < NDIR; i++) { - GC_DESTROY(bc->d[i].c); - GM_DESTROY(bc->d[i].m); + if (bc->d[i].c) GC_DESTROY(bc->d[i].c); + if (bc->d[i].m) GM_DESTROY(bc->d[i].m); } DESTROY(bc); } @@ -359,10 +407,13 @@ static int v0_encrypt(bulkctx *bbc, unsigned ty, const octet *p = BCUR(b); size_t sz = BLEFT(b); octet *qmac, *qseq, *qiv, *qpk; - size_t ivsz = GC_CLASS(c)->blksz; + size_t ivsz; size_t tagsz = bc->tagsz; octet t[4]; + assert(c); + ivsz = GC_CLASS(c)->blksz; + /* --- Determine the ciphertext layout --- */ if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0); @@ -419,10 +470,13 @@ static int v0_decrypt(bulkctx *bbc, unsigned ty, octet *q = BCUR(bb); ghash *h; gcipher *c = bc->d[DIR_IN].c; - size_t ivsz = GC_CLASS(c)->blksz; + size_t ivsz; size_t tagsz = bc->tagsz; octet t[4]; + assert(c); + ivsz = GC_CLASS(c)->blksz; + /* --- Break up the packet into its components --- */ if (psz < ivsz + SEQSZ + tagsz) { @@ -587,7 +641,7 @@ static size_t iiv_expsz(const bulkalgs *aa) return (gencomp_expsz(&a->ga)); } -static bulkctx *iiv_genkeys(const bulkalgs *aa, const struct rawkey *rk) +static bulkctx *iiv_genkeys(const bulkalgs *aa, const deriveargs *da) { const iiv_algs *a = (const iiv_algs *)aa; iiv_ctx *bc = CREATE(iiv_ctx); @@ -596,11 +650,13 @@ static bulkctx *iiv_genkeys(const bulkalgs *aa, const struct rawkey *rk) bc->tagsz = a->ga.tagsz; for (i = 0; i < NDIR; i++) { - ks_derivekey(k, a->ga.cksz, rk, i, "encryption"); + if (!(da->f&(1 << i))) + { bc->d[i].c = 0; bc->d[i].b = 0; bc->d[i].m = 0; continue; } + derivekey(k, a->ga.cksz, da, i, "encryption"); bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz); - ks_derivekey(k, a->bksz, rk, i, "blkc"); + derivekey(k, a->bksz, da, i, "blkc"); bc->d[i].b = GC_INIT(a->b, k, a->bksz); - ks_derivekey(k, a->ga.mksz, rk, i, "integrity"); + derivekey(k, a->ga.mksz, da, i, "integrity"); bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz); } return (&bc->_b); @@ -624,9 +680,9 @@ static void iiv_freectx(bulkctx *bbc) int i; for (i = 0; i < NDIR; i++) { - GC_DESTROY(bc->d[i].c); - GC_DESTROY(bc->d[i].b); - GM_DESTROY(bc->d[i].m); + if (bc->d[i].c) GC_DESTROY(bc->d[i].c); + if (bc->d[i].b) GC_DESTROY(bc->d[i].b); + if (bc->d[i].m) GM_DESTROY(bc->d[i].m); } DESTROY(bc); } @@ -644,10 +700,14 @@ static int iiv_encrypt(bulkctx *bbc, unsigned ty, const octet *p = BCUR(b); size_t sz = BLEFT(b); octet *qmac, *qseq, *qpk; - size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz; + size_t ivsz, blkcsz; size_t tagsz = bc->tagsz; octet t[4]; + assert(c); assert(blkc); + ivsz = GC_CLASS(c)->blksz; + blkcsz = GC_CLASS(blkc)->blksz; + /* --- Determine the ciphertext layout --- */ if (buf_ensure(bb, tagsz + SEQSZ + sz)) return (0); @@ -707,10 +767,14 @@ static int iiv_decrypt(bulkctx *bbc, unsigned ty, octet *q = BCUR(bb); ghash *h; gcipher *c = bc->d[DIR_IN].c, *blkc = bc->d[DIR_IN].b; - size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz; + size_t ivsz, blkcsz; size_t tagsz = bc->tagsz; octet t[4]; + assert(c); assert(blkc); + ivsz = GC_CLASS(c)->blksz; + blkcsz = GC_CLASS(blkc)->blksz; + /* --- Break up the packet into its components --- */ if (psz < SEQSZ + tagsz) { @@ -893,7 +957,7 @@ static size_t naclbox_overhead(const bulkalgs *aa) static size_t naclbox_expsz(const bulkalgs *aa) { return (MEG(2048)); } -static bulkctx *naclbox_genkeys(const bulkalgs *aa, const struct rawkey *rk) +static bulkctx *naclbox_genkeys(const bulkalgs *aa, const deriveargs *da) { const naclbox_algs *a = (const naclbox_algs *)aa; naclbox_ctx *bc = CREATE(naclbox_ctx); @@ -901,7 +965,8 @@ static bulkctx *naclbox_genkeys(const bulkalgs *aa, const struct rawkey *rk) int i; for (i = 0; i < NDIR; i++) { - ks_derivekey(k, a->cksz, rk, i, "encryption"); + if (!(da->f&(1 << i))) { bc->d[i].c = 0; continue; } + derivekey(k, a->cksz, da, i, "encryption"); bc->d[i].c = GC_INIT(a->c, k, a->cksz); } return (&bc->_b); @@ -960,7 +1025,7 @@ static void naclbox_freectx(bulkctx *bbc) naclbox_ctx *bc = (naclbox_ctx *)bbc; int i; - for (i = 0; i < NDIR; i++) GC_DESTROY(bc->d[i].c); + for (i = 0; i < NDIR; i++) { if (bc->d[i].c) GC_DESTROY(bc->d[i].c); } DESTROY(bc); } @@ -975,6 +1040,8 @@ static int naclbox_encrypt(bulkctx *bbc, unsigned ty, size_t sz = BLEFT(b); octet *qmac, *qseq, *qpk; + assert(c); + /* --- Determine the ciphertext layout --- */ if (buf_ensure(bb, POLY1305_TAGSZ + SEQSZ + sz)) return (0); @@ -1022,6 +1089,8 @@ static int naclbox_decrypt(bulkctx *bbc, unsigned ty, size_t sz; octet *q = BCUR(bb); + assert(c); + /* --- Break up the packet into its components --- */ if (psz < SEQSZ + POLY1305_TAGSZ) { diff --git a/server/keyexch.c b/server/keyexch.c index 9d08bec6..be5bc880 100644 --- a/server/keyexch.c +++ b/server/keyexch.c @@ -637,8 +637,8 @@ static kxchal *respond(keyexch *kx, unsigned msg, buf *b) dhge *C = 0; dhge *R = 0; dhge *CC = 0; + deriveargs a; const octet *hc, *ck; - size_t x, y, z; dhsc *c = 0; kxchal *kxc; ghash *h = 0; @@ -752,13 +752,13 @@ static kxchal *respond(keyexch *kx, unsigned msg, buf *b) /* --- Create a new symmetric keyset --- */ - buf_init(&bb, buf_o, sizeof(buf_o)); - g->ops->stge(g, &bb, kx->C, DHFMT_HASH); x = BLEN(&bb); - g->ops->stge(g, &bb, kxc->C, DHFMT_HASH); y = BLEN(&bb); - g->ops->stge(g, &bb, R, DHFMT_HASH); z = BLEN(&bb); + buf_init(&bb, buf_o, sizeof(buf_o)); a.k = BBASE(&bb); + g->ops->stge(g, &bb, kx->C, DHFMT_HASH); a.x = BLEN(&bb); + g->ops->stge(g, &bb, kxc->C, DHFMT_HASH); a.y = BLEN(&bb); + g->ops->stge(g, &bb, R, DHFMT_HASH); a.z = BLEN(&bb); assert(BOK(&bb)); - kxc->ks = ks_gen(BBASE(&bb), x, y, z, kx->p); + kxc->ks = ks_gen(&a, kx->p); } if (C) g->ops->freege(g, C); diff --git a/server/keyset.c b/server/keyset.c index 9429fa4a..a0c4577d 100644 --- a/server/keyset.c +++ b/server/keyset.c @@ -169,95 +169,33 @@ void ks_drop(keyset *ks) DESTROY(ks); } -/* --- @ks_derivekey@ --- * - * - * Arguments: @octet *k@ = pointer to an output buffer of at least - * @MAXHASHSZ@ bytes - * @size_t ksz@ = actual size wanted (for tracing) - * @const struct rawkey *rk@ = a raw key, as passed into - * @genkeys@ - * @int dir@ = direction for the key (@DIR_IN@ or @DIR_OUT@) - * @const char *what@ = label for the key (input to derivation) - * - * Returns: --- - * - * Use: Derives a session key, for use on incoming or outgoing data. - * This function is part of a private protocol between @ks_gen@ - * and the bulk crypto transform @genkeys@ operation. - */ - -struct rawkey { - const gchash *hc; - const octet *k; - size_t x, y, z; -}; - -void ks_derivekey(octet *k, size_t ksz, const struct rawkey *rk, - int dir, const char *what) -{ - const gchash *hc = rk->hc; - ghash *h; - - assert(ksz <= hc->hashsz); - assert(hc->hashsz <= MAXHASHSZ); - h = GH_INIT(hc); - GH_HASH(h, "tripe-", 6); GH_HASH(h, what, strlen(what) + 1); - switch (dir) { - case DIR_IN: - GH_HASH(h, rk->k, rk->x); - GH_HASH(h, rk->k + rk->x, rk->y - rk->x); - break; - case DIR_OUT: - GH_HASH(h, rk->k + rk->x, rk->y - rk->x); - GH_HASH(h, rk->k, rk->x); - break; - default: - abort(); - } - GH_HASH(h, rk->k + rk->y, rk->z - rk->y); - GH_DONE(h, k); - GH_DESTROY(h); - IF_TRACING(T_KEYSET, { IF_TRACING(T_CRYPTO, { - char _buf[32]; - sprintf(_buf, "crypto: %s key %s", dir ? "outgoing" : "incoming", what); - trace_block(T_CRYPTO, _buf, k, ksz); - }) }) -} - /* --- @ks_gen@ --- * * - * Arguments: @const void *k@ = pointer to key material - * @size_t x, y, z@ = offsets into key material (see below) + * Arguments: @deriveargs *a@ = key derivation parameters (modified) * @peer *p@ = pointer to peer information * * Returns: A pointer to the new keyset. * - * Use: Derives a new keyset from the given key material. The - * offsets @x@, @y@ and @z@ separate the key material into three - * parts. Between the @k@ and @k + x@ is `my' contribution to - * the key material; between @k + x@ and @k + y@ is `your' - * contribution; and between @k + y@ and @k + z@ is a shared - * value we made together. These are used to construct two - * collections of symmetric keys: one for outgoing messages, the - * other for incoming messages. + * Use: Derives a new keyset from the given key material. This will + * set the @what@, @f@, and @hc@ members in @*a@; other members + * must be filled in by the caller. * * The new key is marked so that it won't be selected for output * by @ksl_encrypt@. You can still encrypt data with it by * calling @ks_encrypt@ directly. */ -keyset *ks_gen(const void *k, size_t x, size_t y, size_t z, peer *p) +keyset *ks_gen(deriveargs *a, peer *p) { keyset *ks = CREATE(keyset); time_t now = time(0); const algswitch *algs = &p->kx.kpriv->algs; - struct rawkey rk; T( static unsigned seq = 0; ) T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); ) - rk.hc = algs->h; rk.k = k; rk.x = x; rk.y = y; rk.z = z; - ks->bulk = algs->bulk->ops->genkeys(algs->bulk, &rk); + a->what = "tripe-"; a->f = DF_IN | DF_OUT; a->hc = algs->h; + ks->bulk = algs->bulk->ops->genkeys(algs->bulk, a); ks->bulk->ops = algs->bulk->ops; T( ks->seq = seq++; ) diff --git a/server/tripe.h b/server/tripe.h index 4b6c7101..75ad2f1f 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -181,6 +181,16 @@ enum { DHFMT_VAR /* Variable-width-format, mostly a bad idea */ }; +typedef struct deriveargs { + const char *what; /* Operation name (hashed) */ + unsigned f; /* Flags */ +#define DF_IN 1u /* Make incoming key */ +#define DF_OUT 2u /* Make outgoing key */ + const gchash *hc; /* Hash class */ + const octet *k; /* Pointer to contributions */ + size_t x, y, z; /* Markers in contributions */ +} deriveargs; + typedef struct bulkalgs { const struct bulkops *ops; } bulkalgs; @@ -194,8 +204,6 @@ typedef struct bulkchal { size_t tagsz; } bulkchal; -struct rawkey; - typedef struct dhops { const char *name; @@ -325,9 +333,17 @@ typedef struct bulkops { * after which the keys must no longer be used. */ - bulkctx *(*genkeys)(const bulkalgs */*a*/, const struct rawkey */*rk*/); + bulkctx *(*genkeys)(const bulkalgs */*a*/, const deriveargs */*a*/); /* Generate session keys and construct and return an appropriate - * context for using them, by calling @ks_derive@. + * context for using them. The offsets @a->x@, @a->y@ and @a->z@ + * separate the key material into three parts. Between @a->k@ and + * @a->k + a->x@ is `my' contribution to the key material; between + * @a->k + a->x@ and @a->k + a->y@ is `your' contribution; and + * between @a->k + a->y@ and @a->k + a->z@ is a shared value we made + * together. These are used to construct (up to) two collections of + * symmetric keys: one for outgoing messages, the other for incoming + * messages. If @a->x == 0@ (or @a->y == a->x@) then my (or your) + * contribution is omitted. */ bulkchal *(*genchal)(const bulkalgs */*a*/); @@ -939,52 +955,23 @@ extern int kx_init(keyexch */*kx*/, peer */*p*/, extern void ks_drop(keyset */*ks*/); -/* --- @ks_derivekey@ --- * - * - * Arguments: @octet *k@ = pointer to an output buffer of at least - * @MAXHASHSZ@ bytes - * @size_t ksz@ = actual size wanted (for tracing) - * @const struct rawkey *rk@ = a raw key, as passed into - * @genkeys@ - * @int dir@ = direction for the key (@DIR_IN@ or @DIR_OUT@) - * @const char *what@ = label for the key (input to derivation) - * - * Returns: --- - * - * Use: Derives a session key, for use on incoming or outgoing data. - * This function is part of a private protocol between @ks_gen@ - * and the bulk crypto transform @genkeys@ operation. - */ - -extern void ks_derivekey(octet */*k*/, size_t /*ksz*/, - const struct rawkey */*rk*/, - int /*dir*/, const char */*what*/); - /* --- @ks_gen@ --- * * - * Arguments: @const void *k@ = pointer to key material - * @size_t x, y, z@ = offsets into key material (see below) + * Arguments: @deriveargs *a@ = key derivation parameters (modified) * @peer *p@ = pointer to peer information * * Returns: A pointer to the new keyset. * - * Use: Derives a new keyset from the given key material. The - * offsets @x@, @y@ and @z@ separate the key material into three - * parts. Between the @k@ and @k + x@ is `my' contribution to - * the key material; between @k + x@ and @k + y@ is `your' - * contribution; and between @k + y@ and @k + z@ is a shared - * value we made together. These are used to construct two - * collections of symmetric keys: one for outgoing messages, the - * other for incoming messages. + * Use: Derives a new keyset from the given key material. This will + * set the @what@, @f@, and @hc@ members in @*a@; other members + * must be filled in by the caller. * * The new key is marked so that it won't be selected for output * by @ksl_encrypt@. You can still encrypt data with it by * calling @ks_encrypt@ directly. */ -extern keyset *ks_gen(const void */*k*/, - size_t /*x*/, size_t /*y*/, size_t /*z*/, - peer */*p*/); +extern keyset *ks_gen(deriveargs */*a*/, peer */*p*/); /* --- @ks_activate@ --- * * -- 2.11.0