summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--Makefile.in2
-rw-r--r--channels.c460
-rw-r--r--channels.h15
-rw-r--r--compat.c33
-rw-r--r--compat.h6
-rw-r--r--dsa.c309
-rw-r--r--dsa.h20
-rw-r--r--hmac.c64
-rw-r--r--hmac.h11
-rw-r--r--kex.c407
-rw-r--r--kex.h111
-rw-r--r--nchan.c379
-rw-r--r--nchan.h30
-rw-r--r--nchan2.ms64
-rw-r--r--packet.c514
-rw-r--r--packet.h10
17 files changed, 2277 insertions, 166 deletions
diff --git a/ChangeLog b/ChangeLog
index 2beaf7fc6..906e09f04 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
120000404 120000404
2 - Add tests for RAND_add function when searching for OpenSSL 2 - Add tests for RAND_add function when searching for OpenSSL
3 - OpenBSD CVS update:
4 - [packet.h packet.c]
5 ssh2 packet format
6 - [packet.h packet.c nchan2.ms nchan.h compat.h compat.c]
7 [channels.h channels.c]
8 channel layer support for ssh2
9 - [kex.h kex.c hmac.h hmac.c dsa.c dsa.h]
10 DSA, keyexchange, algorithm agreement for ssh2
3 11
420000403 1220000403
5 - Wrote entropy collection routines for systems that lack /dev/random 13 - Wrote entropy collection routines for systems that lack /dev/random
diff --git a/Makefile.in b/Makefile.in
index 89b408487..bb08b53b9 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -31,7 +31,7 @@ LDFLAGS=-L. @LDFLAGS@
31 31
32TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS) 32TARGETS=ssh sshd ssh-add ssh-keygen ssh-agent scp $(EXTRA_TARGETS)
33 33
34LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hostfile.o key.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o 34LIBOBJS= atomicio.o authfd.o authfile.o bsd-bindresvport.o bsd-daemon.o bsd-misc.o bsd-mktemp.o bsd-rresvport.o bsd-setenv.o bsd-snprintf.o bsd-strlcat.o bsd-strlcpy.o bufaux.o buffer.o canohost.o channels.o cipher.o compat.o compress.o crc32.o deattack.o dispatch.o dsa.o fake-getaddrinfo.o fake-getnameinfo.o fingerprint.o hmac.o hostfile.o key.o kex.o log.o match.o mpaux.o nchan.o packet.o radix.o entropy.o readpass.o rsa.o tildexpand.o ttymodes.o uidswap.o xmalloc.o
35 35
36SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o 36SSHOBJS= ssh.o sshconnect.o log-client.o readconf.o clientloop.o
37 37
diff --git a/channels.c b/channels.c
index b87ff9f4f..18f667f6b 100644
--- a/channels.c
+++ b/channels.c
@@ -13,10 +13,11 @@
13 * There is also code for initiating connection forwarding for X11 connections, 13 * There is also code for initiating connection forwarding for X11 connections,
14 * arbitrary tcp/ip connections, and the authentication agent connection. 14 * arbitrary tcp/ip connections, and the authentication agent connection.
15 * 15 *
16 * SSH2 support added by Markus Friedl.
16 */ 17 */
17 18
18#include "includes.h" 19#include "includes.h"
19RCSID("$Id: channels.c,v 1.20 2000/04/01 01:09:23 damien Exp $"); 20RCSID("$Id: channels.c,v 1.21 2000/04/04 04:39:00 damien Exp $");
20 21
21#include "ssh.h" 22#include "ssh.h"
22#include "packet.h" 23#include "packet.h"
@@ -31,6 +32,8 @@ RCSID("$Id: channels.c,v 1.20 2000/04/01 01:09:23 damien Exp $");
31#include "nchan.h" 32#include "nchan.h"
32#include "compat.h" 33#include "compat.h"
33 34
35#include "ssh2.h"
36
34/* Maximum number of fake X11 displays to try. */ 37/* Maximum number of fake X11 displays to try. */
35#define MAX_DISPLAYS 1000 38#define MAX_DISPLAYS 1000
36 39
@@ -165,6 +168,7 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
165 168
166 /* Do initial allocation if this is the first call. */ 169 /* Do initial allocation if this is the first call. */
167 if (channels_alloc == 0) { 170 if (channels_alloc == 0) {
171 chan_init();
168 channels_alloc = 10; 172 channels_alloc = 10;
169 channels = xmalloc(channels_alloc * sizeof(Channel)); 173 channels = xmalloc(channels_alloc * sizeof(Channel));
170 for (i = 0; i < channels_alloc; i++) 174 for (i = 0; i < channels_alloc; i++)
@@ -237,9 +241,28 @@ channel_free(int id)
237 if (c == NULL) 241 if (c == NULL)
238 packet_disconnect("channel free: bad local channel %d", id); 242 packet_disconnect("channel free: bad local channel %d", id);
239 debug("channel_free: channel %d: status: %s", id, channel_open_message()); 243 debug("channel_free: channel %d: status: %s", id, channel_open_message());
244 if (c->dettach_user != NULL) {
245 debug("channel_free: channel %d: dettaching channel user", id);
246 c->dettach_user(c->self, NULL);
247 }
240 if (c->sock != -1) { 248 if (c->sock != -1) {
241 shutdown(c->sock, SHUT_RDWR); 249 shutdown(c->sock, SHUT_RDWR);
242 close(c->sock); 250 close(c->sock);
251 c->sock = -1;
252 }
253 if (compat20) {
254 if (c->rfd != -1) {
255 close(c->rfd);
256 c->rfd = -1;
257 }
258 if (c->wfd != -1) {
259 close(c->wfd);
260 c->wfd = -1;
261 }
262 if (c->efd != -1) {
263 close(c->efd);
264 c->efd = -1;
265 }
243 } 266 }
244 buffer_free(&c->input); 267 buffer_free(&c->input);
245 buffer_free(&c->output); 268 buffer_free(&c->output);
@@ -296,6 +319,32 @@ channel_pre_open_15(Channel *c, fd_set * readset, fd_set * writeset)
296} 319}
297 320
298void 321void
322channel_pre_open_20(Channel *c, fd_set * readset, fd_set * writeset)
323{
324 if (c->istate == CHAN_INPUT_OPEN &&
325 c->remote_window > 0 &&
326 buffer_len(&c->input) < c->remote_window)
327 FD_SET(c->rfd, readset);
328 if (c->ostate == CHAN_OUTPUT_OPEN ||
329 c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
330 if (buffer_len(&c->output) > 0) {
331 FD_SET(c->wfd, writeset);
332 } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) {
333 chan_obuf_empty(c);
334 }
335 }
336 /** XXX check close conditions, too */
337 if (c->efd != -1) {
338 if (c->extended_usage == CHAN_EXTENDED_WRITE &&
339 buffer_len(&c->extended) > 0)
340 FD_SET(c->efd, writeset);
341 else if (c->extended_usage == CHAN_EXTENDED_READ &&
342 buffer_len(&c->extended) < c->remote_window)
343 FD_SET(c->efd, readset);
344 }
345}
346
347void
299channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset) 348channel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset)
300{ 349{
301 if (buffer_len(&c->input) == 0) { 350 if (buffer_len(&c->input) == 0) {
@@ -483,15 +532,27 @@ channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
483 SSH_CHANNEL_OPENING, newsock, newsock, -1, 532 SSH_CHANNEL_OPENING, newsock, newsock, -1,
484 c->local_window_max, c->local_maxpacket, 533 c->local_window_max, c->local_maxpacket,
485 0, xstrdup(buf)); 534 0, xstrdup(buf));
486 535 if (compat20) {
487 packet_start(SSH_MSG_PORT_OPEN); 536 packet_start(SSH2_MSG_CHANNEL_OPEN);
488 packet_put_int(newch); 537 packet_put_cstring("direct-tcpip");
489 packet_put_string(c->path, strlen(c->path)); 538 packet_put_int(newch);
490 packet_put_int(c->host_port); 539 packet_put_int(c->local_window_max);
491 if (have_hostname_in_open) { 540 packet_put_int(c->local_maxpacket);
492 packet_put_string(buf, strlen(buf)); 541 packet_put_string(c->path, strlen(c->path));
542 packet_put_int(c->host_port);
543 packet_put_cstring(remote_hostname);
544 packet_put_int(remote_port);
545 packet_send();
546 } else {
547 packet_start(SSH_MSG_PORT_OPEN);
548 packet_put_int(newch);
549 packet_put_string(c->path, strlen(c->path));
550 packet_put_int(c->host_port);
551 if (have_hostname_in_open) {
552 packet_put_string(buf, strlen(buf));
553 }
554 packet_send();
493 } 555 }
494 packet_send();
495 xfree(remote_hostname); 556 xfree(remote_hostname);
496 } 557 }
497} 558}
@@ -569,6 +630,56 @@ channel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset)
569 return -1; 630 return -1;
570 } 631 }
571 buffer_consume(&c->output, len); 632 buffer_consume(&c->output, len);
633 if (compat20 && len > 0) {
634 c->local_consumed += len;
635 }
636 }
637 return 1;
638}
639int
640channel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset)
641{
642 char buf[16*1024];
643 int len;
644
645 if (c->efd != -1) {
646 if (c->extended_usage == CHAN_EXTENDED_WRITE &&
647 FD_ISSET(c->efd, writeset) &&
648 buffer_len(&c->extended) > 0) {
649 len = write(c->efd, buffer_ptr(&c->extended),
650 buffer_len(&c->extended));
651 debug("channel %d: written %d to efd %d",
652 c->self, len, c->efd);
653 if (len > 0) {
654 buffer_consume(&c->extended, len);
655 c->local_consumed += len;
656 }
657 } else if (c->extended_usage == CHAN_EXTENDED_READ &&
658 FD_ISSET(c->efd, readset)) {
659 len = read(c->efd, buf, sizeof(buf));
660 debug("channel %d: read %d from efd %d",
661 c->self, len, c->efd);
662 if (len > 0)
663 buffer_append(&c->extended, buf, len);
664 }
665 }
666 return 1;
667}
668int
669channel_check_window(Channel *c, fd_set * readset, fd_set * writeset)
670{
671 if (!(c->flags & CHAN_CLOSE_SENT) &&
672 c->local_window < c->local_window_max/2 &&
673 c->local_consumed > 0) {
674 packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
675 packet_put_int(c->remote_id);
676 packet_put_int(c->local_consumed);
677 packet_send();
678 debug("channel %d: window %d sent adjust %d",
679 c->self, c->local_window,
680 c->local_consumed);
681 c->local_window += c->local_consumed;
682 c->local_consumed = 0;
572 } 683 }
573 return 1; 684 return 1;
574} 685}
@@ -581,6 +692,15 @@ channel_post_open_1(Channel *c, fd_set * readset, fd_set * writeset)
581} 692}
582 693
583void 694void
695channel_post_open_2(Channel *c, fd_set * readset, fd_set * writeset)
696{
697 channel_handle_rfd(c, readset, writeset);
698 channel_handle_wfd(c, readset, writeset);
699 channel_handle_efd(c, readset, writeset);
700 channel_check_window(c, readset, writeset);
701}
702
703void
584channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) 704channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
585{ 705{
586 int len; 706 int len;
@@ -596,6 +716,16 @@ channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
596} 716}
597 717
598void 718void
719channel_handler_init_20(void)
720{
721 channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20;
722 channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener;
723
724 channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2;
725 channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener;
726}
727
728void
599channel_handler_init_13(void) 729channel_handler_init_13(void)
600{ 730{
601 channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13; 731 channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_13;
@@ -636,7 +766,9 @@ channel_handler_init(void)
636 channel_pre[i] = NULL; 766 channel_pre[i] = NULL;
637 channel_post[i] = NULL; 767 channel_post[i] = NULL;
638 } 768 }
639 if (compat13) 769 if (compat20)
770 channel_handler_init_20();
771 else if (compat13)
640 channel_handler_init_13(); 772 channel_handler_init_13();
641 else 773 else
642 channel_handler_init_15(); 774 channel_handler_init_15();
@@ -660,8 +792,7 @@ channel_handler(chan_fn *ftab[], fd_set * readset, fd_set * writeset)
660 if (ftab[c->type] == NULL) 792 if (ftab[c->type] == NULL)
661 continue; 793 continue;
662 (*ftab[c->type])(c, readset, writeset); 794 (*ftab[c->type])(c, readset, writeset);
663 if (!compat13) 795 chan_delete_if_full_closed(c);
664 chan_delete_if_full_closed(c);
665 } 796 }
666} 797}
667 798
@@ -700,27 +831,39 @@ channel_output_poll()
700 c->istate != CHAN_INPUT_WAIT_DRAIN) 831 c->istate != CHAN_INPUT_WAIT_DRAIN)
701 continue; 832 continue;
702 } 833 }
834 if (compat20 && (c->flags & CHAN_CLOSE_SENT)) {
835 debug("channel: %d: no data after CLOSE", c->self);
836 continue;
837 }
703 838
704 /* Get the amount of buffered data for this channel. */ 839 /* Get the amount of buffered data for this channel. */
705 len = buffer_len(&c->input); 840 len = buffer_len(&c->input);
706 if (len > 0) { 841 if (len > 0) {
707 /* Send some data for the other side over the secure connection. */ 842 /* Send some data for the other side over the secure connection. */
708 if (packet_is_interactive()) { 843 if (compat20) {
709 if (len > 1024) 844 if (len > c->remote_window)
710 len = 512; 845 len = c->remote_window;
846 if (len > c->remote_maxpacket)
847 len = c->remote_maxpacket;
711 } else { 848 } else {
712 /* Keep the packets at reasonable size. */ 849 if (packet_is_interactive()) {
713 if (len > packet_get_maxsize()) 850 if (len > 1024)
714 len = packet_get_maxsize()/2; 851 len = 512;
852 } else {
853 /* Keep the packets at reasonable size. */
854 if (len > packet_get_maxsize()/2)
855 len = packet_get_maxsize()/2;
856 }
715 } 857 }
716 if (len > 0) { 858 if (len > 0) {
717 packet_start(SSH_MSG_CHANNEL_DATA); 859 packet_start(compat20 ?
860 SSH2_MSG_CHANNEL_DATA : SSH_MSG_CHANNEL_DATA);
718 packet_put_int(c->remote_id); 861 packet_put_int(c->remote_id);
719 packet_put_string(buffer_ptr(&c->input), len); 862 packet_put_string(buffer_ptr(&c->input), len);
720 packet_send(); 863 packet_send();
721 buffer_consume(&c->input, len); 864 buffer_consume(&c->input, len);
722 c->remote_window -= len; 865 c->remote_window -= len;
723debug("channel %d: send data len %d", c->self, len); 866 debug("channel %d: send data len %d", c->self, len);
724 } 867 }
725 } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) { 868 } else if (c->istate == CHAN_INPUT_WAIT_DRAIN) {
726 if (compat13) 869 if (compat13)
@@ -731,6 +874,23 @@ debug("channel %d: send data len %d", c->self, len);
731 */ 874 */
732 chan_ibuf_empty(c); 875 chan_ibuf_empty(c);
733 } 876 }
877 /* Send extended data, i.e. stderr */
878 if (compat20 &&
879 c->remote_window > 0 &&
880 (len = buffer_len(&c->extended)) > 0 &&
881 c->extended_usage == CHAN_EXTENDED_READ) {
882 if (len > c->remote_window)
883 len = c->remote_window;
884 if (len > c->remote_maxpacket)
885 len = c->remote_maxpacket;
886 packet_start(SSH2_MSG_CHANNEL_EXTENDED_DATA);
887 packet_put_int(c->remote_id);
888 packet_put_int(SSH2_EXTENDED_DATA_STDERR);
889 packet_put_string(buffer_ptr(&c->extended), len);
890 packet_send();
891 buffer_consume(&c->extended, len);
892 c->remote_window -= len;
893 }
734 } 894 }
735} 895}
736 896
@@ -766,10 +926,63 @@ channel_input_data(int type, int plen)
766 /* Get the data. */ 926 /* Get the data. */
767 data = packet_get_string(&data_len); 927 data = packet_get_string(&data_len);
768 928
769 packet_integrity_check(plen, 4 + 4 + data_len, SSH_MSG_CHANNEL_DATA); 929 if (compat20){
930 if (data_len > c->local_maxpacket) {
931 log("channel %d: rcvd big packet %d, maxpack %d",
932 c->self, data_len, c->local_maxpacket);
933 }
934 if (data_len > c->local_window) {
935 log("channel %d: rcvd too much data %d, win %d",
936 c->self, data_len, c->local_window);
937 xfree(data);
938 return;
939 }
940 c->local_window -= data_len;
941 }else{
942 packet_integrity_check(plen, 4 + 4 + data_len, type);
943 }
770 buffer_append(&c->output, data, data_len); 944 buffer_append(&c->output, data, data_len);
771 xfree(data); 945 xfree(data);
772} 946}
947void
948channel_input_extended_data(int type, int plen)
949{
950 int id;
951 int tcode;
952 char *data;
953 unsigned int data_len;
954 Channel *c;
955
956 /* Get the channel number and verify it. */
957 id = packet_get_int();
958 c = channel_lookup(id);
959
960 if (c == NULL)
961 packet_disconnect("Received extended_data for bad channel %d.", id);
962 if (c->type != SSH_CHANNEL_OPEN) {
963 log("channel %d: ext data for non open", id);
964 return;
965 }
966 tcode = packet_get_int();
967 if (c->efd == -1 ||
968 c->extended_usage != CHAN_EXTENDED_WRITE ||
969 tcode != SSH2_EXTENDED_DATA_STDERR) {
970 log("channel %d: bad ext data", c->self);
971 return;
972 }
973 data = packet_get_string(&data_len);
974 if (data_len > c->local_window) {
975 log("channel %d: rcvd too much extended_data %d, win %d",
976 c->self, data_len, c->local_window);
977 xfree(data);
978 return;
979 }
980 debug("channel %d: rcvd ext data %d", c->self, data_len);
981 c->local_window -= data_len;
982 buffer_append(&c->extended, data, data_len);
983 xfree(data);
984}
985
773 986
774/* 987/*
775 * Returns true if no channel has too much buffered data, and false if one or 988 * Returns true if no channel has too much buffered data, and false if one or
@@ -785,7 +998,7 @@ channel_not_very_much_buffered_data()
785 for (i = 0; i < channels_alloc; i++) { 998 for (i = 0; i < channels_alloc; i++) {
786 c = &channels[i]; 999 c = &channels[i];
787 if (c->type == SSH_CHANNEL_OPEN) { 1000 if (c->type == SSH_CHANNEL_OPEN) {
788 if (buffer_len(&c->input) > packet_get_maxsize()) { 1001 if (!compat20 && buffer_len(&c->input) > packet_get_maxsize()) {
789 debug("channel %d: big input buffer %d", 1002 debug("channel %d: big input buffer %d",
790 c->self, buffer_len(&c->input)); 1003 c->self, buffer_len(&c->input));
791 return 0; 1004 return 0;
@@ -886,7 +1099,8 @@ channel_input_open_confirmation(int type, int plen)
886 int id, remote_id; 1099 int id, remote_id;
887 Channel *c; 1100 Channel *c;
888 1101
889 packet_integrity_check(plen, 4 + 4, type); 1102 if (!compat20)
1103 packet_integrity_check(plen, 4 + 4, type);
890 1104
891 id = packet_get_int(); 1105 id = packet_get_int();
892 c = channel_lookup(id); 1106 c = channel_lookup(id);
@@ -898,6 +1112,18 @@ channel_input_open_confirmation(int type, int plen)
898 /* Record the remote channel number and mark that the channel is now open. */ 1112 /* Record the remote channel number and mark that the channel is now open. */
899 c->remote_id = remote_id; 1113 c->remote_id = remote_id;
900 c->type = SSH_CHANNEL_OPEN; 1114 c->type = SSH_CHANNEL_OPEN;
1115
1116 if (compat20) {
1117 c->remote_window = packet_get_int();
1118 c->remote_maxpacket = packet_get_int();
1119 if (c->cb_fn != NULL && c->cb_event == type) {
1120 debug("callback start");
1121 c->cb_fn(c->self, c->cb_arg);
1122 debug("callback done");
1123 }
1124 debug("channel %d: open confirm rwindow %d rmax %d", c->self,
1125 c->remote_window, c->remote_maxpacket);
1126 }
901} 1127}
902 1128
903void 1129void
@@ -906,7 +1132,8 @@ channel_input_open_failure(int type, int plen)
906 int id; 1132 int id;
907 Channel *c; 1133 Channel *c;
908 1134
909 packet_integrity_check(plen, 4, type); 1135 if (!compat20)
1136 packet_integrity_check(plen, 4, type);
910 1137
911 id = packet_get_int(); 1138 id = packet_get_int();
912 c = channel_lookup(id); 1139 c = channel_lookup(id);
@@ -914,11 +1141,64 @@ channel_input_open_failure(int type, int plen)
914 if (c==NULL || c->type != SSH_CHANNEL_OPENING) 1141 if (c==NULL || c->type != SSH_CHANNEL_OPENING)
915 packet_disconnect("Received open failure for " 1142 packet_disconnect("Received open failure for "
916 "non-opening channel %d.", id); 1143 "non-opening channel %d.", id);
917 1144 if (compat20) {
1145 int reason = packet_get_int();
1146 char *msg = packet_get_string(NULL);
1147 log("channel_open_failure: %d: reason %d: %s", id, reason, msg);
1148 xfree(msg);
1149 }
918 /* Free the channel. This will also close the socket. */ 1150 /* Free the channel. This will also close the socket. */
919 channel_free(id); 1151 channel_free(id);
920} 1152}
921 1153
1154void
1155channel_input_channel_request(int type, int plen)
1156{
1157 int id;
1158 Channel *c;
1159
1160 id = packet_get_int();
1161 c = channel_lookup(id);
1162
1163 if (c == NULL ||
1164 (c->type != SSH_CHANNEL_OPEN && c->type != SSH_CHANNEL_LARVAL))
1165 packet_disconnect("Received request for "
1166 "non-open channel %d.", id);
1167 if (c->cb_fn != NULL && c->cb_event == type) {
1168 debug("callback start");
1169 c->cb_fn(c->self, c->cb_arg);
1170 debug("callback done");
1171 } else {
1172 char *service = packet_get_string(NULL);
1173 debug("channel: %d rcvd request for %s", c->self, service);
1174debug("cb_fn %p cb_event %d", c->cb_fn , c->cb_event);
1175 xfree(service);
1176 }
1177}
1178
1179void
1180channel_input_window_adjust(int type, int plen)
1181{
1182 Channel *c;
1183 int id, adjust;
1184
1185 if (!compat20)
1186 return;
1187
1188 /* Get the channel number and verify it. */
1189 id = packet_get_int();
1190 c = channel_lookup(id);
1191
1192 if (c == NULL || c->type != SSH_CHANNEL_OPEN) {
1193 log("Received window adjust for "
1194 "non-open channel %d.", id);
1195 return;
1196 }
1197 adjust = packet_get_int();
1198 debug("channel %d: rcvd adjust %d", id, adjust);
1199 c->remote_window += adjust;
1200}
1201
922/* 1202/*
923 * Stops listening for channels, and removes any unix domain sockets that we 1203 * Stops listening for channels, and removes any unix domain sockets that we
924 * might have. 1204 * might have.
@@ -983,6 +1263,10 @@ channel_still_open()
983 case SSH_CHANNEL_CLOSED: 1263 case SSH_CHANNEL_CLOSED:
984 case SSH_CHANNEL_AUTH_SOCKET: 1264 case SSH_CHANNEL_AUTH_SOCKET:
985 continue; 1265 continue;
1266 case SSH_CHANNEL_LARVAL:
1267 if (!compat20)
1268 fatal("cannot happen: SSH_CHANNEL_LARVAL");
1269 continue;
986 case SSH_CHANNEL_OPENING: 1270 case SSH_CHANNEL_OPENING:
987 case SSH_CHANNEL_OPEN: 1271 case SSH_CHANNEL_OPEN:
988 case SSH_CHANNEL_X11_OPEN: 1272 case SSH_CHANNEL_X11_OPEN:
@@ -1024,6 +1308,7 @@ channel_open_message()
1024 case SSH_CHANNEL_CLOSED: 1308 case SSH_CHANNEL_CLOSED:
1025 case SSH_CHANNEL_AUTH_SOCKET: 1309 case SSH_CHANNEL_AUTH_SOCKET:
1026 continue; 1310 continue;
1311 case SSH_CHANNEL_LARVAL:
1027 case SSH_CHANNEL_OPENING: 1312 case SSH_CHANNEL_OPENING:
1028 case SSH_CHANNEL_OPEN: 1313 case SSH_CHANNEL_OPEN:
1029 case SSH_CHANNEL_X11_OPEN: 1314 case SSH_CHANNEL_X11_OPEN:
@@ -1156,17 +1441,26 @@ channel_request_remote_forwarding(u_short listen_port, const char *host_to_conne
1156 num_permitted_opens++; 1441 num_permitted_opens++;
1157 1442
1158 /* Send the forward request to the remote side. */ 1443 /* Send the forward request to the remote side. */
1159 packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); 1444 if (compat20) {
1160 packet_put_int(port_to_connect); 1445 const char *address_to_bind = "0.0.0.0";
1161 packet_put_string(host_to_connect, strlen(host_to_connect)); 1446 packet_start(SSH2_MSG_GLOBAL_REQUEST);
1162 packet_put_int(listen_port); 1447 packet_put_cstring("tcpip-forward");
1163 packet_send(); 1448 packet_put_char(0); /* boolean: want reply */
1164 packet_write_wait(); 1449 packet_put_cstring(address_to_bind);
1165 /* 1450 packet_put_int(listen_port);
1166 * Wait for response from the remote side. It will send a disconnect 1451 } else {
1167 * message on failure, and we will never see it here. 1452 packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
1168 */ 1453 packet_put_int(port_to_connect);
1169 packet_read_expect(&payload_len, SSH_SMSG_SUCCESS); 1454 packet_put_cstring(host_to_connect);
1455 packet_put_int(listen_port);
1456 packet_send();
1457 packet_write_wait();
1458 /*
1459 * Wait for response from the remote side. It will send a disconnect
1460 * message on failure, and we will never see it here.
1461 */
1462 packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
1463 }
1170} 1464}
1171 1465
1172/* 1466/*
@@ -1839,3 +2133,97 @@ auth_input_open_request(int type, int plen)
1839 packet_put_int(newch); 2133 packet_put_int(newch);
1840 packet_send(); 2134 packet_send();
1841} 2135}
2136
2137void
2138channel_open(int id)
2139{
2140 Channel *c = channel_lookup(id);
2141 if (c == NULL) {
2142 log("channel_open: %d: bad id", id);
2143 return;
2144 }
2145 packet_start(SSH2_MSG_CHANNEL_OPEN);
2146 packet_put_cstring(c->ctype);
2147 packet_put_int(c->self);
2148 packet_put_int(c->local_window);
2149 packet_put_int(c->local_maxpacket);
2150 packet_send();
2151 debug("channel open %d", id);
2152}
2153void
2154channel_request(int id, char *service, int wantconfirm)
2155{
2156 channel_request_start(id, service, wantconfirm);
2157 packet_send();
2158 debug("channel request %d: %s", id, service) ;
2159}
2160void
2161channel_request_start(int id, char *service, int wantconfirm)
2162{
2163 Channel *c = channel_lookup(id);
2164 if (c == NULL) {
2165 log("channel_request: %d: bad id", id);
2166 return;
2167 }
2168 packet_start(SSH2_MSG_CHANNEL_REQUEST);
2169 packet_put_int(c->remote_id);
2170 packet_put_cstring(service);
2171 packet_put_char(wantconfirm);
2172}
2173void
2174channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg)
2175{
2176 Channel *c = channel_lookup(id);
2177 if (c == NULL) {
2178 log("channel_register_callback: %d: bad id", id);
2179 return;
2180 }
2181 c->cb_event = mtype;
2182 c->cb_fn = fn;
2183 c->cb_arg = arg;
2184}
2185void
2186channel_register_cleanup(int id, channel_callback_fn *fn)
2187{
2188 Channel *c = channel_lookup(id);
2189 if (c == NULL) {
2190 log("channel_register_cleanup: %d: bad id", id);
2191 return;
2192 }
2193 c->dettach_user = fn;
2194}
2195void
2196channel_cancel_cleanup(int id)
2197{
2198 Channel *c = channel_lookup(id);
2199 if (c == NULL) {
2200 log("channel_cancel_cleanup: %d: bad id", id);
2201 return;
2202 }
2203 c->dettach_user = NULL;
2204}
2205
2206void
2207channel_set_fds(int id, int rfd, int wfd, int efd, int extusage)
2208{
2209 Channel *c = channel_lookup(id);
2210 if (c == NULL || c->type != SSH_CHANNEL_LARVAL)
2211 fatal("channel_activate for non-larval channel %d.", id);
2212 if (rfd > channel_max_fd_value)
2213 channel_max_fd_value = rfd;
2214 if (wfd > channel_max_fd_value)
2215 channel_max_fd_value = wfd;
2216 if (efd > channel_max_fd_value)
2217 channel_max_fd_value = efd;
2218 c->type = SSH_CHANNEL_OPEN;
2219 c->rfd = rfd;
2220 c->wfd = wfd;
2221 c->efd = efd;
2222 c->extended_usage = extusage;
2223 /* XXX window size? */
2224 c->local_window = c->local_window_max = c->local_maxpacket/2;
2225 packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
2226 packet_put_int(c->remote_id);
2227 packet_put_int(c->local_window);
2228 packet_send();
2229}
diff --git a/channels.h b/channels.h
index 73ff5a595..33af09d9d 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
1/* RCSID("$Id: channels.h,v 1.5 2000/04/01 01:09:23 damien Exp $"); */ 1/* RCSID("$Id: channels.h,v 1.6 2000/04/04 04:39:01 damien Exp $"); */
2 2
3#ifndef CHANNELS_H 3#ifndef CHANNELS_H
4#define CHANNELS_H 4#define CHANNELS_H
@@ -30,6 +30,7 @@ typedef struct Channel {
30 /* peer can be reached over encrypted connection, via packet-sent */ 30 /* peer can be reached over encrypted connection, via packet-sent */
31 int istate; /* input from channel (state of receive half) */ 31 int istate; /* input from channel (state of receive half) */
32 int ostate; /* output to channel (state of transmit half) */ 32 int ostate; /* output to channel (state of transmit half) */
33 int flags; /* close sent/rcvd */
33 int rfd; /* read fd */ 34 int rfd; /* read fd */
34 int wfd; /* write fd */ 35 int wfd; /* write fd */
35 int efd; /* extended fd */ 36 int efd; /* extended fd */
@@ -66,21 +67,30 @@ typedef struct Channel {
66#define CHAN_EXTENDED_READ 1 67#define CHAN_EXTENDED_READ 1
67#define CHAN_EXTENDED_WRITE 2 68#define CHAN_EXTENDED_WRITE 2
68 69
70void channel_set_fds(int id, int rfd, int wfd, int efd, int extusage);
69void channel_open(int id); 71void channel_open(int id);
72void channel_request(int id, char *service, int wantconfirm);
73void channel_request_start(int id, char *service, int wantconfirm);
74void channel_register_callback(int id, int mtype, channel_callback_fn *fn, void *arg);
75void channel_register_cleanup(int id, channel_callback_fn *fn);
76void channel_cancel_cleanup(int id);
70Channel *channel_lookup(int id); 77Channel *channel_lookup(int id);
71 78
72int 79int
73channel_new(char *ctype, int type, int rfd, int wfd, int efd, 80channel_new(char *ctype, int type, int rfd, int wfd, int efd,
74 int window, int maxpack, int extended_usage, char *remote_name); 81 int window, int maxpack, int extended_usage, char *remote_name);
75 82
83void channel_input_channel_request(int type, int plen);
76void channel_input_close(int type, int plen); 84void channel_input_close(int type, int plen);
77void channel_input_close_confirmation(int type, int plen); 85void channel_input_close_confirmation(int type, int plen);
78void channel_input_data(int type, int plen); 86void channel_input_data(int type, int plen);
87void channel_input_extended_data(int type, int plen);
79void channel_input_ieof(int type, int plen); 88void channel_input_ieof(int type, int plen);
80void channel_input_oclose(int type, int plen); 89void channel_input_oclose(int type, int plen);
81void channel_input_open_confirmation(int type, int plen); 90void channel_input_open_confirmation(int type, int plen);
82void channel_input_open_failure(int type, int plen); 91void channel_input_open_failure(int type, int plen);
83void channel_input_port_open(int type, int plen); 92void channel_input_port_open(int type, int plen);
93void channel_input_window_adjust(int type, int plen);
84void channel_input_open(int type, int plen); 94void channel_input_open(int type, int plen);
85 95
86/* Sets specific protocol options. */ 96/* Sets specific protocol options. */
@@ -218,4 +228,7 @@ void auth_input_request_forwarding(struct passwd * pw);
218/* This is called to process an SSH_SMSG_AGENT_OPEN message. */ 228/* This is called to process an SSH_SMSG_AGENT_OPEN message. */
219void auth_input_open_request(int type, int plen); 229void auth_input_open_request(int type, int plen);
220 230
231/* XXX */
232int channel_connect_to(const char *host, u_short host_port);
233
221#endif 234#endif
diff --git a/compat.c b/compat.c
index d39a3d6f7..3ecf7101e 100644
--- a/compat.c
+++ b/compat.c
@@ -28,15 +28,46 @@
28 */ 28 */
29 29
30#include "includes.h" 30#include "includes.h"
31RCSID("$Id: compat.c,v 1.3 1999/11/25 00:54:59 damien Exp $"); 31RCSID("$Id: compat.c,v 1.4 2000/04/04 04:39:01 damien Exp $");
32 32
33#include "ssh.h" 33#include "ssh.h"
34#include "packet.h"
34 35
35int compat13 = 0; 36int compat13 = 0;
37int compat20 = 0;
38int datafellows = 0;
36 39
37void 40void
41enable_compat20(void)
42{
43 fatal("protocol 2.0 not implemented");
44}
45void
38enable_compat13(void) 46enable_compat13(void)
39{ 47{
40 verbose("Enabling compatibility mode for protocol 1.3"); 48 verbose("Enabling compatibility mode for protocol 1.3");
41 compat13 = 1; 49 compat13 = 1;
42} 50}
51/* datafellows bug compatibility */
52void
53compat_datafellows(const char *version)
54{
55 int i;
56 size_t len;
57 static const char *check[] = {
58 "2.0.1",
59 "2.1.0.beta.9",
60 "2.1.0.pre.3",
61 "2.1.0.public.beta.1",
62 NULL
63 };
64 for (i = 0; check[i]; i++) {
65 len = strlen(check[i]);
66 if (strlen(version) >= len &&
67 (strncmp(version, check[i], len) == 0)) {
68 log("datafellows: %.200s", version);
69 datafellows = 1;
70 return;
71 }
72 }
73}
diff --git a/compat.h b/compat.h
index 4f53607f3..4247f53b4 100644
--- a/compat.h
+++ b/compat.h
@@ -26,10 +26,14 @@
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29/* RCSID("$Id: compat.h,v 1.3 1999/11/25 00:54:59 damien Exp $"); */ 29/* RCSID("$Id: compat.h,v 1.4 2000/04/04 04:39:01 damien Exp $"); */
30 30
31#ifndef COMPAT_H 31#ifndef COMPAT_H
32#define COMPAT_H 32#define COMPAT_H
33void enable_compat13(void); 33void enable_compat13(void);
34void enable_compat20(void);
35void compat_datafellows(const char *s);
34extern int compat13; 36extern int compat13;
37extern int compat20;
38extern int datafellows;
35#endif 39#endif
diff --git a/dsa.c b/dsa.c
new file mode 100644
index 000000000..99d8ceaf9
--- /dev/null
+++ b/dsa.c
@@ -0,0 +1,309 @@
1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "includes.h"
31RCSID("$Id: dsa.c,v 1.1 2000/04/03 20:06:14 markus Exp $");
32
33#include "ssh.h"
34#include "xmalloc.h"
35#include "buffer.h"
36#include "bufaux.h"
37#include "compat.h"
38
39#if HAVE_OPENSSL
40# include <openssl/bn.h>
41# include <openssl/dh.h>
42# include <openssl/rsa.h>
43# include <openssl/dsa.h>
44# include <openssl/evp.h>
45# include <openssl/bio.h>
46# include <openssl/pem.h>
47#endif /* HAVE_OPENSSL */
48#if HAVE_SSL
49# include <ssl/bn.h>
50# include <ssl/dh.h>
51# include <ssl/rsa.h>
52# include <ssl/dsa.h>
53# include <ssl/evp.h>
54# include <ssl/bio.h>
55# include <ssl/pem.h>
56#endif /* HAVE_SSL */
57
58#include <ssl/hmac.h>
59#include "kex.h"
60#include "key.h"
61
62#define INTBLOB_LEN 20
63#define SIGBLOB_LEN (2*INTBLOB_LEN)
64
65Key *
66dsa_serverkey_from_blob(
67 char *serverhostkey, int serverhostkeylen)
68{
69 Buffer b;
70 char *ktype;
71 int rlen;
72 DSA *dsa;
73 Key *key;
74
75 /* fetch & parse DSA/DSS pubkey */
76 key = key_new(KEY_DSA);
77 dsa = key->dsa;
78 buffer_init(&b);
79 buffer_append(&b, serverhostkey, serverhostkeylen);
80 ktype = buffer_get_string(&b, NULL);
81 if (strcmp(KEX_DSS, ktype) != 0) {
82 log("dsa_serverkey_from_blob: cannot handle type %s", ktype);
83 key_free(key);
84 return NULL;
85 }
86 buffer_get_bignum2(&b, dsa->p);
87 buffer_get_bignum2(&b, dsa->q);
88 buffer_get_bignum2(&b, dsa->g);
89 buffer_get_bignum2(&b, dsa->pub_key);
90 rlen = buffer_len(&b);
91 if(rlen != 0)
92 log("dsa_serverkey_from_blob: remaining bytes in serverhostkey %d", rlen);
93 buffer_free(&b);
94
95 log("keytype %s", ktype);
96#ifdef DEBUG_DSS
97 DSA_print_fp(stderr, dsa, 8);
98#endif
99 return key;
100}
101DSA *
102dsa_load_private(char *filename)
103{
104 DSA *dsa;
105 BIO *in;
106
107 in = BIO_new(BIO_s_file());
108 if (in == NULL)
109 fatal("BIO_new failed");
110 if (BIO_read_filename(in, filename) <= 0)
111 fatal("BIO_read failed %s: %s", filename, strerror(errno));
112 fprintf(stderr, "read DSA private key\n");
113 dsa = PEM_read_bio_DSAPrivateKey(in,NULL,NULL,NULL);
114 if (dsa == NULL)
115 fatal("PEM_read_bio_DSAPrivateKey failed %s", filename);
116 BIO_free(in);
117 return dsa;
118}
119Key *
120dsa_get_serverkey(char *filename)
121{
122 Key *k = key_new(KEY_EMPTY);
123 k->type = KEY_DSA;
124 k->dsa = dsa_load_private(filename);
125#ifdef DEBUG_DSS
126 DSA_print_fp(stderr, dsa, 8);
127#endif
128 return k;
129}
130int
131dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp)
132{
133 Buffer b;
134 int len;
135 unsigned char *buf;
136
137 if (key == NULL || key->type != KEY_DSA)
138 return 0;
139 buffer_init(&b);
140 buffer_put_cstring(&b, KEX_DSS);
141 buffer_put_bignum2(&b, key->dsa->p);
142 buffer_put_bignum2(&b, key->dsa->q);
143 buffer_put_bignum2(&b, key->dsa->g);
144 buffer_put_bignum2(&b, key->dsa->pub_key);
145 len = buffer_len(&b);
146 buf = xmalloc(len);
147 memcpy(buf, buffer_ptr(&b), len);
148 memset(buffer_ptr(&b), 0, len);
149 buffer_free(&b);
150 if (lenp != NULL)
151 *lenp = len;
152 if (blobp != NULL)
153 *blobp = buf;
154 return len;
155}
156int
157dsa_sign(
158 Key *key,
159 unsigned char **sigp, int *lenp,
160 unsigned char *hash, int hlen)
161{
162 unsigned char *digest;
163 unsigned char *ret;
164 DSA_SIG *sig;
165 EVP_MD *evp_md = EVP_sha1();
166 EVP_MD_CTX md;
167 unsigned int rlen;
168 unsigned int slen;
169 unsigned int len;
170 unsigned char sigblob[SIGBLOB_LEN];
171 Buffer b;
172
173 if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
174 log("dsa_sign: no DSA key");
175 return -1;
176 }
177 digest = xmalloc(evp_md->md_size);
178 EVP_DigestInit(&md, evp_md);
179 EVP_DigestUpdate(&md, hash, hlen);
180 EVP_DigestFinal(&md, digest, NULL);
181
182 sig = DSA_do_sign(digest, evp_md->md_size, key->dsa);
183
184 rlen = BN_num_bytes(sig->r);
185 slen = BN_num_bytes(sig->s);
186 if (rlen > INTBLOB_LEN || slen > INTBLOB_LEN) {
187 log("bad sig size %d %d", rlen, slen);
188 DSA_SIG_free(sig);
189 return -1;
190 }
191 log("sig size %d %d", rlen, slen);
192
193 memset(sigblob, 0, SIGBLOB_LEN);
194 BN_bn2bin(sig->r, sigblob+ SIGBLOB_LEN - INTBLOB_LEN - rlen);
195 BN_bn2bin(sig->s, sigblob+ SIGBLOB_LEN - slen);
196 DSA_SIG_free(sig);
197
198 if (datafellows) {
199 log("datafellows");
200 ret = xmalloc(SIGBLOB_LEN);
201 memcpy(ret, sigblob, SIGBLOB_LEN);
202 if (lenp != NULL)
203 *lenp = SIGBLOB_LEN;
204 if (sigp != NULL)
205 *sigp = ret;
206 } else {
207 /* ietf-drafts */
208 buffer_init(&b);
209 buffer_put_cstring(&b, KEX_DSS);
210 buffer_put_string(&b, sigblob, SIGBLOB_LEN);
211 len = buffer_len(&b);
212 ret = xmalloc(len);
213 memcpy(ret, buffer_ptr(&b), len);
214 buffer_free(&b);
215 if (lenp != NULL)
216 *lenp = len;
217 if (sigp != NULL)
218 *sigp = ret;
219 }
220 return 0;
221}
222int
223dsa_verify(
224 Key *key,
225 unsigned char *signature, int signaturelen,
226 unsigned char *hash, int hlen)
227{
228 Buffer b;
229 unsigned char *digest;
230 DSA_SIG *sig;
231 EVP_MD *evp_md = EVP_sha1();
232 EVP_MD_CTX md;
233 char *ktype;
234 unsigned char *sigblob;
235 char *txt;
236 unsigned int len;
237 int rlen;
238 int ret;
239
240 if (key == NULL || key->type != KEY_DSA || key->dsa == NULL) {
241 log("dsa_verify: no DSA key");
242 return -1;
243 }
244
245 if (datafellows && signaturelen != SIGBLOB_LEN) {
246 log("heh? datafellows ssh2 complies with ietf-drafts????");
247 datafellows = 0;
248 }
249
250 log("len %d datafellows %d", signaturelen, datafellows);
251
252 /* fetch signature */
253 if (datafellows) {
254 sigblob = signature;
255 len = signaturelen;
256 } else {
257 /* ietf-drafts */
258 buffer_init(&b);
259 buffer_append(&b, (char *) signature, signaturelen);
260 ktype = buffer_get_string(&b, NULL);
261 sigblob = (unsigned char *)buffer_get_string(&b, &len);
262 rlen = buffer_len(&b);
263 if(rlen != 0)
264 log("remaining bytes in signature %d", rlen);
265 buffer_free(&b);
266 }
267
268 if (len != SIGBLOB_LEN) {
269 fatal("bad sigbloblen %d != SIGBLOB_LEN", len);
270 }
271
272 /* parse signature */
273 sig = DSA_SIG_new();
274 sig->r = BN_new();
275 sig->s = BN_new();
276 BN_bin2bn(sigblob, INTBLOB_LEN, sig->r);
277 BN_bin2bn(sigblob+ INTBLOB_LEN, INTBLOB_LEN, sig->s);
278 if (!datafellows) {
279 memset(sigblob, 0, len);
280 xfree(sigblob);
281 }
282
283 /* sha1 the signed data (== session_id == hash) */
284 digest = xmalloc(evp_md->md_size);
285 EVP_DigestInit(&md, evp_md);
286 EVP_DigestUpdate(&md, hash, hlen);
287 EVP_DigestFinal(&md, digest, NULL);
288
289 ret = DSA_do_verify(digest, evp_md->md_size, sig, key->dsa);
290
291 memset(digest, 0, evp_md->md_size);
292 xfree(digest);
293 DSA_SIG_free(sig);
294
295 switch (ret) {
296 case 1:
297 txt = "correct";
298 break;
299 case 0:
300 txt = "incorrect";
301 break;
302 case -1:
303 default:
304 txt = "error";
305 break;
306 }
307 log("dsa_verify: signature %s", txt);
308 return ret;
309}
diff --git a/dsa.h b/dsa.h
new file mode 100644
index 000000000..65e651d9b
--- /dev/null
+++ b/dsa.h
@@ -0,0 +1,20 @@
1#ifndef DSA_H
2#define DSA_H
3
4Key *dsa_serverkey_from_blob(char *serverhostkey, int serverhostkeylen);
5Key *dsa_get_serverkey(char *filename);
6int dsa_make_serverkey_blob(Key *key, unsigned char **blobp, unsigned int *lenp);
7
8int
9dsa_sign(
10 Key *key,
11 unsigned char **sigp, int *lenp,
12 unsigned char *hash, int hlen);
13
14int
15dsa_verify(
16 Key *key,
17 unsigned char *signature, int signaturelen,
18 unsigned char *hash, int hlen);
19
20#endif
diff --git a/hmac.c b/hmac.c
new file mode 100644
index 000000000..45037ef87
--- /dev/null
+++ b/hmac.c
@@ -0,0 +1,64 @@
1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "includes.h"
31RCSID("$Id: hmac.c,v 1.1 2000/04/03 20:06:15 markus Exp $");
32
33#include "xmalloc.h"
34#include "ssh.h"
35#include "getput.h"
36
37#if HAVE_OPENSSL
38# include <openssl/hmac.h>
39#endif /* HAVE_OPENSSL */
40#if HAVE_SSL
41# include <ssl/hmac.h>
42#endif /* HAVE_SSL */
43
44unsigned char *
45hmac(
46 EVP_MD *evp_md,
47 unsigned int seqno,
48 unsigned char *data, int datalen,
49 unsigned char *key, int keylen)
50{
51 HMAC_CTX c;
52 static unsigned char m[EVP_MAX_MD_SIZE];
53 unsigned char b[4];
54
55 if (key == NULL)
56 fatal("hmac: no key");
57 HMAC_Init(&c, key, keylen, evp_md);
58 PUT_32BIT(b, seqno);
59 HMAC_Update(&c, b, sizeof b);
60 HMAC_Update(&c, data, datalen);
61 HMAC_Final(&c, m, NULL);
62 HMAC_cleanup(&c);
63 return(m);
64}
diff --git a/hmac.h b/hmac.h
new file mode 100644
index 000000000..fb6802927
--- /dev/null
+++ b/hmac.h
@@ -0,0 +1,11 @@
1#ifndef HMAC_H
2#define HMAC_H
3
4unsigned char *
5hmac(
6 EVP_MD *evp_md,
7 unsigned int seqno,
8 unsigned char *data, int datalen,
9 unsigned char *key, int len);
10
11#endif
diff --git a/kex.c b/kex.c
new file mode 100644
index 000000000..e730536ac
--- /dev/null
+++ b/kex.c
@@ -0,0 +1,407 @@
1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "includes.h"
31RCSID("$Id: kex.c,v 1.1 2000/04/04 04:39:02 damien Exp $");
32
33#include "ssh.h"
34#include "ssh2.h"
35#include "xmalloc.h"
36#include "buffer.h"
37#include "bufaux.h"
38#include "cipher.h"
39#include "compat.h"
40
41#if HAVE_OPENSSL
42# include <openssl/bn.h>
43# include <openssl/dh.h>
44# include <openssl/crypto.h>
45# include <openssl/bio.h>
46# include <openssl/bn.h>
47# include <openssl/dh.h>
48# include <openssl/pem.h>
49#endif /* HAVE_OPENSSL */
50#if HAVE_SSL
51# include <ssl/bn.h>
52# include <ssl/dh.h>
53# include <ssl/crypto.h>
54# include <ssl/bio.h>
55# include <ssl/bn.h>
56# include <ssl/dh.h>
57# include <ssl/pem.h>
58#endif /* HAVE_SSL */
59
60#include "entropy.h"
61#include "kex.h"
62
63Buffer *
64kex_init(char *myproposal[PROPOSAL_MAX])
65{
66 char c = 0;
67 unsigned char cookie[16];
68 u_int32_t rand = 0;
69 int i;
70 Buffer *ki = xmalloc(sizeof(*ki));
71 for (i = 0; i < 16; i++) {
72 if (i % 4 == 0)
73 rand = arc4random();
74 cookie[i] = rand & 0xff;
75 rand >>= 8;
76 }
77 buffer_init(ki);
78 buffer_append(ki, (char *)cookie, sizeof cookie);
79 for (i = 0; i < PROPOSAL_MAX; i++)
80 buffer_put_cstring(ki, myproposal[i]);
81 buffer_append(ki, &c, 1); /* boolean first_kex_packet_follows */
82 buffer_put_int(ki, 0); /* uint32 0 (reserved for future extension) */
83 return ki;
84}
85
86/* diffie-hellman-group1-sha1 */
87
88DH *
89new_dh_group1()
90{
91 static char *group1 =
92 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
93 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
94 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
95 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
96 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
97 "FFFFFFFF" "FFFFFFFF";
98 DH *dh;
99 int ret;
100 dh = DH_new();
101 if(dh == NULL)
102 fatal("DH_new");
103 ret = BN_hex2bn(&dh->p,group1);
104 if(ret<0)
105 fatal("BN_hex2bn");
106 dh->g = BN_new();
107 if(dh->g == NULL)
108 fatal("DH_new g");
109 BN_set_word(dh->g,2);
110
111 seed_rng();
112 if (DH_generate_key(dh) == 0)
113 fatal("DH_generate_key");
114 seed_rng();
115
116 return dh;
117}
118
119void
120bignum_print(BIGNUM *b)
121{
122 BN_print_fp(stderr,b);
123}
124
125void
126dump_digest(unsigned char *digest, int len)
127{
128 int i;
129 for (i = 0; i< len; i++){
130 fprintf(stderr, "%02x", digest[i]);
131 if(i%2!=0)
132 fprintf(stderr, " ");
133 }
134 fprintf(stderr, "\n");
135}
136
137unsigned char *
138kex_hash(
139 char *client_version_string,
140 char *server_version_string,
141 char *ckexinit, int ckexinitlen,
142 char *skexinit, int skexinitlen,
143 char *serverhostkeyblob, int sbloblen,
144 BIGNUM *client_dh_pub,
145 BIGNUM *server_dh_pub,
146 BIGNUM *shared_secret)
147{
148 Buffer b;
149 static unsigned char digest[EVP_MAX_MD_SIZE];
150 EVP_MD *evp_md = EVP_sha1();
151 EVP_MD_CTX md;
152
153 buffer_init(&b);
154 buffer_put_string(&b, client_version_string, strlen(client_version_string));
155 buffer_put_string(&b, server_version_string, strlen(server_version_string));
156
157 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
158 buffer_put_int(&b, ckexinitlen+1);
159 buffer_put_char(&b, SSH2_MSG_KEXINIT);
160 buffer_append(&b, ckexinit, ckexinitlen);
161 buffer_put_int(&b, skexinitlen+1);
162 buffer_put_char(&b, SSH2_MSG_KEXINIT);
163 buffer_append(&b, skexinit, skexinitlen);
164
165 buffer_put_string(&b, serverhostkeyblob, sbloblen);
166 buffer_put_bignum2(&b, client_dh_pub);
167 buffer_put_bignum2(&b, server_dh_pub);
168 buffer_put_bignum2(&b, shared_secret);
169
170#ifdef DEBUG_KEX
171 buffer_dump(&b);
172#endif
173
174 EVP_DigestInit(&md, evp_md);
175 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
176 EVP_DigestFinal(&md, digest, NULL);
177
178 buffer_free(&b);
179
180#ifdef DEBUG_KEX
181 dump_digest(digest, evp_md->md_size);
182#endif
183 return digest;
184}
185
186unsigned char *
187derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
188{
189 Buffer b;
190 EVP_MD *evp_md = EVP_sha1();
191 EVP_MD_CTX md;
192 char c = id;
193 int have;
194 int mdsz = evp_md->md_size;
195 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
196
197 buffer_init(&b);
198 buffer_put_bignum2(&b, shared_secret);
199
200 EVP_DigestInit(&md, evp_md);
201 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
202 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
203 EVP_DigestUpdate(&md, &c, 1); /* key id */
204 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
205 EVP_DigestFinal(&md, digest, NULL);
206
207 /* expand */
208 for (have = mdsz; need > have; have += mdsz) {
209 EVP_DigestInit(&md, evp_md);
210 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
211 EVP_DigestUpdate(&md, hash, mdsz);
212 EVP_DigestUpdate(&md, digest, have);
213 EVP_DigestFinal(&md, digest + have, NULL);
214 }
215 buffer_free(&b);
216#ifdef DEBUG_KEX
217 fprintf(stderr, "Digest '%c'== ", c);
218 dump_digest(digest, need);
219#endif
220 return digest;
221}
222
223#define NKEYS 6
224
225#define MAX_PROP 20
226#define SEP ","
227
228char *
229get_match(char *client, char *server)
230{
231 char *sproposals[MAX_PROP];
232 char *p;
233 int i, j, nproposals;
234
235 for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
236 if (i < MAX_PROP)
237 sproposals[i] = p;
238 else
239 break;
240 }
241 nproposals = i;
242
243 for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
244 for (j = 0; j < nproposals; j++)
245 if (strcmp(p, sproposals[j]) == 0)
246 return xstrdup(p);
247 }
248 return NULL;
249}
250void
251choose_enc(Enc *enc, char *client, char *server)
252{
253 char *name = get_match(client, server);
254 if (name == NULL)
255 fatal("no matching cipher found: client %s server %s", client, server);
256 enc->type = cipher_number(name);
257
258 switch (enc->type) {
259 case SSH_CIPHER_3DES_CBC:
260 enc->key_len = 24;
261 enc->iv_len = 8;
262 enc->block_size = 8;
263 break;
264 case SSH_CIPHER_BLOWFISH_CBC:
265 case SSH_CIPHER_CAST128_CBC:
266 enc->key_len = 16;
267 enc->iv_len = 8;
268 enc->block_size = 8;
269 break;
270 case SSH_CIPHER_ARCFOUR:
271 enc->key_len = 16;
272 enc->iv_len = 0;
273 enc->block_size = 8;
274 break;
275 default:
276 fatal("unsupported cipher %s", name);
277 }
278 enc->name = name;
279 enc->enabled = 0;
280 enc->iv = NULL;
281 enc->key = NULL;
282}
283void
284choose_mac(Mac *mac, char *client, char *server)
285{
286 char *name = get_match(client, server);
287 if (name == NULL)
288 fatal("no matching mac found: client %s server %s", client, server);
289 if (strcmp(name, "hmac-md5") == 0) {
290 mac->md = EVP_md5();
291 } else if (strcmp(name, "hmac-sha1") == 0) {
292 mac->md = EVP_sha1();
293 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
294 mac->md = EVP_ripemd160();
295 } else {
296 fatal("unsupported mac %s", name);
297 }
298 mac->name = name;
299 mac->mac_len = mac->md->md_size;
300 mac->key_len = datafellows ? 16 : mac->mac_len;
301 mac->key = NULL;
302 mac->enabled = 0;
303}
304void
305choose_comp(Comp *comp, char *client, char *server)
306{
307 char *name = get_match(client, server);
308 if (name == NULL)
309 fatal("no matching comp found: client %s server %s", client, server);
310 if (strcmp(name, "zlib") == 0) {
311 comp->type = 1;
312 } else if (strcmp(name, "none") == 0) {
313 comp->type = 0;
314 } else {
315 fatal("unsupported comp %s", name);
316 }
317 comp->name = name;
318}
319void
320choose_kex(Kex *k, char *client, char *server)
321{
322 k->name = get_match(client, server);
323 if (k->name == NULL)
324 fatal("no kex alg");
325 if (strcmp(k->name, KEX_DH1) != 0)
326 fatal("bad kex alg %s", k->name);
327}
328void
329choose_hostkeyalg(Kex *k, char *client, char *server)
330{
331 k->hostkeyalg = get_match(client, server);
332 if (k->hostkeyalg == NULL)
333 fatal("no hostkey alg");
334 if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
335 fatal("bad hostkey alg %s", k->hostkeyalg);
336}
337
338Kex *
339kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
340{
341 int i;
342 int mode;
343 int ctos; /* direction: if true client-to-server */
344 int need;
345 Kex *k;
346
347 k = xmalloc(sizeof(*k));
348 memset(k, 0, sizeof(*k));
349 k->server = server;
350
351 for (mode = 0; mode < MODE_MAX; mode++) {
352 int nenc, nmac, ncomp;
353 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
354 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
355 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
356 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
357 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
358 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
359 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
360 log("kex: %s %s %s %s",
361 ctos ? "client->server" : "server->client",
362 k->enc[mode].name,
363 k->mac[mode].name,
364 k->comp[mode].name);
365 }
366 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
367 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
368 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
369 for (i = 0; i < PROPOSAL_MAX; i++) {
370 xfree(cprop[i]);
371 xfree(sprop[i]);
372 }
373 need = 0;
374 for (mode = 0; mode < MODE_MAX; mode++) {
375 if (need < k->enc[mode].key_len)
376 need = k->enc[mode].key_len;
377 if (need < k->enc[mode].iv_len)
378 need = k->enc[mode].iv_len;
379 if (need < k->mac[mode].key_len)
380 need = k->mac[mode].key_len;
381 }
382 /* need runden? */
383#define WE_NEED 32
384 k->we_need = WE_NEED;
385 k->we_need = need;
386 return k;
387}
388
389int
390kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
391{
392 int i;
393 int mode;
394 int ctos;
395 unsigned char *keys[NKEYS];
396
397 for (i = 0; i < NKEYS; i++)
398 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
399
400 for (mode = 0; mode < MODE_MAX; mode++) {
401 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
402 k->enc[mode].iv = keys[ctos ? 0 : 1];
403 k->enc[mode].key = keys[ctos ? 2 : 3];
404 k->mac[mode].key = keys[ctos ? 4 : 5];
405 }
406 return 0;
407}
diff --git a/kex.h b/kex.h
new file mode 100644
index 000000000..f9e799948
--- /dev/null
+++ b/kex.h
@@ -0,0 +1,111 @@
1/*
2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29#ifndef KEX_H
30#define KEX_H
31
32#define KEX_DH1 "diffie-hellman-group1-sha1"
33#define KEX_DSS "ssh-dss"
34
35enum kex_init_proposals {
36 PROPOSAL_KEX_ALGS,
37 PROPOSAL_SERVER_HOST_KEY_ALGS,
38 PROPOSAL_ENC_ALGS_CTOS,
39 PROPOSAL_ENC_ALGS_STOC,
40 PROPOSAL_MAC_ALGS_CTOS,
41 PROPOSAL_MAC_ALGS_STOC,
42 PROPOSAL_COMP_ALGS_CTOS,
43 PROPOSAL_COMP_ALGS_STOC,
44 PROPOSAL_LANG_CTOS,
45 PROPOSAL_LANG_STOC,
46 PROPOSAL_MAX
47};
48
49enum kex_modes {
50 MODE_IN,
51 MODE_OUT,
52 MODE_MAX
53};
54
55typedef struct Kex Kex;
56typedef struct Mac Mac;
57typedef struct Comp Comp;
58typedef struct Enc Enc;
59
60struct Enc {
61 int type;
62 int enabled;
63 int block_size;
64 unsigned char *key;
65 unsigned char *iv;
66 int key_len;
67 int iv_len;
68 char *name;
69};
70struct Mac {
71 EVP_MD *md;
72 int enabled;
73 int mac_len;
74 unsigned char *key;
75 int key_len;
76 char *name;
77};
78struct Comp {
79 int type;
80 int enabled;
81 char *name;
82};
83struct Kex {
84 Enc enc [MODE_MAX];
85 Mac mac [MODE_MAX];
86 Comp comp[MODE_MAX];
87 int we_need;
88 int server;
89 char *name;
90 char *hostkeyalg;
91};
92
93Buffer *kex_init(char *myproposal[PROPOSAL_MAX]);
94DH *new_dh_group1();
95Kex *kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server);
96int kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret);
97void bignum_print(BIGNUM *b);
98void packet_set_kex(Kex *k);
99
100unsigned char *
101kex_hash(
102 char *client_version_string,
103 char *server_version_string,
104 char *ckexinit, int ckexinitlen,
105 char *skexinit, int skexinitlen,
106 char *serverhostkeyblob, int sbloblen,
107 BIGNUM *client_dh_pub,
108 BIGNUM *server_dh_pub,
109 BIGNUM *shared_secret);
110
111#endif
diff --git a/nchan.c b/nchan.c
index 996623fb4..3795d8ad4 100644
--- a/nchan.c
+++ b/nchan.c
@@ -28,7 +28,7 @@
28 */ 28 */
29 29
30#include "includes.h" 30#include "includes.h"
31RCSID("$Id: nchan.c,v 1.6 2000/04/01 01:09:24 damien Exp $"); 31RCSID("$Id: nchan.c,v 1.7 2000/04/04 04:39:02 damien Exp $");
32 32
33#include "ssh.h" 33#include "ssh.h"
34 34
@@ -37,138 +37,169 @@ RCSID("$Id: nchan.c,v 1.6 2000/04/01 01:09:24 damien Exp $");
37#include "channels.h" 37#include "channels.h"
38#include "nchan.h" 38#include "nchan.h"
39 39
40static void chan_send_ieof(Channel *c); 40#include "ssh2.h"
41static void chan_send_oclose(Channel *c); 41#include "compat.h"
42static void chan_shutdown_write(Channel *c);
43static void chan_shutdown_read(Channel *c);
44 42
43/* functions manipulating channel states */
45/* 44/*
46 * EVENTS update channel input/output states execute ACTIONS 45 * EVENTS update channel input/output states execute ACTIONS
47 */ 46 */
48
49/* events concerning the INPUT from socket for channel (istate) */ 47/* events concerning the INPUT from socket for channel (istate) */
50void 48chan_event_fn *chan_rcvd_oclose = NULL;
51chan_rcvd_oclose(Channel *c) 49chan_event_fn *chan_read_failed = NULL;
50chan_event_fn *chan_ibuf_empty = NULL;
51/* events concerning the OUTPUT from channel for socket (ostate) */
52chan_event_fn *chan_rcvd_ieof = NULL;
53chan_event_fn *chan_write_failed = NULL;
54chan_event_fn *chan_obuf_empty = NULL;
55/*
56 * ACTIONS: should never update the channel states
57 */
58static void chan_send_ieof1(Channel *c);
59static void chan_send_oclose1(Channel *c);
60static void chan_send_close2(Channel *c);
61static void chan_send_eof2(Channel *c);
62
63/* channel cleanup */
64chan_event_fn *chan_delete_if_full_closed = NULL;
65
66/* helper */
67static void chan_shutdown_write(Channel *c);
68static void chan_shutdown_read(Channel *c);
69
70/*
71 * SSH1 specific implementation of event functions
72 */
73
74static void
75chan_rcvd_oclose1(Channel *c)
52{ 76{
77 debug("channel %d: rcvd oclose", c->self);
53 switch (c->istate) { 78 switch (c->istate) {
54 case CHAN_INPUT_WAIT_OCLOSE: 79 case CHAN_INPUT_WAIT_OCLOSE:
55 debug("channel %d: INPUT_WAIT_OCLOSE -> INPUT_CLOSED [rcvd OCLOSE]", c->self); 80 debug("channel %d: input wait_oclose -> closed", c->self);
56 c->istate = CHAN_INPUT_CLOSED; 81 c->istate = CHAN_INPUT_CLOSED;
57 break; 82 break;
58 case CHAN_INPUT_OPEN: 83 case CHAN_INPUT_OPEN:
59 debug("channel %d: INPUT_OPEN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self); 84 debug("channel %d: input open -> closed", c->self);
60 chan_shutdown_read(c); 85 chan_shutdown_read(c);
61 chan_send_ieof(c); 86 chan_send_ieof1(c);
62 c->istate = CHAN_INPUT_CLOSED; 87 c->istate = CHAN_INPUT_CLOSED;
63 break; 88 break;
64 case CHAN_INPUT_WAIT_DRAIN: 89 case CHAN_INPUT_WAIT_DRAIN:
65 /* both local read_failed and remote write_failed */ 90 /* both local read_failed and remote write_failed */
66 log("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self); 91 log("channel %d: input drain -> closed", c->self);
67 debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_CLOSED [rvcd OCLOSE, send IEOF]", c->self); 92 chan_send_ieof1(c);
68 chan_send_ieof(c);
69 c->istate = CHAN_INPUT_CLOSED; 93 c->istate = CHAN_INPUT_CLOSED;
70 break; 94 break;
71 default: 95 default:
72 error("protocol error: chan_rcvd_oclose %d for istate %d", c->self, c->istate); 96 error("channel %d: protocol error: chan_rcvd_oclose for istate %d",
97 c->self, c->istate);
73 return; 98 return;
74 } 99 }
75} 100}
76void 101static void
77chan_read_failed(Channel *c) 102chan_read_failed_12(Channel *c)
78{ 103{
104 debug("channel %d: read failed", c->self);
79 switch (c->istate) { 105 switch (c->istate) {
80 case CHAN_INPUT_OPEN: 106 case CHAN_INPUT_OPEN:
81 debug("channel %d: INPUT_OPEN -> INPUT_WAIT_DRAIN [read failed]", c->self); 107 debug("channel %d: input open -> drain", c->self);
82 chan_shutdown_read(c); 108 chan_shutdown_read(c);
83 c->istate = CHAN_INPUT_WAIT_DRAIN; 109 c->istate = CHAN_INPUT_WAIT_DRAIN;
84 break; 110 break;
85 default: 111 default:
86 error("internal error: we do not read, but chan_read_failed %d for istate %d", 112 error("channel %d: internal error: we do not read, but chan_read_failed for istate %d",
87 c->self, c->istate); 113 c->self, c->istate);
88 break; 114 break;
89 } 115 }
90} 116}
91void 117static void
92chan_ibuf_empty(Channel *c) 118chan_ibuf_empty1(Channel *c)
93{ 119{
120 debug("channel %d: ibuf empty", c->self);
94 if (buffer_len(&c->input)) { 121 if (buffer_len(&c->input)) {
95 error("internal error: chan_ibuf_empty %d for non empty buffer", c->self); 122 error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
123 c->self);
96 return; 124 return;
97 } 125 }
98 switch (c->istate) { 126 switch (c->istate) {
99 case CHAN_INPUT_WAIT_DRAIN: 127 case CHAN_INPUT_WAIT_DRAIN:
100 debug("channel %d: INPUT_WAIT_DRAIN -> INPUT_WAIT_OCLOSE [inbuf empty, send IEOF]", c->self); 128 debug("channel %d: input drain -> wait_oclose", c->self);
101 chan_send_ieof(c); 129 chan_send_ieof1(c);
102 c->istate = CHAN_INPUT_WAIT_OCLOSE; 130 c->istate = CHAN_INPUT_WAIT_OCLOSE;
103 break; 131 break;
104 default: 132 default:
105 error("internal error: chan_ibuf_empty %d for istate %d", c->self, c->istate); 133 error("channel %d: internal error: chan_ibuf_empty for istate %d",
134 c->self, c->istate);
106 break; 135 break;
107 } 136 }
108} 137}
109 138static void
110/* events concerning the OUTPUT from channel for socket (ostate) */ 139chan_rcvd_ieof1(Channel *c)
111void
112chan_rcvd_ieof(Channel *c)
113{ 140{
141 debug("channel %d: rcvd ieof", c->self);
114 switch (c->ostate) { 142 switch (c->ostate) {
115 case CHAN_OUTPUT_OPEN: 143 case CHAN_OUTPUT_OPEN:
116 debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_DRAIN [rvcd IEOF]", c->self); 144 debug("channel %d: output open -> drain", c->self);
117 c->ostate = CHAN_OUTPUT_WAIT_DRAIN; 145 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
118 break; 146 break;
119 case CHAN_OUTPUT_WAIT_IEOF: 147 case CHAN_OUTPUT_WAIT_IEOF:
120 debug("channel %d: OUTPUT_WAIT_IEOF -> OUTPUT_CLOSED [rvcd IEOF]", c->self); 148 debug("channel %d: output wait_ieof -> closed", c->self);
121 c->ostate = CHAN_OUTPUT_CLOSED; 149 c->ostate = CHAN_OUTPUT_CLOSED;
122 break; 150 break;
123 default: 151 default:
124 error("protocol error: chan_rcvd_ieof %d for ostate %d", c->self, c->ostate); 152 error("channel %d: protocol error: chan_rcvd_ieof for ostate %d",
153 c->self, c->ostate);
125 break; 154 break;
126 } 155 }
127} 156}
128void 157static void
129chan_write_failed(Channel *c) 158chan_write_failed1(Channel *c)
130{ 159{
160 debug("channel %d: write failed", c->self);
131 switch (c->ostate) { 161 switch (c->ostate) {
132 case CHAN_OUTPUT_OPEN: 162 case CHAN_OUTPUT_OPEN:
133 debug("channel %d: OUTPUT_OPEN -> OUTPUT_WAIT_IEOF [write failed]", c->self); 163 debug("channel %d: output open -> wait_ieof", c->self);
134 chan_send_oclose(c); 164 chan_send_oclose1(c);
135 c->ostate = CHAN_OUTPUT_WAIT_IEOF; 165 c->ostate = CHAN_OUTPUT_WAIT_IEOF;
136 break; 166 break;
137 case CHAN_OUTPUT_WAIT_DRAIN: 167 case CHAN_OUTPUT_WAIT_DRAIN:
138 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [write failed]", c->self); 168 debug("channel %d: output wait_drain -> closed", c->self);
139 chan_send_oclose(c); 169 chan_send_oclose1(c);
140 c->ostate = CHAN_OUTPUT_CLOSED; 170 c->ostate = CHAN_OUTPUT_CLOSED;
141 break; 171 break;
142 default: 172 default:
143 error("internal error: chan_write_failed %d for ostate %d", c->self, c->ostate); 173 error("channel %d: internal error: chan_write_failed for ostate %d",
174 c->self, c->ostate);
144 break; 175 break;
145 } 176 }
146} 177}
147void 178static void
148chan_obuf_empty(Channel *c) 179chan_obuf_empty1(Channel *c)
149{ 180{
181 debug("channel %d: obuf empty", c->self);
150 if (buffer_len(&c->output)) { 182 if (buffer_len(&c->output)) {
151 debug("internal error: chan_obuf_empty %d for non empty buffer", c->self); 183 error("channel %d: internal error: chan_obuf_empty for non empty buffer",
184 c->self);
152 return; 185 return;
153 } 186 }
154 switch (c->ostate) { 187 switch (c->ostate) {
155 case CHAN_OUTPUT_WAIT_DRAIN: 188 case CHAN_OUTPUT_WAIT_DRAIN:
156 debug("channel %d: OUTPUT_WAIT_DRAIN -> OUTPUT_CLOSED [obuf empty, send OCLOSE]", c->self); 189 debug("channel %d: output drain -> closed", c->self);
157 chan_send_oclose(c); 190 chan_send_oclose1(c);
158 c->ostate = CHAN_OUTPUT_CLOSED; 191 c->ostate = CHAN_OUTPUT_CLOSED;
159 break; 192 break;
160 default: 193 default:
161 error("internal error: chan_obuf_empty %d for ostate %d", c->self, c->ostate); 194 error("channel %d: internal error: chan_obuf_empty for ostate %d",
195 c->self, c->ostate);
162 break; 196 break;
163 } 197 }
164} 198}
165
166/*
167 * ACTIONS: should never update the channel states: c->istate or c->ostate
168 */
169static void 199static void
170chan_send_ieof(Channel *c) 200chan_send_ieof1(Channel *c)
171{ 201{
202 debug("channel %d: send ieof", c->self);
172 switch (c->istate) { 203 switch (c->istate) {
173 case CHAN_INPUT_OPEN: 204 case CHAN_INPUT_OPEN:
174 case CHAN_INPUT_WAIT_DRAIN: 205 case CHAN_INPUT_WAIT_DRAIN:
@@ -177,13 +208,15 @@ chan_send_ieof(Channel *c)
177 packet_send(); 208 packet_send();
178 break; 209 break;
179 default: 210 default:
180 error("internal error: channel %d: cannot send IEOF for istate %d", c->self, c->istate); 211 error("channel %d: internal error: cannot send ieof for istate %d",
212 c->self, c->istate);
181 break; 213 break;
182 } 214 }
183} 215}
184static void 216static void
185chan_send_oclose(Channel *c) 217chan_send_oclose1(Channel *c)
186{ 218{
219 debug("channel %d: send oclose", c->self);
187 switch (c->ostate) { 220 switch (c->ostate) {
188 case CHAN_OUTPUT_OPEN: 221 case CHAN_OUTPUT_OPEN:
189 case CHAN_OUTPUT_WAIT_DRAIN: 222 case CHAN_OUTPUT_WAIT_DRAIN:
@@ -194,40 +227,246 @@ chan_send_oclose(Channel *c)
194 packet_send(); 227 packet_send();
195 break; 228 break;
196 default: 229 default:
197 error("internal error: channel %d: cannot send OCLOSE for ostate %d", c->self, c->istate); 230 error("channel %d: internal error: cannot send oclose for ostate %d",
231 c->self, c->ostate);
198 break; 232 break;
199 } 233 }
200} 234}
235static void
236chan_delete_if_full_closed1(Channel *c)
237{
238 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
239 debug("channel %d: full closed", c->self);
240 channel_free(c->self);
241 }
242}
201 243
202/* helper */ 244/*
245 * the same for SSH2
246 */
203static void 247static void
204chan_shutdown_write(Channel *c) 248chan_rcvd_oclose2(Channel *c)
205{ 249{
206 /* shutdown failure is allowed if write failed already */ 250 debug("channel %d: rcvd close", c->self);
207 debug("channel %d: shutdown_write", c->self); 251 if (c->flags & CHAN_CLOSE_RCVD)
208 if (shutdown(c->sock, SHUT_WR) < 0) 252 error("channel %d: protocol error: close rcvd twice", c->self);
209 debug("chan_shutdown_write failed for #%d/fd%d: %.100s", 253 c->flags |= CHAN_CLOSE_RCVD;
210 c->self, c->sock, strerror(errno)); 254 if (c->type == SSH_CHANNEL_LARVAL) {
255 /* tear down larval channels immediately */
256 c->ostate = CHAN_OUTPUT_CLOSED;
257 c->istate = CHAN_INPUT_CLOSED;
258 return;
259 }
260 switch (c->ostate) {
261 case CHAN_OUTPUT_OPEN:
262 /* wait until a data from the channel is consumed if a CLOSE is received */
263 debug("channel %d: output open -> drain", c->self);
264 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
265 break;
266 }
267 switch (c->istate) {
268 case CHAN_INPUT_OPEN:
269 debug("channel %d: input open -> closed", c->self);
270 chan_shutdown_read(c);
271 break;
272 case CHAN_INPUT_WAIT_DRAIN:
273 debug("channel %d: input drain -> closed", c->self);
274 chan_send_eof2(c);
275 break;
276 }
277 c->istate = CHAN_INPUT_CLOSED;
211} 278}
212static void 279static void
213chan_shutdown_read(Channel *c) 280chan_ibuf_empty2(Channel *c)
281{
282 debug("channel %d: ibuf empty", c->self);
283 if (buffer_len(&c->input)) {
284 error("channel %d: internal error: chan_ibuf_empty for non empty buffer",
285 c->self);
286 return;
287 }
288 switch (c->istate) {
289 case CHAN_INPUT_WAIT_DRAIN:
290 debug("channel %d: input drain -> closed", c->self);
291 if (!(c->flags & CHAN_CLOSE_SENT))
292 chan_send_eof2(c);
293 c->istate = CHAN_INPUT_CLOSED;
294 break;
295 default:
296 error("channel %d: internal error: chan_ibuf_empty for istate %d",
297 c->self, c->istate);
298 break;
299 }
300}
301static void
302chan_rcvd_ieof2(Channel *c)
214{ 303{
215 debug("channel %d: shutdown_read", c->self); 304 debug("channel %d: rcvd eof", c->self);
216 if (shutdown(c->sock, SHUT_RD) < 0) 305 if (c->ostate == CHAN_OUTPUT_OPEN) {
217 error("chan_shutdown_read failed for #%d/fd%d [i%d o%d]: %.100s", 306 debug("channel %d: output open -> drain", c->self);
218 c->self, c->sock, c->istate, c->ostate, strerror(errno)); 307 c->ostate = CHAN_OUTPUT_WAIT_DRAIN;
308 }
219} 309}
220void 310static void
221chan_delete_if_full_closed(Channel *c) 311chan_write_failed2(Channel *c)
312{
313 debug("channel %d: write failed", c->self);
314 switch (c->ostate) {
315 case CHAN_OUTPUT_OPEN:
316 debug("channel %d: output open -> closed", c->self);
317 chan_shutdown_write(c); // ??
318 c->ostate = CHAN_OUTPUT_CLOSED;
319 break;
320 case CHAN_OUTPUT_WAIT_DRAIN:
321 debug("channel %d: output drain -> closed", c->self);
322 chan_shutdown_write(c);
323 c->ostate = CHAN_OUTPUT_CLOSED;
324 break;
325 default:
326 error("channel %d: internal error: chan_write_failed for ostate %d",
327 c->self, c->ostate);
328 break;
329 }
330}
331static void
332chan_obuf_empty2(Channel *c)
333{
334 debug("channel %d: obuf empty", c->self);
335 if (buffer_len(&c->output)) {
336 error("internal error: chan_obuf_empty %d for non empty buffer",
337 c->self);
338 return;
339 }
340 switch (c->ostate) {
341 case CHAN_OUTPUT_WAIT_DRAIN:
342 debug("channel %d: output drain -> closed", c->self);
343 chan_shutdown_write(c);
344 c->ostate = CHAN_OUTPUT_CLOSED;
345 break;
346 default:
347 error("channel %d: internal error: chan_obuf_empty for ostate %d",
348 c->self, c->ostate);
349 break;
350 }
351}
352static void
353chan_send_eof2(Channel *c)
354{
355 debug("channel %d: send eof", c->self);
356 switch (c->istate) {
357 case CHAN_INPUT_WAIT_DRAIN:
358 packet_start(SSH2_MSG_CHANNEL_EOF);
359 packet_put_int(c->remote_id);
360 packet_send();
361 break;
362 default:
363 error("channel %d: internal error: cannot send eof for istate %d",
364 c->self, c->istate);
365 break;
366 }
367}
368static void
369chan_send_close2(Channel *c)
370{
371 debug("channel %d: send close", c->self);
372 if (c->ostate != CHAN_OUTPUT_CLOSED ||
373 c->istate != CHAN_INPUT_CLOSED) {
374 error("channel %d: internal error: cannot send close for istate/ostate %d/%d",
375 c->self, c->istate, c->ostate);
376 } else if (c->flags & CHAN_CLOSE_SENT) {
377 error("channel %d: internal error: already sent close", c->self);
378 } else {
379 packet_start(SSH2_MSG_CHANNEL_CLOSE);
380 packet_put_int(c->remote_id);
381 packet_send();
382 c->flags |= CHAN_CLOSE_SENT;
383 }
384}
385static void
386chan_delete_if_full_closed2(Channel *c)
222{ 387{
223 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) { 388 if (c->istate == CHAN_INPUT_CLOSED && c->ostate == CHAN_OUTPUT_CLOSED) {
224 debug("channel %d: full closed", c->self); 389 if (!(c->flags & CHAN_CLOSE_SENT)) {
225 channel_free(c->self); 390 chan_send_close2(c);
391 }
392 if ((c->flags & CHAN_CLOSE_SENT) &&
393 (c->flags & CHAN_CLOSE_RCVD)) {
394 debug("channel %d: full closed2", c->self);
395 channel_free(c->self);
396 }
226 } 397 }
227} 398}
399
400/* shared */
228void 401void
229chan_init_iostates(Channel *c) 402chan_init_iostates(Channel *c)
230{ 403{
231 c->ostate = CHAN_OUTPUT_OPEN; 404 c->ostate = CHAN_OUTPUT_OPEN;
232 c->istate = CHAN_INPUT_OPEN; 405 c->istate = CHAN_INPUT_OPEN;
406 c->flags = 0;
407}
408
409/* init */
410void
411chan_init(void)
412{
413 if (compat20) {
414 chan_rcvd_oclose = chan_rcvd_oclose2;
415 chan_read_failed = chan_read_failed_12;
416 chan_ibuf_empty = chan_ibuf_empty2;
417
418 chan_rcvd_ieof = chan_rcvd_ieof2;
419 chan_write_failed = chan_write_failed2;
420 chan_obuf_empty = chan_obuf_empty2;
421
422 chan_delete_if_full_closed = chan_delete_if_full_closed2;
423 } else {
424 chan_rcvd_oclose = chan_rcvd_oclose1;
425 chan_read_failed = chan_read_failed_12;
426 chan_ibuf_empty = chan_ibuf_empty1;
427
428 chan_rcvd_ieof = chan_rcvd_ieof1;
429 chan_write_failed = chan_write_failed1;
430 chan_obuf_empty = chan_obuf_empty1;
431
432 chan_delete_if_full_closed = chan_delete_if_full_closed1;
433 }
434}
435
436/* helper */
437static void
438chan_shutdown_write(Channel *c)
439{
440 buffer_consume(&c->output, buffer_len(&c->output));
441 if (compat20 && c->type == SSH_CHANNEL_LARVAL)
442 return;
443 /* shutdown failure is allowed if write failed already */
444 debug("channel %d: close_write", c->self);
445 if (c->sock != -1) {
446 if (shutdown(c->sock, SHUT_WR) < 0)
447 debug("channel %d: chan_shutdown_write: shutdown() failed for fd%d: %.100s",
448 c->self, c->sock, strerror(errno));
449 } else {
450 if (close(c->wfd) < 0)
451 log("channel %d: chan_shutdown_write: close() failed for fd%d: %.100s",
452 c->self, c->wfd, strerror(errno));
453 c->wfd = -1;
454 }
455}
456static void
457chan_shutdown_read(Channel *c)
458{
459 if (compat20 && c->type == SSH_CHANNEL_LARVAL)
460 return;
461 debug("channel %d: close_read", c->self);
462 if (c->sock != -1) {
463 if (shutdown(c->sock, SHUT_RD) < 0)
464 error("channel %d: chan_shutdown_read: shutdown() failed for fd%d [i%d o%d]: %.100s",
465 c->self, c->sock, c->istate, c->ostate, strerror(errno));
466 } else {
467 if (close(c->rfd) < 0)
468 log("channel %d: chan_shutdown_read: close() failed for fd%d: %.100s",
469 c->self, c->rfd, strerror(errno));
470 c->rfd = -1;
471 }
233} 472}
diff --git a/nchan.h b/nchan.h
index 0ceee1c71..ae2b70619 100644
--- a/nchan.h
+++ b/nchan.h
@@ -27,7 +27,7 @@
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */ 28 */
29 29
30/* RCSID("$Id: nchan.h,v 1.4 2000/04/01 01:09:24 damien Exp $"); */ 30/* RCSID("$Id: nchan.h,v 1.5 2000/04/04 04:39:02 damien Exp $"); */
31 31
32#ifndef NCHAN_H 32#ifndef NCHAN_H
33#define NCHAN_H 33#define NCHAN_H
@@ -72,17 +72,25 @@
72#define CHAN_OUTPUT_WAIT_IEOF 0x40 72#define CHAN_OUTPUT_WAIT_IEOF 0x40
73#define CHAN_OUTPUT_CLOSED 0x80 73#define CHAN_OUTPUT_CLOSED 0x80
74 74
75/* EVENTS for the input state */ 75#define CHAN_CLOSE_SENT 0x01
76void chan_rcvd_oclose(Channel * c); 76#define CHAN_CLOSE_RCVD 0x02
77void chan_read_failed(Channel * c);
78void chan_ibuf_empty(Channel * c);
79 77
80/* EVENTS for the output state */
81void chan_rcvd_ieof(Channel * c);
82void chan_write_failed(Channel * c);
83void chan_obuf_empty(Channel * c);
84 78
85void chan_init_iostates(Channel * c); 79/* Channel EVENTS */
80typedef void chan_event_fn(Channel * c);
81
82/* for the input state */
83extern chan_event_fn *chan_rcvd_oclose;
84extern chan_event_fn *chan_read_failed;
85extern chan_event_fn *chan_ibuf_empty;
86
87/* for the output state */
88extern chan_event_fn *chan_rcvd_ieof;
89extern chan_event_fn *chan_write_failed;
90extern chan_event_fn *chan_obuf_empty;
86 91
87void chan_delete_if_full_closed(Channel *c); 92extern chan_event_fn *chan_delete_if_full_closed;
93
94void chan_init_iostates(Channel * c);
95void chan_init(void);
88#endif 96#endif
diff --git a/nchan2.ms b/nchan2.ms
new file mode 100644
index 000000000..1b119d135
--- /dev/null
+++ b/nchan2.ms
@@ -0,0 +1,64 @@
1.TL
2OpenSSH Channel Close Protocol 2.0 Implementation
3.SH
4Channel Input State Diagram
5.PS
6reset
7l=1
8s=1.2
9ellipsewid=s*ellipsewid
10boxwid=s*boxwid
11ellipseht=s*ellipseht
12S1: ellipse "INPUT" "OPEN"
13move right 2*l from last ellipse.e
14S3: ellipse invis
15move down l from last ellipse.s
16S4: ellipse "INPUT" "CLOSED"
17move down l from 1st ellipse.s
18S2: ellipse "INPUT" "WAIT" "DRAIN"
19arrow from S1.e to S4.n
20box invis "rcvd CLOSE/" "shutdown_read" with .sw at last arrow.c
21arrow "ibuf_empty ||" "rcvd CLOSE/" "send EOF" "" from S2.e to S4.w
22arrow from S1.s to S2.n
23box invis "read_failed/" "shutdown_read" with .e at last arrow.c
24ellipse wid .9*ellipsewid ht .9*ellipseht at S4
25arrow "start" "" from S1.w+(-0.5,0) to S1.w
26.PE
27.SH
28Channel Output State Diagram
29.PS
30S1: ellipse "OUTPUT" "OPEN"
31move right 2*l from last ellipse.e
32S3: ellipse invis
33move down l from last ellipse.s
34S4: ellipse "OUTPUT" "CLOSED"
35move down l from 1st ellipse.s
36S2: ellipse "OUTPUT" "WAIT" "DRAIN"
37arrow from S1.e to S4.n
38box invis "write_failed/" "shutdown_write" with .sw at last arrow.c
39arrow "obuf_empty ||" "write_failed/" "shutdown_write" "" from S2.e to S4.w
40arrow from S1.s to S2.n
41box invis "rcvd EOF ||" "rcvd CLOSE/" "-" with .e at last arrow.c
42ellipse wid .9*ellipsewid ht .9*ellipseht at S4
43arrow "start" "" from S1.w+(-0.5,0) to S1.w
44.PE
45.SH
46Notes
47.PP
48The input buffer is filled with data from the socket
49(the socket represents the local consumer/producer of the
50forwarded channel).
51The data is then sent over the INPUT-end (transmit-end) of the channel to the
52remote peer.
53Data sent by the peer is received on the OUTPUT-end (receive-end),
54saved in the output buffer and written to the socket.
55.PP
56If the local protocol instance has forwarded all data on the
57INPUT-end of the channel, it sends an EOF message to the peer.
58.PP
59A CLOSE message is sent to the peer if
60both the INPUT- and the OUTOUT-half of the local
61end of the channel are closed.
62.PP
63The channel can be deallocated by a protocol instance
64if a CLOSE message he been both sent and received.
diff --git a/packet.c b/packet.c
index ffce2c745..3875d8f9b 100644
--- a/packet.c
+++ b/packet.c
@@ -11,11 +11,13 @@
11 * 11 *
12 * This file contains code implementing the packet protocol and communication 12 * This file contains code implementing the packet protocol and communication
13 * with the other side. This same code is used both on client and server side. 13 * with the other side. This same code is used both on client and server side.
14 * 14 *
15 * SSH2 packet format added by Markus Friedl.
16 *
15 */ 17 */
16 18
17#include "includes.h" 19#include "includes.h"
18RCSID("$Id: packet.c,v 1.13 2000/04/01 01:09:25 damien Exp $"); 20RCSID("$Id: packet.c,v 1.14 2000/04/04 04:39:03 damien Exp $");
19 21
20#include "xmalloc.h" 22#include "xmalloc.h"
21#include "buffer.h" 23#include "buffer.h"
@@ -30,6 +32,22 @@ RCSID("$Id: packet.c,v 1.13 2000/04/01 01:09:25 damien Exp $");
30#include "deattack.h" 32#include "deattack.h"
31#include "channels.h" 33#include "channels.h"
32 34
35#include "compat.h"
36#include "ssh2.h"
37
38#include <ssl/bn.h>
39#include <ssl/dh.h>
40#include <ssl/hmac.h>
41#include "buffer.h"
42#include "kex.h"
43#include "hmac.h"
44
45#ifdef PACKET_DEBUG
46#define DBG(x) x
47#else
48#define DBG(x)
49#endif
50
33/* 51/*
34 * This variable contains the file descriptors used for communicating with 52 * This variable contains the file descriptors used for communicating with
35 * the other side. connection_in is used for reading; connection_out for 53 * the other side. connection_in is used for reading; connection_out for
@@ -81,11 +99,45 @@ static int initialized = 0;
81/* Set to true if the connection is interactive. */ 99/* Set to true if the connection is interactive. */
82static int interactive_mode = 0; 100static int interactive_mode = 0;
83 101
102/* True if SSH2 packet format is used */
103int use_ssh2_packet_format = 0;
104
105/* Session key information for Encryption and MAC */
106Kex *kex = NULL;
107
108void
109packet_set_kex(Kex *k)
110{
111 if( k->mac[MODE_IN ].key == NULL ||
112 k->enc[MODE_IN ].key == NULL ||
113 k->enc[MODE_IN ].iv == NULL ||
114 k->mac[MODE_OUT].key == NULL ||
115 k->enc[MODE_OUT].key == NULL ||
116 k->enc[MODE_OUT].iv == NULL)
117 fatal("bad KEX");
118 kex = k;
119}
120void
121clear_enc_keys(Enc *enc, int len)
122{
123 memset(enc->iv, 0, len);
124 memset(enc->key, 0, len);
125 xfree(enc->iv);
126 xfree(enc->key);
127 enc->iv = NULL;
128 enc->key = NULL;
129}
130void
131packet_set_ssh2_format(void)
132{
133 debug("use_ssh2_packet_format");
134 use_ssh2_packet_format = 1;
135}
136
84/* 137/*
85 * Sets the descriptors used for communication. Disables encryption until 138 * Sets the descriptors used for communication. Disables encryption until
86 * packet_set_encryption_key is called. 139 * packet_set_encryption_key is called.
87 */ 140 */
88
89void 141void
90packet_set_connection(int fd_in, int fd_out) 142packet_set_connection(int fd_in, int fd_out)
91{ 143{
@@ -225,6 +277,7 @@ packet_get_protocol_flags()
225 * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip. 277 * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
226 */ 278 */
227 279
280/*** XXXXX todo: kex means re-init */
228void 281void
229packet_start_compression(int level) 282packet_start_compression(int level)
230{ 283{
@@ -242,7 +295,7 @@ packet_start_compression(int level)
242 295
243void 296void
244packet_encrypt(CipherContext * cc, void *dest, void *src, 297packet_encrypt(CipherContext * cc, void *dest, void *src,
245 unsigned int bytes) 298 unsigned int bytes)
246{ 299{
247 cipher_encrypt(cc, dest, src, bytes); 300 cipher_encrypt(cc, dest, src, bytes);
248} 301}
@@ -254,7 +307,7 @@ packet_encrypt(CipherContext * cc, void *dest, void *src,
254 307
255void 308void
256packet_decrypt(CipherContext * cc, void *dest, void *src, 309packet_decrypt(CipherContext * cc, void *dest, void *src,
257 unsigned int bytes) 310 unsigned int bytes)
258{ 311{
259 int i; 312 int i;
260 313
@@ -266,15 +319,11 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
266 * (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com) 319 * (C)1998 CORE-SDI, Buenos Aires Argentina Ariel Futoransky(futo@core-sdi.com)
267 */ 320 */
268 321
269 switch (cc->type) { 322 if (cc->type == SSH_CIPHER_NONE || compat20) {
270 case SSH_CIPHER_NONE:
271 i = DEATTACK_OK; 323 i = DEATTACK_OK;
272 break; 324 } else {
273 default:
274 i = detect_attack(src, bytes, NULL); 325 i = detect_attack(src, bytes, NULL);
275 break;
276 } 326 }
277
278 if (i == DEATTACK_DETECTED) 327 if (i == DEATTACK_DETECTED)
279 packet_disconnect("crc32 compensation attack: network attack detected"); 328 packet_disconnect("crc32 compensation attack: network attack detected");
280 329
@@ -289,8 +338,11 @@ packet_decrypt(CipherContext * cc, void *dest, void *src,
289 338
290void 339void
291packet_set_encryption_key(const unsigned char *key, unsigned int keylen, 340packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
292 int cipher) 341 int cipher)
293{ 342{
343 if (keylen < 20)
344 fatal("keylen too small: %d", keylen);
345
294 /* All other ciphers use the same key in both directions for now. */ 346 /* All other ciphers use the same key in both directions for now. */
295 cipher_set_key(&receive_context, cipher, key, keylen, 0); 347 cipher_set_key(&receive_context, cipher, key, keylen, 0);
296 cipher_set_key(&send_context, cipher, key, keylen, 1); 348 cipher_set_key(&send_context, cipher, key, keylen, 1);
@@ -299,7 +351,7 @@ packet_set_encryption_key(const unsigned char *key, unsigned int keylen,
299/* Starts constructing a packet to send. */ 351/* Starts constructing a packet to send. */
300 352
301void 353void
302packet_start(int type) 354packet_start1(int type)
303{ 355{
304 char buf[9]; 356 char buf[9];
305 357
@@ -309,6 +361,29 @@ packet_start(int type)
309 buffer_append(&outgoing_packet, buf, 9); 361 buffer_append(&outgoing_packet, buf, 9);
310} 362}
311 363
364void
365packet_start2(int type)
366{
367 char buf[4+1+1];
368
369 buffer_clear(&outgoing_packet);
370 memset(buf, 0, sizeof buf);
371 /* buf[0..3] = payload_len; */
372 /* buf[4] = pad_len; */
373 buf[5] = type & 0xff;
374 buffer_append(&outgoing_packet, buf, sizeof buf);
375}
376
377void
378packet_start(int type)
379{
380 DBG(debug("packet_start[%d]",type));
381 if (use_ssh2_packet_format)
382 packet_start2(type);
383 else
384 packet_start1(type);
385}
386
312/* Appends a character to the packet data. */ 387/* Appends a character to the packet data. */
313 388
314void 389void
@@ -333,6 +408,18 @@ packet_put_string(const char *buf, unsigned int len)
333{ 408{
334 buffer_put_string(&outgoing_packet, buf, len); 409 buffer_put_string(&outgoing_packet, buf, len);
335} 410}
411void
412packet_put_cstring(const char *str)
413{
414 buffer_put_string(&outgoing_packet, str, strlen(str));
415}
416
417void
418packet_put_raw(const char *buf, unsigned int len)
419{
420 buffer_append(&outgoing_packet, buf, len);
421}
422
336 423
337/* Appends an arbitrary precision integer to packet data. */ 424/* Appends an arbitrary precision integer to packet data. */
338 425
@@ -341,6 +428,11 @@ packet_put_bignum(BIGNUM * value)
341{ 428{
342 buffer_put_bignum(&outgoing_packet, value); 429 buffer_put_bignum(&outgoing_packet, value);
343} 430}
431void
432packet_put_bignum2(BIGNUM * value)
433{
434 buffer_put_bignum2(&outgoing_packet, value);
435}
344 436
345/* 437/*
346 * Finalizes and sends the packet. If the encryption key has been set, 438 * Finalizes and sends the packet. If the encryption key has been set,
@@ -348,7 +440,7 @@ packet_put_bignum(BIGNUM * value)
348 */ 440 */
349 441
350void 442void
351packet_send() 443packet_send1()
352{ 444{
353 char buf[8], *cp; 445 char buf[8], *cp;
354 int i, padding, len; 446 int i, padding, len;
@@ -419,6 +511,139 @@ packet_send()
419} 511}
420 512
421/* 513/*
514 * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
515 */
516void
517packet_send2()
518{
519 unsigned char *macbuf = NULL;
520 char *cp;
521 unsigned int packet_length = 0;
522 unsigned int i, padlen, len;
523 u_int32_t rand = 0;
524 static unsigned int seqnr = 0;
525 int type;
526 Enc *enc = NULL;
527 Mac *mac = NULL;
528 Comp *comp = NULL;
529 int block_size;
530
531 if (kex != NULL) {
532 enc = &kex->enc[MODE_OUT];
533 mac = &kex->mac[MODE_OUT];
534 comp = &kex->comp[MODE_OUT];
535 }
536 block_size = enc ? enc->block_size : 8;
537
538 cp = buffer_ptr(&outgoing_packet);
539 type = cp[5] & 0xff;
540
541#ifdef PACKET_DEBUG
542 fprintf(stderr, "plain: ");
543 buffer_dump(&outgoing_packet);
544#endif
545
546 if (comp && comp->enabled) {
547 len = buffer_len(&outgoing_packet);
548 /* skip header, compress only payload */
549 buffer_consume(&outgoing_packet, 5);
550 buffer_clear(&compression_buffer);
551 buffer_compress(&outgoing_packet, &compression_buffer);
552 buffer_clear(&outgoing_packet);
553 buffer_append(&outgoing_packet, "\0\0\0\0\0", 5);
554 buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer),
555 buffer_len(&compression_buffer));
556 DBG(debug("compression: raw %d compressed %d", len,
557 buffer_len(&outgoing_packet)));
558 }
559
560 /* sizeof (packet_len + pad_len + payload) */
561 len = buffer_len(&outgoing_packet);
562
563 /*
564 * calc size of padding, alloc space, get random data,
565 * minimum padding is 4 bytes
566 */
567 padlen = block_size - (len % block_size);
568 if (padlen < 4)
569 padlen += block_size;
570 buffer_append_space(&outgoing_packet, &cp, padlen);
571 if (enc && enc->type != SSH_CIPHER_NONE) {
572 for (i = 0; i < padlen; i++) {
573 if (i % 4 == 0)
574 rand = arc4random();
575 cp[i] = rand & 0xff;
576 rand <<= 8;
577 }
578 }
579 /* packet_length includes payload, padding and padding length field */
580 packet_length = buffer_len(&outgoing_packet) - 4;
581 cp = buffer_ptr(&outgoing_packet);
582 PUT_32BIT(cp, packet_length);
583 cp[4] = padlen & 0xff;
584 DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen));
585
586 /* compute MAC over seqnr and packet(length fields, payload, padding) */
587 if (mac && mac->enabled) {
588 macbuf = hmac( mac->md, seqnr,
589 (unsigned char *) buffer_ptr(&outgoing_packet),
590 buffer_len(&outgoing_packet),
591 mac->key, mac->key_len
592 );
593 DBG(debug("done calc HMAC out #%d", seqnr));
594 }
595 /* encrypt packet and append to output buffer. */
596 buffer_append_space(&output, &cp, buffer_len(&outgoing_packet));
597 packet_encrypt(&send_context, cp, buffer_ptr(&outgoing_packet),
598 buffer_len(&outgoing_packet));
599 /* append unencrypted MAC */
600 if (mac && mac->enabled)
601 buffer_append(&output, (char *)macbuf, mac->mac_len);
602#ifdef PACKET_DEBUG
603 fprintf(stderr, "encrypted: ");
604 buffer_dump(&output);
605#endif
606 /* increment sequence number for outgoing packets */
607 if (++seqnr == 0)
608 log("outgoing seqnr wraps around");
609 buffer_clear(&outgoing_packet);
610
611 if (type == SSH2_MSG_NEWKEYS) {
612 if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
613 fatal("packet_send2: no KEX");
614 if (mac->md != NULL)
615 mac->enabled = 1;
616 debug("cipher_set_key_iv send_context");
617 cipher_set_key_iv(&send_context, enc->type,
618 enc->key, enc->key_len,
619 enc->iv, enc->iv_len);
620 clear_enc_keys(enc, kex->we_need);
621 if (comp->type != 0 && comp->enabled == 0) {
622 comp->enabled = 1;
623 if (! packet_compression)
624 packet_start_compression(6);
625 }
626 }
627}
628
629void
630packet_send()
631{
632 if (use_ssh2_packet_format)
633 packet_send2();
634 else
635 packet_send1();
636 DBG(debug("packet_send done"));
637}
638
639void
640packet_send_and_wait()
641{
642 packet_send();
643 packet_write_wait();
644}
645
646/*
422 * Waits until a packet has been received, and returns its type. Note that 647 * Waits until a packet has been received, and returns its type. Note that
423 * no other data is processed until this returns, so this function should not 648 * no other data is processed until this returns, so this function should not
424 * be used during the interactive session. 649 * be used during the interactive session.
@@ -430,6 +655,7 @@ packet_read(int *payload_len_ptr)
430 int type, len; 655 int type, len;
431 fd_set set; 656 fd_set set;
432 char buf[8192]; 657 char buf[8192];
658 DBG(debug("packet_read()"));
433 659
434 /* Since we are blocking, ensure that all written packets have been sent. */ 660 /* Since we are blocking, ensure that all written packets have been sent. */
435 packet_write_wait(); 661 packet_write_wait();
@@ -483,7 +709,7 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
483 type = packet_read(payload_len_ptr); 709 type = packet_read(payload_len_ptr);
484 if (type != expected_type) 710 if (type != expected_type)
485 packet_disconnect("Protocol error: expected packet type %d, got %d", 711 packet_disconnect("Protocol error: expected packet type %d, got %d",
486 expected_type, type); 712 expected_type, type);
487} 713}
488 714
489/* Checks if a full packet is available in the data received so far via 715/* Checks if a full packet is available in the data received so far via
@@ -502,15 +728,13 @@ packet_read_expect(int *payload_len_ptr, int expected_type)
502 */ 728 */
503 729
504int 730int
505packet_read_poll(int *payload_len_ptr) 731packet_read_poll1(int *payload_len_ptr)
506{ 732{
507 unsigned int len, padded_len; 733 unsigned int len, padded_len;
508 unsigned char *ucp; 734 unsigned char *ucp;
509 char buf[8], *cp, *msg; 735 char buf[8], *cp;
510 unsigned int checksum, stored_checksum; 736 unsigned int checksum, stored_checksum;
511 737
512restart:
513
514 /* Check if input size is less than minimum packet size. */ 738 /* Check if input size is less than minimum packet size. */
515 if (buffer_len(&input) < 4 + 8) 739 if (buffer_len(&input) < 4 + 8)
516 return SSH_MSG_NONE; 740 return SSH_MSG_NONE;
@@ -543,7 +767,7 @@ restart:
543 767
544 /* Compute packet checksum. */ 768 /* Compute packet checksum. */
545 checksum = crc32((unsigned char *) buffer_ptr(&incoming_packet), 769 checksum = crc32((unsigned char *) buffer_ptr(&incoming_packet),
546 buffer_len(&incoming_packet) - 4); 770 buffer_len(&incoming_packet) - 4);
547 771
548 /* Skip padding. */ 772 /* Skip padding. */
549 buffer_consume(&incoming_packet, 8 - len % 8); 773 buffer_consume(&incoming_packet, 8 - len % 8);
@@ -552,7 +776,7 @@ restart:
552 776
553 if (len != buffer_len(&incoming_packet)) 777 if (len != buffer_len(&incoming_packet))
554 packet_disconnect("packet_read_poll: len %d != buffer_len %d.", 778 packet_disconnect("packet_read_poll: len %d != buffer_len %d.",
555 len, buffer_len(&incoming_packet)); 779 len, buffer_len(&incoming_packet));
556 780
557 ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4; 781 ucp = (unsigned char *) buffer_ptr(&incoming_packet) + len - 4;
558 stored_checksum = GET_32BIT(ucp); 782 stored_checksum = GET_32BIT(ucp);
@@ -566,7 +790,7 @@ restart:
566 buffer_uncompress(&incoming_packet, &compression_buffer); 790 buffer_uncompress(&incoming_packet, &compression_buffer);
567 buffer_clear(&incoming_packet); 791 buffer_clear(&incoming_packet);
568 buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), 792 buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
569 buffer_len(&compression_buffer)); 793 buffer_len(&compression_buffer));
570 } 794 }
571 /* Get packet type. */ 795 /* Get packet type. */
572 buffer_get(&incoming_packet, &buf[0], 1); 796 buffer_get(&incoming_packet, &buf[0], 1);
@@ -574,29 +798,208 @@ restart:
574 /* Return length of payload (without type field). */ 798 /* Return length of payload (without type field). */
575 *payload_len_ptr = buffer_len(&incoming_packet); 799 *payload_len_ptr = buffer_len(&incoming_packet);
576 800
577 /* Handle disconnect message. */
578 if ((unsigned char) buf[0] == SSH_MSG_DISCONNECT) {
579 msg = packet_get_string(NULL);
580 log("Received disconnect: %.900s", msg);
581 xfree(msg);
582 fatal_cleanup();
583 }
584
585 /* Ignore ignore messages. */
586 if ((unsigned char) buf[0] == SSH_MSG_IGNORE)
587 goto restart;
588
589 /* Send debug messages as debugging output. */
590 if ((unsigned char) buf[0] == SSH_MSG_DEBUG) {
591 msg = packet_get_string(NULL);
592 debug("Remote: %.900s", msg);
593 xfree(msg);
594 goto restart;
595 }
596 /* Return type. */ 801 /* Return type. */
597 return (unsigned char) buf[0]; 802 return (unsigned char) buf[0];
598} 803}
599 804
805int
806packet_read_poll2(int *payload_len_ptr)
807{
808 unsigned int padlen, need;
809 unsigned char buf[8], *macbuf;
810 unsigned char *ucp;
811 char *cp;
812 static unsigned int packet_length = 0;
813 static unsigned int seqnr = 0;
814 int type;
815 int maclen, block_size;
816 Enc *enc = NULL;
817 Mac *mac = NULL;
818 Comp *comp = NULL;
819
820 if (kex != NULL) {
821 enc = &kex->enc[MODE_IN];
822 mac = &kex->mac[MODE_IN];
823 comp = &kex->comp[MODE_IN];
824 }
825 maclen = mac && mac->enabled ? mac->mac_len : 0;
826 block_size = enc ? enc->block_size : 8;
827
828 if (packet_length == 0) {
829 /*
830 * check if input size is less than the cipher block size,
831 * decrypt first block and extract length of incoming packet
832 */
833 if (buffer_len(&input) < block_size)
834 return SSH_MSG_NONE;
835 buffer_clear(&incoming_packet);
836 buffer_append_space(&incoming_packet, &cp, block_size);
837 packet_decrypt(&receive_context, cp, buffer_ptr(&input),
838 block_size);
839 ucp = (unsigned char *) buffer_ptr(&incoming_packet);
840 packet_length = GET_32BIT(ucp);
841 if (packet_length < 1 + 4 || packet_length > 256 * 1024) {
842 buffer_dump(&incoming_packet);
843 packet_disconnect("Bad packet length %d.", packet_length);
844 }
845 DBG(debug("input: packet len %d", packet_length+4));
846 buffer_consume(&input, block_size);
847 }
848 /* we have a partial packet of block_size bytes */
849 need = 4 + packet_length - block_size;
850 DBG(debug("partial packet %d, need %d, maclen %d", block_size,
851 need, maclen));
852 if (need % block_size != 0)
853 fatal("padding error: need %d block %d mod %d",
854 need, block_size, need % block_size);
855 /*
856 * check if the entire packet has been received and
857 * decrypt into incoming_packet
858 */
859 if (buffer_len(&input) < need + maclen)
860 return SSH_MSG_NONE;
861#ifdef PACKET_DEBUG
862 fprintf(stderr, "read_poll enc/full: ");
863 buffer_dump(&input);
864#endif
865 buffer_append_space(&incoming_packet, &cp, need);
866 packet_decrypt(&receive_context, cp, buffer_ptr(&input), need);
867 buffer_consume(&input, need);
868 /*
869 * compute MAC over seqnr and packet,
870 * increment sequence number for incoming packet
871 */
872 if (mac && mac->enabled) {
873 macbuf = hmac( mac->md, seqnr,
874 (unsigned char *) buffer_ptr(&incoming_packet),
875 buffer_len(&incoming_packet),
876 mac->key, mac->key_len
877 );
878 if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
879 packet_disconnect("Corrupted HMAC on input.");
880 DBG(debug("HMAC #%d ok", seqnr));
881 buffer_consume(&input, mac->mac_len);
882 }
883 if (++seqnr == 0)
884 log("incoming seqnr wraps around");
885
886 /* get padlen */
887 cp = buffer_ptr(&incoming_packet) + 4;
888 padlen = *cp & 0xff;
889 DBG(debug("input: padlen %d", padlen));
890 if (padlen < 4)
891 packet_disconnect("Corrupted padlen %d on input.", padlen);
892
893 /* skip packet size + padlen, discard padding */
894 buffer_consume(&incoming_packet, 4 + 1);
895 buffer_consume_end(&incoming_packet, padlen);
896
897 DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet)));
898 if (comp && comp->enabled) {
899 buffer_clear(&compression_buffer);
900 buffer_uncompress(&incoming_packet, &compression_buffer);
901 buffer_clear(&incoming_packet);
902 buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
903 buffer_len(&compression_buffer));
904 DBG(debug("input: len after de-compress %d", buffer_len(&incoming_packet)));
905 }
906 /*
907 * get packet type, implies consume.
908 * return length of payload (without type field)
909 */
910 buffer_get(&incoming_packet, (char *)&buf[0], 1);
911 *payload_len_ptr = buffer_len(&incoming_packet);
912
913 /* reset for next packet */
914 packet_length = 0;
915
916 /* extract packet type */
917 type = (unsigned char)buf[0];
918
919 if (type == SSH2_MSG_NEWKEYS) {
920 if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
921 fatal("packet_read_poll2: no KEX");
922 if (mac->md != NULL)
923 mac->enabled = 1;
924 debug("cipher_set_key_iv receive_context");
925 cipher_set_key_iv(&receive_context, enc->type,
926 enc->key, enc->key_len,
927 enc->iv, enc->iv_len);
928 clear_enc_keys(enc, kex->we_need);
929 if (comp->type != 0 && comp->enabled == 0) {
930 comp->enabled = 1;
931 if (! packet_compression)
932 packet_start_compression(6);
933 }
934 }
935
936#ifdef PACKET_DEBUG
937 fprintf(stderr, "read/plain[%d]:\r\n",type);
938 buffer_dump(&incoming_packet);
939#endif
940 return (unsigned char)type;
941}
942
943int
944packet_read_poll(int *payload_len_ptr)
945{
946 char *msg;
947 for (;;) {
948 int type = use_ssh2_packet_format ?
949 packet_read_poll2(payload_len_ptr):
950 packet_read_poll1(payload_len_ptr);
951
952 if(compat20) {
953 int reason;
954 if (type != 0)
955 DBG(debug("received packet type %d", type));
956 switch(type) {
957 case SSH2_MSG_IGNORE:
958 break;
959 case SSH2_MSG_DEBUG:
960 packet_get_char();
961 msg = packet_get_string(NULL);
962 debug("Remote: %.900s", msg);
963 xfree(msg);
964 msg = packet_get_string(NULL);
965 xfree(msg);
966 break;
967 case SSH2_MSG_DISCONNECT:
968 reason = packet_get_int();
969 msg = packet_get_string(NULL);
970 log("Received disconnect: %d: %.900s", reason, msg);
971 xfree(msg);
972 fatal_cleanup();
973 break;
974 default:
975 return type;
976 break;
977 }
978 } else {
979 switch(type) {
980 case SSH_MSG_IGNORE:
981 break;
982 case SSH_MSG_DEBUG:
983 msg = packet_get_string(NULL);
984 debug("Remote: %.900s", msg);
985 xfree(msg);
986 break;
987 case SSH_MSG_DISCONNECT:
988 msg = packet_get_string(NULL);
989 log("Received disconnect: %.900s", msg);
990 fatal_cleanup();
991 xfree(msg);
992 break;
993 default:
994 if (type != 0)
995 DBG(debug("received packet type %d", type));
996 return type;
997 break;
998 }
999 }
1000 }
1001}
1002
600/* 1003/*
601 * Buffers the given amount of input characters. This is intended to be used 1004 * Buffers the given amount of input characters. This is intended to be used
602 * together with packet_read_poll. 1005 * together with packet_read_poll.
@@ -637,6 +1040,21 @@ packet_get_bignum(BIGNUM * value, int *length_ptr)
637 *length_ptr = buffer_get_bignum(&incoming_packet, value); 1040 *length_ptr = buffer_get_bignum(&incoming_packet, value);
638} 1041}
639 1042
1043void
1044packet_get_bignum2(BIGNUM * value, int *length_ptr)
1045{
1046 *length_ptr = buffer_get_bignum2(&incoming_packet, value);
1047}
1048
1049char *
1050packet_get_raw(int *length_ptr)
1051{
1052 int bytes = buffer_len(&incoming_packet);
1053 if (length_ptr != NULL)
1054 *length_ptr = bytes;
1055 return buffer_ptr(&incoming_packet);
1056}
1057
640/* 1058/*
641 * Returns a string from the packet data. The string is allocated using 1059 * Returns a string from the packet data. The string is allocated using
642 * xmalloc; it is the responsibility of the calling program to free it when 1060 * xmalloc; it is the responsibility of the calling program to free it when
@@ -701,8 +1119,15 @@ packet_disconnect(const char *fmt,...)
701 va_end(args); 1119 va_end(args);
702 1120
703 /* Send the disconnect message to the other side, and wait for it to get sent. */ 1121 /* Send the disconnect message to the other side, and wait for it to get sent. */
704 packet_start(SSH_MSG_DISCONNECT); 1122 if (compat20) {
705 packet_put_string(buf, strlen(buf)); 1123 packet_start(SSH2_MSG_DISCONNECT);
1124 packet_put_int(SSH2_DISCONNECT_PROTOCOL_ERROR);
1125 packet_put_cstring(buf);
1126 packet_put_cstring("");
1127 } else {
1128 packet_start(SSH_MSG_DISCONNECT);
1129 packet_put_string(buf, strlen(buf));
1130 }
706 packet_send(); 1131 packet_send();
707 packet_write_wait(); 1132 packet_write_wait();
708 1133
@@ -833,7 +1258,8 @@ packet_set_maxsize(int s)
833{ 1258{
834 static int called = 0; 1259 static int called = 0;
835 if (called) { 1260 if (called) {
836 log("packet_set_maxsize: called twice: old %d new %d", max_packet_size, s); 1261 log("packet_set_maxsize: called twice: old %d new %d",
1262 max_packet_size, s);
837 return -1; 1263 return -1;
838 } 1264 }
839 if (s < 4 * 1024 || s > 1024 * 1024) { 1265 if (s < 4 * 1024 || s > 1024 * 1024) {
diff --git a/packet.h b/packet.h
index d1fc41dd1..39c0edea2 100644
--- a/packet.h
+++ b/packet.h
@@ -13,7 +13,7 @@
13 * 13 *
14 */ 14 */
15 15
16/* RCSID("$Id: packet.h,v 1.10 2000/03/17 12:40:16 damien Exp $"); */ 16/* RCSID("$Id: packet.h,v 1.11 2000/04/04 04:39:03 damien Exp $"); */
17 17
18#ifndef PACKET_H 18#ifndef PACKET_H
19#define PACKET_H 19#define PACKET_H
@@ -90,9 +90,12 @@ void packet_put_int(unsigned int value);
90 90
91/* Appends an arbitrary precision integer to packet data. */ 91/* Appends an arbitrary precision integer to packet data. */
92void packet_put_bignum(BIGNUM * value); 92void packet_put_bignum(BIGNUM * value);
93void packet_put_bignum2(BIGNUM * value);
93 94
94/* Appends a string to packet data. */ 95/* Appends a string to packet data. */
95void packet_put_string(const char *buf, unsigned int len); 96void packet_put_string(const char *buf, unsigned int len);
97void packet_put_cstring(const char *str);
98void packet_put_raw(const char *buf, unsigned int len);
96 99
97/* 100/*
98 * Finalizes and sends the packet. If the encryption key has been set, 101 * Finalizes and sends the packet. If the encryption key has been set,
@@ -136,6 +139,8 @@ unsigned int packet_get_int(void);
136 * must have been initialized before this call. 139 * must have been initialized before this call.
137 */ 140 */
138void packet_get_bignum(BIGNUM * value, int *length_ptr); 141void packet_get_bignum(BIGNUM * value, int *length_ptr);
142void packet_get_bignum2(BIGNUM * value, int *length_ptr);
143char *packet_get_raw(int *length_ptr);
139 144
140/* 145/*
141 * Returns a string from the packet data. The string is allocated using 146 * Returns a string from the packet data. The string is allocated using
@@ -202,4 +207,7 @@ do { \
202int packet_connection_is_on_socket(void); 207int packet_connection_is_on_socket(void);
203int packet_connection_is_ipv4(void); 208int packet_connection_is_ipv4(void);
204 209
210/* enable SSH2 packet format */
211void packet_set_ssh2_format(void);
212
205#endif /* PACKET_H */ 213#endif /* PACKET_H */