Skip to content

Commit

Permalink
upstream: Refactor creation of KEX proposal.
Browse files Browse the repository at this point in the history
This adds kex_proposal_populate_entries (and corresponding free) which
populates the KEX proposal array with dynamically allocated strings.
This replaces the previous mix of static and dynamic that has been the
source of previous leaks and bugs.  Remove unused compat functions.
With & ok djm@.

OpenBSD-Commit-ID: f2f99da4aae2233cb18bf9c749320c5e040a9c7b
  • Loading branch information
daztucker committed Mar 6, 2023
1 parent aa59d6a commit 9641753
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 86 deletions.
19 changes: 2 additions & 17 deletions compat.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: compat.c,v 1.125 2023/02/17 04:22:50 dtucker Exp $ */
/* $OpenBSD: compat.c,v 1.126 2023/03/06 12:14:48 dtucker Exp $ */
/*
* Copyright (c) 1999, 2000, 2001, 2002 Markus Friedl. All rights reserved.
*
Expand Down Expand Up @@ -36,7 +36,6 @@
#include "compat.h"
#include "log.h"
#include "match.h"
#include "kex.h"

/* determine bug flags from SSH protocol banner */
void
Expand Down Expand Up @@ -140,21 +139,7 @@ compat_banner(struct ssh *ssh, const char *version)

/* Always returns pointer to allocated memory, caller must free. */
char *
compat_cipher_proposal(struct ssh *ssh, char *cipher_prop)
{
return xstrdup(cipher_prop);
}

/* Always returns pointer to allocated memory, caller must free. */
char *
compat_pkalg_proposal(struct ssh *ssh, char *pkalg_prop)
{
return xstrdup(pkalg_prop);
}

/* Always returns pointer to allocated memory, caller must free. */
char *
compat_kex_proposal(struct ssh *ssh, char *p)
compat_kex_proposal(struct ssh *ssh, const char *p)
{
char *cp = NULL, *cp2 = NULL;

Expand Down
6 changes: 2 additions & 4 deletions compat.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: compat.h,v 1.61 2023/02/17 04:22:50 dtucker Exp $ */
/* $OpenBSD: compat.h,v 1.62 2023/03/06 12:14:48 dtucker Exp $ */

/*
* Copyright (c) 1999, 2000, 2001 Markus Friedl. All rights reserved.
Expand Down Expand Up @@ -61,7 +61,5 @@
struct ssh;

void compat_banner(struct ssh *, const char *);
char *compat_cipher_proposal(struct ssh *, char *);
char *compat_pkalg_proposal(struct ssh *, char *);
char *compat_kex_proposal(struct ssh *, char *);
char *compat_kex_proposal(struct ssh *, const char *);
#endif
59 changes: 58 additions & 1 deletion kex.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: kex.c,v 1.175 2023/02/28 21:31:50 dtucker Exp $ */
/* $OpenBSD: kex.c,v 1.176 2023/03/06 12:14:48 dtucker Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
*
Expand Down Expand Up @@ -57,10 +57,12 @@
#include "misc.h"
#include "dispatch.h"
#include "monitor.h"
#include "myproposal.h"

#include "ssherr.h"
#include "sshbuf.h"
#include "digest.h"
#include "xmalloc.h"

/* prototype */
static int kex_choose_conf(struct ssh *);
Expand Down Expand Up @@ -317,6 +319,61 @@ kex_assemble_names(char **listp, const char *def, const char *all)
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.
* Array contents must be freed by calling kex_proposal_free_entries.
*/
void
kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX],
const char *kexalgos, const char *ciphers, const char *macs,
const char *comp, const char *hkalgs)
{
const char *defpropserver[PROPOSAL_MAX] = { KEX_SERVER };
const char *defpropclient[PROPOSAL_MAX] = { KEX_CLIENT };
const char **defprop = ssh->kex->server ? defpropserver : defpropclient;
u_int i;

if (prop == NULL)
fatal_f("proposal missing");

for (i = 0; i < PROPOSAL_MAX; i++) {
switch(i) {
case PROPOSAL_KEX_ALGS:
prop[i] = compat_kex_proposal(ssh,
kexalgos ? kexalgos : defprop[i]);
break;
case PROPOSAL_ENC_ALGS_CTOS:
case PROPOSAL_ENC_ALGS_STOC:
prop[i] = xstrdup(ciphers ? ciphers : defprop[i]);
break;
case PROPOSAL_MAC_ALGS_CTOS:
case PROPOSAL_MAC_ALGS_STOC:
prop[i] = xstrdup(macs ? macs : defprop[i]);
break;
case PROPOSAL_COMP_ALGS_CTOS:
case PROPOSAL_COMP_ALGS_STOC:
prop[i] = xstrdup(comp ? comp : defprop[i]);
break;
case PROPOSAL_SERVER_HOST_KEY_ALGS:
prop[i] = xstrdup(hkalgs ? hkalgs : defprop[i]);
break;
default:
prop[i] = xstrdup(defprop[i]);
}
}
}

void
kex_proposal_free_entries(char *prop[PROPOSAL_MAX])
{
u_int i;

for (i = 0; i < PROPOSAL_MAX; i++)
free(prop[i]);
}

/* put algorithm proposal into buffer */
int
kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX])
Expand Down
5 changes: 4 additions & 1 deletion kex.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: kex.h,v 1.117 2022/01/06 21:55:23 djm Exp $ */
/* $OpenBSD: kex.h,v 1.118 2023/03/06 12:14:48 dtucker Exp $ */

/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
Expand Down Expand Up @@ -182,6 +182,9 @@ int kex_names_valid(const char *);
char *kex_alg_list(char);
char *kex_names_cat(const char *, const char *);
int kex_assemble_names(char **, const char *, const char *);
void kex_proposal_populate_entries(struct ssh *, char *prop[PROPOSAL_MAX],
const char *, const char *, const char *, const char *, const char *);
void kex_proposal_free_entries(char *prop[PROPOSAL_MAX]);

int kex_exchange_identification(struct ssh *, int, const char *);

Expand Down
65 changes: 24 additions & 41 deletions sshconnect2.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: sshconnect2.c,v 1.363 2023/03/03 02:34:29 dtucker Exp $ */
/* $OpenBSD: sshconnect2.c,v 1.364 2023/03/06 12:14:48 dtucker Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
Expand Down Expand Up @@ -56,7 +56,6 @@
#include "cipher.h"
#include "sshkey.h"
#include "kex.h"
#include "myproposal.h"
#include "sshconnect.h"
#include "authfile.h"
#include "dh.h"
Expand Down Expand Up @@ -221,24 +220,17 @@ void
ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
const struct ssh_conn_info *cinfo)
{
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
char *s, *all_key;
char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL;
int r, use_known_hosts_order = 0;
char *myproposal[PROPOSAL_MAX];
char *s, *all_key, *hkalgs = NULL;
int r;

xxx_host = host;
xxx_hostaddr = hostaddr;
xxx_conn_info = cinfo;

/*
* If the user has not specified HostkeyAlgorithms, or has only
* appended or removed algorithms from that list then prefer algorithms
* that are in the list that are supported by known_hosts keys.
*/
if (options.hostkeyalgorithms == NULL ||
options.hostkeyalgorithms[0] == '-' ||
options.hostkeyalgorithms[0] == '+')
use_known_hosts_order = 1;
if (options.rekey_limit || options.rekey_interval)
ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
options.rekey_interval);

/* Expand or fill in HostkeyAlgorithms */
all_key = sshkey_alg_list(0, 0, 1, ',');
Expand All @@ -249,29 +241,22 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,

if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
fatal_f("kex_names_cat");
myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, s);
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
myproposal[PROPOSAL_ENC_ALGS_STOC] = prop_enc =
compat_cipher_proposal(ssh, options.ciphers);
myproposal[PROPOSAL_COMP_ALGS_CTOS] =
myproposal[PROPOSAL_COMP_ALGS_STOC] =
(char *)compression_alg_list(options.compression);
myproposal[PROPOSAL_MAC_ALGS_CTOS] =
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;
if (use_known_hosts_order) {
/* Query known_hosts and prefer algorithms that appear there */
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
compat_pkalg_proposal(ssh,
order_hostkeyalgs(host, hostaddr, port, cinfo));
} else {
/* Use specified HostkeyAlgorithms exactly */
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
compat_pkalg_proposal(ssh, options.hostkeyalgorithms);
}

if (options.rekey_limit || options.rekey_interval)
ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
options.rekey_interval);
/*
* If the user has not specified HostkeyAlgorithms, or has only
* appended or removed algorithms from that list then prefer algorithms
* that are in the list that are supported by known_hosts keys.
*/
if (options.hostkeyalgorithms == NULL ||
options.hostkeyalgorithms[0] == '-' ||
options.hostkeyalgorithms[0] == '+')
hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo);

kex_proposal_populate_entries(ssh, myproposal, s, options.ciphers,
options.macs, compression_alg_list(options.compression),
hkalgs ? hkalgs : options.hostkeyalgorithms);

free(hkalgs);

/* start key exchange */
if ((r = kex_setup(ssh, myproposal)) != 0)
Expand All @@ -295,6 +280,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done);

/* remove ext-info from the KEX proposals for rekeying */
free(myproposal[PROPOSAL_KEX_ALGS]);
myproposal[PROPOSAL_KEX_ALGS] =
compat_kex_proposal(ssh, options.kex_algorithms);
if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0)
Expand All @@ -308,10 +294,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port,
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send packet");
#endif
/* Free only parts of proposal that were dynamically allocated here. */
free(prop_kex);
free(prop_enc);
free(prop_hostkey);
kex_proposal_free_entries(myproposal);
}

/*
Expand Down
34 changes: 12 additions & 22 deletions sshd.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: sshd.c,v 1.598 2023/03/03 03:12:24 dtucker Exp $ */
/* $OpenBSD: sshd.c,v 1.599 2023/03/06 12:14:48 dtucker Exp $ */
/*
* Author: Tatu Ylonen <[email protected]>
* Copyright (c) 1995 Tatu Ylonen <[email protected]>, Espoo, Finland
Expand Down Expand Up @@ -104,7 +104,6 @@
#include "digest.h"
#include "sshkey.h"
#include "kex.h"
#include "myproposal.h"
#include "authfile.h"
#include "pathnames.h"
#include "atomicio.h"
Expand Down Expand Up @@ -2389,30 +2388,23 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey,
static void
do_ssh2_kex(struct ssh *ssh)
{
char *myproposal[PROPOSAL_MAX] = { KEX_SERVER };
char *hkalgs = NULL, *myproposal[PROPOSAL_MAX];
const char *compression = NULL;
struct kex *kex;
char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL;
int r;

myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh,
options.kex_algorithms);
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
myproposal[PROPOSAL_ENC_ALGS_STOC] = prop_enc =
compat_cipher_proposal(ssh, options.ciphers);
myproposal[PROPOSAL_MAC_ALGS_CTOS] =
myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs;

if (options.compression == COMP_NONE) {
myproposal[PROPOSAL_COMP_ALGS_CTOS] =
myproposal[PROPOSAL_COMP_ALGS_STOC] = "none";
}

if (options.rekey_limit || options.rekey_interval)
ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
options.rekey_interval);

myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
compat_pkalg_proposal(ssh, list_hostkey_types());
if (options.compression == COMP_NONE)
compression = "none";
hkalgs = list_hostkey_types();

kex_proposal_populate_entries(ssh, myproposal, options.kex_algorithms,
options.ciphers, options.macs, compression, hkalgs);

free(hkalgs);

/* start key exchange */
if ((r = kex_setup(ssh, myproposal)) != 0)
Expand Down Expand Up @@ -2447,9 +2439,7 @@ do_ssh2_kex(struct ssh *ssh)
(r = ssh_packet_write_wait(ssh)) != 0)
fatal_fr(r, "send test");
#endif
free(prop_kex);
free(prop_enc);
free(prop_hostkey);
kex_proposal_free_entries(myproposal);
debug("KEX done");
}

Expand Down

0 comments on commit 9641753

Please sign in to comment.