1 /*
2 * Binary packet protocol for SSH-1.
3 */
4
5 #include <assert.h>
6
7 #include "putty.h"
8 #include "ssh.h"
9 #include "sshbpp.h"
10 #include "sshcr.h"
11
12 struct ssh1_bpp_state {
13 int crState;
14 long len, pad, biglen, length, maxlen;
15 unsigned char *data;
16 uint32_t realcrc, gotcrc;
17 int chunk;
18 PktIn *pktin;
19
20 ssh_cipher *cipher_in, *cipher_out;
21
22 struct crcda_ctx *crcda_ctx;
23 uint8_t iv[8]; /* for crcda */
24
25 bool pending_compression_request;
26 ssh_compressor *compctx;
27 ssh_decompressor *decompctx;
28
29 BinaryPacketProtocol bpp;
30 };
31
32 static void ssh1_bpp_free(BinaryPacketProtocol *bpp);
33 static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp);
34 static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp);
35 static void ssh1_bpp_queue_disconnect(BinaryPacketProtocol *bpp,
36 const char *msg, int category);
37 static PktOut *ssh1_bpp_new_pktout(int type);
38
39 static const BinaryPacketProtocolVtable ssh1_bpp_vtable = {
40 .free = ssh1_bpp_free,
41 .handle_input = ssh1_bpp_handle_input,
42 .handle_output = ssh1_bpp_handle_output,
43 .new_pktout = ssh1_bpp_new_pktout,
44 .queue_disconnect = ssh1_bpp_queue_disconnect,
45 .packet_size_limit = 0xFFFFFFFF, /* no special limit for this bpp */
46 };
47
ssh1_bpp_new(LogContext * logctx)48 BinaryPacketProtocol *ssh1_bpp_new(LogContext *logctx)
49 {
50 struct ssh1_bpp_state *s = snew(struct ssh1_bpp_state);
51 memset(s, 0, sizeof(*s));
52 s->bpp.vt = &ssh1_bpp_vtable;
53 s->bpp.logctx = logctx;
54 ssh_bpp_common_setup(&s->bpp);
55 return &s->bpp;
56 }
57
ssh1_bpp_free(BinaryPacketProtocol * bpp)58 static void ssh1_bpp_free(BinaryPacketProtocol *bpp)
59 {
60 struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp);
61 if (s->cipher_in)
62 ssh_cipher_free(s->cipher_in);
63 if (s->cipher_out)
64 ssh_cipher_free(s->cipher_out);
65 if (s->compctx)
66 ssh_compressor_free(s->compctx);
67 if (s->decompctx)
68 ssh_decompressor_free(s->decompctx);
69 if (s->crcda_ctx)
70 crcda_free_context(s->crcda_ctx);
71 sfree(s->pktin);
72 sfree(s);
73 }
74
ssh1_bpp_new_cipher(BinaryPacketProtocol * bpp,const ssh_cipheralg * cipher,const void * session_key)75 void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp,
76 const ssh_cipheralg *cipher,
77 const void *session_key)
78 {
79 struct ssh1_bpp_state *s;
80 assert(bpp->vt == &ssh1_bpp_vtable);
81 s = container_of(bpp, struct ssh1_bpp_state, bpp);
82
83 assert(!s->cipher_in);
84 assert(!s->cipher_out);
85
86 if (cipher) {
87 s->cipher_in = ssh_cipher_new(cipher);
88 s->cipher_out = ssh_cipher_new(cipher);
89 ssh_cipher_setkey(s->cipher_in, session_key);
90 ssh_cipher_setkey(s->cipher_out, session_key);
91
92 assert(!s->crcda_ctx);
93 s->crcda_ctx = crcda_make_context();
94
95 bpp_logevent("Initialised %s encryption", cipher->text_name);
96
97 memset(s->iv, 0, sizeof(s->iv));
98
99 assert(cipher->blksize <= sizeof(s->iv));
100 ssh_cipher_setiv(s->cipher_in, s->iv);
101 ssh_cipher_setiv(s->cipher_out, s->iv);
102 }
103 }
104
ssh1_bpp_start_compression(BinaryPacketProtocol * bpp)105 void ssh1_bpp_start_compression(BinaryPacketProtocol *bpp)
106 {
107 struct ssh1_bpp_state *s;
108 assert(bpp->vt == &ssh1_bpp_vtable);
109 s = container_of(bpp, struct ssh1_bpp_state, bpp);
110
111 assert(!s->compctx);
112 assert(!s->decompctx);
113
114 s->compctx = ssh_compressor_new(&ssh_zlib);
115 s->decompctx = ssh_decompressor_new(&ssh_zlib);
116
117 bpp_logevent("Started zlib (RFC1950) compression");
118 }
119
120 #define BPP_READ(ptr, len) do \
121 { \
122 bool success; \
123 crMaybeWaitUntilV((success = bufchain_try_fetch_consume( \
124 s->bpp.in_raw, ptr, len)) || \
125 s->bpp.input_eof); \
126 if (!success) \
127 goto eof; \
128 ssh_check_frozen(s->bpp.ssh); \
129 } while (0)
130
ssh1_bpp_handle_input(BinaryPacketProtocol * bpp)131 static void ssh1_bpp_handle_input(BinaryPacketProtocol *bpp)
132 {
133 struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp);
134
135 crBegin(s->crState);
136
137 while (1) {
138 s->maxlen = 0;
139 s->length = 0;
140
141 {
142 unsigned char lenbuf[4];
143 BPP_READ(lenbuf, 4);
144 s->len = toint(GET_32BIT_MSB_FIRST(lenbuf));
145 }
146
147 if (s->len < 5 || s->len > 262144) { /* SSH1.5-mandated max size */
148 ssh_sw_abort(s->bpp.ssh,
149 "Out-of-range packet length from remote suggests"
150 " data stream corruption");
151 crStopV;
152 }
153
154 s->pad = 8 - (s->len % 8);
155 s->biglen = s->len + s->pad;
156 s->length = s->len - 5;
157
158 /*
159 * Allocate the packet to return, now we know its length.
160 */
161 s->pktin = snew_plus(PktIn, s->biglen);
162 s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
163 s->pktin->qnode.on_free_queue = false;
164 s->pktin->type = 0;
165
166 s->maxlen = s->biglen;
167 s->data = snew_plus_get_aux(s->pktin);
168
169 BPP_READ(s->data, s->biglen);
170
171 if (s->cipher_in && detect_attack(s->crcda_ctx,
172 s->data, s->biglen, s->iv)) {
173 ssh_sw_abort(s->bpp.ssh,
174 "Network attack (CRC compensation) detected!");
175 crStopV;
176 }
177 /* Save the last cipher block, to be passed to the next call
178 * to detect_attack */
179 assert(s->biglen >= 8);
180 memcpy(s->iv, s->data + s->biglen - 8, sizeof(s->iv));
181
182 if (s->cipher_in)
183 ssh_cipher_decrypt(s->cipher_in, s->data, s->biglen);
184
185 s->realcrc = crc32_ssh1(make_ptrlen(s->data, s->biglen - 4));
186 s->gotcrc = GET_32BIT_MSB_FIRST(s->data + s->biglen - 4);
187 if (s->gotcrc != s->realcrc) {
188 ssh_sw_abort(s->bpp.ssh, "Incorrect CRC received on packet");
189 crStopV;
190 }
191
192 if (s->decompctx) {
193 unsigned char *decompblk;
194 int decomplen;
195 if (!ssh_decompressor_decompress(
196 s->decompctx, s->data + s->pad, s->length + 1,
197 &decompblk, &decomplen)) {
198 ssh_sw_abort(s->bpp.ssh,
199 "Zlib decompression encountered invalid data");
200 crStopV;
201 }
202
203 if (s->maxlen < s->pad + decomplen) {
204 PktIn *old_pktin = s->pktin;
205
206 s->maxlen = s->pad + decomplen;
207 s->pktin = snew_plus(PktIn, s->maxlen);
208 *s->pktin = *old_pktin; /* structure copy */
209 s->data = snew_plus_get_aux(s->pktin);
210
211 smemclr(old_pktin, s->biglen);
212 sfree(old_pktin);
213 }
214
215 memcpy(s->data + s->pad, decompblk, decomplen);
216 sfree(decompblk);
217 s->length = decomplen - 1;
218 }
219
220 /*
221 * Now we can find the bounds of the semantic content of the
222 * packet, and the initial type byte.
223 */
224 s->data += s->pad;
225 s->pktin->type = *s->data++;
226 BinarySource_INIT(s->pktin, s->data, s->length);
227
228 if (s->bpp.logctx) {
229 logblank_t blanks[MAX_BLANKS];
230 int nblanks = ssh1_censor_packet(
231 s->bpp.pls, s->pktin->type, false,
232 make_ptrlen(s->data, s->length), blanks);
233 log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type,
234 ssh1_pkt_type(s->pktin->type),
235 get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks,
236 NULL, 0, NULL);
237 }
238
239 s->pktin->qnode.formal_size = get_avail(s->pktin);
240 pq_push(&s->bpp.in_pq, s->pktin);
241
242 {
243 int type = s->pktin->type;
244 s->pktin = NULL;
245
246 switch (type) {
247 case SSH1_SMSG_SUCCESS:
248 case SSH1_SMSG_FAILURE:
249 if (s->pending_compression_request) {
250 /*
251 * This is the response to
252 * SSH1_CMSG_REQUEST_COMPRESSION.
253 */
254 if (type == SSH1_SMSG_SUCCESS) {
255 /*
256 * If the response was positive, start
257 * compression.
258 */
259 ssh1_bpp_start_compression(&s->bpp);
260 }
261
262 /*
263 * Either way, cancel the pending flag, and
264 * schedule a run of our output side in case we
265 * had any packets queued up in the meantime.
266 */
267 s->pending_compression_request = false;
268 queue_idempotent_callback(&s->bpp.ic_out_pq);
269 }
270 break;
271 }
272 }
273 }
274
275 eof:
276 if (!s->bpp.expect_close) {
277 ssh_remote_error(s->bpp.ssh,
278 "Remote side unexpectedly closed network connection");
279 } else {
280 ssh_remote_eof(s->bpp.ssh, "Remote side closed network connection");
281 }
282 return; /* avoid touching s now it's been freed */
283
284 crFinishV;
285 }
286
ssh1_bpp_new_pktout(int pkt_type)287 static PktOut *ssh1_bpp_new_pktout(int pkt_type)
288 {
289 PktOut *pkt = ssh_new_packet();
290 pkt->length = 4 + 8; /* space for length + max padding */
291 put_byte(pkt, pkt_type);
292 pkt->prefix = pkt->length;
293 pkt->type = pkt_type;
294 pkt->downstream_id = 0;
295 pkt->additional_log_text = NULL;
296 return pkt;
297 }
298
ssh1_bpp_format_packet(struct ssh1_bpp_state * s,PktOut * pkt)299 static void ssh1_bpp_format_packet(struct ssh1_bpp_state *s, PktOut *pkt)
300 {
301 int pad, biglen, pktoffs;
302 uint32_t crc;
303 int len;
304
305 if (s->bpp.logctx) {
306 ptrlen pktdata = make_ptrlen(pkt->data + pkt->prefix,
307 pkt->length - pkt->prefix);
308 logblank_t blanks[MAX_BLANKS];
309 int nblanks = ssh1_censor_packet(
310 s->bpp.pls, pkt->type, true, pktdata, blanks);
311 log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type,
312 ssh1_pkt_type(pkt->type),
313 pktdata.ptr, pktdata.len, nblanks, blanks,
314 NULL, 0, NULL);
315 }
316
317 if (s->compctx) {
318 unsigned char *compblk;
319 int complen;
320 ssh_compressor_compress(s->compctx, pkt->data + 12, pkt->length - 12,
321 &compblk, &complen, 0);
322 /* Replace the uncompressed packet data with the compressed
323 * version. */
324 pkt->length = 12;
325 put_data(pkt, compblk, complen);
326 sfree(compblk);
327 }
328
329 put_uint32(pkt, 0); /* space for CRC */
330 len = pkt->length - 4 - 8; /* len(type+data+CRC) */
331 pad = 8 - (len % 8);
332 pktoffs = 8 - pad;
333 biglen = len + pad; /* len(padding+type+data+CRC) */
334
335 random_read(pkt->data + pktoffs, 4+8 - pktoffs);
336 crc = crc32_ssh1(
337 make_ptrlen(pkt->data + pktoffs + 4, biglen - 4)); /* all ex len */
338 PUT_32BIT_MSB_FIRST(pkt->data + pktoffs + 4 + biglen - 4, crc);
339 PUT_32BIT_MSB_FIRST(pkt->data + pktoffs, len);
340
341 if (s->cipher_out)
342 ssh_cipher_encrypt(s->cipher_out, pkt->data + pktoffs + 4, biglen);
343
344 bufchain_add(s->bpp.out_raw, pkt->data + pktoffs,
345 biglen + 4); /* len(length+padding+type+data+CRC) */
346 }
347
ssh1_bpp_handle_output(BinaryPacketProtocol * bpp)348 static void ssh1_bpp_handle_output(BinaryPacketProtocol *bpp)
349 {
350 struct ssh1_bpp_state *s = container_of(bpp, struct ssh1_bpp_state, bpp);
351 PktOut *pkt;
352
353 if (s->pending_compression_request) {
354 /*
355 * Don't send any output packets while we're awaiting a
356 * response to SSH1_CMSG_REQUEST_COMPRESSION, because if they
357 * cross over in transit with the responding SSH1_CMSG_SUCCESS
358 * then the other end could decode them with the wrong
359 * compression settings.
360 */
361 return;
362 }
363
364 while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) {
365 int type = pkt->type;
366 ssh1_bpp_format_packet(s, pkt);
367 ssh_free_pktout(pkt);
368
369 if (type == SSH1_CMSG_REQUEST_COMPRESSION) {
370 /*
371 * When we see the actual compression request go past, set
372 * the pending flag, and stop processing packets this
373 * time.
374 */
375 s->pending_compression_request = true;
376 break;
377 }
378 }
379 }
380
ssh1_bpp_queue_disconnect(BinaryPacketProtocol * bpp,const char * msg,int category)381 static void ssh1_bpp_queue_disconnect(BinaryPacketProtocol *bpp,
382 const char *msg, int category)
383 {
384 PktOut *pkt = ssh_bpp_new_pktout(bpp, SSH1_MSG_DISCONNECT);
385 put_stringz(pkt, msg);
386 pq_push(&bpp->out_pq, pkt);
387 }
388