diff options
| -rw-r--r-- | sys/man/8/tlssrv | 15 | ||||
| -rw-r--r-- | sys/src/cmd/tlsclient.c | 44 | ||||
| -rw-r--r-- | sys/src/libsec/port/tlshand.c | 81 | ||||
| -rw-r--r-- | sys/src/libsec/port/x509.c | 14 |
4 files changed, 134 insertions, 20 deletions
diff --git a/sys/man/8/tlssrv b/sys/man/8/tlssrv index bbc74d3c8..e813f150c 100644 --- a/sys/man/8/tlssrv +++ b/sys/man/8/tlssrv @@ -24,6 +24,13 @@ logfile .PP .B tlsclient [ +.B -D +] +[ +.B -c +.I cert.pem +] +[ .B -t .I trustedkeys ] @@ -69,6 +76,14 @@ starts TLS, and then relays between the network connection and standard input and output. +The +.B -D +flag enables some debug output. +Specifying a certificate in pem(8) format with the +.B -c +flag, causes the client to submit this certificate upon +server's request. A corresponding key has to be present in +.IR factotum(4). If the .B -t flag diff --git a/sys/src/cmd/tlsclient.c b/sys/src/cmd/tlsclient.c index 8bfff5d0f..f4f1a25d8 100644 --- a/sys/src/cmd/tlsclient.c +++ b/sys/src/cmd/tlsclient.c @@ -6,7 +6,7 @@ void usage(void) { - fprint(2, "usage: tlsclient [-t /sys/lib/tls/xxx] [-x /sys/lib/tls/xxx.exclude] dialstring\n"); + fprint(2, "usage: tlsclient [-c lib/tls/clientcert] [-t /sys/lib/tls/xxx] [-x /sys/lib/tls/xxx.exclude] dialstring\n"); exits("usage"); } @@ -21,18 +21,34 @@ xfer(int from, int to) break; } +static int +reporter(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprint(2, "%s: tls reports ", argv0); + vfprint(2, fmt, ap); + fprint(2, "\n"); + + va_end(ap); + return 0; +} + void main(int argc, char **argv) { - int fd, netfd; + int fd, netfd, debug; uchar digest[20]; - TLSconn conn; - char *addr, *file, *filex; + TLSconn *conn; + char *addr, *file, *filex, *ccert; Thumbprint *thumb; file = nil; filex = nil; thumb = nil; + ccert=nil; + debug=0; ARGBEGIN{ case 't': file = EARGF(usage()); @@ -40,6 +56,12 @@ main(int argc, char **argv) case 'x': filex = EARGF(usage()); break; + case 'D': + debug++; + break; + case 'c': + ccert = EARGF(usage()); + break; default: usage(); }ARGEND @@ -59,20 +81,24 @@ main(int argc, char **argv) if((netfd = dial(addr, 0, 0, 0)) < 0) sysfatal("dial %s: %r", addr); - memset(&conn, 0, sizeof conn); - fd = tlsClient(netfd, &conn); + conn = (TLSconn*)mallocz(sizeof *conn, 1); + if(ccert) + conn->cert = readcert(ccert, &conn->certlen); + if(debug) + conn->trace = reporter; + fd = tlsClient(netfd, conn); if(fd < 0) sysfatal("tlsclient: %r"); if(thumb){ - if(conn.cert==nil || conn.certlen<=0) + if(conn->cert==nil || conn->certlen<=0) sysfatal("server did not provide TLS certificate"); - sha1(conn.cert, conn.certlen, digest, nil); + sha1(conn->cert, conn->certlen, digest, nil); if(!okThumbprint(digest, thumb)){ fmtinstall('H', encodefmt); sysfatal("server certificate %.*H not recognized", SHA1dlen, digest); } } - free(conn.cert); + free(conn->cert); close(netfd); rfork(RFNOTEG); diff --git a/sys/src/libsec/port/tlshand.c b/sys/src/libsec/port/tlshand.c index 5ebd3d4e5..16a82ef65 100644 --- a/sys/src/libsec/port/tlshand.c +++ b/sys/src/libsec/port/tlshand.c @@ -112,6 +112,9 @@ typedef struct Msg{ struct { Bytes *key; } clientKeyExchange; + struct { + Bytes *signature; + } certificateVerify; Finished finished; } u; } Msg; @@ -249,8 +252,7 @@ static uchar compressors[] = { }; static TlsConnection *tlsServer2(int ctl, int hand, uchar *cert, int ncert, int (*trace)(char*fmt, ...), PEMChain *chain); -static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...)); - +static TlsConnection *tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, 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); @@ -301,11 +303,15 @@ static int get24(uchar *p); static int get16(uchar *p); static Bytes* newbytes(int len); static Bytes* makebytes(uchar* buf, int len); +static Bytes* mptobytes(mpint* big); static void freebytes(Bytes* b); static Ints* newints(int len); static Ints* makeints(int* buf, int len); static void freeints(Ints* b); +/* x509.c */ +extern mpint* pkcs1padbuf(uchar *buf, int len, mpint *modulus); + //================= client/server ======================== // push TLS onto fd, returning new (application) file descriptor @@ -398,7 +404,7 @@ tlsClient(int fd, TLSconn *conn) return -1; } fprint(ctl, "fd %d 0x%x", fd, ProtocolVersion); - tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->trace); + tls = tlsClient2(ctl, hand, conn->sessionID, conn->sessionIDlen, conn->cert, conn->certlen, conn->trace); close(hand); close(ctl); close(fd); @@ -602,13 +608,14 @@ Err: } static TlsConnection * -tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ...)) +tlsClient2(int ctl, int hand, uchar *csid, int ncsid, uchar *cert, int certlen, int (*trace)(char*fmt, ...)) { TlsConnection *c; Msg m; uchar kd[MaxKeyData], *epm; char *secrets; int creq, nepm, rv; + mpint *signedMP, *paddedHashes; if(!initCiphers()) return nil; @@ -719,7 +726,9 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ... } if(creq) { - /* send a zero length certificate */ + m.u.certificate.ncert = 1; + m.u.certificate.certs = emalloc(m.u.certificate.ncert * sizeof(Bytes)); + m.u.certificate.certs[0] = makebytes(cert, certlen); m.tag = HCertificate; if(!msgSend(c, &m, AFlush)) goto Err; @@ -735,10 +744,55 @@ tlsClient2(int ctl, int hand, uchar *csid, int ncsid, int (*trace)(char*fmt, ... tlsError(c, EHandshakeFailure, "can't set secret: %r"); goto Err; } + if(!msgSend(c, &m, AFlush)) goto Err; msgClear(&m); + /* CertificateVerify */ + /*XXX I should only send this when it is not DH right? + Also we need to know which TLS key + we have to use in case there are more than one*/ + if(cert) { + m.tag = HCertificateVerify; + uchar hshashes[MD5dlen+SHA1dlen]; /* content of signature */ + MD5state hsmd5_save; + SHAstate hssha1_save; + + /* save the state for the Finish message */ + + hsmd5_save = c->hsmd5; + hssha1_save = c->hssha1; + md5(nil, 0, hshashes, &c->hsmd5); + sha1(nil, 0, hshashes+MD5dlen, &c->hssha1); + + c->hsmd5 = hsmd5_save; + c->hssha1 = hssha1_save; + + 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); + + paddedHashes = pkcs1padbuf(hshashes, 36, c->sec->rsapub->n); + signedMP = factotum_rsa_decrypt(c->sec->rpc, paddedHashes); + m.u.certificateVerify.signature = mptobytes(signedMP); + free(signedMP); + + if(m.u.certificateVerify.signature == nil){ + msgClear(&m); + goto Err; + } + + if(!msgSend(c, &m, AFlush)){ + msgClear(&m); + goto Err; + } + msgClear(&m); + } + /* change cipher spec */ if(fprint(c->ctl, "changecipher") < 0){ tlsError(c, EInternalError, "can't enable cipher: %r"); @@ -892,6 +946,12 @@ msgSend(TlsConnection *c, Msg *m, int act) p += m->u.certificate.certs[i]->len; } break; + case HCertificateVerify: + put16(p, m->u.certificateVerify.signature->len); + p += 2; + memmove(p, m->u.certificateVerify.signature->data, m->u.certificateVerify.signature->len); + p += m->u.certificateVerify.signature->len; + break; case HClientKeyExchange: n = m->u.clientKeyExchange.key->len; if(c->version != SSL3Version){ @@ -1116,7 +1176,7 @@ msgRecv(TlsConnection *c, Msg *m) nn = get24(p); p += 3; n -= 3; - if(n != nn) + if(nn == 0 && n > 0) goto Short; /* certs */ i = 0; @@ -1142,7 +1202,7 @@ msgRecv(TlsConnection *c, Msg *m) nn = p[0]; p += 1; n -= 1; - if(nn < 1 || nn > n) + if(nn > n) goto Short; m->u.certificateRequest.types = makebytes(p, nn); p += nn; @@ -1250,6 +1310,9 @@ msgClear(Msg *m) freebytes(m->u.certificateRequest.cas[i]); free(m->u.certificateRequest.cas); break; + case HCertificateVerify: + freebytes(m->u.certificateVerify.signature); + break; case HServerHelloDone: break; case HClientKeyExchange: @@ -1343,6 +1406,10 @@ msgPrint(char *buf, int n, Msg *m) for(i=0; i<m->u.certificateRequest.nca; i++) bs = bytesPrint(bs, be, "\t\t", m->u.certificateRequest.cas[i], "\n"); break; + case HCertificateVerify: + bs = seprint(bs, be, "HCertificateVerify\n"); + bs = bytesPrint(bs, be, "\tsignature: ", m->u.certificateVerify.signature,"\n"); + break; case HServerHelloDone: bs = seprint(bs, be, "ServerHelloDone\n"); break; diff --git a/sys/src/libsec/port/x509.c b/sys/src/libsec/port/x509.c index 103ab2933..77c2205f9 100644 --- a/sys/src/libsec/port/x509.c +++ b/sys/src/libsec/port/x509.c @@ -2036,27 +2036,33 @@ asn1mpint(Elem *e) return nil; } -static mpint* -pkcs1pad(Bytes *b, mpint *modulus) +mpint* +pkcs1padbuf(uchar *buf, int len, mpint *modulus) { int n = (mpsignif(modulus)+7)/8; int pm1, i; uchar *p; mpint *mp; - pm1 = n - 1 - b->len; + pm1 = n - 1 - len; p = (uchar*)emalloc(n); p[0] = 0; p[1] = 1; for(i = 2; i < pm1; i++) p[i] = 0xFF; p[pm1] = 0; - memcpy(&p[pm1+1], b->data, b->len); + memcpy(&p[pm1+1], buf, len); mp = betomp(p, n, nil); free(p); return mp; } +static mpint* +pkcs1pad(Bytes *b, mpint *modulus) +{ + return pkcs1padbuf(b->data, b->len, modulus); +} + RSApriv* asn1toRSApriv(uchar *kd, int kn) { |
