Compare commits

...
Sign in to create a new pull request.

8 commits

Author SHA1 Message Date
Dmitry Belyavskiy
1b082685ca Fix remote code execution in ssh-agent PKCS#11 support
Resolves: CVE-2023-38408
2023-07-21 17:23:02 +02:00
Dmitry Belyavskiy
54b8791379 Avoid possible self-DoS attack
Resolves: CVE-2023-25136
2023-04-14 13:22:13 +02:00
Zoltan Fridrich
d6f5d0536e Add sk-dummy subpackage for test purposes
Resolves: rhbz#2176795

Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
2023-03-13 13:49:49 +01:00
Norbert Pocs
450d837c69 Add additional audit logging
Additional information audited about the SSH key used to log in

Resolves: rhbz#2049947

Signed-off-by: Norbert Pocs <npocs@redhat.com>
2022-10-24 19:47:20 +02:00
Dmitry Belyavskiy
b0b8b17faa RSAMinSize => RequiredRSASize
Related: rhbz#2117264
2022-09-29 13:39:28 +02:00
Dmitry Belyavskiy
2879e85d2a - Port patches from CentOS - RSAMinSize (rhbz#2117264) 2022-08-17 09:47:20 +02:00
Dmitry Belyavskiy
f1fdd1cbbc Avoid spirous message on connecting to the machine with ssh-rsa keys
Related: rhbz#2118626
2022-08-16 14:55:48 +02:00
Dmitry Belyavskiy
9baa2cbd50 Add patches from CentOS/RHEL9.1
Related: rhbz#2117264
2022-08-10 20:13:06 +02:00
21 changed files with 2457 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)) {
+ if (FIPS_mode())
+ logit_f("the key length might be unsupported by FIPS mode approved key generation method");
+ 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,38 @@
diff --git a/compat.c b/compat.c
index 46dfe3a9c2e..478a9403eea 100644
--- a/compat.c
+++ b/compat.c
@@ -190,26 +190,26 @@ compat_pkalg_proposal(struct ssh *ssh, char *pkalg_prop)
char *
compat_kex_proposal(struct ssh *ssh, char *p)
{
- char *cp = NULL;
+ char *cp = NULL, *cp2 = NULL;
if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0)
return xstrdup(p);
debug2_f("original KEX proposal: %s", p);
if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0)
- if ((p = match_filter_denylist(p,
+ if ((cp = 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,
+ if ((cp2 = match_filter_denylist(cp ? cp : p,
"diffie-hellman-group-exchange-sha256,"
"diffie-hellman-group-exchange-sha1")) == NULL)
fatal("match_filter_denylist failed");
free(cp);
+ cp = cp2;
}
- debug2_f("compat KEX proposal: %s", p);
- if (*p == '\0')
+ if (cp == NULL || *cp == '\0')
fatal("No supported key exchange algorithms found");
- return p;
+ debug2_f("compat KEX proposal: %s", cp);
+ return cp;
}

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,207 @@
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 --git a/hostfile.c b/hostfile.c
index a035b381..bd49e3ac 100644
--- a/hostfile.c
+++ b/hostfile.c
@@ -642,7 +642,7 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip,
/* Re-add the requested keys */
want = HKF_MATCH_HOST | (ip == NULL ? 0 : HKF_MATCH_IP);
for (i = 0; i < nkeys; i++) {
- if ((want & ctx.match_keys[i]) == want)
+ if (keys[i] == NULL || (want & ctx.match_keys[i]) == want)
continue;
if ((fp = sshkey_fingerprint(keys[i], hash_alg,
SSH_FP_DEFAULT)) == NULL) {
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,446 @@
diff --git a/auth2-hostbased.c b/auth2-hostbased.c
index 36b9d2f5..6b517db4 100644
--- a/auth2-hostbased.c
+++ b/auth2-hostbased.c
@@ -119,6 +119,11 @@ userauth_hostbased(struct ssh *ssh, const char *method)
"(null)" : key->cert->signature_type);
goto done;
}
+ if ((r = sshkey_check_rsa_length(key,
+ options.required_rsa_size)) != 0) {
+ logit_r(r, "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 962fd342..5d59febc 100644
--- a/auth2-pubkey.c
+++ b/auth2-pubkey.c
@@ -175,6 +175,11 @@ userauth_pubkey(struct ssh *ssh, const char *method)
"(null)" : key->cert->signature_type);
goto done;
}
+ if ((r = sshkey_check_rsa_length(key,
+ options.required_rsa_size)) != 0) {
+ logit_r(r, "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 7f26c680..42be690b 100644
--- a/readconf.c
+++ b/readconf.c
@@ -174,7 +174,7 @@ typedef enum {
oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms,
oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump,
- oSecurityKeyProvider, oKnownHostsCommand,
+ oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize,
oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported
} OpCodes;
@@ -320,6 +320,8 @@ static struct {
{ "proxyjump", oProxyJump },
{ "securitykeyprovider", oSecurityKeyProvider },
{ "knownhostscommand", oKnownHostsCommand },
+ { "requiredrsasize", oRequiredRSASize },
+ { "rsaminsize", oRequiredRSASize }, /* alias */
{ NULL, oBadOption }
};
@@ -2176,6 +2177,10 @@ parse_pubkey_algos:
*charptr = xstrdup(arg);
break;
+ case oRequiredRSASize:
+ intptr = &options->required_rsa_size;
+ goto parse_int;
+
case oDeprecated:
debug("%s line %d: Deprecated option \"%s\"",
filename, linenum, keyword);
@@ -2423,6 +2428,7 @@ initialize_options(Options * options)
options->hostbased_accepted_algos = NULL;
options->pubkey_accepted_algos = NULL;
options->known_hosts_command = NULL;
+ options->required_rsa_size = -1;
}
/*
@@ -2619,6 +2625,8 @@ fill_default_options(Options * options)
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("$SSH_SK_PROVIDER");
#endif
+ if (options->required_rsa_size == -1)
+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
/* Expand KEX name lists */
all_cipher = cipher_alg_list(',', 0);
@@ -3308,6 +3316,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(oRequiredRSASize, o->required_rsa_size);
/* String options */
dump_cfg_string(oBindAddress, o->bind_address);
diff --git a/readconf.h b/readconf.h
index f647bd42..ffb5ec4f 100644
--- a/readconf.h
+++ b/readconf.h
@@ -176,6 +176,8 @@ typedef struct {
char *known_hosts_command;
+ int required_rsa_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 29df0463..423772b1 100644
--- a/servconf.c
+++ b/servconf.c
@@ -195,6 +195,7 @@ initialize_server_options(ServerOptions *options)
options->fingerprint_hash = -1;
options->disable_forwarding = -1;
options->expose_userauth_info = -1;
+ options->required_rsa_size = -1;
}
/* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */
@@ -441,6 +442,8 @@ fill_default_server_options(ServerOptions *options)
options->expose_userauth_info = 0;
if (options->sk_provider == NULL)
options->sk_provider = xstrdup("internal");
+ if (options->required_rsa_size == -1)
+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE;
assemble_algorithms(options);
@@ -517,6 +520,7 @@ typedef enum {
sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
+ sRequiredRSASize,
sDeprecated, sIgnore, sUnsupported
} ServerOpCodes;
@@ -676,6 +680,8 @@ static struct {
{ "rdomain", sRDomain, SSHCFG_ALL },
{ "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL },
{ "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL },
+ { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL },
+ { "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */
{ NULL, sBadOption, 0 }
};
@@ -2438,6 +2443,10 @@ process_server_config_line_depth(ServerOptions *options, char *line,
*charptr = xstrdup(arg);
break;
+ case sRequiredRSASize:
+ intptr = &options->required_rsa_size;
+ goto parse_int;
+
case sDeprecated:
case sIgnore:
case sUnsupported:
@@ -2610,6 +2619,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(required_rsa_size);
/*
* The bind_mask is a mode_t that may be unsigned, so we can't use
@@ -2874,6 +2884,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(sRequiredRSASize, o->required_rsa_size);
dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask);
/* formatted integer arguments */
diff --git a/servconf.h b/servconf.h
index 8a04463e..9346155c 100644
--- a/servconf.h
+++ b/servconf.h
@@ -229,6 +229,7 @@ typedef struct {
int expose_userauth_info;
u_int64_t timing_secret;
char *sk_provider;
+ int required_rsa_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 559bf2af..25be53d5 100644
--- a/ssh.c
+++ b/ssh.c
@@ -516,14 +516,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.required_rsa_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:
@@ -1578,7 +1586,7 @@ 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) \
@@ -1586,7 +1594,8 @@ main(int ac, char **av)
#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]);
@@ -2284,7 +2293,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) {
@@ -2315,7 +2324,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 f9bd19ea..58fe98db 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -96,6 +96,11 @@ 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.required_rsa_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.");
@@ -1606,6 +1611,13 @@ load_identity_file(Identity *id)
private = NULL;
quit = 1;
}
+ if (!quit && (r = sshkey_check_rsa_length(private,
+ options.required_rsa_size)) != 0) {
+ debug_fr(r, "Skipping key %s", id->filename);
+ sshkey_free(private);
+ private = NULL;
+ quit = 1;
+ }
if (!quit && private != NULL && id->agent_fd == -1 &&
!(id->key && id->isprivate))
maybe_add_key_to_agent(id->filename, private, comment,
@@ -1752,6 +1764,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.required_rsa_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 17eee9d8..395ef493 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1870,6 +1870,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.required_rsa_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 ed2b5dff..77093235 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -2365,18 +2365,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,
@@ -2439,7 +2445,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);
@@ -3642,7 +3648,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;
@@ -4644,7 +4650,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 094815e0..be254e6b 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -273,6 +273,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..e255b9b9 100644
--- a/ssh.1
+++ b/ssh.1
@@ -571,6 +571,7 @@ For full details of the options listed below, and their possible values, see
.It RemoteCommand
.It RemoteForward
.It RequestTTY
+.It RequiredRSASize
.It SendEnv
.It ServerAliveInterval
.It ServerAliveCountMax
diff --git a/ssh_config.5 b/ssh_config.5
index 24a46460..d1ede18e 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1634,6 +1634,17 @@ and
.Fl T
flags for
.Xr ssh 1 .
+.It Cm RequiredRSASize
+Specifies the minimum RSA key size (in bits) that
+.Xr ssh 1
+will accept.
+User authentication keys smaller than this limit will be ignored.
+Servers that present host keys smaller than this limit will cause the
+connection to be terminated.
+The default is
+.Cm 1024
+bits.
+Note that this limit may only be raised from the default.
.It Cm RevokedHostKeys
Specifies revoked host public keys.
Keys listed in this file will be refused for host authentication.
diff --git a/sshd_config.5 b/sshd_config.5
index 867a747d..f5a06637 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -1596,6 +1596,16 @@ is
.Cm default none ,
which means that rekeying is performed after the cipher's default amount
of data has been sent or received and no time based rekeying is done.
+.It Cm RequiredRSASize
+Specifies the minimum RSA key size (in bits) that
+.Xr sshd 8
+will accept.
+User and host-based authentication keys smaller than this limit will be
+refused.
+The default is
+.Cm 1024
+bits.
+Note that this limit may only be raised from the default.
.It Cm RevokedKeys
Specifies revoked public keys file, or
.Cm none

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 NoHostAuthenticationForLocalhost
@@ -566,6 +571,8 @@
.It RemoteCommand
.It RemoteForward
.It RequestTTY
+.It RevokedHostKeys
+.It SecurityKeyProvider
.It RequiredRSASize
.It SendEnv
.It ServerAliveInterval
@@ -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

@ -0,0 +1,119 @@
diff -up openssh-9.0p1/audit-bsm.c.patch openssh-9.0p1/audit-bsm.c
--- openssh-9.0p1/audit-bsm.c.patch 2022-10-24 15:02:16.544858331 +0200
+++ openssh-9.0p1/audit-bsm.c 2022-10-24 14:51:43.685766639 +0200
@@ -405,7 +405,7 @@ audit_session_close(struct logininfo *li
}
int
-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv)
+audit_keyusage(struct ssh *ssh, int host_user, char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv)
{
/* not implemented */
}
diff -up openssh-9.0p1/audit.c.patch openssh-9.0p1/audit.c
--- openssh-9.0p1/audit.c.patch 2022-10-24 15:02:16.544858331 +0200
+++ openssh-9.0p1/audit.c 2022-10-24 15:20:38.854548226 +0200
@@ -116,12 +116,22 @@ audit_event_lookup(ssh_audit_event_t ev)
void
audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key)
{
- char *fp;
+ char *key_fp = NULL;
+ char *issuer_fp = NULL;
+ struct sshkey_cert *cert = NULL;
- fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX);
- if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0)
+ key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX);
+ if (sshkey_is_cert(key) && key->cert != NULL && key->cert->signature_key != NULL) {
+ cert = key->cert;
+ issuer_fp = sshkey_fingerprint(cert->signature_key,
+ options.fingerprint_hash, SSH_FP_DEFAULT);
+ }
+ if (audit_keyusage(ssh, host_user, key_fp, cert, issuer_fp, (*rv == 0)) == 0)
*rv = -SSH_ERR_INTERNAL_ERROR;
- free(fp);
+ if (key_fp)
+ free(key_fp);
+ if (issuer_fp)
+ free(issuer_fp);
}
void
diff -up openssh-9.0p1/audit.h.patch openssh-9.0p1/audit.h
--- openssh-9.0p1/audit.h.patch 2022-10-24 15:02:16.544858331 +0200
+++ openssh-9.0p1/audit.h 2022-10-24 14:58:20.887565518 +0200
@@ -64,7 +64,7 @@ void audit_session_close(struct logininf
int audit_run_command(struct ssh *, const char *);
void audit_end_command(struct ssh *, int, const char *);
ssh_audit_event_t audit_classify_auth(const char *);
-int audit_keyusage(struct ssh *, int, char *, int);
+int audit_keyusage(struct ssh *, int, const char *, const struct sshkey_cert *, const char *, int);
void audit_key(struct ssh *, int, int *, const struct sshkey *);
void audit_unsupported(struct ssh *, int);
void audit_kex(struct ssh *, int, char *, char *, char *, char *);
diff -up openssh-9.0p1/audit-linux.c.patch openssh-9.0p1/audit-linux.c
--- openssh-9.0p1/audit-linux.c.patch 2022-10-24 15:02:16.544858331 +0200
+++ openssh-9.0p1/audit-linux.c 2022-10-24 15:21:58.165303951 +0200
@@ -137,10 +137,12 @@ fatal_report:
}
int
-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv)
+audit_keyusage(struct ssh *ssh, int host_user, const char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv)
{
char buf[AUDIT_LOG_SIZE];
int audit_fd, rc, saved_errno;
+ const char *rip;
+ u_int i;
audit_fd = audit_open();
if (audit_fd < 0) {
@@ -150,14 +152,44 @@ audit_keyusage(struct ssh *ssh, int host
else
return 0; /* Must prevent login */
}
+ rip = ssh_remote_ipaddr(ssh);
snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased");
rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
- buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv);
+ buf, audit_username(), -1, NULL, rip, NULL, rv);
if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
goto out;
- snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp);
+ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", key_fp);
rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL,
- ssh_remote_ipaddr(ssh), NULL, rv);
+ rip, NULL, rv);
+ if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
+ goto out;
+
+ if (cert) {
+ char *pbuf;
+
+ pbuf = audit_encode_nv_string("key_id", cert->key_id, 0);
+ if (pbuf == NULL)
+ goto out;
+ snprintf(buf, sizeof(buf), "cert %s cert_serial=%llu cert_issuer_alg=\"%s\" cert_issuer_fp=\"%s\"",
+ pbuf, (unsigned long long)cert->serial, sshkey_type(cert->signature_key), issuer_fp);
+ free(pbuf);
+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
+ buf, audit_username(), -1, NULL, rip, NULL, rv);
+ if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
+ goto out;
+
+ for (i = 0; cert->principals != NULL && i < cert->nprincipals; i++) {
+ pbuf = audit_encode_nv_string("cert_principal", cert->principals[i], 0);
+ if (pbuf == NULL)
+ goto out;
+ snprintf(buf, sizeof(buf), "principal %s", pbuf);
+ free(pbuf);
+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
+ buf, audit_username(), -1, NULL, rip, NULL, rv);
+ if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
+ goto out;
+ }
+ }
out:
saved_errno = errno;
audit_close(audit_fd);

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

@ -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 11
%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
@ -86,6 +86,8 @@ Patch100: openssh-6.7p1-coverity.patch
Patch200: openssh-7.6p1-audit.patch
# Audit race condition in forked child (#1310684)
Patch201: openssh-7.1p2-audit-race-condition.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2049947
Patch202: openssh-9.0p1-audit-log.patch
# --- pam_ssh-agent ---
# make it build reusing the openssh sources
@ -102,6 +104,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 +201,65 @@ 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
# CVE-2023-25136
Patch1007: openssh-8.7p1-CVE-2023-25136.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
Patch1015: openssh-9.3p1-upstream-cve-2023-38408.patch
License: BSD
Requires: /sbin/nologin
@ -265,6 +328,10 @@ Requires: openssh = %{version}-%{release}
Summary: A passphrase dialog for OpenSSH and X
Requires: openssh = %{version}-%{release}
%package sk-dummy
Summary: OpenSSH SK driver for test purposes
Requires: openssh = %{version}-%{release}
%package -n pam_ssh_agent_auth
Summary: PAM module for authentication with ssh-agent
Version: %{pam_ssh_agent_ver}
@ -305,6 +372,9 @@ OpenSSH is a free version of SSH (Secure SHell), a program for logging
into and executing commands on a remote machine. This package contains
an X11 passphrase dialog for OpenSSH.
%description sk-dummy
This package contains a test SK driver used for OpenSSH test purposes
%description -n pam_ssh_agent_auth
This package contains a PAM module which can be used to authenticate
users using ssh keys stored in a ssh-agent. Through the use of the
@ -325,6 +395,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,12 +446,29 @@ 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
%patch1007 -p1 -b .cve-2023-25136
%patch1100 -p1 -b .skipsshrsadsstests
%patch100 -p1 -b .coverity
%patch -P 1015 -p1 -b .cve-2023-38408
autoreconf
pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver}
@ -458,6 +546,7 @@ perl -pi -e "s|-lcrypto|%{_libdir}/libcrypto.a|g" Makefile
%endif
%make_build
make regress/misc/sk-dummy/sk-dummy.so
# Define a variable to toggle gtk2/gtk3 building. This is necessary
# because RPM doesn't handle nested %%if statements.
@ -550,6 +639,9 @@ pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver}
popd
%endif
install -m 755 -d $RPM_BUILD_ROOT%{_libdir}/sshtest/
install -m 755 regress/misc/sk-dummy/sk-dummy.so $RPM_BUILD_ROOT%{_libdir}/sshtest
%pre
getent group ssh_keys >/dev/null || groupadd -r -g 101 ssh_keys || :
@ -653,6 +745,9 @@ test -f %{sysconfig_anaconda} && \
%attr(0755,root,root) %{_libexecdir}/openssh/ssh-askpass
%endif
%files sk-dummy
%attr(0755,root,root) %{_libdir}/sshtest/sk-dummy.so
%if %{pam_ssh_agent}
%files -n pam_ssh_agent_auth
%license pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver}/OPENSSH_LICENSE
@ -661,6 +756,32 @@ test -f %{sysconfig_anaconda} && \
%endif
%changelog
* Fri Jul 21 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.8p1-11
- Fix remote code execution in ssh-agent PKCS#11 support
Resolves: CVE-2023-38408
* Fri Apr 14 2023 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.8p1-10
- Avoid possible self-DoS attack
Resolves: CVE-2023-25136
* Mon Mar 13 2023 Zoltan Fridrich <zfridric@redhat.com> - 8.8p1-9
- Add sk-dummy subpackage for test purposes (rhbz#2176795)
* Mon Oct 24 2022 Norbert Pocs <npocs@redhat.com> - 8.8p1-8
- Add additional audit logging about ssh key used to login (rhbz#2049947)
* Thu Sep 29 2022 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.8p1-7
- RSAMinSize => RequiredRSASize (related rhbz#2117264)
* Wed Aug 17 2022 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.8p1-6
- Port patches from CentOS - RSAMinSize (rhbz#2117264)
* Tue Aug 16 2022 Dmitry Belyavskiy <dbelyavs@redhat.com> - 8.8p1-5
- Avoid spirous message on connecting to the machine with ssh-rsa keys (rhbz#2118626)
* 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)