summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/man/8/tlssrv15
-rw-r--r--sys/src/cmd/tlsclient.c44
-rw-r--r--sys/src/libsec/port/tlshand.c81
-rw-r--r--sys/src/libsec/port/x509.c14
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)
{