diff --git a/openssh-6.7p1-coverity.patch b/openssh-6.7p1-coverity.patch index 930de69..147d90d 100644 --- a/openssh-6.7p1-coverity.patch +++ b/openssh-6.7p1-coverity.patch @@ -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) diff --git a/openssh-7.7p1-fips.patch b/openssh-7.7p1-fips.patch index 72bceb1..cc513db 100644 --- a/openssh-7.7p1-fips.patch +++ b/openssh-7.7p1-fips.patch @@ -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 + #include + #include ++#include + + #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 + #include ++#include + + #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; diff --git a/openssh-8.0p1-crypto-policies.patch b/openssh-8.0p1-crypto-policies.patch index 2ad438c..62616aa 100644 --- a/openssh-8.0p1-crypto-policies.patch +++ b/openssh-8.0p1-crypto-policies.patch @@ -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 diff --git a/openssh-8.7p1-evpgenkey.patch b/openssh-8.7p1-evpgenkey.patch new file mode 100644 index 0000000..1af9b49 --- /dev/null +++ b/openssh-8.7p1-evpgenkey.patch @@ -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 */ diff --git a/openssh-8.7p1-gssapi-auth.patch b/openssh-8.7p1-gssapi-auth.patch new file mode 100644 index 0000000..6908cad --- /dev/null +++ b/openssh-8.7p1-gssapi-auth.patch @@ -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); diff --git a/openssh-8.7p1-host-based-auth.patch b/openssh-8.7p1-host-based-auth.patch new file mode 100644 index 0000000..23efe91 --- /dev/null +++ b/openssh-8.7p1-host-based-auth.patch @@ -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); + diff --git a/openssh-8.7p1-ibmca.patch b/openssh-8.7p1-ibmca.patch new file mode 100644 index 0000000..c9c12ee --- /dev/null +++ b/openssh-8.7p1-ibmca.patch @@ -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 + #include + diff --git a/openssh-8.7p1-mem-leak.patch b/openssh-8.7p1-mem-leak.patch new file mode 100644 index 0000000..8c9ac80 --- /dev/null +++ b/openssh-8.7p1-mem-leak.patch @@ -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"); + } + diff --git a/openssh-8.7p1-minimize-sha1-use.patch b/openssh-8.7p1-minimize-sha1-use.patch new file mode 100644 index 0000000..cbaba49 --- /dev/null +++ b/openssh-8.7p1-minimize-sha1-use.patch @@ -0,0 +1,194 @@ +diff --color -ru a/clientloop.c b/clientloop.c +--- a/clientloop.c 2022-06-29 16:35:06.677597259 +0200 ++++ b/clientloop.c 2022-06-29 16:40:29.737926205 +0200 +@@ -116,6 +116,9 @@ + #include "ssh-gss.h" + #endif + ++/* Permitted RSA signature algorithms for UpdateHostkeys proofs */ ++#define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256" ++ + /* import options */ + extern Options options; + +@@ -2110,8 +2113,10 @@ + struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx; + size_t i, ndone; + struct sshbuf *signdata; +- int r, kexsigtype, use_kexsigtype; ++ int r, plaintype; + const u_char *sig; ++ const char *rsa_kexalg = NULL; ++ char *alg = NULL; + size_t siglen; + + if (ctx->nnew == 0) +@@ -2122,9 +2127,9 @@ + hostkeys_update_ctx_free(ctx); + return; + } +- kexsigtype = sshkey_type_plain( +- sshkey_type_from_name(ssh->kex->hostkey_alg)); +- ++ if (sshkey_type_plain(sshkey_type_from_name( ++ ssh->kex->hostkey_alg)) == KEY_RSA) ++ rsa_kexalg = ssh->kex->hostkey_alg; + if ((signdata = sshbuf_new()) == NULL) + fatal_f("sshbuf_new failed"); + /* +@@ -2135,6 +2140,7 @@ + for (ndone = i = 0; i < ctx->nkeys; i++) { + if (ctx->keys_match[i]) + continue; ++ plaintype = sshkey_type_plain(ctx->keys[i]->type); + /* Prepare data to be signed: session ID, unique string, key */ + sshbuf_reset(signdata); + if ( (r = sshbuf_put_cstring(signdata, +@@ -2148,19 +2154,33 @@ + error_fr(r, "parse sig"); + goto out; + } ++ if ((r = sshkey_get_sigtype(sig, siglen, &alg)) != 0) { ++ error_fr(r, "server gave unintelligible signature " ++ "for %s key %zu", sshkey_type(ctx->keys[i]), i); ++ goto out; ++ } + /* +- * For RSA keys, prefer to use the signature type negotiated +- * during KEX to the default (SHA1). ++ * Special case for RSA keys: if a RSA hostkey was negotiated, ++ * then use its signature type for verification of RSA hostkey ++ * proofs. Otherwise, accept only RSA-SHA256/512 signatures. + */ +- use_kexsigtype = kexsigtype == KEY_RSA && +- sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA; +- debug3_f("verify %s key %zu using %s sigalg", +- sshkey_type(ctx->keys[i]), i, +- use_kexsigtype ? ssh->kex->hostkey_alg : "default"); ++ if (plaintype == KEY_RSA && rsa_kexalg == NULL && ++ match_pattern_list(alg, HOSTKEY_PROOF_RSA_ALGS, 0) != 1) { ++ debug_f("server used untrusted RSA signature algorithm " ++ "%s for key %zu, disregarding", alg, i); ++ free(alg); ++ /* zap the key from the list */ ++ sshkey_free(ctx->keys[i]); ++ ctx->keys[i] = NULL; ++ ndone++; ++ continue; ++ } ++ debug3_f("verify %s key %zu using sigalg %s", ++ sshkey_type(ctx->keys[i]), i, alg); ++ free(alg); + if ((r = sshkey_verify(ctx->keys[i], sig, siglen, + sshbuf_ptr(signdata), sshbuf_len(signdata), +- use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0, +- NULL)) != 0) { ++ plaintype == KEY_RSA ? rsa_kexalg : NULL, 0, NULL)) != 0) { + error_fr(r, "server gave bad signature for %s key %zu", + sshkey_type(ctx->keys[i]), i); + goto out; +diff --color -ru a/kex.c b/kex.c +--- a/kex.c 2022-06-29 16:35:06.775599179 +0200 ++++ b/kex.c 2022-06-29 16:42:00.839710940 +0200 +@@ -959,6 +959,18 @@ + return (1); + } + ++/* returns non-zero if proposal contains any algorithm from algs */ ++static int ++has_any_alg(const char *proposal, const char *algs) ++{ ++ char *cp; ++ ++ if ((cp = match_list(proposal, algs, NULL)) == NULL) ++ return 0; ++ free(cp); ++ return 1; ++} ++ + static int + kex_choose_conf(struct ssh *ssh) + { +@@ -994,6 +1006,16 @@ + free(ext); + } + ++ /* Check whether client supports rsa-sha2 algorithms */ ++ if (kex->server && (kex->flags & KEX_INITIAL)) { ++ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], ++ "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com")) ++ kex->flags |= KEX_RSA_SHA2_256_SUPPORTED; ++ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], ++ "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com")) ++ kex->flags |= KEX_RSA_SHA2_512_SUPPORTED; ++ } ++ + /* Algorithm Negotiation */ + if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], + sprop[PROPOSAL_KEX_ALGS])) != 0) { +diff --color -ru a/kex.h b/kex.h +--- a/kex.h 2022-06-29 16:35:06.766599003 +0200 ++++ b/kex.h 2022-06-29 16:42:24.199168567 +0200 +@@ -116,6 +116,8 @@ + + #define KEX_INIT_SENT 0x0001 + #define KEX_INITIAL 0x0002 ++#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */ ++#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */ + + struct sshenc { + char *name; +diff --color -ru a/serverloop.c b/serverloop.c +--- a/serverloop.c 2021-08-20 06:03:49.000000000 +0200 ++++ b/serverloop.c 2022-06-29 16:45:05.902336428 +0200 +@@ -684,16 +684,18 @@ + struct sshbuf *resp = NULL; + struct sshbuf *sigbuf = NULL; + struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL; +- int r, ndx, kexsigtype, use_kexsigtype, success = 0; ++ int r, ndx, success = 0; + const u_char *blob; ++ const char *sigalg, *kex_rsa_sigalg = NULL; + u_char *sig = 0; + size_t blen, slen; + + if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL) + fatal_f("sshbuf_new"); + +- kexsigtype = sshkey_type_plain( +- sshkey_type_from_name(ssh->kex->hostkey_alg)); ++ if (sshkey_type_plain(sshkey_type_from_name( ++ ssh->kex->hostkey_alg)) == KEY_RSA) ++ kex_rsa_sigalg = ssh->kex->hostkey_alg; + while (ssh_packet_remaining(ssh) > 0) { + sshkey_free(key); + key = NULL; +@@ -726,16 +728,24 @@ + * For RSA keys, prefer to use the signature type negotiated + * during KEX to the default (SHA1). + */ +- use_kexsigtype = kexsigtype == KEY_RSA && +- sshkey_type_plain(key->type) == KEY_RSA; ++ sigalg = NULL; ++ if (sshkey_type_plain(key->type) == KEY_RSA) { ++ if (kex_rsa_sigalg != NULL) ++ sigalg = kex_rsa_sigalg; ++ else if (ssh->kex->flags & KEX_RSA_SHA2_512_SUPPORTED) ++ sigalg = "rsa-sha2-512"; ++ else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) ++ sigalg = "rsa-sha2-256"; ++ } ++ debug3_f("sign %s key (index %d) using sigalg %s", ++ sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); + if ((r = sshbuf_put_cstring(sigbuf, + "hostkeys-prove-00@openssh.com")) != 0 || + (r = sshbuf_put_stringb(sigbuf, + ssh->kex->session_id)) != 0 || + (r = sshkey_puts(key, sigbuf)) != 0 || + (r = ssh->kex->sign(ssh, key_prv, key_pub, &sig, &slen, +- sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), +- use_kexsigtype ? ssh->kex->hostkey_alg : NULL)) != 0 || ++ sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), sigalg)) != 0 || + (r = sshbuf_put_string(resp, sig, slen)) != 0) { + error_fr(r, "assemble signature"); + goto out; diff --git a/openssh-8.7p1-minrsabits.patch b/openssh-8.7p1-minrsabits.patch new file mode 100644 index 0000000..57019b6 --- /dev/null +++ b/openssh-8.7p1-minrsabits.patch @@ -0,0 +1,424 @@ +diff --git a/auth2-hostbased.c b/auth2-hostbased.c +index 2ab222ed6..4e9437912 100644 +--- a/auth2-hostbased.c ++++ b/auth2-hostbased.c +@@ -118,6 +118,10 @@ userauth_hostbased(struct ssh *ssh, const char *method) + "(null)" : key->cert->signature_type); + goto done; + } ++ if ((r = sshkey_check_rsa_length(key, options.rsa_min_size)) != 0) { ++ logit("refusing %s key", sshkey_type(key)); ++ goto done; ++ } + + if (!authctxt->valid || authctxt->user == NULL) { + debug2_f("disabled because of invalid user"); +diff --git a/auth2-pubkey.c b/auth2-pubkey.c +index daa756a01..68e7dea1f 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -172,6 +172,10 @@ userauth_pubkey(struct ssh *ssh, const char *method) + "(null)" : key->cert->signature_type); + goto done; + } ++ if ((r = sshkey_check_rsa_length(key, options.rsa_min_size)) != 0) { ++ logit("refusing %s key", sshkey_type(key)); ++ goto done; ++ } + key_s = format_key(key); + if (sshkey_is_cert(key)) + ca_s = format_key(key->cert->signature_key); +diff --git a/readconf.c b/readconf.c +index 5b5afa8e3..5e17abd41 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -160,7 +160,7 @@ typedef enum { + oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, + oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms, + oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, +- oSecurityKeyProvider, oKnownHostsCommand, ++ oSecurityKeyProvider, oKnownHostsCommand, oRSAMinSize, + oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported + } OpCodes; + +@@ -306,6 +306,7 @@ static struct { + { "proxyjump", oProxyJump }, + { "securitykeyprovider", oSecurityKeyProvider }, + { "knownhostscommand", oKnownHostsCommand }, ++ { "rsaminsize", oRSAMinSize }, + + { NULL, oBadOption } + }; +@@ -2162,6 +2163,10 @@ process_config_line_depth(Options *options, struct passwd *pw, const char *host, + *charptr = xstrdup(arg); + break; + ++ case oRSAMinSize: ++ intptr = &options->rsa_min_size; ++ goto parse_int; ++ + case oDeprecated: + debug("%s line %d: Deprecated option \"%s\"", + filename, linenum, keyword); +@@ -2409,6 +2414,7 @@ initialize_options(Options * options) + options->hostbased_accepted_algos = NULL; + options->pubkey_accepted_algos = NULL; + options->known_hosts_command = NULL; ++ options->rsa_min_size = -1; + } + + /* +@@ -2598,6 +2604,8 @@ fill_default_options(Options * options) + if (options->sk_provider == NULL) + options->sk_provider = xstrdup("$SSH_SK_PROVIDER"); + #endif ++ if (options->rsa_min_size == -1) ++ options->rsa_min_size = SSH_RSA_MINIMUM_MODULUS_SIZE; + + /* Expand KEX name lists */ + all_cipher = cipher_alg_list(',', 0); +@@ -3287,6 +3295,7 @@ dump_client_config(Options *o, const char *host) + dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); + dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); + dump_cfg_int(oServerAliveInterval, o->server_alive_interval); ++ dump_cfg_int(oRSAMinSize, o->rsa_min_size); + + /* String options */ + dump_cfg_string(oBindAddress, o->bind_address); +diff --git a/readconf.h b/readconf.h +index f647bd42a..29db353ab 100644 +--- a/readconf.h ++++ b/readconf.h +@@ -176,6 +176,8 @@ typedef struct { + + char *known_hosts_command; + ++ int rsa_min_size; /* minimum size of RSA keys */ ++ + char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ + } Options; + +diff --git a/servconf.c b/servconf.c +index f7317a5cb..362ff5b67 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -177,6 +177,7 @@ initialize_server_options(ServerOptions *options) + options->fingerprint_hash = -1; + options->disable_forwarding = -1; + options->expose_userauth_info = -1; ++ options->rsa_min_size = -1; + } + + /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ +@@ -416,6 +417,8 @@ fill_default_server_options(ServerOptions *options) + options->expose_userauth_info = 0; + if (options->sk_provider == NULL) + options->sk_provider = xstrdup("internal"); ++ if (options->rsa_min_size == -1) ++ options->rsa_min_size = SSH_RSA_MINIMUM_MODULUS_SIZE; + + assemble_algorithms(options); + +@@ -489,6 +492,7 @@ typedef enum { + sStreamLocalBindMask, sStreamLocalBindUnlink, + sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, + sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, ++ sRSAMinSize, + sDeprecated, sIgnore, sUnsupported + } ServerOpCodes; + +@@ -632,6 +636,7 @@ static struct { + { "rdomain", sRDomain, SSHCFG_ALL }, + { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, + { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, ++ { "rsaminsize", sRSAMinSize, SSHCFG_ALL }, + { NULL, sBadOption, 0 } + }; + +@@ -2377,6 +2382,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, + *charptr = xstrdup(arg); + break; + ++ case sRSAMinSize: ++ intptr = &options->rsa_min_size; ++ goto parse_int; ++ + case sDeprecated: + case sIgnore: + case sUnsupported: +@@ -2549,6 +2558,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) + M_CP_INTOPT(rekey_limit); + M_CP_INTOPT(rekey_interval); + M_CP_INTOPT(log_level); ++ M_CP_INTOPT(rsa_min_size); + + /* + * The bind_mask is a mode_t that may be unsigned, so we can't use +@@ -2810,6 +2820,7 @@ dump_config(ServerOptions *o) + dump_cfg_int(sMaxSessions, o->max_sessions); + dump_cfg_int(sClientAliveInterval, o->client_alive_interval); + dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max); ++ dump_cfg_int(sRSAMinSize, o->rsa_min_size); + dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask); + + /* formatted integer arguments */ +diff --git a/servconf.h b/servconf.h +index 115db1e79..2e3486906 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -227,6 +227,7 @@ typedef struct { + int expose_userauth_info; + u_int64_t timing_secret; + char *sk_provider; ++ int rsa_min_size; /* minimum size of RSA keys */ + } ServerOptions; + + /* Information about the incoming connection as used by Match */ +diff --git a/ssh.c b/ssh.c +index a926cc007..cd13fb879 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -500,14 +500,22 @@ resolve_canonicalize(char **hostp, int port) + } + + /* +- * Check the result of hostkey loading, ignoring some errors and +- * fatal()ing for others. ++ * Check the result of hostkey loading, ignoring some errors and either ++ * discarding the key or fatal()ing for others. + */ + static void +-check_load(int r, const char *path, const char *message) ++check_load(int r, struct sshkey **k, const char *path, const char *message) + { + switch (r) { + case 0: ++ /* Check RSA keys size and discard if undersized */ ++ if (k != NULL && *k != NULL && ++ (r = sshkey_check_rsa_length(*k, ++ options.rsa_min_size)) != 0) { ++ error_r(r, "load %s \"%s\"", message, path); ++ free(*k); ++ *k = NULL; ++ } + break; + case SSH_ERR_INTERNAL_ERROR: + case SSH_ERR_ALLOC_FAIL: +@@ -1557,12 +1565,13 @@ main(int ac, char **av) + if ((o) >= sensitive_data.nkeys) \ + fatal_f("pubkey out of array bounds"); \ + check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \ +- p, "pubkey"); \ ++ &(sensitive_data.keys[o]), p, "pubkey"); \ + } while (0) + #define L_CERT(p,o) do { \ + if ((o) >= sensitive_data.nkeys) \ + fatal_f("cert out of array bounds"); \ +- check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \ ++ check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), \ ++ &(sensitive_data.keys[o]), p, "cert"); \ + } while (0) + + if (options.hostbased_authentication == 1) { +@@ -2244,7 +2253,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) + filename = default_client_percent_dollar_expand(cp, cinfo); + free(cp); + check_load(sshkey_load_public(filename, &public, NULL), +- filename, "pubkey"); ++ &public, filename, "pubkey"); + debug("identity file %s type %d", filename, + public ? public->type : -1); + free(options.identity_files[i]); +@@ -2263,7 +2272,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) + continue; + xasprintf(&cp, "%s-cert", filename); + check_load(sshkey_load_public(cp, &public, NULL), +- filename, "pubkey"); ++ &public, filename, "pubkey"); + debug("identity file %s type %d", cp, + public ? public->type : -1); + if (public == NULL) { +@@ -2294,7 +2303,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) + free(cp); + + check_load(sshkey_load_public(filename, &public, NULL), +- filename, "certificate"); ++ &public, filename, "certificate"); + debug("certificate file %s type %d", filename, + public ? public->type : -1); + free(options.certificate_files[i]); +diff --git a/sshconnect2.c b/sshconnect2.c +index 67f8e0309..d050c1656 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -91,6 +91,10 @@ static const struct ssh_conn_info *xxx_conn_info; + static int + verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh) + { ++ int r; ++ ++ if ((r = sshkey_check_rsa_length(hostkey, options.rsa_min_size)) != 0) ++ fatal_r(r, "Bad server host key"); + if (verify_host_key(xxx_host, xxx_hostaddr, hostkey, + xxx_conn_info) == -1) + fatal("Host key verification failed."); +@@ -1747,6 +1751,12 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt) + close(agent_fd); + } else { + for (j = 0; j < idlist->nkeys; j++) { ++ if ((r = sshkey_check_rsa_length(idlist->keys[j], ++ options.rsa_min_size)) != 0) { ++ debug_fr(r, "ignoring %s agent key", ++ sshkey_ssh_name(idlist->keys[j])); ++ continue; ++ } + found = 0; + TAILQ_FOREACH(id, &files, next) { + /* +diff --git a/sshd.c b/sshd.c +index d26eb86ae..5f36905a1 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -1746,6 +1746,13 @@ main(int ac, char **av) + fatal_r(r, "Could not demote key: \"%s\"", + options.host_key_files[i]); + } ++ if (pubkey != NULL && (r = sshkey_check_rsa_length(pubkey, ++ options.rsa_min_size)) != 0) { ++ error_fr(r, "Host key %s", options.host_key_files[i]); ++ sshkey_free(pubkey); ++ sshkey_free(key); ++ continue; ++ } + sensitive_data.host_keys[i] = key; + sensitive_data.host_pubkeys[i] = pubkey; + +diff --git a/sshkey.c b/sshkey.c +index 47864e6d8..8bad6bd99 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -2319,18 +2319,24 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) + return ret; + } + +-#ifdef WITH_OPENSSL +-static int +-check_rsa_length(const RSA *rsa) ++int ++sshkey_check_rsa_length(const struct sshkey *k, int min_size) + { ++#ifdef WITH_OPENSSL + const BIGNUM *rsa_n; ++ int nbits; + +- RSA_get0_key(rsa, &rsa_n, NULL, NULL); +- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) ++ if (k == NULL || k->rsa == NULL || ++ (k->type != KEY_RSA && k->type != KEY_RSA_CERT)) ++ return 0; ++ RSA_get0_key(k->rsa, &rsa_n, NULL, NULL); ++ nbits = BN_num_bits(rsa_n); ++ if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE || ++ (min_size > 0 && nbits < min_size)) + return SSH_ERR_KEY_LENGTH; ++#endif /* WITH_OPENSSL */ + return 0; + } +-#endif + + static int + sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, +@@ -2391,7 +2397,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, + goto out; + } + rsa_n = rsa_e = NULL; /* transferred */ +- if ((ret = check_rsa_length(key->rsa)) != 0) ++ if ((ret = sshkey_check_rsa_length(key, 0)) != 0) + goto out; + #ifdef DEBUG_PK + RSA_print_fp(stderr, key->rsa, 8); +@@ -3580,7 +3586,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) + goto out; + } + rsa_p = rsa_q = NULL; /* transferred */ +- if ((r = check_rsa_length(k->rsa)) != 0) ++ if ((r = sshkey_check_rsa_length(k, 0)) != 0) + goto out; + if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0) + goto out; +@@ -4566,7 +4572,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- if ((r = check_rsa_length(prv->rsa)) != 0) ++ if ((r = sshkey_check_rsa_length(prv, 0)) != 0) + goto out; + } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA && + (type == KEY_UNSPEC || type == KEY_DSA)) { +diff --git a/sshkey.h b/sshkey.h +index 125cadb64..52e879456 100644 +--- a/sshkey.h ++++ b/sshkey.h +@@ -267,6 +267,7 @@ int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, + int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, + int type, struct sshkey **pubkeyp); + ++int sshkey_check_rsa_length(const struct sshkey *, int); + /* XXX should be internal, but used by ssh-keygen */ + int ssh_rsa_complete_crt_parameters(struct sshkey *, const BIGNUM *); + +diff --git a/ssh.1 b/ssh.1 +index b4956aec..b1a40ebd 100644 +--- a/ssh.1 ++++ b/ssh.1 +@@ -554,6 +554,7 @@ For full details of the options listed below, and their possible values, see + .It LogLevel + .It MACs + .It Match ++.It RSAMinSize + .It NoHostAuthenticationForLocalhost + .It NumberOfPasswordPrompts + .It PasswordAuthentication +diff --git a/ssh_config.5 b/ssh_config.5 +index 24a46460..68771e4b 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -1322,6 +1322,10 @@ The argument to this keyword must be + or + .Cm no + (the default). ++.It Cm RSAMinSize ++Provides a minimal bits requirement for RSA keys when used for signature and ++verification but not for the key generation. The default value is 1024 and ++can't be reduced. + .It Cm NumberOfPasswordPrompts + Specifies the number of password prompts before giving up. + The argument to this keyword must be an integer. +diff --git a/sshd_config.5 b/sshd_config.5 +index 867a747d..e08811ca 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1266,6 +1266,10 @@ will refuse connection attempts with a probability of rate/100 (30%) + if there are currently start (10) unauthenticated connections. + The probability increases linearly and all connection attempts + are refused if the number of unauthenticated connections reaches full (60). ++.It Cm RSAMinSize ++Provides a minimal bits requirement for RSA keys when used for signature and ++verification but not for the key generation. The default value is 1024 and ++can't be reduced. + .It Cm ModuliFile + Specifies the + .Xr moduli 5 +diff --git a/sshkey.h b/sshkey.h +index 094815e0..2bb8cb90 100644 +--- a/sshkey.h ++++ b/sshkey.h +@@ -286,6 +286,8 @@ int sshkey_private_serialize_maxsign(struct sshkey *key, + + void sshkey_sig_details_free(struct sshkey_sig_details *); + ++int ssh_set_rsa_min_bits(int minbits); ++ + #ifdef SSHKEY_INTERNAL + int ssh_rsa_sign(const struct sshkey *key, + u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, diff --git a/openssh-8.7p1-negotiate-supported-algs.patch b/openssh-8.7p1-negotiate-supported-algs.patch new file mode 100644 index 0000000..2fb9297 --- /dev/null +++ b/openssh-8.7p1-negotiate-supported-algs.patch @@ -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) { diff --git a/openssh-8.7p1-recursive-scp.patch b/openssh-8.7p1-recursive-scp.patch new file mode 100644 index 0000000..25765fb --- /dev/null +++ b/openssh-8.7p1-recursive-scp.patch @@ -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); diff --git a/openssh-8.7p1-scp-clears-file.patch b/openssh-8.7p1-scp-clears-file.patch new file mode 100644 index 0000000..4c033da --- /dev/null +++ b/openssh-8.7p1-scp-clears-file.patch @@ -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 diff --git a/openssh-8.7p1-sftpscp-dir-create.patch b/openssh-8.7p1-sftpscp-dir-create.patch new file mode 100644 index 0000000..bc504f9 --- /dev/null +++ b/openssh-8.7p1-sftpscp-dir-create.patch @@ -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); diff --git a/openssh-8.7p1-ssh-manpage.patch b/openssh-8.7p1-ssh-manpage.patch new file mode 100644 index 0000000..bd0bdb7 --- /dev/null +++ b/openssh-8.7p1-ssh-manpage.patch @@ -0,0 +1,53 @@ +diff --color -ru a/ssh.1 b/ssh.1 +--- a/ssh.1 2022-07-12 11:47:51.307295880 +0200 ++++ b/ssh.1 2022-07-12 11:50:28.793363263 +0200 +@@ -493,6 +493,7 @@ + .It AddressFamily + .It BatchMode + .It BindAddress ++.It BindInterface + .It CanonicalDomains + .It CanonicalizeFallbackLocal + .It CanonicalizeHostname +@@ -510,6 +511,7 @@ + .It ControlPath + .It ControlPersist + .It DynamicForward ++.It EnableSSHKeysign + .It EscapeChar + .It ExitOnForwardFailure + .It FingerprintHash +@@ -538,6 +540,8 @@ + .It IdentitiesOnly + .It IdentityAgent + .It IdentityFile ++.It IgnoreUnknown ++.It Include + .It IPQoS + .It KbdInteractiveAuthentication + .It KbdInteractiveDevices +@@ -546,6 +550,7 @@ + .It LocalCommand + .It LocalForward + .It LogLevel ++.It LogVerbose + .It MACs + .It Match + .It RSAMinSize +@@ -566,6 +571,8 @@ + .It RemoteCommand + .It RemoteForward + .It RequestTTY ++.It RevokedHostKeys ++.It SecurityKeyProvider + .It SendEnv + .It ServerAliveInterval + .It ServerAliveCountMax +@@ -575,6 +582,7 @@ + .It StreamLocalBindMask + .It StreamLocalBindUnlink + .It StrictHostKeyChecking ++.It SyslogFacility + .It TCPKeepAlive + .It Tunnel + .It TunnelDevice diff --git a/openssh-8.8p1-skip-some-tests.patch b/openssh-8.8p1-skip-some-tests.patch new file mode 100644 index 0000000..7268eb3 --- /dev/null +++ b/openssh-8.8p1-skip-some-tests.patch @@ -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" + diff --git a/openssh.spec b/openssh.spec index 3130e5d..eb64acc 100644 --- a/openssh.spec +++ b/openssh.spec @@ -51,9 +51,9 @@ # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 %global openssh_ver 8.8p1 -%global openssh_rel 3 +%global openssh_rel 4 %global pam_ssh_agent_ver 0.10.4 -%global pam_ssh_agent_rel 5 +%global pam_ssh_agent_rel 6 Summary: An open source implementation of SSH protocol version 2 Name: openssh @@ -102,6 +102,8 @@ Patch306: pam_ssh_agent_auth-0.10.2-compat.patch # Fix NULL dereference from getpwuid() return value # https://sourceforge.net/p/pamsshagentauth/bugs/22/ Patch307: pam_ssh_agent_auth-0.10.2-dereference.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2070113 +Patch308: pam_ssh_agent_auth-0.10.4-rsasha2.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX) Patch400: openssh-7.8p1-role-mls.patch @@ -197,6 +199,62 @@ Patch975: openssh-8.0p1-preserve-pam-errors.patch Patch976: openssh-8.7p1-sftp-default-protocol.patch # Implement kill switch for SCP protocol Patch977: openssh-8.7p1-scp-kill-switch.patch +# Create non-existent directories when scp works in sftp mode and some more minor fixes +# upstream commits: +# ba61123eef9c6356d438c90c1199a57a0d7bcb0a +# 63670d4e9030bcee490d5a9cce561373ac5b3b23 +# ac7c9ec894ed0825d04ef69c55babb49bab1d32e +Patch980: openssh-8.7p1-sftpscp-dir-create.patch +# Workaround for lack of sftp_realpath in older versions of RHEL +# https://bugzilla.redhat.com/show_bug.cgi?id=2038854 +# https://github.com/openssh/openssh-portable/pull/299 +# downstream only +Patch981: openssh-8.7p1-recursive-scp.patch +# https://github.com/djmdjm/openssh-wip/pull/13 +Patch982: openssh-8.7p1-minrsabits.patch +# downstream only +Patch983: openssh-8.7p1-evpgenkey.patch +# downstream only, IBMCA tentative fix +# From https://bugzilla.redhat.com/show_bug.cgi?id=1976202#c14 +Patch984: openssh-8.7p1-ibmca.patch + +# Minimize the use of SHA1 as a proof of possession for RSA key (#2031868) +# upstream commits: +# 291721bc7c840d113a49518f3fca70e86248b8e8 +# 0fa33683223c76289470a954404047bc762be84c +Patch1000: openssh-8.7p1-minimize-sha1-use.patch +# Fix for scp clearing file when src and dest are the same (#2056884) +# upstream commits: +# 7b1cbcb7599d9f6a3bbad79d412604aa1203b5ee +Patch1001: openssh-8.7p1-scp-clears-file.patch +# Add missing options from ssh_config into ssh manpage +# upstream bug: +# https://bugzilla.mindrot.org/show_bug.cgi?id=3455 +Patch1002: openssh-8.7p1-ssh-manpage.patch +# Always return allocated strings from the kex filtering so that we can free them +# upstream commits: +# 486c4dc3b83b4b67d663fb0fa62bc24138ec3946 +# 6c31ba10e97b6953c4f325f526f3e846dfea647a +# 322964f8f2e9c321e77ebae1e4d2cd0ccc5c5a0b +Patch1003: openssh-8.7p1-mem-leak.patch +# Reenable MONITOR_REQ_GSSCHECKMIC after gssapi-with-mic failures +# upstream MR: +# https://github.com/openssh-gsskex/openssh-gsskex/pull/21 +Patch1004: openssh-8.7p1-gssapi-auth.patch +# Fix host-based authentication with rsa keys +# upstream commits: +# 7aa7b096cf2bafe2777085abdeed5ce00581f641 +# d9dbb5d9a0326e252d3c7bc13beb9c2434f59409 +# fdb1d58d0d3888b042e5a500f6ce524486aaf782 +Patch1005: openssh-8.7p1-host-based-auth.patch +# Don't propose disallowed algorithms during hostkey negotiation +# upstream MR: +# https://github.com/openssh/openssh-portable/pull/323 +Patch1006: openssh-8.7p1-negotiate-supported-algs.patch + +# downstream only +# we skip some ssh-rsa/ssh-dss tests to make native test suite pass +Patch1100: openssh-8.8p1-skip-some-tests.patch License: BSD Requires: /sbin/nologin @@ -325,6 +383,7 @@ pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} %patch306 -p2 -b .psaa-compat %patch305 -p2 -b .psaa-agent %patch307 -p2 -b .psaa-deref +%patch308 -p2 -b .rsasha2 # Remove duplicate headers and library files rm -f $(cat %{SOURCE5}) popd @@ -375,11 +434,26 @@ popd %patch975 -p1 -b .preserve-pam-errors %patch976 -p1 -b .sftp-by-default %patch977 -p1 -b .kill-scp +%patch980 -p1 -b .sftpdirs +%patch981 -p1 -b .scp-sftpdirs +%patch982 -p1 -b .minrsabits +%patch983 -p1 -b .evpgenrsa +%patch984 -p1 -b .ibmca %patch200 -p1 -b .audit %patch201 -p1 -b .audit-race %patch700 -p1 -b .fips +%patch1000 -p1 -b .minimize-sha1-use +%patch1001 -p1 -b .scp-clears-file +%patch1002 -p1 -b .ssh-manpage +%patch1003 -p1 -b .mem-leak +%patch1004 -p1 -b .gssapi-auth +%patch1005 -p1 -b .host-based-auth +%patch1006 -p1 -b .negotiate-supported-algs + +%patch1100 -p1 -b .skipsshrsadsstests + %patch100 -p1 -b .coverity autoreconf @@ -661,6 +735,9 @@ test -f %{sysconfig_anaconda} && \ %endif %changelog +* Wed Aug 10 2022 Dmitry Belyavskiy - 8.8p1-4 + 0.10.4-6 +- Port patches from CentOS (rhbz#2117264) + * Mon Aug 01 2022 Luca BRUNO - 8.8p1-3 - Use allocated static GID for 'ssh_keys' group (rhbz#2104595) diff --git a/pam_ssh_agent_auth-0.10.4-rsasha2.patch b/pam_ssh_agent_auth-0.10.4-rsasha2.patch new file mode 100644 index 0000000..c8815bb --- /dev/null +++ b/pam_ssh_agent_auth-0.10.4-rsasha2.patch @@ -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)