diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-14 19:19:08 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-09-14 19:19:08 +0200 |
commit | 56836bfdbdca9fd6a5b608d249d178a22d3337d8 (patch) | |
tree | 75b84ef6650f92a48ba70823cb1e22f27d1d39bd | |
parent | be5992955d4e417ca625b07af93a800464d4c11f (diff) |
tls: fix various tlsClient()/tlsServer() related bugs
- TLSconn structure on stack but not initialized (zeroed)
- original filedescriptor double closed in error case
- original filedescriptor leaked in success case
- leaked TLSconn.sessionID and TLSconn.cert
- clarify in pushtls(2) and pushssl(2)
-rw-r--r-- | sys/src/cmd/ip/ftpfs/proto.c | 41 | ||||
-rw-r--r-- | sys/src/cmd/ip/httpd/httpd.c | 5 | ||||
-rw-r--r-- | sys/src/cmd/ip/httpfile.c | 7 | ||||
-rw-r--r-- | sys/src/cmd/tlsclient.c | 8 | ||||
-rw-r--r-- | sys/src/cmd/tlssrv.c | 2 | ||||
-rw-r--r-- | sys/src/cmd/upas/fs/pop3.c | 10 | ||||
-rw-r--r-- | sys/src/cmd/upas/pop3/pop3.c | 14 | ||||
-rw-r--r-- | sys/src/cmd/upas/smtp/smtp.c | 58 | ||||
-rw-r--r-- | sys/src/cmd/upas/smtp/smtpd.c | 27 | ||||
-rw-r--r-- | sys/src/cmd/vnc/vncs.c | 9 | ||||
-rw-r--r-- | sys/src/cmd/vnc/vncv.c | 9 | ||||
-rw-r--r-- | sys/src/cmd/webfs/http.c | 16 | ||||
-rw-r--r-- | sys/src/libsec/port/tlshand.c | 50 |
13 files changed, 127 insertions, 129 deletions
diff --git a/sys/src/cmd/ip/ftpfs/proto.c b/sys/src/cmd/ip/ftpfs/proto.c index cc8a1d5a5..0231dd7c9 100644 --- a/sys/src/cmd/ip/ftpfs/proto.c +++ b/sys/src/cmd/ip/ftpfs/proto.c @@ -55,6 +55,18 @@ static Node* vmsdir(char*); static int getpassword(char*, char*); static int nw_mode(char dirlet, char *s); +static void +starttls(int *fd) +{ + TLSconn conn; + + memset(&conn, 0, sizeof(conn)); + if((*fd = tlsClient(*fd, &conn)) < 0) + fatal("starting tls: %r"); + free(conn.cert); + free(conn.sessionID); +} + /* * connect to remote server, default network is "tcp/ip" */ @@ -63,7 +75,6 @@ hello(char *dest) { char *p; char dir[Maxpath]; - TLSconn conn; Binit(&stdin, 0, OREAD); /* init for later use */ @@ -93,11 +104,8 @@ hello(char *dest) if(getreply(&ctlin, msg, sizeof(msg), 1) != Success) fatal("bad auth tls"); - ctlfd = tlsClient(ctlfd, &conn); - if(ctlfd < 0) - fatal("starting tls: %r"); - free(conn.cert); - + starttls(&ctlfd); + Binit(&ctlin, ctlfd, OREAD); sendrequest("PBSZ", "0"); @@ -1227,7 +1235,6 @@ active(int mode, Biobuf **bpp, char *cmda, char *cmdb) int cfd, dfd, rv; char newdir[Maxpath]; char datafile[Maxpath + 6]; - TLSconn conn; if(port() < 0) return TempFail; @@ -1253,13 +1260,8 @@ active(int mode, Biobuf **bpp, char *cmda, char *cmdb) if(dfd < 0) fatal("opening data connection"); - if(usetls){ - memset(&conn, 0, sizeof(conn)); - dfd = tlsClient(dfd, &conn); - if(dfd < 0) - fatal("starting tls: %r"); - free(conn.cert); - } + if(usetls) + starttls(&dfd); Binit(&dbuf, dfd, mode); *bpp = &dbuf; @@ -1277,7 +1279,6 @@ passive(int mode, Biobuf **bpp, char *cmda, char *cmdb) char *f[6]; char *p; int x, fd; - TLSconn conn; if(nopassive) return Impossible; @@ -1327,13 +1328,9 @@ passive(int mode, Biobuf **bpp, char *cmda, char *cmdb) return x; } - if(usetls){ - memset(&conn, 0, sizeof(conn)); - fd = tlsClient(fd, &conn); - if(fd < 0) - fatal("starting tls: %r"); - free(conn.cert); - } + if(usetls) + starttls(&fd); + Binit(&dbuf, fd, mode); *bpp = &dbuf; diff --git a/sys/src/cmd/ip/httpd/httpd.c b/sys/src/cmd/ip/httpd/httpd.c index 895bd15e2..657ae5487 100644 --- a/sys/src/cmd/ip/httpd/httpd.c +++ b/sys/src/cmd/ip/httpd/httpd.c @@ -172,7 +172,6 @@ dolisten(char *address) NetConnInfo *nci; char ndir[NETPATHLEN], dir[NETPATHLEN], *p, *scheme; int ctl, nctl, data, t, ok, spotchk; - TLSconn conn; spotchk = 0; syslog(0, HTTPLOG, "httpd starting"); @@ -217,12 +216,16 @@ dolisten(char *address) */ data = accept(ctl, ndir); if(data >= 0 && certificate != nil){ + TLSconn conn; + memset(&conn, 0, sizeof(conn)); conn.cert = certificate; conn.certlen = certlen; if (certchain != nil) conn.chain = certchain; data = tlsServer(data, &conn); + free(conn.cert); + free(conn.sessionID); scheme = "https"; }else scheme = "http"; diff --git a/sys/src/cmd/ip/httpfile.c b/sys/src/cmd/ip/httpfile.c index 8b4c725a6..b28cd63eb 100644 --- a/sys/src/cmd/ip/httpfile.c +++ b/sys/src/cmd/ip/httpfile.c @@ -186,12 +186,11 @@ dotls(int fd) { TLSconn conn; + memset(&conn, 0, sizeof(conn)); if((fd=tlsClient(fd, &conn)) < 0) sysfatal("tlsclient: %r"); - - if(conn.cert != nil) - free(conn.cert); - + free(conn.cert); + free(conn.sessionID); return fd; } diff --git a/sys/src/cmd/tlsclient.c b/sys/src/cmd/tlsclient.c index f4f1a25d8..d96e733b4 100644 --- a/sys/src/cmd/tlsclient.c +++ b/sys/src/cmd/tlsclient.c @@ -38,7 +38,7 @@ reporter(char *fmt, ...) void main(int argc, char **argv) { - int fd, netfd, debug; + int fd, debug; uchar digest[20]; TLSconn *conn; char *addr, *file, *filex, *ccert; @@ -78,7 +78,7 @@ main(int argc, char **argv) } addr = argv[0]; - if((netfd = dial(addr, 0, 0, 0)) < 0) + if((fd = dial(addr, 0, 0, 0)) < 0) sysfatal("dial %s: %r", addr); conn = (TLSconn*)mallocz(sizeof *conn, 1); @@ -86,7 +86,7 @@ main(int argc, char **argv) conn->cert = readcert(ccert, &conn->certlen); if(debug) conn->trace = reporter; - fd = tlsClient(netfd, conn); + fd = tlsClient(fd, conn); if(fd < 0) sysfatal("tlsclient: %r"); if(thumb){ @@ -98,8 +98,6 @@ main(int argc, char **argv) sysfatal("server certificate %.*H not recognized", SHA1dlen, digest); } } - free(conn->cert); - close(netfd); rfork(RFNOTEG); switch(fork()){ diff --git a/sys/src/cmd/tlssrv.c b/sys/src/cmd/tlssrv.c index ef27f26d9..245191f56 100644 --- a/sys/src/cmd/tlssrv.c +++ b/sys/src/cmd/tlssrv.c @@ -147,7 +147,7 @@ main(int argc, char *argv[]) if(conn == nil) sysfatal("out of memory"); conn->chain = readcertchain(cert); - if (conn->chain == nil) + if(conn->chain == nil) sysfatal("can't read certificate"); conn->cert = conn->chain->pem; conn->certlen = conn->chain->pemlen; diff --git a/sys/src/cmd/upas/fs/pop3.c b/sys/src/cmd/upas/fs/pop3.c index fbb6f6c5e..257fc8970 100644 --- a/sys/src/cmd/upas/fs/pop3.c +++ b/sys/src/cmd/upas/fs/pop3.c @@ -129,6 +129,9 @@ pop3pushtls(Pop *pop) err = "tls error"; goto out; } + pop->fd = fd; + Binit(&pop->bin, pop->fd, OREAD); + Binit(&pop->bout, pop->fd, OWRITE); if(conn.cert==nil || conn.certlen <= 0){ err = "server did not provide TLS certificate"; goto out; @@ -140,17 +143,10 @@ pop3pushtls(Pop *pop) err = "bad server certificate"; goto out; } - close(pop->fd); - pop->fd = fd; pop->encrypted = 1; - Binit(&pop->bin, pop->fd, OREAD); - Binit(&pop->bout, pop->fd, OWRITE); - fd = -1; out: free(conn.sessionID); free(conn.cert); - if(fd >= 0) - close(fd); return err; } diff --git a/sys/src/cmd/upas/pop3/pop3.c b/sys/src/cmd/upas/pop3/pop3.c index 61b418062..1416f03ca 100644 --- a/sys/src/cmd/upas/pop3/pop3.c +++ b/sys/src/cmd/upas/pop3/pop3.c @@ -551,27 +551,31 @@ trace(char *fmt, ...) static int stlscmd(char*) { - int fd; TLSconn conn; + int fd; if(didtls) return senderr("tls already started"); if(!tlscert) return senderr("don't have any tls credentials"); - sendok(""); - Bflush(&out); - memset(&conn, 0, sizeof conn); - conn.cert = tlscert; conn.certlen = ntlscert; + conn.cert = malloc(ntlscert); + if(conn.cert == nil) + return senderr("out of memory"); + memmove(conn.cert, tlscert, ntlscert); if(debug) conn.trace = trace; + sendok(""); + Bflush(&out); fd = tlsServer(0, &conn); if(fd < 0) sysfatal("tlsServer: %r"); dup(fd, 0); dup(fd, 1); close(fd); + free(conn.cert); + free(conn.sessionID); Binit(&in, 0, OREAD); Binit(&out, 1, OWRITE); didtls = 1; diff --git a/sys/src/cmd/upas/smtp/smtp.c b/sys/src/cmd/upas/smtp/smtp.c index 895c84914..41395899a 100644 --- a/sys/src/cmd/upas/smtp/smtp.c +++ b/sys/src/cmd/upas/smtp/smtp.c @@ -324,59 +324,53 @@ wraptls(void) { TLSconn *c; Thumbprint *goodcerts; - char *h; + char *h, *err; int fd; uchar hash[SHA1dlen]; + err = Giveup; c = mallocz(sizeof(*c), 1); if (c == nil) - return Giveup; + return err; fd = tlsClient(Bfildes(&bout), c); if (fd < 0) { syslog(0, "smtp", "tlsClient to %q: %r", ddomain); - free(c); - return Giveup; + goto Out; } + Bterm(&bout); + Binit(&bout, fd, OWRITE); + fd = dup(fd, Bfildes(&bin)); + Bterm(&bin); + Binit(&bin, fd, OREAD); + goodcerts = initThumbprints(smtpthumbs, smtpexclthumbs); if (goodcerts == nil) { syslog(0, "smtp", "bad thumbprints in %s", smtpthumbs); - close(fd); - free(c); - return Giveup; /* how to recover? TLS is started */ + goto Out; } /* compute sha1 hash of remote's certificate, see if we know it */ sha1(c->cert, c->certlen, hash, nil); if (!okThumbprint(hash, goodcerts)) { /* TODO? if not excluded, add hash to thumb list */ h = malloc(2*sizeof hash + 1); - if (h != nil) { - enc16(h, 2*sizeof hash + 1, hash, sizeof hash); - // fprint(2, "x509 sha1=%s", h); - syslog(0, "smtp", - "remote cert. has bad thumbprint: x509 sha1=%s server=%q", - h, ddomain); - free(h); - } - close(fd); - free(c); - return Giveup; /* how to recover? TLS is started */ + if (h == nil) + goto Out; + enc16(h, 2*sizeof hash + 1, hash, sizeof hash); + syslog(0, "smtp", "remote cert. has bad thumbprint: x509 sha1=%s server=%q", + h, ddomain); + free(h); + goto Out; } - freeThumbprints(goodcerts); - free(c); - Bterm(&bin); - Bterm(&bout); - - /* - * set up bin & bout to use the TLS fd, i/o upon which generates - * i/o on the original, underlying fd. - */ - Binit(&bin, fd, OREAD); - fd = dup(fd, -1); - Binit(&bout, fd, OWRITE); - syslog(0, "smtp", "started TLS to %q", ddomain); - return nil; + err = nil; +Out: + if(goodcerts != nil) + freeThumbprints(goodcerts); + free(c->cert); + free(c->sessionID); + free(c); + return err; } /* diff --git a/sys/src/cmd/upas/smtp/smtpd.c b/sys/src/cmd/upas/smtp/smtpd.c index 8d9ebcb56..caa66dc06 100644 --- a/sys/src/cmd/upas/smtp/smtpd.c +++ b/sys/src/cmd/upas/smtp/smtpd.c @@ -1551,38 +1551,33 @@ starttls(void) { int certlen, fd; uchar *cert; - TLSconn *conn; + TLSconn conn; if (tlscert == nil) { reply("500 5.5.1 illegal command or bad syntax\r\n"); return; } - conn = mallocz(sizeof *conn, 1); cert = readcert(tlscert, &certlen); - if (conn == nil || cert == nil) { - if (conn != nil) - free(conn); + if (cert == nil) { reply("454 4.7.5 TLS not available\r\n"); return; } reply("220 2.0.0 Go ahead make my day\r\n"); - conn->cert = cert; - conn->certlen = certlen; - fd = tlsServer(Bfildes(&bin), conn); + memset(&conn, 0, sizeof(conn)); + conn.cert = cert; + conn.certlen = certlen; + fd = tlsServer(Bfildes(&bin), &conn); if (fd < 0) { - free(cert); - free(conn); syslog(0, "smtpd", "TLS start-up failed with %s", him); - - /* force the client to hang up */ - close(Bfildes(&bin)); /* probably fd 0 */ - close(1); exits("tls failed"); } Bterm(&bin); - Binit(&bin, fd, OREAD); - if (dup(fd, 1) < 0) + if (dup(fd, 0) < 0 || dup(fd, 1) < 0) fprint(2, "dup of %d failed: %r\n", fd); + close(fd); + Binit(&bin, 0, OREAD); + free(conn.cert); + free(conn.sessionID); passwordinclear = 1; syslog(0, "smtpd", "started TLS with %s", him); } diff --git a/sys/src/cmd/vnc/vncs.c b/sys/src/cmd/vnc/vncs.c index ee36d0c7b..f191db7e2 100644 --- a/sys/src/cmd/vnc/vncs.c +++ b/sys/src/cmd/vnc/vncs.c @@ -152,7 +152,7 @@ main(int argc, char **argv) exits(nil); } - if(altnet && !cert) + if(altnet && cert == nil) sysfatal("announcing on alternate network requires TLS (-c)"); if(argc == 0) @@ -524,7 +524,6 @@ vncaccept(Vncs *v) { char buf[32]; int fd; - TLSconn conn; /* caller returns to listen */ switch(rfork(RFPROC|RFMEM|RFNAMEG)){ @@ -546,6 +545,8 @@ vncaccept(Vncs *v) } if(cert != nil){ + TLSconn conn; + memset(&conn, 0, sizeof conn); conn.cert = readcert(cert, &conn.certlen); if(conn.cert == nil){ @@ -556,11 +557,9 @@ vncaccept(Vncs *v) if(fd < 0){ fprint(2, "%V: tlsServer: %r; hanging up\n", v); free(conn.cert); - if(conn.sessionID) - free(conn.sessionID); + free(conn.sessionID); exits(nil); } - close(v->datafd); v->datafd = fd; free(conn.cert); free(conn.sessionID); diff --git a/sys/src/cmd/vnc/vncv.c b/sys/src/cmd/vnc/vncv.c index 8d44813c9..49203b04b 100644 --- a/sys/src/cmd/vnc/vncv.c +++ b/sys/src/cmd/vnc/vncv.c @@ -84,7 +84,6 @@ main(int argc, char **argv) int p, dfd, cfd, shared; char *keypattern, *addr, *label; Point d; - TLSconn conn; keypattern = nil; shared = 0; @@ -123,10 +122,14 @@ main(int argc, char **argv) if(dfd < 0) sysfatal("cannot dial %s: %r", addr); if(tls){ - dfd = tlsClient(dfd, &conn); - if(dfd < 0) + TLSconn conn; + + memset(&conn, 0, sizeof(conn)); + if((dfd = tlsClient(dfd, &conn)) < 0) sysfatal("tlsClient: %r"); /* XXX check thumbprint */ + free(conn.cert); + free(conn.sessionID); } vnc = vncinit(dfd, cfd, nil); diff --git a/sys/src/cmd/webfs/http.c b/sys/src/cmd/webfs/http.c index 03029bb6a..e659bd725 100644 --- a/sys/src/cmd/webfs/http.c +++ b/sys/src/cmd/webfs/http.c @@ -65,7 +65,7 @@ hdial(Url *u) { char addr[128]; Hconn *h, *p; - int fd, ctl, ofd; + int fd, ofd, ctl; snprint(addr, sizeof(addr), "tcp!%s!%s", u->host, u->port ? u->port : u->scheme); @@ -90,18 +90,16 @@ hdial(Url *u) return nil; if(strcmp(u->scheme, "https") == 0){ char err[ERRMAX]; - TLSconn *tc; + TLSconn conn; - tc = emalloc(sizeof(*tc)); strcpy(err, "tls error"); - if((fd = tlsClient(ofd = fd, tc)) < 0) + memset(&conn, 0, sizeof(conn)); + if((fd = tlsClient(ofd = fd, &conn)) < 0) errstr(err, sizeof(err)); - close(ofd); - /* BUG: should validate but how? */ - free(tc->cert); - free(tc->sessionID); - free(tc); + free(conn.cert); + free(conn.sessionID); if(fd < 0){ + close(ofd); close(ctl); if(debug) fprint(2, "tlsClient: %s\n", err); errstr(err, sizeof(err)); diff --git a/sys/src/libsec/port/tlshand.c b/sys/src/libsec/port/tlshand.c index c9dd093db..2ad92e37a 100644 --- a/sys/src/libsec/port/tlshand.c +++ b/sys/src/libsec/port/tlshand.c @@ -335,8 +335,8 @@ tlsServer(int fd, TLSconn *conn) return -1; } buf[n] = 0; - sprint(conn->dir, "#a/tls/%s", buf); - sprint(dname, "#a/tls/%s/hand", buf); + snprint(conn->dir, sizeof(conn->dir), "#a/tls/%s", buf); + snprint(dname, sizeof(dname), "#a/tls/%s/hand", buf); hand = open(dname, ORDWR); if(hand < 0){ close(ctl); @@ -344,27 +344,32 @@ tlsServer(int fd, TLSconn *conn) } fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion); tls = tlsServer2(ctl, hand, conn->cert, conn->certlen, conn->trace, conn->chain); - sprint(dname, "#a/tls/%s/data", buf); + snprint(dname, sizeof(dname), "#a/tls/%s/data", buf); data = open(dname, ORDWR); - close(fd); close(hand); close(ctl); - if(data < 0) - return -1; - if(tls == nil){ - close(data); + if(data < 0 || tls == nil){ + if(tls != nil) + tlsConnectionFree(tls); return -1; } - if(conn->cert) - free(conn->cert); + free(conn->cert); conn->cert = 0; // client certificates are not yet implemented conn->certlen = 0; conn->sessionIDlen = tls->sid->len; conn->sessionID = emalloc(conn->sessionIDlen); memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen); - if(conn->sessionKey != nil && conn->sessionType != nil && strcmp(conn->sessionType, "ttls") == 0) - tls->sec->prf(conn->sessionKey, conn->sessionKeylen, tls->sec->sec, MasterSecretSize, conn->sessionConst, tls->sec->crandom, RandomSize, tls->sec->srandom, RandomSize); + if(conn->sessionKey != nil + && conn->sessionType != nil + && strcmp(conn->sessionType, "ttls") == 0) + tls->sec->prf( + conn->sessionKey, conn->sessionKeylen, + tls->sec->sec, MasterSecretSize, + conn->sessionConst, + tls->sec->crandom, RandomSize, + tls->sec->srandom, RandomSize); tlsConnectionFree(tls); + close(fd); return data; } @@ -378,7 +383,7 @@ tlsClient(int fd, TLSconn *conn) int n, data, ctl, hand; TlsConnection *tls; - if(!conn) + if(conn == nil) return -1; ctl = open("#a/tls/clone", ORDWR); if(ctl < 0) @@ -389,14 +394,14 @@ tlsClient(int fd, TLSconn *conn) return -1; } buf[n] = 0; - sprint(conn->dir, "#a/tls/%s", buf); - sprint(dname, "#a/tls/%s/hand", buf); + snprint(conn->dir, sizeof(conn->dir), "#a/tls/%s", buf); + snprint(dname, sizeof(dname), "#a/tls/%s/hand", buf); hand = open(dname, ORDWR); if(hand < 0){ close(ctl); return -1; } - sprint(dname, "#a/tls/%s/data", buf); + snprint(dname, sizeof(dname), "#a/tls/%s/data", buf); data = open(dname, ORDWR); if(data < 0){ close(hand); @@ -407,7 +412,6 @@ tlsClient(int fd, TLSconn *conn) tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->cert, conn->certlen, conn->trace); close(hand); close(ctl); - close(fd); if(tls == nil){ close(data); return -1; @@ -418,9 +422,17 @@ tlsClient(int fd, TLSconn *conn) conn->sessionIDlen = tls->sid->len; conn->sessionID = emalloc(conn->sessionIDlen); memcpy(conn->sessionID, tls->sid->data, conn->sessionIDlen); - if(conn->sessionKey != nil && conn->sessionType != nil && strcmp(conn->sessionType, "ttls") == 0) - tls->sec->prf(conn->sessionKey, conn->sessionKeylen, tls->sec->sec, MasterSecretSize, conn->sessionConst, tls->sec->crandom, RandomSize, tls->sec->srandom, RandomSize); + if(conn->sessionKey != nil + && conn->sessionType != nil + && strcmp(conn->sessionType, "ttls") == 0) + tls->sec->prf( + conn->sessionKey, conn->sessionKeylen, + tls->sec->sec, MasterSecretSize, + conn->sessionConst, + tls->sec->crandom, RandomSize, + tls->sec->srandom, RandomSize); tlsConnectionFree(tls); + close(fd); return data; } |