/*
- * 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"
{
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];
};
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);
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);
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) {
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);
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);
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;
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 {
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);
return n;
}
-static void
-randfill(uchar *buf, int len)
-{
- while(len-- > 0)
- *buf++ = nrand(256);
-}
-
/*
* write a block in tls records
*/
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){
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);
}
static void
initclearmac(Hashalg *, int, Secret *s, uchar *)
{
- s->maclen = 0;
s->mac = nomac;
}
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;
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;
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 */
}
}
+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[] =
{ "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 }
};
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;
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)
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);
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;
}
static void
freeSec(Secret *s)
{
- if(s != nil){
- free(s->enckey);
- free(s);
- }
+ if(s == nil)
+ return;
+ secfree(s->enckey);
+ secfree(s);
}
static int
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;
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 *)
{
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)
{