From c70a7c5cedab62209640b76f03d97c1876e38dc6 Mon Sep 17 00:00:00 2001 Message-Id: From: Mark Wooding Date: Wed, 19 Apr 2017 20:41:18 +0100 Subject: [PATCH] server/: Make bulk crypto transforms responsible for algorithm selection. Organization: Straylight/Edgeware From: Mark Wooding Move all of the logic around processing symmetric algorithm selections into the `bulkcrypto' transforms. There are now three associated object types: * an algorithm selection, which ends up attached to a peer key; * an encryption context, which actually performs the bulk transform on packets; and * a challenge context, which can issue and verify challenge tags. The important improvement here is that now we can add new bulk crypto transforms which are parametrized in different ways. --- server/admin.c | 30 +-- server/bulkcrypto.c | 470 ++++++++++++++++++++++++++++++++++++++++---- server/chal.c | 44 ++--- server/keymgmt.c | 130 +----------- server/keyset.c | 122 ++++++------ server/tests.at | 6 +- server/tripe.h | 153 +++++++++++--- 7 files changed, 657 insertions(+), 298 deletions(-) diff --git a/server/admin.c b/server/admin.c index fcf27d3e..b12a3be6 100644 --- a/server/admin.c +++ b/server/admin.c @@ -1743,33 +1743,15 @@ static void acmd_algs(admin *a, unsigned ac, char *av[]) "hash-sz=%lu", (unsigned long)algs->h->hashsz, A_END); a_info(a, - "bulk-transform=%s", algs->bulk->name, - "bulk-overhead=%lu", (unsigned long)algs->bulk->overhead(algs), + "bulk-transform=%s", algs->bulk->ops->name, + "bulk-overhead=%lu", + (unsigned long)algs->bulk->ops->overhead(algs->bulk), A_END); - if (algs->c) { - a_info(a, - "cipher=%s", algs->c->name, - "cipher-keysz=%lu", (unsigned long)algs->cksz, - "cipher-blksz=%lu", (unsigned long)algs->c->blksz, - A_END); - } + algs->bulk->ops->alginfo(algs->bulk, a); a_info(a, - "cipher-data-limit=%lu", (unsigned long)algs->expsz, + "cipher-data-limit=%lu", + (unsigned long)algs->bulk->ops->expsz(algs->bulk), A_END); - if (algs->m) { - a_info(a, - "mac=%s", algs->m->name, - "mac-keysz=%lu", (unsigned long)algs->mksz, - "mac-tagsz=%lu", (unsigned long)algs->tagsz, - A_END); - } - if (algs->b) { - a_info(a, - "blkc=%.*s", strlen(algs->b->name) - 4, algs->b->name, - "blkc-keysz=%lu", (unsigned long)algs->bksz, - "blkc-blksz=%lu", (unsigned long)algs->b->blksz, - A_END); - } a_ok(a); } diff --git a/server/bulkcrypto.c b/server/bulkcrypto.c index 26ae9ede..288eed9d 100644 --- a/server/bulkcrypto.c +++ b/server/bulkcrypto.c @@ -50,6 +50,8 @@ trace_block(T_CRYPTO, "crypto: expected MAC", (pmac), (tagsz)); \ }) } while (0) +/*----- Common functionality for generic-composition transforms -----------*/ + #define CHECK_MAC(h, pmac, tagsz) do { \ ghash *_h = (h); \ const octet *_pmac = (pmac); \ @@ -64,6 +66,172 @@ } \ } while (0) +typedef struct gencomp_algs { + const gccipher *c; size_t cksz; + const gcmac *m; size_t mksz; size_t tagsz; +} gencomp_algs; + +typedef struct gencomp_chal { + bulkchal _b; + gmac *m; size_t tagsz; +} gencomp_chal; + +static int gencomp_getalgs(gencomp_algs *a, const algswitch *asw, + dstr *e, key_file *kf, key *k) +{ + const char *p; + char *q, *qq; + unsigned long n; + dstr d = DSTR_INIT; + int rc = -1; + + /* --- Symmetric encryption --- */ + + if ((p = key_getattr(kf, k, "cipher")) == 0) p = "blowfish-cbc"; + if ((a->c = gcipher_byname(p)) == 0) { + a_format(e, "unknown-cipher", "%s", p, A_END); + goto done; + } + + /* --- Message authentication --- */ + + if ((p = key_getattr(kf, k, "mac")) != 0) { + dstr_reset(&d); + dstr_puts(&d, p); + if ((q = strchr(d.buf, '/')) != 0) + *q++ = 0; + if ((a->m = gmac_byname(d.buf)) == 0) { + a_format(e, "unknown-mac", "%s", d.buf, A_END); + goto done; + } + if (!q) + a->tagsz = a->m->hashsz; + else { + n = strtoul(q, &qq, 0); + if (*qq) { + a_format(e, "bad-tag-length-string", "%s", q, A_END); + goto done; + } + if (n%8 || n/8 > a->m->hashsz) { + a_format(e, "bad-tag-length", "%lu", n, A_END); + goto done; + } + a->tagsz = n/8; + } + } else { + dstr_reset(&d); + dstr_putf(&d, "%s-hmac", asw->h->name); + if ((a->m = gmac_byname(d.buf)) == 0) { + a_format(e, "no-hmac-for-hash", "%s", asw->h->name, A_END); + goto done; + } + a->tagsz = asw->h->hashsz/2; + } + + rc = 0; +done: + dstr_destroy(&d); + return (rc); +} + +#ifndef NTRACE +static void gencomp_tracealgs(const gencomp_algs *a) +{ + trace(T_CRYPTO, "crypto: cipher = %s", a->c->name); + trace(T_CRYPTO, "crypto: mac = %s/%lu", + a->m->name, (unsigned long)a->tagsz * 8); +} +#endif + +static int gencomp_checkalgs(gencomp_algs *a, const algswitch *asw, dstr *e) +{ + /* --- Derive the key sizes --- * + * + * Must ensure that we have non-empty keys. This isn't ideal, but it + * provides a handy sanity check. Also must be based on a 64- or 128-bit + * block cipher or we can't do the data expiry properly. + */ + + if ((a->cksz = keysz(asw->hashsz, a->c->keysz)) == 0) { + a_format(e, "cipher", "%s", a->c->name, + "no-key-size", "%lu", (unsigned long)asw->hashsz, + A_END); + return (-1); + } + if ((a->mksz = keysz(asw->hashsz, a->m->keysz)) == 0) { + a_format(e, "mac", "%s", a->m->name, + "no-key-size", "%lu", (unsigned long)asw->hashsz, + A_END); + return (-1); + } + + return (0); +} + +static void gencomp_alginfo(const gencomp_algs *a, admin *adm) +{ + a_info(adm, + "cipher=%s", a->c->name, + "cipher-keysz=%lu", (unsigned long)a->cksz, + "cipher-blksz=%lu", (unsigned long)a->c->blksz, + A_END); + a_info(adm, + "mac=%s", a->m->name, + "mac-keysz=%lu", (unsigned long)a->mksz, + "mac-tagsz=%lu", (unsigned long)a->tagsz, + A_END); +} + +static int gencomp_samealgsp(const gencomp_algs *a, const gencomp_algs *aa) +{ + return (a->c == aa->c && + a->m == aa->m && a->tagsz == aa->tagsz); +} + +static size_t gencomp_expsz(const gencomp_algs *a) + { return (a->c->blksz < 16 ? MEG(64) : MEG(2048)); } + +static bulkchal *gencomp_genchal(const gencomp_algs *a) +{ + gencomp_chal *gc = CREATE(gencomp_chal); + + rand_get(RAND_GLOBAL, buf_t, a->mksz); + gc->m = GM_KEY(a->m, buf_t, a->mksz); + gc->_b.tagsz = a->tagsz; + IF_TRACING(T_CHAL, { + trace(T_CHAL, "chal: generated new challenge key"); + trace_block(T_CRYPTO, "chal: new key", buf_t, a->mksz); + }) + return (&gc->_b); +} + +static int gencomp_chaltag(bulkchal *bc, const void *m, size_t msz, void *t) +{ + gencomp_chal *gc = (gencomp_chal *)bc; + ghash *h = GM_INIT(gc->m); + + GH_HASH(h, m, msz); + memcpy(t, GH_DONE(h, 0), bc->tagsz); + GH_DESTROY(h); + return (0); +} + +static int gencomp_chalvrf(bulkchal *bc, const void *m, size_t msz, + const void *t) +{ + gencomp_chal *gc = (gencomp_chal *)bc; + ghash *h = GM_INIT(gc->m); + int ok; + + GH_HASH(h, m, msz); + ok = ct_memeq(GH_DONE(h, 0), t, gc->_b.tagsz); + GH_DESTROY(h); + return (ok ? 0 : -1); +} + +static void gencomp_freechal(bulkchal *bc) + { gencomp_chal *gc = (gencomp_chal *)bc; GM_DESTROY(gc->m); DESTROY(gc); } + /*----- The original transform --------------------------------------------* * * We generate a random initialization vector (if the cipher needs one). We @@ -90,22 +258,110 @@ * ciphertext and extracts the sequence number. */ -static int v0_check(const algswitch *a, dstr *e) - { return (0); } +typedef struct v0_algs { + bulkalgs _b; + gencomp_algs ga; +} v0_algs; + +typedef struct v0_ctx { + bulkctx _b; + size_t tagsz; + struct { + gcipher *c; + gmac *m; + } d[NDIR]; +} v0_ctx; + +static bulkalgs *v0_getalgs(const algswitch *asw, dstr *e, + key_file *kf, key *k) +{ + v0_algs *a = CREATE(v0_algs); + if (gencomp_getalgs(&a->ga, asw, e, kf, k)) { DESTROY(a); return (0); } + return (&a->_b); +} + +#ifndef NTRACE +static void v0_tracealgs(const bulkalgs *aa) + { const v0_algs *a = (const v0_algs *)aa; gencomp_tracealgs(&a->ga); } +#endif + +static int v0_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e) +{ + v0_algs *a = (v0_algs *)aa; + if (gencomp_checkalgs(&a->ga, asw, e)) return (-1); + return (0); +} + +static int v0_samealgsp(const bulkalgs *aa, const bulkalgs *bb) +{ + const v0_algs *a = (const v0_algs *)aa, *b = (const v0_algs *)bb; + return (gencomp_samealgsp(&a->ga, &b->ga)); +} + +static void v0_alginfo(const bulkalgs *aa, admin *adm) + { const v0_algs *a = (const v0_algs *)aa; gencomp_alginfo(&a->ga, adm); } + +static size_t v0_overhead(const bulkalgs *aa) +{ + const v0_algs *a = (const v0_algs *)aa; + return (a->ga.tagsz + SEQSZ + a->ga.c->blksz); +} -static size_t v0_overhead(const algswitch *a) - { return a->tagsz + SEQSZ + a->c->blksz; } +static size_t v0_expsz(const bulkalgs *aa) + { const v0_algs *a = (const v0_algs *)aa; return (gencomp_expsz(&a->ga)); } -static int v0_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) +static bulkctx *v0_genkeys(const bulkalgs *aa, const struct rawkey *rk) { + const v0_algs *a = (const v0_algs *)aa; + v0_ctx *bc = CREATE(v0_ctx); + octet k[MAXHASHSZ]; + int i; + + bc->tagsz = a->ga.tagsz; + for (i = 0; i < NDIR; i++) { + ks_derivekey(k, a->ga.cksz, rk, i, "encryption"); + bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz); + ks_derivekey(k, a->ga.mksz, rk, i, "integrity"); + bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz); + } + return (&bc->_b); +} + +static bulkchal *v0_genchal(const bulkalgs *aa) +{ + const v0_algs *a = (const v0_algs *)aa; + return (gencomp_genchal(&a->ga)); +} +#define v0_chaltag gencomp_chaltag +#define v0_chalvrf gencomp_chalvrf +#define v0_freechal gencomp_freechal + +static void v0_freealgs(bulkalgs *aa) + { v0_algs *a = (v0_algs *)aa; DESTROY(a); } + +static void v0_freectx(bulkctx *bbc) +{ + v0_ctx *bc = (v0_ctx *)bbc; + int i; + + for (i = 0; i < NDIR; i++) { + GC_DESTROY(bc->d[i].c); + GM_DESTROY(bc->d[i].m); + } + DESTROY(bc); +} + +static int v0_encrypt(bulkctx *bbc, unsigned ty, + buf *b, buf *bb, uint32 seq) +{ + v0_ctx *bc = (v0_ctx *)bbc; ghash *h; - gcipher *c = ks->out.c; + gcipher *c = bc->d[DIR_OUT].c; const octet *p = BCUR(b); size_t sz = BLEFT(b); octet *qmac, *qseq, *qiv, *qpk; - uint32 oseq; size_t ivsz = GC_CLASS(c)->blksz; - size_t tagsz = ks->tagsz; + size_t tagsz = bc->tagsz; octet t[4]; /* --- Determine the ciphertext layout --- */ @@ -123,8 +379,7 @@ static int v0_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) /* --- Store the sequence number --- */ - oseq = ks->oseq++; - STORE32(qseq, oseq); + STORE32(qseq, seq); /* --- Establish an initialization vector if necessary --- */ @@ -142,7 +397,7 @@ static int v0_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) /* --- Compute a MAC over type, sequence number, IV, and ciphertext --- */ if (tagsz) { - h = GM_INIT(ks->out.m); + h = GM_INIT(bc->d[DIR_OUT].m); GH_HASH(h, t, sizeof(t)); GH_HASH(h, qseq, SEQSZ + ivsz + sz); memcpy(qmac, GH_DONE(h, 0), tagsz); @@ -155,22 +410,24 @@ static int v0_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) return (0); } -static int v0_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) +static int v0_decrypt(bulkctx *bbc, unsigned ty, + buf *b, buf *bb, uint32 *seq) { + v0_ctx *bc = (v0_ctx *)bbc; const octet *pmac, *piv, *pseq, *ppk; size_t psz = BLEFT(b); size_t sz; octet *q = BCUR(bb); ghash *h; - gcipher *c = ks->in.c; + gcipher *c = bc->d[DIR_IN].c; size_t ivsz = GC_CLASS(c)->blksz; - size_t tagsz = ks->tagsz; + size_t tagsz = bc->tagsz; octet t[4]; /* --- Break up the packet into its components --- */ if (psz < ivsz + SEQSZ + tagsz) { - T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); ) + T( trace(T_KEYSET, "keyset: block too small for keyset"); ) return (KSERR_MALFORMED); } sz = psz - ivsz - SEQSZ - tagsz; @@ -180,7 +437,7 @@ static int v0_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) /* --- Verify the MAC on the packet --- */ if (tagsz) { - h = GM_INIT(ks->in.m); + h = GM_INIT(bc->d[DIR_IN].m); GH_HASH(h, t, sizeof(t)); GH_HASH(h, pseq, SEQSZ + ivsz + sz); CHECK_MAC(h, pmac, tagsz); @@ -229,9 +486,74 @@ static int v0_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) * tagsz 32 sz */ -static int iiv_check(const algswitch *a, dstr *e) +typedef struct iiv_algs { + bulkalgs _b; + gencomp_algs ga; + const gccipher *b; size_t bksz; +} iiv_algs; + +typedef struct iiv_ctx { + bulkctx _b; + size_t tagsz; + struct { + gcipher *c, *b; + gmac *m; + } d[NDIR]; +} iiv_ctx; + + +static bulkalgs *iiv_getalgs(const algswitch *asw, dstr *e, + key_file *kf, key *k) +{ + iiv_algs *a = CREATE(iiv_algs); + dstr d = DSTR_INIT, dd = DSTR_INIT; + const char *p; + char *q; + + if (gencomp_getalgs(&a->ga, asw, e, kf, k)) goto fail; + + if ((p = key_getattr(kf, k, "blkc")) == 0) { + dstr_puts(&dd, a->ga.c->name); + if ((q = strrchr(dd.buf, '-')) != 0) *q = 0; + p = dd.buf; + } + dstr_putf(&d, "%s-ecb", p); + if ((a->b = gcipher_byname(d.buf)) == 0) { + a_format(e, "unknown-blkc", "%s", p, A_END); + goto fail; + } + + dstr_destroy(&d); dstr_destroy(&dd); + return (&a->_b); +fail: + dstr_destroy(&d); dstr_destroy(&dd); + DESTROY(a); + return (0); +} + +#ifndef NTRACE +static void iiv_tracealgs(const bulkalgs *aa) +{ + const iiv_algs *a = (const iiv_algs *)aa; + + gencomp_tracealgs(&a->ga); + trace(T_CRYPTO, "crypto: blkc = %.*s", strlen(a->b->name) - 4, a->b->name); +} +#endif + +static int iiv_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e) { - if (a->b->blksz < a->c->blksz) { + iiv_algs *a = (iiv_algs *)aa; + + if (gencomp_checkalgs(&a->ga, asw, e)) return (-1); + + if ((a->bksz = keysz(asw->hashsz, a->b->keysz)) == 0) { + a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name, + "no-key-size", "%lu", (unsigned long)asw->hashsz, + A_END); + return (-1); + } + if (a->b->blksz < a->ga.c->blksz) { a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name, "blksz-insufficient", A_END); return (-1); @@ -239,23 +561,91 @@ static int iiv_check(const algswitch *a, dstr *e) return (0); } -static size_t iiv_overhead(const algswitch *a) - { return a->tagsz + SEQSZ; } +static int iiv_samealgsp(const bulkalgs *aa, const bulkalgs *bb) +{ + const iiv_algs *a = (const iiv_algs *)aa, *b = (const iiv_algs *)bb; + return (gencomp_samealgsp(&a->ga, &b->ga) && a->b == b->b); +} + +static void iiv_alginfo(const bulkalgs *aa, admin *adm) +{ + const iiv_algs *a = (const iiv_algs *)aa; + gencomp_alginfo(&a->ga, adm); + a_info(adm, + "blkc=%.*s", strlen(a->b->name) - 4, a->b->name, + "blkc-keysz=%lu", (unsigned long)a->bksz, + "blkc-blksz=%lu", (unsigned long)a->b->blksz, + A_END); +} + +static size_t iiv_overhead(const bulkalgs *aa) + { const iiv_algs *a = (const iiv_algs *)aa; return (a->ga.tagsz + SEQSZ); } + +static size_t iiv_expsz(const bulkalgs *aa) +{ + const iiv_algs *a = (const iiv_algs *)aa; + return (gencomp_expsz(&a->ga)); +} + +static bulkctx *iiv_genkeys(const bulkalgs *aa, const struct rawkey *rk) +{ + const iiv_algs *a = (const iiv_algs *)aa; + iiv_ctx *bc = CREATE(iiv_ctx); + octet k[MAXHASHSZ]; + int i; + + bc->tagsz = a->ga.tagsz; + for (i = 0; i < NDIR; i++) { + ks_derivekey(k, a->ga.cksz, rk, i, "encryption"); + bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz); + ks_derivekey(k, a->bksz, rk, i, "blkc"); + bc->d[i].b = GC_INIT(a->b, k, a->bksz); + ks_derivekey(k, a->ga.mksz, rk, i, "integrity"); + bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz); + } + return (&bc->_b); +} + +static bulkchal *iiv_genchal(const bulkalgs *aa) +{ + const iiv_algs *a = (const iiv_algs *)aa; + return (gencomp_genchal(&a->ga)); +} +#define iiv_chaltag gencomp_chaltag +#define iiv_chalvrf gencomp_chalvrf +#define iiv_freechal gencomp_freechal + +static void iiv_freealgs(bulkalgs *aa) + { iiv_algs *a = (iiv_algs *)aa; DESTROY(a); } + +static void iiv_freectx(bulkctx *bbc) +{ + iiv_ctx *bc = (iiv_ctx *)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); + } + DESTROY(bc); +} #define TRACE_PRESEQ(qseq, ivsz) do { IF_TRACING(T_KEYSET, { \ trace_block(T_CRYPTO, "crypto: IV derivation input", (qseq), (ivsz)); \ }) } while (0) -static int iiv_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) +static int iiv_encrypt(bulkctx *bbc, unsigned ty, + buf *b, buf *bb, uint32 seq) { + iiv_ctx *bc = (iiv_ctx *)bbc; ghash *h; - gcipher *c = ks->out.c, *blkc = ks->out.b; + gcipher *c = bc->d[DIR_OUT].c, *blkc = bc->d[DIR_OUT].b; const octet *p = BCUR(b); size_t sz = BLEFT(b); octet *qmac, *qseq, *qpk; - uint32 oseq; size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz; - size_t tagsz = ks->tagsz; + size_t tagsz = bc->tagsz; octet t[4]; /* --- Determine the ciphertext layout --- */ @@ -273,8 +663,7 @@ static int iiv_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) /* --- Store the sequence number --- */ - oseq = ks->oseq++; - STORE32(qseq, oseq); + STORE32(qseq, seq); /* --- Establish an initialization vector if necessary --- */ @@ -295,7 +684,7 @@ static int iiv_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) /* --- Compute a MAC over type, sequence number, and ciphertext --- */ if (tagsz) { - h = GM_INIT(ks->out.m); + h = GM_INIT(bc->d[DIR_OUT].m); GH_HASH(h, t, sizeof(t)); GH_HASH(h, qseq, SEQSZ + sz); memcpy(qmac, GH_DONE(h, 0), tagsz); @@ -308,22 +697,24 @@ static int iiv_encrypt(keyset *ks, unsigned ty, buf *b, buf *bb) return (0); } -static int iiv_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) +static int iiv_decrypt(bulkctx *bbc, unsigned ty, + buf *b, buf *bb, uint32 *seq) { + iiv_ctx *bc = (iiv_ctx *)bbc; const octet *pmac, *pseq, *ppk; size_t psz = BLEFT(b); size_t sz; octet *q = BCUR(bb); ghash *h; - gcipher *c = ks->in.c, *blkc = ks->in.b; + 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 tagsz = ks->tagsz; + size_t tagsz = bc->tagsz; octet t[4]; /* --- Break up the packet into its components --- */ if (psz < SEQSZ + tagsz) { - T( trace(T_KEYSET, "keyset: block too small for keyset %u", ks->seq); ) + T( trace(T_KEYSET, "keyset: block too small for keyset"); ) return (KSERR_MALFORMED); } sz = psz - SEQSZ - tagsz; @@ -333,7 +724,7 @@ static int iiv_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) /* --- Verify the MAC on the packet --- */ if (tagsz) { - h = GM_INIT(ks->in.m); + h = GM_INIT(bc->d[DIR_IN].m); GH_HASH(h, t, sizeof(t)); GH_HASH(h, pseq, SEQSZ + sz); CHECK_MAC(h, pmac, tagsz); @@ -362,11 +753,18 @@ static int iiv_decrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) const bulkops bulktab[] = { -#define BULK(name, pre, prim) \ - { name, prim, pre##_check, pre##_overhead, pre##_encrypt, pre##_decrypt } +#define COMMA , + +#define BULK(name, pre) \ + { name, pre##_getalgs, T( pre##_tracealgs COMMA ) \ + pre##_checkalgs, pre##_samealgsp, \ + pre##_alginfo, pre##_overhead, pre##_expsz, \ + pre##_genkeys, pre##_genchal, pre##_freealgs, \ + pre##_encrypt, pre##_decrypt, pre##_freectx, \ + pre##_chaltag, pre##_chalvrf, pre##_freechal } - BULK("v0", v0, BCP_CIPHER | BCP_MAC), - BULK("iiv", iiv, BCP_CIPHER | BCP_MAC | BCP_BLKC), + BULK("v0", v0), + BULK("iiv", iiv), #undef BULK { 0 } diff --git a/server/chal.c b/server/chal.c index 387f0db1..71fde49c 100644 --- a/server/chal.c +++ b/server/chal.c @@ -30,7 +30,7 @@ /*----- Static variables --------------------------------------------------*/ -static gmac *mac; +static bulkchal *bulk; static uint32 oseq; static seqwin iseq; @@ -47,17 +47,13 @@ static seqwin iseq; static void c_genkey(void) { - if (mac && GM_CLASS(mac) == master->algs.m && oseq < 0x07ffffff) return; - if (mac) GM_DESTROY(mac); - assert(master->algs.mksz < sizeof(buf_t)); - rand_get(RAND_GLOBAL, buf_t, master->algs.mksz); - mac = GM_KEY(master->algs.m, buf_t, master->algs.mksz); + if (bulk && bulk->ops == master->algs.bulk->ops && oseq < 0x07ffffff) + return; + if (bulk) bulk->ops->freechal(bulk); + bulk = master->algs.bulk->ops->genchal(master->algs.bulk); + bulk->ops = master->algs.bulk->ops; oseq = 0; seq_reset(&iseq); - IF_TRACING(T_CHAL, { - trace(T_CHAL, "chal: generated new challenge key"); - trace_block(T_CRYPTO, "chal: new key", buf_t, master->algs.mksz); - }) } /* --- @c_new@ --- * @@ -72,16 +68,11 @@ static void c_genkey(void) int c_new(buf *b) { octet *p; - ghash *h; c_genkey(); p = BCUR(b); - if (buf_putu32(b, oseq++)) return (-1); - h = GM_INIT(mac); - GH_HASH(h, p, BCUR(b) - p); - buf_put(b, GH_DONE(h, 0), master->algs.tagsz); - GH_DESTROY(h); - if (BBAD(b)) return (-1); + if (buf_putu32(b, oseq++) || !buf_get(b, bulk->tagsz)) return (-1); + if (bulk->ops->chaltag(bulk, p, 4, p + 4)) return (-1); IF_TRACING(T_CHAL, { trace(T_CHAL, "chal: issuing challenge %lu", (unsigned long)(oseq - 1)); trace_block(T_CRYPTO, "chal: challenge block", p, BCUR(b) - p); @@ -101,25 +92,20 @@ int c_new(buf *b) int c_check(buf *b) { const octet *p; - size_t sz = 4 + master->algs.tagsz; + size_t sz; uint32 seq; - ghash *h; - int ok; + if (!bulk) { + a_warn("CHAL", "impossible-challenge", A_END); + goto fail; + } + sz = 4 + bulk->tagsz; if ((p = buf_get(b, sz)) == 0) { a_warn("CHAL", "invalid-challenge", A_END); goto fail; } IF_TRACING(T_CHAL, trace_block(T_CRYPTO, "chal: check challenge", p, sz); ) - if (!mac) { - a_warn("CHAL", "impossible-challenge", A_END); - goto fail; - } - h = GM_INIT(mac); - GH_HASH(h, p, 4); - ok = ct_memeq(GH_DONE(h, 0), p + 4, master->algs.tagsz); - GH_DESTROY(h); - if (!ok) { + if (bulk->ops->chalvrf(bulk, p, 4, p + 4)) { a_warn("CHAL", "incorrect-tag", A_END); goto fail; } diff --git a/server/keymgmt.c b/server/keymgmt.c index 837bc6ef..2324f157 100644 --- a/server/keymgmt.c +++ b/server/keymgmt.c @@ -178,8 +178,7 @@ static const kgops *kgtab[] = { static int algs_get(algswitch *a, dstr *e, key_file *kf, key *k) { const char *p; - const bulkops *bulk; - char *q, *qq; + const bulkops *bops; dstr d = DSTR_INIT, dd = DSTR_INIT; int rc = -1; @@ -206,83 +205,13 @@ static int algs_get(algswitch *a, dstr *e, key_file *kf, key *k) /* --- Bulk crypto transform --- */ if ((p = key_getattr(kf, k, "bulk")) == 0) p = "v0"; - for (bulk = bulktab; bulk->name && strcmp(p, bulk->name) != 0; bulk++); - if (!bulk->name) { + for (bops = bulktab; bops->name && strcmp(p, bops->name) != 0; bops++); + if (!bops->name) { a_format(e, "unknown-bulk-transform", "%s", p, A_END); goto done; } - a->bulk = bulk; - - /* --- Symmetric encryption for bulk data --- */ - - if (!(a->bulk->prim & BCP_CIPHER)) - a->c = 0; - else { - if ((p = key_getattr(kf, k, "cipher")) == 0) p = "blowfish-cbc"; - if ((a->c = gcipher_byname(p)) == 0) { - a_format(e, "unknown-cipher", "%s", p, A_END); - goto done; - } - } - - /* --- Block cipher for miscellaneous use --- */ - - if (!(a->bulk->prim & BCP_BLKC)) - a->b = 0; - else { - if ((p = key_getattr(kf, k, "blkc")) == 0) { - dstr_reset(&dd); - dstr_puts(&dd, a->c ? a->c->name : "rijndael-"); - if ((q = strrchr(dd.buf, '-')) != 0) *q = 0; - p = dd.buf; - } - dstr_reset(&d); - dstr_putf(&d, "%s-ecb", p); - if ((a->b = gcipher_byname(d.buf)) == 0) { - a_format(e, "unknown-blkc", "%s", p, A_END); - goto done; - } - } - - /* --- Message authentication for bulk data --- */ - - if (!(a->bulk->prim & BCP_MAC)) { - a->m = 0; - a->tagsz = 0; - } else { - if ((p = key_getattr(kf, k, "mac")) != 0) { - dstr_reset(&d); - dstr_puts(&d, p); - if ((q = strchr(d.buf, '/')) != 0) - *q++ = 0; - if ((a->m = gmac_byname(d.buf)) == 0) { - a_format(e, "unknown-mac", "%s", d.buf, A_END); - goto done; - } - if (!q) - a->tagsz = a->m->hashsz; - else { - unsigned long n = strtoul(q, &qq, 0); - if (*qq) { - a_format(e, "bad-tag-length-string", "%s", q, A_END); - goto done; - } - if (n%8 || n/8 > a->m->hashsz) { - a_format(e, "bad-tag-length", "%lu", n, A_END); - goto done; - } - a->tagsz = n/8; - } - } else { - dstr_reset(&d); - dstr_putf(&d, "%s-hmac", a->h->name); - if ((a->m = gmac_byname(d.buf)) == 0) { - a_format(e, "no-hmac-for-hash", "%s", a->h->name, A_END); - goto done; - } - a->tagsz = a->h->hashsz/2; - } - } + if ((a->bulk = bops->getalgs(a, e, kf, k)) == 0) goto done; + a->bulk->ops = bops; /* --- All done --- */ @@ -309,43 +238,7 @@ done: static int algs_check(algswitch *a, dstr *e, const group *g) { - /* --- Check the bulk crypto transform --- */ - - if (a->bulk->check(a, e)) return (-1); - - /* --- Derive the key sizes --- * - * - * Must ensure that we have non-empty keys. This isn't ideal, but it - * provides a handy sanity check. Also must be based on a 64- or 128-bit - * block cipher or we can't do the data expiry properly. - */ - a->hashsz = a->h->hashsz; - if (a->c && (a->cksz = keysz(a->hashsz, a->c->keysz)) == 0) { - a_format(e, "cipher", "%s", a->c->name, - "no-key-size", "%lu", (unsigned long)a->hashsz, - A_END); - return (-1); - } - if (a->m && (a->mksz = keysz(a->hashsz, a->m->keysz)) == 0) { - a_format(e, "mac", "%s", a->m->name, - "no-key-size", "%lu", (unsigned long)a->hashsz, - A_END); - return (-1); - } - if (a->b && (a->bksz = keysz(a->hashsz, a->b->keysz)) == 0) { - a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name, - "no-key-size", "%lu", (unsigned long)a->hashsz, - A_END); - return (-1); - } - - /* --- Derive the data limit --- */ - - if (a->c && a->c->blksz < 16) a->expsz = MEG(64); - else a->expsz = MEG(2048); - - /* --- Ensure the MGF accepts hashes as keys --- */ if (keysz(a->hashsz, a->mgf->keysz) != a->hashsz) { a_format(e, "mgf", "%s", a->mgf->name, @@ -354,7 +247,7 @@ static int algs_check(algswitch *a, dstr *e, const group *g) return (-1); } - /* --- All ship-shape and Bristol-fashion --- */ + if (a->bulk->ops->checkalgs(a->bulk, a, e)) return (-1); return (0); } @@ -374,10 +267,9 @@ int km_samealgsp(const kdata *kdx, const kdata *kdy) const algswitch *a = &kdx->algs, *aa = &kdy->algs; return (group_samep(kdx->g, kdy->g) && - a->bulk == aa->bulk && - a->c == aa->c && a->b == aa->b && a->mgf == aa->mgf && a->h == aa->h && - a->m == aa->m && a->tagsz == aa->tagsz); + a->bulk->ops == aa->bulk->ops && + a->bulk->ops->samealgsp(a->bulk, aa->bulk)); } /*----- Key data and key nodes --------------------------------------------*/ @@ -624,11 +516,7 @@ foundko: trace(T_CRYPTO, "crypto: h = %s", mpstr(kd->g->h)); if (kd->kpriv) trace(T_CRYPTO, "crypto: x = %s", mpstr(kd->kpriv)); - trace(T_CRYPTO, "crypto: cipher = %s", kd->algs.c->name); - trace(T_CRYPTO, "crypto: mgf = %s", kd->algs.mgf->name); - trace(T_CRYPTO, "crypto: hash = %s", kd->algs.h->name); - trace(T_CRYPTO, "crypto: mac = %s/%lu", - kd->algs.m->name, (unsigned long)kd->algs.tagsz * 8); + kd->algs.bulk->ops->tracealgs(kd->algs.bulk); }) }) diff --git a/server/keyset.c b/server/keyset.c index 94fcae02..1d7817c8 100644 --- a/server/keyset.c +++ b/server/keyset.c @@ -90,8 +90,9 @@ static int doencrypt(keyset *ks, unsigned ty, buf *b, buf *bb) /* --- Apply the bulk-crypto transformation --- */ - rc = ks->bulk->encrypt(ks, ty, b, bb); + rc = ks->bulk->ops->encrypt(ks->bulk, ty, b, bb, ks->oseq); if (rc || !BOK(bb)) return (rc); + ks->oseq++; /* --- Do the necessary accounting for data volume --- */ @@ -139,7 +140,7 @@ static int dodecrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) trace_block(T_CRYPTO, "crypto: ciphertext packet", BCUR(b), BLEFT(b)); }) - rc = ks->bulk->decrypt(ks, ty, b, bb, seq); + rc = ks->bulk->ops->decrypt(ks->bulk, ty, b, bb, seq); if (rc) return (rc); IF_TRACING(T_KEYSET, { @@ -164,22 +165,64 @@ static int dodecrypt(keyset *ks, unsigned ty, buf *b, buf *bb, uint32 *seq) void ks_drop(keyset *ks) { - if (--ks->ref) - return; - -#define DROP(dir, a, drop) do { if (ks->dir.a) drop(ks->dir.a); } while (0) -#define DROP_DIR(dir) do { \ - DROP(dir, c, GC_DESTROY); \ - DROP(dir, m, GM_DESTROY); \ -} while (0) + if (--ks->ref) return; + ks->bulk->ops->freectx(ks->bulk); + DESTROY(ks); +} - DROP_DIR(in); - DROP_DIR(out); +/* --- @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. + */ -#undef DROP -#undef DROP_DIR +struct rawkey { + const gchash *hc; + const octet *k; + size_t x, y, z; +}; - DESTROY(ks); +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 ? "incoming" : "outgoing", what); + trace_block(T_CRYPTO, _buf, k, ksz); + }) }) } /* --- @ks_gen@ --- * @@ -205,67 +248,30 @@ void ks_drop(keyset *ks) * calling @ks_encrypt@ directly. */ -static void gen_dir(const algswitch *algs, struct ksdir *ksd, - const char *whichdir, - const octet *from, size_t fromsz, - const octet *to, size_t tosz, - const octet *both, size_t bothsz) -{ -#define SETKEY(what, a, init) do { \ - ghash *_h; \ - octet *_hh; \ - \ - if (!algs->a) \ - ksd->a = 0; \ - else { \ - _h = GH_INIT(algs->h); \ - HASH_STRING(_h, "tripe-" what); \ - GH_HASH(_h, from, fromsz); \ - GH_HASH(_h, to, tosz); \ - GH_HASH(_h, both, bothsz); \ - _hh = GH_DONE(_h, 0); \ - IF_TRACING(T_KEYSET, { IF_TRACING(T_CRYPTO, { \ - char _buf[32]; \ - sprintf(_buf, "crypto: %s key " what, whichdir); \ - trace_block(T_CRYPTO, _buf, _hh, algs->a##ksz); \ - }) }) \ - ksd->a = init(algs->a, _hh, algs->a##ksz); \ - GH_DESTROY(_h); \ - } \ -} while (0) - - SETKEY("encryption", c, GC_INIT); - SETKEY("integrity", m, GM_KEY); - SETKEY("blkc", b, GC_INIT); - -#undef SETKEY -} - 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; + struct rawkey rk; T( static unsigned seq = 0; ) T( trace(T_KEYSET, "keyset: adding new keyset %u", seq); ) - gen_dir(algs, &ks->in, "incoming", pp, x, pp + x, y - x, pp + y, z - y); - gen_dir(algs, &ks->out, "outgoing", pp + x, y - x, pp, x, pp + y, z - y); + 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); + ks->bulk->ops = algs->bulk->ops; T( ks->seq = seq++; ) - ks->bulk = algs->bulk; ks->ref = 1; ks->t_exp = now + T_EXP; - ks->sz_exp = algs->expsz; - ks->sz_regen = algs->expsz/2; + ks->sz_exp = algs->bulk->ops->expsz(algs->bulk); + ks->sz_regen = ks->sz_exp/2; ks->oseq = 0; seq_reset(&ks->iseq); ks->next = 0; ks->p = p; ks->f = KSF_LISTEN; - ks->tagsz = algs->tagsz; return (ks); } diff --git a/server/tests.at b/server/tests.at index 4311a434..6c5d5e32 100644 --- a/server/tests.at +++ b/server/tests.at @@ -590,8 +590,8 @@ kx-group=ec kx-group-order-bits=256 kx-group-elt-bits=512 hash=rmd160 mgf=rmd160-mgf hash-sz=20 bulk-transform=v0 bulk-overhead=22 cipher=blowfish-cbc cipher-keysz=20 cipher-blksz=8 -cipher-data-limit=67108864 mac=rmd160-hmac mac-keysz=20 mac-tagsz=10 +cipher-data-limit=67108864 ]) AT_DATA([algs-beta-old], [dnl @@ -599,8 +599,8 @@ kx-group=prime kx-group-order-bits=160 kx-group-elt-bits=1023 hash=rmd160 mgf=rmd160-mgf hash-sz=20 bulk-transform=v0 bulk-overhead=22 cipher=blowfish-cbc cipher-keysz=20 cipher-blksz=8 -cipher-data-limit=67108864 mac=rmd160-hmac mac-keysz=20 mac-tagsz=10 +cipher-data-limit=67108864 ]) AT_DATA([algs-beta-new], [dnl @@ -608,9 +608,9 @@ kx-group=ec kx-group-order-bits=161 kx-group-elt-bits=320 hash=rmd160 mgf=rmd160-mgf hash-sz=20 bulk-transform=iiv bulk-overhead=14 cipher=blowfish-cbc cipher-keysz=20 cipher-blksz=8 -cipher-data-limit=67108864 mac=rmd160-hmac mac-keysz=20 mac-tagsz=10 blkc=blowfish blkc-keysz=20 blkc-blksz=8 +cipher-data-limit=67108864 ]) cp algs-alpha expout; AT_CHECK([TRIPECTL -dalice ALGS],, [expout]) diff --git a/server/tripe.h b/server/tripe.h index 4669711e..24cec434 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -158,32 +158,114 @@ typedef struct keyset keyset; typedef struct algswitch algswitch; +typedef struct admin admin; + +typedef struct bulkalgs { + const struct bulkops *ops; +} bulkalgs; + +typedef struct bulkctx { + const struct bulkops *ops; +} bulkctx; + +typedef struct bulkchal { + const struct bulkops *ops; + size_t tagsz; +} bulkchal; + +struct rawkey; typedef struct bulkops { const char *name; - unsigned prim; - int (*check)(const algswitch */*a*/, dstr */*e*/); - size_t (*overhead)(const algswitch */*a*/); - int (*encrypt)(keyset */*ks*/, unsigned /*ty*/, buf */*b*/, buf */*bb*/); - int (*decrypt)(keyset */*ks*/, unsigned /*ty*/, + + bulkalgs *(*getalgs)(const algswitch */*asw*/, dstr */*e*/, + key_file */*kf*/, key */*k*/); + /* Determine algorithms to use and return a @bulkalgs@ object + * representing the decision. On error, write tokens to @e@ and + * return null. + */ + + T( void (*tracealgs)(const bulkalgs */*a*/); ) + /* Write trace information about the algorithm selection. */ + + int (*checkalgs)(bulkalgs */*a*/, const algswitch */*asw*/, dstr */*e*/); + /* Check that the algorithms in @a@ and @asw@ are acceptable. On + * error, write tokens to @e@ and return @-1@; otherwise return zero. + */ + + int (*samealgsp)(const bulkalgs */*a*/, const bulkalgs */*aa*/); + /* If @a@ and @aa@ represent the same algorithm selection, return + * nonzero; if not, return zero. + */ + + void (*alginfo)(const bulkalgs */*a*/, admin */*adm*/); + /* Report on the algorithm selection to an admin client: call + * @a_info@ with appropriate key-value pairs. + */ + + size_t (*overhead)(const bulkalgs */*a*/); + /* Return the per-packet overhead of the bulk transform, in bytes. */ + + size_t (*expsz)(const bulkalgs */*a*/); + /* Return the total size limit for the bulk transform, in bytes, + * after which the keys must no longer be used. + */ + + bulkctx *(*genkeys)(const bulkalgs */*a*/, const struct rawkey */*rk*/); + /* Generate session keys and construct and return an appropriate + * context for using them, by calling @ks_derive@. + */ + + bulkchal *(*genchal)(const bulkalgs */*a*/); + /* Construct and return a challenge issuing and verification + * context with a fresh random key. + */ + + void (*freealgs)(bulkalgs */*a*/); + /* Release an algorithm selection object. (Associated bulk + * encryption contexts and challenge contexts may still exist and + * must remain valid.) + */ + + int (*encrypt)(bulkctx */*bc*/, unsigned /*ty*/, + buf */*b*/, buf */*bb*/, uint32 /*seq*/); + /* Encrypt the packet in @b@, with type @ty@ (which doesn't need + * encoding separately) and sequence number @seq@ (which must be + * recoverable by @decrypt@), and write the result to @bb@. On + * error, return a @KSERR_...@ code and/or break the output buffer. + */ + + int (*decrypt)(bulkctx */*bc*/, unsigned /*ty*/, buf */*b*/, buf */*bb*/, uint32 */*seq*/); -} bulkops; + /* Decrypt the packet in @b@, with type @ty@, writing the result to + * @bb@ and storing the incoming (claimed) sequence number in @seq@. + * On error, return a @KSERR_...@ code. + */ + + void (*freectx)(bulkctx */*a*/); + /* Release a bulk encryption context and the resources it holds. */ + + int (*chaltag)(bulkchal */*bc*/, const void */*m*/, size_t /*msz*/, + void */*t*/); + /* Calculate a tag for the challenge in @m@, @msz@, and write it to + * @t@. Return @-1@ on error, zero on success. + */ + + int (*chalvrf)(bulkchal */*bc*/, const void */*m*/, size_t /*msz*/, + const void */*t*/); + /* Check the tag @t@ on @m@, @msz@: return zero if the tag is OK, + * nonzero if it's bad. + */ + + void (*freechal)(bulkchal */*bc*/); + /* Release a challenge context and the resources it holds. */ -#define BCP_CIPHER 1 -#define BCP_MAC 2 -#define BCP_BLKC 4 +} bulkops; struct algswitch { - const gchash *h; /* Hash function */ + const gchash *h; size_t hashsz; /* Hash function */ const gccipher *mgf; /* Mask-generation function */ - const bulkops *bulk; /* Bulk crypto transformation */ - const gccipher *c; /* Symmetric encryption scheme */ - const gcmac *m; /* Message authentication code */ - const gccipher *b; /* Block cipher */ - size_t hashsz; /* Hash output size */ - size_t tagsz; /* Length to truncate MAC tags */ - size_t expsz; /* Size of data to process */ - size_t cksz, mksz, bksz; /* Key lengths for things */ + bulkalgs *bulk; /* Bulk crypto algorithms */ }; typedef struct kdata { @@ -258,6 +340,8 @@ typedef struct seqwin { * expiry. */ +enum { DIR_IN, DIR_OUT, NDIR }; + struct keyset { struct keyset *next; /* Next active keyset in the list */ unsigned ref; /* Reference count for keyset */ @@ -266,13 +350,7 @@ struct keyset { unsigned long sz_exp, sz_regen; /* Data limits for the keyset */ T( unsigned seq; ) /* Sequence number for tracing */ unsigned f; /* Various useful flags */ - const bulkops *bulk; /* Bulk crypto transform */ - size_t tagsz; /* Length to truncate MAC tags */ - struct ksdir { - gcipher *c; /* Keyset cipher for encryption */ - gmac *m; /* Keyset MAC for integrity */ - gcipher *b; /* Block cipher, just in case */ - } in, out; + bulkctx *bulk; /* Bulk crypto transform */ uint32 oseq; /* Outbound sequence number */ seqwin iseq; /* Inbound sequence number */ }; @@ -529,7 +607,7 @@ typedef struct admin_jobtable { admin_jobentry *v; /* And the big array of entries */ } admin_jobtable; -typedef struct admin { +struct admin { struct admin *next, *prev; /* Links to next and previous */ unsigned f; /* Various useful flags */ unsigned ref; /* Reference counter */ @@ -543,7 +621,7 @@ typedef struct admin { admin_jobtable j; /* Table of outstanding jobs */ selbuf b; /* Line buffer for commands */ sel_file w; /* Selector for write buffering */ -} admin; +}; #define AF_DEAD 1u /* Destroy this admin block */ #define AF_CLOSE 2u /* Client closed connection */ @@ -748,6 +826,27 @@ 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 -- [mdw]