xref: /plan9/sys/src/libc/9sys/pushtls.c (revision 0591a7c1821da27d40a0fa8bed7304fc2fa2b020)
1 #include <u.h>
2 #include <libc.h>
3 #include <mp.h>
4 #include <libsec.h>
5 
6 enum {
7 	TLSFinishedLen = 12,
8 	HFinished = 20,
9 };
10 
11 static int
finished(int hand,int isclient)12 finished(int hand, int isclient)
13 {
14 	int i, n;
15 	uchar buf[500], buf2[500];
16 
17 	buf[0] = HFinished;
18 	buf[1] = TLSFinishedLen>>16;
19 	buf[2] = TLSFinishedLen>>8;
20 	buf[3] = TLSFinishedLen;
21 	n = TLSFinishedLen+4;
22 
23 	for(i=0; i<2; i++){
24 		if(i==0)
25 			memmove(buf+4, "client finished", TLSFinishedLen);
26 		else
27 			memmove(buf+4, "server finished", TLSFinishedLen);
28 		if(isclient == 1-i){
29 			if(write(hand, buf, n) != n)
30 				return -1;
31 		}else{
32 			if(readn(hand, buf2, n) != n || memcmp(buf,buf2,n) != 0)
33 				return -1;
34 		}
35 	}
36 	return 1;
37 }
38 
39 
40 // given a plain fd and secrets established beforehand, return encrypted connection
41 int
pushtls(int fd,char * hashalg,char * encalg,int isclient,char * secret,char * dir)42 pushtls(int fd, char *hashalg, char *encalg, int isclient, char *secret, char *dir)
43 {
44 	char buf[8];
45 	char dname[64];
46 	int n, data, ctl, hand;
47 
48 	// open a new filter; get ctl fd
49 	data = hand = -1;
50 	// /net/tls uses decimal file descriptors to name channels, hence a
51 	// user-level file server can't stand in for #a; may as well hard-code it.
52 	ctl = open("#a/tls/clone", ORDWR);
53 	if(ctl < 0)
54 		goto error;
55 	n = read(ctl, buf, sizeof(buf)-1);
56 	if(n < 0)
57 		goto error;
58 	buf[n] = 0;
59 	if(dir)
60 		sprint(dir, "#a/tls/%s", buf);
61 
62 	// get application fd
63 	sprint(dname, "#a/tls/%s/data", buf);
64 	data = open(dname, ORDWR);
65 	if(data < 0)
66 		goto error;
67 
68 	// get handshake fd
69 	sprint(dname, "#a/tls/%s/hand", buf);
70 	hand = open(dname, ORDWR);
71 	if(hand < 0)
72 		goto error;
73 
74 	// speak a minimal handshake
75 	if(fprint(ctl, "fd %d 0x301", fd) < 0 ||
76 	   fprint(ctl, "version 0x301") < 0 ||
77 	   fprint(ctl, "secret %s %s %d %s", hashalg, encalg, isclient, secret) < 0 ||
78 	   fprint(ctl, "changecipher") < 0 ||
79 	   finished(hand, isclient) < 0 ||
80 	   fprint(ctl, "opened") < 0){
81 		close(hand);
82 		hand = -1;
83 		goto error;
84 	}
85 	close(ctl);
86 	close(hand);
87 	close(fd);
88 	return data;
89 
90 error:
91 	if(data>=0)
92 		close(data);
93 	if(ctl>=0)
94 		close(ctl);
95 	if(hand>=0)
96 		close(hand);
97 	return -1;
98 }
99