| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- From 6e43be5c7b99dbee49dc72b6f989f29fdd7e9356 Mon Sep 17 00:00:00 2001
- From: Matt Johnston <[email protected]>
- Date: Mon, 20 Nov 2023 14:02:47 +0800
- Subject: Implement Strict KEX mode
- As specified by OpenSSH with [email protected] and
- [email protected].
- ---
- cli-session.c | 11 +++++++++++
- common-algo.c | 6 ++++++
- common-kex.c | 26 +++++++++++++++++++++++++-
- kex.h | 3 +++
- process-packet.c | 34 +++++++++++++++++++---------------
- ssh.h | 4 ++++
- svr-session.c | 3 +++
- 7 files changed, 71 insertions(+), 16 deletions(-)
- --- a/cli-session.c
- +++ b/cli-session.c
- @@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NO
- static void recv_msg_service_accept(void);
- static void cli_session_cleanup(void);
- static void recv_msg_global_request_cli(void);
- +static void cli_algos_initialise(void);
-
- struct clientsession cli_ses; /* GLOBAL */
-
- @@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o
- }
-
- chaninitialise(cli_chantypes);
- + cli_algos_initialise();
-
- /* Set up cli_ses vars */
- cli_session_init(proxy_cmd_pid);
- @@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, cons
- fflush(stderr);
- }
-
- +static void cli_algos_initialise(void) {
- + algo_type *algo;
- + for (algo = sshkex; algo->name; algo++) {
- + if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) {
- + algo->usable = 0;
- + }
- + }
- +}
- +
- --- a/common-algo.c
- +++ b/common-algo.c
- @@ -308,6 +308,12 @@ algo_type sshkex[] = {
- {SSH_EXT_INFO_C, 0, NULL, 1, NULL},
- #endif
- #endif
- +#if DROPBEAR_CLIENT
- + {SSH_STRICT_KEX_C, 0, NULL, 1, NULL},
- +#endif
- +#if DROPBEAR_SERVER
- + {SSH_STRICT_KEX_S, 0, NULL, 1, NULL},
- +#endif
- {NULL, 0, NULL, 0, NULL}
- };
-
- --- a/common-kex.c
- +++ b/common-kex.c
- @@ -183,6 +183,10 @@ void send_msg_newkeys() {
- gen_new_keys();
- switch_keys();
-
- + if (ses.kexstate.strict_kex) {
- + ses.transseq = 0;
- + }
- +
- TRACE(("leave send_msg_newkeys"))
- }
-
- @@ -193,7 +197,11 @@ void recv_msg_newkeys() {
-
- ses.kexstate.recvnewkeys = 1;
- switch_keys();
- -
- +
- + if (ses.kexstate.strict_kex) {
- + ses.recvseq = 0;
- + }
- +
- TRACE(("leave recv_msg_newkeys"))
- }
-
- @@ -550,6 +558,10 @@ void recv_msg_kexinit() {
-
- ses.kexstate.recvkexinit = 1;
-
- + if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) {
- + dropbear_exit("First packet wasn't kexinit");
- + }
- +
- TRACE(("leave recv_msg_kexinit"))
- }
-
- @@ -859,6 +871,18 @@ static void read_kex_algos() {
- }
- #endif
-
- + if (!ses.kexstate.donefirstkex) {
- + const char* strict_name;
- + if (IS_DROPBEAR_CLIENT) {
- + strict_name = SSH_STRICT_KEX_S;
- + } else {
- + strict_name = SSH_STRICT_KEX_C;
- + }
- + if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) {
- + ses.kexstate.strict_kex = 1;
- + }
- + }
- +
- algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
- allgood &= goodguess;
- if (algo == NULL || algo->data == NULL) {
- --- a/kex.h
- +++ b/kex.h
- @@ -83,6 +83,9 @@ struct KEXState {
-
- unsigned our_first_follows_matches : 1;
-
- + /* Boolean indicating that strict kex mode is in use */
- + unsigned int strict_kex;
- +
- time_t lastkextime; /* time of the last kex */
- unsigned int datatrans; /* data transmitted since last kex */
- unsigned int datarecv; /* data received since last kex */
- --- a/process-packet.c
- +++ b/process-packet.c
- @@ -44,6 +44,7 @@ void process_packet() {
-
- unsigned char type;
- unsigned int i;
- + unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex;
- time_t now;
-
- TRACE2(("enter process_packet"))
- @@ -54,22 +55,24 @@ void process_packet() {
- now = monotonic_now();
- ses.last_packet_time_keepalive_recv = now;
-
- - /* These packets we can receive at any time */
- - switch(type) {
-
- - case SSH_MSG_IGNORE:
- - goto out;
- - case SSH_MSG_DEBUG:
- - goto out;
- -
- - case SSH_MSG_UNIMPLEMENTED:
- - /* debugging XXX */
- - TRACE(("SSH_MSG_UNIMPLEMENTED"))
- - goto out;
- -
- - case SSH_MSG_DISCONNECT:
- - /* TODO cleanup? */
- - dropbear_close("Disconnect received");
- + if (type == SSH_MSG_DISCONNECT) {
- + /* Allowed at any time */
- + dropbear_close("Disconnect received");
- + }
- +
- + /* These packets may be received at any time,
- + except during first kex with strict kex */
- + if (!first_strict_kex) {
- + switch(type) {
- + case SSH_MSG_IGNORE:
- + goto out;
- + case SSH_MSG_DEBUG:
- + goto out;
- + case SSH_MSG_UNIMPLEMENTED:
- + TRACE(("SSH_MSG_UNIMPLEMENTED"))
- + goto out;
- + }
- }
-
- /* Ignore these packet types so that keepalives don't interfere with
- @@ -98,7 +101,8 @@ void process_packet() {
- if (type >= 1 && type <= 49
- && type != SSH_MSG_SERVICE_REQUEST
- && type != SSH_MSG_SERVICE_ACCEPT
- - && type != SSH_MSG_KEXINIT)
- + && type != SSH_MSG_KEXINIT
- + && !first_strict_kex)
- {
- TRACE(("unknown allowed packet during kexinit"))
- recv_unimplemented();
- --- a/ssh.h
- +++ b/ssh.h
- @@ -100,6 +100,10 @@
- #define SSH_EXT_INFO_C "ext-info-c"
- #define SSH_SERVER_SIG_ALGS "server-sig-algs"
-
- +/* OpenSSH strict KEX feature */
- +#define SSH_STRICT_KEX_S "[email protected]"
- +#define SSH_STRICT_KEX_C "[email protected]"
- +
- /* service types */
- #define SSH_SERVICE_USERAUTH "ssh-userauth"
- #define SSH_SERVICE_USERAUTH_LEN 12
- --- a/svr-session.c
- +++ b/svr-session.c
- @@ -370,6 +370,9 @@ static void svr_algos_initialise(void) {
- algo->usable = 0;
- }
- #endif
- + if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) {
- + algo->usable = 0;
- + }
- }
- }
-
|