update to (some parts of) tls 1.2 (cinap). some careful updates to allow for the fd message to differentiate between 1.0 tls support and later updates. Reference: /n/atom/patch/applied/devtls1.2 Date: Tue Sep 22 04:30:24 CES 2015 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/port/devtls.c Tue Sep 22 04:27:29 2015 +++ /sys/src/nix/port/devtls.c Tue Sep 22 04:27:31 2015 @@ -21,14 +21,15 @@ MaxRecLen = 1<<14, /* max payload length of a record layer message */ MaxCipherRecLen = MaxRecLen + 2048, RecHdrLen = 5, - MaxMacLen = SHA1dlen, + MaxMacLen = SHA2_256dlen, /* protocol versions we can accept */ - TLSVersion = 0x0301, - SSL3Version = 0x0300, - ProtocolVersion = 0x0301, /* maximum version we speak */ - MinProtoVersion = 0x0300, /* limits on version we accept */ - MaxProtoVersion = 0x03ff, + SSL3Version = 0x0300, + TLS10Version = 0x0301, + TLS11Version = 0x0302, + TLS12Version = 0x0303, + MinProtoVersion = SSL3Version, /* limits on version we accept */ + MaxProtoVersion = TLS12Version, /* connection states */ SHandshake = 1 << 0, /* doing handshake */ @@ -73,6 +74,7 @@ EInternalError = 80, EUserCanceled = 90, ENoRenegotiation = 100, + EUnrecognizedName = 112, EMAX = 256 }; @@ -800,8 +802,20 @@ /* to avoid Canvel-Hiltgen-Vaudenay-Vuagnoux attack, all errors here should look alike, including timing of the response. */ unpad_len = (*in->sec->dec)(in->sec, p, len); + + /* excplicit iv */ + if(tr->version >= TLS11Version){ + len -= in->sec->block; + if(len < 0) + rcvError(tr, EDecodeError, "runt record message"); + + unpad_len -= in->sec->block; + p += in->sec->block; + } + if(unpad_len >= in->sec->maclen) len = unpad_len - in->sec->maclen; + if(tr->debug) pprint("decrypted %d\n", unpad_len); if(tr->debug) pdump(unpad_len, p, "decrypted:"); @@ -814,7 +828,8 @@ rcvError(tr, EBadRecordMac, "short record mac"); if(memcmp(hmac, p+len, in->sec->maclen) != 0) rcvError(tr, EBadRecordMac, "record mac mismatch"); - b->wp = b->rp + len; + b->rp = p; + b->wp = p+len; } qunlock(&in->seclock); poperror(); @@ -850,18 +865,25 @@ /* * propagate non-fatal alerts to handshaker */ - if(p[1] == ECloseNotify) { + switch(p[1]){ + case ECloseNotify: tlsclosed(tr, SRClose); if(tr->opened) error("tls hungup"); error("close notify"); - } - if(p[1] == ENoRenegotiation) + break; + case ENoRenegotiation: alertHand(tr, "no renegotiation"); - else if(p[1] == EUserCanceled) + break; + case EUserCanceled: alertHand(tr, "handshake canceled by user"); - else + break; + case EUnrecognizedName: + /* happens in response to SNI, can be ignored. */ + break; + default: rcvError(tr, EIllegalParameter, "invalid alert code"); + } break; case RHandshake: /* @@ -1203,6 +1225,14 @@ return n; } +/* is this good enough randomness? */ +static void +randfill(uchar *buf, int len) +{ + while(len-- > 0) + *buf++ = nrand(256); +} + /* * write a block in tls records */ @@ -1213,7 +1243,7 @@ Block *nb; uchar *p, seq[8]; OneWay *volatile out; - int n, maclen, pad, ok; + int n, ivlen, maclen, pad, ok; out = &tr->out; bb = b; @@ -1246,21 +1276,24 @@ qlock(&out->seclock); maclen = 0; pad = 0; + ivlen = 0; if(out->sec != nil){ maclen = out->sec->maclen; pad = maclen + out->sec->block; + if(tr->version >= TLS11Version) + ivlen = out->sec->block; } n = BLEN(bb); if(n > MaxRecLen){ n = MaxRecLen; - nb = allocb(n + pad + RecHdrLen); - memmove(nb->wp + RecHdrLen, bb->rp, n); + nb = allocb(RecHdrLen + ivlen + n + pad); + memmove(nb->wp + RecHdrLen + ivlen, bb->rp, n); bb->rp += n; }else{ /* * carefully reuse bb so it will get freed if we're out of memory */ - bb = padblock(bb, RecHdrLen); + bb = padblock(bb, RecHdrLen + ivlen); if(pad) nb = padblock(bb, -pad); else @@ -1276,9 +1309,15 @@ if(out->sec != nil){ put64(seq, out->seq); out->seq++; - (*tr->packMac)(out->sec, out->sec->mackey, seq, p, p + RecHdrLen, n, p + RecHdrLen + n); + (*tr->packMac)(out->sec, out->sec->mackey, seq, p, p + RecHdrLen + ivlen, n, p + RecHdrLen + ivlen + n); n += maclen; + /* explicit iv */ + if(ivlen > 0){ + randfill(p + RecHdrLen, ivlen); + n += ivlen; + } + /* encrypt */ n = (*out->sec->enc)(out->sec, p + RecHdrLen, n); nb->wp = p + RecHdrLen + n; @@ -1381,11 +1420,25 @@ memmove(s->mackey, p, ha->maclen); } +static void +initsha2_256key(Hashalg *ha, int version, Secret *s, uchar *p) +{ + s->maclen = ha->maclen; + + /* only TLS 1.2 has SHA256. */ + if(version != TLS12Version) + error("sha256 is TLS 1.2 only"); + + s->mac = hmac_sha2_256; + memmove(s->mackey, p, ha->maclen); +} + static Hashalg hashtab[] = { { "clear", 0, initclearmac, }, { "md5", MD5dlen, initmd5key, }, { "sha1", SHA1dlen, initsha1key, }, + { "sha256", SHA2_256dlen, initsha2_256key, }, { 0 } }; @@ -1556,12 +1609,12 @@ if(tr->verset) error("version already set"); m = strtol(cb->f[1], nil, 0); + if(m < MinProtoVersion || m > MaxProtoVersion) + error("unsupported version"); if(m == SSL3Version) tr->packMac = sslPackMac; - else if(m == TLSVersion) - tr->packMac = tlsPackMac; else - error("unsupported version"); + tr->packMac = tlsPackMac; tr->verset = 1; tr->version = m; }else if(strcmp(cb->f[0], "secret") == 0){