diff options
Diffstat (limited to 'packet.c')
-rw-r--r-- | packet.c | 145 |
1 files changed, 123 insertions, 22 deletions
@@ -37,7 +37,9 @@ | |||
37 | */ | 37 | */ |
38 | 38 | ||
39 | #include "includes.h" | 39 | #include "includes.h" |
40 | RCSID("$OpenBSD: packet.c,v 1.104 2003/04/01 10:22:21 markus Exp $"); | 40 | RCSID("$OpenBSD: packet.c,v 1.105 2003/04/02 09:48:07 markus Exp $"); |
41 | |||
42 | #include <sys/queue.h> | ||
41 | 43 | ||
42 | #include "xmalloc.h" | 44 | #include "xmalloc.h" |
43 | #include "buffer.h" | 45 | #include "buffer.h" |
@@ -116,8 +118,14 @@ static int interactive_mode = 0; | |||
116 | 118 | ||
117 | /* Session key information for Encryption and MAC */ | 119 | /* Session key information for Encryption and MAC */ |
118 | Newkeys *newkeys[MODE_MAX]; | 120 | Newkeys *newkeys[MODE_MAX]; |
119 | static u_int32_t read_seqnr = 0; | 121 | static struct packet_state { |
120 | static u_int32_t send_seqnr = 0; | 122 | u_int32_t seqnr; |
123 | u_int32_t packets; | ||
124 | u_int64_t blocks; | ||
125 | } p_read, p_send; | ||
126 | |||
127 | static u_int64_t max_blocks_in, max_blocks_out; | ||
128 | static u_int32_t rekey_limit; | ||
121 | 129 | ||
122 | /* Session key for protocol v1 */ | 130 | /* Session key for protocol v1 */ |
123 | static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; | 131 | static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; |
@@ -126,6 +134,13 @@ static u_int ssh1_keylen; | |||
126 | /* roundup current message to extra_pad bytes */ | 134 | /* roundup current message to extra_pad bytes */ |
127 | static u_char extra_pad = 0; | 135 | static u_char extra_pad = 0; |
128 | 136 | ||
137 | struct packet { | ||
138 | TAILQ_ENTRY(packet) next; | ||
139 | u_char type; | ||
140 | Buffer payload; | ||
141 | }; | ||
142 | TAILQ_HEAD(, packet) outgoing; | ||
143 | |||
129 | /* | 144 | /* |
130 | * Sets the descriptors used for communication. Disables encryption until | 145 | * Sets the descriptors used for communication. Disables encryption until |
131 | * packet_set_encryption_key is called. | 146 | * packet_set_encryption_key is called. |
@@ -148,6 +163,7 @@ packet_set_connection(int fd_in, int fd_out) | |||
148 | buffer_init(&output); | 163 | buffer_init(&output); |
149 | buffer_init(&outgoing_packet); | 164 | buffer_init(&outgoing_packet); |
150 | buffer_init(&incoming_packet); | 165 | buffer_init(&incoming_packet); |
166 | TAILQ_INIT(&outgoing); | ||
151 | } | 167 | } |
152 | /* Kludge: arrange the close function to be called from fatal(). */ | 168 | /* Kludge: arrange the close function to be called from fatal(). */ |
153 | fatal_add_cleanup((void (*) (void *)) packet_close, NULL); | 169 | fatal_add_cleanup((void (*) (void *)) packet_close, NULL); |
@@ -254,22 +270,26 @@ packet_get_ssh1_cipher() | |||
254 | return (cipher_get_number(receive_context.cipher)); | 270 | return (cipher_get_number(receive_context.cipher)); |
255 | } | 271 | } |
256 | 272 | ||
257 | 273 | void | |
258 | u_int32_t | 274 | packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets) |
259 | packet_get_seqnr(int mode) | ||
260 | { | 275 | { |
261 | return (mode == MODE_IN ? read_seqnr : send_seqnr); | 276 | struct packet_state *state; |
277 | |||
278 | state = (mode == MODE_IN) ? &p_read : &p_send; | ||
279 | *seqnr = state->seqnr; | ||
280 | *blocks = state->blocks; | ||
281 | *packets = state->packets; | ||
262 | } | 282 | } |
263 | 283 | ||
264 | void | 284 | void |
265 | packet_set_seqnr(int mode, u_int32_t seqnr) | 285 | packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets) |
266 | { | 286 | { |
267 | if (mode == MODE_IN) | 287 | struct packet_state *state; |
268 | read_seqnr = seqnr; | 288 | |
269 | else if (mode == MODE_OUT) | 289 | state = (mode == MODE_IN) ? &p_read : &p_send; |
270 | send_seqnr = seqnr; | 290 | state->seqnr = seqnr; |
271 | else | 291 | state->blocks = blocks; |
272 | fatal("packet_set_seqnr: bad mode %d", mode); | 292 | state->packets = packets; |
273 | } | 293 | } |
274 | 294 | ||
275 | /* returns 1 if connection is via ipv4 */ | 295 | /* returns 1 if connection is via ipv4 */ |
@@ -562,6 +582,7 @@ set_newkeys(int mode) | |||
562 | Mac *mac; | 582 | Mac *mac; |
563 | Comp *comp; | 583 | Comp *comp; |
564 | CipherContext *cc; | 584 | CipherContext *cc; |
585 | u_int64_t *max_blocks; | ||
565 | int encrypt; | 586 | int encrypt; |
566 | 587 | ||
567 | debug2("set_newkeys: mode %d", mode); | 588 | debug2("set_newkeys: mode %d", mode); |
@@ -569,9 +590,13 @@ set_newkeys(int mode) | |||
569 | if (mode == MODE_OUT) { | 590 | if (mode == MODE_OUT) { |
570 | cc = &send_context; | 591 | cc = &send_context; |
571 | encrypt = CIPHER_ENCRYPT; | 592 | encrypt = CIPHER_ENCRYPT; |
593 | p_send.packets = p_send.blocks = 0; | ||
594 | max_blocks = &max_blocks_out; | ||
572 | } else { | 595 | } else { |
573 | cc = &receive_context; | 596 | cc = &receive_context; |
574 | encrypt = CIPHER_DECRYPT; | 597 | encrypt = CIPHER_DECRYPT; |
598 | p_read.packets = p_read.blocks = 0; | ||
599 | max_blocks = &max_blocks_in; | ||
575 | } | 600 | } |
576 | if (newkeys[mode] != NULL) { | 601 | if (newkeys[mode] != NULL) { |
577 | debug("set_newkeys: rekeying"); | 602 | debug("set_newkeys: rekeying"); |
@@ -610,13 +635,16 @@ set_newkeys(int mode) | |||
610 | buffer_compress_init_recv(); | 635 | buffer_compress_init_recv(); |
611 | comp->enabled = 1; | 636 | comp->enabled = 1; |
612 | } | 637 | } |
638 | *max_blocks = ((u_int64_t)1 << (enc->block_size*2)); | ||
639 | if (rekey_limit) | ||
640 | *max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size); | ||
613 | } | 641 | } |
614 | 642 | ||
615 | /* | 643 | /* |
616 | * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) | 644 | * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue) |
617 | */ | 645 | */ |
618 | static void | 646 | static void |
619 | packet_send2(void) | 647 | packet_send2_wrapped(void) |
620 | { | 648 | { |
621 | u_char type, *cp, *macbuf = NULL; | 649 | u_char type, *cp, *macbuf = NULL; |
622 | u_char padlen, pad; | 650 | u_char padlen, pad; |
@@ -698,10 +726,10 @@ packet_send2(void) | |||
698 | 726 | ||
699 | /* compute MAC over seqnr and packet(length fields, payload, padding) */ | 727 | /* compute MAC over seqnr and packet(length fields, payload, padding) */ |
700 | if (mac && mac->enabled) { | 728 | if (mac && mac->enabled) { |
701 | macbuf = mac_compute(mac, send_seqnr, | 729 | macbuf = mac_compute(mac, p_send.seqnr, |
702 | buffer_ptr(&outgoing_packet), | 730 | buffer_ptr(&outgoing_packet), |
703 | buffer_len(&outgoing_packet)); | 731 | buffer_len(&outgoing_packet)); |
704 | DBG(debug("done calc MAC out #%d", send_seqnr)); | 732 | DBG(debug("done calc MAC out #%d", p_send.seqnr)); |
705 | } | 733 | } |
706 | /* encrypt packet and append to output buffer. */ | 734 | /* encrypt packet and append to output buffer. */ |
707 | cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); | 735 | cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); |
@@ -715,14 +743,64 @@ packet_send2(void) | |||
715 | buffer_dump(&output); | 743 | buffer_dump(&output); |
716 | #endif | 744 | #endif |
717 | /* increment sequence number for outgoing packets */ | 745 | /* increment sequence number for outgoing packets */ |
718 | if (++send_seqnr == 0) | 746 | if (++p_send.seqnr == 0) |
719 | log("outgoing seqnr wraps around"); | 747 | log("outgoing seqnr wraps around"); |
748 | if (++p_send.packets == 0) | ||
749 | if (!(datafellows & SSH_BUG_NOREKEY)) | ||
750 | fatal("XXX too many packets with same key"); | ||
751 | p_send.blocks += (packet_length + 4) / block_size; | ||
720 | buffer_clear(&outgoing_packet); | 752 | buffer_clear(&outgoing_packet); |
721 | 753 | ||
722 | if (type == SSH2_MSG_NEWKEYS) | 754 | if (type == SSH2_MSG_NEWKEYS) |
723 | set_newkeys(MODE_OUT); | 755 | set_newkeys(MODE_OUT); |
724 | } | 756 | } |
725 | 757 | ||
758 | static void | ||
759 | packet_send2(void) | ||
760 | { | ||
761 | static int rekeying = 0; | ||
762 | struct packet *p; | ||
763 | u_char type, *cp; | ||
764 | |||
765 | cp = buffer_ptr(&outgoing_packet); | ||
766 | type = cp[5]; | ||
767 | |||
768 | /* during rekeying we can only send key exchange messages */ | ||
769 | if (rekeying) { | ||
770 | if (!((type >= SSH2_MSG_TRANSPORT_MIN) && | ||
771 | (type <= SSH2_MSG_TRANSPORT_MAX))) { | ||
772 | debug("enqueue packet: %u", type); | ||
773 | p = xmalloc(sizeof(*p)); | ||
774 | p->type = type; | ||
775 | memcpy(&p->payload, &outgoing_packet, sizeof(Buffer)); | ||
776 | buffer_init(&outgoing_packet); | ||
777 | TAILQ_INSERT_TAIL(&outgoing, p, next); | ||
778 | return; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | /* rekeying starts with sending KEXINIT */ | ||
783 | if (type == SSH2_MSG_KEXINIT) | ||
784 | rekeying = 1; | ||
785 | |||
786 | packet_send2_wrapped(); | ||
787 | |||
788 | /* after a NEWKEYS message we can send the complete queue */ | ||
789 | if (type == SSH2_MSG_NEWKEYS) { | ||
790 | rekeying = 0; | ||
791 | while ((p = TAILQ_FIRST(&outgoing))) { | ||
792 | type = p->type; | ||
793 | debug("dequeue packet: %u", type); | ||
794 | buffer_free(&outgoing_packet); | ||
795 | memcpy(&outgoing_packet, &p->payload, | ||
796 | sizeof(Buffer)); | ||
797 | TAILQ_REMOVE(&outgoing, p, next); | ||
798 | xfree(p); | ||
799 | packet_send2_wrapped(); | ||
800 | } | ||
801 | } | ||
802 | } | ||
803 | |||
726 | void | 804 | void |
727 | packet_send(void) | 805 | packet_send(void) |
728 | { | 806 | { |
@@ -966,18 +1044,22 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
966 | * increment sequence number for incoming packet | 1044 | * increment sequence number for incoming packet |
967 | */ | 1045 | */ |
968 | if (mac && mac->enabled) { | 1046 | if (mac && mac->enabled) { |
969 | macbuf = mac_compute(mac, read_seqnr, | 1047 | macbuf = mac_compute(mac, p_read.seqnr, |
970 | buffer_ptr(&incoming_packet), | 1048 | buffer_ptr(&incoming_packet), |
971 | buffer_len(&incoming_packet)); | 1049 | buffer_len(&incoming_packet)); |
972 | if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) | 1050 | if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) |
973 | packet_disconnect("Corrupted MAC on input."); | 1051 | packet_disconnect("Corrupted MAC on input."); |
974 | DBG(debug("MAC #%d ok", read_seqnr)); | 1052 | DBG(debug("MAC #%d ok", p_read.seqnr)); |
975 | buffer_consume(&input, mac->mac_len); | 1053 | buffer_consume(&input, mac->mac_len); |
976 | } | 1054 | } |
977 | if (seqnr_p != NULL) | 1055 | if (seqnr_p != NULL) |
978 | *seqnr_p = read_seqnr; | 1056 | *seqnr_p = p_read.seqnr; |
979 | if (++read_seqnr == 0) | 1057 | if (++p_read.seqnr == 0) |
980 | log("incoming seqnr wraps around"); | 1058 | log("incoming seqnr wraps around"); |
1059 | if (++p_read.packets == 0) | ||
1060 | if (!(datafellows & SSH_BUG_NOREKEY)) | ||
1061 | fatal("XXX too many packets with same key"); | ||
1062 | p_read.blocks += (packet_length + 4) / block_size; | ||
981 | 1063 | ||
982 | /* get padlen */ | 1064 | /* get padlen */ |
983 | cp = buffer_ptr(&incoming_packet); | 1065 | cp = buffer_ptr(&incoming_packet); |
@@ -1416,3 +1498,22 @@ packet_send_ignore(int nbytes) | |||
1416 | rand >>= 8; | 1498 | rand >>= 8; |
1417 | } | 1499 | } |
1418 | } | 1500 | } |
1501 | |||
1502 | #define MAX_PACKETS (1<<31) | ||
1503 | int | ||
1504 | packet_need_rekeying(void) | ||
1505 | { | ||
1506 | if (datafellows & SSH_BUG_NOREKEY) | ||
1507 | return 0; | ||
1508 | return | ||
1509 | (p_send.packets > MAX_PACKETS) || | ||
1510 | (p_read.packets > MAX_PACKETS) || | ||
1511 | (max_blocks_out && (p_send.blocks > max_blocks_out)) || | ||
1512 | (max_blocks_in && (p_read.blocks > max_blocks_in)); | ||
1513 | } | ||
1514 | |||
1515 | void | ||
1516 | packet_set_rekey_limit(u_int32_t bytes) | ||
1517 | { | ||
1518 | rekey_limit = bytes; | ||
1519 | } | ||