=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/kex.c,v retrieving revision 1.185 retrieving revision 1.186 diff -u -r1.185 -r1.186 --- src/usr.bin/ssh/kex.c 2024/01/08 00:34:33 1.185 +++ src/usr.bin/ssh/kex.c 2024/05/17 00:30:23 1.186 @@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.185 2024/01/08 00:34:33 djm Exp $ */ +/* $OpenBSD: kex.c,v 1.186 2024/05/17 00:30:23 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -76,245 +76,7 @@ "languages stoc", }; -struct kexalg { - char *name; - u_int type; - int ec_nid; - int hash_alg; -}; -static const struct kexalg kexalgs[] = { -#ifdef WITH_OPENSSL - { KEX_DH1, KEX_DH_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, - { KEX_DH14_SHA1, KEX_DH_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, - { KEX_DH14_SHA256, KEX_DH_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, - { KEX_DH16_SHA512, KEX_DH_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, - { KEX_DH18_SHA512, KEX_DH_GRP18_SHA512, 0, SSH_DIGEST_SHA512 }, - { KEX_DHGEX_SHA1, KEX_DH_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, - { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 }, - { KEX_ECDH_SHA2_NISTP256, KEX_ECDH_SHA2, - NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, - { KEX_ECDH_SHA2_NISTP384, KEX_ECDH_SHA2, NID_secp384r1, - SSH_DIGEST_SHA384 }, - { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1, - SSH_DIGEST_SHA512 }, -#endif - { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, - { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, - { KEX_SNTRUP761X25519_SHA512, KEX_KEM_SNTRUP761X25519_SHA512, 0, - SSH_DIGEST_SHA512 }, - { NULL, 0, -1, -1}, -}; - -char * -kex_alg_list(char sep) -{ - char *ret = NULL, *tmp; - size_t nlen, rlen = 0; - const struct kexalg *k; - - for (k = kexalgs; k->name != NULL; k++) { - if (ret != NULL) - ret[rlen++] = sep; - nlen = strlen(k->name); - if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { - free(ret); - return NULL; - } - ret = tmp; - 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) -{ - char *s, *cp, *p; - - if (names == NULL || strcmp(names, "") == 0) - return 0; - if ((s = cp = strdup(names)) == NULL) - return 0; - for ((p = strsep(&cp, ",")); p && *p != '\0'; - (p = strsep(&cp, ","))) { - if (kex_alg_by_name(p) == NULL) { - error("Unsupported KEX algorithm \"%.100s\"", p); - free(s); - return 0; - } - } - debug3("kex names ok: [%s]", names); - free(s); - return 1; -} - -/* returns non-zero if proposal contains any algorithm from algs */ -static int -has_any_alg(const char *proposal, const char *algs) -{ - char *cp; - - if ((cp = match_list(proposal, algs, NULL)) == NULL) - return 0; - free(cp); - return 1; -} - /* - * Concatenate algorithm names, avoiding duplicates in the process. - * Caller must free returned string. - */ -char * -kex_names_cat(const char *a, const char *b) -{ - char *ret = NULL, *tmp = NULL, *cp, *p; - size_t len; - - if (a == NULL || *a == '\0') - return strdup(b); - if (b == NULL || *b == '\0') - return strdup(a); - if (strlen(b) > 1024*1024) - return NULL; - len = strlen(a) + strlen(b) + 2; - if ((tmp = cp = strdup(b)) == NULL || - (ret = calloc(1, len)) == NULL) { - free(tmp); - return NULL; - } - strlcpy(ret, a, len); - for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { - if (has_any_alg(ret, p)) - continue; /* Algorithm already present */ - if (strlcat(ret, ",", len) >= len || - strlcat(ret, p, len) >= len) { - free(tmp); - free(ret); - return NULL; /* Shouldn't happen */ - } - } - free(tmp); - return ret; -} - -/* - * Assemble a list of algorithms from a default list and a string from a - * configuration file. The user-provided string may begin with '+' to - * indicate that it should be appended to the default, '-' that the - * specified names should be removed, or '^' that they should be placed - * at the head. - */ -int -kex_assemble_names(char **listp, const char *def, const char *all) -{ - char *cp, *tmp, *patterns; - char *list = NULL, *ret = NULL, *matching = NULL, *opatterns = NULL; - int r = SSH_ERR_INTERNAL_ERROR; - - if (listp == NULL || def == NULL || all == NULL) - return SSH_ERR_INVALID_ARGUMENT; - - if (*listp == NULL || **listp == '\0') { - if ((*listp = strdup(def)) == NULL) - return SSH_ERR_ALLOC_FAIL; - return 0; - } - - list = *listp; - *listp = NULL; - if (*list == '+') { - /* Append names to default list */ - if ((tmp = kex_names_cat(def, list + 1)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto fail; - } - free(list); - list = tmp; - } else if (*list == '-') { - /* Remove names from default list */ - if ((*listp = match_filter_denylist(def, list + 1)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto fail; - } - free(list); - /* filtering has already been done */ - return 0; - } else if (*list == '^') { - /* Place names at head of default list */ - if ((tmp = kex_names_cat(list + 1, def)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto fail; - } - free(list); - list = tmp; - } else { - /* Explicit list, overrides default - just use "list" as is */ - } - - /* - * The supplied names may be a pattern-list. For the -list case, - * the patterns are applied above. For the +list and explicit list - * cases we need to do it now. - */ - ret = NULL; - if ((patterns = opatterns = strdup(list)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto fail; - } - /* Apply positive (i.e. non-negated) patterns from the list */ - while ((cp = strsep(&patterns, ",")) != NULL) { - if (*cp == '!') { - /* negated matches are not supported here */ - r = SSH_ERR_INVALID_ARGUMENT; - goto fail; - } - free(matching); - if ((matching = match_filter_allowlist(all, cp)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto fail; - } - if ((tmp = kex_names_cat(ret, matching)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto fail; - } - free(ret); - ret = tmp; - } - if (ret == NULL || *ret == '\0') { - /* An empty name-list is an error */ - /* XXX better error code? */ - r = SSH_ERR_INVALID_ARGUMENT; - goto fail; - } - - /* success */ - *listp = ret; - ret = NULL; - r = 0; - - fail: - free(matching); - free(opatterns); - free(list); - free(ret); - return r; -} - -/* * Fill out a proposal array with dynamically allocated values, which may * be modified as required for compatibility reasons. * Any of the options may be NULL, in which case the default is used. @@ -512,11 +274,11 @@ (alg = strsep(&algs, ","))) { if ((sigalg = sshkey_sigalg_by_name(alg)) == NULL) continue; - if (!has_any_alg(sigalg, sigalgs)) + if (!kex_has_any_alg(sigalg, sigalgs)) continue; /* Don't add an algorithm twice. */ if (ssh->kex->server_sig_algs != NULL && - has_any_alg(sigalg, ssh->kex->server_sig_algs)) + kex_has_any_alg(sigalg, ssh->kex->server_sig_algs)) continue; xextendf(&ssh->kex->server_sig_algs, ",", "%s", sigalg); } @@ -1091,20 +853,18 @@ static int choose_kex(struct kex *k, char *client, char *server) { - const struct kexalg *kexalg; - k->name = match_list(client, server, NULL); debug("kex: algorithm: %s", k->name ? k->name : "(no match)"); if (k->name == NULL) return SSH_ERR_NO_KEX_ALG_MATCH; - if ((kexalg = kex_alg_by_name(k->name)) == NULL) { + if (!kex_name_valid(k->name)) { error_f("unsupported KEX method %s", k->name); return SSH_ERR_INTERNAL_ERROR; } - k->kex_type = kexalg->type; - k->hash_alg = kexalg->hash_alg; - k->ec_nid = kexalg->ec_nid; + k->kex_type = kex_type_from_name(k->name); + k->hash_alg = kex_hash_from_name(k->name); + k->ec_nid = kex_nid_from_name(k->name); return 0; } @@ -1154,7 +914,7 @@ static int kexalgs_contains(char **peer, const char *ext) { - return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext); + return kex_has_any_alg(peer[PROPOSAL_KEX_ALGS], ext); } static int @@ -1205,10 +965,10 @@ /* Check whether client supports rsa-sha2 algorithms */ if (kex->server && (kex->flags & KEX_INITIAL)) { - if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], + if (kex_has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com")) kex->flags |= KEX_RSA_SHA2_256_SUPPORTED; - if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], + if (kex_has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com")) kex->flags |= KEX_RSA_SHA2_512_SUPPORTED; }