021-Implement-Strict-KEX-mode.patch 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. From 6e43be5c7b99dbee49dc72b6f989f29fdd7e9356 Mon Sep 17 00:00:00 2001
  2. From: Matt Johnston <[email protected]>
  3. Date: Mon, 20 Nov 2023 14:02:47 +0800
  4. Subject: Implement Strict KEX mode
  5. As specified by OpenSSH with [email protected] and
  6. [email protected].
  7. ---
  8. cli-session.c | 11 +++++++++++
  9. common-algo.c | 6 ++++++
  10. common-kex.c | 26 +++++++++++++++++++++++++-
  11. kex.h | 3 +++
  12. process-packet.c | 34 +++++++++++++++++++---------------
  13. ssh.h | 4 ++++
  14. svr-session.c | 3 +++
  15. 7 files changed, 71 insertions(+), 16 deletions(-)
  16. --- a/cli-session.c
  17. +++ b/cli-session.c
  18. @@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NO
  19. static void recv_msg_service_accept(void);
  20. static void cli_session_cleanup(void);
  21. static void recv_msg_global_request_cli(void);
  22. +static void cli_algos_initialise(void);
  23. struct clientsession cli_ses; /* GLOBAL */
  24. @@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o
  25. }
  26. chaninitialise(cli_chantypes);
  27. + cli_algos_initialise();
  28. /* Set up cli_ses vars */
  29. cli_session_init(proxy_cmd_pid);
  30. @@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, cons
  31. fflush(stderr);
  32. }
  33. +static void cli_algos_initialise(void) {
  34. + algo_type *algo;
  35. + for (algo = sshkex; algo->name; algo++) {
  36. + if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) {
  37. + algo->usable = 0;
  38. + }
  39. + }
  40. +}
  41. +
  42. --- a/common-algo.c
  43. +++ b/common-algo.c
  44. @@ -308,6 +308,12 @@ algo_type sshkex[] = {
  45. {SSH_EXT_INFO_C, 0, NULL, 1, NULL},
  46. #endif
  47. #endif
  48. +#if DROPBEAR_CLIENT
  49. + {SSH_STRICT_KEX_C, 0, NULL, 1, NULL},
  50. +#endif
  51. +#if DROPBEAR_SERVER
  52. + {SSH_STRICT_KEX_S, 0, NULL, 1, NULL},
  53. +#endif
  54. {NULL, 0, NULL, 0, NULL}
  55. };
  56. --- a/common-kex.c
  57. +++ b/common-kex.c
  58. @@ -183,6 +183,10 @@ void send_msg_newkeys() {
  59. gen_new_keys();
  60. switch_keys();
  61. + if (ses.kexstate.strict_kex) {
  62. + ses.transseq = 0;
  63. + }
  64. +
  65. TRACE(("leave send_msg_newkeys"))
  66. }
  67. @@ -193,7 +197,11 @@ void recv_msg_newkeys() {
  68. ses.kexstate.recvnewkeys = 1;
  69. switch_keys();
  70. -
  71. +
  72. + if (ses.kexstate.strict_kex) {
  73. + ses.recvseq = 0;
  74. + }
  75. +
  76. TRACE(("leave recv_msg_newkeys"))
  77. }
  78. @@ -550,6 +558,10 @@ void recv_msg_kexinit() {
  79. ses.kexstate.recvkexinit = 1;
  80. + if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) {
  81. + dropbear_exit("First packet wasn't kexinit");
  82. + }
  83. +
  84. TRACE(("leave recv_msg_kexinit"))
  85. }
  86. @@ -859,6 +871,18 @@ static void read_kex_algos() {
  87. }
  88. #endif
  89. + if (!ses.kexstate.donefirstkex) {
  90. + const char* strict_name;
  91. + if (IS_DROPBEAR_CLIENT) {
  92. + strict_name = SSH_STRICT_KEX_S;
  93. + } else {
  94. + strict_name = SSH_STRICT_KEX_C;
  95. + }
  96. + if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) {
  97. + ses.kexstate.strict_kex = 1;
  98. + }
  99. + }
  100. +
  101. algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
  102. allgood &= goodguess;
  103. if (algo == NULL || algo->data == NULL) {
  104. --- a/kex.h
  105. +++ b/kex.h
  106. @@ -83,6 +83,9 @@ struct KEXState {
  107. unsigned our_first_follows_matches : 1;
  108. + /* Boolean indicating that strict kex mode is in use */
  109. + unsigned int strict_kex;
  110. +
  111. time_t lastkextime; /* time of the last kex */
  112. unsigned int datatrans; /* data transmitted since last kex */
  113. unsigned int datarecv; /* data received since last kex */
  114. --- a/process-packet.c
  115. +++ b/process-packet.c
  116. @@ -44,6 +44,7 @@ void process_packet() {
  117. unsigned char type;
  118. unsigned int i;
  119. + unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex;
  120. time_t now;
  121. TRACE2(("enter process_packet"))
  122. @@ -54,22 +55,24 @@ void process_packet() {
  123. now = monotonic_now();
  124. ses.last_packet_time_keepalive_recv = now;
  125. - /* These packets we can receive at any time */
  126. - switch(type) {
  127. - case SSH_MSG_IGNORE:
  128. - goto out;
  129. - case SSH_MSG_DEBUG:
  130. - goto out;
  131. -
  132. - case SSH_MSG_UNIMPLEMENTED:
  133. - /* debugging XXX */
  134. - TRACE(("SSH_MSG_UNIMPLEMENTED"))
  135. - goto out;
  136. -
  137. - case SSH_MSG_DISCONNECT:
  138. - /* TODO cleanup? */
  139. - dropbear_close("Disconnect received");
  140. + if (type == SSH_MSG_DISCONNECT) {
  141. + /* Allowed at any time */
  142. + dropbear_close("Disconnect received");
  143. + }
  144. +
  145. + /* These packets may be received at any time,
  146. + except during first kex with strict kex */
  147. + if (!first_strict_kex) {
  148. + switch(type) {
  149. + case SSH_MSG_IGNORE:
  150. + goto out;
  151. + case SSH_MSG_DEBUG:
  152. + goto out;
  153. + case SSH_MSG_UNIMPLEMENTED:
  154. + TRACE(("SSH_MSG_UNIMPLEMENTED"))
  155. + goto out;
  156. + }
  157. }
  158. /* Ignore these packet types so that keepalives don't interfere with
  159. @@ -98,7 +101,8 @@ void process_packet() {
  160. if (type >= 1 && type <= 49
  161. && type != SSH_MSG_SERVICE_REQUEST
  162. && type != SSH_MSG_SERVICE_ACCEPT
  163. - && type != SSH_MSG_KEXINIT)
  164. + && type != SSH_MSG_KEXINIT
  165. + && !first_strict_kex)
  166. {
  167. TRACE(("unknown allowed packet during kexinit"))
  168. recv_unimplemented();
  169. --- a/ssh.h
  170. +++ b/ssh.h
  171. @@ -100,6 +100,10 @@
  172. #define SSH_EXT_INFO_C "ext-info-c"
  173. #define SSH_SERVER_SIG_ALGS "server-sig-algs"
  174. +/* OpenSSH strict KEX feature */
  175. +#define SSH_STRICT_KEX_S "[email protected]"
  176. +#define SSH_STRICT_KEX_C "[email protected]"
  177. +
  178. /* service types */
  179. #define SSH_SERVICE_USERAUTH "ssh-userauth"
  180. #define SSH_SERVICE_USERAUTH_LEN 12
  181. --- a/svr-session.c
  182. +++ b/svr-session.c
  183. @@ -370,6 +370,9 @@ static void svr_algos_initialise(void) {
  184. algo->usable = 0;
  185. }
  186. #endif
  187. + if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) {
  188. + algo->usable = 0;
  189. + }
  190. }
  191. }