--- /n/sources/plan9/sys/include/libsec.h Tue Sep 17 01:03:04 2013 +++ /sys/include/libsec.h Mon Dec 30 00:00:00 2013 @@ -402,3 +402,10 @@ /* readcert.c */ uchar *readcert(char *filename, int *pcertlen); PEMChain*readcertchain(char *filename); + +/* X509.c */ +typedef struct Bytes { + int len; + uchar data[1]; +} Bytes; +mpint *pkcs1pad(Bytes *b, mpint *modulus); --- /n/sources/plan9/sys/src/cmd/tlsclient.c Tue Jun 18 04:39:09 2002 +++ /sys/src/cmd/tlsclient.c Mon Dec 30 00:00:00 2013 @@ -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 @@ 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 @@ case 'x': filex = EARGF(usage()); break; + case 'D': + debug++; + break; + case 'c': + ccert = EARGF(usage()); + break; default: usage(); }ARGEND @@ -59,20 +81,24 @@ 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); --- /n/sources/plan9/sys/src/libsec/port/tlshand.c Fri Jul 29 21:12:14 2011 +++ /sys/src/libsec/port/tlshand.c Mon Dec 30 00:00:00 2013 @@ -28,11 +28,6 @@ typedef struct TlsSec TlsSec; -typedef struct Bytes{ - int len; - uchar data[1]; // [len] -} Bytes; - typedef struct Ints{ int len; int data[1]; // [len] @@ -112,6 +107,9 @@ struct { Bytes *key; } clientKeyExchange; + struct { + Bytes *signature; + } certificateVerify; Finished finished; } u; } Msg; @@ -251,8 +249,8 @@ }; 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); @@ -303,6 +301,7 @@ 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); @@ -398,7 +397,7 @@ if(data < 0) 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(fd); close(hand); close(ctl); @@ -602,13 +601,14 @@ } 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 +719,9 @@ } 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; @@ -739,6 +741,50 @@ 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 = pkcs1pad(makebytes(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 +938,12 @@ 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 +1168,7 @@ nn = get24(p); p += 3; n -= 3; - if(n != nn) + if(nn == 0 && n > 0) goto Short; /* certs */ i = 0; @@ -1142,8 +1194,7 @@ nn = p[0]; p += 1; n -= 1; - if(nn < 1 || nn > n) - goto Short; + m->u.certificateRequest.types = makebytes(p, nn); p += nn; n -= nn; @@ -1250,6 +1301,9 @@ 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 +1397,10 @@ for(i=0; iu.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; --- /n/sources/plan9/sys/man/8/tlssrv Sun Dec 2 23:42:28 2007 +++ /sys/man/8/tlssrv Mon Dec 30 00:00:00 2013 @@ -24,6 +24,13 @@ .PP .B tlsclient [ +.B -D +] +[ +.B -c +.I cert.pem +] +[ .B -t .I trustedkeys ] @@ -69,6 +76,14 @@ 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 --- /n/sources/plan9/sys/src/libsec/port/x509.c Tue Sep 17 01:04:24 2013 +++ /sys/src/libsec/port/x509.c Mon Dec 30 00:00:00 2013 @@ -19,7 +19,6 @@ typedef struct Elem Elem; typedef struct Tag Tag; typedef struct Value Value; -typedef struct Bytes Bytes; typedef struct Ints Ints; typedef struct Bits Bits; typedef struct Elist Elist; @@ -56,10 +55,6 @@ #define UniversalString 28 #define BMPString 30 -struct Bytes { - int len; - uchar data[1]; -}; struct Ints { int len; @@ -2031,7 +2026,7 @@ return nil; } -static mpint* +mpint* pkcs1pad(Bytes *b, mpint *modulus) { int n = (mpsignif(modulus)+7)/8;