summaryrefslogtreecommitdiffstats
path: root/kex.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2024-05-17 00:30:23 +0000
committerDamien Miller <djm@mindrot.org>2024-05-17 14:41:35 +1000
commit03e3de416ed7c34faeb692967737be4a7bbe2eb5 (patch)
tree6794217dbc0a1369e9d6e1b0a9f40534596a6648 /kex.c
parent1c0d81357921f8d3bab06841df649edac515ae5b (diff)
upstream: Start the process of splitting sshd into separate
binaries. This step splits sshd into a listener and a session binary. More splits are planned. After this changes, the listener binary will validate the configuration, load the hostkeys, listen on port 22 and manage MaxStartups only. All session handling will be performed by a new sshd-session binary that the listener fork+execs. This reduces the listener process to the minimum necessary and sets us up for future work on the sshd-session binary. feedback/ok markus@ deraadt@ NB. if you're updating via source, please restart sshd after installing, otherwise you run the risk of locking yourself out. OpenBSD-Commit-ID: 43c04a1ab96cdbdeb53d2df0125a6d42c5f19934
Diffstat (limited to 'kex.c')
-rw-r--r--kex.c270
1 files changed, 10 insertions, 260 deletions
diff --git a/kex.c b/kex.c
index 8a0f1651..63aae5d7 100644
--- a/kex.c
+++ b/kex.c
@@ -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.
*
@@ -81,254 +81,6 @@ static const char * const proposal_names[PROPOSAL_MAX] = {
"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 },
-#ifdef HAVE_EVP_SHA256
- { KEX_DHGEX_SHA256, KEX_DH_GEX_SHA256, 0, SSH_DIGEST_SHA256 },
-#endif /* HAVE_EVP_SHA256 */
-#ifdef OPENSSL_HAS_ECC
- { 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 },
-# ifdef OPENSSL_HAS_NISTP521
- { KEX_ECDH_SHA2_NISTP521, KEX_ECDH_SHA2, NID_secp521r1,
- SSH_DIGEST_SHA512 },
-# endif /* OPENSSL_HAS_NISTP521 */
-#endif /* OPENSSL_HAS_ECC */
-#endif /* WITH_OPENSSL */
-#if defined(HAVE_EVP_SHA256) || !defined(WITH_OPENSSL)
- { KEX_CURVE25519_SHA256, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
- { KEX_CURVE25519_SHA256_OLD, KEX_C25519_SHA256, 0, SSH_DIGEST_SHA256 },
-#ifdef USE_SNTRUP761X25519
- { KEX_SNTRUP761X25519_SHA512, KEX_KEM_SNTRUP761X25519_SHA512, 0,
- SSH_DIGEST_SHA512 },
-#endif
-#endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */
- { 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.
@@ -527,11 +279,11 @@ kex_set_server_sig_algs(struct ssh *ssh, const char *allowed_algs)
(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);
}
@@ -1108,20 +860,18 @@ choose_comp(struct sshcomp *comp, char *client, char *server)
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;
}
@@ -1171,7 +921,7 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
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
@@ -1222,10 +972,10 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq)
/* 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;
}