upstream: more strictly enforce KEX state-machine by banning packet

types once they are received. Fixes memleak caused by duplicate
SSH2_MSG_KEX_DH_GEX_REQUEST (spotted by portable OpenSSH kex_fuzz via
oss-fuzz #30078).

ok markus@

OpenBSD-Commit-ID: 87331c715c095b587d5c88724694cdeb701c9def
This commit is contained in:
djm@openbsd.org 2021-01-31 22:55:29 +00:00 committed by Damien Miller
parent 7a92a324a2
commit 3dd0c64e08
5 changed files with 25 additions and 9 deletions

4
kex.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.c,v 1.166 2021/01/27 23:49:46 djm Exp $ */ /* $OpenBSD: kex.c,v 1.167 2021/01/31 22:55:29 djm Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
* *
@ -405,7 +405,7 @@ kex_prop_free(char **proposal)
} }
/* ARGSUSED */ /* ARGSUSED */
static int int
kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh) kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh)
{ {
int r; int r;

3
kex.h
View File

@ -1,4 +1,4 @@
/* $OpenBSD: kex.h,v 1.113 2021/01/27 10:05:28 djm Exp $ */ /* $OpenBSD: kex.h,v 1.114 2021/01/31 22:55:29 djm Exp $ */
/* /*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@ -193,6 +193,7 @@ int kex_verify_host_key(struct ssh *, struct sshkey *);
int kex_send_kexinit(struct ssh *); int kex_send_kexinit(struct ssh *);
int kex_input_kexinit(int, u_int32_t, struct ssh *); int kex_input_kexinit(int, u_int32_t, struct ssh *);
int kex_input_ext_info(int, u_int32_t, struct ssh *); int kex_input_ext_info(int, u_int32_t, struct ssh *);
int kex_protocol_error(int, u_int32_t, struct ssh *);
int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *); int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *);
int kex_send_newkeys(struct ssh *); int kex_send_newkeys(struct ssh *);
int kex_start_rekex(struct ssh *); int kex_start_rekex(struct ssh *);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgen.c,v 1.5 2020/12/29 00:59:15 djm Exp $ */ /* $OpenBSD: kexgen.c,v 1.6 2021/01/31 22:55:29 djm Exp $ */
/* /*
* Copyright (c) 2019 Markus Friedl. All rights reserved. * Copyright (c) 2019 Markus Friedl. All rights reserved.
* *
@ -148,6 +148,9 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
size_t slen, hashlen; size_t slen, hashlen;
int r; int r;
debug("SSH2_MSG_KEX_ECDH_REPLY received");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &kex_protocol_error);
/* hostkey */ /* hostkey */
if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
goto out; goto out;
@ -254,6 +257,9 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
size_t slen, hashlen; size_t slen, hashlen;
int r; int r;
debug("SSH2_MSG_KEX_ECDH_INIT received");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &kex_protocol_error);
if ((r = kex_load_hostkey(ssh, &server_host_private, if ((r = kex_load_hostkey(ssh, &server_host_private,
&server_host_public)) != 0) &server_host_public)) != 0)
goto out; goto out;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgexc.c,v 1.36 2021/01/27 09:26:54 djm Exp $ */ /* $OpenBSD: kexgexc.c,v 1.37 2021/01/31 22:55:29 djm Exp $ */
/* /*
* Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -83,6 +83,7 @@ kexgex_client(struct ssh *ssh)
fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
kex->min, kex->nbits, kex->max); kex->min, kex->nbits, kex->max);
#endif #endif
debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP,
&input_kex_dh_gex_group); &input_kex_dh_gex_group);
r = 0; r = 0;
@ -98,7 +99,8 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
const BIGNUM *pub_key; const BIGNUM *pub_key;
int r, bits; int r, bits;
debug("got SSH2_MSG_KEX_DH_GEX_GROUP"); debug("SSH2_MSG_KEX_DH_GEX_GROUP received");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, &kex_protocol_error);
if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 || if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 ||
(r = sshpkt_get_bignum2(ssh, &g)) != 0 || (r = sshpkt_get_bignum2(ssh, &g)) != 0 ||
@ -130,7 +132,7 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh)
BN_print_fp(stderr, pub_key); BN_print_fp(stderr, pub_key);
fprintf(stderr, "\n"); fprintf(stderr, "\n");
#endif #endif
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL); debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply); ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply);
r = 0; r = 0;
out: out:
@ -153,7 +155,9 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh)
size_t slen, hashlen; size_t slen, hashlen;
int r; int r;
debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); debug("SSH2_MSG_KEX_DH_GEX_REPLY received");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &kex_protocol_error);
/* key, cert */ /* key, cert */
if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0)
goto out; goto out;

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kexgexs.c,v 1.42 2019/01/23 00:30:41 djm Exp $ */ /* $OpenBSD: kexgexs.c,v 1.43 2021/01/31 22:55:29 djm Exp $ */
/* /*
* Copyright (c) 2000 Niels Provos. All rights reserved. * Copyright (c) 2000 Niels Provos. All rights reserved.
* Copyright (c) 2001 Markus Friedl. All rights reserved. * Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -77,6 +77,8 @@ input_kex_dh_gex_request(int type, u_int32_t seq, struct ssh *ssh)
const BIGNUM *dh_p, *dh_g; const BIGNUM *dh_p, *dh_g;
debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST, &kex_protocol_error);
if ((r = sshpkt_get_u32(ssh, &min)) != 0 || if ((r = sshpkt_get_u32(ssh, &min)) != 0 ||
(r = sshpkt_get_u32(ssh, &nbits)) != 0 || (r = sshpkt_get_u32(ssh, &nbits)) != 0 ||
(r = sshpkt_get_u32(ssh, &max)) != 0 || (r = sshpkt_get_u32(ssh, &max)) != 0 ||
@ -136,6 +138,9 @@ input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh)
size_t slen, hashlen; size_t slen, hashlen;
int r; int r;
debug("SSH2_MSG_KEX_DH_GEX_INIT received");
ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &kex_protocol_error);
if ((r = kex_load_hostkey(ssh, &server_host_private, if ((r = kex_load_hostkey(ssh, &server_host_private,
&server_host_public)) != 0) &server_host_public)) != 0)
goto out; goto out;