--- /sys/src/9/port/devtls.c +++ /sys/src/9/port/devtls.c @@ -1,5 +1,5 @@ /* - * devtls - record layer for transport layer security 1.0 and secure sockets layer 3.0 + * devtls - record layer for transport layer security 1.0, 1.1, 1.2 and secure sockets layer 3.0 */ #include "u.h" #include "../port/lib.h" @@ -21,12 +21,13 @@ enum { 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 */ + TLS10Version = 0x0301, + TLS11Version = 0x0302, + TLS12Version = 0x0303, MinProtoVersion = 0x0300, /* limits on version we accept */ MaxProtoVersion = 0x03ff, @@ -73,6 +74,7 @@ enum { EInternalError = 80, EUserCanceled = 90, ENoRenegotiation = 100, + EUnrecognizedName = 112, EMAX = 256 }; @@ -800,6 +802,17 @@ if(tr->debug) pprint("consumed unprocessed %d\n", len); /* 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); @@ -814,7 +827,8 @@ if(tr->debug) pdump(unpad_len, p, "decrypted:"); 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 +864,25 @@ if(tr->debug) pdump(unpad_len, p, "decrypted:"); /* * propate 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: /* @@ -1202,6 +1223,13 @@ tlsread(Chan *c, void *a, long n, vlong off) return n; } +static void +randfill(uchar *buf, int len) +{ + while(len-- > 0) + *buf++ = nrand(256); +} + /* * write a block in tls records */ @@ -1212,7 +1240,7 @@ tlsrecwrite(TlsRec *tr, int type, Block *b) 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; @@ -1245,21 +1273,24 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:"); 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 @@ -1275,9 +1306,15 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:"); 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; @@ -1380,11 +1417,22 @@ initsha1key(Hashalg *ha, int version, Secret *s, uchar *p) memmove(s->mackey, p, ha->maclen); } +static void +initsha2_256key(Hashalg *ha, int version, Secret *s, uchar *p) +{ + if(version == SSL3Version) + error("sha256 cannot be used with SSL"); + s->maclen = ha->maclen; + 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 } }; @@ -1555,12 +1603,12 @@ tlswrite(Chan *c, void *a, long n, vlong off) 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){ --- /sys/man/3/tls +++ /sys/man/3/tls @@ -17,7 +17,8 @@ tls \- TLS1 and SSL3 record layer .fi .SH DESCRIPTION The TLS device implements the record layer protocols -of Transport Layer Security version 1.0 and Secure Sockets Layer version 3.0. +of Transport Layer Security versions 1.[0-2] and +Secure Sockets Layer version 3.0. It does not implement the handshake protocols, which are responsible for mutual authentication and key exchange. The @@ -54,9 +55,14 @@ Initially, outgoing messages use version format records, but incoming messages of either version are accepted. Valid versions are .B 0x300 -for SSLv3.0 and +for SSLv3.0, .B 0x301 -for TLSv1.0 (which could be known as SSLv3.01.) +for TLSv1.0, +.B 0x302 +for TLSv1.1, +and +.B 0x303 +for TLSv1.2. This command must be issued before any other command and before reading or writing any messages; it may only be executed once. @@ -265,9 +271,10 @@ Currently implemented encryption algorithms are and .BR 'aes_256_cbc' . Currently implemented hashing algorithms are -.B 'md5' +.BR "md5" , +.BR "sha1" , and -.BR 'sha1' . +.BR "sha2_256" . .SH "SEE ALSO" .IR listen (8), .IR dial (2),