diff options
Diffstat (limited to 'kex.c')
-rw-r--r-- | kex.c | 130 |
1 files changed, 80 insertions, 50 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.c,v 1.88 2013/01/08 18:49:04 markus Exp $ */ | 1 | /* $OpenBSD: kex.c,v 1.91 2013/05/17 00:13:13 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -66,6 +66,69 @@ extern const EVP_MD *evp_ssh_sha256(void); | |||
66 | static void kex_kexinit_finish(Kex *); | 66 | static void kex_kexinit_finish(Kex *); |
67 | static void kex_choose_conf(Kex *); | 67 | static void kex_choose_conf(Kex *); |
68 | 68 | ||
69 | struct kexalg { | ||
70 | char *name; | ||
71 | int type; | ||
72 | int ec_nid; | ||
73 | const EVP_MD *(*mdfunc)(void); | ||
74 | }; | ||
75 | static const struct kexalg kexalgs[] = { | ||
76 | { KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 }, | ||
77 | { KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 }, | ||
78 | { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 }, | ||
79 | #ifdef HAVE_EVP_SHA256 | ||
80 | { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 }, | ||
81 | #endif | ||
82 | #ifdef OPENSSL_HAS_ECC | ||
83 | { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 }, | ||
84 | { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 }, | ||
85 | { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 }, | ||
86 | #endif | ||
87 | { NULL, -1, -1, NULL}, | ||
88 | }; | ||
89 | static const struct kexalg kexalg_prefixes[] = { | ||
90 | #ifdef GSSAPI | ||
91 | { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, EVP_sha1 }, | ||
92 | { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, EVP_sha1 }, | ||
93 | { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, EVP_sha1 }, | ||
94 | #endif | ||
95 | { NULL, -1, -1, NULL }, | ||
96 | }; | ||
97 | |||
98 | char * | ||
99 | kex_alg_list(void) | ||
100 | { | ||
101 | char *ret = NULL; | ||
102 | size_t nlen, rlen = 0; | ||
103 | const struct kexalg *k; | ||
104 | |||
105 | for (k = kexalgs; k->name != NULL; k++) { | ||
106 | if (ret != NULL) | ||
107 | ret[rlen++] = '\n'; | ||
108 | nlen = strlen(k->name); | ||
109 | ret = xrealloc(ret, 1, rlen + nlen + 2); | ||
110 | memcpy(ret + rlen, k->name, nlen + 1); | ||
111 | rlen += nlen; | ||
112 | } | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | static const struct kexalg * | ||
117 | kex_alg_by_name(const char *name) | ||
118 | { | ||
119 | const struct kexalg *k; | ||
120 | |||
121 | for (k = kexalgs; k->name != NULL; k++) { | ||
122 | if (strcmp(k->name, name) == 0) | ||
123 | return k; | ||
124 | } | ||
125 | for (k = kexalg_prefixes; k->name != NULL; k++) { | ||
126 | if (strncmp(k->name, name, strlen(k->name)) == 0) | ||
127 | return k; | ||
128 | } | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
69 | /* Validate KEX method name list */ | 132 | /* Validate KEX method name list */ |
70 | int | 133 | int |
71 | kex_names_valid(const char *names) | 134 | kex_names_valid(const char *names) |
@@ -77,20 +140,14 @@ kex_names_valid(const char *names) | |||
77 | s = cp = xstrdup(names); | 140 | s = cp = xstrdup(names); |
78 | for ((p = strsep(&cp, ",")); p && *p != '\0'; | 141 | for ((p = strsep(&cp, ",")); p && *p != '\0'; |
79 | (p = strsep(&cp, ","))) { | 142 | (p = strsep(&cp, ","))) { |
80 | if (strcmp(p, KEX_DHGEX_SHA256) != 0 && | 143 | if (kex_alg_by_name(p) == NULL) { |
81 | strcmp(p, KEX_DHGEX_SHA1) != 0 && | ||
82 | strcmp(p, KEX_DH14) != 0 && | ||
83 | strcmp(p, KEX_DH1) != 0 && | ||
84 | (strncmp(p, KEX_ECDH_SHA2_STEM, | ||
85 | sizeof(KEX_ECDH_SHA2_STEM) - 1) != 0 || | ||
86 | kex_ecdh_name_to_nid(p) == -1)) { | ||
87 | error("Unsupported KEX algorithm \"%.100s\"", p); | 144 | error("Unsupported KEX algorithm \"%.100s\"", p); |
88 | xfree(s); | 145 | free(s); |
89 | return 0; | 146 | return 0; |
90 | } | 147 | } |
91 | } | 148 | } |
92 | debug3("kex names ok: [%s]", names); | 149 | debug3("kex names ok: [%s]", names); |
93 | xfree(s); | 150 | free(s); |
94 | return 1; | 151 | return 1; |
95 | } | 152 | } |
96 | 153 | ||
@@ -150,8 +207,8 @@ kex_prop_free(char **proposal) | |||
150 | u_int i; | 207 | u_int i; |
151 | 208 | ||
152 | for (i = 0; i < PROPOSAL_MAX; i++) | 209 | for (i = 0; i < PROPOSAL_MAX; i++) |
153 | xfree(proposal[i]); | 210 | free(proposal[i]); |
154 | xfree(proposal); | 211 | free(proposal); |
155 | } | 212 | } |
156 | 213 | ||
157 | /* ARGSUSED */ | 214 | /* ARGSUSED */ |
@@ -188,7 +245,7 @@ kex_finish(Kex *kex) | |||
188 | buffer_clear(&kex->peer); | 245 | buffer_clear(&kex->peer); |
189 | /* buffer_clear(&kex->my); */ | 246 | /* buffer_clear(&kex->my); */ |
190 | kex->flags &= ~KEX_INIT_SENT; | 247 | kex->flags &= ~KEX_INIT_SENT; |
191 | xfree(kex->name); | 248 | free(kex->name); |
192 | kex->name = NULL; | 249 | kex->name = NULL; |
193 | } | 250 | } |
194 | 251 | ||
@@ -245,7 +302,7 @@ kex_input_kexinit(int type, u_int32_t seq, void *ctxt) | |||
245 | for (i = 0; i < KEX_COOKIE_LEN; i++) | 302 | for (i = 0; i < KEX_COOKIE_LEN; i++) |
246 | packet_get_char(); | 303 | packet_get_char(); |
247 | for (i = 0; i < PROPOSAL_MAX; i++) | 304 | for (i = 0; i < PROPOSAL_MAX; i++) |
248 | xfree(packet_get_string(NULL)); | 305 | free(packet_get_string(NULL)); |
249 | /* | 306 | /* |
250 | * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported | 307 | * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported |
251 | * KEX method has the server move first, but a server might be using | 308 | * KEX method has the server move first, but a server might be using |
@@ -352,43 +409,16 @@ choose_comp(Comp *comp, char *client, char *server) | |||
352 | static void | 409 | static void |
353 | choose_kex(Kex *k, char *client, char *server) | 410 | choose_kex(Kex *k, char *client, char *server) |
354 | { | 411 | { |
412 | const struct kexalg *kexalg; | ||
413 | |||
355 | k->name = match_list(client, server, NULL); | 414 | k->name = match_list(client, server, NULL); |
356 | if (k->name == NULL) | 415 | if (k->name == NULL) |
357 | fatal("Unable to negotiate a key exchange method"); | 416 | fatal("Unable to negotiate a key exchange method"); |
358 | if (strcmp(k->name, KEX_DH1) == 0) { | 417 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) |
359 | k->kex_type = KEX_DH_GRP1_SHA1; | 418 | fatal("unsupported kex alg %s", k->name); |
360 | k->evp_md = EVP_sha1(); | 419 | k->kex_type = kexalg->type; |
361 | } else if (strcmp(k->name, KEX_DH14) == 0) { | 420 | k->evp_md = kexalg->mdfunc(); |
362 | k->kex_type = KEX_DH_GRP14_SHA1; | 421 | k->ec_nid = kexalg->ec_nid; |
363 | k->evp_md = EVP_sha1(); | ||
364 | } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { | ||
365 | k->kex_type = KEX_DH_GEX_SHA1; | ||
366 | k->evp_md = EVP_sha1(); | ||
367 | #if OPENSSL_VERSION_NUMBER >= 0x00907000L | ||
368 | } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { | ||
369 | k->kex_type = KEX_DH_GEX_SHA256; | ||
370 | k->evp_md = evp_ssh_sha256(); | ||
371 | } else if (strncmp(k->name, KEX_ECDH_SHA2_STEM, | ||
372 | sizeof(KEX_ECDH_SHA2_STEM) - 1) == 0) { | ||
373 | k->kex_type = KEX_ECDH_SHA2; | ||
374 | k->evp_md = kex_ecdh_name_to_evpmd(k->name); | ||
375 | #endif | ||
376 | #ifdef GSSAPI | ||
377 | } else if (strncmp(k->name, KEX_GSS_GEX_SHA1_ID, | ||
378 | sizeof(KEX_GSS_GEX_SHA1_ID) - 1) == 0) { | ||
379 | k->kex_type = KEX_GSS_GEX_SHA1; | ||
380 | k->evp_md = EVP_sha1(); | ||
381 | } else if (strncmp(k->name, KEX_GSS_GRP1_SHA1_ID, | ||
382 | sizeof(KEX_GSS_GRP1_SHA1_ID) - 1) == 0) { | ||
383 | k->kex_type = KEX_GSS_GRP1_SHA1; | ||
384 | k->evp_md = EVP_sha1(); | ||
385 | } else if (strncmp(k->name, KEX_GSS_GRP14_SHA1_ID, | ||
386 | sizeof(KEX_GSS_GRP14_SHA1_ID) - 1) == 0) { | ||
387 | k->kex_type = KEX_GSS_GRP14_SHA1; | ||
388 | k->evp_md = EVP_sha1(); | ||
389 | #endif | ||
390 | } else | ||
391 | fatal("bad kex alg %s", k->name); | ||
392 | } | 422 | } |
393 | 423 | ||
394 | static void | 424 | static void |
@@ -400,7 +430,7 @@ choose_hostkeyalg(Kex *k, char *client, char *server) | |||
400 | k->hostkey_type = key_type_from_name(hostkeyalg); | 430 | k->hostkey_type = key_type_from_name(hostkeyalg); |
401 | if (k->hostkey_type == KEY_UNSPEC) | 431 | if (k->hostkey_type == KEY_UNSPEC) |
402 | fatal("bad hostkey alg '%s'", hostkeyalg); | 432 | fatal("bad hostkey alg '%s'", hostkeyalg); |
403 | xfree(hostkeyalg); | 433 | free(hostkeyalg); |
404 | } | 434 | } |
405 | 435 | ||
406 | static int | 436 | static int |
@@ -454,7 +484,7 @@ kex_choose_conf(Kex *kex) | |||
454 | roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); | 484 | roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); |
455 | if (roaming) { | 485 | if (roaming) { |
456 | kex->roaming = 1; | 486 | kex->roaming = 1; |
457 | xfree(roaming); | 487 | free(roaming); |
458 | } | 488 | } |
459 | } | 489 | } |
460 | 490 | ||