]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/devtls.c
devproc: return process id when reading /proc/n/ctl file
[plan9front.git] / sys / src / 9 / port / devtls.c
index 3e98eaf021b8ad694ecf49b2c801549b7f16089c..177d8ecb4243f2be49f892b4fd988265ec995527 100644 (file)
@@ -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.2 and secure sockets layer 3.0
  */
 #include       "u.h"
 #include       "../port/lib.h"
 #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       = SHA2_256dlen,
 
        /* protocol versions we can accept */
-       TLSVersion              = 0x0301,
-       SSL3Version             = 0x0300,
-       ProtocolVersion = 0x0301,       /* maximum version we speak */
+       SSL3Version     = 0x0300,
+       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
 };
@@ -81,21 +83,27 @@ struct Secret
 {
        char            *encalg;        /* name of encryption alg */
        char            *hashalg;       /* name of hash alg */
+
+       int             (*aead_enc)(Secret*, uchar*, int, uchar*, uchar*, int);
+       int             (*aead_dec)(Secret*, uchar*, int, uchar*, uchar*, int);
+
        int             (*enc)(Secret*, uchar*, int);
        int             (*dec)(Secret*, uchar*, int);
        int             (*unpad)(uchar*, int, int);
-       DigestState     *(*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
+       DigestState*    (*mac)(uchar*, ulong, uchar*, ulong, uchar*, DigestState*);
+
        int             block;          /* encryption block len, 0 if none */
-       int             maclen;
+       int             maclen;         /* # bytes of record mac / authentication tag */
+       int             recivlen;       /* # bytes of record iv for AEAD ciphers */
        void            *enckey;
-       uchar   mackey[MaxMacLen];
+       uchar           mackey[MaxMacLen];
 };
 
 struct OneWay
 {
        QLock           io;             /* locks io access */
        QLock           seclock;        /* locks secret paramaters */
-       ulong           seq;
+       u64int          seq;
        Secret          *sec;           /* cipher in use */
        Secret          *new;           /* cipher waiting for enable */
 };
@@ -117,8 +125,11 @@ struct TlsRec
        int             state;
        int             debug;
 
-       /* record layer mac functions for different protocol versions */
-       void            (*packMac)(Secret*, uchar*, uchar*, uchar*, uchar*, int, uchar*);
+       /*
+        * function to genrate authenticated data blob for different
+        * protocol versions
+        */
+       int             (*packAAD)(u64int, uchar*, uchar*);
 
        /* input side -- protected by in.io */
        OneWay          in;
@@ -219,13 +230,13 @@ static TlsRec     *mktlsrec(void);
 static DigestState*sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
 static DigestState*sslmac_sha1(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
 static DigestState*nomac(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestState *s);
-static void    sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);
-static void    tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac);
-static void    put64(uchar *p, vlong x);
+static int     sslPackAAD(u64int, uchar*, uchar*);
+static int     tlsPackAAD(u64int, uchar*, uchar*);
+static void    packMac(Secret*, uchar*, int, uchar*, int, uchar*);
+static void    put64(uchar *p, u64int);
 static void    put32(uchar *p, u32int);
 static void    put24(uchar *p, int);
 static void    put16(uchar *p, int);
-static u32int  get32(uchar *p);
 static int     get16(uchar *p);
 static void    tlsSetState(TlsRec *tr, int new, int old);
 static void    rcvAlert(TlsRec *tr, int err);
@@ -236,6 +247,10 @@ static int des3enc(Secret *sec, uchar *buf, int n);
 static int     des3dec(Secret *sec, uchar *buf, int n);
 static int     aesenc(Secret *sec, uchar *buf, int n);
 static int     aesdec(Secret *sec, uchar *buf, int n);
+static int     ccpoly_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len);
+static int     ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len);
+static int     aesgcm_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len);
+static int     aesgcm_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len);
 static int     noenc(Secret *sec, uchar *buf, int n);
 static int     sslunpad(uchar *buf, int n, int block);
 static int     tlsunpad(uchar *buf, int n, int block);
@@ -408,21 +423,7 @@ static Chan*
 tlsopen(Chan *c, int omode)
 {
        TlsRec *tr, **pp;
-       int t, perm;
-
-       perm = 0;
-       omode &= 3;
-       switch(omode) {
-       case OREAD:
-               perm = 4;
-               break;
-       case OWRITE:
-               perm = 2;
-               break;
-       case ORDWR:
-               perm = 6;
-               break;
-       }
+       int t;
 
        t = TYPE(c->qid);
        switch(t) {
@@ -455,10 +456,7 @@ tlsopen(Chan *c, int omode)
                tr = *pp;
                if(tr == nil)
                        error("must open connection using clone");
-               if((perm & (tr->perm>>6)) != perm
-               && (strcmp(up->user, tr->user) != 0
-                   || (perm & tr->perm) != perm))
-                       error(Eperm);
+               devpermcheck(tr->user, tr->perm, omode);
                if(t == Qhand){
                        if(waserror()){
                                unlock(&tr->hqlock);
@@ -487,7 +485,7 @@ tlsopen(Chan *c, int omode)
        c->mode = openmode(omode);
        c->flag |= COPEN;
        c->offset = 0;
-       c->iounit = qiomaxatomic;
+       c->iounit = MaxRecLen;
        return c;
 }
 
@@ -518,7 +516,7 @@ tlswstat(Chan *c, uchar *dp, int n)
                error(Eshortstat);
        if(!emptystr(d->uid))
                kstrdup(&tr->user, d->uid);
-       if(d->mode != ~0UL)
+       if(d->mode != -1)
                tr->perm = d->mode;
 
        free(d);
@@ -732,9 +730,10 @@ tlsrecread(TlsRec *tr)
 {
        OneWay *volatile in;
        Block *volatile b;
-       uchar *p, seq[8], header[RecHdrLen], hmac[MaxMacLen];
+       uchar *p, aad[8+RecHdrLen], header[RecHdrLen], hmac[MaxMacLen];
        int volatile nconsumed;
-       int len, type, ver, unpad_len;
+       int len, type, ver, unpad_len, aadlen, ivlen;
+       Secret *sec;
 
        nconsumed = 0;
        if(waserror()){
@@ -796,25 +795,48 @@ if(tr->debug) pprint("consumed unprocessed %d\n", len);
        }
        qlock(&in->seclock);
        p = b->rp;
-       if(in->sec != nil) {
+       sec = in->sec;
+       if(sec != nil) {
                /* 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);
-               if(unpad_len >= in->sec->maclen)
-                       len = unpad_len - in->sec->maclen;
+               if(sec->aead_dec != nil)
+                       unpad_len = len;
+               else {
+                       unpad_len = (*sec->dec)(sec, p, len);
 if(tr->debug) pprint("decrypted %d\n", unpad_len);
 if(tr->debug) pdump(unpad_len, p, "decrypted:");
+               }
+
+               ivlen = sec->recivlen;
+               if(tr->version >= TLS11Version){
+                       if(ivlen == 0)
+                               ivlen = sec->block;
+               }
+               len -= ivlen;
+               if(len < 0)
+                       rcvError(tr, EDecodeError, "runt record message");
+               unpad_len -= ivlen;
+               p += ivlen;
+
+               if(unpad_len >= sec->maclen)
+                       len = unpad_len - sec->maclen;
 
                /* update length */
                put16(header+3, len);
-               put64(seq, in->seq);
-               in->seq++;
-               (*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)
-                       rcvError(tr, EBadRecordMac, "record mac mismatch");
-               b->wp = b->rp + len;
+               aadlen = (*tr->packAAD)(in->seq++, header, aad);
+               if(sec->aead_dec != nil) {
+                       len = (*sec->aead_dec)(sec, aad, aadlen, p - ivlen, p, unpad_len);
+                       if(len < 0)
+                               rcvError(tr, EBadRecordMac, "record mac mismatch");
+               } else {
+                       packMac(sec, aad, aadlen, p, len, hmac);
+                       if(unpad_len < sec->maclen)
+                               rcvError(tr, EBadRecordMac, "short record mac");
+                       if(tsmemcmp(hmac, p + len, sec->maclen) != 0)
+                               rcvError(tr, EBadRecordMac, "record mac mismatch");
+               }
+               b->rp = p;
+               b->wp = p+len;
        }
        qunlock(&in->seclock);
        poperror();
@@ -848,20 +870,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:
                /*
@@ -1074,7 +1103,7 @@ tlsbread(Chan *c, long n, ulong offset)
 
                /* return at most what was asked for */
                b = qgrab(&tr->processed, n);
-if(tr->debug) pprint("consumed processed %ld\n", BLEN(b));
+if(tr->debug) pprint("consumed processed %zd\n", BLEN(b));
 if(tr->debug) pdump(BLEN(b), b->rp, "consumed:");
                qunlock(&tr->in.io);
                poperror();
@@ -1150,7 +1179,9 @@ tlsread(Chan *c, void *a, long n, vlong off)
                if(tr->out.sec != nil)
                        s = seprint(s, e, "EncOut: %s\nHashOut: %s\n", tr->out.sec->encalg, tr->out.sec->hashalg);
                if(tr->out.new != nil)
-                       seprint(s, e, "NewEncOut: %s\nNewHashOut: %s\n", tr->out.new->encalg, tr->out.new->hashalg);
+                       s = seprint(s, e, "NewEncOut: %s\nNewHashOut: %s\n", tr->out.new->encalg, tr->out.new->hashalg);
+               if(tr->c != nil)
+                       seprint(s, e, "Chan: %s\n", chanpath(tr->c));
                qunlock(&tr->in.seclock);
                qunlock(&tr->out.seclock);
                n = readstr(offset, a, n, buf);
@@ -1210,9 +1241,10 @@ tlsrecwrite(TlsRec *tr, int type, Block *b)
 {
        Block *volatile bb;
        Block *nb;
-       uchar *p, seq[8];
+       uchar *p, aad[8+RecHdrLen];
        OneWay *volatile out;
-       int n, maclen, pad, ok;
+       int n, ivlen, maclen, aadlen, pad, ok;
+       Secret *sec;
 
        out = &tr->out;
        bb = b;
@@ -1223,7 +1255,7 @@ tlsrecwrite(TlsRec *tr, int type, Block *b)
                nexterror();
        }
        qlock(&out->io);
-if(tr->debug)pprint("send %ld\n", BLEN(b));
+if(tr->debug)pprint("send %zd\n", BLEN(b));
 if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
 
 
@@ -1245,21 +1277,28 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
                qlock(&out->seclock);
                maclen = 0;
                pad = 0;
-               if(out->sec != nil){
-                       maclen = out->sec->maclen;
-                       pad = maclen + out->sec->block;
+               ivlen = 0;
+               sec = out->sec;
+               if(sec != nil){
+                       maclen = sec->maclen;
+                       pad = maclen + sec->block;
+                       ivlen = sec->recivlen;
+                       if(tr->version >= TLS11Version){
+                               if(ivlen == 0)
+                                       ivlen = 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
@@ -1272,14 +1311,16 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
                put16(p+1, tr->version);
                put16(p+3, n);
 
-               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);
-                       n += maclen;
-
-                       /* encrypt */
-                       n = (*out->sec->enc)(out->sec, p + RecHdrLen, n);
+               if(sec != nil){
+                       aadlen = (*tr->packAAD)(out->seq++, p, aad);
+                       if(sec->aead_enc != nil)
+                               n = (*sec->aead_enc)(sec, aad, aadlen, p + RecHdrLen, p + RecHdrLen + ivlen, n) + ivlen;
+                       else {
+                               if(ivlen > 0)
+                                       prng(p + RecHdrLen, ivlen);
+                               packMac(sec, aad, aadlen, p + RecHdrLen + ivlen, n, p + RecHdrLen + ivlen + n);
+                               n = (*sec->enc)(sec, p + RecHdrLen, ivlen + n + maclen);
+                       }
                        nb->wp = p + RecHdrLen + n;
 
                        /* update length */
@@ -1365,7 +1406,6 @@ initmd5key(Hashalg *ha, int version, Secret *s, uchar *p)
 static void
 initclearmac(Hashalg *, int, Secret *s, uchar *)
 {
-       s->maclen = 0;
        s->mac = nomac;
 }
 
@@ -1380,11 +1420,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, },
+       { "clear",      0,              initclearmac, },
+       { "md5",        MD5dlen,        initmd5key, },
+       { "sha1",       SHA1dlen,       initsha1key, },
+       { "sha256",     SHA2_256dlen,   initsha2_256key, },
        { 0 }
 };
 
@@ -1412,17 +1463,16 @@ struct Encalg
 static void
 initRC4key(Encalg *ea, Secret *s, uchar *p, uchar *)
 {
-       s->enckey = smalloc(sizeof(RC4state));
+       s->enckey = secalloc(sizeof(RC4state));
        s->enc = rc4enc;
        s->dec = rc4enc;
-       s->block = 0;
        setupRC4state(s->enckey, p, ea->keylen);
 }
 
 static void
 initDES3key(Encalg *, Secret *s, uchar *p, uchar *iv)
 {
-       s->enckey = smalloc(sizeof(DES3state));
+       s->enckey = secalloc(sizeof(DES3state));
        s->enc = des3enc;
        s->dec = des3dec;
        s->block = 8;
@@ -1432,19 +1482,48 @@ initDES3key(Encalg *, Secret *s, uchar *p, uchar *iv)
 static void
 initAESkey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
 {
-       s->enckey = smalloc(sizeof(AESstate));
+       s->enckey = secalloc(sizeof(AESstate));
        s->enc = aesenc;
        s->dec = aesdec;
        s->block = 16;
        setupAESstate(s->enckey, p, ea->keylen, iv);
 }
 
+static void
+initccpolykey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
+{
+       s->enckey = secalloc(sizeof(Chachastate));
+       s->aead_enc = ccpoly_aead_enc;
+       s->aead_dec = ccpoly_aead_dec;
+       s->maclen = Poly1305dlen;
+       if(ea->ivlen == 0) {
+               /* older draft version, iv is 64-bit sequence number */
+               setupChachastate(s->enckey, p, ea->keylen, nil, 64/8, 20);
+       } else {
+               /* IETF standard, 96-bit iv xored with sequence number */
+               memmove(s->mackey, iv, ea->ivlen);
+               setupChachastate(s->enckey, p, ea->keylen, iv, ea->ivlen, 20);
+       }
+}
+
+static void
+initaesgcmkey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
+{
+       s->enckey = secalloc(sizeof(AESGCMstate));
+       s->aead_enc = aesgcm_aead_enc;
+       s->aead_dec = aesgcm_aead_dec;
+       s->maclen = 16;
+       s->recivlen = 8;
+       memmove(s->mackey, iv, ea->ivlen);
+       prng(s->mackey + ea->ivlen, s->recivlen);
+       setupAESGCMstate(s->enckey, p, ea->keylen, nil, 0);
+}
+
 static void
 initclearenc(Encalg *, Secret *s, uchar *, uchar *)
 {
        s->enc = noenc;
        s->dec = noenc;
-       s->block = 0;
 }
 
 static Encalg encrypttab[] =
@@ -1454,6 +1533,10 @@ static Encalg encrypttab[] =
        { "3des_ede_cbc", 3 * 8, 8, initDES3key },
        { "aes_128_cbc", 128/8, 16, initAESkey },
        { "aes_256_cbc", 256/8, 16, initAESkey },
+       { "ccpoly64_aead", 256/8, 0, initccpolykey },
+       { "ccpoly96_aead", 256/8, 96/8, initccpolykey },
+       { "aes_128_gcm_aead", 128/8, 4, initaesgcmkey },
+       { "aes_256_gcm_aead", 256/8, 4, initaesgcmkey },
        { 0 }
 };
 
@@ -1495,8 +1578,8 @@ tlswrite(Chan *c, void *a, long n, vlong off)
                e = p + n;
                do{
                        m = e - p;
-                       if(m > MaxRecLen)
-                               m = MaxRecLen;
+                       if(m > c->iounit)
+                               m = c->iounit;
 
                        b = allocb(m);
                        if(waserror()){
@@ -1555,12 +1638,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;
+                       tr->packAAD = sslPackAAD;
                else
-                       error("unsupported version");
+                       tr->packAAD = tlsPackAAD;
                tr->verset = 1;
                tr->version = m;
        }else if(strcmp(cb->f[0], "secret") == 0){
@@ -1582,32 +1665,34 @@ tlswrite(Chan *c, void *a, long n, vlong off)
                ea = parseencalg(cb->f[2]);
 
                p = cb->f[4];
-               m = (strlen(p)*3)/2;
-               x = smalloc(m);
-               tos = nil;
-               toc = nil;
+               m = (strlen(p)*3)/2 + 1;
+               x = secalloc(m);
+               tos = secalloc(sizeof(Secret));
+               toc = secalloc(sizeof(Secret));
                if(waserror()){
+                       secfree(x);
                        freeSec(tos);
                        freeSec(toc);
-                       free(x);
                        nexterror();
                }
+
                m = dec64(x, m, p, strlen(p));
+               memset(p, 0, strlen(p));
                if(m < 2 * ha->maclen + 2 * ea->keylen + 2 * ea->ivlen)
                        error("not enough secret data provided");
 
-               tos = smalloc(sizeof(Secret));
-               toc = smalloc(sizeof(Secret));
                if(!ha->initkey || !ea->initkey)
                        error("misimplemented secret algorithm");
+
                (*ha->initkey)(ha, tr->version, tos, &x[0]);
                (*ha->initkey)(ha, tr->version, toc, &x[ha->maclen]);
                (*ea->initkey)(ea, tos, &x[2 * ha->maclen], &x[2 * ha->maclen + 2 * ea->keylen]);
                (*ea->initkey)(ea, toc, &x[2 * ha->maclen + ea->keylen], &x[2 * ha->maclen + 2 * ea->keylen + ea->ivlen]);
 
-               if(!tos->mac || !tos->enc || !tos->dec
-               || !toc->mac || !toc->enc || !toc->dec)
-                       error("missing algorithm implementations");
+               if(!tos->aead_enc || !tos->aead_dec || !toc->aead_enc || !toc->aead_dec)
+                       if(!tos->mac || !tos->enc || !tos->dec || !toc->mac || !toc->enc || !toc->dec)
+                               error("missing algorithm implementations");
+
                if(strtol(cb->f[3], nil, 0) == 0){
                        tr->in.new = tos;
                        tr->out.new = toc;
@@ -1627,7 +1712,7 @@ tlswrite(Chan *c, void *a, long n, vlong off)
                tos->encalg = ea->name;
                tos->hashalg = ha->name;
 
-               free(x);
+               secfree(x);
                poperror();
        }else if(strcmp(cb->f[0], "changecipher") == 0){
                if(cb->nf != 1)
@@ -1708,12 +1793,8 @@ tlsinit(void)
        struct Hashalg *h;
        int n;
        char *cp;
-       static int already;
 
-       if(!already){
-               fmtinstall('H', encodefmt);
-               already = 1;
-       }
+       fmtinstall('H', encodefmt);
 
        tlsdevs = smalloc(sizeof(TlsRec*) * maxtlsdevs);
        trnames = smalloc((sizeof *trnames) * maxtlsdevs);
@@ -1780,7 +1861,7 @@ buftochan(char *p)
        fd = strtoul(p, 0, 0);
        if(fd < 0)
                error(Ebadarg);
-       c = fdtochan(fd, -1, 0, 1);     /* error check and inc ref */
+       c = fdtochan(fd, ORDWR, 1, 1);  /* error check and inc ref */
        return c;
 }
 
@@ -1824,7 +1905,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;
@@ -1956,10 +2037,10 @@ tlsstate(int s)
 static void
 freeSec(Secret *s)
 {
-       if(s != nil){
-               free(s->enckey);
-               free(s);
-       }
+       if(s == nil)
+               return;
+       secfree(s->enckey);
+       secfree(s);
 }
 
 static int
@@ -2045,6 +2126,83 @@ aesdec(Secret *sec, uchar *buf, int n)
        return (*sec->unpad)(buf, n, 16);
 }
 
+static void
+ccpoly_aead_setiv(Secret *sec, uchar seq[8])
+{
+       uchar iv[ChachaIVlen];
+       Chachastate *cs;
+       int i;
+
+       cs = (Chachastate*)sec->enckey;
+       if(cs->ivwords == 2){
+               chacha_setiv(cs, seq);
+               return;
+       }
+
+       memmove(iv, sec->mackey, ChachaIVlen);
+       for(i=0; i<8; i++)
+               iv[i+(ChachaIVlen-8)] ^= seq[i];
+
+       chacha_setiv(cs, iv);
+
+       memset(iv, 0, sizeof(iv));
+}
+
+static int
+ccpoly_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len)
+{
+       USED(reciv);
+       ccpoly_aead_setiv(sec, aad);
+       ccpoly_encrypt(data, len, aad, aadlen, data+len, sec->enckey);
+       return len + sec->maclen;
+}
+
+static int
+ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len)
+{
+       USED(reciv);
+       len -= sec->maclen;
+       if(len < 0)
+               return -1;
+       ccpoly_aead_setiv(sec, aad);
+       if(ccpoly_decrypt(data, len, aad, aadlen, data+len, sec->enckey) != 0)
+               return -1;
+       return len;
+}
+
+static int
+aesgcm_aead_enc(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len)
+{
+       uchar iv[12];
+       int i;
+
+       memmove(iv, sec->mackey, 4+8);
+       for(i=0; i<8; i++) iv[4+i] ^= aad[i];
+       memmove(reciv, iv+4, 8);
+       aesgcm_setiv(sec->enckey, iv, 12);
+       memset(iv, 0, sizeof(iv));
+       aesgcm_encrypt(data, len, aad, aadlen, data+len, sec->enckey);
+       return len + sec->maclen;
+}
+
+static int
+aesgcm_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *reciv, uchar *data, int len)
+{
+       uchar iv[12];
+
+       len -= sec->maclen;
+       if(len < 0)
+               return -1;
+       memmove(iv, sec->mackey, 4);
+       memmove(iv+4, reciv, 8);
+       aesgcm_setiv(sec->enckey, iv, 12);
+       memset(iv, 0, sizeof(iv));
+       if(aesgcm_decrypt(data, len, aad, aadlen, data+len, sec->enckey) != 0)
+               return -1;
+       return len;
+}
+
+
 static DigestState*
 nomac(uchar *, ulong, uchar *, ulong, uchar *, DigestState *)
 {
@@ -2104,32 +2262,35 @@ sslmac_md5(uchar *p, ulong len, uchar *key, ulong klen, uchar *digest, DigestSta
        return sslmac_x(p, len, key, klen, digest, s, md5, MD5dlen, 48);
 }
 
-static void
-sslPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac)
+static int
+sslPackAAD(u64int seq, uchar *hdr, uchar *aad)
 {
-       DigestState *s;
-       uchar buf[11];
-
-       memmove(buf, seq, 8);
-       buf[8] = header[0];
-       buf[9] = header[3];
-       buf[10] = header[4];
+       put64(aad, seq);
+       aad[8] = hdr[0];
+       aad[9] = hdr[3];
+       aad[10] = hdr[4];
+       return 11;
+}
 
-       s = (*sec->mac)(buf, 11, mackey, sec->maclen, 0, 0);
-       (*sec->mac)(body, len, mackey, sec->maclen, mac, s);
+static int
+tlsPackAAD(u64int seq, uchar *hdr, uchar *aad)
+{
+       put64(aad, seq);
+       aad[8] = hdr[0];
+       aad[9] = hdr[1];
+       aad[10] = hdr[2];
+       aad[11] = hdr[3];
+       aad[12] = hdr[4];
+       return 13;
 }
 
 static void
-tlsPackMac(Secret *sec, uchar *mackey, uchar *seq, uchar *header, uchar *body, int len, uchar *mac)
+packMac(Secret *sec, uchar *aad, int aadlen, uchar *body, int bodylen, uchar *mac)
 {
        DigestState *s;
-       uchar buf[13];
-
-       memmove(buf, seq, 8);
-       memmove(&buf[8], header, 5);
 
-       s = (*sec->mac)(buf, 13, mackey, sec->maclen, 0, 0);
-       (*sec->mac)(body, len, mackey, sec->maclen, mac, s);
+       s = (*sec->mac)(aad, aadlen, sec->mackey, sec->maclen, nil, nil);
+       (*sec->mac)(body, bodylen, sec->mackey, sec->maclen, mac, s);
 }
 
 static void
@@ -2142,10 +2303,10 @@ put32(uchar *p, u32int x)
 }
 
 static void
-put64(uchar *p, vlong x)
+put64(uchar *p, u64int x)
 {
-       put32(p, (u32int)(x >> 32));
-       put32(p+4, (u32int)x);
+       put32(p, x >> 32);
+       put32(p+4, x);
 }
 
 static void
@@ -2163,12 +2324,6 @@ put16(uchar *p, int x)
        p[1] = x;
 }
 
-static u32int
-get32(uchar *p)
-{
-       return (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3];
-}
-
 static int
 get16(uchar *p)
 {