]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/tlsclient.c
tlssrv: p9any authentication support using TLS-PSK cipher suits
[plan9front.git] / sys / src / cmd / tlsclient.c
1 #include <u.h>
2 #include <libc.h>
3 #include <mp.h>
4 #include <libsec.h>
5 #include <auth.h>
6
7 int debug, auth;
8 char *keyspec = "";
9 char *servername, *file, *filex, *ccert;
10
11 void
12 usage(void)
13 {
14         fprint(2, "usage: tlsclient [-D] [-a [-k keyspec] ] [-c lib/tls/clientcert] [-t /sys/lib/tls/xxx] [-x /sys/lib/tls/xxx.exclude] [-n servername] dialstring [cmd [args...]]\n");
15         exits("usage");
16 }
17
18 void
19 xfer(int from, int to)
20 {
21         char buf[12*1024];
22         int n;
23
24         while((n = read(from, buf, sizeof buf)) > 0)
25                 if(write(to, buf, n) < 0)
26                         break;
27 }
28
29 static int
30 reporter(char *fmt, ...)
31 {
32         va_list ap;
33         
34         va_start(ap, fmt);
35         fprint(2, "%s:  tls reports ", argv0);
36         vfprint(2, fmt, ap);
37         fprint(2, "\n");
38
39         va_end(ap);
40         return 0;
41 }
42
43 void
44 main(int argc, char **argv)
45 {
46         int fd;
47         char *addr;
48         TLSconn *conn;
49         Thumbprint *thumb;
50
51         fmtinstall('H', encodefmt);
52
53         ARGBEGIN{
54         case 'D':
55                 debug++;
56                 break;
57         case 'a':
58                 auth++;
59                 break;
60         case 'k':
61                 keyspec = EARGF(usage());
62                 break;
63         case 't':
64                 file = EARGF(usage());
65                 break;
66         case 'x':
67                 filex = EARGF(usage());
68                 break;
69         case 'c':
70                 ccert = EARGF(usage());
71                 break;
72         case 'n':
73                 servername = EARGF(usage());
74                 break;
75         default:
76                 usage();
77         }ARGEND
78
79         if(argc < 1)
80                 usage();
81
82         if(filex && !file)      
83                 sysfatal("specifying -x without -t is useless");
84
85         if(file){
86                 thumb = initThumbprints(file, filex);
87                 if(thumb == nil)
88                         sysfatal("initThumbprints: %r");
89         } else
90                 thumb = nil;
91
92         addr = *argv++;
93         if((fd = dial(addr, 0, 0, 0)) < 0)
94                 sysfatal("dial %s: %r", addr);
95
96         conn = (TLSconn*)mallocz(sizeof *conn, 1);
97         conn->serverName = servername;
98         if(ccert){
99                 conn->cert = readcert(ccert, &conn->certlen);
100                 if(conn->cert == nil)
101                         sysfatal("readcert: %r");
102         }
103
104         if(auth){
105                 AuthInfo *ai;
106
107                 ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec);
108                 if(ai == nil)
109                         sysfatal("auth_proxy: %r");
110
111                 conn->pskID = "p9secret";
112                 conn->psk = ai->secret;
113                 conn->psklen = ai->nsecret;
114         }
115
116         if(debug)
117                 conn->trace = reporter;
118
119         fd = tlsClient(fd, conn);
120         if(fd < 0)
121                 sysfatal("tlsclient: %r");
122
123         if(thumb){
124                 uchar digest[20];
125
126                 if(conn->cert==nil || conn->certlen<=0)
127                         sysfatal("server did not provide TLS certificate");
128                 sha1(conn->cert, conn->certlen, digest, nil);
129                 if(!okThumbprint(digest, thumb))
130                         sysfatal("server certificate %.*H not recognized", SHA1dlen, digest);
131         }
132
133         if(*argv){
134                 dup(fd, 0);
135                 dup(fd, 1);
136                 if(fd > 1)
137                         close(fd);
138                 exec(*argv, argv);
139                 sysfatal("exec: %r");
140         }
141
142         rfork(RFNOTEG);
143         switch(fork()){
144         case -1:
145                 sysfatal("fork: %r");
146         case 0:
147                 xfer(0, fd);
148                 break;
149         default:
150                 xfer(fd, 1);
151                 break;
152         }
153         postnote(PNGROUP, getpid(), "die yankee pig dog");
154         exits(0);
155 }