dropbear: cherry-pick upstream patches
[openwrt/staging/robimarko.git] / package / network / services / dropbear / patches / 021-Implement-Strict-KEX-mode.patch
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
5
6 As specified by OpenSSH with kex-strict-c-v00@openssh.com and
7 kex-strict-s-v00@openssh.com.
8 ---
9 cli-session.c | 11 +++++++++++
10 common-algo.c | 6 ++++++
11 common-kex.c | 26 +++++++++++++++++++++++++-
12 kex.h | 3 +++
13 process-packet.c | 34 +++++++++++++++++++---------------
14 ssh.h | 4 ++++
15 svr-session.c | 3 +++
16 7 files changed, 71 insertions(+), 16 deletions(-)
17
18 --- a/cli-session.c
19 +++ b/cli-session.c
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);
25
26 struct clientsession cli_ses; /* GLOBAL */
27
28 @@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o
29 }
30
31 chaninitialise(cli_chantypes);
32 + cli_algos_initialise();
33
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
37 fflush(stderr);
38 }
39
40 +static void cli_algos_initialise(void) {
41 + algo_type *algo;
42 + for (algo = sshkex; algo->name; algo++) {
43 + if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) {
44 + algo->usable = 0;
45 + }
46 + }
47 +}
48 +
49 --- a/common-algo.c
50 +++ b/common-algo.c
51 @@ -308,6 +308,12 @@ algo_type sshkex[] = {
52 {SSH_EXT_INFO_C, 0, NULL, 1, NULL},
53 #endif
54 #endif
55 +#if DROPBEAR_CLIENT
56 + {SSH_STRICT_KEX_C, 0, NULL, 1, NULL},
57 +#endif
58 +#if DROPBEAR_SERVER
59 + {SSH_STRICT_KEX_S, 0, NULL, 1, NULL},
60 +#endif
61 {NULL, 0, NULL, 0, NULL}
62 };
63
64 --- a/common-kex.c
65 +++ b/common-kex.c
66 @@ -183,6 +183,10 @@ void send_msg_newkeys() {
67 gen_new_keys();
68 switch_keys();
69
70 + if (ses.kexstate.strict_kex) {
71 + ses.transseq = 0;
72 + }
73 +
74 TRACE(("leave send_msg_newkeys"))
75 }
76
77 @@ -193,7 +197,11 @@ void recv_msg_newkeys() {
78
79 ses.kexstate.recvnewkeys = 1;
80 switch_keys();
81 -
82 +
83 + if (ses.kexstate.strict_kex) {
84 + ses.recvseq = 0;
85 + }
86 +
87 TRACE(("leave recv_msg_newkeys"))
88 }
89
90 @@ -550,6 +558,10 @@ void recv_msg_kexinit() {
91
92 ses.kexstate.recvkexinit = 1;
93
94 + if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) {
95 + dropbear_exit("First packet wasn't kexinit");
96 + }
97 +
98 TRACE(("leave recv_msg_kexinit"))
99 }
100
101 @@ -859,6 +871,18 @@ static void read_kex_algos() {
102 }
103 #endif
104
105 + if (!ses.kexstate.donefirstkex) {
106 + const char* strict_name;
107 + if (IS_DROPBEAR_CLIENT) {
108 + strict_name = SSH_STRICT_KEX_S;
109 + } else {
110 + strict_name = SSH_STRICT_KEX_C;
111 + }
112 + if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) {
113 + ses.kexstate.strict_kex = 1;
114 + }
115 + }
116 +
117 algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
118 allgood &= goodguess;
119 if (algo == NULL || algo->data == NULL) {
120 --- a/kex.h
121 +++ b/kex.h
122 @@ -83,6 +83,9 @@ struct KEXState {
123
124 unsigned our_first_follows_matches : 1;
125
126 + /* Boolean indicating that strict kex mode is in use */
127 + unsigned int strict_kex;
128 +
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() {
135
136 unsigned char type;
137 unsigned int i;
138 + unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex;
139 time_t now;
140
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;
145
146 - /* These packets we can receive at any time */
147 - switch(type) {
148
149 - case SSH_MSG_IGNORE:
150 - goto out;
151 - case SSH_MSG_DEBUG:
152 - goto out;
153 -
154 - case SSH_MSG_UNIMPLEMENTED:
155 - /* debugging XXX */
156 - TRACE(("SSH_MSG_UNIMPLEMENTED"))
157 - goto out;
158 -
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");
165 + }
166 +
167 + /* These packets may be received at any time,
168 + except during first kex with strict kex */
169 + if (!first_strict_kex) {
170 + switch(type) {
171 + case SSH_MSG_IGNORE:
172 + goto out;
173 + case SSH_MSG_DEBUG:
174 + goto out;
175 + case SSH_MSG_UNIMPLEMENTED:
176 + TRACE(("SSH_MSG_UNIMPLEMENTED"))
177 + goto out;
178 + }
179 }
180
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)
189 {
190 TRACE(("unknown allowed packet during kexinit"))
191 recv_unimplemented();
192 --- a/ssh.h
193 +++ b/ssh.h
194 @@ -100,6 +100,10 @@
195 #define SSH_EXT_INFO_C "ext-info-c"
196 #define SSH_SERVER_SIG_ALGS "server-sig-algs"
197
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"
201 +
202 /* service types */
203 #define SSH_SERVICE_USERAUTH "ssh-userauth"
204 #define SSH_SERVICE_USERAUTH_LEN 12
205 --- a/svr-session.c
206 +++ b/svr-session.c
207 @@ -370,6 +370,9 @@ static void svr_algos_initialise(void) {
208 algo->usable = 0;
209 }
210 #endif
211 + if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) {
212 + algo->usable = 0;
213 + }
214 }
215 }
216