summaryrefslogtreecommitdiffstats
path: root/meta-networking
diff options
context:
space:
mode:
authorVijay Anusuri <vanusuri@mvista.com>2025-10-20 13:22:25 +0530
committerGyorgy Sarvari <skandigraun@gmail.com>2025-10-20 11:59:36 +0200
commit6c8ae54fc345fb6249f1cc92ed769d451ddc12b5 (patch)
tree8d495627d38465eff44413d9c2fbd3639d267c4d /meta-networking
parentb476f98381af7e7b369e788fffee817d4e4ebb45 (diff)
downloadmeta-openembedded-6c8ae54fc345fb6249f1cc92ed769d451ddc12b5.tar.gz
proftpd: Fix CVE-2023-48795
Upstream-Status: Backport from https://github.com/proftpd/proftpd/commit/bcec15efe6c53dac40420731013f1cd2fd54123b Signed-off-by: Vijay Anusuri <vanusuri@mvista.com> Signed-off-by: Gyorgy Sarvari <skandigraun@gmail.com>
Diffstat (limited to 'meta-networking')
-rw-r--r--meta-networking/recipes-daemons/proftpd/files/CVE-2023-48795.patch751
-rw-r--r--meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb1
2 files changed, 752 insertions, 0 deletions
diff --git a/meta-networking/recipes-daemons/proftpd/files/CVE-2023-48795.patch b/meta-networking/recipes-daemons/proftpd/files/CVE-2023-48795.patch
new file mode 100644
index 0000000000..39def781fb
--- /dev/null
+++ b/meta-networking/recipes-daemons/proftpd/files/CVE-2023-48795.patch
@@ -0,0 +1,751 @@
1From bcec15efe6c53dac40420731013f1cd2fd54123b Mon Sep 17 00:00:00 2001
2From: TJ Saunders <tj@castaglia.org>
3Date: Tue, 19 Dec 2023 18:55:58 -0800
4Subject: [PATCH] Issue #1760: Implement the "strict KEX" mitigations for the
5 Terrapin SSH protocol attack (CVE-2023-48795).
6
7Upstream-Status: Backport [https://github.com/proftpd/proftpd/commit/bcec15efe6c53dac40420731013f1cd2fd54123b]
8CVE: CVE-2023-48795
9Signed-off-by: Vijay Anusuri <vanusuri@mvista.com>
10---
11 contrib/mod_sftp/kex.c | 124 ++++++++--
12 contrib/mod_sftp/mod_sftp.c | 8 +-
13 contrib/mod_sftp/mod_sftp.h.in | 1 +
14 contrib/mod_sftp/packet.c | 12 +
15 contrib/mod_sftp/packet.h | 9 +-
16 contrib/mod_sftp/tap.c | 26 ++-
17 contrib/mod_sftp/tap.h | 5 +-
18 doc/contrib/mod_sftp.html | 15 +-
19 tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm | 217 ++++++++++++++++++
20 9 files changed, 380 insertions(+), 37 deletions(-)
21
22diff --git a/contrib/mod_sftp/kex.c b/contrib/mod_sftp/kex.c
23index 754bd9e87..c1caa1c27 100644
24--- a/contrib/mod_sftp/kex.c
25+++ b/contrib/mod_sftp/kex.c
26@@ -149,6 +149,13 @@ static struct sftp_kex *kex_first_kex = NULL;
27 static struct sftp_kex *kex_rekey_kex = NULL;
28 static int kex_sent_kexinit = FALSE;
29
30+/* Using strict kex? Note that we maintain this value here, rather than
31+ * in the sftp_kex struct, so that any "use strict KEX" flag set via the
32+ * first KEXINIT is used through any subsequent KEXINITs.
33+ */
34+static int use_strict_kex = FALSE;
35+static int kex_done_first_kex = FALSE;
36+
37 /* Diffie-Hellman group moduli */
38
39 static const char *dh_group1_str =
40@@ -1593,6 +1600,16 @@ static const char *get_kexinit_exchange_list(pool *p) {
41 res = pstrcat(p, res, *res ? "," : "", pstrdup(p, "ext-info-s"), NULL);
42 }
43
44+ if (!(sftp_opts & SFTP_OPT_NO_STRICT_KEX)) {
45+ /* Indicate support for OpenSSH's custom "strict KEX" mode extension,
46+ * but only if we have not done/completed our first KEX.
47+ */
48+ if (kex_done_first_kex == FALSE) {
49+ res = pstrcat(p, res, *res ? "," : "",
50+ pstrdup(p, "kex-strict-s-v00@openssh.com"), NULL);
51+ }
52+ }
53+
54 return res;
55 }
56
57@@ -2174,6 +2191,21 @@ static int get_session_names(struct sftp_kex *kex, int *correct_guess) {
58 pr_trace_msg(trace_channel, 20, "client %s EXT_INFO support",
59 kex->use_ext_info ? "signaled" : "did not signal" );
60
61+ if (!(sftp_opts & SFTP_OPT_NO_STRICT_KEX)) {
62+ /* Did the client indicate "strict kex" support (Issue 1760)?
63+ *
64+ * Note that we only check for this if it is our first KEXINIT.
65+ * The "strict kex" extension is ignored in any subsequent KEXINITs, as
66+ * for rekeys.
67+ */
68+ if (kex_done_first_kex == FALSE) {
69+ use_strict_kex = sftp_misc_namelist_contains(kex->pool,
70+ client_list, "kex-strict-c-v00@openssh.com");
71+ pr_trace_msg(trace_channel, 20, "client %s strict KEX support",
72+ use_strict_kex ? "signaled" : "did not signal" );
73+ }
74+ }
75+
76 } else {
77 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
78 "no shared key exchange algorithm found (client sent '%s', server sent "
79@@ -4406,7 +4438,6 @@ static int handle_kex_ecdh(struct ssh2_packet *pkt, struct sftp_kex *kex) {
80 destroy_pool(pkt->pool);
81 return 0;
82 }
83-
84 #endif /* PR_USE_OPENSSL_ECC */
85
86 static struct ssh2_packet *read_kex_packet(pool *p, struct sftp_kex *kex,
87@@ -4457,6 +4488,10 @@ static struct ssh2_packet *read_kex_packet(pool *p, struct sftp_kex *kex,
88 /* Per RFC 4253, Section 11, DEBUG, DISCONNECT, IGNORE, and UNIMPLEMENTED
89 * messages can occur at any time, even during KEX. We have to be prepared
90 * for this, and Do The Right Thing(tm).
91+ *
92+ * However, due to the Terrapin attack, if we are using a "strict KEX"
93+ * mode, then only DISCONNECT messages can occur during KEX; DEBUG,
94+ * IGNORE, and UNIMPLEMENTED messages will lead to disconnecting.
95 */
96
97 mesg_type = sftp_ssh2_packet_get_mesg_type(pkt);
98@@ -4485,35 +4520,43 @@ static struct ssh2_packet *read_kex_packet(pool *p, struct sftp_kex *kex,
99 }
100
101 switch (mesg_type) {
102- case SFTP_SSH2_MSG_DEBUG:
103- sftp_ssh2_packet_handle_debug(pkt);
104- pr_response_set_pool(NULL);
105- pkt = NULL;
106- break;
107-
108+ /* DISCONNECT messages are always allowed. */
109 case SFTP_SSH2_MSG_DISCONNECT:
110 sftp_ssh2_packet_handle_disconnect(pkt);
111 pr_response_set_pool(NULL);
112 pkt = NULL;
113 break;
114
115+ case SFTP_SSH2_MSG_DEBUG:
116+ if (use_strict_kex == FALSE) {
117+ sftp_ssh2_packet_handle_debug(pkt);
118+ pr_response_set_pool(NULL);
119+ pkt = NULL;
120+ break;
121+ }
122+
123 case SFTP_SSH2_MSG_IGNORE:
124- sftp_ssh2_packet_handle_ignore(pkt);
125- pr_response_set_pool(NULL);
126- pkt = NULL;
127- break;
128+ if (use_strict_kex == FALSE) {
129+ sftp_ssh2_packet_handle_ignore(pkt);
130+ pr_response_set_pool(NULL);
131+ pkt = NULL;
132+ break;
133+ }
134
135 case SFTP_SSH2_MSG_UNIMPLEMENTED:
136- sftp_ssh2_packet_handle_unimplemented(pkt);
137- pr_response_set_pool(NULL);
138- pkt = NULL;
139- break;
140+ if (use_strict_kex == FALSE) {
141+ sftp_ssh2_packet_handle_unimplemented(pkt);
142+ pr_response_set_pool(NULL);
143+ pkt = NULL;
144+ break;
145+ }
146
147 default:
148 /* For any other message type, it's considered a protocol error. */
149 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
150- "received %s (%d) unexpectedly, disconnecting",
151- sftp_ssh2_packet_get_mesg_type_desc(mesg_type), mesg_type);
152+ "received %s (%d) unexpectedly%s, disconnecting",
153+ sftp_ssh2_packet_get_mesg_type_desc(mesg_type), mesg_type,
154+ use_strict_kex ? " during strict KEX" : "");
155 pr_response_set_pool(NULL);
156 destroy_kex(kex);
157 destroy_pool(pkt->pool);
158@@ -4534,7 +4577,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
159 * initial connect (kex_first_kex not null), or because we
160 * are in a server-initiated rekeying (kex_rekey_kex not null).
161 */
162- if (kex_first_kex) {
163+ if (kex_first_kex != NULL) {
164 kex = kex_first_kex;
165
166 /* We need to assign the client/server versions, which this struct
167@@ -4543,7 +4586,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
168 kex->client_version = kex_client_version;
169 kex->server_version = kex_server_version;
170
171- } else if (kex_rekey_kex) {
172+ } else if (kex_rekey_kex != NULL) {
173 kex = kex_rekey_kex;
174
175 } else {
176@@ -4579,6 +4622,24 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
177 return -1;
178 }
179
180+ if (use_strict_kex == TRUE &&
181+ kex_done_first_kex == FALSE) {
182+ uint32_t client_seqno;
183+
184+ client_seqno = sftp_ssh2_packet_get_client_seqno();
185+ if (client_seqno != 1) {
186+ /* Receiving any messages other than a KEXINIT as the first client
187+ * message indicates the possibility of the Terrapin attack being
188+ * conducted (Issue 1760). Thus we disconnect the client in such
189+ * cases.
190+ */
191+ (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
192+ "'strict KEX' violation, as KEXINIT was not the first message; disconnecting");
193+ destroy_kex(kex);
194+ SFTP_DISCONNECT_CONN(SFTP_SSH2_DISCONNECT_BY_APPLICATION, NULL);
195+ }
196+ }
197+
198 /* Once we have received the client KEXINIT message, we can compare what we
199 * want to send against what we already received from the client.
200 *
201@@ -4637,7 +4698,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
202
203 destroy_pool(pkt->pool);
204
205- if (!kex_sent_kexinit) {
206+ if (kex_sent_kexinit == FALSE) {
207 pkt = sftp_ssh2_packet_create(kex_pool);
208 res = write_kexinit(pkt, kex);
209 if (res < 0) {
210@@ -4660,7 +4721,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
211 }
212 }
213
214- if (!kex_sent_kexinit) {
215+ if (kex_sent_kexinit == FALSE) {
216 pkt = sftp_ssh2_packet_create(kex_pool);
217 res = write_kexinit(pkt, kex);
218 if (res < 0) {
219@@ -4785,7 +4846,7 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
220 NULL, 1, SFTP_SSH2_MSG_NEWKEYS);
221
222 /* If we didn't send our NEWKEYS message earlier, do it now. */
223- if (!sent_newkeys) {
224+ if (sent_newkeys == FALSE) {
225 struct ssh2_packet *pkt2;
226
227 pr_trace_msg(trace_channel, 9, "sending NEWKEYS message to client");
228@@ -4809,6 +4870,11 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
229 destroy_pool(pkt2->pool);
230 }
231
232+ if (use_strict_kex == TRUE) {
233+ sftp_ssh2_packet_reset_client_seqno();
234+ sftp_ssh2_packet_reset_server_seqno();
235+ }
236+
237 /* Last but certainly not least, set up the keys for encryption and
238 * authentication, based on H and K.
239 */
240@@ -4828,6 +4894,9 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
241 destroy_pool(pkt->pool);
242 cmd = NULL;
243
244+ /* We've now completed our KEX, possibly our first. */
245+ kex_done_first_kex = TRUE;
246+
247 /* If extension negotiation has not been disabled, AND if we have not
248 * received a service request, AND if the client sent "ext-info-c", THEN
249 * send our EXT_INFO. We do not want send this during rekeys.
250@@ -4864,6 +4933,12 @@ int sftp_kex_handle(struct ssh2_packet *pkt) {
251 cmd = NULL;
252 }
253
254+ /* Only start the TAP timer after we have completed our first KEX.
255+ * Otherwise, we risk sending "illegal" packets prior to, or during,
256+ * a "strict KEX" session (Issue 1760).
257+ */
258+ sftp_tap_start_policy();
259+
260 /* Reset this flag for the next time through. */
261 kex_sent_kexinit = FALSE;
262
263@@ -4893,7 +4968,7 @@ int sftp_kex_free(void) {
264 destroy_kex(rekey_kex);
265 }
266
267- if (kex_pool) {
268+ if (kex_pool != NULL) {
269 destroy_pool(kex_pool);
270 kex_pool = NULL;
271 }
272@@ -5065,7 +5140,7 @@ int sftp_kex_send_first_kexinit(void) {
273 struct ssh2_packet *pkt;
274 int res;
275
276- if (!kex_pool) {
277+ if (kex_pool == NULL) {
278 kex_pool = make_sub_pool(sftp_pool);
279 pr_pool_tag(kex_pool, "Kex Pool");
280 }
281@@ -5100,4 +5175,3 @@ int sftp_kex_send_first_kexinit(void) {
282 destroy_pool(pkt->pool);
283 return 0;
284 }
285-
286diff --git a/contrib/mod_sftp/mod_sftp.c b/contrib/mod_sftp/mod_sftp.c
287index b84b1a77b..2406ea611 100644
288--- a/contrib/mod_sftp/mod_sftp.c
289+++ b/contrib/mod_sftp/mod_sftp.c
290@@ -1,6 +1,6 @@
291 /*
292 * ProFTPD - mod_sftp
293- * Copyright (c) 2008-2020 TJ Saunders
294+ * Copyright (c) 2008-2023 TJ Saunders
295 *
296 * This program is free software; you can redistribute it and/or modify
297 * it under the terms of the GNU General Public License as published by
298@@ -1411,8 +1411,9 @@ MODRET set_sftpoptions(cmd_rec *cmd) {
299 config_rec *c;
300 unsigned long opts = 0UL;
301
302- if (cmd->argc-1 == 0)
303+ if (cmd->argc-1 == 0) {
304 CONF_ERROR(cmd, "wrong number of parameters");
305+ }
306
307 CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);
308
309@@ -1476,6 +1477,9 @@ MODRET set_sftpoptions(cmd_rec *cmd) {
310 } else if (strcmp(cmd->argv[i], "NoExtensionNegotiation") == 0) {
311 opts |= SFTP_OPT_NO_EXT_INFO;
312
313+ } else if (strcmp(cmd->argv[i], "NoStrictKex") == 0) {
314+ opts |= SFTP_OPT_NO_STRICT_KEX;
315+
316 } else {
317 CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, ": unknown SFTPOption '",
318 cmd->argv[i], "'", NULL));
319diff --git a/contrib/mod_sftp/mod_sftp.h.in b/contrib/mod_sftp/mod_sftp.h.in
320index 065981c31..adcf71276 100644
321--- a/contrib/mod_sftp/mod_sftp.h.in
322+++ b/contrib/mod_sftp/mod_sftp.h.in
323@@ -131,6 +131,7 @@
324 #define SFTP_OPT_IGNORE_SFTP_SET_XATTRS 0x04000
325 #define SFTP_OPT_INCLUDE_SFTP_TIMES 0x08000
326 #define SFTP_OPT_NO_EXT_INFO 0x10000
327+#define SFTP_OPT_NO_STRICT_KEX 0x040000
328
329 /* mod_sftp service flags */
330 #define SFTP_SERVICE_FL_SFTP 0x0001
331diff --git a/contrib/mod_sftp/packet.c b/contrib/mod_sftp/packet.c
332index b0067ea80..d8c97e92b 100644
333--- a/contrib/mod_sftp/packet.c
334+++ b/contrib/mod_sftp/packet.c
335@@ -1742,6 +1742,18 @@ int sftp_ssh2_packet_rekey_set_size(off_t size) {
336 return 0;
337 }
338
339+uint32_t sftp_ssh2_packet_get_client_seqno(void) {
340+ return packet_client_seqno;
341+}
342+
343+void sftp_ssh2_packet_reset_client_seqno(void) {
344+ packet_client_seqno = 0;
345+}
346+
347+void sftp_ssh2_packet_reset_server_seqno(void) {
348+ packet_server_seqno = 0;
349+}
350+
351 int sftp_ssh2_packet_send_version(void) {
352 if (!sent_version_id) {
353 int res;
354diff --git a/contrib/mod_sftp/packet.h b/contrib/mod_sftp/packet.h
355index a424e9b25..fe538cbd7 100644
356--- a/contrib/mod_sftp/packet.h
357+++ b/contrib/mod_sftp/packet.h
358@@ -1,6 +1,6 @@
359 /*
360 * ProFTPD - mod_sftp packet IO
361- * Copyright (c) 2008-2020 TJ Saunders
362+ * Copyright (c) 2008-2023 TJ Saunders
363 *
364 * This program is free software; you can redistribute it and/or modify
365 * it under the terms of the GNU General Public License as published by
366@@ -107,6 +107,13 @@ int sftp_ssh2_packet_rekey_reset(void);
367 int sftp_ssh2_packet_rekey_set_seqno(uint32_t);
368 int sftp_ssh2_packet_rekey_set_size(off_t);
369
370+/* These are used for implementing the "strict KEX" mitigations of the Terrapin
371+ * attack (Issue 1760).
372+ */
373+uint32_t sftp_ssh2_packet_get_client_seqno(void);
374+void sftp_ssh2_packet_reset_client_seqno(void);
375+void sftp_ssh2_packet_reset_server_seqno(void);
376+
377 int sftp_ssh2_packet_send_version(void);
378 int sftp_ssh2_packet_set_poll_timeout(int);
379 int sftp_ssh2_packet_set_version(const char *);
380diff --git a/contrib/mod_sftp/tap.c b/contrib/mod_sftp/tap.c
381index 95f388e43..7eaf959e2 100644
382--- a/contrib/mod_sftp/tap.c
383+++ b/contrib/mod_sftp/tap.c
384@@ -1,6 +1,6 @@
385 /*
386 * ProFTPD - mod_sftp traffic analysis protection
387- * Copyright (c) 2008-2016 TJ Saunders
388+ * Copyright (c) 2008-2023 TJ Saunders
389 *
390 * This program is free software; you can redistribute it and/or modify
391 * it under the terms of the GNU General Public License as published by
392@@ -149,7 +149,6 @@ static void set_policy_chance(struct sftp_tap_policy *policy) {
393 }
394
395 static void set_policy_timer(struct sftp_tap_policy *policy) {
396-
397 /* Start a timer which checks the last times we received and sent packets.
398 * From there, we may want to inject a TAP message, depending on the
399 * policy.
400@@ -177,6 +176,16 @@ int sftp_tap_send_packet(void) {
401 int rnd;
402 unsigned int chance;
403
404+ /* Due to chances of violating client-side "strict KEX" Terrapin
405+ * mitigations, we will not send packets if we are in the middle of a KEX.
406+ */
407+ if (!(sftp_sess_state & SFTP_SESS_STATE_HAVE_KEX) ||
408+ (sftp_sess_state & SFTP_SESS_STATE_REKEYING)) {
409+ pr_trace_msg(trace_channel, 11,
410+ "unwilling to send TAP packet during KEX");
411+ return 0;
412+ }
413+
414 if (!sftp_interop_supports_feature(SFTP_SSH2_FEAT_IGNORE_MSG)) {
415 pr_trace_msg(trace_channel, 3,
416 "unable to send TAP packet: IGNORE not supported by client");
417@@ -205,7 +214,7 @@ int sftp_tap_send_packet(void) {
418 struct ssh2_packet *pkt;
419 unsigned int max_datalen = 8192;
420
421- if (curr_policy.max_datalen) {
422+ if (curr_policy.max_datalen > 0) {
423 max_datalen = curr_policy.max_datalen;
424 }
425
426@@ -246,15 +255,15 @@ int sftp_tap_send_packet(void) {
427 int sftp_tap_set_policy(const char *policy) {
428 register unsigned int i;
429
430- if (tap_pool) {
431+ if (tap_pool != NULL) {
432
433 /* Special case: IFF the existing policy is 'none' AND the given
434 * policy is 'rogaway', just return. The 'none' policy must have been
435 * explicitly configured, and it should override the automatic use of
436 * the 'rogaway' policy.
437 */
438- if (strncmp(curr_policy.policy, "none", 5) == 0 &&
439- strncasecmp(policy, "rogaway", 8) == 0) {
440+ if (strcasecmp(curr_policy.policy, "none") == 0 &&
441+ strcasecmp(policy, "rogaway") == 0) {
442 (void) pr_log_writefile(sftp_logfd, MOD_SFTP_VERSION,
443 "'none' traffic policy explicitly configured, ignoring '%s' policy",
444 policy);
445@@ -278,7 +287,6 @@ int sftp_tap_set_policy(const char *policy) {
446 if (strcasecmp(tap_policies[i].policy, policy) == 0) {
447 copy_policy(&curr_policy, &(tap_policies[i]));
448 set_policy_chance(&curr_policy);
449- set_policy_timer(&curr_policy);
450 return 0;
451 }
452 }
453@@ -286,3 +294,7 @@ int sftp_tap_set_policy(const char *policy) {
454 errno = ENOENT;
455 return -1;
456 }
457+
458+void sftp_tap_start_policy(void) {
459+ set_policy_timer(&curr_policy);
460+}
461diff --git a/contrib/mod_sftp/tap.h b/contrib/mod_sftp/tap.h
462index 4a4c065d2..312223595 100644
463--- a/contrib/mod_sftp/tap.h
464+++ b/contrib/mod_sftp/tap.h
465@@ -1,6 +1,6 @@
466 /*
467 * ProFTPD - mod_sftp traffic analysis protection
468- * Copyright (c) 2008-2016 TJ Saunders
469+ * Copyright (c) 2008-2013 TJ Saunders
470 *
471 * This program is free software; you can redistribute it and/or modify
472 * it under the terms of the GNU General Public License as published by
473@@ -63,4 +63,7 @@ int sftp_tap_send_packet(void);
474 */
475 int sftp_tap_set_policy(const char *);
476
477+/* Sets the configured TAP policy in motion. */
478+void sftp_tap_start_policy(void);
479+
480 #endif /* MOD_SFTP_TAP_H */
481diff --git a/doc/contrib/mod_sftp.html b/doc/contrib/mod_sftp.html
482index 60c3436fa..cfc639d05 100644
483--- a/doc/contrib/mod_sftp.html
484+++ b/doc/contrib/mod_sftp.html
485@@ -1186,6 +1186,19 @@ The currently implemented options are:
486 <code>proftpd-1.3.7rc4</code>.
487 </li>
488
489+ <p>
490+ <li><code>NoStrictKex</code><br>
491+ <p>
492+ By default, <code>mod_sftp</code> will honor/support the OpenSSH
493+ "strict KEX" mode extension, "kex-strict-c-v00@openssh.com" and
494+ "kex-strict-s-v00@openssh.com". Use this option to disable support for
495+ these custom OpenSSH extensions.
496+
497+ <p>
498+ <b>Note</b> that this option first appeared in
499+ <code>proftpd-1.3.9rc1</code>.
500+ </li>
501+
502 <p>
503 <li><code>OldProtocolCompat</code><br>
504 <p>
505@@ -2642,7 +2655,7 @@ deal with this issue, then, you can hopefully upgrade to ProFTPD 1.3.6 or later,
506 <p>
507 <hr>
508 <font size=2><b><i>
509-&copy; Copyright 2008-2021 TJ Saunders<br>
510+&copy; Copyright 2008-2023 TJ Saunders<br>
511 All Rights Reserved<br>
512 </i></b></font>
513 <hr>
514diff --git a/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm b/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
515index b4bdf516b..8c2be5465 100644
516--- a/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
517+++ b/tests/t/lib/ProFTPD/Tests/Modules/mod_sftp.pm
518@@ -87,6 +87,11 @@ my $TESTS = {
519 test_class => [qw(forking ssh2)],
520 },
521
522+ ssh2_ext_kex_strict_terrapin_issue1760 => {
523+ order => ++$order,
524+ test_class => [qw(bug forking ssh2)],
525+ },
526+
527 ssh2_hostkey_rsa => {
528 order => ++$order,
529 test_class => [qw(forking ssh2)],
530@@ -3885,6 +3890,218 @@ EOC
531 unlink($log_file);
532 }
533
534+sub ssh2_ext_kex_strict_terrapin_issue1760 {
535+ my $self = shift;
536+ my $tmpdir = $self->{tmpdir};
537+ my $setup = test_setup($tmpdir, 'sftp');
538+
539+ my $rsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_rsa_key');
540+ my $dsa_host_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/ssh_host_dsa_key');
541+
542+ my $rsa_priv_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key');
543+ my $rsa_pub_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/test_rsa_key.pub');
544+ my $rsa_rfc4716_key = File::Spec->rel2abs('t/etc/modules/mod_sftp/authorized_rsa_keys');
545+
546+ my $authorized_keys = File::Spec->rel2abs("$tmpdir/.authorized_keys");
547+ unless (copy($rsa_rfc4716_key, $authorized_keys)) {
548+ die("Can't copy $rsa_rfc4716_key to $authorized_keys: $!");
549+ }
550+
551+ my $ssh_config = File::Spec->rel2abs("$tmpdir/ssh.conf");
552+ if (open(my $fh, "> $ssh_config")) {
553+ print $fh <<EOC;
554+HostKeyAlgorithms rsa-sha2-256
555+IdentityAgent none
556+PubkeyAcceptedKeyTypes rsa-sha2-256
557+EOC
558+ unless (close($fh)) {
559+ die("Can't write $ssh_config: $!");
560+ }
561+
562+ } else {
563+ die("Can't open $ssh_config: $!");
564+ }
565+
566+ my $batch_file = File::Spec->rel2abs("$tmpdir/sftp-batch.conf");
567+ if (open(my $fh, "> $batch_file")) {
568+ print $fh "ls -l\n";
569+
570+ unless (close($fh)) {
571+ die("Can't write $batch_file: $!");
572+ }
573+
574+ } else {
575+ die("Can't open $batch_file: $!");
576+ }
577+
578+ my $config = {
579+ PidFile => $setup->{pid_file},
580+ ScoreboardFile => $setup->{scoreboard_file},
581+ SystemLog => $setup->{log_file},
582+ TraceLog => $setup->{log_file},
583+ Trace => 'ssh2:30 sftp:20 scp:20',
584+
585+ AuthUserFile => $setup->{auth_user_file},
586+ AuthGroupFile => $setup->{auth_group_file},
587+ AuthOrder => 'mod_auth_file.c',
588+
589+ IfModules => {
590+ 'mod_delay.c' => {
591+ DelayEngine => 'off',
592+ },
593+
594+ 'mod_sftp.c' => [
595+ "SFTPEngine on",
596+ "SFTPLog $setup->{log_file}",
597+
598+ "SFTPHostKey $rsa_host_key",
599+ "SFTPHostKey $dsa_host_key",
600+
601+ "SFTPAuthorizedUserKeys file:~/.authorized_keys",
602+ ],
603+ },
604+ };
605+
606+ my ($port, $config_user, $config_group) = config_write($setup->{config_file},
607+ $config);
608+
609+ # Open pipes, for use between the parent and child processes. Specifically,
610+ # the child will indicate when it's done with its test by writing a message
611+ # to the parent.
612+ my ($rfh, $wfh);
613+ unless (pipe($rfh, $wfh)) {
614+ die("Can't open pipe: $!");
615+ }
616+
617+ require Net::SSH2;
618+
619+ my $ex;
620+
621+ # Fork child
622+ $self->handle_sigchld();
623+ defined(my $pid = fork()) or die("Can't fork: $!");
624+ if ($pid) {
625+ eval {
626+ # We use OpenSSH-9.6p1 to test our "strict KEX" Terrapin mitigations.
627+ my $sftp = '/Users/tj/local/openssh-9.6p1/bin/sftp';
628+
629+ my @cmd = (
630+ $sftp,
631+ '-F',
632+ $ssh_config,
633+ '-oBatchMode=yes',
634+ '-oCheckHostIP=no',
635+ '-oCompression=yes',
636+ "-oPort=$port",
637+ "-oIdentityFile=$rsa_priv_key",
638+ '-oPubkeyAuthentication=yes',
639+ '-oStrictHostKeyChecking=no',
640+ '-oUserKnownHostsFile=/dev/null',
641+ '-vvv',
642+ '-b',
643+ $batch_file,
644+ "$setup->{user}\@127.0.0.1",
645+ );
646+
647+ my $sftp_rh = IO::Handle->new();
648+ my $sftp_wh = IO::Handle->new();
649+ my $sftp_eh = IO::Handle->new();
650+
651+ $sftp_wh->autoflush(1);
652+
653+ sleep(1);
654+
655+ local $SIG{CHLD} = 'DEFAULT';
656+
657+ # Make sure that the perms on the priv key are what OpenSSH wants
658+ unless (chmod(0400, $rsa_priv_key)) {
659+ die("Can't set perms on $rsa_priv_key to 0400: $!");
660+ }
661+
662+ if ($ENV{TEST_VERBOSE}) {
663+ print STDERR "Executing: ", join(' ', @cmd), "\n";
664+ }
665+
666+ my $sftp_pid = open3($sftp_wh, $sftp_rh, $sftp_eh, @cmd);
667+ waitpid($sftp_pid, 0);
668+ my $exit_status = $?;
669+
670+ # Restore the perms on the priv key
671+ unless (chmod(0644, $rsa_priv_key)) {
672+ die("Can't set perms on $rsa_priv_key to 0644: $!");
673+ }
674+
675+ my ($res, $errstr);
676+ if ($exit_status >> 8 == 0) {
677+ $errstr = join('', <$sftp_eh>);
678+ $res = 0;
679+
680+ } else {
681+ $errstr = join('', <$sftp_eh>);
682+ if ($ENV{TEST_VERBOSE}) {
683+ print STDERR "Stderr: $errstr\n";
684+ }
685+
686+ $res = 1;
687+ }
688+
689+ unless ($res == 0) {
690+ die("Can't list files on server: $errstr");
691+ }
692+ };
693+ if ($@) {
694+ $ex = $@;
695+ }
696+
697+ $wfh->print("done\n");
698+ $wfh->flush();
699+
700+ } else {
701+ eval { server_wait($setup->{config_file}, $rfh) };
702+ if ($@) {
703+ warn($@);
704+ exit 1;
705+ }
706+
707+ exit 0;
708+ }
709+
710+ # Stop server
711+ server_stop($setup->{pid_file});
712+ $self->assert_child_ok($pid);
713+
714+ eval {
715+ if (open(my $fh, "< $setup->{log_file}")) {
716+ my $ok = 0;
717+
718+ while (my $line = <$fh>) {
719+ chomp($line);
720+
721+ if ($ENV{TEST_VERBOSE}) {
722+ print STDERR "# $line\n";
723+ }
724+
725+ if ($line =~ /client signaled strict KEX support/) {
726+ $ok = 1;
727+ last;
728+ }
729+ }
730+
731+ close($fh);
732+
733+ $self->assert($ok, test_msg("Did not see expected 'strict KEX' TraceLog message"));
734+
735+ } else {
736+ die("Can't read $setup->{log_file}: $!");
737+ }
738+ };
739+ if ($@) {
740+ $ex = $@;
741+ }
742+
743+ test_cleanup($setup->{log_file}, $ex);
744+}
745+
746 sub ssh2_hostkey_rsa {
747 my $self = shift;
748 my $tmpdir = $self->{tmpdir};
749--
7502.25.1
751
diff --git a/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb b/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb
index 3a0fff5599..c8097a14b0 100644
--- a/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb
+++ b/meta-networking/recipes-daemons/proftpd/proftpd_1.3.7c.bb
@@ -17,6 +17,7 @@ SRC_URI = "git://github.com/proftpd/proftpd.git;branch=${BRANCH};protocol=https
17 file://proftpd.service \ 17 file://proftpd.service \
18 file://CVE-2023-51713.patch \ 18 file://CVE-2023-51713.patch \
19 file://CVE-2024-57392.patch \ 19 file://CVE-2024-57392.patch \
20 file://CVE-2023-48795.patch \
20 " 21 "
21 22
22S = "${WORKDIR}/git" 23S = "${WORKDIR}/git"