diff options
Diffstat (limited to 'kex.c')
-rw-r--r-- | kex.c | 104 |
1 files changed, 68 insertions, 36 deletions
@@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.88 2013/01/08 18:49:04 markus Exp $ */ +/* $OpenBSD: kex.c,v 1.91 2013/05/17 00:13:13 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -62,6 +62,57 @@ extern const EVP_MD *evp_ssh_sha256(void); static void kex_kexinit_finish(Kex *); static void kex_choose_conf(Kex *); +struct kexalg { + char *name; + int type; + int ec_nid; + const EVP_MD *(*mdfunc)(void); +}; +static const struct kexalg kexalgs[] = { + { KEX_DH1, KEX_DH_GRP1_SHA1, 0, EVP_sha1 }, + { KEX_DH14, KEX_DH_GRP14_SHA1, 0, EVP_sha1 }, + { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, EVP_sha1 }, +#ifdef HAVE_EVP_SHA256 + { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, EVP_sha256 }, +#endif +#ifdef OPENSSL_HAS_ECC + { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, NID_X9_62_prime256v1, EVP_sha256 }, + { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, EVP_sha384 }, + { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, EVP_sha512 }, +#endif + { NULL, -1, -1, NULL}, +}; + +char * +kex_alg_list(void) +{ + char *ret = NULL; + size_t nlen, rlen = 0; + const struct kexalg *k; + + for (k = kexalgs; k->name != NULL; k++) { + if (ret != NULL) + ret[rlen++] = '\n'; + nlen = strlen(k->name); + ret = xrealloc(ret, 1, rlen + nlen + 2); + memcpy(ret + rlen, k->name, nlen + 1); + rlen += nlen; + } + return ret; +} + +static const struct kexalg * +kex_alg_by_name(const char *name) +{ + const struct kexalg *k; + + for (k = kexalgs; k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; + } + return NULL; +} + /* Validate KEX method name list */ int kex_names_valid(const char *names) @@ -73,20 +124,14 @@ kex_names_valid(const char *names) s = cp = xstrdup(names); for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { - if (strcmp(p, KEX_DHGEX_SHA256) != 0 && - strcmp(p, KEX_DHGEX_SHA1) != 0 && - strcmp(p, KEX_DH14) != 0 && - strcmp(p, KEX_DH1) != 0 && - (strncmp(p, KEX_ECDH_SHA2_STEM, - sizeof(KEX_ECDH_SHA2_STEM) - 1) != 0 || - kex_ecdh_name_to_nid(p) == -1)) { + if (kex_alg_by_name(p) == NULL) { error("Unsupported KEX algorithm \"%.100s\"", p); - xfree(s); + free(s); return 0; } } debug3("kex names ok: [%s]", names); - xfree(s); + free(s); return 1; } @@ -146,8 +191,8 @@ kex_prop_free(char **proposal) u_int i; for (i = 0; i < PROPOSAL_MAX; i++) - xfree(proposal[i]); - xfree(proposal); + free(proposal[i]); + free(proposal); } /* ARGSUSED */ @@ -184,7 +229,7 @@ kex_finish(Kex *kex) buffer_clear(&kex->peer); /* buffer_clear(&kex->my); */ kex->flags &= ~KEX_INIT_SENT; - xfree(kex->name); + free(kex->name); kex->name = NULL; } @@ -241,7 +286,7 @@ kex_input_kexinit(int type, u_int32_t seq, void *ctxt) for (i = 0; i < KEX_COOKIE_LEN; i++) packet_get_char(); for (i = 0; i < PROPOSAL_MAX; i++) - xfree(packet_get_string(NULL)); + free(packet_get_string(NULL)); /* * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported * KEX method has the server move first, but a server might be using @@ -348,29 +393,16 @@ choose_comp(Comp *comp, char *client, char *server) static void choose_kex(Kex *k, char *client, char *server) { + const struct kexalg *kexalg; + k->name = match_list(client, server, NULL); if (k->name == NULL) fatal("Unable to negotiate a key exchange method"); - if (strcmp(k->name, KEX_DH1) == 0) { - k->kex_type = KEX_DH_GRP1_SHA1; - k->evp_md = EVP_sha1(); - } else if (strcmp(k->name, KEX_DH14) == 0) { - k->kex_type = KEX_DH_GRP14_SHA1; - k->evp_md = EVP_sha1(); - } else if (strcmp(k->name, KEX_DHGEX_SHA1) == 0) { - k->kex_type = KEX_DH_GEX_SHA1; - k->evp_md = EVP_sha1(); -#if OPENSSL_VERSION_NUMBER >= 0x00907000L - } else if (strcmp(k->name, KEX_DHGEX_SHA256) == 0) { - k->kex_type = KEX_DH_GEX_SHA256; - k->evp_md = evp_ssh_sha256(); - } else if (strncmp(k->name, KEX_ECDH_SHA2_STEM, - sizeof(KEX_ECDH_SHA2_STEM) - 1) == 0) { - k->kex_type = KEX_ECDH_SHA2; - k->evp_md = kex_ecdh_name_to_evpmd(k->name); -#endif - } else - fatal("bad kex alg %s", k->name); + if ((kexalg = kex_alg_by_name(k->name)) == NULL) + fatal("unsupported kex alg %s", k->name); + k->kex_type = kexalg->type; + k->evp_md = kexalg->mdfunc(); + k->ec_nid = kexalg->ec_nid; } static void @@ -382,7 +414,7 @@ choose_hostkeyalg(Kex *k, char *client, char *server) k->hostkey_type = key_type_from_name(hostkeyalg); if (k->hostkey_type == KEY_UNSPEC) fatal("bad hostkey alg '%s'", hostkeyalg); - xfree(hostkeyalg); + free(hostkeyalg); } static int @@ -436,7 +468,7 @@ kex_choose_conf(Kex *kex) roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); if (roaming) { kex->roaming = 1; - xfree(roaming); + free(roaming); } } |