ref: 39f18c9d88f52a22373790dec5721fa3521d3f00
parent: 4a6ab355c1af789f7ddb4edbf4d82d17efd9d2bf
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Dec 25 12:05:05 EST 2015
libsec: implement TLS-PSK for tlsClient()/tlsServer()
--- a/sys/include/libsec.h
+++ b/sys/include/libsec.h
@@ -412,8 +412,10 @@
char dir[40]; /* connection directory */
uchar *cert; /* certificate (local on input, remote on output) */
uchar *sessionID;
+ uchar *psk;
int certlen;
int sessionIDlen;
+ int psklen;
int (*trace)(char*fmt, ...);
PEMChain*chain; /* optional extra certificate evidence for servers to present */
char *sessionType;
@@ -421,6 +423,7 @@
int sessionKeylen;
char *sessionConst;
char *serverName;
+ char *pskID;
} TLSconn;
/* tlshand.c */
--- a/sys/man/2/pushtls
+++ b/sys/man/2/pushtls
@@ -100,7 +100,8 @@
char dir[40]; /* OUT connection directory */
uchar *cert; /* IN/OUT certificate */
uchar *sessionID; /* IN/OUT session ID */
- int certlen, sessionIDlen;
+ uchar *psk; /* opt IN pre-shared key */
+ int certlen, sessionIDlen, psklen;
int (*trace)(char*fmt, ...);
PEMChain *chain;
char *sessionType; /* opt IN session type */
@@ -108,6 +109,7 @@
int sessionKeylen; /* opt IN session key length */
char *sessionConst; /* opt IN session constant */
char *serverName; /* opt IN server name */
+ char *pskID; /* opt IN pre-shared key ID */
} TLSconn;
.EE
.PP
--- a/sys/src/libsec/port/tlshand.c
+++ b/sys/src/libsec/port/tlshand.c
@@ -135,9 +135,11 @@
Bytes **cas;
} certificateRequest;
struct {
+ Bytes *pskid;
Bytes *key;
} clientKeyExchange;
struct {
+ Bytes *pskid;
Bytes *dh_p;
Bytes *dh_g;
Bytes *dh_Ys;
@@ -159,6 +161,8 @@
int ok; // <0 killed; == 0 in progress; >0 reusable
RSApub *rsapub;
AuthRpc *rpc; // factotum for rsa private key
+ uchar *psk; // pre-shared key
+ int psklen;
uchar sec[MasterSecretSize]; // master secret
uchar crandom[RandomSize]; // client random
uchar srandom[RandomSize]; // server random
@@ -223,6 +227,7 @@
EInternalError = 80,
EUserCanceled = 90,
ENoRenegotiation = 100,
+ EUnknownPSKidentity = 115,
EMax = 256
};
@@ -274,6 +279,16 @@
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0XC013,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0XC014,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027,
+
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = 0xCCA8,
+ TLS_DHE_RSA_WITH_CHACHA20_POLY1305 = 0xCCAA,
+
+ GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305 = 0xCC13,
+ GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305 = 0xCC15,
+
+ TLS_PSK_WITH_CHACHA20_POLY1305 = 0xCCAB,
+ TLS_PSK_WITH_AES_128_CBC_SHA256 = 0x00AE,
+ TLS_PSK_WITH_AES_128_CBC_SHA = 0x008C,
};
// compression methods
@@ -283,10 +298,12 @@
};
static Algs cipherAlgs[] = {
- {"ccpoly96_aead", "clear", 2*(32+12), 0xCCA8}, // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (IETF)
- {"ccpoly96_aead", "clear", 2*(32+12), 0xCCAA}, // TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (IETF)
- {"ccpoly64_aead", "clear", 2*32, 0xCC13}, // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (draft)
- {"ccpoly64_aead", "clear", 2*32, 0xCC15}, // TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (draft)
+ {"ccpoly96_aead", "clear", 2*(32+12), TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305},
+ {"ccpoly96_aead", "clear", 2*(32+12), TLS_DHE_RSA_WITH_CHACHA20_POLY1305},
+
+ {"ccpoly64_aead", "clear", 2*32, GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305},
+ {"ccpoly64_aead", "clear", 2*32, GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305},
+
{"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
{"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
{"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
@@ -299,6 +316,11 @@
{"aes_256_cbc", "sha1", 2*(32+16+SHA1dlen), TLS_RSA_WITH_AES_256_CBC_SHA},
{"3des_ede_cbc","sha1", 2*(4*8+SHA1dlen), TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
{"3des_ede_cbc","sha1", 2*(4*8+SHA1dlen), TLS_RSA_WITH_3DES_EDE_CBC_SHA},
+
+ // PSK cipher suits
+ {"ccpoly96_aead", "clear", 2*(32+12), TLS_PSK_WITH_CHACHA20_POLY1305},
+ {"aes_128_cbc", "sha256", 2*(16+16+SHA2_256dlen), TLS_PSK_WITH_AES_128_CBC_SHA256},
+ {"aes_128_cbc", "sha1", 2*(16+16+SHA1dlen), TLS_PSK_WITH_AES_128_CBC_SHA},
};
static uchar compressors[] = {
@@ -327,8 +349,15 @@
0x0201, /* SHA1 RSA */
};
-static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int certlen, int (*trace)(char*fmt, ...), PEMChain *chain);
-static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, uchar *ext, int extlen, int (*trace)(char*fmt, ...));
+static TlsConnection *tlsServer2(int ctl, int hand,
+ uchar *cert, int certlen,
+ char *pskid, uchar *psk, int psklen,
+ int (*trace)(char*fmt, ...), PEMChain *chain);
+static TlsConnection *tlsClient2(int ctl, int hand,
+ uchar *csid, int ncsid,
+ uchar *cert, int certlen,
+ char *pskid, uchar *psk, int psklen,
+ uchar *ext, int extlen, int (*trace)(char*fmt, ...));
static void msgClear(Msg *m);
static char* msgPrint(char *buf, int n, Msg *m);
static int msgRecv(TlsConnection *c, Msg *m);
@@ -340,15 +369,17 @@
static void tlsConnectionFree(TlsConnection *c);
static int setAlgs(TlsConnection *c, int a);
-static int okCipher(Ints *cv);
+static int okCipher(Ints *cv, int ispsk);
static int okCompression(Bytes *cv);
static int initCiphers(void);
-static Ints* makeciphers(void);
+static Ints* makeciphers(int ispsk);
static TlsSec* tlsSecInits(int cvers, uchar *csid, int ncsid, uchar *crandom, uchar *ssid, int *nssid, uchar *srandom);
static int tlsSecRSAs(TlsSec *sec, int vers, Bytes *epm);
+static int tlsSecPSKs(TlsSec *sec, int vers);
static TlsSec* tlsSecInitc(int cvers, uchar *crandom);
static Bytes* tlsSecRSAc(TlsSec *sec, uchar *sid, int nsid, uchar *srandom, uchar *cert, int ncert, int vers);
+static int tlsSecPSKc(TlsSec *sec, uchar *srandom, int vers);
static Bytes* tlsSecDHEc(TlsSec *sec, uchar *srandom, int vers, Bytes *p, Bytes *g, Bytes *Ys);
static Bytes* tlsSecECDHEc(TlsSec *sec, uchar *srandom, int vers, int curve, Bytes *Ys);
static int tlsSecFinished(TlsSec *sec, HandshakeHash hsh, uchar *fin, int nfin, int isclient);
@@ -424,7 +455,10 @@
return -1;
}
fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
- tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace, conn->chain);
+ tls = tlsServer2(ctl, hand,
+ conn->cert, conn->certlen,
+ conn->pskID, conn->psk, conn->psklen,
+ conn->trace, conn->chain);
snprint(dname, sizeof(dname), "#a/tls/%s/data", buf);
data = open(dname, ORDWR);
close(hand);
@@ -435,7 +469,7 @@
return -1;
}
free(conn->cert);
- conn->cert = 0; // client certificates are not yet implemented
+ conn->cert = nil; // client certificates are not yet implemented
conn->certlen = 0;
conn->sessionIDlen = tls->sid->len;
conn->sessionID = emalloc(conn->sessionIDlen);
@@ -561,7 +595,10 @@
}
fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion);
ext = tlsClientExtensions(conn, &n);
- tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->cert, conn->certlen,
+ tls = tlsClient2(ctl, hand,
+ conn->sessionID, conn->sessionIDlen,
+ conn->cert, conn->certlen,
+ conn->pskID, conn->psk, conn->psklen,
ext, n, conn->trace);
free(ext);
close(hand);
@@ -570,9 +607,14 @@
close(data);
return -1;
}
- conn->certlen = tls->cert->len;
- conn->cert = emalloc(conn->certlen);
- memcpy(conn->cert, tls->cert->data, conn->certlen);
+ if(tls->cert != nil){
+ conn->certlen = tls->cert->len;
+ conn->cert = emalloc(conn->certlen);
+ memcpy(conn->cert, tls->cert->data, conn->certlen);
+ } else {
+ conn->certlen = 0;
+ conn->cert = nil;
+ }
conn->sessionIDlen = tls->sid->len;
conn->sessionID = emalloc(conn->sessionIDlen);
memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen);
@@ -603,7 +645,10 @@
}
static TlsConnection *
-tlsServer2(int ctl, int hand, uchar *cert, int certlen, int (*trace)(char*fmt, ...), PEMChain *chp)
+tlsServer2(int ctl, int hand,
+ uchar *cert, int certlen,
+ char *pskid, uchar *psk, int psklen,
+ int (*trace)(char*fmt, ...), PEMChain *chp)
{
TlsConnection *c;
Msg m;
@@ -641,7 +686,7 @@
}
memmove(c->crandom, m.u.clientHello.random, RandomSize);
- cipher = okCipher(m.u.clientHello.ciphers);
+ cipher = okCipher(m.u.clientHello.ciphers, psklen > 0);
if(cipher < 0) {
// reply with EInsufficientSecurity if we know that's the case
if(cipher == -2)
@@ -662,21 +707,27 @@
csid = m.u.clientHello.sid;
if(trace)
- trace(" cipher %d, compressor %d, csidlen %d\n", cipher, compressor, csid->len);
+ trace(" cipher %x, compressor %x, csidlen %d\n", cipher, compressor, csid->len);
c->sec = tlsSecInits(c->clientVersion, csid->data, csid->len, c->crandom, sid, &nsid, c->srandom);
if(c->sec == nil){
tlsError(c, EHandshakeFailure, "can't initialize security: %r");
goto Err;
}
- c->sec->rpc = factotum_rsa_open(cert, certlen);
- if(c->sec->rpc == nil){
- tlsError(c, EHandshakeFailure, "factotum_rsa_open: %r");
- goto Err;
+ if(psklen > 0){
+ c->sec->psk = psk;
+ c->sec->psklen = psklen;
}
- c->sec->rsapub = X509toRSApub(cert, certlen, nil, 0);
- if(c->sec->rsapub == nil){
- tlsError(c, EHandshakeFailure, "invalid X509/rsa certificate");
- goto Err;
+ if(certlen > 0){
+ c->sec->rpc = factotum_rsa_open(cert, certlen);
+ if(c->sec->rpc == nil){
+ tlsError(c, EHandshakeFailure, "factotum_rsa_open: %r");
+ goto Err;
+ }
+ c->sec->rsapub = X509toRSApub(cert, certlen, nil, 0);
+ if(c->sec->rsapub == nil){
+ tlsError(c, EHandshakeFailure, "invalid X509/rsa certificate");
+ goto Err;
+ }
}
msgClear(&m);
@@ -691,16 +742,18 @@
goto Err;
msgClear(&m);
- m.tag = HCertificate;
- numcerts = countchain(chp);
- m.u.certificate.ncert = 1 + numcerts;
- m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes*));
- m.u.certificate.certs[0] = makebytes(cert, certlen);
- for (i = 0; i < numcerts && chp; i++, chp = chp->next)
- m.u.certificate.certs[i+1] = makebytes(chp->pem, chp->pemlen);
- if(!msgSend(c, &m, AQueue))
- goto Err;
- msgClear(&m);
+ if(certlen > 0){
+ m.tag = HCertificate;
+ numcerts = countchain(chp);
+ m.u.certificate.ncert = 1 + numcerts;
+ m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes*));
+ m.u.certificate.certs[0] = makebytes(cert, certlen);
+ for (i = 0; i < numcerts && chp; i++, chp = chp->next)
+ m.u.certificate.certs[i+1] = makebytes(chp->pem, chp->pemlen);
+ if(!msgSend(c, &m, AQueue))
+ goto Err;
+ msgClear(&m);
+ }
m.tag = HServerHelloDone;
if(!msgSend(c, &m, AFlush))
@@ -713,10 +766,29 @@
tlsError(c, EUnexpectedMessage, "expected a client key exchange");
goto Err;
}
- if(tlsSecRSAs(c->sec, c->version, m.u.clientKeyExchange.key) < 0){
- tlsError(c, EHandshakeFailure, "couldn't set secrets: %r");
+ if(pskid != nil){
+ if(m.u.clientKeyExchange.pskid == nil
+ || m.u.clientKeyExchange.pskid->len != strlen(pskid)
+ || memcmp(pskid, m.u.clientKeyExchange.pskid->data, m.u.clientKeyExchange.pskid->len) != 0){
+ tlsError(c, EUnknownPSKidentity, "unknown or missing pskid");
+ goto Err;
+ }
+ }
+ if(certlen > 0){
+ if(tlsSecRSAs(c->sec, c->version, m.u.clientKeyExchange.key) < 0){
+ tlsError(c, EHandshakeFailure, "couldn't set secrets: %r");
+ goto Err;
+ }
+ } else if(psklen > 0){
+ if(tlsSecPSKs(c->sec, c->version) < 0){
+ tlsError(c, EHandshakeFailure, "couldn't set secrets: %r");
+ goto Err;
+ }
+ } else {
+ tlsError(c, EInternalError, "no psk or certificate");
goto Err;
}
+
setSecrets(c->sec, kd, c->nsecret);
if(trace)
trace("tls secrets\n");
@@ -786,7 +858,8 @@
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
- case 0xCCAA: case 0xCC15: // TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ case TLS_DHE_RSA_WITH_CHACHA20_POLY1305:
+ case GOOGLE_DHE_RSA_WITH_CHACHA20_POLY1305:
return 1;
}
return 0;
@@ -799,12 +872,25 @@
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
- case 0xCCA8: case 0xCC13: // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305:
+ case GOOGLE_ECDHE_RSA_WITH_CHACHA20_POLY1305:
return 1;
}
return 0;
}
+static int
+isPSK(int tlsid)
+{
+ switch(tlsid){
+ case TLS_PSK_WITH_CHACHA20_POLY1305:
+ case TLS_PSK_WITH_AES_128_CBC_SHA256:
+ case TLS_PSK_WITH_AES_128_CBC_SHA:
+ return 1;
+ }
+ return 0;
+}
+
static Bytes*
tlsSecDHEc(TlsSec *sec, uchar *srandom, int vers,
Bytes *p, Bytes *g, Bytes *Ys)
@@ -980,9 +1066,19 @@
RSApub *pk;
char *err;
- if(sig == nil || sig->len <= 0)
+ if(par == nil || par->len <= 0)
+ return "no dh parameters";
+
+ if(sig == nil || sig->len <= 0){
+ if(c->sec->psklen > 0)
+ return nil;
+
return "no signature";
+ }
+ if(c->cert == nil)
+ return "no certificate";
+
pk = X509toRSApub(c->cert->data, c->cert->len, nil, 0);
if(pk == nil)
return "bad certificate";
@@ -1015,7 +1111,11 @@
}
static TlsConnection *
-tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, uchar *ext, int extlen,
+tlsClient2(int ctl, int hand,
+ uchar *csid, int ncsid,
+ uchar *cert, int certlen,
+ char *pskid, uchar *psk, int psklen,
+ uchar *ext, int extlen,
int (*trace)(char*fmt, ...))
{
TlsConnection *c;
@@ -1036,10 +1136,17 @@
c->trace = trace;
c->isClient = 1;
c->clientVersion = c->version;
+ c->cert = nil;
c->sec = tlsSecInitc(c->clientVersion, c->crandom);
if(c->sec == nil)
goto Err;
+
+ if(psklen > 0){
+ c->sec->psk = psk;
+ c->sec->psklen = psklen;
+ }
+
/* client hello */
memset(&m, 0, sizeof(m));
m.tag = HClientHello;
@@ -1046,7 +1153,7 @@
m.u.clientHello.version = c->clientVersion;
memmove(m.u.clientHello.random, c->crandom, RandomSize);
m.u.clientHello.sid = makebytes(csid, ncsid);
- m.u.clientHello.ciphers = makeciphers();
+ m.u.clientHello.ciphers = makeciphers(psklen > 0);
m.u.clientHello.compressors = makebytes(compressors,sizeof(compressors));
m.u.clientHello.extensions = makebytes(ext, extlen);
if(!msgSend(c, &m, AFlush))
@@ -1071,7 +1178,7 @@
goto Err;
}
cipher = m.u.serverHello.cipher;
- if(!setAlgs(c, cipher)) {
+ if((psklen > 0) != isPSK(cipher) || !setAlgs(c, cipher)) {
tlsError(c, EIllegalParameter, "invalid cipher suite");
goto Err;
}
@@ -1081,48 +1188,47 @@
}
msgClear(&m);
- /* certificate */
- if(!msgRecv(c, &m) || m.tag != HCertificate) {
- tlsError(c, EUnexpectedMessage, "expected a certificate");
- goto Err;
- }
- if(m.u.certificate.ncert < 1) {
- tlsError(c, EIllegalParameter, "runt certificate");
- goto Err;
- }
- c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len);
- msgClear(&m);
-
- /* server key exchange */
dhx = isDHE(cipher) || isECDHE(cipher);
if(!msgRecv(c, &m))
goto Err;
+ if(m.tag == HCertificate){
+ if(m.u.certificate.ncert < 1) {
+ tlsError(c, EIllegalParameter, "runt certificate");
+ goto Err;
+ }
+ c->cert = makebytes(m.u.certificate.certs[0]->data, m.u.certificate.certs[0]->len);
+ msgClear(&m);
+ if(!msgRecv(c, &m))
+ goto Err;
+ } else if(psklen == 0) {
+ tlsError(c, EUnexpectedMessage, "expected a certificate");
+ goto Err;
+ }
if(m.tag == HServerKeyExchange) {
- char *err;
-
- if(!dhx){
+ if(dhx){
+ char *err = verifyDHparams(c,
+ m.u.serverKeyExchange.dh_parameters,
+ m.u.serverKeyExchange.dh_signature,
+ m.u.serverKeyExchange.sigalg);
+ if(err != nil){
+ tlsError(c, EBadCertificate, "can't verify dh parameters: %s", err);
+ goto Err;
+ }
+ if(isECDHE(cipher))
+ epm = tlsSecECDHEc(c->sec, c->srandom, c->version,
+ m.u.serverKeyExchange.curve,
+ m.u.serverKeyExchange.dh_Ys);
+ else
+ epm = tlsSecDHEc(c->sec, c->srandom, c->version,
+ m.u.serverKeyExchange.dh_p,
+ m.u.serverKeyExchange.dh_g,
+ m.u.serverKeyExchange.dh_Ys);
+ if(epm == nil)
+ goto Badcert;
+ } else if(psklen == 0){
tlsError(c, EUnexpectedMessage, "got an server key exchange");
goto Err;
}
- err = verifyDHparams(c,
- m.u.serverKeyExchange.dh_parameters,
- m.u.serverKeyExchange.dh_signature,
- m.u.serverKeyExchange.sigalg);
- if(err != nil){
- tlsError(c, EBadCertificate, "can't verify dh parameters: %s", err);
- goto Err;
- }
- if(isECDHE(cipher))
- epm = tlsSecECDHEc(c->sec, c->srandom, c->version,
- m.u.serverKeyExchange.curve,
- m.u.serverKeyExchange.dh_Ys);
- else
- epm = tlsSecDHEc(c->sec, c->srandom, c->version,
- m.u.serverKeyExchange.dh_p,
- m.u.serverKeyExchange.dh_g,
- m.u.serverKeyExchange.dh_Ys);
- if(epm == nil)
- goto Badcert;
msgClear(&m);
if(!msgRecv(c, &m))
goto Err;
@@ -1146,14 +1252,22 @@
}
msgClear(&m);
- if(!dhx)
- epm = tlsSecRSAc(c->sec, c->sid->data, c->sid->len, c->srandom,
- c->cert->data, c->cert->len, c->version);
-
- if(epm == nil){
- Badcert:
- tlsError(c, EBadCertificate, "bad certificate: %r");
- goto Err;
+ if(!dhx){
+ if(c->cert != nil){
+ epm = tlsSecRSAc(c->sec, c->sid->data, c->sid->len, c->srandom,
+ c->cert->data, c->cert->len, c->version);
+ if(epm == nil){
+ Badcert:
+ tlsError(c, EBadCertificate, "bad certificate: %r");
+ goto Err;
+ }
+ } else if(psklen > 0) {
+ if(tlsSecPSKc(c->sec, c->srandom, c->version) < 0)
+ goto Badcert;
+ } else {
+ tlsError(c, EInternalError, "no psk or certificate");
+ goto Err;
+ }
}
setSecrets(c->sec, kd, c->nsecret);
@@ -1182,12 +1296,13 @@
/* client key exchange */
m.tag = HClientKeyExchange;
+ if(psklen > 0){
+ if(pskid == nil)
+ pskid = "";
+ m.u.clientKeyExchange.pskid = makebytes((uchar*)pskid, strlen(pskid));
+ }
m.u.clientKeyExchange.key = epm;
epm = nil;
- if(m.u.clientKeyExchange.key == nil) {
- tlsError(c, EHandshakeFailure, "can't set secret: %r");
- goto Err;
- }
if(!msgSend(c, &m, AFlush))
goto Err;
@@ -1423,8 +1538,17 @@
p += 2;
memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len);
p += m->u.certificateVerify.signature->len;
- break;
+ break;
case HClientKeyExchange:
+ if(m->u.clientKeyExchange.pskid != nil){
+ n = m->u.clientKeyExchange.pskid->len;
+ put16(p, n);
+ p += 2;
+ memmove(p, m->u.clientKeyExchange.pskid->data, n);
+ p += n;
+ }
+ if(m->u.clientKeyExchange.key == nil)
+ break;
n = m->u.clientKeyExchange.key->len;
if(c->version != SSL3Version){
if(isECDHE(c->cipher))
@@ -1737,6 +1861,18 @@
case HServerHelloDone:
break;
case HServerKeyExchange:
+ if(isPSK(c->cipher)){
+ if(n < 2)
+ goto Short;
+ nn = get16(p);
+ p += 2, n -= 2;
+ if(nn > n)
+ goto Short;
+ m->u.serverKeyExchange.pskid = makebytes(p, nn);
+ p += nn, n -= nn;
+ if(n == 0)
+ break;
+ }
if(n < 2)
goto Short;
s = p;
@@ -1805,6 +1941,18 @@
* this message depends upon the encryption selected
* assume rsa.
*/
+ if(isPSK(c->cipher)){
+ if(n < 2)
+ goto Short;
+ nn = get16(p);
+ p += 2, n -= 2;
+ if(nn > n)
+ goto Short;
+ m->u.clientKeyExchange.pskid = makebytes(p, nn);
+ p += nn, n -= nn;
+ if(n == 0)
+ break;
+ }
if(c->version == SSL3Version)
nn = n;
else{
@@ -1883,6 +2031,7 @@
case HServerHelloDone:
break;
case HServerKeyExchange:
+ freebytes(m->u.serverKeyExchange.pskid);
freebytes(m->u.serverKeyExchange.dh_p);
freebytes(m->u.serverKeyExchange.dh_g);
freebytes(m->u.serverKeyExchange.dh_Ys);
@@ -1890,6 +2039,7 @@
freebytes(m->u.serverKeyExchange.dh_signature);
break;
case HClientKeyExchange:
+ freebytes(m->u.clientKeyExchange.pskid);
freebytes(m->u.clientKeyExchange.key);
break;
case HFinished:
@@ -1998,6 +2148,10 @@
break;
case HServerKeyExchange:
bs = seprint(bs, be, "HServerKeyExchange\n");
+ if(m->u.serverKeyExchange.pskid != nil)
+ bs = bytesPrint(bs, be, "\tpskid: ", m->u.serverKeyExchange.pskid, "\n");
+ if(m->u.serverKeyExchange.dh_parameters == nil)
+ break;
if(m->u.serverKeyExchange.curve != 0){
bs = seprint(bs, be, "\tcurve: %.4x\n", m->u.serverKeyExchange.curve);
} else {
@@ -2012,7 +2166,10 @@
break;
case HClientKeyExchange:
bs = seprint(bs, be, "HClientKeyExchange\n");
- bs = bytesPrint(bs, be, "\tkey: ", m->u.clientKeyExchange.key, "\n");
+ if(m->u.clientKeyExchange.pskid != nil)
+ bs = bytesPrint(bs, be, "\tpskid: ", m->u.clientKeyExchange.pskid, "\n");
+ if(m->u.clientKeyExchange.key != nil)
+ bs = bytesPrint(bs, be, "\tkey: ", m->u.clientKeyExchange.key, "\n");
break;
case HFinished:
bs = seprint(bs, be, "HFinished\n");
@@ -2137,7 +2294,7 @@
}
static int
-okCipher(Ints *cv)
+okCipher(Ints *cv, int ispsk)
{
int weak, i, j, c;
@@ -2148,6 +2305,8 @@
weak = 0;
else
weak &= weakCipher[c];
+ if(isPSK(c) != ispsk)
+ continue;
if(isDHE(c) || isECDHE(c))
continue; /* TODO: not implemented for server */
for(j = 0; j < nelem(cipherAlgs); j++)
@@ -2243,7 +2402,7 @@
}
static Ints*
-makeciphers(void)
+makeciphers(int ispsk)
{
Ints *is;
int i, j;
@@ -2250,10 +2409,10 @@
is = newints(nciphers);
j = 0;
- for(i = 0; i < nelem(cipherAlgs); i++){
- if(cipherAlgs[i].ok)
+ for(i = 0; i < nelem(cipherAlgs); i++)
+ if(cipherAlgs[i].ok && isPSK(cipherAlgs[i].tlsid) == ispsk)
is->data[j++] = cipherAlgs[i].tlsid;
- }
+ is->len = j;
return is;
}
@@ -2489,6 +2648,17 @@
return -1;
}
+static int
+tlsSecPSKs(TlsSec *sec, int vers)
+{
+ if(setVers(sec, vers) < 0){
+ sec->ok = -1;
+ return -1;
+ }
+ setMasterSecret(sec, newbytes(sec->psklen));
+ return 0;
+}
+
static TlsSec*
tlsSecInitc(int cvers, uchar *crandom)
{
@@ -2500,6 +2670,18 @@
return sec;
}
+static int
+tlsSecPSKc(TlsSec *sec, uchar *srandom, int vers)
+{
+ memmove(sec->srandom, srandom, RandomSize);
+ if(setVers(sec, vers) < 0){
+ sec->ok = -1;
+ return -1;
+ }
+ setMasterSecret(sec, newbytes(sec->psklen));
+ return 0;
+}
+
static Bytes*
tlsSecRSAc(TlsSec *sec, uchar *sid, int nsid, uchar *srandom, uchar *cert, int ncert, int vers)
{
@@ -2608,6 +2790,22 @@
static void
setMasterSecret(TlsSec *sec, Bytes *pm)
{
+ if(sec->psklen > 0){
+ Bytes *opm = pm;
+ uchar *p;
+
+ /* concatenate psk to pre-master secret */
+ pm = newbytes(4 + opm->len + sec->psklen);
+ p = pm->data;
+ put16(p, opm->len), p += 2;
+ memmove(p, opm->data, opm->len), p += opm->len;
+ put16(p, sec->psklen), p += 2;
+ memmove(p, sec->psk, sec->psklen);
+
+ memset(opm->data, 0, opm->len);
+ freebytes(opm);
+ }
+
(*sec->prf)(sec->sec, MasterSecretSize, pm->data, pm->len, "master secret",
sec->crandom, RandomSize, sec->srandom, RandomSize);