Compare commits

...

4 Commits

Author SHA1 Message Date
eabdullin b6a876a1a7 import UBI openssh-8.0p1-19.el8_9.2 2024-01-30 19:53:52 +00:00
Andrew Lukoshko f47dcec1ba import UBI openssh-8.0p1-19.el8_8 2023-08-02 07:42:27 +00:00
CentOS Sources 8098341697 import openssh-8.0p1-17.el8_7 2023-02-21 09:54:50 +00:00
CentOS Sources d538637397 import openssh-8.0p1-16.el8 2022-11-08 14:04:01 +00:00
13 changed files with 1155 additions and 23 deletions

View File

@ -1,6 +1,6 @@
diff -up openssh-7.2p2/sftp-server.8.sftp-force-mode openssh-7.2p2/sftp-server.8
--- openssh-7.2p2/sftp-server.8.sftp-force-mode 2016-03-09 19:04:48.000000000 +0100
+++ openssh-7.2p2/sftp-server.8 2016-06-23 16:18:20.463854117 +0200
diff --color -ru a/sftp-server.8 b/sftp-server.8
--- a/sftp-server.8 2019-04-18 00:52:57.000000000 +0200
+++ b/sftp-server.8 2022-06-20 16:03:47.892540068 +0200
@@ -38,6 +38,7 @@
.Op Fl P Ar blacklisted_requests
.Op Fl p Ar whitelisted_requests
@ -9,21 +9,23 @@ diff -up openssh-7.2p2/sftp-server.8.sftp-force-mode openssh-7.2p2/sftp-server.8
.Ek
.Nm
.Fl Q Ar protocol_feature
@@ -138,6 +139,10 @@ Sets an explicit
@@ -138,6 +139,12 @@
.Xr umask 2
to be applied to newly-created files and directories, instead of the
user's default mask.
+.It Fl m Ar force_file_perms
+Sets explicit file permissions to be applied to newly-created files instead
+of the default or client requested mode. Numeric values include:
+777, 755, 750, 666, 644, 640, etc. Option -u is ineffective if -m is set.
+777, 755, 750, 666, 644, 640, etc. Using both -m and -u switches makes the
+umask (-u) effective only for newly created directories and explicit mode (-m)
+for newly created files.
.El
.Pp
On some systems,
diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
--- openssh-7.2p2/sftp-server.c.sftp-force-mode 2016-06-23 16:18:20.446854128 +0200
+++ openssh-7.2p2/sftp-server.c 2016-06-23 16:20:37.950766082 +0200
@@ -69,6 +69,10 @@ struct sshbuf *oqueue;
diff --color -ru a/sftp-server.c b/sftp-server.c
--- a/sftp-server.c 2022-06-20 16:01:26.183793633 +0200
+++ b/sftp-server.c 2022-06-20 16:02:12.442690608 +0200
@@ -65,6 +65,10 @@
/* Version of client */
static u_int version;
@ -34,7 +36,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
/* SSH2_FXP_INIT received */
static int init_done;
@@ -683,6 +687,7 @@ process_open(u_int32_t id)
@@ -683,6 +687,7 @@
Attrib a;
char *name;
int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE;
@ -42,7 +44,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 ||
(r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */
@@ -692,6 +697,10 @@ process_open(u_int32_t id)
@@ -692,6 +697,10 @@
debug3("request %u: open flags %d", id, pflags);
flags = flags_from_portable(pflags);
mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666;
@ -53,7 +55,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
logit("open \"%s\" flags %s mode 0%o",
name, string_from_portable(pflags), mode);
if (readonly &&
@@ -713,6 +722,8 @@ process_open(u_int32_t id)
@@ -713,6 +722,8 @@
}
}
}
@ -62,7 +64,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
if (status != SSH2_FX_OK)
send_status(id, status);
free(name);
@@ -1494,7 +1505,7 @@ sftp_server_usage(void)
@@ -1555,7 +1566,7 @@
fprintf(stderr,
"usage: %s [-ehR] [-d start_directory] [-f log_facility] "
"[-l log_level]\n\t[-P blacklisted_requests] "
@ -71,7 +73,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
" %s -Q protocol_feature\n",
__progname, __progname);
exit(1);
@@ -1520,7 +1531,7 @@ sftp_server_main(int argc, char **argv,
@@ -1581,7 +1592,7 @@
pw = pwcopy(user_pw);
while (!skipargs && (ch = getopt(argc, argv,
@ -80,7 +82,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c
switch (ch) {
case 'Q':
if (strcasecmp(optarg, "requests") != 0) {
@@ -1580,6 +1591,15 @@ sftp_server_main(int argc, char **argv,
@@ -1643,6 +1654,15 @@
fatal("Invalid umask \"%s\"", optarg);
(void)umask((mode_t)mask);
break;

View File

@ -32,7 +32,7 @@ diff -up openssh-7.9p1/dh.c.fips openssh-7.9p1/dh.c
struct dhgroup dhg;
+ if (FIPS_mode()) {
+ logit("Using arbitrary primes is not allowed in FIPS mode."
+ verbose("Using arbitrary primes is not allowed in FIPS mode."
+ " Falling back to known groups.");
+ return (dh_new_group_fallback(max));
+ }

View File

@ -5,9 +5,9 @@ diff --git a/sshd.c b/sshd.c
parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name,
cfg, NULL);
+ /* 'UsePAM no' is not supported in Fedora */
+ /* 'UsePAM no' is not supported in RHEL */
+ if (! options.use_pam)
+ logit("WARNING: 'UsePAM no' is not supported in Fedora and may cause several problems.");
+ logit("WARNING: 'UsePAM no' is not supported in RHEL and may cause several problems.");
+
/* Fill in default values for those options not explicitly set. */
fill_default_server_options(&options);
@ -19,7 +19,7 @@ diff --git a/sshd_config b/sshd_config
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
+# WARNING: 'UsePAM no' is not supported in Fedora and may cause several
+# WARNING: 'UsePAM no' is not supported in RHEL and may cause several
+# problems.
UsePAM yes

View File

@ -0,0 +1,25 @@
diff --color -ru a/sshd.8 b/sshd.8
--- a/sshd.8 2022-05-31 13:39:10.231843926 +0200
+++ b/sshd.8 2022-05-31 14:34:01.460815420 +0200
@@ -78,6 +78,7 @@
.Xr sshd_config 5 ) ;
command-line options override values specified in the
configuration file.
+This mechanism is used by systemd to apply system-wide crypto-policies to ssh server.
.Nm
rereads its configuration file when it receives a hangup signal,
.Dv SIGHUP ,
@@ -207,6 +208,13 @@
rules may be applied by specifying the connection parameters using one or more
.Fl C
options.
+The configuration does not contain the system-wide crypto-policy configuration.
+To show the most accurate runtime configuration, use:
+.Bd -literal -offset 3n
+source /etc/crypto-policies/back-ends/opensshserver.config
+source /etc/sysconfig/sshd
+sshd -T $OPTIONS $CRYPTO_POLICY
+.Ed
.It Fl t
Test mode.
Only check the validity of the configuration file and sanity of the keys.

View File

@ -0,0 +1,27 @@
diff --git a/sftp.c b/sftp.c
index 04881c83..03c7a5c7 100644
--- a/sftp.c
+++ b/sftp.c
@@ -2527,12 +2527,17 @@ main(int argc, char **argv)
port = tmp;
break;
default:
+ /* Try with user, host and path. */
if (parse_user_host_path(*argv, &user, &host,
- &file1) == -1) {
- /* Treat as a plain hostname. */
- host = xstrdup(*argv);
- host = cleanhostname(host);
- }
+ &file1) == 0)
+ break;
+ /* Try with user and host. */
+ if (parse_user_host_port(*argv, &user, &host, NULL)
+ == 0)
+ break;
+ /* Treat as a plain hostname. */
+ host = xstrdup(*argv);
+ host = cleanhostname(host);
break;
}
file2 = *(argv + 1);

View File

@ -0,0 +1,273 @@
diff --color -ruN a/Makefile.in b/Makefile.in
--- a/Makefile.in 2022-06-23 11:31:10.168186838 +0200
+++ b/Makefile.in 2022-06-23 11:32:19.146513347 +0200
@@ -125,7 +125,7 @@
monitor.o monitor_wrap.o auth-krb5.o \
auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \
loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \
- sftp-server.o sftp-common.o \
+ sftp-server.o sftp-common.o sftp-realpath.o \
sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \
sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-pledge.o \
sandbox-solaris.o uidswap.o
@@ -217,8 +217,8 @@
ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a ssh-keyscan.o
$(LD) -o $@ ssh-keyscan.o $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS)
-sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-server.o sftp-server-main.o
- $(LD) -o $@ sftp-server.o sftp-common.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
+sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-common.o sftp-realpath.o sftp-server.o sftp-server-main.o
+ $(LD) -o $@ sftp-server.o sftp-common.o sftp-realpath.o sftp-server-main.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS)
sftp$(EXEEXT): $(LIBCOMPAT) libssh.a sftp.o sftp-client.o sftp-common.o sftp-glob.o progressmeter.o
$(LD) -o $@ progressmeter.o sftp.o sftp-client.o sftp-common.o sftp-glob.o $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT)
diff --color -ruN a/sftp-realpath.c b/sftp-realpath.c
--- a/sftp-realpath.c 1970-01-01 01:00:00.000000000 +0100
+++ b/sftp-realpath.c 2022-06-23 11:35:33.193244873 +0200
@@ -0,0 +1,225 @@
+/* $OpenBSD: sftp-realpath.c,v 1.2 2021/09/02 21:03:54 deraadt Exp $ */
+/*
+ * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "includes.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#ifndef SYMLOOP_MAX
+# define SYMLOOP_MAX 32
+#endif
+
+/* XXX rewrite sftp-server to use POSIX realpath and remove this hack */
+
+char *sftp_realpath(const char *path, char *resolved);
+
+/*
+ * char *realpath(const char *path, char resolved[PATH_MAX]);
+ *
+ * Find the real name of path, by removing all ".", ".." and symlink
+ * components. Returns (resolved) on success, or (NULL) on failure,
+ * in which case the path which caused trouble is left in (resolved).
+ */
+char *
+sftp_realpath(const char *path, char *resolved)
+{
+ struct stat sb;
+ char *p, *q, *s;
+ size_t left_len, resolved_len;
+ unsigned symlinks;
+ int serrno, slen, mem_allocated;
+ char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
+
+ if (path[0] == '\0') {
+ errno = ENOENT;
+ return (NULL);
+ }
+
+ serrno = errno;
+
+ if (resolved == NULL) {
+ resolved = malloc(PATH_MAX);
+ if (resolved == NULL)
+ return (NULL);
+ mem_allocated = 1;
+ } else
+ mem_allocated = 0;
+
+ symlinks = 0;
+ if (path[0] == '/') {
+ resolved[0] = '/';
+ resolved[1] = '\0';
+ if (path[1] == '\0')
+ return (resolved);
+ resolved_len = 1;
+ left_len = strlcpy(left, path + 1, sizeof(left));
+ } else {
+ if (getcwd(resolved, PATH_MAX) == NULL) {
+ if (mem_allocated)
+ free(resolved);
+ else
+ strlcpy(resolved, ".", PATH_MAX);
+ return (NULL);
+ }
+ resolved_len = strlen(resolved);
+ left_len = strlcpy(left, path, sizeof(left));
+ }
+ if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ goto err;
+ }
+
+ /*
+ * Iterate over path components in `left'.
+ */
+ while (left_len != 0) {
+ /*
+ * Extract the next path component and adjust `left'
+ * and its length.
+ */
+ p = strchr(left, '/');
+ s = p ? p : left + left_len;
+ if (s - left >= (ptrdiff_t)sizeof(next_token)) {
+ errno = ENAMETOOLONG;
+ goto err;
+ }
+ memcpy(next_token, left, s - left);
+ next_token[s - left] = '\0';
+ left_len -= s - left;
+ if (p != NULL)
+ memmove(left, s + 1, left_len + 1);
+ if (resolved[resolved_len - 1] != '/') {
+ if (resolved_len + 1 >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ goto err;
+ }
+ resolved[resolved_len++] = '/';
+ resolved[resolved_len] = '\0';
+ }
+ if (next_token[0] == '\0')
+ continue;
+ else if (strcmp(next_token, ".") == 0)
+ continue;
+ else if (strcmp(next_token, "..") == 0) {
+ /*
+ * Strip the last path component except when we have
+ * single "/"
+ */
+ if (resolved_len > 1) {
+ resolved[resolved_len - 1] = '\0';
+ q = strrchr(resolved, '/') + 1;
+ *q = '\0';
+ resolved_len = q - resolved;
+ }
+ continue;
+ }
+
+ /*
+ * Append the next path component and lstat() it. If
+ * lstat() fails we still can return successfully if
+ * there are no more path components left.
+ */
+ resolved_len = strlcat(resolved, next_token, PATH_MAX);
+ if (resolved_len >= PATH_MAX) {
+ errno = ENAMETOOLONG;
+ goto err;
+ }
+ if (lstat(resolved, &sb) != 0) {
+ if (errno == ENOENT && p == NULL) {
+ errno = serrno;
+ return (resolved);
+ }
+ goto err;
+ }
+ if (S_ISLNK(sb.st_mode)) {
+ if (symlinks++ > SYMLOOP_MAX) {
+ errno = ELOOP;
+ goto err;
+ }
+ slen = readlink(resolved, symlink, sizeof(symlink) - 1);
+ if (slen < 0)
+ goto err;
+ symlink[slen] = '\0';
+ if (symlink[0] == '/') {
+ resolved[1] = 0;
+ resolved_len = 1;
+ } else if (resolved_len > 1) {
+ /* Strip the last path component. */
+ resolved[resolved_len - 1] = '\0';
+ q = strrchr(resolved, '/') + 1;
+ *q = '\0';
+ resolved_len = q - resolved;
+ }
+
+ /*
+ * If there are any path components left, then
+ * append them to symlink. The result is placed
+ * in `left'.
+ */
+ if (p != NULL) {
+ if (symlink[slen - 1] != '/') {
+ if (slen + 1 >=
+ (ptrdiff_t)sizeof(symlink)) {
+ errno = ENAMETOOLONG;
+ goto err;
+ }
+ symlink[slen] = '/';
+ symlink[slen + 1] = 0;
+ }
+ left_len = strlcat(symlink, left, sizeof(symlink));
+ if (left_len >= sizeof(symlink)) {
+ errno = ENAMETOOLONG;
+ goto err;
+ }
+ }
+ left_len = strlcpy(left, symlink, sizeof(left));
+ }
+ }
+
+ /*
+ * Remove trailing slash except when the resolved pathname
+ * is a single "/".
+ */
+ if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
+ resolved[resolved_len - 1] = '\0';
+ return (resolved);
+
+err:
+ if (mem_allocated)
+ free(resolved);
+ return (NULL);
+}
diff --color -ruN a/sftp-server.c b/sftp-server.c
--- a/sftp-server.c 2022-06-23 11:31:10.147186434 +0200
+++ b/sftp-server.c 2022-06-23 11:32:19.147513366 +0200
@@ -51,6 +51,8 @@
#include "sftp.h"
#include "sftp-common.h"
+char *sftp_realpath(const char *, char *); /* sftp-realpath.c */
+
/* Our verbosity */
static LogLevel log_level = SYSLOG_LEVEL_ERROR;
@@ -1185,7 +1187,7 @@
}
debug3("request %u: realpath", id);
verbose("realpath \"%s\"", path);
- if (realpath(path, resolvedname) == NULL) {
+ if (sftp_realpath(path, resolvedname) == NULL) {
send_status(id, errno_to_portable(errno));
} else {
Stat s;

View File

@ -779,7 +779,7 @@ diff -up openssh-8.0p1/sshd.c.sshdinclude openssh-8.0p1/sshd.c
- cfg, NULL);
+ cfg, &includes, NULL);
/* 'UsePAM no' is not supported in Fedora */
/* 'UsePAM no' is not supported in RHEL */
if (! options.use_pam)
@@ -1946,7 +1978,7 @@ main(int ac, char **av)
if (connection_info == NULL)
@ -790,3 +790,16 @@ diff -up openssh-8.0p1/sshd.c.sshdinclude openssh-8.0p1/sshd.c
dump_config(&options);
}
diff -up openssh-8.0p1/sshbuf-getput-basic.c.stringb openssh-8.0p1/sshbuf-getput-basic.c
--- openssh-8.0p1/sshbuf-getput-basic.c.stringb 2022-12-21 12:18:43.274799163 +0100
+++ openssh-8.0p1/sshbuf-getput-basic.c 2022-12-21 12:19:19.758081516 +0100
@@ -371,6 +371,9 @@ sshbuf_put_cstring(struct sshbuf *buf, c
int
sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
{
+ if (v == NULL)
+ return sshbuf_put_string(buf, NULL, 0);
+
return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
}

View File

@ -0,0 +1,166 @@
diff --color -ru a/kex.c b/kex.c
--- a/kex.c 2022-06-23 10:25:29.529922670 +0200
+++ b/kex.c 2022-06-23 10:26:12.911762100 +0200
@@ -906,6 +906,18 @@
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;
+}
+
static int
kex_choose_conf(struct ssh *ssh)
{
@@ -941,6 +953,16 @@
free(ext);
}
+ /* Check whether client supports rsa-sha2 algorithms */
+ if (kex->server && (kex->flags & KEX_INITIAL)) {
+ if (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],
+ "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com"))
+ kex->flags |= KEX_RSA_SHA2_512_SUPPORTED;
+ }
+
/* Algorithm Negotiation */
if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS],
sprop[PROPOSAL_KEX_ALGS])) != 0) {
diff --color -ru a/kex.h b/kex.h
--- a/kex.h 2022-06-23 10:25:29.511922322 +0200
+++ b/kex.h 2022-06-23 10:26:12.902761926 +0200
@@ -117,6 +117,8 @@
#define KEX_INIT_SENT 0x0001
#define KEX_INITIAL 0x0002
+#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */
+#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */
struct sshenc {
char *name;
diff --color -ru a/serverloop.c b/serverloop.c
--- a/serverloop.c 2022-06-23 10:25:29.537922825 +0200
+++ b/serverloop.c 2022-06-23 10:26:12.918762235 +0200
@@ -736,16 +736,17 @@
struct sshbuf *resp = NULL;
struct sshbuf *sigbuf = NULL;
struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL;
- int r, ndx, kexsigtype, use_kexsigtype, success = 0;
+ int r, ndx, success = 0;
const u_char *blob;
+ const char *sigalg, *kex_rsa_sigalg = NULL;
u_char *sig = 0;
size_t blen, slen;
if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new", __func__);
-
- kexsigtype = sshkey_type_plain(
- sshkey_type_from_name(ssh->kex->hostkey_alg));
+ if (sshkey_type_plain(sshkey_type_from_name(
+ ssh->kex->hostkey_alg)) == KEY_RSA)
+ kex_rsa_sigalg = ssh->kex->hostkey_alg;
while (ssh_packet_remaining(ssh) > 0) {
sshkey_free(key);
key = NULL;
@@ -780,16 +781,24 @@
* For RSA keys, prefer to use the signature type negotiated
* during KEX to the default (SHA1).
*/
- use_kexsigtype = kexsigtype == KEY_RSA &&
- sshkey_type_plain(key->type) == KEY_RSA;
+ sigalg = NULL;
+ if (sshkey_type_plain(key->type) == KEY_RSA) {
+ if (kex_rsa_sigalg != NULL)
+ sigalg = kex_rsa_sigalg;
+ else if (ssh->kex->flags & KEX_RSA_SHA2_512_SUPPORTED)
+ sigalg = "rsa-sha2-512";
+ else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED)
+ sigalg = "rsa-sha2-256";
+ }
+ debug3("%s: sign %s key (index %d) using sigalg %s", __func__,
+ sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg);
if ((r = sshbuf_put_cstring(sigbuf,
"hostkeys-prove-00@openssh.com")) != 0 ||
(r = sshbuf_put_string(sigbuf,
ssh->kex->session_id, ssh->kex->session_id_len)) != 0 ||
(r = sshkey_puts(key, sigbuf)) != 0 ||
(r = ssh->kex->sign(ssh, key_prv, key_pub, &sig, &slen,
- sshbuf_ptr(sigbuf), sshbuf_len(sigbuf),
- use_kexsigtype ? ssh->kex->hostkey_alg : NULL)) != 0 ||
+ sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), sigalg)) != 0 ||
(r = sshbuf_put_string(resp, sig, slen)) != 0) {
error("%s: couldn't prepare signature: %s",
__func__, ssh_err(r));
diff --color -ru a/sshkey.c b/sshkey.c
--- a/sshkey.c 2022-06-23 10:25:29.532922728 +0200
+++ b/sshkey.c 2022-06-23 10:26:12.914762158 +0200
@@ -82,7 +82,6 @@
struct sshbuf *buf, enum sshkey_serialize_rep);
static int sshkey_from_blob_internal(struct sshbuf *buf,
struct sshkey **keyp, int allow_cert);
-static int get_sigtype(const u_char *sig, size_t siglen, char **sigtypep);
/* Supported key types */
struct keytype {
@@ -2092,7 +2091,8 @@
if ((ret = sshkey_verify(key->cert->signature_key, sig, slen,
sshbuf_ptr(key->cert->certblob), signed_len, NULL, 0)) != 0)
goto out;
- if ((ret = get_sigtype(sig, slen, &key->cert->signature_type)) != 0)
+ if ((ret = sshkey_get_sigtype(sig, slen,
+ &key->cert->signature_type)) != 0)
goto out;
/* Success */
@@ -2394,8 +2394,8 @@
return r;
}
-static int
-get_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
+int
+sshkey_get_sigtype(const u_char *sig, size_t siglen, char **sigtypep)
{
int r;
struct sshbuf *b = NULL;
@@ -2477,7 +2477,7 @@
return 0;
if ((expected_alg = sshkey_sigalg_by_name(requested_alg)) == NULL)
return SSH_ERR_INVALID_ARGUMENT;
- if ((r = get_sigtype(sig, siglen, &sigtype)) != 0)
+ if ((r = sshkey_get_sigtype(sig, siglen, &sigtype)) != 0)
return r;
r = strcmp(expected_alg, sigtype) == 0;
free(sigtype);
@@ -2739,7 +2739,7 @@
sshbuf_len(cert), alg, 0, signer_ctx)) != 0)
goto out;
/* Check and update signature_type against what was actually used */
- if ((ret = get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
+ if ((ret = sshkey_get_sigtype(sig_blob, sig_len, &sigtype)) != 0)
goto out;
if (alg != NULL && strcmp(alg, sigtype) != 0) {
ret = SSH_ERR_SIGN_ALG_UNSUPPORTED;
diff --color -ru a/sshkey.h b/sshkey.h
--- a/sshkey.h 2022-06-23 10:25:29.521922515 +0200
+++ b/sshkey.h 2022-06-23 10:26:12.907762022 +0200
@@ -211,6 +211,7 @@
const u_char *, size_t, const char *, u_int);
int sshkey_check_sigtype(const u_char *, size_t, const char *);
const char *sshkey_sigalg_by_name(const char *);
+int sshkey_get_sigtype(const u_char *, size_t, char **);
/* for debug */
void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *);

View File

@ -0,0 +1,32 @@
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index d29a03b4..d7283136 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -490,6 +490,15 @@ congreet(int s)
return;
}
+ /*
+ * Read the server banner as per RFC4253 section 4.2. The "SSH-"
+ * protocol identification string may be preceeded by an arbitarily
+ * large banner which we must read and ignore. Loop while reading
+ * newline-terminated lines until we have one starting with "SSH-".
+ * The ID string cannot be longer than 255 characters although the
+ * preceeding banner lines may (in which case they'll be discarded
+ * in multiple iterations of the outer loop).
+ */
for (;;) {
memset(buf, '\0', sizeof(buf));
bufsiz = sizeof(buf);
@@ -517,6 +526,11 @@ congreet(int s)
conrecycle(s);
return;
}
+ if (cp >= buf + sizeof(buf)) {
+ error("%s: greeting exceeds allowable length", c->c_name);
+ confree(s);
+ return;
+ }
if (*cp != '\n' && *cp != '\r') {
error("%s: bad greeting", c->c_name);
confree(s);

View File

@ -0,0 +1,17 @@
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index 6be647ec..ebddf6c3 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -1537,10 +1537,8 @@ pkcs11_register_provider(char *provider_id, char *pin,
error("dlopen %s failed: %s", provider_module, dlerror());
goto fail;
}
- if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
- error("dlsym(C_GetFunctionList) failed: %s", dlerror());
- goto fail;
- }
+ if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL)
+ fatal("dlsym(C_GetFunctionList) failed: %s", dlerror());
p->module->handle = handle;
/* setup the pkcs11 callbacks */

View File

@ -0,0 +1,447 @@
diff --git a/PROTOCOL b/PROTOCOL
index d453c779..ded935eb 100644
--- a/PROTOCOL
+++ b/PROTOCOL
@@ -137,6 +137,32 @@ than as a named global or channel request to allow pings with very
described at:
http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.org.txt?h=curve25519
+1.9 transport: strict key exchange extension
+
+OpenSSH supports a number of transport-layer hardening measures under
+a "strict KEX" feature. This feature is signalled similarly to the
+RFC8308 ext-info feature: by including a additional algorithm in the
+initiial SSH2_MSG_KEXINIT kex_algorithms field. The client may append
+"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server
+may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms
+are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored
+if they are present in subsequent SSH2_MSG_KEXINIT packets.
+
+When an endpoint that supports this extension observes this algorithm
+name in a peer's KEXINIT packet, it MUST make the following changes to
+the the protocol:
+
+a) During initial KEX, terminate the connection if any unexpected or
+ out-of-sequence packet is received. This includes terminating the
+ connection if the first packet received is not SSH2_MSG_KEXINIT.
+ Unexpected packets for the purpose of strict KEX include messages
+ that are otherwise valid at any time during the connection such as
+ SSH2_MSG_DEBUG and SSH2_MSG_IGNORE.
+b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the
+ packet sequence number to zero. This behaviour persists for the
+ duration of the connection (i.e. not just the first
+ SSH2_MSG_NEWKEYS).
+
2. Connection protocol changes
2.1. connection: Channel write close extension "eow@openssh.com"
diff --git a/kex.c b/kex.c
index aa5e792d..d478ff6e 100644
--- a/kex.c
+++ b/kex.c
@@ -65,7 +65,7 @@
#endif
/* prototype */
-static int kex_choose_conf(struct ssh *);
+static int kex_choose_conf(struct ssh *, uint32_t seq);
static int kex_input_newkeys(int, u_int32_t, struct ssh *);
static const char *proposal_names[PROPOSAL_MAX] = {
@@ -177,6 +177,18 @@ kex_names_valid(const char *names)
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.
@@ -184,7 +196,7 @@ kex_names_valid(const char *names)
char *
kex_names_cat(const char *a, const char *b)
{
- char *ret = NULL, *tmp = NULL, *cp, *p, *m;
+ char *ret = NULL, *tmp = NULL, *cp, *p;
size_t len;
if (a == NULL || *a == '\0')
@@ -201,10 +213,8 @@ kex_names_cat(const char *a, const char *b)
}
strlcpy(ret, a, len);
for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) {
- if ((m = match_list(ret, p, NULL)) != NULL) {
- free(m);
+ if (has_any_alg(ret, p))
continue; /* Algorithm already present */
- }
if (strlcat(ret, ",", len) >= len ||
strlcat(ret, p, len) >= len) {
free(tmp);
@@ -466,7 +485,12 @@ kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh)
{
int r;
- error("kex protocol error: type %d seq %u", type, seq);
+ /* If in strict mode, any unexpected message is an error */
+ if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) {
+ ssh_packet_disconnect(ssh, "strict KEX violation: "
+ "unexpected packet type %u (seqnr %u)", type, seq);
+ }
+ error("type %u seq %u", type, seq);
if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 ||
(r = sshpkt_put_u32(ssh, seq)) != 0 ||
(r = sshpkt_send(ssh)) != 0)
@@ -548,6 +572,11 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh)
ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error);
if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0)
return r;
+ if (ninfo >= 1024) {
+ error("SSH2_MSG_EXT_INFO with too many entries, expected "
+ "<=1024, received %u", ninfo);
+ return dispatch_protocol_error(type, seq, ssh);
+ }
for (i = 0; i < ninfo; i++) {
if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0)
return r;
@@ -681,7 +705,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
if (kex == NULL)
return SSH_ERR_INVALID_ARGUMENT;
- ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL);
+ ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error);
ptr = sshpkt_ptr(ssh, &dlen);
if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0)
return r;
@@ -717,7 +741,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh)
if (!(kex->flags & KEX_INIT_SENT))
if ((r = kex_send_kexinit(ssh)) != 0)
return r;
- if ((r = kex_choose_conf(ssh)) != 0)
+ if ((r = kex_choose_conf(ssh, seq)) != 0)
return r;
if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL)
@@ -981,20 +1005,14 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX])
return (1);
}
-/* returns non-zero if proposal contains any algorithm from algs */
static int
-has_any_alg(const char *proposal, const char *algs)
+kexalgs_contains(char **peer, const char *ext)
{
- char *cp;
-
- if ((cp = match_list(proposal, algs, NULL)) == NULL)
- return 0;
- free(cp);
- return 1;
+ return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext);
}
static int
-kex_choose_conf(struct ssh *ssh)
+kex_choose_conf(struct ssh *ssh, uint32_t seq)
{
struct kex *kex = ssh->kex;
struct newkeys *newkeys;
@@ -1019,13 +1037,23 @@ kex_choose_conf(struct ssh *ssh)
sprop=peer;
}
- /* Check whether client supports ext_info_c */
- if (kex->server && (kex->flags & KEX_INITIAL)) {
- char *ext;
-
- ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL);
- kex->ext_info_c = (ext != NULL);
- free(ext);
+ /* Check whether peer supports ext_info/kex_strict */
+ if ((kex->flags & KEX_INITIAL) != 0) {
+ if (kex->server) {
+ kex->ext_info_c = kexalgs_contains(peer, "ext-info-c");
+ kex->kex_strict = kexalgs_contains(peer,
+ "kex-strict-c-v00@openssh.com");
+ } else {
+ kex->kex_strict = kexalgs_contains(peer,
+ "kex-strict-s-v00@openssh.com");
+ }
+ if (kex->kex_strict) {
+ debug3("will use strict KEX ordering");
+ if (seq != 0)
+ ssh_packet_disconnect(ssh,
+ "strict KEX violation: "
+ "KEXINIT was not the first packet");
+ }
}
/* Check whether client supports rsa-sha2 algorithms */
diff --git a/kex.h b/kex.h
index 5f7ef784..272ebb43 100644
--- a/kex.h
+++ b/kex.h
@@ -149,6 +149,7 @@ struct kex {
u_int kex_type;
char *server_sig_algs;
int ext_info_c;
+ int kex_strict;
struct sshbuf *my;
struct sshbuf *peer;
struct sshbuf *client_version;
diff --git a/packet.c b/packet.c
index 52017def..beb214f9 100644
--- a/packet.c
+++ b/packet.c
@@ -1207,8 +1207,13 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
sshbuf_dump(state->output, stderr);
#endif
/* increment sequence number for outgoing packets */
- if (++state->p_send.seqnr == 0)
+ if (++state->p_send.seqnr == 0) {
+ if ((ssh->kex->flags & KEX_INITIAL) != 0) {
+ ssh_packet_disconnect(ssh, "outgoing sequence number "
+ "wrapped during initial key exchange");
+ }
logit("outgoing seqnr wraps around");
+ }
if (++state->p_send.packets == 0)
if (!(ssh->compat & SSH_BUG_NOREKEY))
return SSH_ERR_NEED_REKEY;
@@ -1216,6 +1221,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh)
state->p_send.bytes += len;
sshbuf_reset(state->outgoing_packet);
+ if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
+ debug("resetting send seqnr %u", state->p_send.seqnr);
+ state->p_send.seqnr = 0;
+ }
+
if (type == SSH2_MSG_NEWKEYS)
r = ssh_set_newkeys(ssh, MODE_OUT);
else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side)
@@ -1344,8 +1354,7 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
/* Stay in the loop until we have received a complete packet. */
for (;;) {
/* Try to read a packet from the buffer. */
- r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p);
- if (r != 0)
+ if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p)) != 0)
break;
/* If we got a packet, return it. */
if (*typep != SSH_MSG_NONE)
@@ -1629,10 +1615,16 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0)
goto out;
}
+
if (seqnr_p != NULL)
*seqnr_p = state->p_read.seqnr;
- if (++state->p_read.seqnr == 0)
+ if (++state->p_read.seqnr == 0) {
+ if ((ssh->kex->flags & KEX_INITIAL) != 0) {
+ ssh_packet_disconnect(ssh, "incoming sequence number "
+ "wrapped during initial key exchange");
+ }
logit("incoming seqnr wraps around");
+ }
if (++state->p_read.packets == 0)
if (!(ssh->compat & SSH_BUG_NOREKEY))
return SSH_ERR_NEED_REKEY;
@@ -1698,6 +1690,10 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
#endif
/* reset for next packet */
state->packlen = 0;
+ if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) {
+ debug("resetting read seqnr %u", state->p_read.seqnr);
+ state->p_read.seqnr = 0;
+ }
/* do we need to rekey? */
if (ssh_packet_need_rekeying(ssh, 0)) {
@@ -1720,10 +1716,39 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
r = ssh_packet_read_poll2(ssh, typep, seqnr_p);
if (r != 0)
return r;
- if (*typep) {
- state->keep_alive_timeouts = 0;
- DBG(debug("received packet type %d", *typep));
+ if (*typep == 0) {
+ /* no message ready */
+ return 0;
}
+ state->keep_alive_timeouts = 0;
+ DBG(debug("received packet type %d", *typep));
+
+ /* Always process disconnect messages */
+ if (*typep == SSH2_MSG_DISCONNECT) {
+ if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
+ return r;
+ /* Ignore normal client exit notifications */
+ do_log2(ssh->state->server_side &&
+ reason == SSH2_DISCONNECT_BY_APPLICATION ?
+ SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
+ "Received disconnect from %s port %d:"
+ "%u: %.400s", ssh_remote_ipaddr(ssh),
+ ssh_remote_port(ssh), reason, msg);
+ free(msg);
+ return SSH_ERR_DISCONNECTED;
+ }
+
+ /*
+ * Do not implicitly handle any messages here during initial
+ * KEX when in strict mode. They will be need to be allowed
+ * explicitly by the KEX dispatch table or they will generate
+ * protocol errors.
+ */
+ if (ssh->kex != NULL &&
+ (ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict)
+ return 0;
+ /* Implicitly handle transport-level messages */
switch (*typep) {
case SSH2_MSG_IGNORE:
debug3("Received SSH2_MSG_IGNORE");
@@ -1738,19 +1763,6 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p)
debug("Remote: %.900s", msg);
free(msg);
break;
- case SSH2_MSG_DISCONNECT:
- if ((r = sshpkt_get_u32(ssh, &reason)) != 0 ||
- (r = sshpkt_get_string(ssh, &msg, NULL)) != 0)
- return r;
- /* Ignore normal client exit notifications */
- do_log2(ssh->state->server_side &&
- reason == SSH2_DISCONNECT_BY_APPLICATION ?
- SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR,
- "Received disconnect from %s port %d:"
- "%u: %.400s", ssh_remote_ipaddr(ssh),
- ssh_remote_port(ssh), reason, msg);
- free(msg);
- return SSH_ERR_DISCONNECTED;
case SSH2_MSG_UNIMPLEMENTED:
if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0)
return r;
@@ -2242,6 +2254,7 @@ kex_to_blob(struct sshbuf *m, struct kex *kex)
(r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 ||
(r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 ||
(r = sshbuf_put_u32(m, kex->kex_type)) != 0 ||
+ (r = sshbuf_put_u32(m, kex->kex_strict)) != 0 ||
(r = sshbuf_put_stringb(m, kex->my)) != 0 ||
(r = sshbuf_put_stringb(m, kex->peer)) != 0 ||
(r = sshbuf_put_stringb(m, kex->client_version)) != 0 ||
@@ -2404,6 +2417,7 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp)
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 ||
(r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 ||
(r = sshbuf_get_u32(m, &kex->kex_type)) != 0 ||
+ (r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 ||
(r = sshbuf_get_stringb(m, kex->my)) != 0 ||
(r = sshbuf_get_stringb(m, kex->peer)) != 0 ||
(r = sshbuf_get_stringb(m, kex->client_version)) != 0 ||
@@ -2732,6 +2746,7 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...)
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
+ debug2("sending SSH2_MSG_DISCONNECT: %s", buf);
if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 ||
(r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 ||
(r = sshpkt_put_cstring(ssh, buf)) != 0 ||
diff --git a/sshconnect2.c b/sshconnect2.c
index df6caf81..0cccbcc4 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -253,7 +253,8 @@ ssh_kex2(struct ssh *ssh, char *host, st
xxx_host = host;
xxx_hostaddr = hostaddr;
- if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
+ if ((s = kex_names_cat(options.kex_algorithms,
+ "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL)
fatal("%s: kex_names_cat", __func__);
myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(s);
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
@@ -358,7 +358,6 @@ struct cauthmethod {
};
static int input_userauth_service_accept(int, u_int32_t, struct ssh *);
-static int input_userauth_ext_info(int, u_int32_t, struct ssh *);
static int input_userauth_success(int, u_int32_t, struct ssh *);
static int input_userauth_failure(int, u_int32_t, struct ssh *);
static int input_userauth_banner(int, u_int32_t, struct ssh *);
@@ -472,7 +471,7 @@ ssh_userauth2(struct ssh *ssh, const char *local_user,
ssh->authctxt = &authctxt;
ssh_dispatch_init(ssh, &input_userauth_error);
- ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info);
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info);
ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept);
ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */
pubkey_cleanup(ssh);
@@ -531,12 +530,6 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh)
}
/* ARGSUSED */
-static int
-input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh)
-{
- return kex_input_ext_info(type, seqnr, ssh);
-}
-
void
userauth(struct ssh *ssh, char *authlist)
{
@@ -615,6 +608,7 @@ input_userauth_success(int type, u_int32_t seq, struct ssh *ssh)
free(authctxt->methoddata);
authctxt->methoddata = NULL;
authctxt->success = 1; /* break out */
+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error);
return 0;
}
diff -up openssh-8.7p1/sshd.c.kexstrict openssh-8.7p1/sshd.c
--- openssh-8.7p1/sshd.c.kexstrict 2023-11-27 13:19:18.855433602 +0100
+++ openssh-8.7p1/sshd.c 2023-11-27 13:28:10.441325314 +0100
@@ -2531,10 +2531,14 @@ do_ssh2_kex(struct ssh *ssh)
{
char *myproposal[PROPOSAL_MAX] = { KEX_SERVER };
struct kex *kex;
+ char *cp;
int r;
- myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(
- options.kex_algorithms);
+ if ((cp = kex_names_cat(options.kex_algorithms,
+ "kex-strict-s-v00@openssh.com")) == NULL)
+ fatal("kex_names_cat");
+
+ myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(cp);
myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(
options.ciphers);
myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(
@@ -2586,7 +2586,7 @@ do_ssh2_kex(struct ssh *ssh)
if (gss && orig)
xasprintf(&newstr, "%s,%s", gss, orig);
else if (gss)
- newstr = gss;
+ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com");
else if (orig)
newstr = orig;
@@ -2650,6 +2654,7 @@ do_ssh2_kex(struct ssh *ssh)
packet_send();
packet_write_wait();
#endif
+ free(cp);
debug("KEX done");
}

View File

@ -0,0 +1,57 @@
diff --git a/ssh.c b/ssh.c
index 35c48e62..48d93ddf 100644
--- a/ssh.c
+++ b/ssh.c
@@ -626,6 +626,41 @@ ssh_conn_info_free(struct ssh_conn_info *cinfo)
}
}
+static int
+valid_hostname(const char *s)
+{
+ size_t i;
+
+ if (*s == '-')
+ return 0;
+ for (i = 0; s[i] != 0; i++) {
+ if (strchr("'`\"$\\;&<>|(){}", s[i]) != NULL ||
+ isspace((u_char)s[i]) || iscntrl((u_char)s[i]))
+ return 0;
+ }
+ return 1;
+}
+
+static int
+valid_ruser(const char *s)
+{
+ size_t i;
+
+ if (*s == '-')
+ return 0;
+ for (i = 0; s[i] != 0; i++) {
+ if (strchr("'`\";&<>|(){}", s[i]) != NULL)
+ return 0;
+ /* Disallow '-' after whitespace */
+ if (isspace((u_char)s[i]) && s[i + 1] == '-')
+ return 0;
+ /* Disallow \ in last position */
+ if (s[i] == '\\' && s[i + 1] == '\0')
+ return 0;
+ }
+ return 1;
+}
+
/*
* Main program for the ssh client.
*/
@@ -1118,6 +1153,10 @@ main(int ac, char **av)
if (!host)
usage();
+ if (!valid_hostname(host))
+ fatal("hostname contains invalid characters");
+ if (options.user != NULL && !valid_ruser(options.user))
+ fatal("remote username contains invalid characters");
host_arg = xstrdup(host);
/* Initialize the command to execute on remote host. */

View File

@ -66,14 +66,14 @@
# Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1
%global openssh_ver 8.0p1
%global openssh_rel 13
%global openssh_rel 19
%global pam_ssh_agent_ver 0.10.3
%global pam_ssh_agent_rel 7
Summary: An open source implementation of SSH protocol version 2
Name: openssh
Version: %{openssh_ver}
Release: %{openssh_rel}%{?dist}%{?rescue_rel}
Release: %{openssh_rel}%{?dist}%{?rescue_rel}.2
URL: http://www.openssh.com/portable.html
#URL1: http://pamsshagentauth.sourceforge.net
Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz
@ -252,11 +252,38 @@ Patch980: openssh-8.7p1-upstream-cve-2021-41617.patch
# c2bd7f74b0e0f3a3ee9d19ac549e6ba89013abaf~1..677d0ece67634262b3b96c3cd6410b19f3a603b7
# 8bdc3bb7cf4c82c3344cfcb82495a43406e87e83
# 47adfdc07f4f8ea0064a1495500244de08d311ed~1..7af1e92cd289b7eaa9a683e9a6f2fddd98f37a01
# supplementary commit 612b1dd1ec91ffb1e01f58cca0c6eb1d47bf4423
Patch981: openssh-8.0p1-sshd_include.patch
# Port upstream ClientAliveCountMax behaviour
# upstream commit:
# 69334996ae203c51c70bf01d414c918a44618f8e
Patch982: openssh-8.0p1-client_alive_count_max.patch
# add a local implementation of BSD realpath() for sftp-server
# use ahead of OpenBSD's realpath changing to match POSIX
# upstream commits:
# 569b650f93b561c09c655f83f128e1dfffe74101
# 53a6ebf1445a857f5e487b18ee5e5830a9575149
# 5428b0d239f6b516c81d1dd15aa9fe9e60af75d4
Patch983: openssh-8.0p1-sftp-realpath.patch
# include caveat for crypto-policy in sshd manpage (#2044354)
Patch984: openssh-8.0p1-crypto-policy-doc.patch
# minimize the use of SHA1 as a proof of possession for RSA key (#2093897)
# upstream commits:
# 291721bc7c840d113a49518f3fca70e86248b8e8
# 0fa33683223c76289470a954404047bc762be84c
# f8df0413f0a057b6a3d3dd7bd8bc7c5d80911d3a
Patch985: openssh-8.7p1-minimize-sha1-use.patch
# Upstream ff89b1bed80721295555bd083b173247a9c0484e
Patch986: openssh-9.1p1-sshbanner.patch
# Upstream 25e3bccbaa63d27b9d5e09c123f1eb28594d2bd6
Patch987: openssh-8.0p1-ipv6-process.patch
# upsream commit
# b23fe83f06ee7e721033769cfa03ae840476d280
Patch1015: openssh-9.3p1-upstream-cve-2023-38408.patch
#upstream commit 1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5
Patch1018: openssh-9.6p1-CVE-2023-48795.patch
#upstream commit 7ef3787c84b6b524501211b11a26c742f829af1a
Patch1019: openssh-9.6p1-CVE-2023-51385.patch
License: BSD
Group: Applications/Internet
@ -349,7 +376,7 @@ Requires: openssh = %{version}-%{release}
Summary: PAM module for authentication with ssh-agent
Group: System Environment/Base
Version: %{pam_ssh_agent_ver}
Release: %{pam_ssh_agent_rel}.%{openssh_rel}%{?dist}%{?rescue_rel}
Release: %{pam_ssh_agent_rel}.%{openssh_rel}%{?dist}%{?rescue_rel}.2
License: BSD
%description
@ -485,6 +512,11 @@ popd
%patch980 -p1 -b .cve-2021-41617
%patch981 -p1 -b .sshdinclude
%patch982 -p1 -b .client_alive_count_max
%patch983 -p1 -b .sftp-realpath
%patch984 -p1 -b .crypto-policy-doc
%patch985 -p1 -b .minimize-sha1-use
%patch986 -p1 -b .banner
%patch987 -p1 -b .sftp_ipv6
%patch200 -p1 -b .audit
%patch201 -p1 -b .audit-race
@ -492,6 +524,10 @@ popd
%patch100 -p1 -b .coverity
%patch1015 -p1 -b .cve-2023-38408
%patch1018 -p1 -b .cve-2023-48795
%patch1019 -p1 -b .cve-2023-51385
autoreconf
pushd pam_ssh_agent_auth-%{pam_ssh_agent_ver}
autoreconf
@ -776,6 +812,43 @@ getent passwd sshd >/dev/null || \
%endif
%changelog
* Mon Jan 08 2024 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-19.2
- Fix Terrapin attack
Resolves: RHEL-19762
* Thu Dec 21 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-19.1
- Fix Terrapin attack
Resolves: RHEL-19762
- Forbid shell metasymbols in username/hostname
Resolves: RHEL-19820
* Thu Aug 24 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-19
- rebuilt
Related: CVE-2023-38408
* Thu Jul 20 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-18
- Avoid remote code execution in ssh-agent PKCS#11 support
Resolves: CVE-2023-38408
* Tue Dec 20 2022 Dmitry Belyavskiy - 8.0p1-17
- Fix parsing of IPv6 IPs in sftp client (#2151334)
- Avoid ssh banner one-byte overflow (#2138344)
- Avoid crash of sshd when Include folder does not exist (#2133087)
* Wed Jun 29 2022 Zoltan Fridrich <zfridric@redhat.com> - 8.0p1-16
- Omit client side from minimize-sha1-use.patch to prevent regression (#2093897)
* Thu Jun 23 2022 Zoltan Fridrich <zfridric@redhat.com> - 8.0p1-15
- Fix new issues found by static analyzers
* Wed Jun 01 2022 Zoltan Fridrich <zfridric@redhat.com> - 8.0p1-14
- Upstream: add a local implementation of BSD realpath() for sftp-server (#2064249)
- Change product name from Fedora to RHEL in openssh-7.8p1-UsePAM-warning.patch (#1953807)
- Include caveat for crypto-policy in sshd manpage (#2044354)
- Change log level of FIPS specific log message to verbose (#2050511)
- Clarify force_file_perms (-m) documentation in sftp-server manpage (#1862504)
- Minimize the use of SHA1 as a proof of possession for RSA key (#2093897)
* Tue Oct 26 2021 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.0p1-13
- Upstream: ClientAliveCountMax=0 disable the connection killing behaviour (#2015828)