SSH 2 support, phase 1, debugging. Currently does Diffie-Hellman and gets
[u/mdw/putty] / ssh.c
CommitLineData
374330e2 1#include <stdio.h>
2#include <stdlib.h>
fb09bf1c 3#include <stdarg.h>
4#include <assert.h>
374330e2 5#include <winsock.h>
6
7#include "putty.h"
fb09bf1c 8#include "ssh.h"
9#include "scp.h"
374330e2 10
11#ifndef FALSE
12#define FALSE 0
13#endif
14#ifndef TRUE
15#define TRUE 1
16#endif
17
fb09bf1c 18#define logevent(s) { logevent(s); \
19 if (IS_SCP && (scp_flags & SCP_VERBOSE) != 0) \
20 fprintf(stderr, "%s\n", s); }
21
e5574168 22#define SSH1_MSG_DISCONNECT 1
23#define SSH1_SMSG_PUBLIC_KEY 2
24#define SSH1_CMSG_SESSION_KEY 3
25#define SSH1_CMSG_USER 4
26#define SSH1_CMSG_AUTH_PASSWORD 9
27#define SSH1_CMSG_REQUEST_PTY 10
28#define SSH1_CMSG_WINDOW_SIZE 11
29#define SSH1_CMSG_EXEC_SHELL 12
30#define SSH1_CMSG_EXEC_CMD 13
31#define SSH1_SMSG_SUCCESS 14
32#define SSH1_SMSG_FAILURE 15
33#define SSH1_CMSG_STDIN_DATA 16
34#define SSH1_SMSG_STDOUT_DATA 17
35#define SSH1_SMSG_STDERR_DATA 18
36#define SSH1_CMSG_EOF 19
37#define SSH1_SMSG_EXIT_STATUS 20
38#define SSH1_CMSG_EXIT_CONFIRMATION 33
39#define SSH1_MSG_IGNORE 32
40#define SSH1_MSG_DEBUG 36
41#define SSH1_CMSG_AUTH_TIS 39
42#define SSH1_SMSG_AUTH_TIS_CHALLENGE 40
43#define SSH1_CMSG_AUTH_TIS_RESPONSE 41
44
45#define SSH1_AUTH_TIS 5
46
47#define SSH2_MSG_DISCONNECT 1
48#define SSH2_MSG_IGNORE 2
49#define SSH2_MSG_UNIMPLEMENTED 3
50#define SSH2_MSG_DEBUG 4
51#define SSH2_MSG_SERVICE_REQUEST 5
52#define SSH2_MSG_SERVICE_ACCEPT 6
53#define SSH2_MSG_KEXINIT 20
54#define SSH2_MSG_NEWKEYS 21
55#define SSH2_MSG_KEXDH_INIT 30
56#define SSH2_MSG_KEXDH_REPLY 31
fb09bf1c 57
58#define GET_32BIT(cp) \
59 (((unsigned long)(unsigned char)(cp)[0] << 24) | \
60 ((unsigned long)(unsigned char)(cp)[1] << 16) | \
61 ((unsigned long)(unsigned char)(cp)[2] << 8) | \
62 ((unsigned long)(unsigned char)(cp)[3]))
63
64#define PUT_32BIT(cp, value) { \
65 (cp)[0] = (unsigned char)((value) >> 24); \
66 (cp)[1] = (unsigned char)((value) >> 16); \
67 (cp)[2] = (unsigned char)((value) >> 8); \
68 (cp)[3] = (unsigned char)(value); }
69
70enum { PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR };
972a41c8 71
374330e2 72/* Coroutine mechanics for the sillier bits of the code */
73#define crBegin1 static int crLine = 0;
74#define crBegin2 switch(crLine) { case 0:;
75#define crBegin crBegin1; crBegin2;
76#define crFinish(z) } crLine = 0; return (z)
77#define crFinishV } crLine = 0; return
78#define crReturn(z) \
79 do {\
80 crLine=__LINE__; return (z); case __LINE__:;\
81 } while (0)
82#define crReturnV \
83 do {\
84 crLine=__LINE__; return; case __LINE__:;\
85 } while (0)
86#define crStop(z) do{ crLine = 0; return (z); }while(0)
87#define crStopV do{ crLine = 0; return; }while(0)
fb09bf1c 88#define crWaitUntil(c) do { crReturn(0); } while (!(c))
374330e2 89
e5574168 90extern struct ssh_cipher ssh_3des;
91extern struct ssh_cipher ssh_des;
92extern struct ssh_cipher ssh_blowfish;
93
94/* for ssh 2; we miss out single-DES because it isn't supported */
95struct ssh_cipher *ciphers[] = { &ssh_3des, &ssh_blowfish };
96
97extern struct ssh_kex ssh_diffiehellman;
98struct ssh_kex *kex_algs[] = { &ssh_diffiehellman };
99
100extern struct ssh_hostkey ssh_dss;
101struct ssh_hostkey *hostkey_algs[] = { &ssh_dss };
102
103extern struct ssh_mac ssh_sha1;
104
105SHA_State exhash;
106
107static void nullmac_sesskey(unsigned char *key, int len) { }
108static void nullmac_generate(unsigned char *blk, int len, unsigned long seq) { }
109static int nullmac_verify(unsigned char *blk, int len, unsigned long seq) { return 1; }
110struct ssh_mac ssh_mac_none = {
111 nullmac_sesskey, nullmac_generate, nullmac_verify, "none", 0
112};
113struct ssh_mac *macs[] = { &ssh_sha1, &ssh_mac_none };
114
115struct ssh_compress ssh_comp_none = {
116 "none"
117};
118struct ssh_compress *compressions[] = { &ssh_comp_none };
119
374330e2 120static SOCKET s = INVALID_SOCKET;
121
122static unsigned char session_key[32];
123static struct ssh_cipher *cipher = NULL;
e5574168 124static struct ssh_cipher *cscipher = NULL;
125static struct ssh_cipher *sccipher = NULL;
126static struct ssh_mac *csmac = NULL;
127static struct ssh_mac *scmac = NULL;
128static struct ssh_compress *cscomp = NULL;
129static struct ssh_compress *sccomp = NULL;
130static struct ssh_kex *kex = NULL;
131static struct ssh_hostkey *hostkey = NULL;
fb09bf1c 132int scp_flags = 0;
85ee8208 133int (*ssh_get_password)(const char *prompt, char *str, int maxlen) = NULL;
374330e2 134
135static char *savedhost;
136
137static enum {
138 SSH_STATE_BEFORE_SIZE,
139 SSH_STATE_INTERMED,
21248260 140 SSH_STATE_SESSION,
141 SSH_STATE_CLOSED
374330e2 142} ssh_state = SSH_STATE_BEFORE_SIZE;
143
144static int size_needed = FALSE;
145
146static void s_write (char *buf, int len) {
147 while (len > 0) {
148 int i = send (s, buf, len, 0);
fb09bf1c 149 if (IS_SCP) {
150 noise_ultralight(i);
151 if (i <= 0)
152 fatalbox("Lost connection while sending");
153 }
374330e2 154 if (i > 0)
155 len -= i, buf += i;
156 }
157}
158
159static int s_read (char *buf, int len) {
160 int ret = 0;
161 while (len > 0) {
162 int i = recv (s, buf, len, 0);
fb09bf1c 163 if (IS_SCP)
164 noise_ultralight(i);
374330e2 165 if (i > 0)
166 len -= i, buf += i, ret += i;
167 else
168 return i;
169 }
170 return ret;
171}
172
173static void c_write (char *buf, int len) {
fb09bf1c 174 if (IS_SCP) {
175 if (len > 0 && buf[len-1] == '\n') len--;
176 if (len > 0 && buf[len-1] == '\r') len--;
177 if (len > 0) { fwrite(buf, len, 1, stderr); fputc('\n', stderr); }
178 return;
179 }
c9def1b8 180 while (len--)
181 c_write1(*buf++);
374330e2 182}
183
184struct Packet {
185 long length;
186 int type;
374330e2 187 unsigned char *data;
188 unsigned char *body;
e5574168 189 long savedpos;
374330e2 190 long maxlen;
191};
192
fb09bf1c 193static struct Packet pktin = { 0, 0, NULL, NULL, 0 };
194static struct Packet pktout = { 0, 0, NULL, NULL, 0 };
374330e2 195
e5574168 196static void (*ssh_protocol)(unsigned char *in, int inlen, int ispkt);
197static void ssh1_protocol(unsigned char *in, int inlen, int ispkt);
198static void ssh2_protocol(unsigned char *in, int inlen, int ispkt);
374330e2 199static void ssh_size(void);
200
e5574168 201static int (*s_rdpkt)(unsigned char **data, int *datalen);
fb09bf1c 202
203/*
204 * Collect incoming data in the incoming packet buffer.
e5574168 205 * Decipher and verify the packet when it is completely read.
206 * Drop SSH1_MSG_DEBUG and SSH1_MSG_IGNORE packets.
fb09bf1c 207 * Update the *data and *datalen variables.
208 * Return the additional nr of bytes needed, or 0 when
209 * a complete packet is available.
210 */
e5574168 211static int ssh1_rdpkt(unsigned char **data, int *datalen)
fb09bf1c 212{
213 static long len, pad, biglen, to_read;
572f871e 214 static unsigned long realcrc, gotcrc;
fb09bf1c 215 static unsigned char *p;
216 static int i;
374330e2 217
218 crBegin;
374330e2 219
fb09bf1c 220next_packet:
37508af4 221
fb09bf1c 222 pktin.type = 0;
223 pktin.length = 0;
374330e2 224
fb09bf1c 225 for (i = len = 0; i < 4; i++) {
226 while ((*datalen) == 0)
227 crReturn(4-i);
228 len = (len << 8) + **data;
229 (*data)++, (*datalen)--;
230 }
374330e2 231
fb09bf1c 232#ifdef FWHACK
233 if (len == 0x52656d6f) { /* "Remo"te server has closed ... */
234 len = 0x300; /* big enough to carry to end */
235 }
236#endif
374330e2 237
fb09bf1c 238 pad = 8 - (len % 8);
239 biglen = len + pad;
240 pktin.length = len - 5;
241
242 if (pktin.maxlen < biglen) {
243 pktin.maxlen = biglen;
e5574168 244 pktin.data = (pktin.data == NULL ? malloc(biglen+APIEXTRA) :
245 realloc(pktin.data, biglen+APIEXTRA));
fb09bf1c 246 if (!pktin.data)
247 fatalbox("Out of memory");
248 }
374330e2 249
fb09bf1c 250 to_read = biglen;
251 p = pktin.data;
252 while (to_read > 0) {
253 static int chunk;
254 chunk = to_read;
255 while ((*datalen) == 0)
256 crReturn(to_read);
257 if (chunk > (*datalen))
258 chunk = (*datalen);
259 memcpy(p, *data, chunk);
260 *data += chunk;
261 *datalen -= chunk;
262 p += chunk;
263 to_read -= chunk;
264 }
374330e2 265
fb09bf1c 266 if (cipher)
267 cipher->decrypt(pktin.data, biglen);
374330e2 268
fb09bf1c 269 pktin.type = pktin.data[pad];
270 pktin.body = pktin.data + pad + 1;
374330e2 271
fb09bf1c 272 realcrc = crc32(pktin.data, biglen-4);
273 gotcrc = GET_32BIT(pktin.data+biglen-4);
274 if (gotcrc != realcrc) {
275 fatalbox("Incorrect CRC received on packet");
276 }
572f871e 277
e5574168 278 if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
279 pktin.type == SSH1_SMSG_STDERR_DATA ||
280 pktin.type == SSH1_MSG_DEBUG ||
281 pktin.type == SSH1_SMSG_AUTH_TIS_CHALLENGE) {
fb09bf1c 282 long strlen = GET_32BIT(pktin.body);
283 if (strlen + 4 != pktin.length)
284 fatalbox("Received data packet with bogus string length");
285 }
286
e5574168 287 if (pktin.type == SSH1_MSG_DEBUG) {
fb09bf1c 288 /* log debug message */
289 char buf[80];
290 int strlen = GET_32BIT(pktin.body);
291 strcpy(buf, "Remote: ");
292 if (strlen > 70) strlen = 70;
293 memcpy(buf+8, pktin.body+4, strlen);
294 buf[8+strlen] = '\0';
295 logevent(buf);
296 goto next_packet;
e5574168 297 } else if (pktin.type == SSH1_MSG_IGNORE) {
fb09bf1c 298 /* do nothing */
299 goto next_packet;
300 }
301
302 crFinish(0);
303}
304
e5574168 305static int ssh2_rdpkt(unsigned char **data, int *datalen)
306{
307 static long len, pad, payload, packetlen, maclen;
308 static int i;
309 static int cipherblk;
310 static unsigned long incoming_sequence = 0;
311
312 crBegin;
313
314next_packet:
315
316 pktin.type = 0;
317 pktin.length = 0;
318
319 if (cipher)
320 cipherblk = cipher->blksize;
321 else
322 cipherblk = 8;
323 if (cipherblk < 8)
324 cipherblk = 8;
325
326 if (pktin.maxlen < cipherblk) {
327 pktin.maxlen = cipherblk;
328 pktin.data = (pktin.data == NULL ? malloc(cipherblk+APIEXTRA) :
329 realloc(pktin.data, cipherblk+APIEXTRA));
330 if (!pktin.data)
331 fatalbox("Out of memory");
332 }
333
334 /*
335 * Acquire and decrypt the first block of the packet. This will
336 * contain the length and padding details.
337 */
338 for (i = len = 0; i < cipherblk; i++) {
339 while ((*datalen) == 0)
340 crReturn(cipherblk-i);
341 pktin.data[i] = *(*data)++;
342 (*datalen)--;
343 }
344#ifdef FWHACK
345 if (!memcmp(pktin.data, "Remo", 4)) {/* "Remo"te server has closed ... */
346 /* FIXME */
347 }
348#endif
349 if (sccipher)
350 sccipher->decrypt(pktin.data, cipherblk);
351
352 /*
353 * Now get the length and padding figures.
354 */
355 len = GET_32BIT(pktin.data);
356 pad = pktin.data[4];
357
358 /*
359 * This enables us to deduce the payload length.
360 */
361 payload = len - pad - 1;
362
363 pktin.length = payload + 5;
364
365 /*
366 * So now we can work out the total packet length.
367 */
368 packetlen = len + 4;
369 maclen = scmac ? scmac->len : 0;
370
371 /*
372 * Adjust memory allocation if packet is too big.
373 */
374 if (pktin.maxlen < packetlen) {
375 pktin.maxlen = packetlen;
376 pktin.data = (pktin.data == NULL ? malloc(packetlen+APIEXTRA) :
377 realloc(pktin.data, packetlen+APIEXTRA));
378 if (!pktin.data)
379 fatalbox("Out of memory");
380 }
381
382 /*
383 * Read and decrypt the remainder of the packet.
384 */
385 for (i = cipherblk; i < packetlen + maclen; i++) {
386 while ((*datalen) == 0)
387 crReturn(packetlen + maclen - i);
388 pktin.data[i] = *(*data)++;
389 (*datalen)--;
390 }
391 /* Decrypt everything _except_ the MAC. */
392 if (sccipher)
393 sccipher->decrypt(pktin.data + cipherblk, packetlen - cipherblk);
394
395 /*
396 * Check the MAC.
397 */
398 if (scmac && !scmac->verify(pktin.data, incoming_sequence++, len+4))
399 fatalbox("Incorrect MAC received on packet");
400
401 pktin.savedpos = 6;
402 pktin.type = pktin.data[5];
403#if 0
404 debug(("Got packet len=%d pad=%d\r\n", len, pad));
405 for (i = 0; i < payload; i++)
406 debug((" %02x", (unsigned char)pktin.data[i]));
407 debug(("\r\n"));
408#endif
409
410 /*
411 * FIXME: handle IGNORE and DEBUG messages.
412 */
413
414 crFinish(0);
415}
416
fb09bf1c 417static void ssh_gotdata(unsigned char *data, int datalen)
418{
419 while (datalen > 0) {
85ee8208 420 if ( s_rdpkt(&data, &datalen) == 0 ) {
374330e2 421 ssh_protocol(NULL, 0, 1);
85ee8208 422 if (ssh_state == SSH_STATE_CLOSED) {
423 return;
424 }
425 }
374330e2 426 }
374330e2 427}
428
fb09bf1c 429
374330e2 430static void s_wrpkt_start(int type, int len) {
431 int pad, biglen;
432
433 len += 5; /* type and CRC */
434 pad = 8 - (len%8);
435 biglen = len + pad;
436
437 pktout.length = len-5;
438 if (pktout.maxlen < biglen) {
439 pktout.maxlen = biglen;
8f203108 440#ifdef MSCRYPTOAPI
fb09bf1c 441 /* Allocate enough buffer space for extra block
8f203108 442 * for MS CryptEncrypt() */
fb09bf1c 443 pktout.data = (pktout.data == NULL ? malloc(biglen+12) :
444 realloc(pktout.data, biglen+12));
8f203108 445#else
c1f5f956 446 pktout.data = (pktout.data == NULL ? malloc(biglen+4) :
447 realloc(pktout.data, biglen+4));
8f203108 448#endif
374330e2 449 if (!pktout.data)
450 fatalbox("Out of memory");
451 }
452
453 pktout.type = type;
454 pktout.body = pktout.data+4+pad+1;
455}
456
457static void s_wrpkt(void) {
458 int pad, len, biglen, i;
459 unsigned long crc;
460
461 len = pktout.length + 5; /* type and CRC */
462 pad = 8 - (len%8);
463 biglen = len + pad;
464
465 pktout.body[-1] = pktout.type;
466 for (i=0; i<pad; i++)
467 pktout.data[i+4] = random_byte();
468 crc = crc32(pktout.data+4, biglen-4);
fb09bf1c 469 PUT_32BIT(pktout.data+biglen, crc);
470 PUT_32BIT(pktout.data, len);
374330e2 471
472 if (cipher)
473 cipher->encrypt(pktout.data+4, biglen);
474
475 s_write(pktout.data, biglen+4);
476}
477
fb09bf1c 478/*
479 * Construct a packet with the specified contents and
480 * send it to the server.
481 */
482static void send_packet(int pkttype, ...)
483{
484 va_list args;
485 unsigned char *p, *argp, argchar;
486 unsigned long argint;
487 int pktlen, argtype, arglen;
488
489 pktlen = 0;
490 va_start(args, pkttype);
491 while ((argtype = va_arg(args, int)) != PKT_END) {
492 switch (argtype) {
493 case PKT_INT:
494 (void) va_arg(args, int);
495 pktlen += 4;
496 break;
497 case PKT_CHAR:
498 (void) va_arg(args, char);
499 pktlen++;
500 break;
501 case PKT_DATA:
502 (void) va_arg(args, unsigned char *);
503 arglen = va_arg(args, int);
504 pktlen += arglen;
505 break;
506 case PKT_STR:
507 argp = va_arg(args, unsigned char *);
508 arglen = strlen(argp);
509 pktlen += 4 + arglen;
510 break;
511 default:
512 assert(0);
513 }
514 }
515 va_end(args);
516
517 s_wrpkt_start(pkttype, pktlen);
518 p = pktout.body;
519
520 va_start(args, pkttype);
521 while ((argtype = va_arg(args, int)) != PKT_END) {
522 switch (argtype) {
523 case PKT_INT:
524 argint = va_arg(args, int);
525 PUT_32BIT(p, argint);
526 p += 4;
527 break;
528 case PKT_CHAR:
529 argchar = va_arg(args, unsigned char);
530 *p = argchar;
531 p++;
532 break;
533 case PKT_DATA:
534 argp = va_arg(args, unsigned char *);
535 arglen = va_arg(args, int);
536 memcpy(p, argp, arglen);
537 p += arglen;
538 break;
539 case PKT_STR:
540 argp = va_arg(args, unsigned char *);
541 arglen = strlen(argp);
542 PUT_32BIT(p, arglen);
543 memcpy(p + 4, argp, arglen);
544 p += 4 + arglen;
545 break;
546 }
547 }
548 va_end(args);
549
550 s_wrpkt();
551}
552
553
554/*
555 * Connect to specified host and port.
556 * Returns an error message, or NULL on success.
557 * Also places the canonical host name into `realhost'.
558 */
559static char *connect_to_host(char *host, int port, char **realhost)
560{
561 SOCKADDR_IN addr;
562 struct hostent *h;
563 unsigned long a;
564#ifdef FWHACK
565 char *FWhost;
566 int FWport;
567#endif
568
569 savedhost = malloc(1+strlen(host));
570 if (!savedhost)
571 fatalbox("Out of memory");
572 strcpy(savedhost, host);
573
574 if (port < 0)
575 port = 22; /* default ssh port */
576
577#ifdef FWHACK
578 FWhost = host;
579 FWport = port;
580 host = FWSTR;
581 port = 23;
582#endif
583
584 /*
585 * Try to find host.
586 */
587 if ( (a = inet_addr(host)) == (unsigned long) INADDR_NONE) {
588 if ( (h = gethostbyname(host)) == NULL)
589 switch (WSAGetLastError()) {
590 case WSAENETDOWN: return "Network is down";
591 case WSAHOST_NOT_FOUND: case WSANO_DATA:
592 return "Host does not exist";
593 case WSATRY_AGAIN: return "Host not found";
594 default: return "gethostbyname: unknown error";
595 }
596 memcpy (&a, h->h_addr, sizeof(a));
597 *realhost = h->h_name;
598 } else
599 *realhost = host;
600#ifdef FWHACK
601 *realhost = FWhost;
602#endif
603 a = ntohl(a);
604
605 /*
606 * Open socket.
607 */
608 s = socket(AF_INET, SOCK_STREAM, 0);
609 if (s == INVALID_SOCKET)
610 switch (WSAGetLastError()) {
611 case WSAENETDOWN: return "Network is down";
612 case WSAEAFNOSUPPORT: return "TCP/IP support not present";
613 default: return "socket(): unknown error";
614 }
615
616 /*
617 * Bind to local address.
618 */
619 addr.sin_family = AF_INET;
620 addr.sin_addr.s_addr = htonl(INADDR_ANY);
621 addr.sin_port = htons(0);
622 if (bind (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
623 switch (WSAGetLastError()) {
624 case WSAENETDOWN: return "Network is down";
625 default: return "bind(): unknown error";
626 }
627
628 /*
629 * Connect to remote address.
630 */
631 addr.sin_addr.s_addr = htonl(a);
632 addr.sin_port = htons((short)port);
633 if (connect (s, (struct sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
634 switch (WSAGetLastError()) {
635 case WSAENETDOWN: return "Network is down";
636 case WSAECONNREFUSED: return "Connection refused";
637 case WSAENETUNREACH: return "Network is unreachable";
638 case WSAEHOSTUNREACH: return "No route to host";
639 default: return "connect(): unknown error";
640 }
641
642#ifdef FWHACK
643 send(s, "connect ", 8, 0);
644 send(s, FWhost, strlen(FWhost), 0);
645 {
646 char buf[20];
647 sprintf(buf, " %d\n", FWport);
648 send (s, buf, strlen(buf), 0);
649 }
650#endif
651
652 return NULL;
653}
654
9697bfd2 655static int ssh_versioncmp(char *a, char *b) {
656 char *ae, *be;
657 unsigned long av, bv;
658
43aa02a7 659 av = strtoul(a, &ae, 10);
660 bv = strtoul(b, &be, 10);
9697bfd2 661 if (av != bv) return (av < bv ? -1 : +1);
662 if (*ae == '.') ae++;
663 if (*be == '.') be++;
43aa02a7 664 av = strtoul(ae, &ae, 10);
665 bv = strtoul(be, &be, 10);
9697bfd2 666 if (av != bv) return (av < bv ? -1 : +1);
667 return 0;
668}
669
e5574168 670
671/*
672 * Utility routine for putting an SSH-protocol `string' into a SHA
673 * state.
674 */
675#include <stdio.h>
676void sha_string(SHA_State *s, void *str, int len) {
677 unsigned char lenblk[4];
678static FILE *fp;
679 PUT_32BIT(lenblk, len);
680if (!fp) fp = fopen("h:\\statham\\windows\\putty\\data","wb");
681fwrite(lenblk, 4, 1, fp);
682 SHA_Bytes(s, lenblk, 4);
683fwrite(str, len, 1, fp);
684fflush(fp);
685 SHA_Bytes(s, str, len);
686}
687
374330e2 688static int do_ssh_init(void) {
c5e9c988 689 char c, *vsp;
374330e2 690 char version[10];
c5e9c988 691 char vstring[80];
692 char vlog[sizeof(vstring)+20];
374330e2 693 int i;
694
695#ifdef FWHACK
696 i = 0;
697 while (s_read(&c, 1) == 1) {
698 if (c == 'S' && i < 2) i++;
699 else if (c == 'S' && i == 2) i = 2;
700 else if (c == 'H' && i == 2) break;
701 else i = 0;
702 }
703#else
704 if (s_read(&c,1) != 1 || c != 'S') return 0;
705 if (s_read(&c,1) != 1 || c != 'S') return 0;
706 if (s_read(&c,1) != 1 || c != 'H') return 0;
707#endif
c5e9c988 708 strcpy(vstring, "SSH-");
709 vsp = vstring+4;
374330e2 710 if (s_read(&c,1) != 1 || c != '-') return 0;
711 i = 0;
712 while (1) {
713 if (s_read(&c,1) != 1)
714 return 0;
c5e9c988 715 if (vsp < vstring+sizeof(vstring)-1)
716 *vsp++ = c;
374330e2 717 if (i >= 0) {
718 if (c == '-') {
719 version[i] = '\0';
720 i = -1;
721 } else if (i < sizeof(version)-1)
722 version[i++] = c;
723 }
724 else if (c == '\n')
725 break;
726 }
727
c5e9c988 728 *vsp = 0;
729 sprintf(vlog, "Server version: %s", vstring);
730 vlog[strcspn(vlog, "\r\n")] = '\0';
731 logevent(vlog);
732
e5574168 733 if (ssh_versioncmp(version, "1.99") >= 0) {
734 /*
735 * This is a v2 server. Begin v2 protocol.
736 */
737 char *verstring = "SSH-2.0-PuTTY";
738 SHA_Init(&exhash);
739 /*
740 * Hash our version string and their version string.
741 */
742 sha_string(&exhash, verstring, strlen(verstring));
743 sha_string(&exhash, vstring, strcspn(vstring, "\r\n"));
744 sprintf(vstring, "%s\n", verstring);
745 sprintf(vlog, "We claim version: %s", verstring);
746 logevent(vlog);
747 logevent("Using SSH protocol version 2");
748 s_write(vstring, strlen(vstring));
749 ssh_protocol = ssh2_protocol;
750 s_rdpkt = ssh2_rdpkt;
751 } else {
752 /*
753 * This is a v1 server. Begin v1 protocol.
754 */
755 sprintf(vstring, "SSH-%s-PuTTY\n",
756 (ssh_versioncmp(version, "1.5") <= 0 ? version : "1.5"));
757 sprintf(vlog, "We claim version: %s", vstring);
758 vlog[strcspn(vlog, "\r\n")] = '\0';
759 logevent(vlog);
760 logevent("Using SSH protocol version 1");
761 s_write(vstring, strlen(vstring));
762 ssh_protocol = ssh1_protocol;
763 s_rdpkt = ssh1_rdpkt;
764 }
fef97f43 765 return 1;
374330e2 766}
767
fb09bf1c 768/*
769 * Handle the key exchange and user authentication phases.
770 */
e5574168 771static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
fb09bf1c 772{
374330e2 773 int i, j, len;
774 unsigned char session_id[16];
775 unsigned char *rsabuf, *keystr1, *keystr2;
776 unsigned char cookie[8];
777 struct RSAKey servkey, hostkey;
778 struct MD5Context md5c;
ccbfb941 779 static unsigned long supported_ciphers_mask, supported_auths_mask;
bea1ef5f 780 int cipher_type;
374330e2 781
374330e2 782 crBegin;
783
fb09bf1c 784 if (!ispkt) crWaitUntil(ispkt);
374330e2 785
e5574168 786 if (pktin.type != SSH1_SMSG_PUBLIC_KEY)
374330e2 787 fatalbox("Public key packet not received");
788
c5e9c988 789 logevent("Received public keys");
374330e2 790
c5e9c988 791 memcpy(cookie, pktin.body, 8);
374330e2 792
793 i = makekey(pktin.body+8, &servkey, &keystr1);
374330e2 794 j = makekey(pktin.body+8+i, &hostkey, &keystr2);
795
c5e9c988 796 /*
797 * Hash the host key and print the hash in the log box. Just as
798 * a last resort in case the registry's host key checking is
799 * compromised, we'll allow the user some ability to verify
800 * host keys by eye.
801 */
802 MD5Init(&md5c);
803 MD5Update(&md5c, keystr2, hostkey.bytes);
804 MD5Final(session_id, &md5c);
805 {
806 char logmsg[80];
807 int i;
808 logevent("Host key MD5 is:");
809 strcpy(logmsg, " ");
810 for (i = 0; i < 16; i++)
811 sprintf(logmsg+strlen(logmsg), "%02x", session_id[i]);
812 logevent(logmsg);
813 }
814
fb09bf1c 815 supported_ciphers_mask = GET_32BIT(pktin.body+12+i+j);
816 supported_auths_mask = GET_32BIT(pktin.body+16+i+j);
bea1ef5f 817
c5e9c988 818 MD5Init(&md5c);
374330e2 819 MD5Update(&md5c, keystr2, hostkey.bytes);
820 MD5Update(&md5c, keystr1, servkey.bytes);
821 MD5Update(&md5c, pktin.body, 8);
374330e2 822 MD5Final(session_id, &md5c);
823
824 for (i=0; i<32; i++)
825 session_key[i] = random_byte();
826
827 len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes);
828
829 rsabuf = malloc(len);
830 if (!rsabuf)
831 fatalbox("Out of memory");
832
89ee5268 833 /*
834 * Verify the host key.
835 */
836 {
837 /*
838 * First format the key into a string.
839 */
840 int len = rsastr_len(&hostkey);
841 char *keystr = malloc(len);
842 if (!keystr)
843 fatalbox("Out of memory");
844 rsastr_fmt(keystr, &hostkey);
845 verify_ssh_host_key(savedhost, keystr);
846 free(keystr);
847 }
374330e2 848
849 for (i=0; i<32; i++) {
850 rsabuf[i] = session_key[i];
851 if (i < 16)
852 rsabuf[i] ^= session_id[i];
853 }
854
855 if (hostkey.bytes > servkey.bytes) {
856 rsaencrypt(rsabuf, 32, &servkey);
857 rsaencrypt(rsabuf, servkey.bytes, &hostkey);
858 } else {
859 rsaencrypt(rsabuf, 32, &hostkey);
860 rsaencrypt(rsabuf, hostkey.bytes, &servkey);
861 }
862
c5e9c988 863 logevent("Encrypted session key");
864
bea1ef5f 865 cipher_type = cfg.cipher == CIPHER_BLOWFISH ? SSH_CIPHER_BLOWFISH :
9697bfd2 866 cfg.cipher == CIPHER_DES ? SSH_CIPHER_DES :
bea1ef5f 867 SSH_CIPHER_3DES;
868 if ((supported_ciphers_mask & (1 << cipher_type)) == 0) {
869 c_write("Selected cipher not supported, falling back to 3DES\r\n", 53);
870 cipher_type = SSH_CIPHER_3DES;
871 }
c5e9c988 872 switch (cipher_type) {
873 case SSH_CIPHER_3DES: logevent("Using 3DES encryption"); break;
874 case SSH_CIPHER_DES: logevent("Using single-DES encryption"); break;
875 case SSH_CIPHER_BLOWFISH: logevent("Using Blowfish encryption"); break;
876 }
bea1ef5f 877
e5574168 878 send_packet(SSH1_CMSG_SESSION_KEY,
fb09bf1c 879 PKT_CHAR, cipher_type,
880 PKT_DATA, cookie, 8,
881 PKT_CHAR, (len*8) >> 8, PKT_CHAR, (len*8) & 0xFF,
882 PKT_DATA, rsabuf, len,
883 PKT_INT, 0,
884 PKT_END);
885
c5e9c988 886 logevent("Trying to enable encryption...");
374330e2 887
888 free(rsabuf);
889
bea1ef5f 890 cipher = cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish :
9697bfd2 891 cipher_type == SSH_CIPHER_DES ? &ssh_des :
bea1ef5f 892 &ssh_3des;
374330e2 893 cipher->sesskey(session_key);
894
fb09bf1c 895 crWaitUntil(ispkt);
374330e2 896
e5574168 897 if (pktin.type != SSH1_SMSG_SUCCESS)
374330e2 898 fatalbox("Encryption not successfully enabled");
899
c5e9c988 900 logevent("Successfully started encryption");
901
374330e2 902 fflush(stdout);
903 {
904 static char username[100];
905 static int pos = 0;
906 static char c;
fb09bf1c 907 if (!IS_SCP && !*cfg.username) {
374330e2 908 c_write("login as: ", 10);
909 while (pos >= 0) {
fb09bf1c 910 crWaitUntil(!ispkt);
374330e2 911 while (inlen--) switch (c = *in++) {
912 case 10: case 13:
913 username[pos] = 0;
914 pos = -1;
915 break;
916 case 8: case 127:
917 if (pos > 0) {
918 c_write("\b \b", 3);
919 pos--;
920 }
921 break;
922 case 21: case 27:
923 while (pos > 0) {
924 c_write("\b \b", 3);
925 pos--;
926 }
927 break;
928 case 3: case 4:
929 random_save_seed();
930 exit(0);
931 break;
932 default:
40d24aa6 933 if (((c >= ' ' && c <= '~') ||
934 ((unsigned char)c >= 160)) && pos < 40) {
374330e2 935 username[pos++] = c;
936 c_write(&c, 1);
937 }
938 break;
939 }
940 }
941 c_write("\r\n", 2);
942 username[strcspn(username, "\n\r")] = '\0';
943 } else {
944 char stuff[200];
945 strncpy(username, cfg.username, 99);
946 username[99] = '\0';
fb09bf1c 947 if (!IS_SCP) {
948 sprintf(stuff, "Sent username \"%s\".\r\n", username);
949 c_write(stuff, strlen(stuff));
950 }
374330e2 951 }
fb09bf1c 952
e5574168 953 send_packet(SSH1_CMSG_USER, PKT_STR, username, PKT_END);
c5e9c988 954 {
955 char userlog[20+sizeof(username)];
956 sprintf(userlog, "Sent username \"%s\"", username);
957 logevent(userlog);
958 }
374330e2 959 }
960
fb09bf1c 961 crWaitUntil(ispkt);
374330e2 962
e5574168 963 while (pktin.type == SSH1_SMSG_FAILURE) {
374330e2 964 static char password[100];
965 static int pos;
966 static char c;
ccbfb941 967 static int pwpkt_type;
968
969 /*
970 * Show password prompt, having first obtained it via a TIS
971 * exchange if we're doing TIS authentication.
972 */
e5574168 973 pwpkt_type = SSH1_CMSG_AUTH_PASSWORD;
fb09bf1c 974
975 if (IS_SCP) {
976 char prompt[200];
977 sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost);
85ee8208 978 if (!ssh_get_password(prompt, password, sizeof(password))) {
979 /*
980 * get_password failed to get a password (for
981 * example because one was supplied on the command
982 * line which has already failed to work).
983 * Terminate.
984 */
985 logevent("No more passwords to try");
986 ssh_state = SSH_STATE_CLOSED;
987 crReturn(1);
988 }
fb09bf1c 989 } else {
990
e5574168 991 if (pktin.type == SSH1_SMSG_FAILURE &&
ccbfb941 992 cfg.try_tis_auth &&
e5574168 993 (supported_auths_mask & (1<<SSH1_AUTH_TIS))) {
994 pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
c5e9c988 995 logevent("Requested TIS authentication");
e5574168 996 send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
fb09bf1c 997 crWaitUntil(ispkt);
e5574168 998 if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
c5e9c988 999 logevent("TIS authentication declined");
ccbfb941 1000 c_write("TIS authentication refused.\r\n", 29);
1001 } else {
1002 int challengelen = ((pktin.body[0] << 24) |
1003 (pktin.body[1] << 16) |
1004 (pktin.body[2] << 8) |
1005 (pktin.body[3]));
c5e9c988 1006 logevent("Received TIS challenge");
ccbfb941 1007 c_write(pktin.body+4, challengelen);
1008 }
1009 }
e5574168 1010 if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD)
ccbfb941 1011 c_write("password: ", 10);
1012
374330e2 1013 pos = 0;
1014 while (pos >= 0) {
fb09bf1c 1015 crWaitUntil(!ispkt);
374330e2 1016 while (inlen--) switch (c = *in++) {
1017 case 10: case 13:
1018 password[pos] = 0;
1019 pos = -1;
1020 break;
1021 case 8: case 127:
1022 if (pos > 0)
1023 pos--;
1024 break;
1025 case 21: case 27:
1026 pos = 0;
1027 break;
1028 case 3: case 4:
1029 random_save_seed();
1030 exit(0);
1031 break;
1032 default:
40d24aa6 1033 if (((c >= ' ' && c <= '~') ||
1034 ((unsigned char)c >= 160)) && pos < 40)
374330e2 1035 password[pos++] = c;
1036 break;
1037 }
1038 }
1039 c_write("\r\n", 2);
fb09bf1c 1040
1041 }
1042
1043 send_packet(pwpkt_type, PKT_STR, password, PKT_END);
c5e9c988 1044 logevent("Sent password");
374330e2 1045 memset(password, 0, strlen(password));
fb09bf1c 1046 crWaitUntil(ispkt);
e5574168 1047 if (pktin.type == SSH1_SMSG_FAILURE) {
374330e2 1048 c_write("Access denied\r\n", 15);
c5e9c988 1049 logevent("Authentication refused");
e5574168 1050 } else if (pktin.type == SSH1_MSG_DISCONNECT) {
fb09bf1c 1051 logevent("Received disconnect request");
85ee8208 1052 ssh_state = SSH_STATE_CLOSED;
1053 crReturn(1);
e5574168 1054 } else if (pktin.type != SSH1_SMSG_SUCCESS) {
374330e2 1055 fatalbox("Strange packet received, type %d", pktin.type);
1056 }
1057 }
1058
c5e9c988 1059 logevent("Authentication successful");
1060
fb09bf1c 1061 crFinish(1);
1062}
1063
e5574168 1064static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
fb09bf1c 1065 crBegin;
1066
1067 random_init();
1068
e5574168 1069 while (!do_ssh1_login(in, inlen, ispkt)) {
fb09bf1c 1070 crReturnV;
85ee8208 1071 }
1072 if (ssh_state == SSH_STATE_CLOSED)
1073 crReturnV;
fb09bf1c 1074
fef97f43 1075 if (!cfg.nopty) {
e5574168 1076 send_packet(SSH1_CMSG_REQUEST_PTY,
fb09bf1c 1077 PKT_STR, cfg.termtype,
1078 PKT_INT, rows, PKT_INT, cols,
1079 PKT_INT, 0, PKT_INT, 0,
1080 PKT_CHAR, 0,
1081 PKT_END);
fef97f43 1082 ssh_state = SSH_STATE_INTERMED;
1083 do { crReturnV; } while (!ispkt);
e5574168 1084 if (pktin.type != SSH1_SMSG_SUCCESS && pktin.type != SSH1_SMSG_FAILURE) {
fef97f43 1085 fatalbox("Protocol confusion");
e5574168 1086 } else if (pktin.type == SSH1_SMSG_FAILURE) {
fef97f43 1087 c_write("Server refused to allocate pty\r\n", 32);
1088 }
c5e9c988 1089 logevent("Allocated pty");
374330e2 1090 }
1091
e5574168 1092 send_packet(SSH1_CMSG_EXEC_SHELL, PKT_END);
c5e9c988 1093 logevent("Started session");
374330e2 1094
1095 ssh_state = SSH_STATE_SESSION;
1096 if (size_needed)
1097 ssh_size();
1098
1099 while (1) {
1100 crReturnV;
1101 if (ispkt) {
e5574168 1102 if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
1103 pktin.type == SSH1_SMSG_STDERR_DATA) {
fb09bf1c 1104 long len = GET_32BIT(pktin.body);
1105 c_write(pktin.body+4, len);
e5574168 1106 } else if (pktin.type == SSH1_MSG_DISCONNECT) {
21248260 1107 ssh_state = SSH_STATE_CLOSED;
c5e9c988 1108 logevent("Received disconnect request");
e5574168 1109 } else if (pktin.type == SSH1_SMSG_SUCCESS) {
972a41c8 1110 /* may be from EXEC_SHELL on some servers */
e5574168 1111 } else if (pktin.type == SSH1_SMSG_FAILURE) {
972a41c8 1112 /* may be from EXEC_SHELL on some servers
374330e2 1113 * if no pty is available or in other odd cases. Ignore */
e5574168 1114 } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) {
1115 send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);
374330e2 1116 } else {
1117 fatalbox("Strange packet received: type %d", pktin.type);
1118 }
1119 } else {
e5574168 1120 send_packet(SSH1_CMSG_STDIN_DATA,
fb09bf1c 1121 PKT_INT, inlen, PKT_DATA, in, inlen, PKT_END);
374330e2 1122 }
1123 }
1124
1125 crFinishV;
1126}
1127
1128/*
e5574168 1129 * SSH2 packet construction functions.
1130 */
1131void ssh2_pkt_adddata(void *data, int len) {
1132 pktout.length += len;
1133 if (pktout.maxlen < pktout.length) {
1134 pktout.maxlen = pktout.length + 256;
1135 pktout.data = (pktout.data == NULL ? malloc(pktout.maxlen+APIEXTRA) :
1136 realloc(pktout.data, pktout.maxlen+APIEXTRA));
1137 if (!pktout.data)
1138 fatalbox("Out of memory");
1139 }
1140 memcpy(pktout.data+pktout.length-len, data, len);
1141}
1142void ssh2_pkt_addbyte(unsigned char byte) {
1143 ssh2_pkt_adddata(&byte, 1);
1144}
1145void ssh2_pkt_init(int pkt_type) {
1146 pktout.length = 5;
1147 ssh2_pkt_addbyte((unsigned char)pkt_type);
1148}
1149void ssh2_pkt_addbool(unsigned char value) {
1150 ssh2_pkt_adddata(&value, 1);
1151}
1152void ssh2_pkt_adduint32(unsigned long value) {
1153 unsigned char x[4];
1154 PUT_32BIT(x, value);
1155 ssh2_pkt_adddata(x, 4);
1156}
1157void ssh2_pkt_addstring_start(void) {
1158 ssh2_pkt_adduint32(0);
1159 pktout.savedpos = pktout.length;
1160}
1161void ssh2_pkt_addstring_str(char *data) {
1162 ssh2_pkt_adddata(data, strlen(data));
1163 PUT_32BIT(pktout.data + pktout.savedpos - 4,
1164 pktout.length - pktout.savedpos);
1165}
1166void ssh2_pkt_addstring_data(char *data, int len) {
1167 ssh2_pkt_adddata(data, len);
1168 PUT_32BIT(pktout.data + pktout.savedpos - 4,
1169 pktout.length - pktout.savedpos);
1170}
1171void ssh2_pkt_addstring(char *data) {
1172 ssh2_pkt_addstring_start();
1173 ssh2_pkt_addstring_str(data);
1174}
1175char *ssh2_mpint_fmt(Bignum b, int *len) {
1176 unsigned char *p;
1177 int i, n = b[0];
1178 p = malloc(n * 2 + 1);
1179 if (!p)
1180 fatalbox("out of memory");
1181 p[0] = 0;
1182 for (i = 0; i < n; i++) {
1183 p[i*2+1] = (b[n-i] >> 8) & 0xFF;
1184 p[i*2+2] = (b[n-i] ) & 0xFF;
1185 }
1186 i = 0;
1187 while (p[i] == 0 && (p[i+1] & 0x80) == 0)
1188 i++;
1189 memmove(p, p+i, n*2+1-i);
1190 *len = n*2+1-i;
1191 return p;
1192}
1193void ssh2_pkt_addmp(Bignum b) {
1194 unsigned char *p;
1195 int len;
1196 p = ssh2_mpint_fmt(b, &len);
1197 ssh2_pkt_addstring_start();
1198 ssh2_pkt_addstring_data(p, len);
1199 free(p);
1200}
1201void ssh2_pkt_send(void) {
1202 int cipherblk, maclen, padding, i;
1203 unsigned long outgoing_sequence = 0;
1204
1205 /*
1206 * Add padding. At least four bytes, and must also bring total
1207 * length (minus MAC) up to a multiple of the block size.
1208 */
1209 cipherblk = cipher ? cipher->blksize : 8; /* block size */
1210 cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */
1211 padding = 4;
1212 padding += (cipherblk - (pktout.length + padding) % cipherblk) % cipherblk;
1213 pktout.data[4] = padding;
1214 for (i = 0; i < padding; i++)
1215 pktout.data[pktout.length + i] = random_byte();
1216 PUT_32BIT(pktout.data, pktout.length + padding - 4);
1217 if (csmac)
1218 csmac->generate(pktout.data, outgoing_sequence++,
1219 pktout.length + padding);
1220 if (cscipher)
1221 cscipher->encrypt(pktout.data, pktout.length + padding);
1222 maclen = csmac ? csmac->len : 0;
1223#if 0
1224 debug(("Sending packet len=%d\r\n", pktout.length+padding+maclen));
1225 for (i = 0; i < pktout.length+padding+maclen; i++)
1226 debug((" %02x", (unsigned char)pktout.data[i]));
1227 debug(("\r\n"));
1228#endif
1229 s_write(pktout.data, pktout.length + padding + maclen);
1230}
1231
1232void sha_mpint(SHA_State *s, Bignum b) {
1233 unsigned char *p;
1234 int len;
1235 p = ssh2_mpint_fmt(b, &len);
1236 sha_string(s, p, len);
1237 free(p);
1238}
1239
1240/*
1241 * SSH2 packet decode functions.
1242 */
1243void ssh2_pkt_getstring(char **p, int *length) {
1244 *p = NULL;
1245 if (pktin.length - pktin.savedpos < 4)
1246 return;
1247 *length = GET_32BIT(pktin.data+pktin.savedpos);
1248 pktin.savedpos += 4;
1249 if (pktin.length - pktin.savedpos < *length)
1250 return;
1251 *p = pktin.data+pktin.savedpos;
1252 pktin.savedpos += *length;
1253}
1254Bignum ssh2_pkt_getmp(void) {
1255 char *p;
1256 int i, j, length;
1257 Bignum b;
1258
1259 ssh2_pkt_getstring(&p, &length);
1260 if (!p)
1261 return NULL;
1262 if (p[0] & 0x80)
1263 fatalbox("internal error: Can't handle negative mpints");
1264 b = newbn((length+1)/2);
1265 for (i = 0; i < length; i++) {
1266 j = length - 1 - i;
1267 if (j & 1)
1268 b[j/2+1] |= ((unsigned char)p[i]) << 8;
1269 else
1270 b[j/2+1] |= ((unsigned char)p[i]);
1271 }
1272 return b;
1273}
1274
1275void bndebug(char *string, Bignum b) {
1276 unsigned char *p;
1277 int i, len;
1278 p = ssh2_mpint_fmt(b, &len);
1279 debug(("%s", string));
1280 for (i = 0; i < len; i++)
1281 debug((" %02x", p[i]));
1282 debug(("\r\n"));
1283 free(p);
1284}
1285
1286/*
1287 * Utility routine for decoding comma-separated strings in KEXINIT.
1288 */
1289int in_commasep_string(char *needle, char *haystack, int haylen) {
1290 int needlen = strlen(needle);
1291 while (1) {
1292 /*
1293 * Is it at the start of the string?
1294 */
1295 if (haylen >= needlen && /* haystack is long enough */
1296 !memcmp(needle, haystack, needlen) && /* initial match */
1297 (haylen == needlen || haystack[needlen] == ',')
1298 /* either , or EOS follows */
1299 )
1300 return 1;
1301 /*
1302 * If not, search for the next comma and resume after that.
1303 * If no comma found, terminate.
1304 */
1305 while (haylen > 0 && *haystack != ',')
1306 haylen--, haystack++;
1307 if (haylen == 0)
1308 return 0;
1309 haylen--, haystack++; /* skip over comma itself */
1310 }
1311}
1312
1313/*
1314 * Handle the SSH2 key exchange phase.
1315 */
1316static int do_ssh2_kex(unsigned char *in, int inlen, int ispkt)
1317{
1318 static int i, len;
1319 static char *str;
1320 static Bignum e, f, K;
1321 static struct ssh_cipher *cscipher_tobe = NULL;
1322 static struct ssh_cipher *sccipher_tobe = NULL;
1323 static struct ssh_mac *csmac_tobe = NULL;
1324 static struct ssh_mac *scmac_tobe = NULL;
1325 static struct ssh_compress *cscomp_tobe = NULL;
1326 static struct ssh_compress *sccomp_tobe = NULL;
1327 static char *hostkeydata, *sigdata;
1328 static int hostkeylen, siglen;
1329 static unsigned char exchange_hash[20];
1330
1331 crBegin;
1332
1333 /*
1334 * Construct and send our key exchange packet.
1335 */
1336 ssh2_pkt_init(SSH2_MSG_KEXINIT);
1337 for (i = 0; i < 16; i++)
1338 ssh2_pkt_addbyte((unsigned char)random_byte());
1339 /* List key exchange algorithms. */
1340 ssh2_pkt_addstring_start();
1341 for (i = 0; i < lenof(kex_algs); i++) {
1342 ssh2_pkt_addstring_str(kex_algs[i]->name);
1343 if (i < lenof(kex_algs)-1)
1344 ssh2_pkt_addstring_str(",");
1345 }
1346 /* List server host key algorithms. */
1347 ssh2_pkt_addstring_start();
1348 for (i = 0; i < lenof(hostkey_algs); i++) {
1349 ssh2_pkt_addstring_str(hostkey_algs[i]->name);
1350 if (i < lenof(hostkey_algs)-1)
1351 ssh2_pkt_addstring_str(",");
1352 }
1353 /* List client->server encryption algorithms. */
1354 ssh2_pkt_addstring_start();
1355 for (i = 0; i < lenof(ciphers); i++) {
1356 ssh2_pkt_addstring_str(ciphers[i]->name);
1357 if (i < lenof(ciphers)-1)
1358 ssh2_pkt_addstring_str(",");
1359 }
1360 /* List server->client encryption algorithms. */
1361 ssh2_pkt_addstring_start();
1362 for (i = 0; i < lenof(ciphers); i++) {
1363 ssh2_pkt_addstring_str(ciphers[i]->name);
1364 if (i < lenof(ciphers)-1)
1365 ssh2_pkt_addstring_str(",");
1366 }
1367 /* List client->server MAC algorithms. */
1368 ssh2_pkt_addstring_start();
1369 for (i = 0; i < lenof(macs); i++) {
1370 ssh2_pkt_addstring_str(macs[i]->name);
1371 if (i < lenof(macs)-1)
1372 ssh2_pkt_addstring_str(",");
1373 }
1374 /* List server->client MAC algorithms. */
1375 ssh2_pkt_addstring_start();
1376 for (i = 0; i < lenof(macs); i++) {
1377 ssh2_pkt_addstring_str(macs[i]->name);
1378 if (i < lenof(macs)-1)
1379 ssh2_pkt_addstring_str(",");
1380 }
1381 /* List client->server compression algorithms. */
1382 ssh2_pkt_addstring_start();
1383 for (i = 0; i < lenof(compressions); i++) {
1384 ssh2_pkt_addstring_str(compressions[i]->name);
1385 if (i < lenof(compressions)-1)
1386 ssh2_pkt_addstring_str(",");
1387 }
1388 /* List server->client compression algorithms. */
1389 ssh2_pkt_addstring_start();
1390 for (i = 0; i < lenof(compressions); i++) {
1391 ssh2_pkt_addstring_str(compressions[i]->name);
1392 if (i < lenof(compressions)-1)
1393 ssh2_pkt_addstring_str(",");
1394 }
1395 /* List client->server languages. Empty list. */
1396 ssh2_pkt_addstring_start();
1397 /* List server->client languages. Empty list. */
1398 ssh2_pkt_addstring_start();
1399 /* First KEX packet does _not_ follow, because we're not that brave. */
1400 ssh2_pkt_addbool(FALSE);
1401 /* Reserved. */
1402 ssh2_pkt_adduint32(0);
1403 sha_string(&exhash, pktout.data+5, pktout.length-5);
1404 ssh2_pkt_send();
1405
1406 if (!ispkt) crWaitUntil(ispkt);
1407 sha_string(&exhash, pktin.data+5, pktin.length-5);
1408
1409 /*
1410 * Now examine the other side's KEXINIT to see what we're up
1411 * to.
1412 */
1413 if (pktin.type != SSH2_MSG_KEXINIT)
1414 fatalbox("expected key exchange packet from server");
1415 kex = NULL; hostkey = NULL; cscipher_tobe = NULL; sccipher_tobe = NULL;
1416 csmac_tobe = NULL; scmac_tobe = NULL; cscomp_tobe = NULL; sccomp_tobe = NULL;
1417 pktin.savedpos += 16; /* skip garbage cookie */
1418 ssh2_pkt_getstring(&str, &len); /* key exchange algorithms */
1419 for (i = 0; i < lenof(kex_algs); i++) {
1420 if (in_commasep_string(kex_algs[i]->name, str, len)) {
1421 kex = kex_algs[i];
1422 break;
1423 }
1424 }
1425 ssh2_pkt_getstring(&str, &len); /* host key algorithms */
1426 for (i = 0; i < lenof(hostkey_algs); i++) {
1427 if (in_commasep_string(hostkey_algs[i]->name, str, len)) {
1428 hostkey = hostkey_algs[i];
1429 break;
1430 }
1431 }
1432 ssh2_pkt_getstring(&str, &len); /* client->server cipher */
1433 for (i = 0; i < lenof(ciphers); i++) {
1434 if (in_commasep_string(ciphers[i]->name, str, len)) {
1435 cscipher_tobe = ciphers[i];
1436 break;
1437 }
1438 }
1439 ssh2_pkt_getstring(&str, &len); /* server->client cipher */
1440 for (i = 0; i < lenof(ciphers); i++) {
1441 if (in_commasep_string(ciphers[i]->name, str, len)) {
1442 sccipher_tobe = ciphers[i];
1443 break;
1444 }
1445 }
1446 ssh2_pkt_getstring(&str, &len); /* client->server mac */
1447 for (i = 0; i < lenof(macs); i++) {
1448 if (in_commasep_string(macs[i]->name, str, len)) {
1449 csmac_tobe = macs[i];
1450 break;
1451 }
1452 }
1453 ssh2_pkt_getstring(&str, &len); /* server->client mac */
1454 for (i = 0; i < lenof(macs); i++) {
1455 if (in_commasep_string(macs[i]->name, str, len)) {
1456 scmac_tobe = macs[i];
1457 break;
1458 }
1459 }
1460 ssh2_pkt_getstring(&str, &len); /* client->server compression */
1461 for (i = 0; i < lenof(compressions); i++) {
1462 if (in_commasep_string(compressions[i]->name, str, len)) {
1463 cscomp_tobe = compressions[i];
1464 break;
1465 }
1466 }
1467 ssh2_pkt_getstring(&str, &len); /* server->client compression */
1468 for (i = 0; i < lenof(compressions); i++) {
1469 if (in_commasep_string(compressions[i]->name, str, len)) {
1470 sccomp_tobe = compressions[i];
1471 break;
1472 }
1473 }
1474 debug(("key exchange is %s\r\n", kex ? kex->name : NULL));
1475 debug(("host key alg is %s\r\n", hostkey ? hostkey->name : NULL));
1476 debug(("cscipher alg is %s\r\n", cscipher_tobe ? cscipher_tobe->name : NULL));
1477 debug(("sccipher alg is %s\r\n", sccipher_tobe ? sccipher_tobe->name : NULL));
1478 debug(("csmac alg is %s\r\n", csmac_tobe ? csmac_tobe->name : NULL));
1479 debug(("scmac alg is %s\r\n", scmac_tobe ? scmac_tobe->name : NULL));
1480 debug(("cscomp alg is %s\r\n", cscomp_tobe ? cscomp_tobe->name : NULL));
1481 debug(("sccomp alg is %s\r\n", sccomp_tobe ? sccomp_tobe->name : NULL));
1482
1483 /*
1484 * Currently we only support Diffie-Hellman and DSS, so let's
1485 * bomb out if those aren't selected.
1486 */
1487 if (kex != &ssh_diffiehellman || hostkey != &ssh_dss)
1488 fatalbox("internal fault: chaos in SSH 2 transport layer");
1489
1490 /*
1491 * Now we begin the fun. Generate and send e for Diffie-Hellman.
1492 */
1493 e = dh_create_e();
1494 bndebug("e=", e);
1495 ssh2_pkt_init(SSH2_MSG_KEXDH_INIT);
1496 ssh2_pkt_addmp(e);
1497 ssh2_pkt_send();
1498
1499 crWaitUntil(ispkt);
1500 if (pktin.type != SSH2_MSG_KEXDH_REPLY)
1501 fatalbox("expected key exchange packet from server");
1502 ssh2_pkt_getstring(&hostkeydata, &hostkeylen);
1503 f = ssh2_pkt_getmp();
1504 bndebug("f=", f);
1505 ssh2_pkt_getstring(&sigdata, &siglen);
1506
1507 K = dh_find_K(f);
1508 bndebug("K=", K);
1509
1510 sha_string(&exhash, hostkeydata, hostkeylen);
1511 sha_mpint(&exhash, e);
1512 sha_mpint(&exhash, f);
1513 sha_mpint(&exhash, K);
1514 SHA_Final(&exhash, exchange_hash);
1515
1516 debug(("Exchange hash is:\r\n"));
1517 for (i = 0; i < 20; i++)
1518 debug((" %02x", exchange_hash[i]));
1519 debug(("\r\n"));
1520
1521 /*
1522 * FIXME: verify hostkeydata and sigdata.
1523 */
1524
1525 crWaitUntil(0);
1526
1527 crFinish(1);
1528}
1529
1530static void ssh2_protocol(unsigned char *in, int inlen, int ispkt) {
1531 crBegin;
1532
1533 random_init();
1534
1535 while (!do_ssh2_kex(in, inlen, ispkt)) {
1536 crReturnV;
1537 }
1538
1539 crFinishV;
1540}
1541
1542/*
374330e2 1543 * Called to set up the connection. Will arrange for WM_NETEVENT
1544 * messages to be passed to the specified window, whose window
1545 * procedure should then call telnet_msg().
1546 *
1547 * Returns an error message, or NULL on success.
374330e2 1548 */
1549static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) {
fb09bf1c 1550 char *p;
8f203108 1551
1552#ifdef MSCRYPTOAPI
1553 if(crypto_startup() == 0)
1554 return "Microsoft high encryption pack not installed!";
1555#endif
374330e2 1556
fb09bf1c 1557 p = connect_to_host(host, port, realhost);
1558 if (p != NULL)
1559 return p;
374330e2 1560
1561 if (!do_ssh_init())
1562 return "Protocol initialisation error";
1563
1564 if (WSAAsyncSelect (s, hwnd, WM_NETEVENT, FD_READ | FD_CLOSE) == SOCKET_ERROR)
1565 switch (WSAGetLastError()) {
1566 case WSAENETDOWN: return "Network is down";
1567 default: return "WSAAsyncSelect(): unknown error";
1568 }
1569
1570 return NULL;
1571}
1572
1573/*
1574 * Process a WM_NETEVENT message. Will return 0 if the connection
1575 * has closed, or <0 for a socket error.
1576 */
1577static int ssh_msg (WPARAM wParam, LPARAM lParam) {
1578 int ret;
1579 char buf[256];
1580
8ce72d2c 1581 /*
1582 * Because reading less than the whole of the available pending
1583 * data can generate an FD_READ event, we need to allow for the
1584 * possibility that FD_READ may arrive with FD_CLOSE already in
1585 * the queue; so it's possible that we can get here even with s
1586 * invalid. If so, we return 1 and don't worry about it.
1587 */
1588 if (s == INVALID_SOCKET)
1589 return 1;
374330e2 1590
1591 if (WSAGETSELECTERROR(lParam) != 0)
1592 return -WSAGETSELECTERROR(lParam);
1593
1594 switch (WSAGETSELECTEVENT(lParam)) {
1595 case FD_READ:
8ce72d2c 1596 case FD_CLOSE:
374330e2 1597 ret = recv(s, buf, sizeof(buf), 0);
1598 if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
1599 return 1;
1600 if (ret < 0) /* any _other_ error */
1601 return -10000-WSAGetLastError();
1602 if (ret == 0) {
1603 s = INVALID_SOCKET;
8ce72d2c 1604 return 0;
374330e2 1605 }
1606 ssh_gotdata (buf, ret);
85ee8208 1607 if (ssh_state == SSH_STATE_CLOSED) {
1608 closesocket(s);
1609 s = INVALID_SOCKET;
1610 return 0;
1611 }
374330e2 1612 return 1;
374330e2 1613 }
1614 return 1; /* shouldn't happen, but WTF */
1615}
1616
1617/*
1618 * Called to send data down the Telnet connection.
1619 */
1620static void ssh_send (char *buf, int len) {
1621 if (s == INVALID_SOCKET)
1622 return;
1623
1624 ssh_protocol(buf, len, 0);
1625}
1626
1627/*
1628 * Called to set the size of the window from Telnet's POV.
1629 */
1630static void ssh_size(void) {
1631 switch (ssh_state) {
1632 case SSH_STATE_BEFORE_SIZE:
21248260 1633 case SSH_STATE_CLOSED:
374330e2 1634 break; /* do nothing */
1635 case SSH_STATE_INTERMED:
1636 size_needed = TRUE; /* buffer for later */
1637 break;
1638 case SSH_STATE_SESSION:
fef97f43 1639 if (!cfg.nopty) {
e5574168 1640 send_packet(SSH1_CMSG_WINDOW_SIZE,
fb09bf1c 1641 PKT_INT, rows, PKT_INT, cols,
1642 PKT_INT, 0, PKT_INT, 0, PKT_END);
fef97f43 1643 }
374330e2 1644 }
1645}
1646
1647/*
1648 * (Send Telnet special codes)
1649 */
1650static void ssh_special (Telnet_Special code) {
1651 /* do nothing */
1652}
1653
fb09bf1c 1654
1655/*
1656 * Read and decrypt one incoming SSH packet.
1657 * (only used by pSCP)
1658 */
1659static void get_packet(void)
1660{
1661 unsigned char buf[4096], *p;
1662 long to_read;
1663 int len;
1664
1665 assert(IS_SCP);
1666
1667 p = NULL;
1668 len = 0;
1669
1670 while ((to_read = s_rdpkt(&p, &len)) > 0) {
1671 if (to_read > sizeof(buf)) to_read = sizeof(buf);
1672 len = s_read(buf, to_read);
1673 if (len != to_read) {
1674 closesocket(s);
1675 s = INVALID_SOCKET;
1676 return;
1677 }
1678 p = buf;
1679 }
1680
1681 assert(len == 0);
1682}
1683
1684/*
1685 * Receive a block of data over the SSH link. Block until
1686 * all data is available. Return nr of bytes read (0 if lost connection).
1687 * (only used by pSCP)
1688 */
1689int ssh_scp_recv(unsigned char *buf, int len)
1690{
1691 static int pending_input_len = 0;
1692 static unsigned char *pending_input_ptr;
1693 int to_read = len;
1694
1695 assert(IS_SCP);
1696
1697 if (pending_input_len >= to_read) {
1698 memcpy(buf, pending_input_ptr, to_read);
1699 pending_input_ptr += to_read;
1700 pending_input_len -= to_read;
1701 return len;
1702 }
1703
1704 if (pending_input_len > 0) {
1705 memcpy(buf, pending_input_ptr, pending_input_len);
1706 buf += pending_input_len;
1707 to_read -= pending_input_len;
1708 pending_input_len = 0;
1709 }
1710
1711 if (s == INVALID_SOCKET)
1712 return 0;
1713 while (to_read > 0) {
1714 get_packet();
1715 if (s == INVALID_SOCKET)
1716 return 0;
e5574168 1717 if (pktin.type == SSH1_SMSG_STDOUT_DATA) {
fb09bf1c 1718 int plen = GET_32BIT(pktin.body);
1719 if (plen <= to_read) {
1720 memcpy(buf, pktin.body + 4, plen);
1721 buf += plen;
1722 to_read -= plen;
1723 } else {
1724 memcpy(buf, pktin.body + 4, to_read);
1725 pending_input_len = plen - to_read;
1726 pending_input_ptr = pktin.body + 4 + to_read;
1727 to_read = 0;
1728 }
e5574168 1729 } else if (pktin.type == SSH1_SMSG_STDERR_DATA) {
fb09bf1c 1730 int plen = GET_32BIT(pktin.body);
1731 fwrite(pktin.body + 4, plen, 1, stderr);
e5574168 1732 } else if (pktin.type == SSH1_MSG_DISCONNECT) {
fb09bf1c 1733 logevent("Received disconnect request");
e5574168 1734 } else if (pktin.type == SSH1_SMSG_SUCCESS ||
1735 pktin.type == SSH1_SMSG_FAILURE) {
fb09bf1c 1736 /* ignore */
e5574168 1737 } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) {
fb09bf1c 1738 char logbuf[100];
1739 sprintf(logbuf, "Remote exit status: %d", GET_32BIT(pktin.body));
1740 logevent(logbuf);
e5574168 1741 send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);
fb09bf1c 1742 logevent("Closing connection");
1743 closesocket(s);
1744 s = INVALID_SOCKET;
1745 } else {
1746 fatalbox("Strange packet received: type %d", pktin.type);
1747 }
1748 }
1749
1750 return len;
1751}
1752
1753/*
1754 * Send a block of data over the SSH link.
1755 * Block until all data is sent.
1756 * (only used by pSCP)
1757 */
1758void ssh_scp_send(unsigned char *buf, int len)
1759{
1760 assert(IS_SCP);
1761 if (s == INVALID_SOCKET)
1762 return;
e5574168 1763 send_packet(SSH1_CMSG_STDIN_DATA,
fb09bf1c 1764 PKT_INT, len, PKT_DATA, buf, len, PKT_END);
1765}
1766
1767/*
1768 * Send an EOF notification to the server.
1769 * (only used by pSCP)
1770 */
1771void ssh_scp_send_eof(void)
1772{
1773 assert(IS_SCP);
1774 if (s == INVALID_SOCKET)
1775 return;
e5574168 1776 send_packet(SSH1_CMSG_EOF, PKT_END);
fb09bf1c 1777}
1778
1779/*
1780 * Set up the connection, login on the remote host and
1781 * start execution of a command.
1782 * Returns an error message, or NULL on success.
1783 * (only used by pSCP)
1784 */
1785char *ssh_scp_init(char *host, int port, char *cmd, char **realhost)
1786{
1787 char buf[160], *p;
1788
1789 assert(IS_SCP);
1790
1791#ifdef MSCRYPTOAPI
1792 if (crypto_startup() == 0)
1793 return "Microsoft high encryption pack not installed!";
1794#endif
1795
1796 p = connect_to_host(host, port, realhost);
1797 if (p != NULL)
1798 return p;
1799
1800 random_init();
1801
1802 if (!do_ssh_init())
1803 return "Protocol initialisation error";
1804
1805 /* Exchange keys and login */
1806 do {
1807 get_packet();
1808 if (s == INVALID_SOCKET)
1809 return "Connection closed by remote host";
e5574168 1810 } while (!do_ssh1_login(NULL, 0, 1));
85ee8208 1811
1812 if (ssh_state == SSH_STATE_CLOSED) {
1813 closesocket(s);
1814 s = INVALID_SOCKET;
1815 return "Session initialisation error";
1816 }
fb09bf1c 1817
1818 /* Execute command */
1819 sprintf(buf, "Sending command: %.100s", cmd);
1820 logevent(buf);
e5574168 1821 send_packet(SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END);
fb09bf1c 1822
1823 return NULL;
1824}
1825
1826
374330e2 1827Backend ssh_backend = {
1828 ssh_init,
1829 ssh_msg,
1830 ssh_send,
1831 ssh_size,
1832 ssh_special
1833};
fb09bf1c 1834