From 4aeefba6811e57afe04a909fe147a29bb419d06b Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Thu, 12 Jan 2017 20:04:41 +0100 Subject: kernel: add "close" ctl message for tcp connection to gracefully hang up a connection without a tcp reset (used by go) --- sys/src/9/ip/tcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sys/src/9/ip/tcp.c b/sys/src/9/ip/tcp.c index b612bbd5a..f241a5c8e 100644 --- a/sys/src/9/ip/tcp.c +++ b/sys/src/9/ip/tcp.c @@ -3282,6 +3282,8 @@ tcpporthogdefensectl(char *val) static char* tcpctl(Conv* c, char** f, int n) { + if(n == 1 && strcmp(f[0], "close") == 0) + return tcpclose(c), nil; if(n == 1 && strcmp(f[0], "hangup") == 0) return tcphangup(c); if(n >= 1 && strcmp(f[0], "keepalive") == 0) -- cgit v1.2.3 From 47f07b2669e74eb957db56befa2237df5afa8474 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Thu, 12 Jan 2017 20:13:20 +0100 Subject: kernel: make the mntcache robust against fileserver like fossil that do not change the qid.vers on wstat introducing new ctrunc() function that invalidates any caches for the passed in chan, invoked when handling wstat with a specified file length or on file creation/truncation. test program to reproduce the problem: #include #include #include void main(int argc, char *argv[]) { int fd; Dir *d, nd; fd = create("xxx", ORDWR, 0666); write(fd, "1234", 4); d = dirstat("xxx"); assert(d->length == 4); nulldir(&nd); nd.length = 0; dirwstat("xxx", &nd); d = dirstat("xxx"); assert(d->length == 0); fd = open("xxx", OREAD); assert(read(fd, (void*)&d, 4) == 0); } --- sys/src/9/port/cache.c | 45 +++++++++++++++++++++++++++++++++++---------- sys/src/9/port/devmnt.c | 12 ++++++++++-- sys/src/9/port/portfns.h | 3 ++- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/sys/src/9/port/cache.c b/sys/src/9/port/cache.c index 306228731..37a4d6813 100644 --- a/sys/src/9/port/cache.c +++ b/sys/src/9/port/cache.c @@ -187,7 +187,7 @@ ccache(Chan *c) return nil; } -void +int copen(Chan *c) { Mntcache *m, *f, **l; @@ -195,19 +195,20 @@ copen(Chan *c) /* directories aren't cacheable */ if(c->qid.type&QTDIR){ c->mcp = nil; - return; + return 0; } lock(&cache); - m = clookup(c, 1); - if(m == nil) - m = cache.head; - else if(m->qid.vers == c->qid.vers) { + m = clookup(c, 0); + if(m != nil){ ctail(m); unlock(&cache); c->mcp = m; - return; + return 1; } + m = clookup(c, 1); + if(m == nil) + m = cache.head; ctail(m); l = &cache.hash[m->qid.path%NHASH]; @@ -234,7 +235,7 @@ copen(Chan *c) unlock(&cache); cacheunlock(m); c->mcp = f; - return; + return 1; } } @@ -251,10 +252,9 @@ copen(Chan *c) m->rah.vers = m->qid.vers; mntrahinit(&m->rah); cnodata(m); - cacheunlock(m); - c->mcp = m; + return 0; } enum { @@ -482,6 +482,31 @@ cwrite(Chan* c, uchar *buf, int len, vlong off) cachedata(m, buf, len, off); } +void +ctrunc(Chan *c) +{ + Mntcache *m; + + if(c->qid.type&QTDIR) + return; + + if((c->flag&COPEN) == 0){ + lock(&cache); + c->mcp = clookup(c, 0); + unlock(&cache); + } + + m = ccache(c); + if(m == nil) + return; + mntrahinit(&m->rah); + cnodata(m); + cacheunlock(m); + + if((c->flag&COPEN) == 0) + c->mcp = nil; +} + void cclunk(Chan *c) { diff --git a/sys/src/9/port/devmnt.c b/sys/src/9/port/devmnt.c index 095381d57..fc5ccbf1e 100644 --- a/sys/src/9/port/devmnt.c +++ b/sys/src/9/port/devmnt.c @@ -521,8 +521,11 @@ mntopencreate(int type, Chan *c, char *name, int omode, ulong perm) poperror(); mntfree(r); - if(c->flag & CCACHE) - copen(c); + if(c->flag & CCACHE){ + if(copen(c)) + if(type == Tcreate || (omode&OTRUNC) != 0) + ctrunc(c); + } return c; } @@ -620,6 +623,11 @@ mntwstat(Chan *c, uchar *dp, int n) mountrpc(m, r); poperror(); mntfree(r); + + if(c->flag & CCACHE) + if(GBIT64(&dp[STATFIXLEN-4*BIT16SZ-BIT64SZ]) != ~0ULL) + ctrunc(c); + return n; } diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 7c7eec461..5564ce0c8 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -41,13 +41,14 @@ void confinit(void); int consactive(void); void (*consdebug)(void); void cpushutdown(void); -void copen(Chan*); +int copen(Chan*); void cclunk(Chan*); Block* concatblock(Block*); Block* copyblock(Block*, int); void copypage(Page*, Page*); void countpagerefs(ulong*, int); int cread(Chan*, uchar*, int, vlong); +void ctrunc(Chan*); void cunmount(Chan*, Chan*); void cupdate(Chan*, uchar*, int, vlong); void cwrite(Chan*, uchar*, int, vlong); -- cgit v1.2.3 From 2e23780d2f4f1e3a55a096227a01995d0f0c2e52 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Thu, 12 Jan 2017 20:16:38 +0100 Subject: libsec: implement extended 192-bit nonce xchacha variant and hchacha function --- sys/include/ape/libsec.h | 6 +- sys/include/libsec.h | 6 +- sys/man/2/chacha | 16 +++++- sys/src/libsec/port/chacha.c | 117 +++++++++++++++++++++++++++++++++------ sys/src/libsec/port/chachatest.c | 41 ++++++++++++++ sys/src/libsec/port/salsa.c | 37 +++++++------ 6 files changed, 183 insertions(+), 40 deletions(-) diff --git a/sys/include/ape/libsec.h b/sys/include/ape/libsec.h index 11e8b5f61..96007de48 100644 --- a/sys/include/ape/libsec.h +++ b/sys/include/ape/libsec.h @@ -101,6 +101,7 @@ enum ChachaBsize= 64, ChachaKeylen= 256/8, ChachaIVlen= 96/8, + XChachaIVlen= 192/8, }; typedef struct Chachastate Chachastate; @@ -115,6 +116,7 @@ struct Chachastate u32int iv[3]; }; }; + u32int xkey[8]; int rounds; int ivwords; }; @@ -125,6 +127,8 @@ void chacha_setblock(Chachastate*, u64int); void chacha_encrypt(uchar*, ulong, Chachastate*); void chacha_encrypt2(uchar*, uchar*, ulong, Chachastate*); +void hchacha(uchar h[32], uchar *key, ulong keylen, uchar nonce[16], int rounds); + void ccpoly_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs); int ccpoly_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs); @@ -143,7 +147,7 @@ typedef struct Salsastate Salsastate; struct Salsastate { u32int input[16]; - u32int key[8]; + u32int xkey[8]; int rounds; int ivwords; }; diff --git a/sys/include/libsec.h b/sys/include/libsec.h index 348f4f967..030faac8c 100644 --- a/sys/include/libsec.h +++ b/sys/include/libsec.h @@ -93,6 +93,7 @@ enum ChachaBsize= 64, ChachaKeylen= 256/8, ChachaIVlen= 96/8, + XChachaIVlen= 192/8, }; typedef struct Chachastate Chachastate; @@ -107,6 +108,7 @@ struct Chachastate u32int iv[3]; }; }; + u32int xkey[8]; int rounds; int ivwords; }; @@ -117,6 +119,8 @@ void chacha_setblock(Chachastate*, u64int); void chacha_encrypt(uchar*, ulong, Chachastate*); void chacha_encrypt2(uchar*, uchar*, ulong, Chachastate*); +void hchacha(uchar h[32], uchar *key, ulong keylen, uchar nonce[16], int rounds); + void ccpoly_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs); int ccpoly_decrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs); @@ -135,7 +139,7 @@ typedef struct Salsastate Salsastate; struct Salsastate { u32int input[16]; - u32int key[8]; + u32int xkey[8]; int rounds; int ivwords; }; diff --git a/sys/man/2/chacha b/sys/man/2/chacha index b339e9dc0..21ce09ea0 100644 --- a/sys/man/2/chacha +++ b/sys/man/2/chacha @@ -1,6 +1,6 @@ .TH CHACHA 2 .SH NAME -setupChachastate, chacha_setblock, chacha_setiv, chacha_encrypt, chacha_encrypt2, ccpoly_encrypt, ccpoly_decrypt \- chacha encryption +setupChachastate, chacha_setblock, chacha_setiv, chacha_encrypt, chacha_encrypt2, hchacha, ccpoly_encrypt, ccpoly_decrypt \- chacha encryption .SH SYNOPSIS .B #include .br @@ -24,6 +24,9 @@ void chacha_setblock(Chachastate *s, u64int blockno) void chacha_setiv(Chachastate *s, uchar *iv); .PP .B +void hchacha(uchar h[32], uchar *key, ulong keylen, uchar nonce[16], int rounds); +.PP +.B void ccpoly_encrypt(uchar *dat, ulong ndat, uchar *aad, ulong naad, uchar tag[16], Chachastate *cs); .PP .B @@ -49,8 +52,11 @@ a or nonce of .I ivlen bytes (can be -.BR ChachaIVlen =12 -or 8, set to all zeros if the +.BR ChachaIVlen =12 , +.B 8 +or +.BR XChachaIVlen =24 ; +set to all zeros if the .I iv argument is nil), and the number of @@ -94,6 +100,10 @@ allowing seeking in an encrypted stream. sets the the initialization vector (nonce) to .IR iv . .PP +.I Hchacha +is a key expansion function that takes a 128 or 256-bit key +and a 128-bit nonce and produces a new 256-bit key. +.PP .I Ccpoly_encrypt and .I ccpoly_decrypt diff --git a/sys/src/libsec/port/chacha.c b/sys/src/libsec/port/chacha.c index c4f8aca77..49b7ee906 100644 --- a/sys/src/libsec/port/chacha.c +++ b/sys/src/libsec/port/chacha.c @@ -57,7 +57,8 @@ setupChachastate(Chachastate *s, uchar *key, ulong keylen, uchar *iv, ulong ivle { if(keylen != 256/8 && keylen != 128/8) sysfatal("invalid chacha key length"); - if(ivlen != 96/8 && ivlen != 64/8) + if(ivlen != 64/8 && ivlen != 96/8 + && ivlen != 128/8 && ivlen != 192/8) /* hchacha, xchacha */ sysfatal("invalid chacha iv length"); if(rounds == 0) rounds = 20; @@ -70,7 +71,16 @@ setupChachastate(Chachastate *s, uchar *key, ulong keylen, uchar *iv, ulong ivle load(&s->input[4], key, 4); load(&s->input[8], key, 4); } - s->ivwords = ivlen/sizeof(u32int); + s->xkey[0] = s->input[4]; + s->xkey[1] = s->input[5]; + s->xkey[2] = s->input[6]; + s->xkey[3] = s->input[7]; + s->xkey[4] = s->input[8]; + s->xkey[5] = s->input[9]; + s->xkey[6] = s->input[10]; + s->xkey[7] = s->input[11]; + + s->ivwords = ivlen/4; s->input[12] = 0; s->input[13] = 0; if(iv == nil){ @@ -80,20 +90,6 @@ setupChachastate(Chachastate *s, uchar *key, ulong keylen, uchar *iv, ulong ivle chacha_setiv(s, iv); } -void -chacha_setiv(Chachastate *s, uchar *iv) -{ - load(&s->input[16 - s->ivwords], iv, s->ivwords); -} - -void -chacha_setblock(Chachastate *s, u64int blockno) -{ - s->input[12] = blockno; - if(s->ivwords == 2) - s->input[13] = blockno>>32; -} - static void dorounds(u32int x[Blockwords], int rounds) { @@ -110,6 +106,83 @@ dorounds(u32int x[Blockwords], int rounds) } } +static void +hchachablock(uchar h[32], Chachastate *s) +{ + u32int x[16]; + + x[0] = s->input[0]; + x[1] = s->input[1]; + x[2] = s->input[2]; + x[3] = s->input[3]; + x[4] = s->input[4]; + x[5] = s->input[5]; + x[6] = s->input[6]; + x[7] = s->input[7]; + x[8] = s->input[8]; + x[9] = s->input[9]; + x[10] = s->input[10]; + x[11] = s->input[11]; + x[12] = s->input[12]; + x[13] = s->input[13]; + x[14] = s->input[14]; + x[15] = s->input[15]; + + dorounds(x, s->rounds); + + PUT4(h+0*4, x[0]); + PUT4(h+1*4, x[1]); + PUT4(h+2*4, x[2]); + PUT4(h+3*4, x[3]); + PUT4(h+4*4, x[12]); + PUT4(h+5*4, x[13]); + PUT4(h+6*4, x[14]); + PUT4(h+7*4, x[15]); +} + +void +chacha_setiv(Chachastate *s, uchar *iv) +{ + if(s->ivwords == 192/32){ + /* xchacha with 192-bit iv */ + u32int counter[2]; + uchar h[32]; + + s->input[4] = s->xkey[0]; + s->input[5] = s->xkey[1]; + s->input[6] = s->xkey[2]; + s->input[7] = s->xkey[3]; + s->input[8] = s->xkey[4]; + s->input[9] = s->xkey[5]; + s->input[10] = s->xkey[6]; + s->input[11] = s->xkey[7]; + + counter[0] = s->input[12]; + counter[1] = s->input[13]; + + load(&s->input[12], iv, 4); + + hchachablock(h, s); + load(&s->input[4], h, 8); + memset(h, 0, 32); + + s->input[12] = counter[0]; + s->input[13] = counter[1]; + + load(&s->input[14], iv+16, 2); + return; + } + load(&s->input[16 - s->ivwords], iv, s->ivwords); +} + +void +chacha_setblock(Chachastate *s, u64int blockno) +{ + s->input[12] = blockno; + if(s->ivwords != 3) + s->input[13] = blockno>>32; +} + static void encryptblock(Chachastate *s, uchar *src, uchar *dst) { @@ -143,7 +216,7 @@ encryptblock(Chachastate *s, uchar *src, uchar *dst) dst += 16; } - if(++s->input[12] == 0 && s->ivwords == 2) + if(++s->input[12] == 0 && s->ivwords != 3) s->input[13]++; } @@ -169,3 +242,13 @@ chacha_encrypt(uchar *buf, ulong bytes, Chachastate *s) { chacha_encrypt2(buf, buf, bytes, s); } + +void +hchacha(uchar h[32], uchar *key, ulong keylen, uchar nonce[16], int rounds) +{ + Chachastate s[1]; + + setupChachastate(s, key, keylen, nonce, 16, rounds); + hchachablock(h, s); + memset(s, 0, sizeof(s)); +} diff --git a/sys/src/libsec/port/chachatest.c b/sys/src/libsec/port/chachatest.c index 92a5d0897..49b4ff104 100644 --- a/sys/src/libsec/port/chachatest.c +++ b/sys/src/libsec/port/chachatest.c @@ -42,6 +42,26 @@ uchar rfcref[] = { 0x87, 0x4d }; +uchar xcckey[] = { + 0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4, 0x62, 0xcd, 0x51, 0x19, 0x7a, 0x9a, 0x46, 0xc7, + 0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2, 0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89, +}; +uchar xcciv[] = { + 0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8, 0x75, 0xfc, 0x73, 0xd6, + 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37, +}; +uchar xccref[] = { + 0x4f, 0xeb, 0xf2, 0xfe, 0x4b, 0x35, 0x9c, 0x50, 0x8d, 0xc5, 0xe8, 0xb5, 0x98, 0x0c, 0x88, 0xe3, + 0x89, 0x46, 0xd8, 0xf1, 0x8f, 0x31, 0x34, 0x65, 0xc8, 0x62, 0xa0, 0x87, 0x82, 0x64, 0x82, 0x48, + 0x01, 0x8d, 0xac, 0xdc, 0xb9, 0x04, 0x17, 0x88, 0x53, 0xa4, 0x6d, 0xca, 0x3a, 0x0e, 0xaa, 0xee, + 0x74, 0x7c, 0xba, 0x97, 0x43, 0x4e, 0xaf, 0xfa, 0xd5, 0x8f, 0xea, 0x82, 0x22, 0x04, 0x7e, 0x0d, + 0xe6, 0xc3, 0xa6, 0x77, 0x51, 0x06, 0xe0, 0x33, 0x1a, 0xd7, 0x14, 0xd2, 0xf2, 0x7a, 0x55, 0x64, + 0x13, 0x40, 0xa1, 0xf1, 0xdd, 0x9f, 0x94, 0x53, 0x2e, 0x68, 0xcb, 0x24, 0x1c, 0xbd, 0xd1, 0x50, + 0x97, 0x0d, 0x14, 0xe0, 0x5c, 0x5b, 0x17, 0x31, 0x93, 0xfb, 0x14, 0xf5, 0x1c, 0x41, 0xf3, 0x93, + 0x83, 0x5b, 0xf7, 0xf4, 0x16, 0xa7, 0xe0, 0xbb, 0xa8, 0x1f, 0xfb, 0x8b, 0x13, 0xaf, 0x0e, 0x21, + 0x69, 0x1d, 0x7e, 0xce, 0xc9, 0x3b, 0x75, 0xe6, 0xe4, 0x18, 0x3a, +}; + uchar ccpaad[] = { 0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, }; @@ -103,6 +123,26 @@ main(int argc, char **argv) } print("\n"); + + print("xchacha key:\n"); + printblock(xcckey, sizeof(xcckey)); + + print("xchacha iv:\n"); + printblock(xcciv, sizeof(xcciv)); + + setupChachastate(&s, xcckey, sizeof(xcckey), xcciv, sizeof(xcciv), 20); + memset(rfcout, 0, sizeof(xccref)); + chacha_encrypt(rfcout, sizeof(xccref), &s); + + print("xchacha out:\n"); + printblock(rfcout, sizeof(xccref)); + if(memcmp(rfcout, xccref, sizeof(xccref)) != 0){ + print("failure of vision\n"); + exits("wrong"); + } + print("\n"); + + print("ccpoly key:\n"); printblock(ccpkey, sizeof(ccpkey)); @@ -136,6 +176,7 @@ main(int argc, char **argv) } print("\n"); + print("ccpoly64 key:\n"); printblock(ccp64key, sizeof(ccp64key)); diff --git a/sys/src/libsec/port/salsa.c b/sys/src/libsec/port/salsa.c index 648f6bca1..3a0ba940b 100644 --- a/sys/src/libsec/port/salsa.c +++ b/sys/src/libsec/port/salsa.c @@ -34,7 +34,8 @@ setupSalsastate(Salsastate *s, uchar *key, ulong keylen, uchar *iv, ulong ivlen, { if(keylen != 256/8 && keylen != 128/8) sysfatal("invalid salsa key length"); - if(ivlen != 64/8 && ivlen != 128/8 && ivlen != 192/8) + if(ivlen != 64/8 + && ivlen != 128/8 && ivlen != 192/8) /* hsalsa, xsalsa */ sysfatal("invalid salsa iv length"); if(rounds == 0) rounds = 20; @@ -54,14 +55,14 @@ setupSalsastate(Salsastate *s, uchar *key, ulong keylen, uchar *iv, ulong ivlen, load(&s->input[11], key, 4); load(&s->input[15], tau +4*3, 1); } - s->key[0] = s->input[1]; - s->key[1] = s->input[2]; - s->key[2] = s->input[3]; - s->key[3] = s->input[4]; - s->key[4] = s->input[11]; - s->key[5] = s->input[12]; - s->key[6] = s->input[13]; - s->key[7] = s->input[14]; + s->xkey[0] = s->input[1]; + s->xkey[1] = s->input[2]; + s->xkey[2] = s->input[3]; + s->xkey[3] = s->input[4]; + s->xkey[4] = s->input[11]; + s->xkey[5] = s->input[12]; + s->xkey[6] = s->input[13]; + s->xkey[7] = s->input[14]; s->ivwords = ivlen/4; s->input[8] = 0; @@ -152,7 +153,7 @@ void salsa_setiv(Salsastate *s, uchar *iv) { if(s->ivwords == 128/32){ - /* hsalsa 128-bit iv */ + /* hsalsa with 128-bit iv */ load(&s->input[6], iv, 4); return; } @@ -164,14 +165,14 @@ salsa_setiv(Salsastate *s, uchar *iv) counter[0] = s->input[8]; counter[1] = s->input[9]; - s->input[1] = s->key[0]; - s->input[2] = s->key[1]; - s->input[3] = s->key[2]; - s->input[4] = s->key[3]; - s->input[11] = s->key[4]; - s->input[12] = s->key[5]; - s->input[13] = s->key[6]; - s->input[14] = s->key[7]; + s->input[1] = s->xkey[0]; + s->input[2] = s->xkey[1]; + s->input[3] = s->xkey[2]; + s->input[4] = s->xkey[3]; + s->input[11] = s->xkey[4]; + s->input[12] = s->xkey[5]; + s->input[13] = s->xkey[6]; + s->input[14] = s->xkey[7]; load(&s->input[6], iv, 4); -- cgit v1.2.3