Add patches from CentOS/RHEL9.1

Related: rhbz#2117264
This commit is contained in:
Dmitry Belyavskiy 2022-08-10 15:08:21 +02:00
parent 14d7b86a50
commit 9fd6981674
18 changed files with 2204 additions and 99 deletions

View File

@ -101,22 +101,6 @@ diff -up openssh-7.4p1/channels.c.coverity openssh-7.4p1/channels.c
return idx;
}
diff -up openssh-8.5p1/compat.c.coverity openssh-8.5p1/compat.c
--- openssh-8.5p1/compat.c.coverity 2021-03-24 12:03:33.768968062 +0100
+++ openssh-8.5p1/compat.c 2021-03-24 12:03:33.783968166 +0100
@@ -191,10 +191,12 @@ compat_kex_proposal(struct ssh *ssh, cha
return p;
debug2_f("original KEX proposal: %s", p);
if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
+ /* coverity[overwrite_var : FALSE] */
if ((p = match_filter_denylist(p,
"curve25519-sha256@libssh.org")) == NULL)
fatal("match_filter_denylist failed");
if ((ssh->compat & SSH_OLD_DHGEX) != 0) {
+ /* coverity[overwrite_var : FALSE] */
if ((p = match_filter_denylist(p,
"diffie-hellman-group-exchange-sha256,"
"diffie-hellman-group-exchange-sha1")) == NULL)
diff -up openssh-8.5p1/dns.c.coverity openssh-8.5p1/dns.c
--- openssh-8.5p1/dns.c.coverity 2021-03-02 11:31:47.000000000 +0100
+++ openssh-8.5p1/dns.c 2021-03-24 12:03:33.783968166 +0100
@ -419,15 +403,6 @@ diff -up openssh-7.4p1/sftp.c.coverity openssh-7.4p1/sftp.c
}
_exit(1);
@@ -762,6 +762,8 @@ process_put(struct sftp_conn *conn, cons
fflag || global_fflag) == -1)
err = -1;
}
+ free(abs_dst);
+ abs_dst = NULL;
}
out:
@@ -985,6 +987,7 @@ do_globbed_ls(struct sftp_conn *conn, co
if (lflag & LS_LONG_VIEW) {
if (g.gl_statv[i] == NULL) {
@ -436,6 +411,30 @@ diff -up openssh-7.4p1/sftp.c.coverity openssh-7.4p1/sftp.c
continue;
}
lname = ls_file(fname, g.gl_statv[i], 1,
diff --git a/sftp-client.c b/sftp-client.c
index 9de9afa20f..ea98d9f8d0 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -2195,6 +2195,7 @@ handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous,
(*nreqsp)--;
}
debug3_f("done: %u outstanding replies", *nreqsp);
+ sshbuf_free(msg);
}
int
diff --git a/sftp-server.c b/sftp-server.c
index 18d1949112..6380c4dd23 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1553,6 +1553,7 @@ process_extended_expand(u_int32_t id)
npath = xstrdup(path + 2);
free(path);
xasprintf(&path, "%s/%s", cwd, npath);
+ free(npath);
} else {
/* ~user expansions */
if (tilde_expand(path, pw->pw_uid, &npath) != 0) {
diff -up openssh-8.5p1/sk-usbhid.c.coverity openssh-8.5p1/sk-usbhid.c
--- openssh-8.5p1/sk-usbhid.c.coverity 2021-03-02 11:31:47.000000000 +0100
+++ openssh-8.5p1/sk-usbhid.c 2021-03-24 12:03:33.786968187 +0100
@ -505,15 +504,6 @@ diff -up openssh-7.4p1/sshd.c.coverity openssh-7.4p1/sshd.c
}
/*
@@ -2474,7 +2479,7 @@ do_ssh2_kex(struct ssh *ssh)
if (options.rekey_limit || options.rekey_interval)
ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
options.rekey_interval);
-
+ /* coverity[leaked_storage : FALSE]*/
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
ssh, list_hostkey_types());
@@ -2519,8 +2524,11 @@ do_ssh2_kex(struct ssh *ssh)
if (newstr)

View File

@ -1,16 +1,3 @@
diff -up openssh-8.6p1/cipher-ctr.c.fips openssh-8.6p1/cipher-ctr.c
--- openssh-8.6p1/cipher-ctr.c.fips 2021-04-19 16:53:02.994577324 +0200
+++ openssh-8.6p1/cipher-ctr.c 2021-04-19 16:53:03.064577862 +0200
@@ -179,7 +179,8 @@ evp_aes_128_ctr(void)
aes_ctr.do_cipher = ssh_aes_ctr;
#ifndef SSH_OLD_EVP
aes_ctr.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH |
- EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV;
+ EVP_CIPH_ALWAYS_CALL_INIT | EVP_CIPH_CUSTOM_IV |
+ EVP_CIPH_FLAG_FIPS;
#endif
return (&aes_ctr);
}
diff -up openssh-8.6p1/dh.c.fips openssh-8.6p1/dh.c
--- openssh-8.6p1/dh.c.fips 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/dh.c 2021-04-19 16:58:47.750263410 +0200
@ -19,7 +6,7 @@ diff -up openssh-8.6p1/dh.c.fips openssh-8.6p1/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));
+ }
@ -116,8 +103,8 @@ diff -up openssh-8.6p1/kexgexc.c.fips openssh-8.6p1/kexgexc.c
/* generate and send 'e', client DH public key */
diff -up openssh-8.6p1/myproposal.h.fips openssh-8.6p1/myproposal.h
--- openssh-8.6p1/myproposal.h.fips 2021-04-16 05:55:25.000000000 +0200
+++ openssh-8.6p1/myproposal.h 2021-04-19 16:53:03.065577869 +0200
@@ -57,6 +57,19 @@
+++ openssh-8.6p1/myproposal.h 2021-05-06 12:08:36.498926877 +0200
@@ -57,6 +57,18 @@
"rsa-sha2-512," \
"rsa-sha2-256"
@ -127,12 +114,11 @@ diff -up openssh-8.6p1/myproposal.h.fips openssh-8.6p1/myproposal.h
+ "ecdsa-sha2-nistp521-cert-v01@openssh.com," \
+ "rsa-sha2-512-cert-v01@openssh.com," \
+ "rsa-sha2-256-cert-v01@openssh.com," \
+ "ssh-rsa-cert-v01@openssh.com," \
+ "ecdsa-sha2-nistp256," \
+ "ecdsa-sha2-nistp384," \
+ "ecdsa-sha2-nistp521," \
+ "rsa-sha2-512," \
+ "rsa-sha2-256,"
+ "rsa-sha2-256"
+
#define KEX_SERVER_ENCRYPT \
"chacha20-poly1305@openssh.com," \
@ -358,6 +344,20 @@ diff -up openssh-8.6p1/sshd.c.fips openssh-8.6p1/sshd.c
/* Save argv. Duplicate so setproctitle emulation doesn't clobber it */
saved_argc = ac;
rexec_argc = ac;
@@ -1931,6 +1931,13 @@ main(int ac, char **av)
&key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
do_log2_r(r, ll, "Unable to load host key \"%s\"",
options.host_key_files[i]);
+ if (FIPS_mode() && key != NULL && (sshkey_type_plain(key->type) == KEY_ED25519_SK
+ || sshkey_type_plain(key->type) == KEY_ED25519)) {
+ logit_f("sshd: Ed25519 keys are not allowed in FIPS mode, skipping %s", options.host_key_files[i]);
+ sshkey_free(key);
+ key = NULL;
+ continue;
+ }
if (sshkey_is_sk(key) &&
key->sk_flags & SSH_SK_USER_PRESENCE_REQD) {
debug("host key %s requires user presence, ignoring",
@@ -2110,6 +2113,10 @@ main(int ac, char **av)
/* Reinitialize the log (because of the fork above). */
log_init(__progname, options.log_level, options.log_facility, log_stderr);
@ -407,15 +407,78 @@ diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c
#include "ssh-sk.h"
#ifdef WITH_XMSS
@@ -1705,6 +1707,8 @@ rsa_generate_private_key(u_int bits, RSA
@@ -285,6 +285,18 @@ sshkey_alg_list(int certs_only, int plai
for (kt = keytypes; kt->type != -1; kt++) {
if (kt->name == NULL || kt->type == KEY_NULL)
continue;
+ if (FIPS_mode()) {
+ switch (kt->type) {
+ case KEY_ED25519:
+ case KEY_ED25519_SK:
+ case KEY_ED25519_CERT:
+ case KEY_ED25519_SK_CERT:
+ continue;
+ break;
+ default:
+ break;
+ }
+ }
if (!include_sigonly && kt->sigonly)
continue;
if ((certs_only && !kt->cert) || (plain_only && kt->cert))
@@ -1503,6 +1503,20 @@ sshkey_read(struct sshkey *ret, char **c
return SSH_ERR_EC_CURVE_MISMATCH;
}
if (!BN_set_word(f4, RSA_F4) ||
!RSA_generate_key_ex(private, bits, f4, NULL)) {
+ switch (type) {
+ case KEY_ED25519:
+ case KEY_ED25519_SK:
+ case KEY_ED25519_CERT:
+ case KEY_ED25519_SK_CERT:
+ if (FIPS_mode()) {
+ sshkey_free(k);
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
+ break;
+ default:
+ break;
+ }
/* Fill in ret from parsed key */
ret->type = type;
if (sshkey_is_cert(ret)) {
@@ -1705,6 +1707,8 @@ rsa_generate_private_key(u_int bits, RSA
goto out;
if (EVP_PKEY_keygen(ctx, &res) <= 0) {
+ if (FIPS_mode())
+ logit_f("the key length might be unsupported by FIPS mode approved key generation method");
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
@@ -2916,6 +2916,11 @@ sshkey_sign(struct sshkey *key,
break;
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
+ if (FIPS_mode()) {
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
+ /* Fallthrough */
case KEY_ECDSA_SK_CERT:
case KEY_ECDSA_SK:
r = sshsk_sign(sk_provider, key, sigp, lenp, data,
@@ -2973,6 +2978,10 @@ sshkey_verify(const struct sshkey *key,
return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat);
case KEY_ED25519_SK:
case KEY_ED25519_SK_CERT:
+ if (FIPS_mode()) {
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
return ssh_ed25519_sk_verify(key, sig, siglen, data, dlen,
compat, detailsp);
#ifdef WITH_XMSS
diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c
--- openssh-8.6p1/ssh-keygen.c.fips 2021-04-19 16:53:03.038577662 +0200
+++ openssh-8.6p1/ssh-keygen.c 2021-04-19 16:53:03.068577892 +0200
@ -426,7 +489,7 @@ diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c
+ if (FIPS_mode()) {
+ if (type == KEY_DSA)
+ fatal("DSA keys are not allowed in FIPS mode");
+ if (type == KEY_ED25519)
+ if (type == KEY_ED25519 || type == KEY_ED25519_SK)
+ fatal("ED25519 keys are not allowed in FIPS mode");
+ }
switch (type) {
@ -451,3 +514,122 @@ diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c
if ((fd = mkstemp(prv_tmp)) == -1) {
error("Could not save your private key in %s: %s",
prv_tmp, strerror(errno));
diff -up openssh-8.7p1/kexgen.c.fips3 openssh-8.7p1/kexgen.c
--- openssh-8.7p1/kexgen.c.fips3 2022-07-11 16:11:21.973519913 +0200
+++ openssh-8.7p1/kexgen.c 2022-07-11 16:25:31.172187365 +0200
@@ -31,6 +31,7 @@
#include <stdio.h>
#include <string.h>
#include <signal.h>
+#include <openssl/crypto.h>
#include "sshkey.h"
#include "kex.h"
@@ -115,10 +116,20 @@ kex_gen_client(struct ssh *ssh)
break;
#endif
case KEX_C25519_SHA256:
- r = kex_c25519_keypair(kex);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type c25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_c25519_keypair(kex);
+ }
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
- r = kex_kem_sntrup761x25519_keypair(kex);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_sntrup761x25519_keypair(kex);
+ }
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
@@ -186,11 +197,21 @@ input_kex_gen_reply(int type, u_int32_t
break;
#endif
case KEX_C25519_SHA256:
- r = kex_c25519_dec(kex, server_blob, &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type c25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_c25519_dec(kex, server_blob, &shared_secret);
+ }
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
- r = kex_kem_sntrup761x25519_dec(kex, server_blob,
- &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_sntrup761x25519_dec(kex, server_blob,
+ &shared_secret);
+ }
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
@@ -285,12 +306,22 @@ input_kex_gen_init(int type, u_int32_t s
break;
#endif
case KEX_C25519_SHA256:
- r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
- &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type c25519 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
+ &shared_secret);
+ }
break;
case KEX_KEM_SNTRUP761X25519_SHA512:
- r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
- &server_pubkey, &shared_secret);
+ if (FIPS_mode()) {
+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode");
+ r = SSH_ERR_INVALID_ARGUMENT;
+ } else {
+ r = kex_kem_sntrup761x25519_enc(kex, client_pubkey,
+ &server_pubkey, &shared_secret);
+ }
break;
default:
r = SSH_ERR_INVALID_ARGUMENT;
diff -up openssh-8.7p1/ssh-ed25519.c.fips3 openssh-8.7p1/ssh-ed25519.c
--- openssh-8.7p1/ssh-ed25519.c.fips3 2022-07-11 16:53:41.428343304 +0200
+++ openssh-8.7p1/ssh-ed25519.c 2022-07-11 16:56:09.284663661 +0200
@@ -24,6 +24,7 @@
#include <string.h>
#include <stdarg.h>
+#include <openssl/crypto.h>
#include "log.h"
#include "sshbuf.h"
@@ -52,6 +53,10 @@ ssh_ed25519_sign(const struct sshkey *ke
key->ed25519_sk == NULL ||
datalen >= INT_MAX - crypto_sign_ed25519_BYTES)
return SSH_ERR_INVALID_ARGUMENT;
+ if (FIPS_mode()) {
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
smlen = slen = datalen + crypto_sign_ed25519_BYTES;
if ((sig = malloc(slen)) == NULL)
return SSH_ERR_ALLOC_FAIL;
@@ -108,6 +113,10 @@ ssh_ed25519_verify(const struct sshkey *
datalen >= INT_MAX - crypto_sign_ed25519_BYTES ||
signature == NULL || signaturelen == 0)
return SSH_ERR_INVALID_ARGUMENT;
+ if (FIPS_mode()) {
+ logit_f("Ed25519 keys are not allowed in FIPS mode");
+ return SSH_ERR_INVALID_ARGUMENT;
+ }
if ((b = sshbuf_from(signature, signaturelen)) == NULL)
return SSH_ERR_ALLOC_FAIL;

View File

@ -1,13 +1,13 @@
diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
--- openssh-8.7p1/ssh_config.5.crypto-policies 2021-08-30 13:29:00.174292872 +0200
+++ openssh-8.7p1/ssh_config.5 2021-08-30 13:31:32.009548808 +0200
@@ -373,17 +373,13 @@ or
diff --color -ru a/ssh_config.5 b/ssh_config.5
--- a/ssh_config.5 2022-07-12 15:05:22.550013071 +0200
+++ b/ssh_config.5 2022-07-12 15:17:20.016704545 +0200
@@ -373,17 +373,13 @@
causes no CNAMEs to be considered for canonicalization.
This is the default behaviour.
.It Cm CASignatureAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies which algorithms are allowed for signing of certificates
@ -24,13 +24,13 @@ diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
If the specified list begins with a
.Sq +
character, then the specified algorithms will be appended to the default set
@@ -445,20 +441,25 @@ If the option is set to
@@ -445,20 +441,25 @@
(the default),
the check will not be executed.
.It Cm Ciphers
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the ciphers allowed and their order of preference.
@ -54,7 +54,7 @@ diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
.Pp
The supported ciphers are:
.Bd -literal -offset indent
@@ -474,13 +475,6 @@ aes256-gcm@openssh.com
@@ -474,13 +475,6 @@
chacha20-poly1305@openssh.com
.Ed
.Pp
@ -68,19 +68,19 @@ diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
The list of available ciphers may also be obtained using
.Qq ssh -Q cipher .
.It Cm ClearAllForwardings
@@ -874,6 +868,11 @@ command line will be passed untouched to
@@ -874,6 +868,11 @@
The default is
.Dq no .
.It Cm GSSAPIKexAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
The list of key exchange algorithms that are offered for GSSAPI
key exchange. Possible values are
.Bd -literal -offset 3n
@@ -886,10 +885,8 @@ gss-nistp256-sha256-,
@@ -886,10 +885,8 @@
gss-curve25519-sha256-
.Ed
.Pp
@ -92,13 +92,13 @@ diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
.It Cm HashKnownHosts
Indicates that
.Xr ssh 1
@@ -1219,29 +1216,25 @@ it may be zero or more of:
@@ -1219,29 +1216,25 @@
and
.Cm pam .
.It Cm KexAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the available KEX (Key Exchange) algorithms.
@ -107,7 +107,7 @@ diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
.Sq +
-character, then the specified algorithms will be appended to the default set
-instead of replacing them.
+character, then the specified algorithms will be appended to the built-in
+character, then the specified methods will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
@ -131,13 +131,13 @@ diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
.Pp
The list of available key exchange algorithms may also be obtained using
.Qq ssh -Q kex .
@@ -1351,37 +1344,33 @@ function, and all code in the
@@ -1351,37 +1344,33 @@
file.
This option is intended for debugging and no overrides are enabled by default.
.It Cm MACs
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the MAC (message authentication code) algorithms
@ -178,13 +178,13 @@ diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
The list of available MAC algorithms may also be obtained using
.Qq ssh -Q mac .
.It Cm NoHostAuthenticationForLocalhost
@@ -1553,36 +1542,25 @@ instead of continuing to execute and pas
@@ -1553,36 +1542,25 @@
The default is
.Cm no .
.It Cm PubkeyAcceptedAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the signature algorithms that will be used for public key
@ -224,16 +224,16 @@ diff -up openssh-8.7p1/ssh_config.5.crypto-policies openssh-8.7p1/ssh_config.5
.Pp
The list of available signature algorithms may also be obtained using
.Qq ssh -Q PubkeyAcceptedAlgorithms .
diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
--- openssh-8.7p1/sshd_config.5.crypto-policies 2021-08-30 13:29:00.157292731 +0200
+++ openssh-8.7p1/sshd_config.5 2021-08-30 13:32:16.263918533 +0200
@@ -373,17 +373,13 @@ If the argument is
diff --color -ru a/sshd_config.5 b/sshd_config.5
--- a/sshd_config.5 2022-07-12 15:05:22.535012771 +0200
+++ b/sshd_config.5 2022-07-12 15:15:33.394809258 +0200
@@ -373,17 +373,13 @@
then no banner is displayed.
By default, no banner is displayed.
.It Cm CASignatureAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies which algorithms are allowed for signing of certificates
@ -250,13 +250,13 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
If the specified list begins with a
.Sq +
character, then the specified algorithms will be appended to the default set
@@ -450,20 +446,25 @@ The default is
@@ -450,20 +446,25 @@
indicating not to
.Xr chroot 2 .
.It Cm Ciphers
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the ciphers allowed.
@ -280,7 +280,7 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
.Pp
The supported ciphers are:
.Pp
@@ -490,13 +491,6 @@ aes256-gcm@openssh.com
@@ -490,13 +491,6 @@
chacha20-poly1305@openssh.com
.El
.Pp
@ -294,13 +294,13 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
The list of available ciphers may also be obtained using
.Qq ssh -Q cipher .
.It Cm ClientAliveCountMax
@@ -685,21 +679,22 @@ For this to work
@@ -685,21 +679,22 @@
.Cm GSSAPIKeyExchange
needs to be enabled in the server and also used by the client.
.It Cm GSSAPIKexAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
The list of key exchange algorithms that are accepted by GSSAPI
@ -327,13 +327,13 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
This option only applies to connections using GSSAPI.
.It Cm HostbasedAcceptedAlgorithms
Specifies the signature algorithms that will be accepted for hostbased
@@ -799,26 +794,13 @@ is specified, the location of the socket
@@ -799,26 +794,13 @@
.Ev SSH_AUTH_SOCK
environment variable.
.It Cm HostKeyAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the host key signature algorithms
@ -359,13 +359,13 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
The list of available signature algorithms may also be obtained using
.Qq ssh -Q HostKeyAlgorithms .
.It Cm IgnoreRhosts
@@ -965,20 +947,25 @@ Specifies whether to look at .k5login fi
@@ -965,20 +947,25 @@
The default is
.Cm yes .
.It Cm KexAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the available KEX (Key Exchange) algorithms.
@ -374,7 +374,7 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
.Sq +
-character, then the specified algorithms will be appended to the default set
-instead of replacing them.
+character, then the specified algorithms will be appended to the built-in
+character, then the specified methods will be appended to the built-in
+openssh default set instead of replacing them.
If the specified list begins with a
.Sq -
@ -389,7 +389,7 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
The supported algorithms are:
.Pp
.Bl -item -compact -offset indent
@@ -1010,15 +997,6 @@ ecdh-sha2-nistp521
@@ -1010,15 +997,6 @@
sntrup761x25519-sha512@openssh.com
.El
.Pp
@ -405,13 +405,13 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
The list of available key exchange algorithms may also be obtained using
.Qq ssh -Q KexAlgorithms .
.It Cm ListenAddress
@@ -1104,21 +1082,26 @@ function, and all code in the
@@ -1104,21 +1082,26 @@
file.
This option is intended for debugging and no overrides are enabled by default.
.It Cm MACs
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the available MAC (message authentication code) algorithms.
@ -436,7 +436,7 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
.Pp
The algorithms that contain
.Qq -etm
@@ -1161,15 +1144,6 @@ umac-64-etm@openssh.com
@@ -1161,15 +1144,6 @@
umac-128-etm@openssh.com
.El
.Pp
@ -452,13 +452,13 @@ diff -up openssh-8.7p1/sshd_config.5.crypto-policies openssh-8.7p1/sshd_config.5
The list of available MAC algorithms may also be obtained using
.Qq ssh -Q mac .
.It Cm Match
@@ -1548,37 +1522,25 @@ or equivalent.)
@@ -1548,37 +1522,25 @@
The default is
.Cm yes .
.It Cm PubkeyAcceptedAlgorithms
+The default is handled system-wide by
+.Xr crypto-policies 7 .
+To see the defaults and how to modify this default, see manual page
+Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page
+.Xr update-crypto-policies 8 .
+.Pp
Specifies the signature algorithms that will be accepted for public key

View File

@ -0,0 +1,110 @@
diff -up openssh-8.7p1/sshkey.c.evpgenrsa openssh-8.7p1/sshkey.c
--- openssh-8.7p1/sshkey.c.evpgenrsa 2022-06-30 15:14:58.200518353 +0200
+++ openssh-8.7p1/sshkey.c 2022-06-30 15:24:31.499641196 +0200
@@ -1657,7 +1657,8 @@ sshkey_cert_type(const struct sshkey *k)
static int
rsa_generate_private_key(u_int bits, RSA **rsap)
{
- RSA *private = NULL;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *res = NULL;
BIGNUM *f4 = NULL;
int ret = SSH_ERR_INTERNAL_ERROR;
@@ -1667,20 +1668,42 @@ rsa_generate_private_key(u_int bits, RSA
bits > SSHBUF_MAX_BIGNUM * 8)
return SSH_ERR_KEY_LENGTH;
*rsap = NULL;
- if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) {
+
+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL
+ || (f4 = BN_new()) == NULL || !BN_set_word(f4, RSA_F4)) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if (!BN_set_word(f4, RSA_F4) ||
- !RSA_generate_key_ex(private, bits, f4, NULL)) {
+
+ if (EVP_PKEY_keygen_init(ctx) <= 0) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+
+ if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) {
+ ret = SSH_ERR_KEY_LENGTH;
+ goto out;
+ }
+
+ if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, f4) <= 0)
+ goto out;
+
+ if (EVP_PKEY_keygen(ctx, &res) <= 0) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+
+ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/
+ *rsap = EVP_PKEY_get1_RSA(res);
+ if (*rsap) {
+ ret = 0;
+ } else {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
- *rsap = private;
- private = NULL;
- ret = 0;
out:
- RSA_free(private);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(res);
BN_free(f4);
return ret;
}
@@ -1820,7 +1820,8 @@ sshkey_ecdsa_key_to_nid(EC_KEY *k)
static int
ecdsa_generate_private_key(u_int bits, int *nid, EC_KEY **ecdsap)
{
- EC_KEY *private;
+ EVP_PKEY_CTX *ctx = NULL;
+ EVP_PKEY *res = NULL;
int ret = SSH_ERR_INTERNAL_ERROR;
if (nid == NULL || ecdsap == NULL)
@@ -1828,20 +1829,29 @@ ecdsa_generate_private_key(u_int bits, i
if ((*nid = sshkey_ecdsa_bits_to_nid(bits)) == -1)
return SSH_ERR_KEY_LENGTH;
*ecdsap = NULL;
- if ((private = EC_KEY_new_by_curve_name(*nid)) == NULL) {
+
+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) {
ret = SSH_ERR_ALLOC_FAIL;
goto out;
}
- if (EC_KEY_generate_key(private) != 1) {
+
+ if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_CTX_set_group_name(ctx, OBJ_nid2sn(*nid)) <= 0
+ || EVP_PKEY_keygen(ctx, &res) <= 0) {
+ ret = SSH_ERR_LIBCRYPTO_ERROR;
+ goto out;
+ }
+ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/
+ *ecdsap = EVP_PKEY_get1_EC_KEY(res);
+ if (*ecdsap) {
+ EC_KEY_set_asn1_flag(*ecdsap, OPENSSL_EC_NAMED_CURVE);
+ ret = 0;
+ } else {
ret = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
- EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE);
- *ecdsap = private;
- private = NULL;
- ret = 0;
out:
- EC_KEY_free(private);
+ EVP_PKEY_CTX_free(ctx);
+ EVP_PKEY_free(res);
return ret;
}
# endif /* OPENSSL_HAS_ECC */

View File

@ -0,0 +1,20 @@
diff --color -rup a/monitor.c b/monitor.c
--- a/monitor.c 2022-07-11 15:11:28.146863144 +0200
+++ b/monitor.c 2022-07-11 15:15:35.726655877 +0200
@@ -376,8 +376,15 @@ monitor_child_preauth(struct ssh *ssh, s
if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) {
auth_log(ssh, authenticated, partial,
auth_method, auth_submethod);
- if (!partial && !authenticated)
+ if (!partial && !authenticated) {
+#ifdef GSSAPI
+ /* If gssapi-with-mic failed, MONITOR_REQ_GSSCHECKMIC is disabled.
+ * We have to reenable it to try again for gssapi-keyex */
+ if (strcmp(auth_method, "gssapi-with-mic") == 0 && options.gss_keyex)
+ monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1);
+#endif
authctxt->failures++;
+ }
if (authenticated || partial) {
auth2_update_session_info(authctxt,
auth_method, auth_submethod);

View File

@ -0,0 +1,151 @@
diff --color -rup a/sshconnect2.c b/sshconnect2.c
--- a/sshconnect2.c 2022-07-11 17:00:02.618575727 +0200
+++ b/sshconnect2.c 2022-07-11 17:03:05.096085690 +0200
@@ -2288,9 +2288,9 @@ userauth_hostbased(struct ssh *ssh)
if (authctxt->sensitive->keys[i] == NULL ||
authctxt->sensitive->keys[i]->type == KEY_UNSPEC)
continue;
- if (match_pattern_list(
+ if (!sshkey_match_keyname_to_sigalgs(
sshkey_ssh_name(authctxt->sensitive->keys[i]),
- authctxt->active_ktype, 0) != 1)
+ authctxt->active_ktype))
continue;
/* we take and free the key */
private = authctxt->sensitive->keys[i];
@@ -2316,7 +2316,8 @@ userauth_hostbased(struct ssh *ssh)
error_f("sshkey_fingerprint failed");
goto out;
}
- debug_f("trying hostkey %s %s", sshkey_ssh_name(private), fp);
+ debug_f("trying hostkey %s %s using sigalg %s",
+ sshkey_ssh_name(private), fp, authctxt->active_ktype);
/* figure out a name for the client host */
lname = get_local_name(ssh_packet_get_connection_in(ssh));
diff --color -rup a/sshkey.c b/sshkey.c
--- a/sshkey.c 2022-07-11 17:00:02.609575554 +0200
+++ b/sshkey.c 2022-07-11 17:12:30.905976443 +0200
@@ -252,6 +252,29 @@ sshkey_ecdsa_nid_from_name(const char *n
return -1;
}
+int
+sshkey_match_keyname_to_sigalgs(const char *keyname, const char *sigalgs)
+{
+ int ktype;
+
+ if (sigalgs == NULL || *sigalgs == '\0' ||
+ (ktype = sshkey_type_from_name(keyname)) == KEY_UNSPEC)
+ return 0;
+ else if (ktype == KEY_RSA) {
+ return match_pattern_list("ssh-rsa", sigalgs, 0) == 1 ||
+ match_pattern_list("rsa-sha2-256", sigalgs, 0) == 1 ||
+ match_pattern_list("rsa-sha2-512", sigalgs, 0) == 1;
+ } else if (ktype == KEY_RSA_CERT) {
+ return match_pattern_list("ssh-rsa-cert-v01@openssh.com",
+ sigalgs, 0) == 1 ||
+ match_pattern_list("rsa-sha2-256-cert-v01@openssh.com",
+ sigalgs, 0) == 1 ||
+ match_pattern_list("rsa-sha2-512-cert-v01@openssh.com",
+ sigalgs, 0) == 1;
+ } else
+ return match_pattern_list(keyname, sigalgs, 0) == 1;
+}
+
char *
sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep)
{
diff --color -rup a/sshkey.h b/sshkey.h
--- a/sshkey.h 2022-07-11 17:00:02.603575438 +0200
+++ b/sshkey.h 2022-07-11 17:13:01.052556879 +0200
@@ -194,6 +194,10 @@ int sshkey_is_cert(const struct sshkey
int sshkey_is_sk(const struct sshkey *);
int sshkey_type_is_cert(int);
int sshkey_type_plain(int);
+
+/* Returns non-zero if key name match sigalgs pattern list. (handles RSA) */
+int sshkey_match_keyname_to_sigalgs(const char *, const char *);
+
int sshkey_to_certified(struct sshkey *);
int sshkey_drop_cert(struct sshkey *);
int sshkey_cert_copy(const struct sshkey *, struct sshkey *);
diff --color -rup a/ssh-keysign.c b/ssh-keysign.c
--- a/ssh-keysign.c 2021-08-20 06:03:49.000000000 +0200
+++ b/ssh-keysign.c 2022-07-11 17:00:23.306973667 +0200
@@ -62,7 +62,7 @@
extern char *__progname;
static int
-valid_request(struct passwd *pw, char *host, struct sshkey **ret,
+valid_request(struct passwd *pw, char *host, struct sshkey **ret, char **pkalgp,
u_char *data, size_t datalen)
{
struct sshbuf *b;
@@ -75,6 +75,8 @@ valid_request(struct passwd *pw, char *h
if (ret != NULL)
*ret = NULL;
+ if (pkalgp != NULL)
+ *pkalgp = NULL;
fail = 0;
if ((b = sshbuf_from(data, datalen)) == NULL)
@@ -122,8 +124,6 @@ valid_request(struct passwd *pw, char *h
fail++;
} else if (key->type != pktype)
fail++;
- free(pkalg);
- free(pkblob);
/* client host name, handle trailing dot */
if ((r = sshbuf_get_cstring(b, &p, &len)) != 0)
@@ -154,8 +154,19 @@ valid_request(struct passwd *pw, char *h
if (fail)
sshkey_free(key);
- else if (ret != NULL)
- *ret = key;
+ else {
+ if (ret != NULL) {
+ *ret = key;
+ key = NULL;
+ }
+ if (pkalgp != NULL) {
+ *pkalgp = pkalg;
+ pkalg = NULL;
+ }
+ }
+ sshkey_free(key);
+ free(pkalg);
+ free(pkblob);
return (fail ? -1 : 0);
}
@@ -170,7 +181,7 @@ main(int argc, char **argv)
struct passwd *pw;
int r, key_fd[NUM_KEYTYPES], i, found, version = 2, fd;
u_char *signature, *data, rver;
- char *host, *fp;
+ char *host, *fp, *pkalg;
size_t slen, dlen;
if (pledge("stdio rpath getpw dns id", NULL) != 0)
@@ -258,7 +269,7 @@ main(int argc, char **argv)
if ((r = sshbuf_get_string(b, &data, &dlen)) != 0)
fatal_r(r, "%s: buffer error", __progname);
- if (valid_request(pw, host, &key, data, dlen) < 0)
+ if (valid_request(pw, host, &key, &pkalg, data, dlen) < 0)
fatal("%s: not a valid request", __progname);
free(host);
@@ -279,7 +290,7 @@ main(int argc, char **argv)
}
if ((r = sshkey_sign(keys[i], &signature, &slen, data, dlen,
- NULL, NULL, NULL, 0)) != 0)
+ pkalg, NULL, NULL, 0)) != 0)
fatal_r(r, "%s: sshkey_sign failed", __progname);
free(data);

12
openssh-8.7p1-ibmca.patch Normal file
View File

@ -0,0 +1,12 @@
--- openssh-8.7p1/openbsd-compat/bsd-closefrom.c.orig 2022-04-12 15:47:03.815044607 +0200
+++ openssh-8.7p1/openbsd-compat/bsd-closefrom.c 2022-04-12 15:48:12.464963511 +0200
@@ -16,7 +16,7 @@
#include "includes.h"
-#ifndef HAVE_CLOSEFROM
+#if (!defined HAVE_CLOSEFROM) || (defined __s390__)
#include <sys/types.h>
#include <sys/param.h>

View File

@ -0,0 +1,156 @@
diff --color -rup a/compat.c b/compat.c
--- a/compat.c 2021-08-20 06:03:49.000000000 +0200
+++ b/compat.c 2022-07-14 17:39:23.770268440 +0200
@@ -157,11 +157,12 @@ compat_banner(struct ssh *ssh, const cha
debug_f("no match: %s", version);
}
+/* Always returns pointer to allocated memory, caller must free. */
char *
compat_cipher_proposal(struct ssh *ssh, char *cipher_prop)
{
if (!(ssh->compat & SSH_BUG_BIGENDIANAES))
- return cipher_prop;
+ return xstrdup(cipher_prop);
debug2_f("original cipher proposal: %s", cipher_prop);
if ((cipher_prop = match_filter_denylist(cipher_prop, "aes*")) == NULL)
fatal("match_filter_denylist failed");
@@ -171,11 +172,12 @@ compat_cipher_proposal(struct ssh *ssh,
return cipher_prop;
}
+/* Always returns pointer to allocated memory, caller must free. */
char *
compat_pkalg_proposal(struct ssh *ssh, char *pkalg_prop)
{
if (!(ssh->compat & SSH_BUG_RSASIGMD5))
- return pkalg_prop;
+ return xstrdup(pkalg_prop);
debug2_f("original public key proposal: %s", pkalg_prop);
if ((pkalg_prop = match_filter_denylist(pkalg_prop, "ssh-rsa")) == NULL)
fatal("match_filter_denylist failed");
@@ -185,21 +187,26 @@ compat_pkalg_proposal(struct ssh *ssh, c
return pkalg_prop;
}
+/* Always returns pointer to allocated memory, caller must free. */
char *
compat_kex_proposal(struct ssh *ssh, char *p)
{
+ char *cp = NULL;
+
if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
- return p;
+ return xstrdup(p);
debug2_f("original KEX proposal: %s", p);
if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
if ((p = match_filter_denylist(p,
"curve25519-sha256@libssh.org")) == NULL)
fatal("match_filter_denylist failed");
if ((ssh->compat & SSH_OLD_DHGEX) != 0) {
+ cp = p;
if ((p = match_filter_denylist(p,
"diffie-hellman-group-exchange-sha256,"
"diffie-hellman-group-exchange-sha1")) == NULL)
fatal("match_filter_denylist failed");
+ free(cp);
}
debug2_f("compat KEX proposal: %s", p);
if (*p == '\0')
diff --color -rup a/sshconnect2.c b/sshconnect2.c
--- a/sshconnect2.c 2022-07-14 17:38:43.241496549 +0200
+++ b/sshconnect2.c 2022-07-14 17:39:23.772268479 +0200
@@ -222,6 +222,7 @@ ssh_kex2(struct ssh *ssh, char *host, st
{
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;
#if defined(GSSAPI) && defined(WITH_OPENSSL)
@@ -252,10 +253,9 @@ ssh_kex2(struct ssh *ssh, char *host, st
if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL)
fatal_f("kex_names_cat");
- myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh, s);
+ myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, s);
myproposal[PROPOSAL_ENC_ALGS_CTOS] =
- compat_cipher_proposal(ssh, options.ciphers);
- myproposal[PROPOSAL_ENC_ALGS_STOC] =
+ myproposal[PROPOSAL_ENC_ALGS_STOC] = prop_enc =
compat_cipher_proposal(ssh, options.ciphers);
myproposal[PROPOSAL_COMP_ALGS_CTOS] =
myproposal[PROPOSAL_COMP_ALGS_STOC] =
@@ -264,12 +264,12 @@ ssh_kex2(struct ssh *ssh, char *host, st
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] =
+ 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] =
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
compat_pkalg_proposal(ssh, options.hostkeyalgorithms);
}
@@ -383,6 +383,10 @@ ssh_kex2(struct ssh *ssh, char *host, st
(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);
}
/*
diff --color -rup a/sshd.c b/sshd.c
--- a/sshd.c 2022-07-14 17:38:43.242496568 +0200
+++ b/sshd.c 2022-07-14 17:42:07.616388978 +0200
@@ -2493,14 +2493,15 @@ do_ssh2_kex(struct ssh *ssh)
{
char *myproposal[PROPOSAL_MAX] = { KEX_SERVER };
struct kex *kex;
+ char *hostkey_types = NULL;
+ char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL;
int r;
- myproposal[PROPOSAL_KEX_ALGS] = compat_kex_proposal(ssh,
+ myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh,
options.kex_algorithms);
- myproposal[PROPOSAL_ENC_ALGS_CTOS] = compat_cipher_proposal(ssh,
- options.ciphers);
- myproposal[PROPOSAL_ENC_ALGS_STOC] = compat_cipher_proposal(ssh,
- options.ciphers);
+ 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;
@@ -2513,8 +2514,10 @@ do_ssh2_kex(struct ssh *ssh)
ssh_packet_set_rekey_limits(ssh, options.rekey_limit,
options.rekey_interval);
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal(
- ssh, list_hostkey_types());
+ hostkey_types = list_hostkey_types();
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
+ compat_pkalg_proposal(ssh, hostkey_types);
+ free(hostkey_types);
#if defined(GSSAPI) && defined(WITH_OPENSSL)
{
@@ -2606,6 +2609,9 @@ 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);
debug("KEX done");
}

View File

@ -0,0 +1,194 @@
diff --color -ru a/clientloop.c b/clientloop.c
--- a/clientloop.c 2022-06-29 16:35:06.677597259 +0200
+++ b/clientloop.c 2022-06-29 16:40:29.737926205 +0200
@@ -116,6 +116,9 @@
#include "ssh-gss.h"
#endif
+/* Permitted RSA signature algorithms for UpdateHostkeys proofs */
+#define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256"
+
/* import options */
extern Options options;
@@ -2110,8 +2113,10 @@
struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx;
size_t i, ndone;
struct sshbuf *signdata;
- int r, kexsigtype, use_kexsigtype;
+ int r, plaintype;
const u_char *sig;
+ const char *rsa_kexalg = NULL;
+ char *alg = NULL;
size_t siglen;
if (ctx->nnew == 0)
@@ -2122,9 +2127,9 @@
hostkeys_update_ctx_free(ctx);
return;
}
- 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)
+ rsa_kexalg = ssh->kex->hostkey_alg;
if ((signdata = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
/*
@@ -2135,6 +2140,7 @@
for (ndone = i = 0; i < ctx->nkeys; i++) {
if (ctx->keys_match[i])
continue;
+ plaintype = sshkey_type_plain(ctx->keys[i]->type);
/* Prepare data to be signed: session ID, unique string, key */
sshbuf_reset(signdata);
if ( (r = sshbuf_put_cstring(signdata,
@@ -2148,19 +2154,33 @@
error_fr(r, "parse sig");
goto out;
}
+ if ((r = sshkey_get_sigtype(sig, siglen, &alg)) != 0) {
+ error_fr(r, "server gave unintelligible signature "
+ "for %s key %zu", sshkey_type(ctx->keys[i]), i);
+ goto out;
+ }
/*
- * For RSA keys, prefer to use the signature type negotiated
- * during KEX to the default (SHA1).
+ * Special case for RSA keys: if a RSA hostkey was negotiated,
+ * then use its signature type for verification of RSA hostkey
+ * proofs. Otherwise, accept only RSA-SHA256/512 signatures.
*/
- use_kexsigtype = kexsigtype == KEY_RSA &&
- sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA;
- debug3_f("verify %s key %zu using %s sigalg",
- sshkey_type(ctx->keys[i]), i,
- use_kexsigtype ? ssh->kex->hostkey_alg : "default");
+ if (plaintype == KEY_RSA && rsa_kexalg == NULL &&
+ match_pattern_list(alg, HOSTKEY_PROOF_RSA_ALGS, 0) != 1) {
+ debug_f("server used untrusted RSA signature algorithm "
+ "%s for key %zu, disregarding", alg, i);
+ free(alg);
+ /* zap the key from the list */
+ sshkey_free(ctx->keys[i]);
+ ctx->keys[i] = NULL;
+ ndone++;
+ continue;
+ }
+ debug3_f("verify %s key %zu using sigalg %s",
+ sshkey_type(ctx->keys[i]), i, alg);
+ free(alg);
if ((r = sshkey_verify(ctx->keys[i], sig, siglen,
sshbuf_ptr(signdata), sshbuf_len(signdata),
- use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0,
- NULL)) != 0) {
+ plaintype == KEY_RSA ? rsa_kexalg : NULL, 0, NULL)) != 0) {
error_fr(r, "server gave bad signature for %s key %zu",
sshkey_type(ctx->keys[i]), i);
goto out;
diff --color -ru a/kex.c b/kex.c
--- a/kex.c 2022-06-29 16:35:06.775599179 +0200
+++ b/kex.c 2022-06-29 16:42:00.839710940 +0200
@@ -959,6 +959,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)
{
@@ -994,6 +1006,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-29 16:35:06.766599003 +0200
+++ b/kex.h 2022-06-29 16:42:24.199168567 +0200
@@ -116,6 +116,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 2021-08-20 06:03:49.000000000 +0200
+++ b/serverloop.c 2022-06-29 16:45:05.902336428 +0200
@@ -684,16 +684,18 @@
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_f("sshbuf_new");
- 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;
@@ -726,16 +728,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_f("sign %s key (index %d) using sigalg %s",
+ sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg);
if ((r = sshbuf_put_cstring(sigbuf,
"hostkeys-prove-00@openssh.com")) != 0 ||
(r = sshbuf_put_stringb(sigbuf,
ssh->kex->session_id)) != 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_fr(r, "assemble signature");
goto out;

View File

@ -0,0 +1,424 @@
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index 2ab222ed6..4e9437912 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -118,6 +118,10 @@ userauth_hostbased(struct ssh *ssh, const char *method)
"(null)" : key->cert->signature_type);
goto done;
}
+ if ((r = sshkey_check_rsa_length(key, options.rsa_min_size)) != 0) {
+ logit("refusing %s key", sshkey_type(key));
+ goto done;
+ }
if (!authctxt->valid || authctxt->user == NULL) {
debug2_f("disabled because of invalid user");
diff --git a/auth2-pubkey.c b/auth2-pubkey.c
index daa756a01..68e7dea1f 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -172,6 +172,10 @@ userauth_pubkey(struct ssh *ssh, const char *method)
"(null)" : key->cert->signature_type);
goto done;
}
+ if ((r = sshkey_check_rsa_length(key, options.rsa_min_size)) != 0) {
+ logit("refusing %s key", sshkey_type(key));
+ goto done;
+ }
key_s = format_key(key);
if (sshkey_is_cert(key))
ca_s = format_key(key->cert->signature_key);
diff --git a/readconf.c b/readconf.c
index 5b5afa8e3..5e17abd41 100644
--- a/readconf.c
+++ b/readconf.c
@@ -160,7 +160,7 @@ typedef enum {
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
- oSecurityKeyProvider, oKnownHostsCommand,
+ oSecurityKeyProvider, oKnownHostsCommand, oRSAMinSize,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@@ -306,6 +306,7 @@ static struct {
{ "proxyjump", oProxyJump },
{ "securitykeyprovider", oSecurityKeyProvider },
{ "knownhostscommand", oKnownHostsCommand },
+ { "rsaminsize", oRSAMinSize },
{ NULL, oBadOption }
};
@@ -2162,6 +2163,10 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host,
*charptr = xstrdup(arg);
break;
+ case oRSAMinSize:
+ intptr = &options->rsa_min_size;
+ goto parse_int;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@@ -2409,6 +2414,7 @@ initialize_options(Options * options)
options->hostbased_accepted_algos = NULL;
options->pubkey_accepted_algos = NULL;
options->known_hosts_command = NULL;
+ options->rsa_min_size = -1;
}
/*
@@ -2598,6 +2604,8 @@ fill_default_options(Options * options)
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
#endif
+ if (options->rsa_min_size == -1)
+ options->rsa_min_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
/* Expand KEX name lists */
all_cipher = cipher_alg_list(',', 0);
@@ -3287,6 +3295,7 @@ dump_client_config(Options *o, const char *host)
dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts);
dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max);
dump_cfg_int(oServerAliveInterval, o->server_alive_interval);
+ dump_cfg_int(oRSAMinSize, o->rsa_min_size);
/* String options */
dump_cfg_string(oBindAddress, o->bind_address);
diff --git a/readconf.h b/readconf.h
index f647bd42a..29db353ab 100644
--- a/readconf.h
+++ b/readconf.h
@@ -176,6 +176,8 @@ typedef struct {
char *known_hosts_command;
+ int rsa_min_size; /* minimum size of RSA keys */
+
char *ignored_unknown; /* Pattern list of unknown tokens to ignore */
} Options;
diff --git a/servconf.c b/servconf.c
index f7317a5cb..362ff5b67 100644
--- a/servconf.c
+++ b/servconf.c
@@ -177,6 +177,7 @@ initialize_server_options(ServerOptions *options)
options->fingerprint_hash = -1;
options->disable_forwarding = -1;
options->expose_userauth_info = -1;
+ options->rsa_min_size = -1;
}
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
@@ -416,6 +417,8 @@ fill_default_server_options(ServerOptions *options)
options->expose_userauth_info = 0;
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("internal");
+ if (options->rsa_min_size == -1)
+ options->rsa_min_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
assemble_algorithms(options);
@@ -489,6 +492,7 @@ typedef enum {
sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
+ sRSAMinSize,
sDeprecated, sIgnore, sUnsupported
} ServerOpCodes;
@@ -632,6 +636,7 @@ static struct {
{ "rdomain", sRDomain, SSHCFG_ALL },
{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
+ { "rsaminsize", sRSAMinSize, SSHCFG_ALL },
{ NULL, sBadOption, 0 }
};
@@ -2377,6 +2382,10 @@ process_server_config_line_depth(ServerOptions *options, char *line,
*charptr = xstrdup(arg);
break;
+ case sRSAMinSize:
+ intptr = &options->rsa_min_size;
+ goto parse_int;
+
case sDeprecated:
case sIgnore:
case sUnsupported:
@@ -2549,6 +2558,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
M_CP_INTOPT(rekey_limit);
M_CP_INTOPT(rekey_interval);
M_CP_INTOPT(log_level);
+ M_CP_INTOPT(rsa_min_size);
/*
* The bind_mask is a mode_t that may be unsigned, so we can't use
@@ -2810,6 +2820,7 @@ dump_config(ServerOptions *o)
dump_cfg_int(sMaxSessions, o->max_sessions);
dump_cfg_int(sClientAliveInterval, o->client_alive_interval);
dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max);
+ dump_cfg_int(sRSAMinSize, o->rsa_min_size);
dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
/* formatted integer arguments */
diff --git a/servconf.h b/servconf.h
index 115db1e79..2e3486906 100644
--- a/servconf.h
+++ b/servconf.h
@@ -227,6 +227,7 @@ typedef struct {
int expose_userauth_info;
u_int64_t timing_secret;
char *sk_provider;
+ int rsa_min_size; /* minimum size of RSA keys */
} ServerOptions;
/* Information about the incoming connection as used by Match */
diff --git a/ssh.c b/ssh.c
index a926cc007..cd13fb879 100644
--- a/ssh.c
+++ b/ssh.c
@@ -500,14 +500,22 @@ resolve_canonicalize(char **hostp, int port)
}
/*
- * Check the result of hostkey loading, ignoring some errors and
- * fatal()ing for others.
+ * Check the result of hostkey loading, ignoring some errors and either
+ * discarding the key or fatal()ing for others.
*/
static void
-check_load(int r, const char *path, const char *message)
+check_load(int r, struct sshkey **k, const char *path, const char *message)
{
switch (r) {
case 0:
+ /* Check RSA keys size and discard if undersized */
+ if (k != NULL && *k != NULL &&
+ (r = sshkey_check_rsa_length(*k,
+ options.rsa_min_size)) != 0) {
+ error_r(r, "load %s \"%s\"", message, path);
+ free(*k);
+ *k = NULL;
+ }
break;
case SSH_ERR_INTERNAL_ERROR:
case SSH_ERR_ALLOC_FAIL:
@@ -1557,12 +1565,13 @@ main(int ac, char **av)
if ((o) >= sensitive_data.nkeys) \
fatal_f("pubkey out of array bounds"); \
check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \
- p, "pubkey"); \
+ &(sensitive_data.keys[o]), p, "pubkey"); \
} while (0)
#define L_CERT(p,o) do { \
if ((o) >= sensitive_data.nkeys) \
fatal_f("cert out of array bounds"); \
- check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \
+ check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), \
+ &(sensitive_data.keys[o]), p, "cert"); \
} while (0)
if (options.hostbased_authentication == 1) {
@@ -2244,7 +2253,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
filename = default_client_percent_dollar_expand(cp, cinfo);
free(cp);
check_load(sshkey_load_public(filename, &public, NULL),
- filename, "pubkey");
+ &public, filename, "pubkey");
debug("identity file %s type %d", filename,
public ? public->type : -1);
free(options.identity_files[i]);
@@ -2263,7 +2272,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
continue;
xasprintf(&cp, "%s-cert", filename);
check_load(sshkey_load_public(cp, &public, NULL),
- filename, "pubkey");
+ &public, filename, "pubkey");
debug("identity file %s type %d", cp,
public ? public->type : -1);
if (public == NULL) {
@@ -2294,7 +2303,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo)
free(cp);
check_load(sshkey_load_public(filename, &public, NULL),
- filename, "certificate");
+ &public, filename, "certificate");
debug("certificate file %s type %d", filename,
public ? public->type : -1);
free(options.certificate_files[i]);
diff --git a/sshconnect2.c b/sshconnect2.c
index 67f8e0309..d050c1656 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -91,6 +91,10 @@ static const struct ssh_conn_info *xxx_conn_info;
static int
verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh)
{
+ int r;
+
+ if ((r = sshkey_check_rsa_length(hostkey, options.rsa_min_size)) != 0)
+ fatal_r(r, "Bad server host key");
if (verify_host_key(xxx_host, xxx_hostaddr, hostkey,
xxx_conn_info) == -1)
fatal("Host key verification failed.");
@@ -1747,6 +1751,12 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt)
close(agent_fd);
} else {
for (j = 0; j < idlist->nkeys; j++) {
+ if ((r = sshkey_check_rsa_length(idlist->keys[j],
+ options.rsa_min_size)) != 0) {
+ debug_fr(r, "ignoring %s agent key",
+ sshkey_ssh_name(idlist->keys[j]));
+ continue;
+ }
found = 0;
TAILQ_FOREACH(id, &files, next) {
/*
diff --git a/sshd.c b/sshd.c
index d26eb86ae..5f36905a1 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1746,6 +1746,13 @@ main(int ac, char **av)
fatal_r(r, "Could not demote key: \"%s\"",
options.host_key_files[i]);
}
+ if (pubkey != NULL && (r = sshkey_check_rsa_length(pubkey,
+ options.rsa_min_size)) != 0) {
+ error_fr(r, "Host key %s", options.host_key_files[i]);
+ sshkey_free(pubkey);
+ sshkey_free(key);
+ continue;
+ }
sensitive_data.host_keys[i] = key;
sensitive_data.host_pubkeys[i] = pubkey;
diff --git a/sshkey.c b/sshkey.c
index 47864e6d8..8bad6bd99 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -2319,18 +2319,24 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf)
return ret;
}
-#ifdef WITH_OPENSSL
-static int
-check_rsa_length(const RSA *rsa)
+int
+sshkey_check_rsa_length(const struct sshkey *k, int min_size)
{
+#ifdef WITH_OPENSSL
const BIGNUM *rsa_n;
+ int nbits;
- RSA_get0_key(rsa, &rsa_n, NULL, NULL);
- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE)
+ if (k == NULL || k->rsa == NULL ||
+ (k->type != KEY_RSA && k->type != KEY_RSA_CERT))
+ return 0;
+ RSA_get0_key(k->rsa, &rsa_n, NULL, NULL);
+ nbits = BN_num_bits(rsa_n);
+ if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE ||
+ (min_size > 0 && nbits < min_size))
return SSH_ERR_KEY_LENGTH;
+#endif /* WITH_OPENSSL */
return 0;
}
-#endif
static int
sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
@@ -2391,7 +2397,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
goto out;
}
rsa_n = rsa_e = NULL; /* transferred */
- if ((ret = check_rsa_length(key->rsa)) != 0)
+ if ((ret = sshkey_check_rsa_length(key, 0)) != 0)
goto out;
#ifdef DEBUG_PK
RSA_print_fp(stderr, key->rsa, 8);
@@ -3580,7 +3586,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
goto out;
}
rsa_p = rsa_q = NULL; /* transferred */
- if ((r = check_rsa_length(k->rsa)) != 0)
+ if ((r = sshkey_check_rsa_length(k, 0)) != 0)
goto out;
if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0)
goto out;
@@ -4566,7 +4572,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type,
r = SSH_ERR_LIBCRYPTO_ERROR;
goto out;
}
- if ((r = check_rsa_length(prv->rsa)) != 0)
+ if ((r = sshkey_check_rsa_length(prv, 0)) != 0)
goto out;
} else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA &&
(type == KEY_UNSPEC || type == KEY_DSA)) {
diff --git a/sshkey.h b/sshkey.h
index 125cadb64..52e879456 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -267,6 +267,7 @@ int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob,
int type, struct sshkey **pubkeyp);
+int sshkey_check_rsa_length(const struct sshkey *, int);
/* XXX should be internal, but used by ssh-keygen */
int ssh_rsa_complete_crt_parameters(struct sshkey *, const BIGNUM *);
diff --git a/ssh.1 b/ssh.1
index b4956aec..b1a40ebd 100644
--- a/ssh.1
+++ b/ssh.1
@@ -554,6 +554,7 @@ For full details of the options listed below, and their possible values, see
.It LogLevel
.It MACs
.It Match
+.It RSAMinSize
.It NoHostAuthenticationForLocalhost
.It NumberOfPasswordPrompts
.It PasswordAuthentication
diff --git a/ssh_config.5 b/ssh_config.5
index 24a46460..68771e4b 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1322,6 +1322,10 @@ The argument to this keyword must be
or
.Cm no
(the default).
+.It Cm RSAMinSize
+Provides a minimal bits requirement for RSA keys when used for signature and
+verification but not for the key generation. The default value is 1024 and
+can't be reduced.
.It Cm NumberOfPasswordPrompts
Specifies the number of password prompts before giving up.
The argument to this keyword must be an integer.
diff --git a/sshd_config.5 b/sshd_config.5
index 867a747d..e08811ca 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -1266,6 +1266,10 @@ will refuse connection attempts with a probability of rate/100 (30%)
if there are currently start (10) unauthenticated connections.
The probability increases linearly and all connection attempts
are refused if the number of unauthenticated connections reaches full (60).
+.It Cm RSAMinSize
+Provides a minimal bits requirement for RSA keys when used for signature and
+verification but not for the key generation. The default value is 1024 and
+can't be reduced.
.It Cm ModuliFile
Specifies the
.Xr moduli 5
diff --git a/sshkey.h b/sshkey.h
index 094815e0..2bb8cb90 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -286,6 +286,8 @@ int sshkey_private_serialize_maxsign(struct sshkey *key,
void sshkey_sig_details_free(struct sshkey_sig_details *);
+int ssh_set_rsa_min_bits(int minbits);
+
#ifdef SSHKEY_INTERNAL
int ssh_rsa_sign(const struct sshkey *key,
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,

View File

@ -0,0 +1,63 @@
diff --color -rup a/regress/hostkey-agent.sh b/regress/hostkey-agent.sh
--- a/regress/hostkey-agent.sh 2021-08-20 06:03:49.000000000 +0200
+++ b/regress/hostkey-agent.sh 2022-07-14 11:58:12.172786060 +0200
@@ -13,8 +13,12 @@ r=$?
grep -vi 'hostkey' $OBJ/sshd_proxy > $OBJ/sshd_proxy.orig
echo "HostKeyAgent $SSH_AUTH_SOCK" >> $OBJ/sshd_proxy.orig
+PUBKEY_ACCEPTED_ALGOS=`$SSH -G "example.com" | \
+ grep -i "PubkeyAcceptedAlgorithms" | cut -d ' ' -f2- | tr "," "|"`
+SSH_ACCEPTED_KEYTYPES=`echo "$SSH_KEYTYPES" | egrep "$PUBKEY_ACCEPTED_ALGOS"`
+
trace "load hostkeys"
-for k in $SSH_KEYTYPES ; do
+for k in $SSH_ACCEPTED_KEYTYPES ; do
${SSHKEYGEN} -qt $k -f $OBJ/agent-key.$k -N '' || fatal "ssh-keygen $k"
(
printf 'localhost-with-alias,127.0.0.1,::1 '
@@ -31,7 +35,7 @@ cp $OBJ/known_hosts.orig $OBJ/known_host
unset SSH_AUTH_SOCK
for ps in yes; do
- for k in $SSH_KEYTYPES ; do
+ for k in $SSH_ACCEPTED_KEYTYPES ; do
verbose "key type $k privsep=$ps"
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
echo "UsePrivilegeSeparation $ps" >> $OBJ/sshd_proxy
diff --color -rup a/sshconnect2.c b/sshconnect2.c
--- a/sshconnect2.c 2022-07-14 10:10:07.262975710 +0200
+++ b/sshconnect2.c 2022-07-14 10:10:32.068452067 +0200
@@ -222,6 +222,7 @@ ssh_kex2(struct ssh *ssh, char *host, st
{
char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
char *s, *all_key;
+ char *hostkeyalgs = NULL, *pkalg = NULL;
char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL;
int r, use_known_hosts_order = 0;
@@ -264,14 +265,19 @@ ssh_kex2(struct ssh *ssh, char *host, st
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));
+ if ((hostkeyalgs = order_hostkeyalgs(host, hostaddr, port, cinfo)) == NULL)
+ fatal_f("order_hostkeyalgs");
+ pkalg = match_filter_allowlist(hostkeyalgs, options.pubkey_accepted_algos);
+ free(hostkeyalgs);
} else {
- /* Use specified HostkeyAlgorithms exactly */
- myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
- compat_pkalg_proposal(ssh, options.hostkeyalgorithms);
+ /* Use specified HostkeyAlgorithms */
+ pkalg = match_filter_allowlist(options.hostkeyalgorithms, options.pubkey_accepted_algos);
}
+ if (pkalg == NULL)
+ fatal_f("match_filter_allowlist");
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = prop_hostkey =
+ compat_pkalg_proposal(ssh, pkalg);
+ free(pkalg);
#if defined(GSSAPI) && defined(WITH_OPENSSL)
if (options.gss_keyex) {

View File

@ -0,0 +1,174 @@
diff -up openssh-8.7p1/scp.c.scp-sftpdirs openssh-8.7p1/scp.c
--- openssh-8.7p1/scp.c.scp-sftpdirs 2022-02-07 12:31:07.407740407 +0100
+++ openssh-8.7p1/scp.c 2022-02-07 12:31:07.409740424 +0100
@@ -1324,7 +1324,7 @@ source_sftp(int argc, char *src, char *t
if (src_is_dir && iamrecursive) {
if (upload_dir(conn, src, abs_dst, pflag,
- SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) {
+ SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) {
error("failed to upload directory %s to %s",
src, abs_dst);
errs = 1;
diff -up openssh-8.7p1/sftp-client.c.scp-sftpdirs openssh-8.7p1/sftp-client.c
--- openssh-8.7p1/sftp-client.c.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200
+++ openssh-8.7p1/sftp-client.c 2022-02-07 12:47:59.117516131 +0100
@@ -971,7 +971,7 @@ do_fsetstat(struct sftp_conn *conn, cons
/* Implements both the realpath and expand-path operations */
static char *
-do_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
+do_realpath_expand(struct sftp_conn *conn, const char *path, int expand, int create_dir)
{
struct sshbuf *msg;
u_int expected_id, count, id;
@@ -1012,9 +1012,38 @@ do_realpath_expand(struct sftp_conn *con
if ((r = sshbuf_get_u32(msg, &status)) != 0)
fatal_fr(r, "parse status");
- error("Couldn't canonicalize: %s", fx2txt(status));
- sshbuf_free(msg);
- return NULL;
+ if ((status == SSH2_FX_NO_SUCH_FILE) && create_dir) {
+ memset(&a, '\0', sizeof(a));
+ if ((r = do_mkdir(conn, path, &a, 0)) != 0) {
+ sshbuf_free(msg);
+ return NULL;
+ }
+
+ send_string_request(conn, id, SSH2_FXP_REALPATH,
+ path, strlen(path));
+
+ get_msg(conn, msg);
+ if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
+ (r = sshbuf_get_u32(msg, &id)) != 0)
+ fatal_fr(r, "parse");
+
+ if (id != expected_id)
+ fatal("ID mismatch (%u != %u)", id, expected_id);
+
+ if (type == SSH2_FXP_STATUS) {
+ u_int status;
+
+ if ((r = sshbuf_get_u32(msg, &status)) != 0)
+ fatal_fr(r, "parse status");
+ error("Couldn't canonicalize: %s", fx2txt(status));
+ sshbuf_free(msg);
+ return NULL;
+ }
+ } else {
+ error("Couldn't canonicalize: %s", fx2txt(status));
+ sshbuf_free(msg);
+ return NULL;
+ }
} else if (type != SSH2_FXP_NAME)
fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
SSH2_FXP_NAME, type);
@@ -1039,9 +1067,9 @@ do_realpath_expand(struct sftp_conn *con
}
char *
-do_realpath(struct sftp_conn *conn, const char *path)
+do_realpath(struct sftp_conn *conn, const char *path, int create_dir)
{
- return do_realpath_expand(conn, path, 0);
+ return do_realpath_expand(conn, path, 0, create_dir);
}
int
@@ -1055,9 +1083,9 @@ do_expand_path(struct sftp_conn *conn, c
{
if (!can_expand_path(conn)) {
debug3_f("no server support, fallback to realpath");
- return do_realpath_expand(conn, path, 0);
+ return do_realpath_expand(conn, path, 0, 0);
}
- return do_realpath_expand(conn, path, 1);
+ return do_realpath_expand(conn, path, 1, 0);
}
int
@@ -1807,7 +1835,7 @@ download_dir(struct sftp_conn *conn, con
char *src_canon;
int ret;
- if ((src_canon = do_realpath(conn, src)) == NULL) {
+ if ((src_canon = do_realpath(conn, src, 0)) == NULL) {
error("Unable to canonicalize path \"%s\"", src);
return -1;
}
@@ -2115,12 +2143,12 @@ upload_dir_internal(struct sftp_conn *co
int
upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
int preserve_flag, int print_flag, int resume, int fsync_flag,
- int follow_link_flag)
+ int follow_link_flag, int create_dir)
{
char *dst_canon;
int ret;
- if ((dst_canon = do_realpath(conn, dst)) == NULL) {
+ if ((dst_canon = do_realpath(conn, dst, create_dir)) == NULL) {
error("Unable to canonicalize path \"%s\"", dst);
return -1;
}
@@ -2557,7 +2585,7 @@ crossload_dir(struct sftp_conn *from, st
char *from_path_canon;
int ret;
- if ((from_path_canon = do_realpath(from, from_path)) == NULL) {
+ if ((from_path_canon = do_realpath(from, from_path, 0)) == NULL) {
error("Unable to canonicalize path \"%s\"", from_path);
return -1;
}
diff -up openssh-8.7p1/sftp-client.h.scp-sftpdirs openssh-8.7p1/sftp-client.h
--- openssh-8.7p1/sftp-client.h.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200
+++ openssh-8.7p1/sftp-client.h 2022-02-07 12:31:07.410740433 +0100
@@ -111,7 +111,7 @@ int do_fsetstat(struct sftp_conn *, cons
int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
/* Canonicalise 'path' - caller must free result */
-char *do_realpath(struct sftp_conn *, const char *);
+char *do_realpath(struct sftp_conn *, const char *, int);
/* Canonicalisation with tilde expansion (requires server extension) */
char *do_expand_path(struct sftp_conn *, const char *);
@@ -159,7 +159,7 @@ int do_upload(struct sftp_conn *, const
* times if 'pflag' is set
*/
int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int,
- int, int);
+ int, int, int);
/*
* Download a 'from_path' from the 'from' connection and upload it to
diff -up openssh-8.7p1/sftp.c.scp-sftpdirs openssh-8.7p1/sftp.c
--- openssh-8.7p1/sftp.c.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200
+++ openssh-8.7p1/sftp.c 2022-02-07 12:31:07.411740442 +0100
@@ -760,7 +760,7 @@ process_put(struct sftp_conn *conn, cons
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (upload_dir(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, 1, resume,
- fflag || global_fflag, 0) == -1)
+ fflag || global_fflag, 0, 0) == -1)
err = -1;
} else {
if (do_upload(conn, g.gl_pathv[i], abs_dst,
@@ -1577,7 +1577,7 @@ parse_dispatch_command(struct sftp_conn
if (path1 == NULL || *path1 == '\0')
path1 = xstrdup(startdir);
path1 = make_absolute(path1, *pwd);
- if ((tmp = do_realpath(conn, path1)) == NULL) {
+ if ((tmp = do_realpath(conn, path1, 0)) == NULL) {
err = 1;
break;
}
@@ -2160,7 +2160,7 @@ interactive_loop(struct sftp_conn *conn,
}
#endif /* USE_LIBEDIT */
- remote_path = do_realpath(conn, ".");
+ remote_path = do_realpath(conn, ".", 0);
if (remote_path == NULL)
fatal("Need cwd");
startdir = xstrdup(remote_path);

View File

@ -0,0 +1,304 @@
diff --color -rup a/scp.c b/scp.c
--- a/scp.c 2022-07-26 14:51:40.560120817 +0200
+++ b/scp.c 2022-07-26 14:52:37.118213004 +0200
@@ -1324,12 +1324,12 @@ source_sftp(int argc, char *src, char *t
if (src_is_dir && iamrecursive) {
if (upload_dir(conn, src, abs_dst, pflag,
- SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) {
+ SFTP_PROGRESS_ONLY, 0, 0, 1, 1, 1) != 0) {
error("failed to upload directory %s to %s",
src, abs_dst);
errs = 1;
}
- } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) {
+ } else if (do_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) {
error("failed to upload file %s to %s", src, abs_dst);
errs = 1;
}
@@ -1566,11 +1566,11 @@ sink_sftp(int argc, char *dst, const cha
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
- pflag, SFTP_PROGRESS_ONLY, 0, 0, 1) == -1)
+ pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
- pflag, 0, 0) == -1)
+ pflag, 0, 0, 1) == -1)
err = -1;
}
free(abs_dst);
diff --color -rup a/sftp.c b/sftp.c
--- a/sftp.c 2022-07-26 14:51:40.561120836 +0200
+++ b/sftp.c 2022-07-26 14:52:37.119213023 +0200
@@ -666,12 +666,12 @@ process_get(struct sftp_conn *conn, cons
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, 1, resume,
- fflag || global_fflag, 0) == -1)
+ fflag || global_fflag, 0, 0) == -1)
err = -1;
} else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, resume,
- fflag || global_fflag) == -1)
+ fflag || global_fflag, 0) == -1)
err = -1;
}
free(abs_dst);
@@ -760,12 +760,12 @@ process_put(struct sftp_conn *conn, cons
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (upload_dir(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, 1, resume,
- fflag || global_fflag, 0, 0) == -1)
+ fflag || global_fflag, 0, 0, 0) == -1)
err = -1;
} else {
if (do_upload(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, resume,
- fflag || global_fflag) == -1)
+ fflag || global_fflag, 0) == -1)
err = -1;
}
}
diff --color -rup a/sftp-client.c b/sftp-client.c
--- a/sftp-client.c 2022-07-26 14:51:40.561120836 +0200
+++ b/sftp-client.c 2022-07-26 15:09:54.825295533 +0200
@@ -1454,7 +1454,7 @@ progress_meter_path(const char *path)
int
do_download(struct sftp_conn *conn, const char *remote_path,
const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
- int fsync_flag)
+ int fsync_flag, int inplace_flag)
{
struct sshbuf *msg;
u_char *handle;
@@ -1498,8 +1498,8 @@ do_download(struct sftp_conn *conn, cons
&handle, &handle_len) != 0)
return -1;
- local_fd = open(local_path,
- O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
+ local_fd = open(local_path, O_WRONLY | O_CREAT |
+ ((resume_flag || inplace_flag) ? 0 : O_TRUNC), mode | S_IWUSR);
if (local_fd == -1) {
error("Couldn't open local file \"%s\" for writing: %s",
local_path, strerror(errno));
@@ -1661,8 +1661,11 @@ do_download(struct sftp_conn *conn, cons
/* Sanity check */
if (TAILQ_FIRST(&requests) != NULL)
fatal("Transfer complete, but requests still in queue");
- /* Truncate at highest contiguous point to avoid holes on interrupt */
- if (read_error || write_error || interrupted) {
+ /*
+ * Truncate at highest contiguous point to avoid holes on interrupt,
+ * or unconditionally if writing in place.
+ */
+ if (inplace_flag || read_error || write_error || interrupted) {
if (reordered && resume_flag) {
error("Unable to resume download of \"%s\": "
"server reordered requests", local_path);
@@ -1724,7 +1727,7 @@ do_download(struct sftp_conn *conn, cons
static int
download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
int depth, Attrib *dirattrib, int preserve_flag, int print_flag,
- int resume_flag, int fsync_flag, int follow_link_flag)
+ int resume_flag, int fsync_flag, int follow_link_flag, int inplace_flag)
{
int i, ret = 0;
SFTP_DIRENT **dir_entries;
@@ -1781,7 +1784,7 @@ download_dir_internal(struct sftp_conn *
if (download_dir_internal(conn, new_src, new_dst,
depth + 1, &(dir_entries[i]->a), preserve_flag,
print_flag, resume_flag,
- fsync_flag, follow_link_flag) == -1)
+ fsync_flag, follow_link_flag, inplace_flag) == -1)
ret = -1;
} else if (S_ISREG(dir_entries[i]->a.perm) ||
(follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) {
@@ -1793,7 +1796,8 @@ download_dir_internal(struct sftp_conn *
if (do_download(conn, new_src, new_dst,
S_ISLNK(dir_entries[i]->a.perm) ? NULL :
&(dir_entries[i]->a),
- preserve_flag, resume_flag, fsync_flag) == -1) {
+ preserve_flag, resume_flag, fsync_flag,
+ inplace_flag) == -1) {
error("Download of file %s to %s failed",
new_src, new_dst);
ret = -1;
@@ -1831,7 +1835,7 @@ download_dir_internal(struct sftp_conn *
int
download_dir(struct sftp_conn *conn, const char *src, const char *dst,
Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
- int fsync_flag, int follow_link_flag)
+ int fsync_flag, int follow_link_flag, int inplace_flag)
{
char *src_canon;
int ret;
@@ -1843,26 +1847,25 @@ download_dir(struct sftp_conn *conn, con
ret = download_dir_internal(conn, src_canon, dst, 0,
dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag,
- follow_link_flag);
+ follow_link_flag, inplace_flag);
free(src_canon);
return ret;
}
int
do_upload(struct sftp_conn *conn, const char *local_path,
- const char *remote_path, int preserve_flag, int resume, int fsync_flag)
+ const char *remote_path, int preserve_flag, int resume,
+ int fsync_flag, int inplace_flag)
{
int r, local_fd;
- u_int status = SSH2_FX_OK;
- u_int id;
- u_char type;
+ u_int openmode, id, status = SSH2_FX_OK, reordered = 0;
off_t offset, progress_counter;
- u_char *handle, *data;
+ u_char type, *handle, *data;
struct sshbuf *msg;
struct stat sb;
- Attrib a, *c = NULL;
- u_int32_t startid;
- u_int32_t ackid;
+ Attrib a, t, *c = NULL;
+ u_int32_t startid, ackid;
+ u_int64_t highwater = 0;
struct request *ack = NULL;
struct requests acks;
size_t handle_len;
@@ -1913,10 +1916,15 @@ do_upload(struct sftp_conn *conn, const
}
}
+ openmode = SSH2_FXF_WRITE|SSH2_FXF_CREAT;
+ if (resume)
+ openmode |= SSH2_FXF_APPEND;
+ else if (!inplace_flag)
+ openmode |= SSH2_FXF_TRUNC;
+
/* Send open request */
- if (send_open(conn, remote_path, "dest", SSH2_FXF_WRITE|SSH2_FXF_CREAT|
- (resume ? SSH2_FXF_APPEND : SSH2_FXF_TRUNC),
- &a, &handle, &handle_len) != 0) {
+ if (send_open(conn, remote_path, "dest", openmode, &a,
+ &handle, &handle_len) != 0) {
close(local_fd);
return -1;
}
@@ -1999,6 +2007,12 @@ do_upload(struct sftp_conn *conn, const
ack->id, ack->len, (unsigned long long)ack->offset);
++ackid;
progress_counter += ack->len;
+ if (!reordered && ack->offset <= highwater)
+ highwater = ack->offset + ack->len;
+ else if (!reordered && ack->offset > highwater) {
+ debug3_f("server reordered ACKs");
+ reordered = 1;
+ }
free(ack);
}
offset += len;
@@ -2017,6 +2031,14 @@ do_upload(struct sftp_conn *conn, const
status = SSH2_FX_FAILURE;
}
+ if (inplace_flag || (resume && (status != SSH2_FX_OK || interrupted))) {
+ debug("truncating at %llu", (unsigned long long)highwater);
+ attrib_clear(&t);
+ t.flags = SSH2_FILEXFER_ATTR_SIZE;
+ t.size = highwater;
+ do_fsetstat(conn, handle, handle_len, &t);
+ }
+
if (close(local_fd) == -1) {
error("Couldn't close local file \"%s\": %s", local_path,
strerror(errno));
@@ -2041,7 +2063,7 @@ do_upload(struct sftp_conn *conn, const
static int
upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
int depth, int preserve_flag, int print_flag, int resume, int fsync_flag,
- int follow_link_flag)
+ int follow_link_flag, int inplace_flag)
{
int ret = 0;
DIR *dirp;
@@ -2119,12 +2141,13 @@ upload_dir_internal(struct sftp_conn *co
if (upload_dir_internal(conn, new_src, new_dst,
depth + 1, preserve_flag, print_flag, resume,
- fsync_flag, follow_link_flag) == -1)
+ fsync_flag, follow_link_flag, inplace_flag) == -1)
ret = -1;
} else if (S_ISREG(sb.st_mode) ||
(follow_link_flag && S_ISLNK(sb.st_mode))) {
if (do_upload(conn, new_src, new_dst,
- preserve_flag, resume, fsync_flag) == -1) {
+ preserve_flag, resume, fsync_flag,
+ inplace_flag) == -1) {
error("Uploading of file %s to %s failed!",
new_src, new_dst);
ret = -1;
@@ -2144,7 +2167,7 @@ upload_dir_internal(struct sftp_conn *co
int
upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
int preserve_flag, int print_flag, int resume, int fsync_flag,
- int follow_link_flag, int create_dir)
+ int follow_link_flag, int create_dir, int inplace_flag)
{
char *dst_canon;
int ret;
@@ -2155,7 +2178,7 @@ upload_dir(struct sftp_conn *conn, const
}
ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
- print_flag, resume, fsync_flag, follow_link_flag);
+ print_flag, resume, fsync_flag, follow_link_flag, inplace_flag);
free(dst_canon);
return ret;
diff --color -rup a/sftp-client.h b/sftp-client.h
--- a/sftp-client.h 2022-07-26 14:51:40.561120836 +0200
+++ b/sftp-client.h 2022-07-26 14:52:37.120213042 +0200
@@ -138,28 +138,29 @@ int do_fsync(struct sftp_conn *conn, u_c
* Download 'remote_path' to 'local_path'. Preserve permissions and times
* if 'pflag' is set
*/
-int do_download(struct sftp_conn *, const char *, const char *,
- Attrib *, int, int, int);
+int do_download(struct sftp_conn *, const char *, const char *, Attrib *,
+ int, int, int, int);
/*
* Recursively download 'remote_directory' to 'local_directory'. Preserve
* times if 'pflag' is set
*/
-int download_dir(struct sftp_conn *, const char *, const char *,
- Attrib *, int, int, int, int, int);
+int download_dir(struct sftp_conn *, const char *, const char *, Attrib *,
+ int, int, int, int, int, int);
/*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
* if 'pflag' is set
*/
-int do_upload(struct sftp_conn *, const char *, const char *, int, int, int);
+int do_upload(struct sftp_conn *, const char *, const char *,
+ int, int, int, int);
/*
* Recursively upload 'local_directory' to 'remote_directory'. Preserve
* times if 'pflag' is set
*/
-int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int,
- int, int, int);
+int upload_dir(struct sftp_conn *, const char *, const char *,
+ int, int, int, int, int, int, int);
/*
* Download a 'from_path' from the 'from' connection and upload it to

View File

@ -0,0 +1,135 @@
diff -up openssh-8.7p1/scp.c.sftpdirs openssh-8.7p1/scp.c
--- openssh-8.7p1/scp.c.sftpdirs 2022-02-02 14:11:12.553447509 +0100
+++ openssh-8.7p1/scp.c 2022-02-02 14:12:56.081316414 +0100
@@ -130,6 +130,7 @@
#include "misc.h"
#include "progressmeter.h"
#include "utf8.h"
+#include "sftp.h"
#include "sftp-common.h"
#include "sftp-client.h"
@@ -1264,13 +1265,18 @@ tolocal(int argc, char **argv, enum scp_
static char *
prepare_remote_path(struct sftp_conn *conn, const char *path)
{
+ size_t nslash;
+
/* Handle ~ prefixed paths */
- if (*path != '~')
- return xstrdup(path);
if (*path == '\0' || strcmp(path, "~") == 0)
return xstrdup(".");
- if (strncmp(path, "~/", 2) == 0)
- return xstrdup(path + 2);
+ if (*path != '~')
+ return xstrdup(path);
+ if (strncmp(path, "~/", 2) == 0) {
+ if ((nslash = strspn(path + 2, "/")) == strlen(path + 2))
+ return xstrdup(".");
+ return xstrdup(path + 2 + nslash);
+ }
if (can_expand_path(conn))
return do_expand_path(conn, path);
/* No protocol extension */
@@ -1282,10 +1288,16 @@ void
source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
{
char *target = NULL, *filename = NULL, *abs_dst = NULL;
- int target_is_dir;
-
+ int src_is_dir, target_is_dir;
+ Attrib a;
+ struct stat st;
+
+ memset(&a, '\0', sizeof(a));
+ if (stat(src, &st) != 0)
+ fatal("stat local \"%s\": %s", src, strerror(errno));
+ src_is_dir = S_ISDIR(st.st_mode);
if ((filename = basename(src)) == NULL)
- fatal("basename %s: %s", src, strerror(errno));
+ fatal("basename \"%s\": %s", src, strerror(errno));
/*
* No need to glob here - the local shell already took care of
@@ -1295,8 +1307,12 @@ source_sftp(int argc, char *src, char *t
cleanup_exit(255);
target_is_dir = remote_is_dir(conn, target);
if (targetshouldbedirectory && !target_is_dir) {
- fatal("Target is not a directory, but more files selected "
- "for upload");
+ debug("target directory \"%s\" does not exist", target);
+ a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS;
+ a.perm = st.st_mode | 0700; /* ensure writable */
+ if (do_mkdir(conn, target, &a, 1) != 0)
+ cleanup_exit(255); /* error already logged */
+ target_is_dir = 1;
}
if (target_is_dir)
abs_dst = path_append(target, filename);
@@ -1306,7 +1322,7 @@ source_sftp(int argc, char *src, char *t
}
debug3_f("copying local %s to remote %s", src, abs_dst);
- if (local_is_dir(src) && iamrecursive) {
+ if (src_is_dir && iamrecursive) {
if (upload_dir(conn, src, abs_dst, pflag,
SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) {
error("failed to upload directory %s to %s",
@@ -1487,14 +1506,15 @@ sink_sftp(int argc, char *dst, const cha
char *abs_dst = NULL;
glob_t g;
char *filename, *tmp = NULL;
- int i, r, err = 0;
+ int i, r, err = 0, dst_is_dir;
+ struct stat st;
memset(&g, 0, sizeof(g));
+
/*
* Here, we need remote glob as SFTP can not depend on remote shell
* expansions
*/
-
if ((abs_src = prepare_remote_path(conn, src)) == NULL) {
err = -1;
goto out;
@@ -1510,11 +1530,24 @@ sink_sftp(int argc, char *dst, const cha
goto out;
}
- if (g.gl_matchc > 1 && !local_is_dir(dst)) {
- error("Multiple files match pattern, but destination "
- "\"%s\" is not a directory", dst);
- err = -1;
- goto out;
+ if ((r = stat(dst, &st)) != 0)
+ debug2_f("stat local \"%s\": %s", dst, strerror(errno));
+ dst_is_dir = r == 0 && S_ISDIR(st.st_mode);
+
+ if (g.gl_matchc > 1 && !dst_is_dir) {
+ if (r == 0) {
+ error("Multiple files match pattern, but destination "
+ "\"%s\" is not a directory", dst);
+ err = -1;
+ goto out;
+ }
+ debug2_f("creating destination \"%s\"", dst);
+ if (mkdir(dst, 0777) != 0) {
+ error("local mkdir \"%s\": %s", dst, strerror(errno));
+ err = -1;
+ goto out;
+ }
+ dst_is_dir = 1;
}
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
@@ -1525,7 +1558,7 @@ sink_sftp(int argc, char *dst, const cha
goto out;
}
- if (local_is_dir(dst))
+ if (dst_is_dir)
abs_dst = path_append(dst, filename);
else
abs_dst = xstrdup(dst);

View File

@ -0,0 +1,53 @@
diff --color -ru a/ssh.1 b/ssh.1
--- a/ssh.1 2022-07-12 11:47:51.307295880 +0200
+++ b/ssh.1 2022-07-12 11:50:28.793363263 +0200
@@ -493,6 +493,7 @@
.It AddressFamily
.It BatchMode
.It BindAddress
+.It BindInterface
.It CanonicalDomains
.It CanonicalizeFallbackLocal
.It CanonicalizeHostname
@@ -510,6 +511,7 @@
.It ControlPath
.It ControlPersist
.It DynamicForward
+.It EnableSSHKeysign
.It EscapeChar
.It ExitOnForwardFailure
.It FingerprintHash
@@ -538,6 +540,8 @@
.It IdentitiesOnly
.It IdentityAgent
.It IdentityFile
+.It IgnoreUnknown
+.It Include
.It IPQoS
.It KbdInteractiveAuthentication
.It KbdInteractiveDevices
@@ -546,6 +550,7 @@
.It LocalCommand
.It LocalForward
.It LogLevel
+.It LogVerbose
.It MACs
.It Match
.It RSAMinSize
@@ -566,6 +571,8 @@
.It RemoteCommand
.It RemoteForward
.It RequestTTY
+.It RevokedHostKeys
+.It SecurityKeyProvider
.It SendEnv
.It ServerAliveInterval
.It ServerAliveCountMax
@@ -575,6 +582,7 @@
.It StreamLocalBindMask
.It StreamLocalBindUnlink
.It StrictHostKeyChecking
+.It SyslogFacility
.It TCPKeepAlive
.It Tunnel
.It TunnelDevice

View File

@ -0,0 +1,41 @@
diff -up openssh-8.8p1/regress/hostkey-agent.sh.redhat openssh-8.8p1/regress/hostkey-agent.sh
--- openssh-8.8p1/regress/hostkey-agent.sh.redhat 2022-08-10 15:54:42.084777662 +0200
+++ openssh-8.8p1/regress/hostkey-agent.sh 2022-08-10 17:01:25.651269994 +0200
@@ -36,6 +36,8 @@ unset SSH_AUTH_SOCK
for ps in yes; do
for k in $SSH_ACCEPTED_KEYTYPES ; do
+ [ "$k" == "ssh-rsa" ] && continue
+ [ "$k" == "ssh-dss" ] && continue
verbose "key type $k privsep=$ps"
cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy
echo "UsePrivilegeSeparation $ps" >> $OBJ/sshd_proxy
diff -up openssh-8.8p1/regress/hostkey-rotate.sh.redhat openssh-8.8p1/regress/hostkey-rotate.sh
--- openssh-8.8p1/regress/hostkey-rotate.sh.redhat 2022-08-10 16:57:12.720029146 +0200
+++ openssh-8.8p1/regress/hostkey-rotate.sh 2022-08-10 17:15:48.274923865 +0200
@@ -40,6 +40,8 @@ trace "prepare hostkeys"
nkeys=0
all_algs=""
for k in $SSH_HOSTKEY_TYPES; do
+ [ "$k" == "ssh-rsa" ] && continue
+ [ "$k" == "ssh-dss" ] && continue
${SSHKEYGEN} -qt $k -f $OBJ/hkr.$k -N '' || fatal "ssh-keygen $k"
echo "Hostkey $OBJ/hkr.${k}" >> $OBJ/sshd_proxy.orig
nkeys=`expr $nkeys + 1`
@@ -87,11 +89,15 @@ dossh -oStrictHostKeyChecking=yes -oHost
# Check that other keys learned
expect_nkeys $nkeys "learn hostkeys"
for k in $SSH_HOSTKEY_TYPES; do
+ [ "$k" == "ssh-rsa" ] && continue
+ [ "$k" == "ssh-dss" ] && continue
check_key_present $k || fail "didn't learn keytype $k"
done
# Check each key type
for k in $SSH_HOSTKEY_TYPES; do
+ [ "$k" == "ssh-rsa" ] && continue
+ [ "$k" == "ssh-dss" ] && continue
verbose "learn additional hostkeys, type=$k"
dossh -oStrictHostKeyChecking=yes -oHostKeyAlgorithms=$k,$all_algs
expect_nkeys $nkeys "learn hostkeys $k"

View File

@ -51,9 +51,9 @@
# Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1
%global openssh_ver 8.8p1
%global openssh_rel 3
%global openssh_rel 4
%global pam_ssh_agent_ver 0.10.4
%global pam_ssh_agent_rel 5
%global pam_ssh_agent_rel 6
Summary: An open source implementation of SSH protocol version 2
Name: openssh
@ -102,6 +102,8 @@ Patch306: pam_ssh_agent_auth-0.10.2-compat.patch
# Fix NULL dereference from getpwuid() return value
# https://sourceforge.net/p/pamsshagentauth/bugs/22/
Patch307: pam_ssh_agent_auth-0.10.2-dereference.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2070113
Patch308: pam_ssh_agent_auth-0.10.4-rsasha2.patch
#https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX)
Patch400: openssh-7.8p1-role-mls.patch
@ -197,6 +199,62 @@ Patch975: openssh-8.0p1-preserve-pam-errors.patch
Patch976: openssh-8.7p1-sftp-default-protocol.patch
# Implement kill switch for SCP protocol
Patch977: openssh-8.7p1-scp-kill-switch.patch
# Create non-existent directories when scp works in sftp mode and some more minor fixes
# upstream commits:
# ba61123eef9c6356d438c90c1199a57a0d7bcb0a
# 63670d4e9030bcee490d5a9cce561373ac5b3b23
# ac7c9ec894ed0825d04ef69c55babb49bab1d32e
Patch980: openssh-8.7p1-sftpscp-dir-create.patch
# Workaround for lack of sftp_realpath in older versions of RHEL
# https://bugzilla.redhat.com/show_bug.cgi?id=2038854
# https://github.com/openssh/openssh-portable/pull/299
# downstream only
Patch981: openssh-8.7p1-recursive-scp.patch
# https://github.com/djmdjm/openssh-wip/pull/13
Patch982: openssh-8.7p1-minrsabits.patch
# downstream only
Patch983: openssh-8.7p1-evpgenkey.patch
# downstream only, IBMCA tentative fix
# From https://bugzilla.redhat.com/show_bug.cgi?id=1976202#c14
Patch984: openssh-8.7p1-ibmca.patch
# Minimize the use of SHA1 as a proof of possession for RSA key (#2031868)
# upstream commits:
# 291721bc7c840d113a49518f3fca70e86248b8e8
# 0fa33683223c76289470a954404047bc762be84c
Patch1000: openssh-8.7p1-minimize-sha1-use.patch
# Fix for scp clearing file when src and dest are the same (#2056884)
# upstream commits:
# 7b1cbcb7599d9f6a3bbad79d412604aa1203b5ee
Patch1001: openssh-8.7p1-scp-clears-file.patch
# Add missing options from ssh_config into ssh manpage
# upstream bug:
# https://bugzilla.mindrot.org/show_bug.cgi?id=3455
Patch1002: openssh-8.7p1-ssh-manpage.patch
# Always return allocated strings from the kex filtering so that we can free them
# upstream commits:
# 486c4dc3b83b4b67d663fb0fa62bc24138ec3946
# 6c31ba10e97b6953c4f325f526f3e846dfea647a
# 322964f8f2e9c321e77ebae1e4d2cd0ccc5c5a0b
Patch1003: openssh-8.7p1-mem-leak.patch
# Reenable MONITOR_REQ_GSSCHECKMIC after gssapi-with-mic failures
# upstream MR:
# https://github.com/openssh-gsskex/openssh-gsskex/pull/21
Patch1004: openssh-8.7p1-gssapi-auth.patch
# Fix host-based authentication with rsa keys
# upstream commits:
# 7aa7b096cf2bafe2777085abdeed5ce00581f641
# d9dbb5d9a0326e252d3c7bc13beb9c2434f59409
# fdb1d58d0d3888b042e5a500f6ce524486aaf782
Patch1005: openssh-8.7p1-host-based-auth.patch
# Don't propose disallowed algorithms during hostkey negotiation
# upstream MR:
# https://github.com/openssh/openssh-portable/pull/323
Patch1006: openssh-8.7p1-negotiate-supported-algs.patch
# downstream only
# we skip some ssh-rsa/ssh-dss tests to make native test suite pass
Patch1100: openssh-8.8p1-skip-some-tests.patch
License: BSD
Requires: /sbin/nologin
@ -325,6 +383,7 @@ pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver}
%patch306 -p2 -b .psaa-compat
%patch305 -p2 -b .psaa-agent
%patch307 -p2 -b .psaa-deref
%patch308 -p2 -b .rsasha2
# Remove duplicate headers and library files
rm -f $(cat %{SOURCE5})
popd
@ -375,11 +434,26 @@ popd
%patch975 -p1 -b .preserve-pam-errors
%patch976 -p1 -b .sftp-by-default
%patch977 -p1 -b .kill-scp
%patch980 -p1 -b .sftpdirs
%patch981 -p1 -b .scp-sftpdirs
%patch982 -p1 -b .minrsabits
%patch983 -p1 -b .evpgenrsa
%patch984 -p1 -b .ibmca
%patch200 -p1 -b .audit
%patch201 -p1 -b .audit-race
%patch700 -p1 -b .fips
%patch1000 -p1 -b .minimize-sha1-use
%patch1001 -p1 -b .scp-clears-file
%patch1002 -p1 -b .ssh-manpage
%patch1003 -p1 -b .mem-leak
%patch1004 -p1 -b .gssapi-auth
%patch1005 -p1 -b .host-based-auth
%patch1006 -p1 -b .negotiate-supported-algs
%patch1100 -p1 -b .skipsshrsadsstests
%patch100 -p1 -b .coverity
autoreconf
@ -661,6 +735,9 @@ test -f %{sysconfig_anaconda} && \
%endif
%changelog
* Wed Aug 10 2022 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.8p1-4 + 0.10.4-6
- Port patches from CentOS (rhbz#2117264)
* Mon Aug 01 2022 Luca BRUNO <lucab@lucabruno.net> - 8.8p1-3
- Use allocated static GID for 'ssh_keys' group (rhbz#2104595)

View File

@ -0,0 +1,19 @@
diff -up openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.rsasha2 openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c
--- openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.rsasha2 2022-07-15 15:08:12.865585410 +0200
+++ openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c 2022-07-15 15:16:25.164282372 +0200
@@ -87,8 +87,13 @@ userauth_pubkey_from_id(const char *ruse
(r = sshbuf_put_string(b, pkblob, blen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
- if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0)
- goto user_auth_clean_exit;
+ if (sshkey_type_plain(id->key->type) == KEY_RSA
+ && ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), "rsa-sha2-256", 0) == 0) {
+ /* Do nothing */
+ } else {
+ if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0)
+ goto user_auth_clean_exit;
+ }
/* test for correct signature */
if (sshkey_verify(id->key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0, NULL) == 0)