From 3deadf73ca497f4c50a2dbe387f544ef0070cfb4 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Mon, 4 Sep 2017 09:36:10 +0100 Subject: [PATCH] server/: Augment challenges to allow a payload. * Augment the external interface to take a pointer/length pair designating the payload. * Change the bulk-crypto interface to pass the sequence number in separately from the (repurposed) payload buffer. * Modify the `naclbox' challenge handling to hash the payload using Poly1305, rather than just producing some Salsa20 output. --- server/admin.c | 4 ++-- server/bulkcrypto.c | 50 ++++++++++++++++++++++++++++++++------------------ server/chal.c | 50 +++++++++++++++++++++++++++++++------------------- server/peer.c | 2 +- server/tripe.h | 25 +++++++++++++++---------- 5 files changed, 81 insertions(+), 50 deletions(-) diff --git a/server/admin.c b/server/admin.c index 46a7348a..d80992cd 100644 --- a/server/admin.c +++ b/server/admin.c @@ -1776,7 +1776,7 @@ static void acmd_getchal(admin *a, unsigned ac, char *av[]) buf b; buf_init(&b, buf_i, PKBUFSZ); - c_new(&b); + c_new(0, 0, &b); a_info(a, "?B64", BBASE(&b), (size_t)BLEN(&b), A_END); a_ok(a); } @@ -1793,7 +1793,7 @@ static void acmd_checkchal(admin *a, unsigned ac, char *av[]) a_fail(a, "bad-base64", "%s", codec_strerror(err), A_END); else { buf_init(&b, d.buf, d.len); - if (c_check(&b) || BBAD(&b) || BLEFT(&b)) + if (c_check(0, 0, &b) || BBAD(&b) || BLEFT(&b)) a_fail(a, "invalid-challenge", A_END); else a_ok(a); diff --git a/server/bulkcrypto.c b/server/bulkcrypto.c index fff2c825..d0e654cc 100644 --- a/server/bulkcrypto.c +++ b/server/bulkcrypto.c @@ -251,25 +251,26 @@ static bulkchal *gencomp_genchal(const gencomp_algs *a) return (&gc->_b); } -static int gencomp_chaltag(bulkchal *bc, const void *m, size_t msz, void *t) +static int gencomp_chaltag(bulkchal *bc, const void *m, size_t msz, + uint32 seq, void *t) { gencomp_chal *gc = (gencomp_chal *)bc; ghash *h = GM_INIT(gc->m); - GH_HASH(h, m, msz); + GH_HASHU32(h, seq); if (msz) 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) + uint32 seq, const void *t) { gencomp_chal *gc = (gencomp_chal *)bc; ghash *h = GM_INIT(gc->m); int ok; - GH_HASH(h, m, msz); + GH_HASHU32(h, seq); if (msz) GH_HASH(h, m, msz); ok = ct_memeq(GH_DONE(h, 0), t, gc->_b.tagsz); GH_DESTROY(h); return (ok ? 0 : -1); @@ -987,31 +988,44 @@ static bulkchal *naclbox_genchal(const bulkalgs *aa) trace(T_CHAL, "chal: generated new challenge key"); trace_block(T_CRYPTO, "chal: new key", buf_t, a->cksz); }) - c->_b.tagsz = 16; + c->_b.tagsz = POLY1305_TAGSZ; return (&c->_b); } -static int naclbox_chaltag(bulkchal *bc, const void *m, size_t msz, void *t) +static int naclbox_chaltag(bulkchal *bc, const void *m, size_t msz, + uint32 seq, void *t) { naclbox_chal *c = (naclbox_chal *)bc; - octet b0[SALSA20_NONCESZ]; - assert(msz <= sizeof(b0)); - memcpy(b0, m, msz); memset(b0 + msz, 0, sizeof(b0) - msz); - GC_SETIV(c->c, b0); - GC_ENCRYPT(c->c, 0, t, c->_b.tagsz); + poly1305_key pk; + poly1305_ctx pm; + octet b[POLY1305_KEYSZ + POLY1305_MASKSZ]; + + assert(SALSA20_NONCESZ <= sizeof(b)); + memset(b, 0, SALSA20_NONCESZ - 4); STORE32(b + SALSA20_NONCESZ - 4, seq); + GC_SETIV(c->c, b); GC_ENCRYPT(c->c, 0, b, sizeof(b)); + poly1305_keyinit(&pk, b, POLY1305_KEYSZ); + poly1305_macinit(&pm, &pk, b + POLY1305_KEYSZ); + if (msz) poly1305_hash(&pm, m, msz); + poly1305_done(&pm, t); return (0); } static int naclbox_chalvrf(bulkchal *bc, const void *m, size_t msz, - const void *t) + uint32 seq, const void *t) { naclbox_chal *c = (naclbox_chal *)bc; - octet b0[SALSA20_NONCESZ], b1[16]; - assert(msz <= sizeof(b0)); assert(c->_b.tagsz <= sizeof(b1)); - memcpy(b0, m, msz); memset(b0 + msz, 0, sizeof(b0) - msz); - GC_SETIV(c->c, b0); - GC_ENCRYPT(c->c, 0, b1, c->_b.tagsz); - return (ct_memeq(t, b1, c->_b.tagsz) ? 0 : -1); + poly1305_key pk; + poly1305_ctx pm; + octet b[POLY1305_KEYSZ + POLY1305_MASKSZ]; + + assert(SALSA20_NONCESZ <= sizeof(b)); + memset(b, 0, SALSA20_NONCESZ - 4); STORE32(b + SALSA20_NONCESZ - 4, seq); + GC_SETIV(c->c, b); GC_ENCRYPT(c->c, 0, b, sizeof(b)); + poly1305_keyinit(&pk, b, POLY1305_KEYSZ); + poly1305_macinit(&pm, &pk, b + POLY1305_KEYSZ); + if (msz) poly1305_hash(&pm, m, msz); + assert(POLY1305_TAGSZ <= sizeof(b)); poly1305_done(&pm, b); + return (ct_memeq(t, b, POLY1305_TAGSZ) ? 0 : -1); } static void naclbox_freechal(bulkchal *bc) diff --git a/server/chal.c b/server/chal.c index e6a30055..68d7f048 100644 --- a/server/chal.c +++ b/server/chal.c @@ -57,61 +57,73 @@ static void c_genkey(void) /* --- @c_new@ --- * * - * Arguments: @buf *b@ = where to put the challenge + * Arguments: @const void *m@ = pointer to associated message, or null + * @size_t msz@ = length of associated message + * @buf *b@ = where to put the challenge * * Returns: Zero if OK, nonzero on error. * * Use: Issues a new challenge. */ -int c_new(buf *b) +int c_new(const void *m, size_t msz, buf *b) { - octet *p; + const octet *p; + octet *t; + int rc; c_genkey(); p = BCUR(b); - if (buf_putu32(b, oseq++) || !buf_get(b, bchal->tagsz)) return (-1); - if (bchal->ops->chaltag(bchal, p, 4, p + 4)) return (-1); + if (buf_putu32(b, oseq) || (t = buf_get(b, bchal->tagsz)) == 0) + { rc = -1; goto done; } + if (bchal->ops->chaltag(bchal, m, msz, oseq, t)) { rc = -1; goto done; } IF_TRACING(T_CHAL, { - trace(T_CHAL, "chal: issuing challenge %lu", (unsigned long)(oseq - 1)); + trace(T_CHAL, "chal: issuing challenge %lu", (unsigned long)oseq); + if (msz) trace_block(T_CRYPTO, "chal: message block", m, msz); trace_block(T_CRYPTO, "chal: challenge block", p, BCUR(b) - p); }) - return (0); + rc = 0; +done: + oseq++; + return (rc); } /* --- @c_check@ --- * * - * Arguments: @buf *b@ = where to find the challenge + * Arguments: @const void *m@ = pointer to associated message, or null + * @size_t msz@ = length of associated message + * @buf *b@ = where to find the challenge * * Returns: Zero if OK, nonzero if it didn't work. * * Use: Checks a challenge. On failure, the buffer is broken. */ -int c_check(buf *b) +int c_check(const void *m, size_t msz, buf *b) { - const octet *p; - size_t sz; + const octet *p, *t; uint32 seq; if (!bchal) { a_warn("CHAL", "impossible-challenge", A_END); goto fail; } - sz = 4 + bchal->tagsz; - if ((p = buf_get(b, sz)) == 0) { + p = BCUR(b); + if (buf_getu32(b, &seq) || (t = buf_get(b, bchal->tagsz)) == 0) { a_warn("CHAL", "invalid-challenge", A_END); goto fail; } - IF_TRACING(T_CHAL, trace_block(T_CRYPTO, "chal: check challenge", p, sz); ) - if (bchal->ops->chalvrf(bchal, p, 4, p + 4)) { + IF_TRACING(T_CHAL, { + trace(T_CHAL, "chal: checking challenge, seq = %lu", (unsigned long)seq); + if (msz) trace_block(T_CRYPTO, "chal: message block", m, msz); + trace_block(T_CRYPTO, "chal: check challenge", p, BCUR(b) - p); + }) + if (bchal->ops->chalvrf(bchal, m, msz, seq, t)) { a_warn("CHAL", "incorrect-tag", A_END); goto fail; } - seq = LOAD32(p); - if (seq_check(&iseq, seq, "CHAL")) - goto fail; - T( trace(T_CHAL, "chal: checked challenge %lu", (unsigned long)seq); ) + if (seq_check(&iseq, seq, "CHAL")) goto fail; + T( trace(T_CHAL, "chal: challenge ok"); ) return (0); fail: diff --git a/server/peer.c b/server/peer.c index 03ed2ae3..0ad32913 100644 --- a/server/peer.c +++ b/server/peer.c @@ -352,7 +352,7 @@ static void p_read(int fd, unsigned mode, void *v) }) buf_init(&b, buf_i, n); buf_getbyte(&b); - if (c_check(&b) || BLEFT(&b)) { + if (c_check(0, 0, &b) || BLEFT(&b)) { a_warn("PEER", "-", "invalid-greeting", A_END); return; } diff --git a/server/tripe.h b/server/tripe.h index 75ad2f1f..6f611822 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -376,15 +376,16 @@ typedef struct bulkops { /* 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. + uint32 /*seq*/, void */*t*/); + /* Calculate a tag for the challenge in @m@, @msz@, with the sequence + * number @seq@, 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. + uint32 /*seq*/, const void */*t*/); + /* Check the tag @t@ on @m@, @msz@ and @seq@: return zero if the tag + * is OK, nonzero if it's bad. */ void (*freechal)(bulkchal */*bc*/); @@ -1110,25 +1111,29 @@ extern int ksl_decrypt(keyset **/*ksroot*/, unsigned /*ty*/, /* --- @c_new@ --- * * - * Arguments: @buf *b@ = where to put the challenge + * Arguments: @const void *m@ = pointer to associated message, or null + * @size_t msz@ = length of associated message + * @buf *b@ = where to put the challenge * * Returns: Zero if OK, nonzero on error. * * Use: Issues a new challenge. */ -extern int c_new(buf */*b*/); +extern int c_new(const void */*m*/, size_t /*msz*/, buf */*b*/); /* --- @c_check@ --- * * - * Arguments: @buf *b@ = where to find the challenge + * Arguments: @const void *m@ = pointer to associated message, or null + * @size_t msz@ = length of associated message + * @buf *b@ = where to find the challenge * * Returns: Zero if OK, nonzero if it didn't work. * * Use: Checks a challenge. On failure, the buffer is broken. */ -extern int c_check(buf */*b*/); +extern int c_check(const void */*m*/, size_t /*msz*/, buf */*b*/); /*----- Administration interface ------------------------------------------*/ -- 2.11.0