]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/tlsclient.c
libsec: implement SPKI fingerprinting for okCertificate()
[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, dialfile;
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] [-o] 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         AuthInfo *ai = nil;
51
52         fmtinstall('B', mpfmt);
53         fmtinstall('[', encodefmt);
54         fmtinstall('H', encodefmt);
55
56         ARGBEGIN{
57         case 'D':
58                 debug++;
59                 break;
60         case 'a':
61                 auth++;
62                 break;
63         case 'k':
64                 keyspec = EARGF(usage());
65                 break;
66         case 't':
67                 file = EARGF(usage());
68                 break;
69         case 'x':
70                 filex = EARGF(usage());
71                 break;
72         case 'c':
73                 ccert = EARGF(usage());
74                 break;
75         case 'n':
76                 servername = EARGF(usage());
77                 break;
78         case 'o':
79                 dialfile = 1;
80                 break;
81         default:
82                 usage();
83         }ARGEND
84
85         if(argc < 1)
86                 usage();
87
88         if(filex && !file)      
89                 sysfatal("specifying -x without -t is useless");
90
91         if(file){
92                 thumb = initThumbprints(file, filex, "x509");
93                 if(thumb == nil)
94                         sysfatal("initThumbprints: %r");
95         } else
96                 thumb = nil;
97
98         addr = *argv++;
99         if((fd = dialfile? open(addr, ORDWR): dial(addr, 0, 0, 0)) < 0)
100                 sysfatal("dial %s: %r", addr);
101
102         conn = (TLSconn*)mallocz(sizeof *conn, 1);
103         conn->serverName = servername;
104         if(ccert){
105                 conn->cert = readcert(ccert, &conn->certlen);
106                 if(conn->cert == nil)
107                         sysfatal("readcert: %r");
108         }
109
110         if(auth){
111                 ai = auth_proxy(fd, auth_getkey, "proto=p9any role=client %s", keyspec);
112                 if(ai == nil)
113                         sysfatal("auth_proxy: %r");
114
115                 conn->pskID = "p9secret";
116                 conn->psk = ai->secret;
117                 conn->psklen = ai->nsecret;
118         }
119
120         if(debug)
121                 conn->trace = reporter;
122
123         fd = tlsClient(fd, conn);
124         if(fd < 0)
125                 sysfatal("tlsclient: %r");
126
127         if(debug)
128                 X509dump(conn->cert, conn->certlen);
129
130         if(thumb){
131                 if(!okCertificate(conn->cert, conn->certlen, thumb))
132                         sysfatal("cert for %s not recognized: %r", servername ? servername : addr);
133                 freeThumbprints(thumb);
134         }
135
136         free(conn->cert);
137         free(conn->sessionID);
138         free(conn);
139         if(ai != nil)
140                 auth_freeAI(ai);
141
142         if(*argv){
143                 dup(fd, 0);
144                 dup(fd, 1);
145                 if(fd > 1)
146                         close(fd);
147                 exec(*argv, argv);
148                 sysfatal("exec: %r");
149         }
150
151         rfork(RFNOTEG);
152         switch(fork()){
153         case -1:
154                 sysfatal("fork: %r");
155         case 0:
156                 xfer(0, fd);
157                 break;
158         default:
159                 xfer(fd, 1);
160                 break;
161         }
162         postnote(PNGROUP, getpid(), "die yankee pig dog");
163         exits(0);
164 }