xref: /plan9-contrib/sys/src/cmd/ssh2/transport.c (revision 63afb9a5d3f910047231762bcce0ee49fed3d07c)
1*63afb9a5SDavid du Colombier #include <u.h>
2*63afb9a5SDavid du Colombier #include <libc.h>
3*63afb9a5SDavid du Colombier #include <mp.h>
4*63afb9a5SDavid du Colombier #include <fcall.h>
5*63afb9a5SDavid du Colombier #include <thread.h>
6*63afb9a5SDavid du Colombier #include <9p.h>
7*63afb9a5SDavid du Colombier #include <libsec.h>
8*63afb9a5SDavid du Colombier #include <ip.h>
9*63afb9a5SDavid du Colombier #include "netssh.h"
10*63afb9a5SDavid du Colombier 
11*63afb9a5SDavid du Colombier extern Cipher *cryptos[];
12*63afb9a5SDavid du Colombier 
13*63afb9a5SDavid du Colombier Packet *
new_packet(Conn * c)14*63afb9a5SDavid du Colombier new_packet(Conn *c)
15*63afb9a5SDavid du Colombier {
16*63afb9a5SDavid du Colombier 	Packet *p;
17*63afb9a5SDavid du Colombier 
18*63afb9a5SDavid du Colombier 	p = emalloc9p(sizeof(Packet));
19*63afb9a5SDavid du Colombier 	init_packet(p);
20*63afb9a5SDavid du Colombier 	p->c = c;
21*63afb9a5SDavid du Colombier 	return p;
22*63afb9a5SDavid du Colombier }
23*63afb9a5SDavid du Colombier 
24*63afb9a5SDavid du Colombier void
init_packet(Packet * p)25*63afb9a5SDavid du Colombier init_packet(Packet *p)
26*63afb9a5SDavid du Colombier {
27*63afb9a5SDavid du Colombier 	memset(p, 0, sizeof(Packet));
28*63afb9a5SDavid du Colombier 	p->rlength = 1;
29*63afb9a5SDavid du Colombier }
30*63afb9a5SDavid du Colombier 
31*63afb9a5SDavid du Colombier void
add_byte(Packet * p,char c)32*63afb9a5SDavid du Colombier add_byte(Packet *p, char c)
33*63afb9a5SDavid du Colombier {
34*63afb9a5SDavid du Colombier 	p->payload[p->rlength-1] = c;
35*63afb9a5SDavid du Colombier 	p->rlength++;
36*63afb9a5SDavid du Colombier }
37*63afb9a5SDavid du Colombier 
38*63afb9a5SDavid du Colombier void
add_uint32(Packet * p,ulong l)39*63afb9a5SDavid du Colombier add_uint32(Packet *p, ulong l)
40*63afb9a5SDavid du Colombier {
41*63afb9a5SDavid du Colombier 	hnputl(p->payload+p->rlength-1, l);
42*63afb9a5SDavid du Colombier 	p->rlength += 4;
43*63afb9a5SDavid du Colombier }
44*63afb9a5SDavid du Colombier 
45*63afb9a5SDavid du Colombier ulong
get_uint32(Packet *,uchar ** data)46*63afb9a5SDavid du Colombier get_uint32(Packet *, uchar **data)
47*63afb9a5SDavid du Colombier {
48*63afb9a5SDavid du Colombier 	ulong x;
49*63afb9a5SDavid du Colombier 	x = nhgetl(*data);
50*63afb9a5SDavid du Colombier 	*data += 4;
51*63afb9a5SDavid du Colombier 	return x;
52*63afb9a5SDavid du Colombier }
53*63afb9a5SDavid du Colombier 
54*63afb9a5SDavid du Colombier int
add_packet(Packet * p,void * data,int len)55*63afb9a5SDavid du Colombier add_packet(Packet *p, void *data, int len)
56*63afb9a5SDavid du Colombier {
57*63afb9a5SDavid du Colombier 	if(p->rlength + len > Maxpayload)
58*63afb9a5SDavid du Colombier 		return -1;
59*63afb9a5SDavid du Colombier 	memmove(p->payload + p->rlength - 1, data, len);
60*63afb9a5SDavid du Colombier 	p->rlength += len;
61*63afb9a5SDavid du Colombier 	return 0;
62*63afb9a5SDavid du Colombier }
63*63afb9a5SDavid du Colombier 
64*63afb9a5SDavid du Colombier void
add_block(Packet * p,void * data,int len)65*63afb9a5SDavid du Colombier add_block(Packet *p, void *data, int len)
66*63afb9a5SDavid du Colombier {
67*63afb9a5SDavid du Colombier 	hnputl(p->payload + p->rlength - 1, len);
68*63afb9a5SDavid du Colombier 	p->rlength += 4;
69*63afb9a5SDavid du Colombier 	add_packet(p, data, len);
70*63afb9a5SDavid du Colombier }
71*63afb9a5SDavid du Colombier 
72*63afb9a5SDavid du Colombier void
add_string(Packet * p,char * s)73*63afb9a5SDavid du Colombier add_string(Packet *p, char *s)
74*63afb9a5SDavid du Colombier {
75*63afb9a5SDavid du Colombier 	uchar *q;
76*63afb9a5SDavid du Colombier 	int n;
77*63afb9a5SDavid du Colombier 	uchar nn[4];
78*63afb9a5SDavid du Colombier 
79*63afb9a5SDavid du Colombier 	n = strlen(s);
80*63afb9a5SDavid du Colombier 	hnputl(nn, n);
81*63afb9a5SDavid du Colombier 	q = p->payload + p->rlength - 1;
82*63afb9a5SDavid du Colombier 	memmove(q, nn, 4);
83*63afb9a5SDavid du Colombier 	memmove(q+4, s, n);
84*63afb9a5SDavid du Colombier 	p->rlength += n + 4;
85*63afb9a5SDavid du Colombier }
86*63afb9a5SDavid du Colombier 
87*63afb9a5SDavid du Colombier uchar *
get_string(Packet * p,uchar * q,char * s,int lim,int * len)88*63afb9a5SDavid du Colombier get_string(Packet *p, uchar *q, char *s, int lim, int *len)
89*63afb9a5SDavid du Colombier {
90*63afb9a5SDavid du Colombier 	int n, m;
91*63afb9a5SDavid du Colombier 
92*63afb9a5SDavid du Colombier 	if (p && q > p->payload + p->rlength)
93*63afb9a5SDavid du Colombier 		s[0] = '\0';
94*63afb9a5SDavid du Colombier 	m = nhgetl(q);
95*63afb9a5SDavid du Colombier 	q += 4;
96*63afb9a5SDavid du Colombier 	if(m < lim)
97*63afb9a5SDavid du Colombier 		n = m;
98*63afb9a5SDavid du Colombier 	else
99*63afb9a5SDavid du Colombier 		n = lim - 1;
100*63afb9a5SDavid du Colombier 	memmove(s, q, n);
101*63afb9a5SDavid du Colombier 	s[n] = '\0';
102*63afb9a5SDavid du Colombier 	q += m;
103*63afb9a5SDavid du Colombier 	if(len)
104*63afb9a5SDavid du Colombier 		*len = n;
105*63afb9a5SDavid du Colombier 	return q;
106*63afb9a5SDavid du Colombier }
107*63afb9a5SDavid du Colombier 
108*63afb9a5SDavid du Colombier void
add_mp(Packet * p,mpint * x)109*63afb9a5SDavid du Colombier add_mp(Packet *p, mpint *x)
110*63afb9a5SDavid du Colombier {
111*63afb9a5SDavid du Colombier 	uchar *q;
112*63afb9a5SDavid du Colombier 	int n;
113*63afb9a5SDavid du Colombier 
114*63afb9a5SDavid du Colombier 	q = p->payload + p->rlength - 1;
115*63afb9a5SDavid du Colombier 	n = mptobe(x, q + 4, Maxpktpay - p->rlength + 1 - 4, nil);
116*63afb9a5SDavid du Colombier 	if(q[4] & 0x80){
117*63afb9a5SDavid du Colombier 		memmove(q + 5, q + 4, n);
118*63afb9a5SDavid du Colombier 		q[4] = 0;
119*63afb9a5SDavid du Colombier 		n++;
120*63afb9a5SDavid du Colombier 	}
121*63afb9a5SDavid du Colombier 	hnputl(q, n);
122*63afb9a5SDavid du Colombier 	p->rlength += n + 4;
123*63afb9a5SDavid du Colombier }
124*63afb9a5SDavid du Colombier 
125*63afb9a5SDavid du Colombier mpint *
get_mp(uchar * q)126*63afb9a5SDavid du Colombier get_mp(uchar *q)
127*63afb9a5SDavid du Colombier {
128*63afb9a5SDavid du Colombier 	return betomp(q + 4, nhgetl(q), nil);
129*63afb9a5SDavid du Colombier }
130*63afb9a5SDavid du Colombier 
131*63afb9a5SDavid du Colombier int
finish_packet(Packet * p)132*63afb9a5SDavid du Colombier finish_packet(Packet *p)
133*63afb9a5SDavid du Colombier {
134*63afb9a5SDavid du Colombier 	Conn *c;
135*63afb9a5SDavid du Colombier 	uchar *q, *buf;
136*63afb9a5SDavid du Colombier 	int blklen, i, n2, n1, maclen;
137*63afb9a5SDavid du Colombier 
138*63afb9a5SDavid du Colombier 	c = p->c;
139*63afb9a5SDavid du Colombier 	blklen = 8;
140*63afb9a5SDavid du Colombier 	if(c && debug > 1)
141*63afb9a5SDavid du Colombier 		fprint(2, "%s: in finish_packet: enc %d outmac %d len %ld\n",
142*63afb9a5SDavid du Colombier 			argv0, c->encrypt, c->outmac, p->rlength);
143*63afb9a5SDavid du Colombier 	if(c && c->encrypt != -1){
144*63afb9a5SDavid du Colombier 		blklen = cryptos[c->encrypt]->blklen;
145*63afb9a5SDavid du Colombier 		if(blklen < 8)
146*63afb9a5SDavid du Colombier 			blklen = 8;
147*63afb9a5SDavid du Colombier 	}
148*63afb9a5SDavid du Colombier 	n1 = p->rlength - 1;
149*63afb9a5SDavid du Colombier 	n2 = blklen - (n1 + 5) % blklen;
150*63afb9a5SDavid du Colombier 	if(n2 < 4)
151*63afb9a5SDavid du Colombier 		n2 += blklen;
152*63afb9a5SDavid du Colombier 	p->pad_len = n2;
153*63afb9a5SDavid du Colombier 	for(i = 0, q = p->payload + n1; i < n2; ++i, ++q)
154*63afb9a5SDavid du Colombier 		*q = fastrand();
155*63afb9a5SDavid du Colombier 	p->rlength = n1 + n2 + 1;
156*63afb9a5SDavid du Colombier 	hnputl(p->nlength, p->rlength);
157*63afb9a5SDavid du Colombier 	maclen = 0;
158*63afb9a5SDavid du Colombier 	if(c && c->outmac != -1){
159*63afb9a5SDavid du Colombier 		maclen = SHA1dlen;
160*63afb9a5SDavid du Colombier 		buf = emalloc9p(Maxpktpay);
161*63afb9a5SDavid du Colombier 		hnputl(buf, c->outseq);
162*63afb9a5SDavid du Colombier 		memmove(buf + 4, p->nlength, p->rlength + 4);
163*63afb9a5SDavid du Colombier 		hmac_sha1(buf, p->rlength + 8, c->outik, maclen, q, nil);
164*63afb9a5SDavid du Colombier 		free(buf);
165*63afb9a5SDavid du Colombier 	}
166*63afb9a5SDavid du Colombier 	if(c && c->encrypt != -1)
167*63afb9a5SDavid du Colombier 		cryptos[c->encrypt]->encrypt(c->enccs, p->nlength, p->rlength + 4);
168*63afb9a5SDavid du Colombier 	if (c)
169*63afb9a5SDavid du Colombier 		c->outseq++;
170*63afb9a5SDavid du Colombier 	if(debug > 1)
171*63afb9a5SDavid du Colombier 		fprint(2, "%s: leaving finish packet: len %ld n1 %d n2 %d maclen %d\n",
172*63afb9a5SDavid du Colombier 			argv0, p->rlength, n1, n2, maclen);
173*63afb9a5SDavid du Colombier 	return p->rlength + 4 + maclen;
174*63afb9a5SDavid du Colombier }
175*63afb9a5SDavid du Colombier 
176*63afb9a5SDavid du Colombier /*
177*63afb9a5SDavid du Colombier  * The first blklen bytes are already decrypted so we could find the
178*63afb9a5SDavid du Colombier  * length.
179*63afb9a5SDavid du Colombier  */
180*63afb9a5SDavid du Colombier int
undo_packet(Packet * p)181*63afb9a5SDavid du Colombier undo_packet(Packet *p)
182*63afb9a5SDavid du Colombier {
183*63afb9a5SDavid du Colombier 	Conn *c;
184*63afb9a5SDavid du Colombier 	long nlength;
185*63afb9a5SDavid du Colombier 	int nb;
186*63afb9a5SDavid du Colombier 	uchar rmac[SHA1dlen], *buf;
187*63afb9a5SDavid du Colombier 
188*63afb9a5SDavid du Colombier 	c = p->c;
189*63afb9a5SDavid du Colombier 	nb = 4;
190*63afb9a5SDavid du Colombier 	if(c->decrypt != -1)
191*63afb9a5SDavid du Colombier 		nb = cryptos[c->decrypt]->blklen;
192*63afb9a5SDavid du Colombier 	if(c->inmac != -1)
193*63afb9a5SDavid du Colombier 		p->rlength -= SHA1dlen;			/* was magic 20 */
194*63afb9a5SDavid du Colombier 	nlength = nhgetl(p->nlength);
195*63afb9a5SDavid du Colombier 	if(c->decrypt != -1)
196*63afb9a5SDavid du Colombier 		cryptos[c->decrypt]->decrypt(c->deccs, p->nlength + nb,
197*63afb9a5SDavid du Colombier 			p->rlength + 4 - nb);
198*63afb9a5SDavid du Colombier 	if(c->inmac != -1){
199*63afb9a5SDavid du Colombier 		buf = emalloc9p(Maxpktpay);
200*63afb9a5SDavid du Colombier 		hnputl(buf, c->inseq);
201*63afb9a5SDavid du Colombier 		memmove(buf + 4, p->nlength, nlength + 4);
202*63afb9a5SDavid du Colombier 		hmac_sha1(buf, nlength + 8, c->inik, SHA1dlen, rmac, nil);
203*63afb9a5SDavid du Colombier 		free(buf);
204*63afb9a5SDavid du Colombier 		if(memcmp(rmac, p->payload + nlength - 1, SHA1dlen) != 0){
205*63afb9a5SDavid du Colombier 			fprint(2, "%s: received MAC verification failed: seq=%d\n",
206*63afb9a5SDavid du Colombier 				argv0, c->inseq);
207*63afb9a5SDavid du Colombier 			return -1;
208*63afb9a5SDavid du Colombier 		}
209*63afb9a5SDavid du Colombier 	}
210*63afb9a5SDavid du Colombier 	c->inseq++;
211*63afb9a5SDavid du Colombier 	p->rlength -= p->pad_len;
212*63afb9a5SDavid du Colombier 	p->pad_len = 0;
213*63afb9a5SDavid du Colombier 	return p->rlength - 1;
214*63afb9a5SDavid du Colombier }
215*63afb9a5SDavid du Colombier 
216*63afb9a5SDavid du Colombier void
dump_packet(Packet * p)217*63afb9a5SDavid du Colombier dump_packet(Packet *p)
218*63afb9a5SDavid du Colombier {
219*63afb9a5SDavid du Colombier 	int i;
220*63afb9a5SDavid du Colombier 	char *buf, *q, *e;
221*63afb9a5SDavid du Colombier 
222*63afb9a5SDavid du Colombier 	fprint(2, "Length: %ld, Padding length: %d\n", p->rlength, p->pad_len);
223*63afb9a5SDavid du Colombier 	q = buf = emalloc9p(Copybufsz);
224*63afb9a5SDavid du Colombier 	e = buf + Copybufsz;
225*63afb9a5SDavid du Colombier 	for(i = 0; i < p->rlength - 1; ++i){
226*63afb9a5SDavid du Colombier 		q = seprint(q, e, " %02x", p->payload[i]);
227*63afb9a5SDavid du Colombier 		if(i % 16 == 15)
228*63afb9a5SDavid du Colombier 			q = seprint(q, e, "\n");
229*63afb9a5SDavid du Colombier 		if(q - buf > Copybufsz - 4){
230*63afb9a5SDavid du Colombier 			fprint(2, "%s", buf);
231*63afb9a5SDavid du Colombier 			q = buf;
232*63afb9a5SDavid du Colombier 		}
233*63afb9a5SDavid du Colombier 	}
234*63afb9a5SDavid du Colombier 	fprint(2, "%s\n", buf);
235*63afb9a5SDavid du Colombier 	free(buf);
236*63afb9a5SDavid du Colombier }
237