upstream: sprinkle in some explicit errors here, otherwise the
percolate all the way up to dispatch_run_fatal() and lose all meaninful context to help with bz#3063; ok dtucker@ OpenBSD-Commit-ID: 5b2da83bb1c4a3471444b7910b2120ae36438a0a
This commit is contained in:
parent
0ea332497b
commit
76f09bd959
80
kex.c
80
kex.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: kex.c,v 1.151 2019/09/05 09:25:13 djm Exp $ */
|
/* $OpenBSD: kex.c,v 1.152 2019/09/05 09:35:19 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||||
*
|
*
|
||||||
|
@ -345,18 +345,25 @@ kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp)
|
||||||
r = SSH_ERR_ALLOC_FAIL;
|
r = SSH_ERR_ALLOC_FAIL;
|
||||||
goto out;
|
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;
|
goto out;
|
||||||
|
}
|
||||||
/* extract kex init proposal strings */
|
/* extract kex init proposal strings */
|
||||||
for (i = 0; i < PROPOSAL_MAX; i++) {
|
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;
|
goto out;
|
||||||
|
}
|
||||||
debug2("%s: %s", proposal_names[i], proposal[i]);
|
debug2("%s: %s", proposal_names[i], proposal[i]);
|
||||||
}
|
}
|
||||||
/* first kex follows / reserved */
|
/* first kex follows / reserved */
|
||||||
if ((r = sshbuf_get_u8(b, &v)) != 0 || /* first_kex_follows */
|
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;
|
goto out;
|
||||||
|
}
|
||||||
if (first_kex_follows != NULL)
|
if (first_kex_follows != NULL)
|
||||||
*first_kex_follows = v;
|
*first_kex_follows = v;
|
||||||
debug2("first_kex_follows %d ", v);
|
debug2("first_kex_follows %d ", v);
|
||||||
|
@ -417,8 +424,10 @@ kex_send_ext_info(struct ssh *ssh)
|
||||||
(r = sshpkt_put_u32(ssh, 1)) != 0 ||
|
(r = sshpkt_put_u32(ssh, 1)) != 0 ||
|
||||||
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
|
(r = sshpkt_put_cstring(ssh, "server-sig-algs")) != 0 ||
|
||||||
(r = sshpkt_put_cstring(ssh, 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;
|
goto out;
|
||||||
|
}
|
||||||
/* success */
|
/* success */
|
||||||
r = 0;
|
r = 0;
|
||||||
out:
|
out:
|
||||||
|
@ -512,23 +521,32 @@ kex_send_kexinit(struct ssh *ssh)
|
||||||
struct kex *kex = ssh->kex;
|
struct kex *kex = ssh->kex;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (kex == NULL)
|
if (kex == NULL) {
|
||||||
|
error("%s: no hex", __func__);
|
||||||
return SSH_ERR_INTERNAL_ERROR;
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
if (kex->flags & KEX_INIT_SENT)
|
if (kex->flags & KEX_INIT_SENT)
|
||||||
return 0;
|
return 0;
|
||||||
kex->done = 0;
|
kex->done = 0;
|
||||||
|
|
||||||
/* generate a random cookie */
|
/* 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;
|
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;
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
arc4random_buf(cookie, KEX_COOKIE_LEN);
|
arc4random_buf(cookie, KEX_COOKIE_LEN);
|
||||||
|
|
||||||
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
|
if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 ||
|
||||||
(r = sshpkt_putb(ssh, kex->my)) != 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;
|
return r;
|
||||||
|
}
|
||||||
debug("SSH2_MSG_KEXINIT sent");
|
debug("SSH2_MSG_KEXINIT sent");
|
||||||
kex->flags |= KEX_INIT_SENT;
|
kex->flags |= KEX_INIT_SENT;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -545,21 +563,28 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
debug("SSH2_MSG_KEXINIT received");
|
debug("SSH2_MSG_KEXINIT received");
|
||||||
if (kex == NULL)
|
if (kex == NULL) {
|
||||||
return SSH_ERR_INVALID_ARGUMENT;
|
error("%s: no hex", __func__);
|
||||||
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
|
ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
|
||||||
ptr = sshpkt_ptr(ssh, &dlen);
|
ptr = sshpkt_ptr(ssh, &dlen);
|
||||||
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
|
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
/* discard packet */
|
/* discard packet */
|
||||||
for (i = 0; i < KEX_COOKIE_LEN; i++)
|
for (i = 0; i < KEX_COOKIE_LEN; i++) {
|
||||||
if ((r = sshpkt_get_u8(ssh, NULL)) != 0)
|
if ((r = sshpkt_get_u8(ssh, NULL)) != 0) {
|
||||||
|
error("%s: discard cookie: %s", __func__, ssh_err(r));
|
||||||
return 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;
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
|
* XXX RFC4253 sec 7: "each side MAY guess" - currently no supported
|
||||||
* KEX method has the server move first, but a server might be using
|
* KEX method has the server move first, but a server might be using
|
||||||
|
@ -584,6 +609,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)
|
if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
|
||||||
return (kex->kex[kex->kex_type])(ssh);
|
return (kex->kex[kex->kex_type])(ssh);
|
||||||
|
|
||||||
|
error("%s: unknown kex type %u", __func__, kex->kex_type);
|
||||||
return SSH_ERR_INTERNAL_ERROR;
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,6 +745,7 @@ choose_enc(struct sshenc *enc, char *client, char *server)
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return SSH_ERR_NO_CIPHER_ALG_MATCH;
|
return SSH_ERR_NO_CIPHER_ALG_MATCH;
|
||||||
if ((enc->cipher = cipher_by_name(name)) == NULL) {
|
if ((enc->cipher = cipher_by_name(name)) == NULL) {
|
||||||
|
error("%s: unsupported cipher %s", __func__, name);
|
||||||
free(name);
|
free(name);
|
||||||
return SSH_ERR_INTERNAL_ERROR;
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -740,6 +767,7 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server)
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return SSH_ERR_NO_MAC_ALG_MATCH;
|
return SSH_ERR_NO_MAC_ALG_MATCH;
|
||||||
if (mac_setup(mac, name) < 0) {
|
if (mac_setup(mac, name) < 0) {
|
||||||
|
error("%s: unsupported MAC %s", __func__, name);
|
||||||
free(name);
|
free(name);
|
||||||
return SSH_ERR_INTERNAL_ERROR;
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -763,6 +791,7 @@ choose_comp(struct sshcomp *comp, char *client, char *server)
|
||||||
} else if (strcmp(name, "none") == 0) {
|
} else if (strcmp(name, "none") == 0) {
|
||||||
comp->type = COMP_NONE;
|
comp->type = COMP_NONE;
|
||||||
} else {
|
} else {
|
||||||
|
error("%s: unsupported compression scheme %s", __func__, name);
|
||||||
free(name);
|
free(name);
|
||||||
return SSH_ERR_INTERNAL_ERROR;
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -780,8 +809,10 @@ choose_kex(struct kex *k, char *client, char *server)
|
||||||
debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
|
debug("kex: algorithm: %s", k->name ? k->name : "(no match)");
|
||||||
if (k->name == NULL)
|
if (k->name == NULL)
|
||||||
return SSH_ERR_NO_KEX_ALG_MATCH;
|
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;
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
k->kex_type = kexalg->type;
|
k->kex_type = kexalg->type;
|
||||||
k->hash_alg = kexalg->hash_alg;
|
k->hash_alg = kexalg->hash_alg;
|
||||||
k->ec_nid = kexalg->ec_nid;
|
k->ec_nid = kexalg->ec_nid;
|
||||||
|
@ -798,8 +829,11 @@ choose_hostkeyalg(struct kex *k, char *client, char *server)
|
||||||
if (k->hostkey_alg == NULL)
|
if (k->hostkey_alg == NULL)
|
||||||
return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
|
return SSH_ERR_NO_HOSTKEY_ALG_MATCH;
|
||||||
k->hostkey_type = sshkey_type_from_name(k->hostkey_alg);
|
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;
|
return SSH_ERR_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
|
k->hostkey_nid = sshkey_ecdsa_nid_from_name(k->hostkey_alg);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -968,6 +1002,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen,
|
||||||
kex->session_id_len) != 0 ||
|
kex->session_id_len) != 0 ||
|
||||||
ssh_digest_final(hashctx, digest, mdsz) != 0) {
|
ssh_digest_final(hashctx, digest, mdsz) != 0) {
|
||||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||||
|
error("%s: KEX hash failed", __func__);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
ssh_digest_free(hashctx);
|
ssh_digest_free(hashctx);
|
||||||
|
@ -984,6 +1019,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, hash, hashlen) != 0 ||
|
||||||
ssh_digest_update(hashctx, digest, have) != 0 ||
|
ssh_digest_update(hashctx, digest, have) != 0 ||
|
||||||
ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
|
ssh_digest_final(hashctx, digest + have, mdsz) != 0) {
|
||||||
|
error("%s: KDF failed", __func__);
|
||||||
r = SSH_ERR_LIBCRYPTO_ERROR;
|
r = SSH_ERR_LIBCRYPTO_ERROR;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -1047,8 +1083,10 @@ kex_load_hostkey(struct ssh *ssh, struct sshkey **prvp, struct sshkey **pubp)
|
||||||
*pubp = NULL;
|
*pubp = NULL;
|
||||||
*prvp = NULL;
|
*prvp = NULL;
|
||||||
if (kex->load_host_public_key == 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;
|
return SSH_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
*pubp = kex->load_host_public_key(kex->hostkey_type,
|
*pubp = kex->load_host_public_key(kex->hostkey_type,
|
||||||
kex->hostkey_nid, ssh);
|
kex->hostkey_nid, ssh);
|
||||||
*prvp = kex->load_host_private_key(kex->hostkey_type,
|
*prvp = kex->load_host_private_key(kex->hostkey_type,
|
||||||
|
@ -1063,8 +1101,10 @@ kex_verify_host_key(struct ssh *ssh, struct sshkey *server_host_key)
|
||||||
{
|
{
|
||||||
struct kex *kex = ssh->kex;
|
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;
|
return SSH_ERR_INVALID_ARGUMENT;
|
||||||
|
}
|
||||||
if (server_host_key->type != kex->hostkey_type ||
|
if (server_host_key->type != kex->hostkey_type ||
|
||||||
(kex->hostkey_type == KEY_ECDSA &&
|
(kex->hostkey_type == KEY_ECDSA &&
|
||||||
server_host_key->ecdsa_nid != kex->hostkey_nid))
|
server_host_key->ecdsa_nid != kex->hostkey_nid))
|
||||||
|
|
Loading…
Reference in New Issue