diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | auth2-hostbased.c | 8 | ||||
-rw-r--r-- | auth2-pubkey.c | 8 | ||||
-rw-r--r-- | compat.c | 61 | ||||
-rw-r--r-- | compat.h | 3 | ||||
-rw-r--r-- | ssh-rsa.c | 23 | ||||
-rw-r--r-- | sshconnect.c | 5 | ||||
-rw-r--r-- | sshconnect2.c | 33 | ||||
-rw-r--r-- | sshd.c | 13 |
9 files changed, 109 insertions, 55 deletions
@@ -1,3 +1,13 @@ | |||
1 | 20131231 | ||
2 | - (djm) OpenBSD CVS Sync | ||
3 | - djm@cvs.openbsd.org 2013/12/30 23:52:28 | ||
4 | [auth2-hostbased.c auth2-pubkey.c compat.c compat.h ssh-rsa.c] | ||
5 | [sshconnect.c sshconnect2.c sshd.c] | ||
6 | refuse RSA keys from old proprietary clients/servers that use the | ||
7 | obsolete RSA+MD5 signature scheme. it will still be possible to connect | ||
8 | with these clients/servers but only DSA keys will be accepted, and we'll | ||
9 | deprecate them entirely in a future release. ok markus@ | ||
10 | |||
1 | 20131229 | 11 | 20131229 |
2 | - (djm) [loginrec.c] Check for username truncation when looking up lastlog | 12 | - (djm) [loginrec.c] Check for username truncation when looking up lastlog |
3 | entries | 13 | entries |
diff --git a/auth2-hostbased.c b/auth2-hostbased.c index a344dcc1f..488008f62 100644 --- a/auth2-hostbased.c +++ b/auth2-hostbased.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-hostbased.c,v 1.16 2013/06/21 00:34:49 djm Exp $ */ | 1 | /* $OpenBSD: auth2-hostbased.c,v 1.17 2013/12/30 23:52:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -100,6 +100,12 @@ userauth_hostbased(Authctxt *authctxt) | |||
100 | "(received %d, expected %d)", key->type, pktype); | 100 | "(received %d, expected %d)", key->type, pktype); |
101 | goto done; | 101 | goto done; |
102 | } | 102 | } |
103 | if (key_type_plain(key->type) == KEY_RSA && | ||
104 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { | ||
105 | error("Refusing RSA key because peer uses unsafe " | ||
106 | "signature format"); | ||
107 | goto done; | ||
108 | } | ||
103 | service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : | 109 | service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : |
104 | authctxt->service; | 110 | authctxt->service; |
105 | buffer_init(&b); | 111 | buffer_init(&b); |
diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 2b3ecb104..0fd27bb92 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth2-pubkey.c,v 1.38 2013/06/21 00:34:49 djm Exp $ */ | 1 | /* $OpenBSD: auth2-pubkey.c,v 1.39 2013/12/30 23:52:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -116,6 +116,12 @@ userauth_pubkey(Authctxt *authctxt) | |||
116 | "(received %d, expected %d)", key->type, pktype); | 116 | "(received %d, expected %d)", key->type, pktype); |
117 | goto done; | 117 | goto done; |
118 | } | 118 | } |
119 | if (key_type_plain(key->type) == KEY_RSA && | ||
120 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { | ||
121 | logit("Refusing RSA key because client uses unsafe " | ||
122 | "signature scheme"); | ||
123 | goto done; | ||
124 | } | ||
119 | if (have_sig) { | 125 | if (have_sig) { |
120 | sig = packet_get_string(&slen); | 126 | sig = packet_get_string(&slen); |
121 | packet_check_eom(); | 127 | packet_check_eom(); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: compat.c,v 1.81 2013/05/17 00:13:13 djm Exp $ */ | 1 | /* $OpenBSD: compat.c,v 1.82 2013/12/30 23:52:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -171,8 +171,9 @@ compat_datafellows(const char *version) | |||
171 | for (i = 0; check[i].pat; i++) { | 171 | for (i = 0; check[i].pat; i++) { |
172 | if (match_pattern_list(version, check[i].pat, | 172 | if (match_pattern_list(version, check[i].pat, |
173 | strlen(check[i].pat), 0) == 1) { | 173 | strlen(check[i].pat), 0) == 1) { |
174 | debug("match: %s pat %s", version, check[i].pat); | ||
175 | datafellows = check[i].bugs; | 174 | datafellows = check[i].bugs; |
175 | debug("match: %s pat %s compat 0x%08x", | ||
176 | version, check[i].pat, datafellows); | ||
176 | return; | 177 | return; |
177 | } | 178 | } |
178 | } | 179 | } |
@@ -208,33 +209,59 @@ proto_spec(const char *spec) | |||
208 | return ret; | 209 | return ret; |
209 | } | 210 | } |
210 | 211 | ||
211 | char * | 212 | /* |
212 | compat_cipher_proposal(char *cipher_prop) | 213 | * Filters a proposal string, excluding any algorithm matching the 'filter' |
214 | * pattern list. | ||
215 | */ | ||
216 | static char * | ||
217 | filter_proposal(char *proposal, const char *filter) | ||
213 | { | 218 | { |
214 | Buffer b; | 219 | Buffer b; |
215 | char *orig_prop, *fix_ciphers; | 220 | char *orig_prop, *fix_prop; |
216 | char *cp, *tmp; | 221 | char *cp, *tmp; |
217 | 222 | ||
218 | if (!(datafellows & SSH_BUG_BIGENDIANAES)) | ||
219 | return(cipher_prop); | ||
220 | |||
221 | buffer_init(&b); | 223 | buffer_init(&b); |
222 | tmp = orig_prop = xstrdup(cipher_prop); | 224 | tmp = orig_prop = xstrdup(proposal); |
223 | while ((cp = strsep(&tmp, ",")) != NULL) { | 225 | while ((cp = strsep(&tmp, ",")) != NULL) { |
224 | if (strncmp(cp, "aes", 3) != 0) { | 226 | if (match_pattern_list(cp, filter, strlen(cp), 0) != 1) { |
225 | if (buffer_len(&b) > 0) | 227 | if (buffer_len(&b) > 0) |
226 | buffer_append(&b, ",", 1); | 228 | buffer_append(&b, ",", 1); |
227 | buffer_append(&b, cp, strlen(cp)); | 229 | buffer_append(&b, cp, strlen(cp)); |
228 | } | 230 | } else |
231 | debug2("Compat: skipping algorithm \"%s\"", cp); | ||
229 | } | 232 | } |
230 | buffer_append(&b, "\0", 1); | 233 | buffer_append(&b, "\0", 1); |
231 | fix_ciphers = xstrdup(buffer_ptr(&b)); | 234 | fix_prop = xstrdup(buffer_ptr(&b)); |
232 | buffer_free(&b); | 235 | buffer_free(&b); |
233 | free(orig_prop); | 236 | free(orig_prop); |
234 | debug2("Original cipher proposal: %s", cipher_prop); | ||
235 | debug2("Compat cipher proposal: %s", fix_ciphers); | ||
236 | if (!*fix_ciphers) | ||
237 | fatal("No available ciphers found."); | ||
238 | 237 | ||
239 | return(fix_ciphers); | 238 | return fix_prop; |
240 | } | 239 | } |
240 | |||
241 | char * | ||
242 | compat_cipher_proposal(char *cipher_prop) | ||
243 | { | ||
244 | if (!(datafellows & SSH_BUG_BIGENDIANAES)) | ||
245 | return cipher_prop; | ||
246 | debug2("%s: original cipher proposal: %s", __func__, cipher_prop); | ||
247 | cipher_prop = filter_proposal(cipher_prop, "aes*"); | ||
248 | debug2("%s: compat cipher proposal: %s", __func__, cipher_prop); | ||
249 | if (*cipher_prop == '\0') | ||
250 | fatal("No supported ciphers found"); | ||
251 | return cipher_prop; | ||
252 | } | ||
253 | |||
254 | |||
255 | char * | ||
256 | compat_pkalg_proposal(char *pkalg_prop) | ||
257 | { | ||
258 | if (!(datafellows & SSH_BUG_RSASIGMD5)) | ||
259 | return pkalg_prop; | ||
260 | debug2("%s: original public key proposal: %s", __func__, pkalg_prop); | ||
261 | pkalg_prop = filter_proposal(pkalg_prop, "ssh-rsa"); | ||
262 | debug2("%s: compat public key proposal: %s", __func__, pkalg_prop); | ||
263 | if (*pkalg_prop == '\0') | ||
264 | fatal("No supported PK algorithms found"); | ||
265 | return pkalg_prop; | ||
266 | } | ||
267 | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: compat.h,v 1.43 2011/09/23 07:45:05 markus Exp $ */ | 1 | /* $OpenBSD: compat.h,v 1.44 2013/12/30 23:52:27 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved. |
@@ -65,6 +65,7 @@ void enable_compat20(void); | |||
65 | void compat_datafellows(const char *); | 65 | void compat_datafellows(const char *); |
66 | int proto_spec(const char *); | 66 | int proto_spec(const char *); |
67 | char *compat_cipher_proposal(char *); | 67 | char *compat_cipher_proposal(char *); |
68 | char *compat_pkalg_proposal(char *); | ||
68 | 69 | ||
69 | extern int compat13; | 70 | extern int compat13; |
70 | extern int compat20; | 71 | extern int compat20; |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-rsa.c,v 1.48 2013/12/27 22:37:18 djm Exp $ */ | 1 | /* $OpenBSD: ssh-rsa.c,v 1.49 2013/12/30 23:52:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> | 3 | * Copyright (c) 2000, 2003 Markus Friedl <markus@openbsd.org> |
4 | * | 4 | * |
@@ -53,7 +53,7 @@ ssh_rsa_sign(const Key *key, u_char **sigp, u_int *lenp, | |||
53 | return -1; | 53 | return -1; |
54 | } | 54 | } |
55 | 55 | ||
56 | nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; | 56 | nid = NID_sha1; |
57 | if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { | 57 | if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { |
58 | error("%s: EVP_get_digestbynid %d failed", __func__, nid); | 58 | error("%s: EVP_get_digestbynid %d failed", __func__, nid); |
59 | return -1; | 59 | return -1; |
@@ -161,7 +161,7 @@ ssh_rsa_verify(const Key *key, const u_char *signature, u_int signaturelen, | |||
161 | memset(sigblob, 0, diff); | 161 | memset(sigblob, 0, diff); |
162 | len = modlen; | 162 | len = modlen; |
163 | } | 163 | } |
164 | nid = (datafellows & SSH_BUG_RSASIGMD5) ? NID_md5 : NID_sha1; | 164 | nid = NID_sha1; |
165 | if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { | 165 | if ((evp_md = EVP_get_digestbynid(nid)) == NULL) { |
166 | error("%s: EVP_get_digestbynid %d failed", __func__, nid); | 166 | error("%s: EVP_get_digestbynid %d failed", __func__, nid); |
167 | free(sigblob); | 167 | free(sigblob); |
@@ -196,18 +196,6 @@ static const u_char id_sha1[] = { | |||
196 | 0x05, 0x00, /* NULL */ | 196 | 0x05, 0x00, /* NULL */ |
197 | 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ | 197 | 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ |
198 | }; | 198 | }; |
199 | /* | ||
200 | * id-md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) | ||
201 | * rsadsi(113549) digestAlgorithm(2) 5 } | ||
202 | */ | ||
203 | static const u_char id_md5[] = { | ||
204 | 0x30, 0x20, /* type Sequence, length 0x20 (32) */ | ||
205 | 0x30, 0x0c, /* type Sequence, length 0x0c (12) */ | ||
206 | 0x06, 0x08, /* type OID, length 0x08 */ | ||
207 | 0x2a, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* id-md5 */ | ||
208 | 0x05, 0x00, /* NULL */ | ||
209 | 0x04, 0x10 /* Octet string, length 0x10 (16), followed by md5 hash */ | ||
210 | }; | ||
211 | 199 | ||
212 | static int | 200 | static int |
213 | openssh_RSA_verify(int type, u_char *hash, u_int hashlen, | 201 | openssh_RSA_verify(int type, u_char *hash, u_int hashlen, |
@@ -225,11 +213,6 @@ openssh_RSA_verify(int type, u_char *hash, u_int hashlen, | |||
225 | oidlen = sizeof(id_sha1); | 213 | oidlen = sizeof(id_sha1); |
226 | hlen = 20; | 214 | hlen = 20; |
227 | break; | 215 | break; |
228 | case NID_md5: | ||
229 | oid = id_md5; | ||
230 | oidlen = sizeof(id_md5); | ||
231 | hlen = 16; | ||
232 | break; | ||
233 | default: | 216 | default: |
234 | goto done; | 217 | goto done; |
235 | } | 218 | } |
diff --git a/sshconnect.c b/sshconnect.c index b492ce915..791b31c12 100644 --- a/sshconnect.c +++ b/sshconnect.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect.c,v 1.242 2013/12/29 05:57:02 djm Exp $ */ | 1 | /* $OpenBSD: sshconnect.c,v 1.243 2013/12/30 23:52:27 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -662,6 +662,9 @@ ssh_exchange_identification(int timeout_ms) | |||
662 | fatal("Protocol major versions differ: %d vs. %d", | 662 | fatal("Protocol major versions differ: %d vs. %d", |
663 | (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, | 663 | (options.protocol & SSH_PROTO_2) ? PROTOCOL_MAJOR_2 : PROTOCOL_MAJOR_1, |
664 | remote_major); | 664 | remote_major); |
665 | if ((datafellows & SSH_BUG_RSASIGMD5) != 0) | ||
666 | logit("Server version \"%.100s\" uses unsafe RSA signature " | ||
667 | "scheme; disabling use of RSA keys", remote_version); | ||
665 | if (!client_banner_sent) | 668 | if (!client_banner_sent) |
666 | send_client_banner(connection_out, minor1); | 669 | send_client_banner(connection_out, minor1); |
667 | chop(server_version_string); | 670 | chop(server_version_string); |
diff --git a/sshconnect2.c b/sshconnect2.c index 1f6160e86..0d339b9c5 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.199 2013/11/02 21:59:15 markus Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.200 2013/12/30 23:52:28 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -188,11 +188,12 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
188 | } | 188 | } |
189 | if (options.hostkeyalgorithms != NULL) | 189 | if (options.hostkeyalgorithms != NULL) |
190 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = | 190 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
191 | options.hostkeyalgorithms; | 191 | compat_pkalg_proposal(options.hostkeyalgorithms); |
192 | else { | 192 | else { |
193 | /* Prefer algorithms that we already have keys for */ | 193 | /* Prefer algorithms that we already have keys for */ |
194 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = | 194 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = |
195 | order_hostkeyalgs(host, hostaddr, port); | 195 | compat_pkalg_proposal( |
196 | order_hostkeyalgs(host, hostaddr, port)); | ||
196 | } | 197 | } |
197 | if (options.kex_algorithms != NULL) | 198 | if (options.kex_algorithms != NULL) |
198 | myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; | 199 | myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms; |
@@ -1489,17 +1490,31 @@ userauth_pubkey(Authctxt *authctxt) | |||
1489 | * encrypted keys we cannot do this and have to load the | 1490 | * encrypted keys we cannot do this and have to load the |
1490 | * private key instead | 1491 | * private key instead |
1491 | */ | 1492 | */ |
1492 | if (id->key && id->key->type != KEY_RSA1) { | 1493 | if (id->key != NULL) { |
1493 | debug("Offering %s public key: %s", key_type(id->key), | 1494 | if (key_type_plain(id->key->type) == KEY_RSA && |
1494 | id->filename); | 1495 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { |
1495 | sent = send_pubkey_test(authctxt, id); | 1496 | debug("Skipped %s key %s for RSA/MD5 server", |
1496 | } else if (id->key == NULL) { | 1497 | key_type(id->key), id->filename); |
1498 | } else if (id->key->type != KEY_RSA1) { | ||
1499 | debug("Offering %s public key: %s", | ||
1500 | key_type(id->key), id->filename); | ||
1501 | sent = send_pubkey_test(authctxt, id); | ||
1502 | } | ||
1503 | } else { | ||
1497 | debug("Trying private key: %s", id->filename); | 1504 | debug("Trying private key: %s", id->filename); |
1498 | id->key = load_identity_file(id->filename, | 1505 | id->key = load_identity_file(id->filename, |
1499 | id->userprovided); | 1506 | id->userprovided); |
1500 | if (id->key != NULL) { | 1507 | if (id->key != NULL) { |
1501 | id->isprivate = 1; | 1508 | id->isprivate = 1; |
1502 | sent = sign_and_send_pubkey(authctxt, id); | 1509 | if (key_type_plain(id->key->type) == KEY_RSA && |
1510 | (datafellows & SSH_BUG_RSASIGMD5) != 0) { | ||
1511 | debug("Skipped %s key %s for RSA/MD5 " | ||
1512 | "server", key_type(id->key), | ||
1513 | id->filename); | ||
1514 | } else { | ||
1515 | sent = sign_and_send_pubkey( | ||
1516 | authctxt, id); | ||
1517 | } | ||
1503 | key_free(id->key); | 1518 | key_free(id->key); |
1504 | id->key = NULL; | 1519 | id->key = NULL; |
1505 | } | 1520 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.412 2013/12/06 13:39:49 markus Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.413 2013/12/30 23:52:28 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -492,17 +492,19 @@ sshd_exchange_identification(int sock_in, int sock_out) | |||
492 | 492 | ||
493 | compat_datafellows(remote_version); | 493 | compat_datafellows(remote_version); |
494 | 494 | ||
495 | if (datafellows & SSH_BUG_PROBE) { | 495 | if ((datafellows & SSH_BUG_PROBE) != 0) { |
496 | logit("probed from %s with %s. Don't panic.", | 496 | logit("probed from %s with %s. Don't panic.", |
497 | get_remote_ipaddr(), client_version_string); | 497 | get_remote_ipaddr(), client_version_string); |
498 | cleanup_exit(255); | 498 | cleanup_exit(255); |
499 | } | 499 | } |
500 | 500 | if ((datafellows & SSH_BUG_SCANNER) != 0) { | |
501 | if (datafellows & SSH_BUG_SCANNER) { | ||
502 | logit("scanned from %s with %s. Don't panic.", | 501 | logit("scanned from %s with %s. Don't panic.", |
503 | get_remote_ipaddr(), client_version_string); | 502 | get_remote_ipaddr(), client_version_string); |
504 | cleanup_exit(255); | 503 | cleanup_exit(255); |
505 | } | 504 | } |
505 | if ((datafellows & SSH_BUG_RSASIGMD5) != 0) | ||
506 | logit("Client version \"%.100s\" uses unsafe RSA signature " | ||
507 | "scheme; disabling use of RSA keys", remote_version); | ||
506 | 508 | ||
507 | mismatch = 0; | 509 | mismatch = 0; |
508 | switch (remote_major) { | 510 | switch (remote_major) { |
@@ -2446,7 +2448,8 @@ do_ssh2_kex(void) | |||
2446 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, | 2448 | packet_set_rekey_limits((u_int32_t)options.rekey_limit, |
2447 | (time_t)options.rekey_interval); | 2449 | (time_t)options.rekey_interval); |
2448 | 2450 | ||
2449 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); | 2451 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( |
2452 | list_hostkey_types()); | ||
2450 | 2453 | ||
2451 | /* start key exchange */ | 2454 | /* start key exchange */ |
2452 | kex = kex_setup(myproposal); | 2455 | kex = kex_setup(myproposal); |