]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/devtls.c
import E script from bell labs
[plan9front.git] / sys / src / 9 / port / devtls.c
index 3e98eaf021b8ad694ecf49b2c801549b7f16089c..ad6750a36ca922d177dfbe207c1f9a623233a806 100644 (file)
 #include       <libsec.h>
 
 typedef struct OneWay  OneWay;
-typedef struct Secret          Secret;
+typedef struct Secret  Secret;
 typedef struct TlsRec  TlsRec;
 typedef struct TlsErrs TlsErrs;
 
 enum {
        Statlen=        1024,           /* max. length of status or stats message */
        /* buffer limits */
-       MaxRecLen               = 1<<14,        /* max payload length of a record layer message */
+       MaxRecLen       = 1<<14,        /* max payload length of a record layer message */
        MaxCipherRecLen = MaxRecLen + 2048,
-       RecHdrLen               = 5,
-       MaxMacLen               = SHA1dlen,
+       RecHdrLen       = 5,
+       MaxMacLen       = SHA1dlen,
 
        /* protocol versions we can accept */
-       TLSVersion              = 0x0301,
-       SSL3Version             = 0x0300,
-       ProtocolVersion = 0x0301,       /* maximum version we speak */
+       SSL3Version     = 0x0300,
+       TLS10Version    = 0x0301,
+       TLS11Version    = 0x0302,
        MinProtoVersion = 0x0300,       /* limits on version we accept */
        MaxProtoVersion = 0x03ff,
 
@@ -73,6 +73,7 @@ enum {
        EInternalError                  = 80,
        EUserCanceled                   = 90,
        ENoRenegotiation                = 100,
+       EUnrecognizedName               = 112,
 
        EMAX = 256
 };
@@ -800,8 +801,20 @@ 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);
 if(tr->debug) pdump(unpad_len, p, "decrypted:");
 
@@ -812,9 +825,10 @@ if(tr->debug) pdump(unpad_len, p, "decrypted:");
                (*tr->packMac)(in->sec, in->sec->mackey, seq, header, p, len, hmac);
                if(unpad_len < in->sec->maclen)
                        rcvError(tr, EBadRecordMac, "short record mac");
-               if(memcmp(hmac, p+len, in->sec->maclen) != 0)
+               if(constcmp(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();
@@ -848,20 +862,27 @@ if(tr->debug) pdump(unpad_len, p, "decrypted:");
                        rcvError(tr, EIllegalParameter, "invalid alert fatal code");
 
                /*
-                * propate non-fatal alerts to handshaker
+                * 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:
                /*
@@ -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;
@@ -1555,12 +1592,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){
@@ -1824,7 +1861,7 @@ tlsError(TlsRec *tr, char *msg)
 {
        int s;
 
-if(tr->debug)pprint("tleError %s\n", msg);
+if(tr->debug)pprint("tlsError %s\n", msg);
        lock(&tr->statelk);
        s = tr->state;
        tr->state = SError;