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