1 From 6e43be5c7b99dbee49dc72b6f989f29fdd7e9356 Mon Sep 17 00:00:00 2001
2 From: Matt Johnston <matt@ucc.asn.au>
3 Date: Mon, 20 Nov 2023 14:02:47 +0800
4 Subject: Implement Strict KEX mode
6 As specified by OpenSSH with kex-strict-c-v00@openssh.com and
7 kex-strict-s-v00@openssh.com.
9 cli-session.c | 11 +++++++++++
10 common-algo.c | 6 ++++++
11 common-kex.c | 26 +++++++++++++++++++++++++-
13 process-packet.c | 34 +++++++++++++++++++---------------
16 7 files changed, 71 insertions(+), 16 deletions(-)
20 @@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NO
21 static void recv_msg_service_accept(void);
22 static void cli_session_cleanup(void);
23 static void recv_msg_global_request_cli(void);
24 +static void cli_algos_initialise(void);
26 struct clientsession cli_ses; /* GLOBAL */
28 @@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o
31 chaninitialise(cli_chantypes);
32 + cli_algos_initialise();
34 /* Set up cli_ses vars */
35 cli_session_init(proxy_cmd_pid);
36 @@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, cons
40 +static void cli_algos_initialise(void) {
42 + for (algo = sshkex; algo->name; algo++) {
43 + if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) {
51 @@ -308,6 +308,12 @@ algo_type sshkex[] = {
52 {SSH_EXT_INFO_C, 0, NULL, 1, NULL},
56 + {SSH_STRICT_KEX_C, 0, NULL, 1, NULL},
59 + {SSH_STRICT_KEX_S, 0, NULL, 1, NULL},
61 {NULL, 0, NULL, 0, NULL}
66 @@ -183,6 +183,10 @@ void send_msg_newkeys() {
70 + if (ses.kexstate.strict_kex) {
74 TRACE(("leave send_msg_newkeys"))
77 @@ -193,7 +197,11 @@ void recv_msg_newkeys() {
79 ses.kexstate.recvnewkeys = 1;
83 + if (ses.kexstate.strict_kex) {
87 TRACE(("leave recv_msg_newkeys"))
90 @@ -550,6 +558,10 @@ void recv_msg_kexinit() {
92 ses.kexstate.recvkexinit = 1;
94 + if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) {
95 + dropbear_exit("First packet wasn't kexinit");
98 TRACE(("leave recv_msg_kexinit"))
101 @@ -859,6 +871,18 @@ static void read_kex_algos() {
105 + if (!ses.kexstate.donefirstkex) {
106 + const char* strict_name;
107 + if (IS_DROPBEAR_CLIENT) {
108 + strict_name = SSH_STRICT_KEX_S;
110 + strict_name = SSH_STRICT_KEX_C;
112 + if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) {
113 + ses.kexstate.strict_kex = 1;
117 algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
118 allgood &= goodguess;
119 if (algo == NULL || algo->data == NULL) {
122 @@ -83,6 +83,9 @@ struct KEXState {
124 unsigned our_first_follows_matches : 1;
126 + /* Boolean indicating that strict kex mode is in use */
127 + unsigned int strict_kex;
129 time_t lastkextime; /* time of the last kex */
130 unsigned int datatrans; /* data transmitted since last kex */
131 unsigned int datarecv; /* data received since last kex */
132 --- a/process-packet.c
133 +++ b/process-packet.c
134 @@ -44,6 +44,7 @@ void process_packet() {
138 + unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex;
141 TRACE2(("enter process_packet"))
142 @@ -54,22 +55,24 @@ void process_packet() {
143 now = monotonic_now();
144 ses.last_packet_time_keepalive_recv = now;
146 - /* These packets we can receive at any time */
149 - case SSH_MSG_IGNORE:
151 - case SSH_MSG_DEBUG:
154 - case SSH_MSG_UNIMPLEMENTED:
155 - /* debugging XXX */
156 - TRACE(("SSH_MSG_UNIMPLEMENTED"))
159 - case SSH_MSG_DISCONNECT:
160 - /* TODO cleanup? */
161 - dropbear_close("Disconnect received");
162 + if (type == SSH_MSG_DISCONNECT) {
163 + /* Allowed at any time */
164 + dropbear_close("Disconnect received");
167 + /* These packets may be received at any time,
168 + except during first kex with strict kex */
169 + if (!first_strict_kex) {
171 + case SSH_MSG_IGNORE:
173 + case SSH_MSG_DEBUG:
175 + case SSH_MSG_UNIMPLEMENTED:
176 + TRACE(("SSH_MSG_UNIMPLEMENTED"))
181 /* Ignore these packet types so that keepalives don't interfere with
182 @@ -98,7 +101,8 @@ void process_packet() {
183 if (type >= 1 && type <= 49
184 && type != SSH_MSG_SERVICE_REQUEST
185 && type != SSH_MSG_SERVICE_ACCEPT
186 - && type != SSH_MSG_KEXINIT)
187 + && type != SSH_MSG_KEXINIT
188 + && !first_strict_kex)
190 TRACE(("unknown allowed packet during kexinit"))
191 recv_unimplemented();
195 #define SSH_EXT_INFO_C "ext-info-c"
196 #define SSH_SERVER_SIG_ALGS "server-sig-algs"
198 +/* OpenSSH strict KEX feature */
199 +#define SSH_STRICT_KEX_S "kex-strict-s-v00@openssh.com"
200 +#define SSH_STRICT_KEX_C "kex-strict-c-v00@openssh.com"
203 #define SSH_SERVICE_USERAUTH "ssh-userauth"
204 #define SSH_SERVICE_USERAUTH_LEN 12
207 @@ -370,6 +370,9 @@ static void svr_algos_initialise(void) {
211 + if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) {