19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <mp.h>
49a747e4fSDavid du Colombier #include <libsec.h>
59a747e4fSDavid du Colombier #include "SConn.h"
69a747e4fSDavid du Colombier
79a747e4fSDavid du Colombier extern int verbose;
89a747e4fSDavid du Colombier
99a747e4fSDavid du Colombier typedef struct ConnState {
109a747e4fSDavid du Colombier uchar secret[SHA1dlen];
119a747e4fSDavid du Colombier ulong seqno;
129a747e4fSDavid du Colombier RC4state rc4;
139a747e4fSDavid du Colombier } ConnState;
149a747e4fSDavid du Colombier
159a747e4fSDavid du Colombier typedef struct SS{
169a747e4fSDavid du Colombier int fd; // file descriptor for read/write of encrypted data
179a747e4fSDavid du Colombier int alg; // if nonzero, "alg sha rc4_128"
189a747e4fSDavid du Colombier ConnState in, out;
199a747e4fSDavid du Colombier } SS;
209a747e4fSDavid du Colombier
219a747e4fSDavid du Colombier static int
SC_secret(SConn * conn,uchar * sigma,int direction)229a747e4fSDavid du Colombier SC_secret(SConn *conn, uchar *sigma, int direction)
239a747e4fSDavid du Colombier {
249a747e4fSDavid du Colombier SS *ss = (SS*)(conn->chan);
259a747e4fSDavid du Colombier int nsigma = conn->secretlen;
269a747e4fSDavid du Colombier
279a747e4fSDavid du Colombier if(direction != 0){
289a747e4fSDavid du Colombier hmac_sha1(sigma, nsigma, (uchar*)"one", 3, ss->out.secret, nil);
299a747e4fSDavid du Colombier hmac_sha1(sigma, nsigma, (uchar*)"two", 3, ss->in.secret, nil);
309a747e4fSDavid du Colombier }else{
319a747e4fSDavid du Colombier hmac_sha1(sigma, nsigma, (uchar*)"two", 3, ss->out.secret, nil);
329a747e4fSDavid du Colombier hmac_sha1(sigma, nsigma, (uchar*)"one", 3, ss->in.secret, nil);
339a747e4fSDavid du Colombier }
349a747e4fSDavid du Colombier setupRC4state(&ss->in.rc4, ss->in.secret, 16); // restrict to 128 bits
359a747e4fSDavid du Colombier setupRC4state(&ss->out.rc4, ss->out.secret, 16);
369a747e4fSDavid du Colombier ss->alg = 1;
379a747e4fSDavid du Colombier return 0;
389a747e4fSDavid du Colombier }
399a747e4fSDavid du Colombier
409a747e4fSDavid du Colombier static void
hash(uchar secret[SHA1dlen],uchar * data,int len,int seqno,uchar d[SHA1dlen])419a747e4fSDavid du Colombier hash(uchar secret[SHA1dlen], uchar *data, int len, int seqno, uchar d[SHA1dlen])
429a747e4fSDavid du Colombier {
439a747e4fSDavid du Colombier DigestState sha;
449a747e4fSDavid du Colombier uchar seq[4];
459a747e4fSDavid du Colombier
469a747e4fSDavid du Colombier seq[0] = seqno>>24;
479a747e4fSDavid du Colombier seq[1] = seqno>>16;
489a747e4fSDavid du Colombier seq[2] = seqno>>8;
499a747e4fSDavid du Colombier seq[3] = seqno;
509a747e4fSDavid du Colombier memset(&sha, 0, sizeof sha);
519a747e4fSDavid du Colombier sha1(secret, SHA1dlen, nil, &sha);
529a747e4fSDavid du Colombier sha1(data, len, nil, &sha);
539a747e4fSDavid du Colombier sha1(seq, 4, d, &sha);
549a747e4fSDavid du Colombier }
559a747e4fSDavid du Colombier
569a747e4fSDavid du Colombier static int
verify(uchar secret[SHA1dlen],uchar * data,int len,int seqno,uchar d[SHA1dlen])579a747e4fSDavid du Colombier verify(uchar secret[SHA1dlen], uchar *data, int len, int seqno, uchar d[SHA1dlen])
589a747e4fSDavid du Colombier {
599a747e4fSDavid du Colombier DigestState sha;
609a747e4fSDavid du Colombier uchar seq[4];
619a747e4fSDavid du Colombier uchar digest[SHA1dlen];
629a747e4fSDavid du Colombier
639a747e4fSDavid du Colombier seq[0] = seqno>>24;
649a747e4fSDavid du Colombier seq[1] = seqno>>16;
659a747e4fSDavid du Colombier seq[2] = seqno>>8;
669a747e4fSDavid du Colombier seq[3] = seqno;
679a747e4fSDavid du Colombier memset(&sha, 0, sizeof sha);
689a747e4fSDavid du Colombier sha1(secret, SHA1dlen, nil, &sha);
699a747e4fSDavid du Colombier sha1(data, len, nil, &sha);
709a747e4fSDavid du Colombier sha1(seq, 4, digest, &sha);
719a747e4fSDavid du Colombier return memcmp(d, digest, SHA1dlen);
729a747e4fSDavid du Colombier }
739a747e4fSDavid du Colombier
749a747e4fSDavid du Colombier static int
SC_read(SConn * conn,uchar * buf,int n)759a747e4fSDavid du Colombier SC_read(SConn *conn, uchar *buf, int n)
769a747e4fSDavid du Colombier {
779a747e4fSDavid du Colombier SS *ss = (SS*)(conn->chan);
789a747e4fSDavid du Colombier uchar count[2], digest[SHA1dlen];
799a747e4fSDavid du Colombier int len, nr;
809a747e4fSDavid du Colombier
81369036d9SDavid du Colombier if(read(ss->fd, count, 2) != 2 || (count[0]&0x80) == 0){
829a747e4fSDavid du Colombier snprint((char*)buf,n,"!SC_read invalid count");
839a747e4fSDavid du Colombier return -1;
849a747e4fSDavid du Colombier }
859a747e4fSDavid du Colombier len = (count[0]&0x7f)<<8 | count[1]; // SSL-style count; no pad
869a747e4fSDavid du Colombier if(ss->alg){
879a747e4fSDavid du Colombier len -= SHA1dlen;
889a747e4fSDavid du Colombier if(len <= 0 || readn(ss->fd, digest, SHA1dlen) != SHA1dlen){
899a747e4fSDavid du Colombier snprint((char*)buf,n,"!SC_read missing sha1");
909a747e4fSDavid du Colombier return -1;
919a747e4fSDavid du Colombier }
929a747e4fSDavid du Colombier if(len > n || readn(ss->fd, buf, len) != len){
939a747e4fSDavid du Colombier snprint((char*)buf,n,"!SC_read missing data");
949a747e4fSDavid du Colombier return -1;
959a747e4fSDavid du Colombier }
969a747e4fSDavid du Colombier rc4(&ss->in.rc4, digest, SHA1dlen);
979a747e4fSDavid du Colombier rc4(&ss->in.rc4, buf, len);
989a747e4fSDavid du Colombier if(verify(ss->in.secret, buf, len, ss->in.seqno, digest) != 0){
999a747e4fSDavid du Colombier snprint((char*)buf,n,"!SC_read integrity check failed");
1009a747e4fSDavid du Colombier return -1;
1019a747e4fSDavid du Colombier }
1029a747e4fSDavid du Colombier }else{
1039a747e4fSDavid du Colombier if(len <= 0 || len > n){
1049a747e4fSDavid du Colombier snprint((char*)buf,n,"!SC_read implausible record length");
1059a747e4fSDavid du Colombier return -1;
1069a747e4fSDavid du Colombier }
1079a747e4fSDavid du Colombier if( (nr = readn(ss->fd, buf, len)) != len){
1089a747e4fSDavid du Colombier snprint((char*)buf,n,"!SC_read expected %d bytes, but got %d", len, nr);
1099a747e4fSDavid du Colombier return -1;
1109a747e4fSDavid du Colombier }
1119a747e4fSDavid du Colombier }
1129a747e4fSDavid du Colombier ss->in.seqno++;
1139a747e4fSDavid du Colombier return len;
1149a747e4fSDavid du Colombier }
1159a747e4fSDavid du Colombier
1169a747e4fSDavid du Colombier static int
SC_write(SConn * conn,uchar * buf,int n)1179a747e4fSDavid du Colombier SC_write(SConn *conn, uchar *buf, int n)
1189a747e4fSDavid du Colombier {
1199a747e4fSDavid du Colombier SS *ss = (SS*)(conn->chan);
1204708ce63SDavid du Colombier uchar count[2], digest[SHA1dlen], enc[Maxmsg+1];
1219a747e4fSDavid du Colombier int len;
1229a747e4fSDavid du Colombier
1239a747e4fSDavid du Colombier if(n <= 0 || n > Maxmsg+1){
1249a747e4fSDavid du Colombier werrstr("!SC_write invalid n %d", n);
1259a747e4fSDavid du Colombier return -1;
1269a747e4fSDavid du Colombier }
1279a747e4fSDavid du Colombier len = n;
1289a747e4fSDavid du Colombier if(ss->alg)
1299a747e4fSDavid du Colombier len += SHA1dlen;
1309a747e4fSDavid du Colombier count[0] = 0x80 | len>>8;
1319a747e4fSDavid du Colombier count[1] = len;
1329a747e4fSDavid du Colombier if(write(ss->fd, count, 2) != 2){
1339a747e4fSDavid du Colombier werrstr("!SC_write invalid count");
1349a747e4fSDavid du Colombier return -1;
1359a747e4fSDavid du Colombier }
1369a747e4fSDavid du Colombier if(ss->alg){
1379a747e4fSDavid du Colombier hash(ss->out.secret, buf, n, ss->out.seqno, digest);
1389a747e4fSDavid du Colombier rc4(&ss->out.rc4, digest, SHA1dlen);
1394708ce63SDavid du Colombier memcpy(enc, buf, n);
1404708ce63SDavid du Colombier rc4(&ss->out.rc4, enc, n);
1419a747e4fSDavid du Colombier if(write(ss->fd, digest, SHA1dlen) != SHA1dlen ||
1424708ce63SDavid du Colombier write(ss->fd, enc, n) != n){
1439a747e4fSDavid du Colombier werrstr("!SC_write error on send");
1449a747e4fSDavid du Colombier return -1;
1459a747e4fSDavid du Colombier }
1469a747e4fSDavid du Colombier }else{
1479a747e4fSDavid du Colombier if(write(ss->fd, buf, n) != n){
1489a747e4fSDavid du Colombier werrstr("!SC_write error on send");
1499a747e4fSDavid du Colombier return -1;
1509a747e4fSDavid du Colombier }
1519a747e4fSDavid du Colombier }
1529a747e4fSDavid du Colombier ss->out.seqno++;
1539a747e4fSDavid du Colombier return n;
1549a747e4fSDavid du Colombier }
1559a747e4fSDavid du Colombier
1569a747e4fSDavid du Colombier static void
SC_free(SConn * conn)1579a747e4fSDavid du Colombier SC_free(SConn *conn)
1589a747e4fSDavid du Colombier {
1599a747e4fSDavid du Colombier SS *ss = (SS*)(conn->chan);
1609a747e4fSDavid du Colombier
1619a747e4fSDavid du Colombier close(ss->fd);
1629a747e4fSDavid du Colombier free(ss);
1639a747e4fSDavid du Colombier free(conn);
1649a747e4fSDavid du Colombier }
1659a747e4fSDavid du Colombier
1669a747e4fSDavid du Colombier SConn*
newSConn(int fd)1679a747e4fSDavid du Colombier newSConn(int fd)
1689a747e4fSDavid du Colombier {
1699a747e4fSDavid du Colombier SS *ss;
1709a747e4fSDavid du Colombier SConn *conn;
1719a747e4fSDavid du Colombier
1729a747e4fSDavid du Colombier if(fd < 0)
1739a747e4fSDavid du Colombier return nil;
1749a747e4fSDavid du Colombier ss = (SS*)emalloc(sizeof(*ss));
1759a747e4fSDavid du Colombier conn = (SConn*)emalloc(sizeof(*conn));
1769a747e4fSDavid du Colombier ss->fd = fd;
1779a747e4fSDavid du Colombier ss->alg = 0;
1789a747e4fSDavid du Colombier conn->chan = (void*)ss;
1799a747e4fSDavid du Colombier conn->secretlen = SHA1dlen;
1809a747e4fSDavid du Colombier conn->free = SC_free;
1819a747e4fSDavid du Colombier conn->secret = SC_secret;
1829a747e4fSDavid du Colombier conn->read = SC_read;
1839a747e4fSDavid du Colombier conn->write = SC_write;
1849a747e4fSDavid du Colombier return conn;
1859a747e4fSDavid du Colombier }
1869a747e4fSDavid du Colombier
1879a747e4fSDavid du Colombier void
writerr(SConn * conn,char * s)1889a747e4fSDavid du Colombier writerr(SConn *conn, char *s)
1899a747e4fSDavid du Colombier {
1909a747e4fSDavid du Colombier char buf[Maxmsg];
1919a747e4fSDavid du Colombier
1929a747e4fSDavid du Colombier snprint(buf, Maxmsg, "!%s", s);
1939a747e4fSDavid du Colombier conn->write(conn, (uchar*)buf, strlen(buf));
1949a747e4fSDavid du Colombier }
1959a747e4fSDavid du Colombier
1969a747e4fSDavid du Colombier int
readstr(SConn * conn,char * s)1979a747e4fSDavid du Colombier readstr(SConn *conn, char *s)
1989a747e4fSDavid du Colombier {
1999a747e4fSDavid du Colombier int n;
2009a747e4fSDavid du Colombier
2019a747e4fSDavid du Colombier n = conn->read(conn, (uchar*)s, Maxmsg);
2029a747e4fSDavid du Colombier if(n >= 0){
2039a747e4fSDavid du Colombier s[n] = 0;
2049a747e4fSDavid du Colombier if(s[0] == '!'){
2059a747e4fSDavid du Colombier memmove(s, s+1, n);
2069a747e4fSDavid du Colombier n = -1;
2079a747e4fSDavid du Colombier }
2089a747e4fSDavid du Colombier }else{
209*6dbcb8a8SDavid du Colombier strcpy(s, "connection read error");
2109a747e4fSDavid du Colombier }
2119a747e4fSDavid du Colombier return n;
2129a747e4fSDavid du Colombier }
213