diff options
author | Ed Maste <emaste@FreeBSD.org> | 2021-02-14 21:00:25 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2021-02-14 21:00:25 +0000 |
commit | 0194e6d04277a638afac6c4a664d3bc6a0d944eb (patch) | |
tree | e97a6dcafc6763aea7c804e4e113c2750cb1400d /kex.c | |
parent | f02e39982452024dafcf0ea6e536ebff586ffce4 (diff) |
Vendor import of OpenSSH 8.1p1vendor/openssh/8.1p1
Diffstat (limited to 'kex.c')
-rw-r--r-- | kex.c | 105 |
1 files changed, 79 insertions, 26 deletions
@@ -1,4 +1,4 @@ -/* $OpenBSD: kex.c,v 1.150 2019/01/21 12:08:13 djm Exp $ */ +/* $OpenBSD: kex.c,v 1.155 2019/10/08 22:40:39 dtucker Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * @@ -111,7 +111,7 @@ static const struct kexalg kexalgs[] = { { KEX_SNTRUP4591761X25519_SHA512, KEX_KEM_SNTRUP4591761X25519_SHA512, 0, SSH_DIGEST_SHA512 }, #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ - { NULL, -1, -1, -1}, + { NULL, 0, -1, -1}, }; char * @@ -213,8 +213,9 @@ kex_names_cat(const char *a, const char *b) /* * 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 or '-' that the - * specified names should be removed. + * 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) @@ -223,7 +224,10 @@ kex_assemble_names(char **listp, const char *def, const char *all) char *list = NULL, *ret = NULL, *matching = NULL, *opatterns = NULL; int r = SSH_ERR_INTERNAL_ERROR; - if (listp == NULL || *listp == NULL || **listp == '\0') { + 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; @@ -248,6 +252,14 @@ kex_assemble_names(char **listp, const char *def, const char *all) 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 */ } @@ -345,18 +357,25 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) r = SSH_ERR_ALLOC_FAIL; goto out; } - if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ + if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) { /* skip cookie */ + error("%s: consume cookie: %s", __func__, ssh_err(r)); goto out; + } /* extract kex init proposal strings */ for (i = 0; i < PROPOSAL_MAX; i++) { - if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) + if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) { + error("%s: parse proposal %u: %s", __func__, + i, ssh_err(r)); goto out; + } debug2("%s: %s", proposal_names[i], proposal[i]); } /* first kex follows / reserved */ if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */ - (r = sshbuf_get_u32(b, &i)) != 0) /* reserved */ + (r = sshbuf_get_u32(b, &i)) != 0) { /* reserved */ + error("%s: parse: %s", __func__, ssh_err(r)); goto out; + } if (first_kex_follows != NULL) *first_kex_follows = v; debug2("first_kex_follows %d ", v); @@ -409,6 +428,7 @@ kex_send_ext_info(struct ssh *ssh) int r; char *algs; + debug("Sending SSH2_MSG_EXT_INFO"); if ((algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) return SSH_ERR_ALLOC_FAIL; /* XXX filter algs list by allowed pubkey/hostbased types */ @@ -416,8 +436,10 @@ kex_send_ext_info(struct ssh *ssh) (r = sshpkt_put_u32(ssh, 1)) != 0 || (r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 || (r = sshpkt_put_cstring(ssh, algs)) != 0 || - (r = sshpkt_send(ssh)) != 0) + (r = sshpkt_send(ssh)) != 0) { + error("%s: compose: %s", __func__, ssh_err(r)); goto out; + } /* success */ r = 0; out: @@ -435,11 +457,11 @@ kex_send_newkeys(struct ssh *ssh) (r = sshpkt_send(ssh)) != 0) return r; debug("SSH2_MSG_NEWKEYS sent"); - debug("expecting SSH2_MSG_NEWKEYS"); ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); - if (ssh->kex->ext_info_c) + if (ssh->kex->ext_info_c && (ssh->kex->flags & KEX_INITIAL) != 0) if ((r = kex_send_ext_info(ssh)) != 0) return r; + debug("expecting SSH2_MSG_NEWKEYS"); return 0; } @@ -511,23 +533,32 @@ kex_send_kexinit(struct ssh *ssh) struct kex *kex = ssh->kex; int r; - if (kex == NULL) + if (kex == NULL) { + error("%s: no hex", __func__); return SSH_ERR_INTERNAL_ERROR; + } if (kex->flags & KEX_INIT_SENT) return 0; kex->done = 0; /* generate a random cookie */ - if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) + if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) { + error("%s: bad kex length: %zu < %d", __func__, + sshbuf_len(kex->my), KEX_COOKIE_LEN); return SSH_ERR_INVALID_FORMAT; - if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) + } + if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) { + error("%s: buffer error", __func__); return SSH_ERR_INTERNAL_ERROR; + } arc4random_buf(cookie, KEX_COOKIE_LEN); if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || (r = sshpkt_putb(ssh, kex->my)) != 0 || - (r = sshpkt_send(ssh)) != 0) + (r = sshpkt_send(ssh)) != 0) { + error("%s: compose reply: %s", __func__, ssh_err(r)); return r; + } debug("SSH2_MSG_KEXINIT sent"); kex->flags |= KEX_INIT_SENT; return 0; @@ -544,21 +575,28 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) int r; debug("SSH2_MSG_KEXINIT received"); - if (kex == NULL) - return SSH_ERR_INVALID_ARGUMENT; - + if (kex == NULL) { + error("%s: no hex", __func__); + return SSH_ERR_INTERNAL_ERROR; + } ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); ptr = sshpkt_ptr(ssh, &dlen); if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) return r; /* discard packet */ - for (i = 0; i < KEX_COOKIE_LEN; i++) - if ((r = sshpkt_get_u8(ssh, NULL)) != 0) + for (i = 0; i < KEX_COOKIE_LEN; i++) { + if ((r = sshpkt_get_u8(ssh, NULL)) != 0) { + error("%s: discard cookie: %s", __func__, ssh_err(r)); return r; - for (i = 0; i < PROPOSAL_MAX; i++) - if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) + } + } + for (i = 0; i < PROPOSAL_MAX; i++) { + if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) { + error("%s: discard proposal: %s", __func__, ssh_err(r)); return r; + } + } /* * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported * KEX method has the server move first, but a server might be using @@ -583,6 +621,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) return (kex->kex[kex->kex_type])(ssh); + error("%s: unknown kex type %u", __func__, kex->kex_type); return SSH_ERR_INTERNAL_ERROR; } @@ -718,6 +757,7 @@ choose_enc(struct sshenc *enc, char *client, char *server) if (name == NULL) return SSH_ERR_NO_CIPHER_ALG_MATCH; if ((enc->cipher = cipher_by_name(name)) == NULL) { + error("%s: unsupported cipher %s", __func__, name); free(name); return SSH_ERR_INTERNAL_ERROR; } @@ -739,6 +779,7 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) if (name == NULL) return SSH_ERR_NO_MAC_ALG_MATCH; if (mac_setup(mac, name) < 0) { + error("%s: unsupported MAC %s", __func__, name); free(name); return SSH_ERR_INTERNAL_ERROR; } @@ -762,6 +803,7 @@ choose_comp(struct sshcomp *comp, char *client, char *server) } else if (strcmp(name, "none") == 0) { comp->type = COMP_NONE; } else { + error("%s: unsupported compression scheme %s", __func__, name); free(name); return SSH_ERR_INTERNAL_ERROR; } @@ -779,8 +821,10 @@ choose_kex(struct kex *k, char *client, char *server) 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 ((kexalg = kex_alg_by_name(k->name)) == NULL) { + error("%s: unsupported KEX method %s", __func__, k->name); return SSH_ERR_INTERNAL_ERROR; + } k->kex_type = kexalg->type; k->hash_alg = kexalg->hash_alg; k->ec_nid = kexalg->ec_nid; @@ -797,8 +841,11 @@ choose_hostkeyalg(struct kex *k, char *client, char *server) if (k->hostkey_alg == NULL) return SSH_ERR_NO_HOSTKEY_ALG_MATCH; k->hostkey_type = sshkey_type_from_name(k->hostkey_alg); - if (k->hostkey_type == KEY_UNSPEC) + if (k->hostkey_type == KEY_UNSPEC) { + error("%s: unsupported hostkey algorithm %s", __func__, + k->hostkey_alg); return SSH_ERR_INTERNAL_ERROR; + } k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg); return 0; } @@ -967,6 +1014,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, kex->session_id_len) != 0 || ssh_digest_final(hashctx, digest, mdsz) != 0) { r = SSH_ERR_LIBCRYPTO_ERROR; + error("%s: KEX hash failed", __func__); goto out; } ssh_digest_free(hashctx); @@ -983,6 +1031,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, ssh_digest_update(hashctx, hash, hashlen) != 0 || ssh_digest_update(hashctx, digest, have) != 0 || ssh_digest_final(hashctx, digest + have, mdsz) != 0) { + error("%s: KDF failed", __func__); r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } @@ -1046,8 +1095,10 @@ kex_load_hostkey(struct ssh *ssh, struct sshkey **prvp, struct sshkey **pubp) *pubp = NULL; *prvp = NULL; if (kex->load_host_public_key == NULL || - kex->load_host_private_key == NULL) + kex->load_host_private_key == NULL) { + error("%s: missing hostkey loader", __func__); return SSH_ERR_INVALID_ARGUMENT; + } *pubp = kex->load_host_public_key(kex->hostkey_type, kex->hostkey_nid, ssh); *prvp = kex->load_host_private_key(kex->hostkey_type, @@ -1062,8 +1113,10 @@ kex_verify_host_key(struct ssh *ssh, struct sshkey *server_host_key) { struct kex *kex = ssh->kex; - if (kex->verify_host_key == NULL) + if (kex->verify_host_key == NULL) { + error("%s: missing hostkey verifier", __func__); return SSH_ERR_INVALID_ARGUMENT; + } if (server_host_key->type != kex->hostkey_type || (kex->hostkey_type == KEY_ECDSA && server_host_key->ecdsa_nid != kex->hostkey_nid)) |