]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/port/devtls.c
kernel: use 64-bit virtual entry point for expanded header, document behaviour in...
[plan9front.git] / sys / src / 9 / port / devtls.c
index 93bd8225ef8d11ae7425825cb292f5734442c60e..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"
@@ -83,16 +83,18 @@ 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*);
-
-       int             (*aead_enc)(Secret*, uchar*, int, uchar*, int);
-       int             (*aead_dec)(Secret*, uchar*, int, uchar*, int);
+       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];
 };
@@ -235,7 +237,6 @@ 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);
@@ -246,8 +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 *data, int len);
-static int     ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *data, int len);
+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);
@@ -420,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) {
@@ -467,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);
@@ -530,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);
@@ -821,14 +807,16 @@ if(tr->debug) pprint("decrypted %d\n", unpad_len);
 if(tr->debug) pdump(unpad_len, p, "decrypted:");
                }
 
+               ivlen = sec->recivlen;
                if(tr->version >= TLS11Version){
-                       ivlen = sec->block;
-                       len -= ivlen;
-                       if(len < 0)
-                               rcvError(tr, EDecodeError, "runt record message");
-                       unpad_len -= ivlen;
-                       p += ivlen;
+                       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;
@@ -837,7 +825,7 @@ if(tr->debug) pdump(unpad_len, p, "decrypted:");
                put16(header+3, len);
                aadlen = (*tr->packAAD)(in->seq++, header, aad);
                if(sec->aead_dec != nil) {
-                       len = (*sec->aead_dec)(sec, aad, aadlen, p, unpad_len);
+                       len = (*sec->aead_dec)(sec, aad, aadlen, p - ivlen, p, unpad_len);
                        if(len < 0)
                                rcvError(tr, EBadRecordMac, "record mac mismatch");
                } else {
@@ -1191,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);
@@ -1243,13 +1233,6 @@ 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
  */
@@ -1299,8 +1282,11 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
                if(sec != nil){
                        maclen = sec->maclen;
                        pad = maclen + sec->block;
-                       if(tr->version >= TLS11Version)
-                               ivlen = sec->block;
+                       ivlen = sec->recivlen;
+                       if(tr->version >= TLS11Version){
+                               if(ivlen == 0)
+                                       ivlen = sec->block;
+                       }
                }
                n = BLEN(bb);
                if(n > MaxRecLen){
@@ -1326,12 +1312,12 @@ if(tr->debug)pdump(BLEN(b), b->rp, "sent:");
                put16(p+3, n);
 
                if(sec != nil){
-                       if(ivlen > 0)
-                               randfill(p + RecHdrLen, ivlen);
                        aadlen = (*tr->packAAD)(out->seq++, p, aad);
                        if(sec->aead_enc != nil)
-                               n = (*sec->aead_enc)(sec, aad, aadlen, p + RecHdrLen + ivlen, n) + ivlen;
+                               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);
                        }
@@ -1420,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;
 }
 
@@ -1478,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;
@@ -1498,7 +1482,7 @@ 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;
@@ -1508,13 +1492,9 @@ initAESkey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
 static void
 initccpolykey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
 {
-       s->enckey = smalloc(sizeof(Chachastate));
-       s->enc = noenc;
-       s->dec = noenc;
-       s->mac = nomac;
+       s->enckey = secalloc(sizeof(Chachastate));
        s->aead_enc = ccpoly_aead_enc;
        s->aead_dec = ccpoly_aead_dec;
-       s->block = 0;
        s->maclen = Poly1305dlen;
        if(ea->ivlen == 0) {
                /* older draft version, iv is 64-bit sequence number */
@@ -1526,12 +1506,24 @@ initccpolykey(Encalg *ea, Secret *s, uchar *p, uchar *iv)
        }
 }
 
+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[] =
@@ -1543,6 +1535,8 @@ static Encalg encrypttab[] =
        { "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 }
 };
 
@@ -1671,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;
@@ -1716,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)
@@ -1797,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);
@@ -1869,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;
 }
 
@@ -2045,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
@@ -2152,19 +2144,23 @@ ccpoly_aead_setiv(Secret *sec, uchar seq[8])
                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 *data, int len)
+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 *data, int len)
+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;
@@ -2174,6 +2170,39 @@ ccpoly_aead_dec(Secret *sec, uchar *aad, int aadlen, uchar *data, int len)
        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 *)
 {
@@ -2295,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)
 {