diff --git a/.gitignore b/.gitignore index a2916ba..3a5b7e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ SOURCES/gpgkey-736060BA.gpg -SOURCES/openssh-8.7p1.tar.gz +SOURCES/openssh-9.9p1.tar.gz SOURCES/pam_ssh_agent_auth-0.10.4.tar.gz diff --git a/.openssh.metadata b/.openssh.metadata index 5891957..9c348a8 100644 --- a/.openssh.metadata +++ b/.openssh.metadata @@ -1,3 +1,3 @@ dbb35b4e9ae3f72b930a82c6fd5e83e9dcd7b193 SOURCES/gpgkey-736060BA.gpg -8719032c1e47732c8fdb14adfb24b5e9e71de802 SOURCES/openssh-8.7p1.tar.gz +5ded7eb0add0b02b5d1a1c4bf5cb2c89d2117b53 SOURCES/openssh-9.9p1.tar.gz 66dd8274346fd006ff40f525c082cfb701085b5f SOURCES/pam_ssh_agent_auth-0.10.4.tar.gz diff --git a/SOURCES/openssh-5.8p2-sigpipe.patch b/SOURCES/openssh-5.8p2-sigpipe.patch index 56af045..554e346 100644 --- a/SOURCES/openssh-5.8p2-sigpipe.patch +++ b/SOURCES/openssh-5.8p2-sigpipe.patch @@ -1,12 +1,14 @@ diff -up openssh-5.8p2/ssh-keyscan.c.sigpipe openssh-5.8p2/ssh-keyscan.c --- openssh-5.8p2/ssh-keyscan.c.sigpipe 2011-08-23 18:30:33.873025916 +0200 +++ openssh-5.8p2/ssh-keyscan.c 2011-08-23 18:32:24.574025362 +0200 -@@ -715,6 +715,8 @@ main(int argc, char **argv) +@@ -715,6 +715,9 @@ main(int argc, char **argv) + if (maxfd > fdlim_get(0)) fdlim_set(maxfd); fdcon = xcalloc(maxfd, sizeof(con)); - ++ + signal(SIGPIPE, SIG_IGN); + - read_wait_nfdset = howmany(maxfd, NFDBITS); - read_wait = xcalloc(read_wait_nfdset, sizeof(fd_mask)); + read_wait = xcalloc(maxfd, sizeof(struct pollfd)); + for (j = 0; j < maxfd; j++) + read_wait[j].fd = -1; diff --git a/SOURCES/openssh-6.3p1-ctr-evp-fast.patch b/SOURCES/openssh-6.3p1-ctr-evp-fast.patch deleted file mode 100644 index ddcb7f1..0000000 --- a/SOURCES/openssh-6.3p1-ctr-evp-fast.patch +++ /dev/null @@ -1,101 +0,0 @@ -diff -up openssh-5.9p1/cipher-ctr.c.ctr-evp openssh-5.9p1/cipher-ctr.c ---- openssh-5.9p1/cipher-ctr.c.ctr-evp 2012-01-11 09:24:06.000000000 +0100 -+++ openssh-5.9p1/cipher-ctr.c 2012-01-11 15:54:04.675956600 +0100 -@@ -38,7 +38,7 @@ void ssh_aes_ctr_iv(EVP_CIPHER_CTX *, in - - struct ssh_aes_ctr_ctx - { -- AES_KEY aes_ctx; -+ EVP_CIPHER_CTX ecbctx; - u_char aes_counter[AES_BLOCK_SIZE]; - }; - -@@ -63,21 +63,42 @@ ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char - { - struct ssh_aes_ctr_ctx *c; - size_t n = 0; -- u_char buf[AES_BLOCK_SIZE]; -+ u_char ctrbuf[AES_BLOCK_SIZE*256]; -+ u_char buf[AES_BLOCK_SIZE*256]; - - if (len == 0) - return (1); - if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) - return (0); - -- while ((len--) > 0) { -+ for (; len > 0; len -= sizeof(u_int)) { -+ u_int r,a,b; -+ - if (n == 0) { -- AES_encrypt(c->aes_counter, buf, &c->aes_ctx); -- ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE); -+ int outl, i, buflen; -+ -+ buflen = MIN(len, sizeof(ctrbuf)); -+ -+ for(i = 0; i < buflen; i += AES_BLOCK_SIZE) { -+ memcpy(&ctrbuf[i], c->aes_counter, AES_BLOCK_SIZE); -+ ssh_ctr_inc(c->aes_counter, AES_BLOCK_SIZE); -+ } -+ -+ EVP_EncryptUpdate(&c->ecbctx, buf, &outl, -+ ctrbuf, buflen); - } -- *(dest++) = *(src++) ^ buf[n]; -- n = (n + 1) % AES_BLOCK_SIZE; -+ -+ memcpy(&a, src, sizeof(a)); -+ memcpy(&b, &buf[n], sizeof(b)); -+ r = a ^ b; -+ memcpy(dest, &r, sizeof(r)); -+ src += sizeof(a); -+ dest += sizeof(r); -+ -+ n = (n + sizeof(b)) % sizeof(buf); - } -+ memset(ctrbuf, '\0', sizeof(ctrbuf)); -+ memset(buf, '\0', sizeof(buf)); - return (1); - } - -@@ -91,9 +112,28 @@ ssh_aes_ctr_init(EVP_CIPHER_CTX *ctx, co - c = xmalloc(sizeof(*c)); - EVP_CIPHER_CTX_set_app_data(ctx, c); - } -- if (key != NULL) -- AES_set_encrypt_key(key, EVP_CIPHER_CTX_key_length(ctx) * 8, -- &c->aes_ctx); -+ -+ EVP_CIPHER_CTX_init(&c->ecbctx); -+ -+ if (key != NULL) { -+ const EVP_CIPHER *cipher; -+ switch(EVP_CIPHER_CTX_key_length(ctx)*8) { -+ case 128: -+ cipher = EVP_aes_128_ecb(); -+ break; -+ case 192: -+ cipher = EVP_aes_192_ecb(); -+ break; -+ case 256: -+ cipher = EVP_aes_256_ecb(); -+ break; -+ default: -+ fatal("ssh_aes_ctr_init: wrong aes key length"); -+ } -+ if(!EVP_EncryptInit_ex(&c->ecbctx, cipher, NULL, key, NULL)) -+ fatal("ssh_aes_ctr_init: cannot initialize aes encryption"); -+ EVP_CIPHER_CTX_set_padding(&c->ecbctx, 0); -+ } - if (iv != NULL) - memcpy(c->aes_counter, iv, AES_BLOCK_SIZE); - return (1); -@@ -105,6 +145,7 @@ ssh_aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) - struct ssh_aes_ctr_ctx *c; - - if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) { -+ EVP_CIPHER_CTX_cleanup(&c->ecbctx); - memset(c, 0, sizeof(*c)); - free(c); - EVP_CIPHER_CTX_set_app_data(ctx, NULL); diff --git a/SOURCES/openssh-6.6.1p1-log-in-chroot.patch b/SOURCES/openssh-6.6.1p1-log-in-chroot.patch index bf3293f..0f65279 100644 --- a/SOURCES/openssh-6.6.1p1-log-in-chroot.patch +++ b/SOURCES/openssh-6.6.1p1-log-in-chroot.patch @@ -1,6 +1,6 @@ diff -up openssh-8.6p1/log.c.log-in-chroot openssh-8.6p1/log.c --- openssh-8.6p1/log.c.log-in-chroot 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/log.c 2021-05-06 11:32:25.179006811 +0200 ++++ openssh-8.6p1/log.c 2021-04-19 14:43:08.544843434 +0200 @@ -194,6 +194,11 @@ void log_init(const char *av0, LogLevel level, SyslogFacility facility, int on_stderr) @@ -27,8 +27,8 @@ diff -up openssh-8.6p1/log.c.log-in-chroot openssh-8.6p1/log.c log_on_stderr = on_stderr; if (on_stderr) diff -up openssh-8.6p1/log.h.log-in-chroot openssh-8.6p1/log.h ---- openssh-8.6p1/log.h.log-in-chroot 2021-05-06 11:32:25.179006811 +0200 -+++ openssh-8.6p1/log.h 2021-05-06 11:34:22.349925757 +0200 +--- openssh-8.6p1/log.h.log-in-chroot 2021-04-19 14:43:08.544843434 +0200 ++++ openssh-8.6p1/log.h 2021-04-19 14:56:46.931042176 +0200 @@ -52,6 +52,7 @@ typedef enum { typedef void (log_handler_fn)(LogLevel, int, const char *, void *); @@ -38,8 +38,8 @@ diff -up openssh-8.6p1/log.h.log-in-chroot openssh-8.6p1/log.h int log_change_level(LogLevel); int log_is_on_stderr(void); diff -up openssh-8.6p1/monitor.c.log-in-chroot openssh-8.6p1/monitor.c ---- openssh-8.6p1/monitor.c.log-in-chroot 2021-05-06 11:32:25.153006607 +0200 -+++ openssh-8.6p1/monitor.c 2021-05-06 11:33:37.671575348 +0200 +--- openssh-8.6p1/monitor.c.log-in-chroot 2021-04-19 14:43:08.526843298 +0200 ++++ openssh-8.6p1/monitor.c 2021-04-19 14:55:25.286424043 +0200 @@ -297,6 +297,8 @@ monitor_child_preauth(struct ssh *ssh, s close(pmonitor->m_log_sendfd); pmonitor->m_log_sendfd = pmonitor->m_recvfd = -1; @@ -99,8 +99,8 @@ diff -up openssh-8.6p1/monitor.c.log-in-chroot openssh-8.6p1/monitor.c #ifdef GSSAPI diff -up openssh-8.6p1/monitor.h.log-in-chroot openssh-8.6p1/monitor.h ---- openssh-8.6p1/monitor.h.log-in-chroot 2021-05-06 11:32:25.153006607 +0200 -+++ openssh-8.6p1/monitor.h 2021-05-06 11:32:25.180006819 +0200 +--- openssh-8.6p1/monitor.h.log-in-chroot 2021-04-19 14:43:08.527843305 +0200 ++++ openssh-8.6p1/monitor.h 2021-04-19 14:43:08.545843441 +0200 @@ -80,10 +80,11 @@ struct monitor { int m_log_sendfd; struct kex **m_pkex; @@ -115,8 +115,8 @@ diff -up openssh-8.6p1/monitor.h.log-in-chroot openssh-8.6p1/monitor.h struct Authctxt; void monitor_child_preauth(struct ssh *, struct monitor *); diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c ---- openssh-8.6p1/session.c.log-in-chroot 2021-05-06 11:32:25.166006709 +0200 -+++ openssh-8.6p1/session.c 2021-05-06 11:32:25.181006827 +0200 +--- openssh-8.6p1/session.c.log-in-chroot 2021-04-19 14:43:08.534843358 +0200 ++++ openssh-8.6p1/session.c 2021-04-19 14:43:08.545843441 +0200 @@ -160,6 +160,7 @@ login_cap_t *lc; static int is_child = 0; @@ -189,7 +189,7 @@ diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c /* Get the last component of the shell name. */ diff -up openssh-8.6p1/sftp.h.log-in-chroot openssh-8.6p1/sftp.h --- openssh-8.6p1/sftp.h.log-in-chroot 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/sftp.h 2021-05-06 11:32:25.181006827 +0200 ++++ openssh-8.6p1/sftp.h 2021-04-19 14:43:08.545843441 +0200 @@ -97,5 +97,5 @@ struct passwd; @@ -199,7 +199,7 @@ diff -up openssh-8.6p1/sftp.h.log-in-chroot openssh-8.6p1/sftp.h void sftp_server_cleanup_exit(int) __attribute__((noreturn)); diff -up openssh-8.6p1/sftp-server.c.log-in-chroot openssh-8.6p1/sftp-server.c --- openssh-8.6p1/sftp-server.c.log-in-chroot 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/sftp-server.c 2021-05-06 11:32:25.181006827 +0200 ++++ openssh-8.6p1/sftp-server.c 2021-04-19 14:43:08.545843441 +0200 @@ -1644,7 +1644,7 @@ sftp_server_usage(void) } @@ -207,8 +207,8 @@ diff -up openssh-8.6p1/sftp-server.c.log-in-chroot openssh-8.6p1/sftp-server.c -sftp_server_main(int argc, char **argv, struct passwd *user_pw) +sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handler) { - fd_set *rset, *wset; - int i, r, in, out, max, ch, skipargs = 0, log_stderr = 0; + int i, r, in, out, ch, skipargs = 0, log_stderr = 0; + ssize_t len, olen; @@ -1657,7 +1657,7 @@ sftp_server_main(int argc, char **argv, extern char *__progname; @@ -229,7 +229,7 @@ diff -up openssh-8.6p1/sftp-server.c.log-in-chroot openssh-8.6p1/sftp-server.c * On platforms where we can, avoid making /proc/self/{mem,maps} diff -up openssh-8.6p1/sftp-server-main.c.log-in-chroot openssh-8.6p1/sftp-server-main.c --- openssh-8.6p1/sftp-server-main.c.log-in-chroot 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/sftp-server-main.c 2021-05-06 11:32:25.181006827 +0200 ++++ openssh-8.6p1/sftp-server-main.c 2021-04-19 14:43:08.545843441 +0200 @@ -50,5 +50,5 @@ main(int argc, char **argv) return 1; } @@ -237,11 +237,11 @@ diff -up openssh-8.6p1/sftp-server-main.c.log-in-chroot openssh-8.6p1/sftp-serve - return (sftp_server_main(argc, argv, user_pw)); + return (sftp_server_main(argc, argv, user_pw, 0)); } -diff -up openssh-8.6p1/sshd.c.log-in-chroot openssh-8.6p1/sshd.c ---- openssh-8.6p1/sshd.c.log-in-chroot 2021-05-06 11:32:25.177006795 +0200 -+++ openssh-8.6p1/sshd.c 2021-05-06 11:32:25.182006834 +0200 +diff -up openssh-8.6p1/sshd-session.c.log-in-chroot openssh-8.6p1/sshd-session.c +--- openssh-8.6p1/sshd-session.c.log-in-chroot 2021-04-19 14:43:08.543843426 +0200 ++++ openssh-8.6p1/sshd-session.c 2021-04-19 14:43:08.545843441 +0200 @@ -559,7 +559,7 @@ privsep_postauth(struct ssh *ssh, Authct - } + #endif /* New socket pair */ - monitor_reinit(pmonitor); diff --git a/SOURCES/openssh-6.6.1p1-selinux-contexts.patch b/SOURCES/openssh-6.6.1p1-selinux-contexts.patch index fa9d591..96161cb 100644 --- a/SOURCES/openssh-6.6.1p1-selinux-contexts.patch +++ b/SOURCES/openssh-6.6.1p1-selinux-contexts.patch @@ -93,19 +93,17 @@ index 8f32464..18a2ca4 100644 #endif diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c -index 22ea8ef..1fc963d 100644 ---- a/openbsd-compat/port-linux.c -+++ b/openbsd-compat/port-linux.c -@@ -179,7 +179,7 @@ ssh_selinux_change_context(const char *newname) - strlcpy(newctx + len, newname, newlen - len); - if ((cx = index(cx + 1, ':'))) - strlcat(newctx, cx, newlen); -- debug3("%s: setting context from '%s' to '%s'", __func__, -+ debug_f("setting context from '%s' to '%s'", - oldctx, newctx); +--- a/openbsd-compat/port-linux.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/openbsd-compat/port-linux.c (date 1703108053912) +@@ -207,7 +207,7 @@ + xasprintf(&newctx, "%.*s%s%s", (int)(cx - oldctx + 1), oldctx, + newname, cx2 == NULL ? "" : cx2); + +- debug3_f("setting context from '%s' to '%s'", oldctx, newctx); ++ debug_f("setting context from '%s' to '%s'", oldctx, newctx); if (setcon(newctx) < 0) - do_log2(log_level, "%s: setcon %s from %s failed with %s", - __func__, newctx, oldctx, strerror(errno)); + do_log2_f(log_level, "setcon %s from %s failed with %s", + newctx, oldctx, strerror(errno)); diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h index cb51f99..8b7cda2 100644 --- a/openbsd-compat/port-linux.h @@ -118,10 +116,10 @@ index cb51f99..8b7cda2 100644 #endif #ifdef LINUX_OOM_ADJUST -diff --git a/sshd.c b/sshd.c +diff --git a/sshd-session.c b/sshd-session.c index 2871fe9..39b9c08 100644 ---- a/sshd.c -+++ b/sshd.c +--- a/sshd-session.c ++++ b/sshd-session.c @@ -629,7 +629,7 @@ privsep_preauth_child(void) demote_sensitive_data(); diff --git a/SOURCES/openssh-6.6p1-GSSAPIEnablek5users.patch b/SOURCES/openssh-6.6p1-GSSAPIEnablek5users.patch index cccb3e0..7fef831 100644 --- a/SOURCES/openssh-6.6p1-GSSAPIEnablek5users.patch +++ b/SOURCES/openssh-6.6p1-GSSAPIEnablek5users.patch @@ -38,16 +38,16 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -418,7 +421,7 @@ typedef enum { - sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, +@@ -578,7 +578,7 @@ typedef enum { sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, + sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, -@@ -497,14 +500,16 @@ static struct { +@@ -600,14 +600,16 @@ static struct { { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, @@ -129,3 +129,6 @@ diff -up openssh-7.4p1/sshd_config.GSSAPIEnablek5users openssh-7.4p1/sshd_config # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will +diff -up openssh-9.8p1/servconf.c.xxx openssh-9.8p1/servconf.c +--- openssh-9.8p1/servconf.c.xxx 2024-07-11 13:51:19.969960781 +0200 ++++ openssh-9.8p1/servconf.c 2024-07-11 13:51:30.938231250 +0200 diff --git a/SOURCES/openssh-6.6p1-allow-ip-opts.patch b/SOURCES/openssh-6.6p1-allow-ip-opts.patch index 953d613..995e04e 100644 --- a/SOURCES/openssh-6.6p1-allow-ip-opts.patch +++ b/SOURCES/openssh-6.6p1-allow-ip-opts.patch @@ -1,7 +1,7 @@ diff -up openssh/sshd.c.ip-opts openssh/sshd.c ---- openssh/sshd.c.ip-opts 2016-07-25 13:58:48.998507834 +0200 -+++ openssh/sshd.c 2016-07-25 14:01:28.346469878 +0200 -@@ -1507,12 +1507,29 @@ check_ip_options(struct ssh *ssh) +--- openssh/sshd-session.c.ip-opts 2016-07-25 13:58:48.998507834 +0200 ++++ openssh/sshd-session.c 2016-07-25 14:01:28.346469878 +0200 +@@ -1507,12 +1507,32 @@ check_ip_options(struct ssh *ssh) if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts, &option_size) >= 0 && option_size != 0) { @@ -21,11 +21,14 @@ diff -up openssh/sshd.c.ip-opts openssh/sshd.c + case 130: + case 133: + case 134: -+ i += opts[i + 1]; -+ break; ++ if (i + 1 < option_size && opts[i + 1] >= 2) { ++ i += opts[i + 1]; ++ break; ++ } ++ /* FALLTHROUGH */ + default: + /* Fail, fatally, if we detect either loose or strict -+ * source routing options. */ ++ * or incorrect source routing options. */ + text[0] = '\0'; + for (i = 0; i < option_size; i++) + snprintf(text + i*3, sizeof(text) - i*3, @@ -35,5 +38,5 @@ diff -up openssh/sshd.c.ip-opts openssh/sshd.c + } + } while (i < option_size); } - return; #endif /* IP_OPTIONS */ + } diff --git a/SOURCES/openssh-6.6p1-keycat.patch b/SOURCES/openssh-6.6p1-keycat.patch index 2aa14bd..4eb0998 100644 --- a/SOURCES/openssh-6.6p1-keycat.patch +++ b/SOURCES/openssh-6.6p1-keycat.patch @@ -39,9 +39,9 @@ diff -up openssh/Makefile.in.keycat openssh/Makefile.in SFTP_SERVER=$(libexecdir)/sftp-server SSH_KEYSIGN=$(libexecdir)/ssh-keysign +SSH_KEYCAT=$(libexecdir)/ssh-keycat + SSHD_SESSION=$(libexecdir)/sshd-session SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper SSH_SK_HELPER=$(libexecdir)/ssh-sk-helper - PRIVSEP_PATH=@PRIVSEP_PATH@ @@ -52,6 +52,7 @@ K5LIBS=@K5LIBS@ K5LIBS=@K5LIBS@ GSSLIBS=@GSSLIBS@ @@ -54,20 +54,20 @@ diff -up openssh/Makefile.in.keycat openssh/Makefile.in .SUFFIXES: .lo --TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) -+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) ssh-keycat$(EXEEXT) +-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) ++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) ssh-keycat$(EXEEXT) XMSS_OBJS=\ ssh-xmss.o \ @@ -190,6 +191,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(SKHELPER_OBJS) - $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2) + $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2) $(CHANNELLIBS) +ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o uidswap.o + $(LD) -o $@ ssh-keycat.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat $(KEYCATLIBS) $(LIBS) + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSCAN_OBJS) - $(LD) -o $@ $(SSHKEYSCAN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) + $(LD) -o $@ $(SSHKEYSCAN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) $(CHANNELLIBS) @@ -321,6 +325,7 @@ install-files: $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) @@ -95,8 +95,8 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/ --- openssh/openbsd-compat/port-linux-sshd.c.keycat 2015-06-24 10:57:50.150849626 +0200 +++ openssh/openbsd-compat/port-linux-sshd.c 2015-06-24 10:57:50.159849603 +0200 @@ -54,6 +54,20 @@ extern Authctxt *the_authctxt; + extern Authctxt *the_authctxt; extern int inetd_flag; - extern int rexeced_flag; +/* Wrapper around is_selinux_enabled() to log its return value once only */ +int @@ -131,7 +131,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/ - rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); + rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : ""); - if (inetd_flag && !rexeced_flag) { + if (inetd_flag) { use_current = "1"; } else { use_current = ""; diff --git a/SOURCES/openssh-6.6p1-kuserok.patch b/SOURCES/openssh-6.6p1-kuserok.patch index 1831f27..e43128b 100644 --- a/SOURCES/openssh-6.6p1-kuserok.patch +++ b/SOURCES/openssh-6.6p1-kuserok.patch @@ -155,8 +155,8 @@ diff -up openssh-7.4p1/gss-serv-krb5.c.kuserok openssh-7.4p1/gss-serv-krb5.c * because if they are on a krb5-protected filesystem, user credentials * to access these files aren't available yet. */ - if (krb5_kuserok(krb_context, princ, name) && k5login_exists) { -+ if (ssh_krb5_kuserok(krb_context, princ, name, k5login_exists) -+ && k5login_exists) { ++ if (k5login_exists && ++ ssh_krb5_kuserok(krb_context, princ, name, k5login_exists)) { retval = 1; logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", name, (char *)client->displayname.value); @@ -196,11 +196,11 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c sPort, sHostKeyFile, sLoginGraceTime, sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, -- sKerberosGetAFSToken, sKerberosUniqueCCache, -+ sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, - sChallengeResponseAuthentication, - sPasswordAuthentication, sKbdInteractiveAuthentication, - sListenAddress, sAddressFamily, +- sKerberosGetAFSToken, sKerberosUniqueCCache, sPasswordAuthentication, ++ sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication, + sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, @@ -478,12 +481,14 @@ static struct { { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, #endif @@ -266,8 +266,8 @@ diff -up openssh-7.4p1/sshd_config.5.kuserok openssh-7.4p1/sshd_config.5 +The default is +.Cm yes . .It Cm KexAlgorithms - Specifies the available KEX (Key Exchange) algorithms. - Multiple algorithms must be comma-separated. + Specifies the permitted KEX (Key Exchange) algorithms that the server will + offer to clients. @@ -1078,6 +1082,7 @@ Available keywords are .Cm IPQoS , .Cm KbdInteractiveAuthentication , diff --git a/SOURCES/openssh-6.6p1-privsep-selinux.patch b/SOURCES/openssh-6.6p1-privsep-selinux.patch index 8047fc3..16d98cd 100644 --- a/SOURCES/openssh-6.6p1-privsep-selinux.patch +++ b/SOURCES/openssh-6.6p1-privsep-selinux.patch @@ -49,7 +49,7 @@ diff -up openssh-7.4p1/session.c.privsep-selinux openssh-7.4p1/session.c platform_setusercontext(pw); - if (platform_privileged_uidswap()) { -+ if (platform_privileged_uidswap() && (!is_child || !use_privsep)) { ++ if (platform_privileged_uidswap() && !is_child) { #ifdef HAVE_LOGIN_CAP if (setusercontext(lc, pw, pw->pw_uid, (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { @@ -96,8 +96,8 @@ diff -up openssh-7.4p1/session.c.privsep-selinux openssh-7.4p1/session.c } diff -up openssh-7.4p1/sshd.c.privsep-selinux openssh-7.4p1/sshd.c ---- openssh-7.4p1/sshd.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100 -+++ openssh-7.4p1/sshd.c 2016-12-23 18:59:13.808124269 +0100 +--- openssh-7.4p1/sshd-session.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100 ++++ openssh-7.4p1/sshd-session.c 2016-12-23 18:59:13.808124269 +0100 @@ -540,6 +540,10 @@ privsep_preauth_child(void) /* Demote the private keys to public keys. */ demote_sensitive_data(); @@ -109,13 +109,12 @@ diff -up openssh-7.4p1/sshd.c.privsep-selinux openssh-7.4p1/sshd.c /* Demote the child */ if (privsep_chroot) { /* Change our root directory */ -@@ -633,6 +637,9 @@ privsep_postauth(Authctxt *authctxt) - { - #ifdef DISABLE_FD_PASSING - if (1) { -+#elif defined(WITH_SELINUX) -+ if (0) { -+ /* even root user can be confined by SELinux */ - #else - if (authctxt->pw->pw_uid == 0) { +@@ -403,7 +403,7 @@ privsep_postauth(struct ssh *ssh, Authct + * fd passing, as AFAIK PTY allocation on this platform doesn't require + * special privileges to begin with. + */ +-#if defined(DISABLE_FD_PASSING) && !defined(HAVE_CYGWIN) ++#if defined(DISABLE_FD_PASSING) && !defined(HAVE_CYGWIN) && !defined(WITH_SELINUX) + skip_privdrop = 1; #endif + diff --git a/SOURCES/openssh-6.7p1-coverity.patch b/SOURCES/openssh-6.7p1-coverity.patch index f12f40e..ffe0c69 100644 --- a/SOURCES/openssh-6.7p1-coverity.patch +++ b/SOURCES/openssh-6.7p1-coverity.patch @@ -1,37 +1,3 @@ -diff -up openssh-8.5p1/addr.c.coverity openssh-8.5p1/addr.c ---- openssh-8.5p1/addr.c.coverity 2021-03-02 11:31:47.000000000 +0100 -+++ openssh-8.5p1/addr.c 2021-03-24 12:03:33.782968159 +0100 -@@ -312,8 +312,10 @@ addr_pton(const char *p, struct xaddr *n - if (p == NULL || getaddrinfo(p, NULL, &hints, &ai) != 0) - return -1; - -- if (ai == NULL || ai->ai_addr == NULL) -+ if (ai == NULL || ai->ai_addr == NULL) { -+ freeaddrinfo(ai); - return -1; -+ } - - if (n != NULL && addr_sa_to_xaddr(ai->ai_addr, ai->ai_addrlen, - n) == -1) { -@@ -336,12 +338,16 @@ addr_sa_pton(const char *h, const char * - if (h == NULL || getaddrinfo(h, s, &hints, &ai) != 0) - return -1; - -- if (ai == NULL || ai->ai_addr == NULL) -+ if (ai == NULL || ai->ai_addr == NULL) { -+ freeaddrinfo(ai); - return -1; -+ } - - if (sa != NULL) { -- if (slen < ai->ai_addrlen) -+ if (slen < ai->ai_addrlen) { -+ freeaddrinfo(ai); - return -1; -+ } - memcpy(sa, &ai->ai_addr, ai->ai_addrlen); - } - diff -up openssh-8.5p1/auth-krb5.c.coverity openssh-8.5p1/auth-krb5.c --- openssh-8.5p1/auth-krb5.c.coverity 2021-03-24 12:03:33.724967756 +0100 +++ openssh-8.5p1/auth-krb5.c 2021-03-24 12:03:33.782968159 +0100 @@ -51,40 +17,6 @@ diff -up openssh-8.5p1/auth-krb5.c.coverity openssh-8.5p1/auth-krb5.c return oerrno; } /* make sure the KRB5CCNAME is set for non-standard location */ -diff -up openssh-8.5p1/auth-options.c.coverity openssh-8.5p1/auth-options.c ---- openssh-8.5p1/auth-options.c.coverity 2021-03-02 11:31:47.000000000 +0100 -+++ openssh-8.5p1/auth-options.c 2021-03-24 12:03:33.782968159 +0100 -@@ -706,6 +708,7 @@ serialise_array(struct sshbuf *m, char * - return r; - } - /* success */ -+ sshbuf_free(b); - return 0; - } - -diff -up openssh-7.4p1/channels.c.coverity openssh-7.4p1/channels.c ---- openssh-7.4p1/channels.c.coverity 2016-12-23 16:40:26.881788686 +0100 -+++ openssh-7.4p1/channels.c 2016-12-23 16:42:36.244818763 +0100 -@@ -1875,7 +1875,7 @@ channel_post_connecting(struct ssh *ssh, - debug("channel %d: connection failed: %s", - c->self, strerror(err)); - /* Try next address, if any */ -- if ((sock = connect_next(&c->connect_ctx)) > 0) { -+ if ((sock = connect_next(&c->connect_ctx)) >= 0) { - close(c->sock); - c->sock = c->rfd = c->wfd = sock; - channel_find_maxfd(ssh->chanctxt); -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 -@@ -282,6 +282,7 @@ verify_host_key_dns(const char *hostname - &hostkey_digest, &hostkey_digest_len, hostkey)) { - error("Error calculating key fingerprint."); - freerrset(fingerprints); -+ free(dnskey_digest); - return -1; - } - diff -up openssh-8.5p1/gss-genr.c.coverity openssh-8.5p1/gss-genr.c --- openssh-8.5p1/gss-genr.c.coverity 2021-03-26 11:52:46.613942552 +0100 +++ openssh-8.5p1/gss-genr.c 2021-03-26 11:54:37.881726318 +0100 @@ -95,21 +27,13 @@ diff -up openssh-8.5p1/gss-genr.c.coverity openssh-8.5p1/gss-genr.c - +#pragma GCC diagnostic ignored "-Wstringop-overflow" cp = strncpy(s, kex, strlen(kex)); -+#pragma pop ++#pragma GCC diagnostic pop for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { if (sshbuf_len(buf) != 0 && diff -up openssh-8.5p1/krl.c.coverity openssh-8.5p1/krl.c --- openssh-8.5p1/krl.c.coverity 2021-03-02 11:31:47.000000000 +0100 +++ openssh-8.5p1/krl.c 2021-03-24 12:03:33.783968166 +0100 -@@ -1209,6 +1209,7 @@ ssh_krl_from_blob(struct sshbuf *buf, st - sshkey_free(key); - sshbuf_free(copy); - sshbuf_free(sect); -+ /* coverity[leaked_storage : FALSE] */ - return r; - } - @@ -1261,6 +1262,7 @@ is_key_revoked(struct ssh_krl *krl, cons return r; erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); @@ -149,22 +73,6 @@ diff -up openssh-8.5p1/loginrec.c.coverity openssh-8.5p1/loginrec.c strncpy(ut->ut_host, li->hostname, MIN_SIZEOF(ut->ut_host, li->hostname)); # endif -@@ -1690,6 +1692,7 @@ record_failed_login(struct ssh *ssh, con - - memset(&ut, 0, sizeof(ut)); - /* strncpy because we don't necessarily want nul termination */ -+ /* coverity[buffer_size_warning : FALSE] */ - strncpy(ut.ut_user, username, sizeof(ut.ut_user)); - strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); - -@@ -1699,6 +1702,7 @@ record_failed_login(struct ssh *ssh, con - ut.ut_pid = getpid(); - - /* strncpy because we don't necessarily want nul termination */ -+ /* coverity[buffer_size_warning : FALSE] */ - strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); - - if (ssh_packet_connection_is_on_socket(ssh) && diff -up openssh-8.5p1/misc.c.coverity openssh-8.5p1/misc.c --- openssh-8.5p1/misc.c.coverity 2021-03-24 12:03:33.745967902 +0100 +++ openssh-8.5p1/misc.c 2021-03-24 13:31:47.037079617 +0100 @@ -185,17 +93,6 @@ diff -up openssh-8.5p1/misc.c.coverity openssh-8.5p1/misc.c return ret; } -diff -up openssh-8.5p1/moduli.c.coverity openssh-8.5p1/moduli.c ---- openssh-8.5p1/moduli.c.coverity 2021-03-02 11:31:47.000000000 +0100 -+++ openssh-8.5p1/moduli.c 2021-03-24 12:03:33.784968173 +0100 -@@ -476,6 +476,7 @@ write_checkpoint(char *cpfile, u_int32_t - else - logit("failed to write to checkpoint file '%s': %s", cpfile, - strerror(errno)); -+ /* coverity[leaked_storage : FALSE] */ - } - - static unsigned long diff -up openssh-7.4p1/monitor.c.coverity openssh-7.4p1/monitor.c --- openssh-7.4p1/monitor.c.coverity 2016-12-23 16:40:26.888788688 +0100 +++ openssh-7.4p1/monitor.c 2016-12-23 16:40:26.900788691 +0100 @@ -217,23 +114,6 @@ diff -up openssh-7.4p1/monitor.c.coverity openssh-7.4p1/monitor.c return (0); error: -diff -up openssh-7.4p1/monitor_wrap.c.coverity openssh-7.4p1/monitor_wrap.c ---- openssh-7.4p1/monitor_wrap.c.coverity 2016-12-23 16:40:26.892788689 +0100 -+++ openssh-7.4p1/monitor_wrap.c 2016-12-23 16:40:26.900788691 +0100 -@@ -525,10 +525,10 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, - if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 || - (tmp2 = dup(pmonitor->m_recvfd)) == -1) { - error_f("cannot allocate fds for pty"); -- if (tmp1 > 0) -+ if (tmp1 >= 0) - close(tmp1); -- if (tmp2 > 0) -- close(tmp2); -+ /*DEAD CODE if (tmp2 >= 0) -+ close(tmp2);*/ - return 0; - } - close(tmp1); diff -up openssh-7.4p1/openbsd-compat/bindresvport.c.coverity openssh-7.4p1/openbsd-compat/bindresvport.c --- openssh-7.4p1/openbsd-compat/bindresvport.c.coverity 2016-12-19 05:59:41.000000000 +0100 +++ openssh-7.4p1/openbsd-compat/bindresvport.c 2016-12-23 16:40:26.901788691 +0100 @@ -287,23 +167,6 @@ diff -up openssh-8.5p1/readconf.c.coverity openssh-8.5p1/readconf.c goto out; } free(arg2); -diff -up openssh-8.7p1/scp.c.coverity openssh-8.7p1/scp.c ---- openssh-8.7p1/scp.c.coverity 2021-08-30 16:23:35.389741329 +0200 -+++ openssh-8.7p1/scp.c 2021-08-30 16:27:04.854555296 +0200 -@@ -186,11 +186,11 @@ killchild(int signo) - { - if (do_cmd_pid > 1) { - kill(do_cmd_pid, signo ? signo : SIGTERM); -- waitpid(do_cmd_pid, NULL, 0); -+ (void) waitpid(do_cmd_pid, NULL, 0); - } - if (do_cmd_pid2 > 1) { - kill(do_cmd_pid2, signo ? signo : SIGTERM); -- waitpid(do_cmd_pid2, NULL, 0); -+ (void) waitpid(do_cmd_pid2, NULL, 0); - } - - if (signo) diff -up openssh-7.4p1/servconf.c.coverity openssh-7.4p1/servconf.c --- openssh-7.4p1/servconf.c.coverity 2016-12-23 16:40:26.896788690 +0100 +++ openssh-7.4p1/servconf.c 2016-12-23 16:40:26.901788691 +0100 @@ -331,87 +194,6 @@ diff -up openssh-8.7p1/serverloop.c.coverity openssh-8.7p1/serverloop.c if (tun != SSH_TUNID_ANY && auth_opts->force_tun_device != (int)tun) goto done; -diff -up openssh-8.5p1/session.c.coverity openssh-8.5p1/session.c ---- openssh-8.5p1/session.c.coverity 2021-03-24 12:03:33.777968124 +0100 -+++ openssh-8.5p1/session.c 2021-03-24 12:03:33.786968187 +0100 -@@ -1223,12 +1223,14 @@ do_setup_env(struct ssh *ssh, Session *s - /* Environment specified by admin */ - for (i = 0; i < options.num_setenv; i++) { - cp = xstrdup(options.setenv[i]); -+ /* coverity[overwrite_var : FALSE] */ - if ((value = strchr(cp, '=')) == NULL) { - /* shouldn't happen; vars are checked in servconf.c */ - fatal("Invalid config SetEnv: %s", options.setenv[i]); - } - *value++ = '\0'; - child_set_env(&env, &envsize, cp, value); -+ free(cp); - } - - /* SSH_CLIENT deprecated */ ---- a/sftp.c 2022-06-30 10:43:13.914058913 +0200 -+++ b/sftp.c 2022-06-30 10:48:17.243997888 +0200 -@@ -222,7 +222,7 @@ killchild(int signo) - pid = sshpid; - if (pid > 1) { - kill(pid, SIGTERM); -- waitpid(pid, NULL, 0); -+ (void) waitpid(pid, NULL, 0); - } - - _exit(1); -@@ -768,6 +768,8 @@ process_put(struct sftp_conn *conn, cons - fflag || global_fflag, 0) == -1) - err = -1; - } -+ free(abs_dst); -+ abs_dst = NULL; - } - - out: -@@ -991,6 +993,7 @@ do_globbed_ls(struct sftp_conn *conn, co - if (lflag & LS_LONG_VIEW) { - if (g.gl_statv[i] == NULL) { - error("no stat information for %s", fname); -+ free(fname); - 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 -@@ -1256,6 +1256,7 @@ sk_load_resident_keys(const char *pin, s - freezero(rks[i], sizeof(*rks[i])); - } - free(rks); -+ free(device); - return ret; - } - diff -up openssh-7.4p1/ssh-agent.c.coverity openssh-7.4p1/ssh-agent.c --- openssh-7.4p1/ssh-agent.c.coverity 2016-12-19 05:59:41.000000000 +0100 +++ openssh-7.4p1/ssh-agent.c 2016-12-23 16:40:26.903788691 +0100 @@ -423,31 +205,9 @@ diff -up openssh-7.4p1/ssh-agent.c.coverity openssh-7.4p1/ssh-agent.c return NULL; } /* validate also provider from URI */ -@@ -1220,8 +1220,8 @@ main(int ac, char **av) - sanitise_stdfd(); - - /* drop */ -- setegid(getgid()); -- setgid(getgid()); -+ (void) setegid(getgid()); -+ (void) setgid(getgid()); - - platform_disable_tracing(0); /* strict=no */ - -diff -up openssh-8.5p1/ssh.c.coverity openssh-8.5p1/ssh.c ---- openssh-8.5p1/ssh.c.coverity 2021-03-24 12:03:33.779968138 +0100 -+++ openssh-8.5p1/ssh.c 2021-03-24 12:03:33.786968187 +0100 -@@ -1746,6 +1746,7 @@ control_persist_detach(void) - close(muxserver_sock); - muxserver_sock = -1; - options.control_master = SSHCTL_MASTER_NO; -+ /* coverity[leaked_handle: FALSE]*/ - muxclient(options.control_path); - /* muxclient() doesn't return on success. */ - fatal("Failed to connect to new control master"); -diff -up openssh-7.4p1/sshd.c.coverity openssh-7.4p1/sshd.c ---- openssh-7.4p1/sshd.c.coverity 2016-12-23 16:40:26.897788690 +0100 -+++ openssh-7.4p1/sshd.c 2016-12-23 16:40:26.904788692 +0100 +diff -up openssh-7.4p1/sshd-session.c.coverity openssh-7.4p1/sshd-session.c +--- openssh-7.4p1/sshd-session.c.coverity 2016-12-23 16:40:26.897788690 +0100 ++++ openssh-7.4p1/sshd-session.c 2016-12-23 16:40:26.904788692 +0100 @@ -691,8 +691,10 @@ privsep_preauth(Authctxt *authctxt) privsep_preauth_child(ssh); @@ -460,16 +220,6 @@ diff -up openssh-7.4p1/sshd.c.coverity openssh-7.4p1/sshd.c return 0; } -@@ -1386,6 +1388,9 @@ server_accept_loop(int *sock_in, int *so - explicit_bzero(rnd, sizeof(rnd)); - } - } -+ -+ if (fdset != NULL) -+ free(fdset); - } - - /* @@ -2519,8 +2524,11 @@ do_ssh2_kex(struct ssh *ssh) if (newstr) @@ -496,32 +246,3 @@ diff -up openssh-8.5p1/ssh-keygen.c.coverity openssh-8.5p1/ssh-keygen.c } else { if (strncasecmp(cp, "key:", 4) == 0) { cp += 4; -@@ -2879,6 +2882,7 @@ do_moduli_screen(const char *out_file, c - } else if (strncmp(opts[i], "start-line=", 11) == 0) { - start_lineno = strtoul(opts[i]+11, NULL, 10); - } else if (strncmp(opts[i], "checkpoint=", 11) == 0) { -+ free(checkpoint); - checkpoint = xstrdup(opts[i]+11); - } else if (strncmp(opts[i], "generator=", 10) == 0) { - generator_wanted = (u_int32_t)strtonum( -@@ -2920,6 +2924,9 @@ do_moduli_screen(const char *out_file, c - #else /* WITH_OPENSSL */ - fatal("Moduli screening is not supported"); - #endif /* WITH_OPENSSL */ -+ free(checkpoint); -+ if (in != stdin) -+ fclose(in); - } - - static char * -diff -up openssh-8.5p1/sshsig.c.coverity openssh-8.5p1/sshsig.c ---- openssh-8.5p1/sshsig.c.coverity 2021-03-02 11:31:47.000000000 +0100 -+++ openssh-8.5p1/sshsig.c 2021-03-24 12:03:33.787968194 +0100 -@@ -515,6 +515,7 @@ hash_file(int fd, const char *hashalg, s - oerrno = errno; - error_f("read: %s", strerror(errno)); - ssh_digest_free(ctx); -+ ctx = NULL; - errno = oerrno; - r = SSH_ERR_SYSTEM_ERROR; - goto out; diff --git a/SOURCES/openssh-7.1p2-audit-race-condition.patch b/SOURCES/openssh-7.1p2-audit-race-condition.patch index b5895f7..57ad148 100644 --- a/SOURCES/openssh-7.1p2-audit-race-condition.patch +++ b/SOURCES/openssh-7.1p2-audit-race-condition.patch @@ -109,7 +109,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c @@ -717,6 +728,8 @@ do_exec(Session *s, const char *command) } if (s->command != NULL && s->ptyfd == -1) - s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); + s->command_handle = mm_audit_run_command(ssh, s->command); + if (pipe(paudit) < 0) + fatal("pipe: %s", strerror(errno)); #endif @@ -121,7 +121,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c +#ifdef SSH_AUDIT_EVENTS + close(paudit[1]); -+ if (use_privsep && ret == 0) { ++ if (ret == 0) { + /* + * Read the audit messages from forked child and send them + * back to monitor. We don't want to communicate directly, @@ -136,7 +136,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c return ret; } -@@ -1538,6 +1565,34 @@ child_close_fds(void) +@@ -1538,6 +1565,33 @@ child_close_fds(void) log_redirect_stderr_to(NULL); } @@ -147,12 +147,11 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c + int pparent = paudit[1]; + close(paudit[0]); + /* Hack the monitor pipe to avoid race condition with parent */ -+ if (use_privsep) -+ mm_set_monitor_pipe(pparent); ++ mm_set_monitor_pipe(pparent); +#endif + + /* remove hostkey from the child's memory */ -+ destroy_sensitive_data(ssh, use_privsep); ++ destroy_sensitive_data(ssh); + /* + * We can audit this, because we hacked the pipe to direct the + * messages over postauth child. But this message requires answer @@ -176,7 +175,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); - /* remove hostkey from the child's memory */ -- destroy_sensitive_data(ssh, 1); +- destroy_sensitive_data(ssh); - ssh_packet_clear_keys(ssh); - /* Don't audit this - both us and the parent would be talking to the - monitor over a single socket, with no synchronization. */ diff --git a/SOURCES/openssh-7.2p2-x11.patch b/SOURCES/openssh-7.2p2-x11.patch index 0a19ecb..6db16be 100644 --- a/SOURCES/openssh-7.2p2-x11.patch +++ b/SOURCES/openssh-7.2p2-x11.patch @@ -1,21 +1,23 @@ -diff -up openssh-7.2p2/channels.c.x11 openssh-7.2p2/channels.c ---- openssh-7.2p2/channels.c.x11 2016-03-09 19:04:48.000000000 +0100 -+++ openssh-7.2p2/channels.c 2016-06-03 10:42:04.775164520 +0200 -@@ -3990,21 +3990,24 @@ x11_create_display_inet(int x11_display_ +diff --git a/channels.c b/channels.c +--- a/channels.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/channels.c (date 1703026069921) +@@ -5075,11 +5075,13 @@ } - + static int -connect_local_xsocket_path(const char *pathname) +connect_local_xsocket_path(const char *pathname, int len) { int sock; struct sockaddr_un addr; - + + if (len <= 0) + return -1; sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock == -1) + if (sock == -1) { error("socket: %.100s", strerror(errno)); +@@ -5087,11 +5089,12 @@ + } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strlcpy(addr.sun_path, pathname, sizeof addr.sun_path); @@ -29,8 +31,8 @@ diff -up openssh-7.2p2/channels.c.x11 openssh-7.2p2/channels.c - error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); return -1; } - -@@ -4012,8 +4015,18 @@ static int + +@@ -5099,8 +5102,18 @@ connect_local_xsocket(u_int dnr) { char buf[1024]; diff --git a/SOURCES/openssh-7.3p1-x11-max-displays.patch b/SOURCES/openssh-7.3p1-x11-max-displays.patch index c8a147b..e28c62e 100644 --- a/SOURCES/openssh-7.3p1-x11-max-displays.patch +++ b/SOURCES/openssh-7.3p1-x11-max-displays.patch @@ -2,7 +2,7 @@ diff -up openssh-7.4p1/channels.c.x11max openssh-7.4p1/channels.c --- openssh-7.4p1/channels.c.x11max 2016-12-23 15:46:32.071506625 +0100 +++ openssh-7.4p1/channels.c 2016-12-23 15:46:32.139506636 +0100 @@ -152,8 +152,8 @@ static int all_opens_permitted = 0; - #define FWD_PERMIT_ANY_HOST "*" + #define NUM_SOCKS 10 /* -- X11 forwarding */ -/* Maximum number of fake X11 displays to try. */ @@ -10,8 +10,8 @@ diff -up openssh-7.4p1/channels.c.x11max openssh-7.4p1/channels.c +/* Minimum port number for X11 forwarding */ +#define X11_PORT_MIN 6000 - /* Per-channel callback for pre/post select() actions */ - typedef void chan_fn(struct ssh *, Channel *c, + /* Per-channel callback for pre/post IO actions */ + typedef void chan_fn(struct ssh *, Channel *c); @@ -4228,7 +4228,7 @@ channel_send_window_changes(void) */ int @@ -82,7 +82,7 @@ diff -up openssh-7.4p1/channels.h.x11max openssh-7.4p1/channels.h +++ openssh-7.4p1/channels.h 2016-12-23 15:46:32.139506636 +0100 @@ -293,7 +293,7 @@ int permitopen_port(const char *); - void channel_set_x11_refuse_time(struct ssh *, u_int); + void channel_set_x11_refuse_time(struct ssh *, time_t); int x11_connect_display(struct ssh *); -int x11_create_display_inet(struct ssh *, int, int, int, u_int *, int **); +int x11_create_display_inet(struct ssh *, int, int, int, int, u_int *, int **); @@ -110,9 +110,9 @@ diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c options->x11_use_localhost = 1; if (options->xauth_location == NULL) @@ -419,7 +422,7 @@ typedef enum { - sPasswordAuthentication, sKbdInteractiveAuthentication, - sListenAddress, sAddressFamily, - sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication, + sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, - sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, + sX11Forwarding, sX11DisplayOffset, sX11MaxDisplays, sX11UseLocalhost, sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, @@ -191,8 +191,8 @@ diff -up openssh-7.4p1/sshd_config.5.x11max openssh-7.4p1/sshd_config.5 --- openssh-7.4p1/sshd_config.5.x11max 2016-12-23 15:46:32.134506635 +0100 +++ openssh-7.4p1/sshd_config.5 2016-12-23 15:46:32.141506636 +0100 @@ -1133,6 +1133,7 @@ Available keywords are - .Cm StreamLocalBindUnlink , .Cm TrustedUserCAKeys , + .Cm UnusedConnectionTimeout , .Cm X11DisplayOffset , +.Cm X11MaxDisplays , .Cm X11Forwarding diff --git a/SOURCES/openssh-7.4p1-systemd.patch b/SOURCES/openssh-7.4p1-systemd.patch deleted file mode 100644 index 4f9e58a..0000000 --- a/SOURCES/openssh-7.4p1-systemd.patch +++ /dev/null @@ -1,98 +0,0 @@ -commit 0e22b79bfde45a7cf7a2e51a68ec11c4285f3b31 -Author: Jakub Jelen -Date: Mon Nov 21 15:04:06 2016 +0100 - - systemd stuff - -diff --git a/configure.ac b/configure.ac -index 2ffc369..162ce92 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -4265,6 +4265,30 @@ AC_ARG_WITH([kerberos5], - AC_SUBST([GSSLIBS]) - AC_SUBST([K5LIBS]) - -+# Check whether user wants systemd support -+SYSTEMD_MSG="no" -+AC_ARG_WITH(systemd, -+ [ --with-systemd Enable systemd support], -+ [ if test "x$withval" != "xno" ; then -+ AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) -+ if test "$PKGCONFIG" != "no"; then -+ AC_MSG_CHECKING([for libsystemd]) -+ if $PKGCONFIG --exists libsystemd; then -+ SYSTEMD_CFLAGS=`$PKGCONFIG --cflags libsystemd` -+ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd` -+ CPPFLAGS="$CPPFLAGS $SYSTEMD_CFLAGS" -+ SSHDLIBS="$SSHDLIBS $SYSTEMD_LIBS" -+ AC_MSG_RESULT([yes]) -+ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if you want systemd support.]) -+ SYSTEMD_MSG="yes" -+ else -+ AC_MSG_RESULT([no]) -+ fi -+ fi -+ fi ] -+) -+ -+ - # Looking for programs, paths and files - - PRIVSEP_PATH=/var/empty -@@ -5097,6 +5121,7 @@ echo " libedit support: $LIBEDIT_MSG" - echo " Solaris process contract support: $SPC_MSG" - echo " Solaris project support: $SP_MSG" - echo " Solaris privilege support: $SPP_MSG" -+echo " systemd support: $SYSTEMD_MSG" - echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" - echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" - echo " BSD Auth support: $BSD_AUTH_MSG" -diff --git a/contrib/sshd.service b/contrib/sshd.service -new file mode 100644 -index 0000000..e0d4923 ---- /dev/null -+++ b/contrib/sshd.service -@@ -0,0 +1,16 @@ -+[Unit] -+Description=OpenSSH server daemon -+Documentation=man:sshd(8) man:sshd_config(5) -+After=network.target -+ -+[Service] -+Type=notify -+ExecStart=/usr/sbin/sshd -D $OPTIONS -+ExecReload=/bin/kill -HUP $MAINPID -+KillMode=process -+Restart=on-failure -+RestartPreventExitStatus=255 -+ -+[Install] -+WantedBy=multi-user.target -+ -diff --git a/sshd.c b/sshd.c -index 816611c..b8b9d13 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -85,6 +85,10 @@ - #include - #endif - -+#ifdef HAVE_SYSTEMD -+#include -+#endif -+ - #include "xmalloc.h" - #include "ssh.h" - #include "ssh2.h" -@@ -1888,6 +1892,11 @@ main(int ac, char **av) - } - } - -+#ifdef HAVE_SYSTEMD -+ /* Signal systemd that we are ready to accept connections */ -+ sd_notify(0, "READY=1"); -+#endif -+ - /* Accept a connection and return in a forked child */ - server_accept_loop(&sock_in, &sock_out, - &newsock, config_s); diff --git a/SOURCES/openssh-7.5p1-sandbox.patch b/SOURCES/openssh-7.5p1-sandbox.patch index 7217c64..90640a0 100644 --- a/SOURCES/openssh-7.5p1-sandbox.patch +++ b/SOURCES/openssh-7.5p1-sandbox.patch @@ -21,7 +21,7 @@ index ca75cc7..6e7de31 100644 + SC_ALLOW(__NR_flock), +#endif #ifdef __NR_futex - SC_ALLOW(__NR_futex), + SC_FUTEX(__NR_futex), #endif @@ -178,6 +181,9 @@ static const struct sock_filter preauth_insns[] = { #ifdef __NR_gettimeofday diff --git a/SOURCES/openssh-7.6p1-audit.patch b/SOURCES/openssh-7.6p1-audit.patch index fa40053..2c7ddc5 100644 --- a/SOURCES/openssh-7.6p1-audit.patch +++ b/SOURCES/openssh-7.6p1-audit.patch @@ -1,6 +1,6 @@ diff -up openssh-8.6p1/audit-bsm.c.audit openssh-8.6p1/audit-bsm.c --- openssh-8.6p1/audit-bsm.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/audit-bsm.c 2021-05-06 12:05:27.376464524 +0200 ++++ openssh-8.6p1/audit-bsm.c 2021-04-19 16:47:35.753062106 +0200 @@ -373,13 +373,26 @@ audit_connection_from(const char *host, #endif } @@ -73,7 +73,7 @@ diff -up openssh-8.6p1/audit-bsm.c.audit openssh-8.6p1/audit-bsm.c #endif /* BSM */ diff -up openssh-8.6p1/audit.c.audit openssh-8.6p1/audit.c --- openssh-8.6p1/audit.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/audit.c 2021-05-06 12:05:27.376464524 +0200 ++++ openssh-8.6p1/audit.c 2021-04-19 16:47:35.753062106 +0200 @@ -34,6 +34,12 @@ #include "log.h" #include "hostfile.h" @@ -129,19 +129,19 @@ diff -up openssh-8.6p1/audit.c.audit openssh-8.6p1/audit.c +void +audit_unsupported(struct ssh *ssh, int what) +{ -+ PRIVSEP(audit_unsupported_body(ssh, what)); ++ mm_audit_unsupported_body(ssh, what); +} + +void +audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs) +{ -+ PRIVSEP(audit_kex_body(ssh, ctos, enc, mac, comp, pfs, getpid(), getuid())); ++ mm_audit_kex_body(ssh, ctos, enc, mac, comp, pfs, getpid(), getuid()); +} + +void +audit_session_key_free(struct ssh *ssh, int ctos) +{ -+ PRIVSEP(audit_session_key_free_body(ssh, ctos, getpid(), getuid())); ++ mm_audit_session_key_free_body(ssh, ctos, getpid(), getuid()); +} + # ifndef CUSTOM_SSH_AUDIT_EVENTS @@ -253,7 +253,7 @@ diff -up openssh-8.6p1/audit.c.audit openssh-8.6p1/audit.c #endif /* SSH_AUDIT_EVENTS */ diff -up openssh-8.6p1/audit.h.audit openssh-8.6p1/audit.h --- openssh-8.6p1/audit.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/audit.h 2021-05-06 12:05:27.376464524 +0200 ++++ openssh-8.6p1/audit.h 2021-04-19 16:47:35.753062106 +0200 @@ -26,6 +26,7 @@ # define _SSH_AUDIT_H @@ -298,7 +298,7 @@ diff -up openssh-8.6p1/audit.h.audit openssh-8.6p1/audit.h #endif /* _SSH_AUDIT_H */ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c --- openssh-8.6p1/audit-linux.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/audit-linux.c 2021-05-06 12:05:27.377464532 +0200 ++++ openssh-8.6p1/audit-linux.c 2021-04-19 16:47:35.753062106 +0200 @@ -33,27 +33,40 @@ #include "log.h" @@ -446,7 +446,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c /* Below is the sshd audit API code */ void -@@ -76,49 +176,210 @@ audit_connection_from(const char *host, +@@ -76,49 +176,211 @@ audit_connection_from(const char *host, /* not implemented */ } @@ -525,6 +525,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c case SSH_AUTH_FAIL_PASSWD: + if (options.use_pam) + break; ++ /* Fallthrough */ + case SSH_LOGIN_EXCEED_MAXTRIES: case SSH_AUTH_FAIL_KBDINT: case SSH_AUTH_FAIL_PUBKEY: @@ -564,7 +565,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c +{ +#ifdef AUDIT_CRYPTO_SESSION + char buf[AUDIT_LOG_SIZE]; -+ const static char *name[] = { "cipher", "mac", "comp" }; ++ static const char *name[] = { "cipher", "mac", "comp" }; + char *s; + int audit_fd; + @@ -582,7 +583,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c +#endif +} + -+const static char *direction[] = { "from-server", "from-client", "both" }; ++static const char *direction[] = { "from-server", "from-client", "both" }; + +void +audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, @@ -661,7 +662,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, + buf, NULL, -+ listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh), ++ ssh_remote_ipaddr(ssh), /*FIXME listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh) */ + NULL, 1); + audit_close(audit_fd); + /* do not abort if the error is EPERM and sshd is run as non root user */ @@ -670,8 +671,8 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c +} #endif /* USE_LINUX_AUDIT */ diff -up openssh-8.6p1/auditstub.c.audit openssh-8.6p1/auditstub.c ---- openssh-8.6p1/auditstub.c.audit 2021-05-06 12:05:27.377464532 +0200 -+++ openssh-8.6p1/auditstub.c 2021-05-06 12:05:27.377464532 +0200 +--- openssh-8.6p1/auditstub.c.audit 2021-04-19 16:47:35.754062114 +0200 ++++ openssh-8.6p1/auditstub.c 2021-04-19 16:47:35.754062114 +0200 @@ -0,0 +1,52 @@ +/* $Id: auditstub.c,v 1.1 jfch Exp $ */ + @@ -726,28 +727,28 @@ diff -up openssh-8.6p1/auditstub.c.audit openssh-8.6p1/auditstub.c +{ +} diff -up openssh-8.6p1/auth2.c.audit openssh-8.6p1/auth2.c ---- openssh-8.6p1/auth2.c.audit 2021-05-06 12:05:27.305463975 +0200 -+++ openssh-8.6p1/auth2.c 2021-05-06 12:05:27.377464532 +0200 +--- openssh-8.6p1/auth2.c.audit 2021-04-19 16:47:35.682061561 +0200 ++++ openssh-8.6p1/auth2.c 2021-04-19 16:47:35.754062114 +0200 @@ -298,9 +298,6 @@ input_userauth_request(int type, u_int32 - } else { + authctxt->valid = 0; /* Invalid user, fake password information */ authctxt->pw = fakepw(); -#ifdef SSH_AUDIT_EVENTS -- PRIVSEP(audit_event(ssh, SSH_INVALID_USER)); +- mm_audit_event(ssh, SSH_INVALID_USER); -#endif } #ifdef USE_PAM if (options.use_pam) diff -up openssh-8.6p1/auth2-hostbased.c.audit openssh-8.6p1/auth2-hostbased.c ---- openssh-8.6p1/auth2-hostbased.c.audit 2021-05-06 12:05:27.283463805 +0200 -+++ openssh-8.6p1/auth2-hostbased.c 2021-05-06 12:05:27.377464532 +0200 +--- openssh-8.6p1/auth2-hostbased.c.audit 2021-04-19 16:47:35.656061361 +0200 ++++ openssh-8.6p1/auth2-hostbased.c 2021-04-19 16:47:35.754062114 +0200 @@ -158,7 +158,7 @@ userauth_hostbased(struct ssh *ssh) authenticated = 0; - if (PRIVSEP(hostbased_key_allowed(ssh, authctxt->pw, cuser, - chost, key)) && -- PRIVSEP(sshkey_verify(key, sig, slen, -+ PRIVSEP(hostbased_key_verify(ssh, key, sig, slen, - sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat, NULL)) == 0) + if (mm_hostbased_key_allowed(ssh, authctxt->pw, cuser, + chost, key) && +- mm_sshkey_verify(key, sig, slen, ++ mm_hostbased_key_verify(ssh, key, sig, slen, + sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat, NULL) == 0) authenticated = 1; @@ -175,6 +175,20 @@ done: @@ -772,17 +773,17 @@ diff -up openssh-8.6p1/auth2-hostbased.c.audit openssh-8.6p1/auth2-hostbased.c int hostbased_key_allowed(struct ssh *ssh, struct passwd *pw, diff -up openssh-8.6p1/auth2-pubkey.c.audit openssh-8.6p1/auth2-pubkey.c ---- openssh-8.6p1/auth2-pubkey.c.audit 2021-05-06 12:05:27.344464277 +0200 -+++ openssh-8.6p1/auth2-pubkey.c 2021-05-06 12:05:27.378464540 +0200 +--- openssh-8.6p1/auth2-pubkey.c.audit 2021-04-19 16:47:35.726061899 +0200 ++++ openssh-8.6p1/auth2-pubkey.c 2021-04-19 16:47:35.754062114 +0200 @@ -213,7 +213,7 @@ userauth_pubkey(struct ssh *ssh) /* test for correct signature */ authenticated = 0; - if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && -- PRIVSEP(sshkey_verify(key, sig, slen, -+ PRIVSEP(user_key_verify(ssh, key, sig, slen, + if (mm_user_key_allowed(ssh, pw, key, 1, &authopts) && +- mm_sshkey_verify(key, sig, slen, ++ mm_user_key_verify(ssh, key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, - ssh->compat, &sig_details)) == 0) { + ssh->compat, &sig_details) == 0) { @@ -305,6 +305,20 @@ done: return authenticated; } @@ -802,11 +803,11 @@ diff -up openssh-8.6p1/auth2-pubkey.c.audit openssh-8.6p1/auth2-pubkey.c +} + static int - match_principals_option(const char *principal_list, struct sshkey_cert *cert) - { + match_principals_file(struct passwd *pw, char *file, + struct sshkey_cert *cert, struct sshauthopt **authoptsp) diff -up openssh-8.6p1/auth.c.audit openssh-8.6p1/auth.c ---- openssh-8.6p1/auth.c.audit 2021-05-06 12:05:27.304463967 +0200 -+++ openssh-8.6p1/auth.c 2021-05-06 12:05:27.378464540 +0200 +--- openssh-8.6p1/auth.c.audit 2021-04-19 16:47:35.681061553 +0200 ++++ openssh-8.6p1/auth.c 2021-04-19 16:47:35.754062114 +0200 @@ -597,9 +597,6 @@ getpwnamallow(struct ssh *ssh, const cha record_failed_login(ssh, user, auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); @@ -818,17 +819,8 @@ diff -up openssh-8.6p1/auth.c.audit openssh-8.6p1/auth.c } if (!allowed_user(ssh, pw)) diff -up openssh-8.6p1/auth.h.audit openssh-8.6p1/auth.h ---- openssh-8.6p1/auth.h.audit 2021-05-06 12:05:27.318464076 +0200 -+++ openssh-8.6p1/auth.h 2021-05-06 12:05:27.378464540 +0200 -@@ -193,6 +193,8 @@ struct passwd * getpwnamallow(struct ssh - - char *expand_authorized_keys(const char *, struct passwd *pw); - char *authorized_principals_file(struct passwd *); -+int user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, -+ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); - - FILE *auth_openkeyfile(const char *, struct passwd *, int); - FILE *auth_openprincipals(const char *, struct passwd *, int); +--- openssh-8.6p1/auth.h.audit 2021-04-19 16:47:35.697061676 +0200 ++++ openssh-8.6p1/auth.h 2021-04-19 16:47:35.754062114 +0200 @@ -212,6 +214,8 @@ struct sshkey *get_hostkey_private_by_ty int get_hostkey_index(struct sshkey *, int, struct ssh *); int sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *, @@ -837,10 +829,19 @@ diff -up openssh-8.6p1/auth.h.audit openssh-8.6p1/auth.h + const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); /* Key / cert options linkage to auth layer */ - const struct sshauthopt *auth_options(struct ssh *); + int auth_activate_options(struct ssh *, struct sshauthopt *); +@@ -239,6 +241,8 @@ struct passwd * getpwnamallow(struct ssh + char *, const char *, const char *, const char *, struct sshauthopt **); + int auth_check_authkeys_file(struct passwd *, FILE *, char *, + struct sshkey *, const char *, const char *, struct sshauthopt **); ++int user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); + FILE *auth_openkeyfile(const char *, struct passwd *, int); + FILE *auth_openprincipals(const char *, struct passwd *, int); + diff -up openssh-8.6p1/cipher.c.audit openssh-8.6p1/cipher.c --- openssh-8.6p1/cipher.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/cipher.c 2021-05-06 12:05:27.378464540 +0200 ++++ openssh-8.6p1/cipher.c 2021-04-19 16:47:35.755062122 +0200 @@ -64,25 +64,6 @@ struct sshcipher_ctx { const struct sshcipher *cipher; }; @@ -878,7 +879,7 @@ diff -up openssh-8.6p1/cipher.c.audit openssh-8.6p1/cipher.c chachapoly_free(cc->cp_ctx); diff -up openssh-8.6p1/cipher.h.audit openssh-8.6p1/cipher.h --- openssh-8.6p1/cipher.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/cipher.h 2021-05-06 12:05:27.378464540 +0200 ++++ openssh-8.6p1/cipher.h 2021-04-19 16:47:35.755062122 +0200 @@ -47,7 +47,25 @@ #define CIPHER_ENCRYPT 1 #define CIPHER_DECRYPT 0 @@ -907,16 +908,16 @@ diff -up openssh-8.6p1/cipher.h.audit openssh-8.6p1/cipher.h const struct sshcipher *cipher_by_name(const char *); diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c ---- openssh-8.6p1/kex.c.audit 2021-05-06 12:05:27.368464462 +0200 -+++ openssh-8.6p1/kex.c 2021-05-06 12:05:27.379464547 +0200 +--- openssh-8.6p1/kex.c.audit 2021-04-19 16:47:35.743062030 +0200 ++++ openssh-8.6p1/kex.c 2021-04-19 16:47:35.755062122 +0200 @@ -65,6 +65,7 @@ - #include "ssherr.h" #include "sshbuf.h" #include "digest.h" + #include "xmalloc.h" +#include "audit.h" - #ifdef GSSAPI - #include "ssh-gss.h" + /* prototype */ + static int kex_choose_conf(struct ssh *, uint32_t seq); @@ -816,12 +817,16 @@ kex_start_rekex(struct ssh *ssh) } @@ -1036,8 +1037,8 @@ diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c * Send a plaintext error message to the peer, suffixed by \r\n. * Only used during banner exchange, and there only for the server. diff -up openssh-8.6p1/kex.h.audit openssh-8.6p1/kex.h ---- openssh-8.6p1/kex.h.audit 2021-05-06 12:05:27.306463983 +0200 -+++ openssh-8.6p1/kex.h 2021-05-06 12:05:27.379464547 +0200 +--- openssh-8.6p1/kex.h.audit 2021-04-19 16:47:35.683061568 +0200 ++++ openssh-8.6p1/kex.h 2021-04-19 16:47:35.756062129 +0200 @@ -226,6 +226,8 @@ int kexgss_client(struct ssh *); int kexgss_server(struct ssh *); #endif @@ -1049,7 +1050,7 @@ diff -up openssh-8.6p1/kex.h.audit openssh-8.6p1/kex.h struct sshbuf **); diff -up openssh-8.6p1/mac.c.audit openssh-8.6p1/mac.c --- openssh-8.6p1/mac.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/mac.c 2021-05-06 12:05:27.379464547 +0200 ++++ openssh-8.6p1/mac.c 2021-04-19 16:47:35.756062129 +0200 @@ -239,6 +239,20 @@ mac_clear(struct sshmac *mac) mac->umac_ctx = NULL; } @@ -1073,7 +1074,7 @@ diff -up openssh-8.6p1/mac.c.audit openssh-8.6p1/mac.c int diff -up openssh-8.6p1/mac.h.audit openssh-8.6p1/mac.h --- openssh-8.6p1/mac.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/mac.h 2021-05-06 12:05:27.379464547 +0200 ++++ openssh-8.6p1/mac.h 2021-04-19 16:47:35.756062129 +0200 @@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int3 int mac_check(struct sshmac *, u_int32_t, const u_char *, size_t, const u_char *, size_t); @@ -1082,10 +1083,10 @@ diff -up openssh-8.6p1/mac.h.audit openssh-8.6p1/mac.h #endif /* SSHMAC_H */ diff -up openssh-8.6p1/Makefile.in.audit openssh-8.6p1/Makefile.in ---- openssh-8.6p1/Makefile.in.audit 2021-05-06 12:05:27.352464339 +0200 -+++ openssh-8.6p1/Makefile.in 2021-05-06 12:05:27.380464555 +0200 +--- openssh-8.6p1/Makefile.in.audit 2021-04-19 16:47:35.731061937 +0200 ++++ openssh-8.6p1/Makefile.in 2021-04-19 16:47:35.756062129 +0200 @@ -112,7 +112,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kexsntrup761x25519.o sntrup761.o kexgen.o \ + kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \ kexgssc.o \ sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ - sshbuf-io.o @@ -1094,8 +1095,8 @@ diff -up openssh-8.6p1/Makefile.in.audit openssh-8.6p1/Makefile.in SKOBJS= ssh-sk-client.o diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c ---- openssh-8.6p1/monitor.c.audit 2021-05-06 12:05:27.326464138 +0200 -+++ openssh-8.6p1/monitor.c 2021-05-06 12:05:27.380464555 +0200 +--- openssh-8.6p1/monitor.c.audit 2021-04-19 16:47:35.707061753 +0200 ++++ openssh-8.6p1/monitor.c 2021-04-19 16:47:35.756062129 +0200 @@ -93,6 +93,7 @@ #include "compat.h" #include "ssh2.h" @@ -1108,7 +1109,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ -+extern void destroy_sensitive_data(struct ssh *, int); ++extern void destroy_sensitive_data(struct ssh *); + /* State exported from the child */ static struct sshbuf *child_state; @@ -1195,9 +1196,9 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c - ret = sshkey_verify(key, signature, signaturelen, data, datalen, - sigalg, ssh->compat, &sig_details); - debug3_f("%s %s signature %s%s%s", auth_method, sshkey_type(key), + debug3_f("%s %s signature using %s %s%s%s", auth_method, + sshkey_type(key), sigalg == NULL ? "default" : sigalg, (ret == 0) ? "verified" : "unverified", - (ret != 0) ? ": " : "", (ret != 0) ? ssh_err(ret) : ""); @@ -1576,13 +1600,19 @@ mm_record_login(struct ssh *ssh, Session } @@ -1241,7 +1242,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c sshpam_cleanup(); #endif -+ destroy_sensitive_data(ssh, 0); ++ destroy_sensitive_data(ssh); + while (waitpid(pmonitor->m_pid, &status, 0) == -1) if (errno != EINTR) @@ -1427,8 +1428,8 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c +} +#endif /* SSH_AUDIT_EVENTS */ diff -up openssh-8.6p1/monitor.h.audit openssh-8.6p1/monitor.h ---- openssh-8.6p1/monitor.h.audit 2021-05-06 12:05:27.326464138 +0200 -+++ openssh-8.6p1/monitor.h 2021-05-06 12:05:27.380464555 +0200 +--- openssh-8.6p1/monitor.h.audit 2021-04-19 16:47:35.707061753 +0200 ++++ openssh-8.6p1/monitor.h 2021-04-19 16:47:35.757062137 +0200 @@ -65,7 +65,13 @@ enum monitor_reqtype { MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107, MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109, @@ -1445,8 +1446,8 @@ diff -up openssh-8.6p1/monitor.h.audit openssh-8.6p1/monitor.h MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c ---- openssh-8.6p1/monitor_wrap.c.audit 2021-05-06 12:05:27.307463991 +0200 -+++ openssh-8.6p1/monitor_wrap.c 2021-05-06 12:05:27.381464563 +0200 +--- openssh-8.6p1/monitor_wrap.c.audit 2021-04-19 16:47:35.685061584 +0200 ++++ openssh-8.6p1/monitor_wrap.c 2021-04-19 16:47:35.757062137 +0200 @@ -520,7 +520,7 @@ mm_key_allowed(enum mm_keytype type, con */ @@ -1536,9 +1537,9 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c } #endif /* SSH_AUDIT_EVENTS */ @@ -1095,3 +1137,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc + return &ci; } - #endif /* GSSAPI */ +#ifdef SSH_AUDIT_EVENTS +void +mm_audit_unsupported_body(struct ssh *ssh, int what) @@ -1620,8 +1621,8 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c +} +#endif /* SSH_AUDIT_EVENTS */ diff -up openssh-8.6p1/monitor_wrap.h.audit openssh-8.6p1/monitor_wrap.h ---- openssh-8.6p1/monitor_wrap.h.audit 2021-05-06 12:05:27.307463991 +0200 -+++ openssh-8.6p1/monitor_wrap.h 2021-05-06 12:05:27.381464563 +0200 +--- openssh-8.6p1/monitor_wrap.h.audit 2021-04-19 16:47:35.685061584 +0200 ++++ openssh-8.6p1/monitor_wrap.h 2021-04-19 16:47:35.757062137 +0200 @@ -61,7 +61,9 @@ int mm_user_key_allowed(struct ssh *, st struct sshauthopt **); int mm_hostbased_key_allowed(struct ssh *, struct passwd *, const char *, @@ -1632,7 +1633,7 @@ diff -up openssh-8.6p1/monitor_wrap.h.audit openssh-8.6p1/monitor_wrap.h +int mm_user_key_verify(struct ssh*, const struct sshkey *, const u_char *, size_t, const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); - #ifdef GSSAPI + void mm_decode_activate_server_options(struct ssh *ssh, struct sshbuf *m); @@ -86,7 +88,12 @@ void mm_sshpam_free_ctx(void *); #ifdef SSH_AUDIT_EVENTS #include "audit.h" @@ -1649,7 +1650,7 @@ diff -up openssh-8.6p1/monitor_wrap.h.audit openssh-8.6p1/monitor_wrap.h struct Session; diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c --- openssh-8.6p1/packet.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/packet.c 2021-05-06 12:07:38.535478683 +0200 ++++ openssh-8.6p1/packet.c 2021-04-19 16:48:46.885608837 +0200 @@ -81,6 +81,7 @@ #endif @@ -1802,7 +1803,7 @@ diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c ssh_packet_set_postauth(struct ssh *ssh) diff -up openssh-8.6p1/packet.h.audit openssh-8.6p1/packet.h --- openssh-8.6p1/packet.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/packet.h 2021-05-06 12:05:27.382464571 +0200 ++++ openssh-8.6p1/packet.h 2021-04-19 16:47:35.758062145 +0200 @@ -218,4 +218,5 @@ const u_char *sshpkt_ptr(struct ssh *, s # undef EC_POINT #endif @@ -1810,14 +1811,14 @@ diff -up openssh-8.6p1/packet.h.audit openssh-8.6p1/packet.h +void packet_destroy_all(struct ssh *, int, int); #endif /* PACKET_H */ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c ---- openssh-8.6p1/session.c.audit 2021-05-06 12:05:27.340464246 +0200 -+++ openssh-8.6p1/session.c 2021-05-06 12:05:27.383464578 +0200 +--- openssh-8.6p1/session.c.audit 2021-04-19 16:47:35.722061868 +0200 ++++ openssh-8.6p1/session.c 2021-04-19 16:47:35.758062145 +0200 @@ -136,7 +136,7 @@ extern char *__progname; extern int debug_flag; extern u_int utmp_len; extern int startup_pipe; -extern void destroy_sensitive_data(void); -+extern void destroy_sensitive_data(struct ssh *, int); ++extern void destroy_sensitive_data(struct ssh *); extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; extern char *tun_fwd_ifnames; /* serverloop.c */ @@ -1843,18 +1844,18 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c + if (s->command != NULL || s->command_handle != -1) + fatal("do_exec: command already set"); if (command != NULL) -- PRIVSEP(audit_run_command(command)); +- mm_audit_run_command(command); + s->command = xstrdup(command); else if (s->ttyfd == -1) { char *shell = s->pw->pw_shell; if (shell[0] == '\0') /* empty shell means /bin/sh */ shell =_PATH_BSHELL; -- PRIVSEP(audit_run_command(shell)); +- mm_audit_run_command(shell); + s->command = xstrdup(shell); } + if (s->command != NULL && s->ptyfd == -1) -+ s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); ++ s->command_handle = mm_audit_run_command(ssh, s->command); #endif if (s->ttyfd != -1) ret = do_exec_pty(ssh, s, command); @@ -1863,7 +1864,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c /* remove hostkey from the child's memory */ - destroy_sensitive_data(); -+ destroy_sensitive_data(ssh, 1); ++ destroy_sensitive_data(ssh); ssh_packet_clear_keys(ssh); + /* Don't audit this - both us and the parent would be talking to the + monitor over a single socket, with no synchronization. */ @@ -1923,7 +1924,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c +{ + if (s->command != NULL) { + if (s->command_handle != -1) -+ PRIVSEP(audit_end_command(ssh, s->command_handle, s->command)); ++ mm_audit_end_command(ssh, s->command_handle, s->command); + free(s->command); + s->command = NULL; + s->command_handle = -1; @@ -1981,7 +1982,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c @@ -2734,7 +2804,7 @@ do_cleanup(struct ssh *ssh, Authctxt *au * or if running in monitor. */ - if (!use_privsep || mm_is_monitor()) + if (mm_is_monitor()) - session_destroy_all(ssh, session_pty_cleanup2); + session_destroy_all(ssh, do_cleanup_one_session); } @@ -1989,7 +1990,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c /* Return a name for the remote host that fits inside utmp_size */ diff -up openssh-8.6p1/session.h.audit openssh-8.6p1/session.h --- openssh-8.6p1/session.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/session.h 2021-05-06 12:05:27.384464586 +0200 ++++ openssh-8.6p1/session.h 2021-04-19 16:47:35.758062145 +0200 @@ -61,6 +61,12 @@ struct Session { char *name; char *val; @@ -2006,7 +2007,7 @@ diff -up openssh-8.6p1/session.h.audit openssh-8.6p1/session.h @@ -71,10 +77,12 @@ void session_unused(int); int session_input_channel_req(struct ssh *, Channel *, const char *); void session_close_by_pid(struct ssh *ssh, pid_t, int); - void session_close_by_channel(struct ssh *, int, void *); + void session_close_by_channel(struct ssh *, int, int, void *); -void session_destroy_all(struct ssh *, void (*)(Session *)); +void session_destroy_all(struct ssh *, void (*)(struct ssh*, Session *)); void session_pty_cleanup2(Session *); @@ -2018,29 +2019,10 @@ diff -up openssh-8.6p1/session.h.audit openssh-8.6p1/session.h void session_close(struct ssh *, Session *); void do_setusercontext(struct passwd *); diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c ---- openssh-8.6p1/sshd.c.audit 2021-05-06 12:05:27.346464292 +0200 -+++ openssh-8.6p1/sshd.c 2021-05-06 12:05:27.385464594 +0200 -@@ -122,6 +122,7 @@ - #include "ssh-gss.h" - #endif - #include "monitor_wrap.h" -+#include "audit.h" - #include "ssh-sandbox.h" - #include "auth-options.h" - #include "version.h" -@@ -260,8 +261,8 @@ struct sshbuf *loginmsg; - struct passwd *privsep_pw = NULL; - - /* Prototypes for various functions defined later in this file. */ --void destroy_sensitive_data(void); --void demote_sensitive_data(void); -+void destroy_sensitive_data(struct ssh *, int); -+void demote_sensitive_data(struct ssh *); - static void do_ssh2_kex(struct ssh *); - - static char *listener_proctitle; +--- openssh-8.6p1/sshd.c.audit 2021-04-19 16:47:35.727061907 +0200 ++++ openssh-8.6p1/sshd.c 2021-04-19 16:47:35.759062152 +0200 @@ -279,6 +280,15 @@ close_listen_socks(void) - num_listen_socks = -1; + num_listen_socks = 0; } +/* @@ -2049,16 +2031,82 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c + */ +int listening_for_clients(void) +{ -+ return num_listen_socks >= 0; ++ return num_listen_socks > 0; +} + + /* Allocate and initialise the children array */ static void - close_startup_pipes(void) - { -@@ -377,18 +387,45 @@ grace_alarm_handler(int sig) - } - } + child_alloc(void) +@@ -1204,6 +1259,7 @@ server_accept_loop(int *sock_in, int *so + if (received_sigterm) { + logit("Received signal %d; terminating.", + (int) received_sigterm); ++ /* destroy_sensitive_data(ssh, 0); FIXME */ + close_listen_socks(); + if (options.pid_file != NULL) + unlink(options.pid_file); +diff -up openssh-8.6p1/sshd-session.c.audit openssh-8.6p1/sshd-session.c +--- openssh-8.6p1/sshd-session.c.audit 2021-04-19 16:47:35.727061907 +0200 ++++ openssh-8.6p1/sshd-session.c 2021-04-19 16:47:35.759062152 +0200 +@@ -122,6 +122,7 @@ + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" ++#include "audit.h" + #include "ssh-sandbox.h" + #include "auth-options.h" + #include "version.h" +@@ -260,8 +261,44 @@ struct sshbuf *loginmsg; + struct sshbuf *loginmsg; + /* Prototypes for various functions defined later in this file. */ +-void destroy_sensitive_data(void); +-void demote_sensitive_data(void); ++void destroy_sensitive_data(struct ssh *); ++void demote_sensitive_data(struct ssh *); ++ ++static int ++sshkey_is_private(const struct sshkey *k) ++{ ++ switch (k->type) { ++#ifdef WITH_OPENSSL ++ case KEY_RSA_CERT: ++ case KEY_RSA: { ++ const BIGNUM *d; ++ const RSA *rsa = EVP_PKEY_get0_RSA(k->pkey); ++ RSA_get0_key(rsa, NULL, NULL, &d); ++ return d != NULL; ++ } ++ case KEY_DSA_CERT: ++ case KEY_DSA: { ++ const BIGNUM *priv_key; ++ DSA_get0_key(k->dsa, NULL, &priv_key); ++ return priv_key != NULL; ++ } ++#ifdef OPENSSL_HAS_ECC ++ case KEY_ECDSA_CERT: ++ case KEY_ECDSA: { ++ const EC_KEY * ecdsa = EVP_PKEY_get0_EC_KEY(k->pkey); ++ return EC_KEY_get0_private_key(ecdsa) != NULL; ++ } ++#endif /* OPENSSL_HAS_ECC */ ++#endif /* WITH_OPENSSL */ ++ case KEY_ED25519_CERT: ++ case KEY_ED25519: ++ return (k->ed25519_pk != NULL); ++ default: ++ /* fatal("key_is_private: bad key type %d", k->type); */ ++ return 0; ++ } ++} ++ + static void do_ssh2_kex(struct ssh *); + + /* +@@ -377,18 +387,40 @@ grace_alarm_handler(int sig) + _exit(EXIT_LOGIN_GRACE); + } + -/* Destroy the host and server keys. They will no longer be needed. */ +/* + * Destroy the host and server keys. They will no longer be needed. Careful, @@ -2066,7 +2114,7 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c + */ void -destroy_sensitive_data(void) -+destroy_sensitive_data(struct ssh *ssh, int privsep) ++destroy_sensitive_data(struct ssh *ssh) { u_int i; +#ifdef SSH_AUDIT_EVENTS @@ -2088,12 +2136,7 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c sensitive_data.host_keys[i] = NULL; + if (fp != NULL) { +#ifdef SSH_AUDIT_EVENTS -+ if (privsep) -+ PRIVSEP(audit_destroy_sensitive_data(ssh, fp, -+ pid, uid)); -+ else -+ audit_destroy_sensitive_data(ssh, fp, -+ pid, uid); ++ audit_destroy_sensitive_data(ssh, fp, pid, uid); +#endif + free(fp); + } @@ -2163,9 +2206,9 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c #ifdef WITH_SELINUX sshd_selinux_change_privsep_preauth_context(); @@ -492,7 +547,7 @@ privsep_preauth(struct ssh *ssh) + pmonitor->m_pkex = &ssh->kex; - if (use_privsep == PRIVSEP_ON) - box = ssh_sandbox_init(pmonitor); + box = ssh_sandbox_init(pmonitor); - pid = fork(); + pmonitor->m_pid = pid = fork(); if (pid == -1) { @@ -2189,48 +2232,21 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c reseed_prngs(); -@@ -1143,7 +1198,7 @@ server_listen(void) - * from this function are in a forked subprocess. - */ - static void --server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) -+server_accept_loop(struct ssh *ssh, int *sock_in, int *sock_out, int *newsock, int *config_s) - { - fd_set *fdset; - int i, j, ret, maxfd; -@@ -1204,6 +1259,7 @@ server_accept_loop(int *sock_in, int *so - if (received_sigterm) { - logit("Received signal %d; terminating.", - (int) received_sigterm); -+ destroy_sensitive_data(ssh, 0); - close_listen_socks(); - if (options.pid_file != NULL) - unlink(options.pid_file); -@@ -2098,7 +2154,7 @@ main(int ac, char **av) - #endif - - /* Accept a connection and return in a forked child */ -- server_accept_loop(&sock_in, &sock_out, -+ server_accept_loop(ssh, &sock_in, &sock_out, - &newsock, config_s); - } - @@ -2333,6 +2389,9 @@ main(int ac, char **av) do_authenticated(ssh, authctxt); /* The connection has been terminated. */ + packet_destroy_all(ssh, 1, 1); -+ destroy_sensitive_data(ssh, 1); ++ destroy_sensitive_data(ssh); + ssh_packet_get_bytes(ssh, &ibytes, &obytes); verbose("Transferred: sent %llu, received %llu bytes", (unsigned long long)obytes, (unsigned long long)ibytes); -@@ -2513,6 +2572,15 @@ do_ssh2_kex(struct ssh *ssh) +@@ -2513,6 +2572,14 @@ do_ssh2_kex(struct ssh *ssh) void cleanup_exit(int i) { + static int in_cleanup = 0; -+ int is_privsep_child; + + /* cleanup_exit can be called at the very least from the privsep + wrappers used for auditing. Make sure we don't recurse @@ -2238,77 +2254,17 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c + if (in_cleanup) + _exit(i); + in_cleanup = 1; + extern int auth_attempted; /* monitor.c */ + if (the_active_state != NULL && the_authctxt != NULL) { - do_cleanup(the_active_state, the_authctxt); - if (use_privsep && privsep_is_preauth && -@@ -2525,9 +2593,16 @@ cleanup_exit(int i) - } - } +@@ -2525,7 +2593,9 @@ cleanup_exit(int i) } -+ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; -+ if (sensitive_data.host_keys != NULL && the_active_state != NULL) -+ destroy_sensitive_data(the_active_state, is_privsep_child); -+ if (the_active_state != NULL) -+ packet_destroy_all(the_active_state, 1, is_privsep_child); #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ -- if (the_active_state != NULL && (!use_privsep || mm_is_monitor())) +- if (the_active_state != NULL && mm_is_monitor()) + if (the_active_state != NULL && + (the_authctxt == NULL || !the_authctxt->authenticated) && -+ (!use_privsep || mm_is_monitor())) ++ mm_is_monitor()) audit_event(the_active_state, SSH_CONNECTION_ABANDON); #endif - _exit(i); -diff -up openssh-8.6p1/sshkey.c.audit openssh-8.6p1/sshkey.c ---- openssh-8.6p1/sshkey.c.audit 2021-05-06 12:05:27.364464431 +0200 -+++ openssh-8.6p1/sshkey.c 2021-05-06 12:05:27.386464602 +0200 -@@ -371,6 +371,38 @@ sshkey_type_is_valid_ca(int type) - } - - int -+sshkey_is_private(const struct sshkey *k) -+{ -+ switch (k->type) { -+#ifdef WITH_OPENSSL -+ case KEY_RSA_CERT: -+ case KEY_RSA: { -+ const BIGNUM *d; -+ RSA_get0_key(k->rsa, NULL, NULL, &d); -+ return d != NULL; -+ } -+ case KEY_DSA_CERT: -+ case KEY_DSA: { -+ const BIGNUM *priv_key; -+ DSA_get0_key(k->dsa, NULL, &priv_key); -+ return priv_key != NULL; -+ } -+#ifdef OPENSSL_HAS_ECC -+ case KEY_ECDSA_CERT: -+ case KEY_ECDSA: -+ return EC_KEY_get0_private_key(k->ecdsa) != NULL; -+#endif /* OPENSSL_HAS_ECC */ -+#endif /* WITH_OPENSSL */ -+ case KEY_ED25519_CERT: -+ case KEY_ED25519: -+ return (k->ed25519_pk != NULL); -+ default: -+ /* fatal("key_is_private: bad key type %d", k->type); */ -+ return 0; -+ } -+} -+ -+int - sshkey_is_cert(const struct sshkey *k) - { - if (k == NULL) -diff -up openssh-8.6p1/sshkey.h.audit openssh-8.6p1/sshkey.h ---- openssh-8.6p1/sshkey.h.audit 2021-05-06 12:05:27.365464439 +0200 -+++ openssh-8.6p1/sshkey.h 2021-05-06 12:05:27.386464602 +0200 -@@ -189,6 +189,7 @@ int sshkey_shield_private(struct sshke - int sshkey_unshield_private(struct sshkey *); - - int sshkey_type_from_name(const char *); -+int sshkey_is_private(const struct sshkey *); - int sshkey_is_cert(const struct sshkey *); - int sshkey_is_sk(const struct sshkey *); - int sshkey_type_is_cert(int); + /* Override default fatal exit value when auth was attempted */ diff --git a/SOURCES/openssh-7.6p1-cleanup-selinux.patch b/SOURCES/openssh-7.6p1-cleanup-selinux.patch index f7cd50f..cfe11ad 100644 --- a/SOURCES/openssh-7.6p1-cleanup-selinux.patch +++ b/SOURCES/openssh-7.6p1-cleanup-selinux.patch @@ -1,23 +1,22 @@ diff -up openssh/auth2-pubkey.c.refactor openssh/auth2-pubkey.c --- openssh/auth2-pubkey.c.refactor 2019-04-04 13:19:12.188821236 +0200 +++ openssh/auth2-pubkey.c 2019-04-04 13:19:12.276822078 +0200 -@@ -72,6 +72,9 @@ +@@ -72,6 +72,8 @@ /* import */ extern ServerOptions options; +extern int inetd_flag; -+extern int rexeced_flag; +extern Authctxt *the_authctxt; + extern struct authmethod_cfg methodcfg_pubkey; static char * - format_key(const struct sshkey *key) @@ -511,7 +514,8 @@ match_principals_command(struct ssh *ssh if ((pid = subprocess("AuthorizedPrincipalsCommand", command, ac, av, &f, SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD, - runas_pw, temporarily_use_uid, restore_uid)) == 0) + runas_pw, temporarily_use_uid, restore_uid, -+ (inetd_flag && !rexeced_flag), the_authctxt)) == 0) ++ inetd_flag, the_authctxt)) == 0) goto out; uid_swapped = 1; @@ -27,7 +26,7 @@ diff -up openssh/auth2-pubkey.c.refactor openssh/auth2-pubkey.c SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD, - runas_pw, temporarily_use_uid, restore_uid)) == 0) + runas_pw, temporarily_use_uid, restore_uid, -+ (inetd_flag && !rexeced_flag), the_authctxt)) == 0) ++ inetd_flag, the_authctxt)) == 0) goto out; uid_swapped = 1; @@ -82,14 +81,13 @@ diff -up openssh/openbsd-compat/port-linux.h.refactor openssh/openbsd-compat/por diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compat/port-linux-sshd.c --- openssh/openbsd-compat/port-linux-sshd.c.refactor 2019-04-04 13:19:12.256821887 +0200 +++ openssh/openbsd-compat/port-linux-sshd.c 2019-04-04 13:19:12.276822078 +0200 -@@ -49,11 +49,6 @@ +@@ -49,10 +49,6 @@ #include #endif -extern ServerOptions options; -extern Authctxt *the_authctxt; -extern int inetd_flag; --extern int rexeced_flag; - /* Wrapper around is_selinux_enabled() to log its return value once only */ int @@ -128,7 +126,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa if (r == 0) { /* If launched from xinetd, we must use current level */ -- if (inetd_flag && !rexeced_flag) { +- if (inetd_flag) { + if (inetd) { security_context_t sshdsc=NULL; @@ -152,7 +150,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : ""); -- if (inetd_flag && !rexeced_flag) { +- if (inetd_flag) { + if (inetd) { use_current = "1"; } else { @@ -216,55 +214,45 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa diff -up openssh/platform.c.refactor openssh/platform.c --- openssh/platform.c.refactor 2019-04-04 13:19:12.204821389 +0200 +++ openssh/platform.c 2019-04-04 13:19:12.277822088 +0200 -@@ -32,6 +32,9 @@ +@@ -32,6 +32,8 @@ + #include "openbsd-compat/openbsd-compat.h" - extern int use_privsep; extern ServerOptions options; +extern int inetd_flag; -+extern int rexeced_flag; +extern Authctxt *the_authctxt; - void - platform_pre_listen(void) + /* return 1 if we are running with privilege to swap UIDs, 0 otherwise */ + int @@ -183,7 +186,9 @@ platform_setusercontext_post_groups(stru } #endif /* HAVE_SETPCRED */ #ifdef WITH_SELINUX - sshd_selinux_setup_exec_context(pw->pw_name); + sshd_selinux_setup_exec_context(pw->pw_name, -+ (inetd_flag && !rexeced_flag), do_pam_putenv, the_authctxt, ++ inetd_flag, do_pam_putenv, the_authctxt, + options.use_pam); #endif } -diff -up openssh/sshd.c.refactor openssh/sshd.c ---- openssh/sshd.c.refactor 2019-04-04 13:19:12.275822068 +0200 -+++ openssh/sshd.c 2019-04-04 13:19:51.270195262 +0200 +diff -up openssh/sshd-session.c.refactor openssh/sshd-session.c +--- openssh/sshd-session.c.refactor 2019-04-04 13:19:12.275822068 +0200 ++++ openssh/sshd-session.c 2019-04-04 13:19:51.270195262 +0200 @@ -158,7 +158,7 @@ int debug_flag = 0; - static int test_flag = 0; + int debug_flag = 0; /* Flag indicating that the daemon is being started from inetd. */ -static int inetd_flag = 0; +int inetd_flag = 0; - /* Flag indicating that sshd should not detach and become a daemon. */ - static int no_daemon_flag = 0; -@@ -171,7 +171,7 @@ static char **saved_argv; - static int saved_argc; - - /* re-exec */ --static int rexeced_flag = 0; -+int rexeced_flag = 0; - static int rexec_flag = 1; - static int rexec_argc = 0; - static char **rexec_argv; + /* debug goes to stderr unless inetd_flag is set */ + static int log_stderr = 0; @@ -2192,7 +2192,9 @@ main(int ac, char **av) } #endif #ifdef WITH_SELINUX - sshd_selinux_setup_exec_context(authctxt->pw->pw_name); + sshd_selinux_setup_exec_context(authctxt->pw->pw_name, -+ (inetd_flag && !rexeced_flag), do_pam_putenv, the_authctxt, ++ inetd_flag, do_pam_putenv, the_authctxt, + options.use_pam); #endif #ifdef USE_PAM diff --git a/SOURCES/openssh-7.7p1-fips.patch b/SOURCES/openssh-7.7p1-fips.patch index 704de05..9f83eee 100644 --- a/SOURCES/openssh-7.7p1-fips.patch +++ b/SOURCES/openssh-7.7p1-fips.patch @@ -72,17 +72,17 @@ diff -up openssh-8.6p1/dh.h.fips openssh-8.6p1/dh.h u_int dh_estimate(int); void dh_set_moduli_file(const char *); -diff -up openssh-8.6p1/kex.c.fips openssh-8.6p1/kex.c ---- openssh-8.6p1/kex.c.fips 2021-05-06 12:08:36.489926807 +0200 -+++ openssh-8.6p1/kex.c 2021-05-06 12:08:36.498926877 +0200 +diff -up openssh-8.6p1/kex-names.c.fips openssh-8.6p1/kex-names.c +--- openssh-8.6p1/kex-names.c.fips 2021-05-06 12:08:36.489926807 +0200 ++++ openssh-8.6p1/kex-names.c 2021-05-06 12:08:36.498926877 +0200 @@ -39,6 +39,7 @@ #ifdef WITH_OPENSSL #include +#include - #include - # ifdef HAVE_EVP_KDF_CTX_NEW - # include + #include + #endif + @@ -203,7 +203,10 @@ kex_names_valid(const char *names) for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { @@ -121,8 +121,8 @@ 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-05-06 12:08:36.498926877 +0200 @@ -57,6 +57,18 @@ - "rsa-sha2-256," \ - "ssh-rsa" + "rsa-sha2-512," \ + "rsa-sha2-256" +#define KEX_FIPS_PK_ALG \ + "ecdsa-sha2-nistp256-cert-v01@openssh.com," \ @@ -268,9 +268,24 @@ diff -up openssh-8.6p1/ssh.c.fips openssh-8.6p1/ssh.c /* Expand SecurityKeyProvider if it refers to an environment variable */ if (options.sk_provider != NULL && *options.sk_provider == '$' && strlen(options.sk_provider) > 1) { -diff -up openssh-8.6p1/sshconnect2.c.fips openssh-8.6p1/sshconnect2.c ---- openssh-8.6p1/sshconnect2.c.fips 2021-05-06 12:08:36.485926777 +0200 -+++ openssh-8.6p1/sshconnect2.c 2021-05-06 12:08:36.501926900 +0200 +diff -up openssh-9.9p1/ssh-gss.h.xxx openssh-9.9p1/ssh-gss.h +--- openssh-9.9p1/ssh-gss.h.xxx 2025-08-04 15:02:15.895341244 +0200 ++++ openssh-9.9p1/ssh-gss.h 2025-08-04 15:02:54.826304548 +0200 +@@ -94,6 +94,11 @@ extern char **k5users_allowed_cmds; + KEX_GSS_GRP14_SHA1_ID "," \ + KEX_GSS_GEX_SHA1_ID + ++#define GSS_KEX_DEFAULT_KEX_FIPS \ ++ KEX_GSS_GRP14_SHA256_ID "," \ ++ KEX_GSS_GRP16_SHA512_ID "," \ ++ KEX_GSS_NISTP256_SHA256_ID ++ + #include "digest.h" /* SSH_DIGEST_MAX_LENGTH */ + + typedef struct { +diff -up openssh-9.9p1/sshconnect2.c.xxx openssh-9.9p1/sshconnect2.c +--- openssh-9.9p1/sshconnect2.c.xxx 2025-08-04 14:58:08.908229826 +0200 ++++ openssh-9.9p1/sshconnect2.c 2025-08-04 15:07:59.942477440 +0200 @@ -45,6 +45,8 @@ #include #endif @@ -280,80 +295,32 @@ diff -up openssh-8.6p1/sshconnect2.c.fips openssh-8.6p1/sshconnect2.c #include "openbsd-compat/sys-queue.h" #include "xmalloc.h" -@@ -269,36 +271,41 @@ ssh_kex2(struct ssh *ssh, char *host, st +@@ -274,6 +277,9 @@ ssh_kex2(struct ssh *ssh, char *host, st #if defined(GSSAPI) && defined(WITH_OPENSSL) if (options.gss_keyex) { -- /* Add the GSSAPI mechanisms currently supported on this -- * client to the key exchange algorithm proposal */ -- orig = myproposal[PROPOSAL_KEX_ALGS]; -- -- if (options.gss_server_identity) { -- gss_host = xstrdup(options.gss_server_identity); -- } else if (options.gss_trust_dns) { -- gss_host = remote_hostname(ssh); -- /* Fall back to specified host if we are using proxy command -- * and can not use DNS on that socket */ -- if (strcmp(gss_host, "UNKNOWN") == 0) { -- free(gss_host); -+ if (FIPS_mode()) { -+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); -+ options.gss_keyex = 0; -+ } else { -+ /* Add the GSSAPI mechanisms currently supported on this -+ * client to the key exchange algorithm proposal */ -+ orig = myproposal[PROPOSAL_KEX_ALGS]; ++ char * gss_kex_filtered = FIPS_mode() ? ++ match_filter_allowlist(options.gss_kex_algorithms, GSS_KEX_DEFAULT_KEX_FIPS) : xstrdup(options.gss_kex_algorithms); + -+ if (options.gss_server_identity) { -+ gss_host = xstrdup(options.gss_server_identity); -+ } else if (options.gss_trust_dns) { -+ gss_host = remote_hostname(ssh); -+ /* Fall back to specified host if we are using proxy command -+ * and can not use DNS on that socket */ -+ if (strcmp(gss_host, "UNKNOWN") == 0) { -+ free(gss_host); -+ gss_host = xstrdup(host); -+ } -+ } else { - gss_host = xstrdup(host); - } -- } else { -- gss_host = xstrdup(host); -- } - -- gss = ssh_gssapi_client_mechanisms(gss_host, -- options.gss_client_identity, options.gss_kex_algorithms); -- if (gss) { -- debug("Offering GSSAPI proposal: %s", gss); -- xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -- "%s,%s", gss, orig); -- -- /* If we've got GSSAPI algorithms, then we also support the -- * 'null' hostkey, as a last resort */ -- orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; -- xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], -- "%s,null", orig); -+ gss = ssh_gssapi_client_mechanisms(gss_host, -+ options.gss_client_identity, options.gss_kex_algorithms); -+ if (gss) { -+ debug("Offering GSSAPI proposal: %s", gss); -+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ -+ /* If we've got GSSAPI algorithms, then we also support the -+ * 'null' hostkey, as a last resort */ -+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; -+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], -+ "%s,null", orig); -+ } + /* Add the GSSAPI mechanisms currently supported on this + * client to the key exchange algorithm proposal */ + orig = myproposal[PROPOSAL_KEX_ALGS]; +@@ -293,7 +299,9 @@ ssh_kex2(struct ssh *ssh, char *host, st } - } - #endif + + gss = ssh_gssapi_client_mechanisms(gss_host, +- options.gss_client_identity, options.gss_kex_algorithms); ++ options.gss_client_identity, gss_kex_filtered); ++ free(gss_kex_filtered); ++ + if (gss) { + debug("Offering GSSAPI proposal: %s", gss); + xasprintf(&myproposal[PROPOSAL_KEX_ALGS], diff -up openssh-8.6p1/sshd.c.fips openssh-8.6p1/sshd.c --- openssh-8.6p1/sshd.c.fips 2021-05-06 12:08:36.493926838 +0200 +++ openssh-8.6p1/sshd.c 2021-05-06 12:13:56.501492639 +0200 @@ -66,6 +66,7 @@ - #include + #endif #include #include +#include @@ -361,21 +328,13 @@ diff -up openssh-8.6p1/sshd.c.fips openssh-8.6p1/sshd.c #include #include @@ -77,6 +78,7 @@ - #include - #include + #ifdef WITH_OPENSSL + #include #include +#include #include "openbsd-compat/openssl-compat.h" #endif -@@ -1619,6 +1621,7 @@ main(int ac, char **av) - #endif - __progname = ssh_get_progname(av[0]); - -+ OpenSSL_add_all_algorithms(); - /* 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\"", @@ -401,7 +360,18 @@ diff -up openssh-8.6p1/sshd.c.fips openssh-8.6p1/sshd.c /* * Chdir to the root directory so that the current disk can be * unmounted if desired. -@@ -2494,10 +2501,14 @@ do_ssh2_kex(struct ssh *ssh) +diff -up openssh-8.6p1/sshd-session.c.fips openssh-8.6p1/sshd-session.c +--- a/sshd-session.c.fips 2021-05-06 12:08:36.493926838 +0200 ++++ b/sshd-session.c 2021-05-06 12:13:56.501492639 +0200 +@@ -78,6 +79,7 @@ + #include + #include + #include ++#include + #include "openbsd-compat/openssl-compat.h" + #endif + +@@ -2506,10 +2513,14 @@ do_ssh2_kex(struct ssh *ssh) if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) orig = NULL; @@ -423,7 +393,7 @@ diff -up openssh-8.6p1/sshd.c.fips openssh-8.6p1/sshd.c diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c --- openssh-8.6p1/sshkey.c.fips 2021-05-06 12:08:36.493926838 +0200 +++ openssh-8.6p1/sshkey.c 2021-05-06 12:08:36.502926908 +0200 -@@ -34,6 +34,7 @@ +@@ -36,6 +36,7 @@ #include #include #include @@ -440,11 +410,11 @@ diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c #ifdef WITH_XMSS @@ -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) + impl = keyimpls[i]; + if (impl->name == NULL || impl->type == KEY_NULL) continue; + if (FIPS_mode()) { -+ switch (kt->type) { ++ switch (impl->type) { + case KEY_ED25519: + case KEY_ED25519_SK: + case KEY_ED25519_CERT: @@ -455,9 +425,9 @@ diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c + break; + } + } - if (!include_sigonly && kt->sigonly) + if (!include_sigonly && impl->sigonly) continue; - if ((certs_only && !kt->cert) || (plain_only && kt->cert)) + if ((certs_only && !impl->cert) || (plain_only && impl->cert)) @@ -1503,6 +1503,20 @@ sshkey_read(struct sshkey *ret, char **c return SSH_ERR_EC_CURVE_MISMATCH; } @@ -477,40 +447,31 @@ diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c + 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; - } + sshkey_free_contents(ret); + *ret = *k; @@ -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, + *lenp = 0; + if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) + return SSH_ERR_INVALID_ARGUMENT; ++ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) { ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } ++ /* Fallthrough */ + if ((impl = sshkey_impl_from_key(key)) == NULL) + return SSH_ERR_KEY_TYPE_UNKNOWN; + if ((r = sshkey_unshield_private(key)) != 0) @@ -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 + *detailsp = NULL; + if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE) + return SSH_ERR_INVALID_ARGUMENT; ++ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) { ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } + if ((impl = sshkey_impl_from_key(key)) == NULL) + return SSH_ERR_KEY_TYPE_UNKNOWN; + return impl->funcs->verify(key, sig, siglen, data, dlen, diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c --- openssh-8.6p1/ssh-keygen.c.fips 2021-05-06 12:08:36.467926637 +0200 +++ openssh-8.6p1/ssh-keygen.c 2021-05-06 12:08:36.503926916 +0200 @@ -522,6 +483,14 @@ diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c #include #include "openbsd-compat/openssl-compat.h" #endif +@@ -69,6 +69,7 @@ + #include "cipher.h" + + #define DEFAULT_KEY_TYPE_NAME "ed25519" ++#define FIPS_DEFAULT_KEY_TYPE_NAME "rsa" + + /* + * Default number of bits in the RSA, DSA and ECDSA keys. These value can be @@ -205,6 +205,12 @@ type_bits_valid(int type, const char *na #endif } @@ -535,11 +504,20 @@ diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c switch (type) { case KEY_DSA: if (*bitsp != 1024) +@@ -266,7 +267,7 @@ ask_filename(struct passwd *pw, const ch + char *name = NULL; + + if (key_type_name == NULL) +- name = _PATH_SSH_CLIENT_ID_ED25519; ++ name = FIPS_mode() ? _PATH_SSH_CLIENT_ID_RSA : _PATH_SSH_CLIENT_ID_ED25519; + else { + switch (sshkey_type_from_shortname(key_type_name)) { + #ifdef WITH_DSA @@ -1098,9 +1104,17 @@ do_gen_all_hostkeys(struct passwd *pw) first = 1; printf("%s: generating new host keys: ", __progname); } -+ type = sshkey_type_from_name(key_types[i].key_type); ++ type = sshkey_type_from_shortname(key_types[i].key_type); + + /* Skip the keys that are not supported in FIPS mode */ + if (FIPS_mode() && (type == KEY_DSA || type == KEY_ED25519)) { @@ -550,13 +528,42 @@ diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c + printf("%s ", key_types[i].key_type_display); fflush(stdout); -- type = sshkey_type_from_name(key_types[i].key_type); +- type = sshkey_type_from_shortname(key_types[i].key_type); 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 +@@ -3830,7 +3831,7 @@ main(int argc, char **argv) + } + + if (key_type_name == NULL) +- key_type_name = DEFAULT_KEY_TYPE_NAME; ++ key_type_name = FIPS_mode() ? FIPS_DEFAULT_KEY_TYPE_NAME : DEFAULT_KEY_TYPE_NAME; + + type = sshkey_type_from_shortname(key_type_name); + type_bits_valid(type, key_type_name, &bits); +diff -up openssh-9.3p1/ssh-rsa.c.evpgenrsa openssh-9.3p1/ssh-rsa.c +--- openssh-9.3p1/ssh-rsa.c.evpgenrsa 2022-06-30 15:14:58.200518353 +0200 ++++ openssh-9.3p1/ssh-rsa.c 2022-06-30 15:24:31.499641196 +0200 +@@ -33,6 +33,7 @@ + + #include + #include ++#include + + #include + #include +@@ -1705,6 +1707,8 @@ ssh_rsa_generate(u_int bits, RSA + goto out; + } + if (EVP_PKEY_keygen(ctx, &res) <= 0 || res == NULL) { ++ 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; + } +diff -up openssh-9.9p1/kexgen.c.xxx openssh-9.9p1/kexgen.c +--- openssh-9.9p1/kexgen.c.xxx 2024-10-09 10:35:56.285946080 +0200 ++++ openssh-9.9p1/kexgen.c 2024-10-09 10:41:52.792597194 +0200 @@ -31,6 +31,7 @@ #include #include @@ -565,7 +572,7 @@ diff -up openssh-8.7p1/kexgen.c.fips3 openssh-8.7p1/kexgen.c #include "sshkey.h" #include "kex.h" -@@ -115,10 +116,20 @@ kex_gen_client(struct ssh *ssh) +@@ -115,13 +116,28 @@ kex_gen_client(struct ssh *ssh) break; #endif case KEX_C25519_SHA256: @@ -584,11 +591,20 @@ diff -up openssh-8.7p1/kexgen.c.fips3 openssh-8.7p1/kexgen.c + r = SSH_ERR_INVALID_ARGUMENT; + } else { + r = kex_kem_sntrup761x25519_keypair(kex); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_keypair(kex); + } break; default: r = SSH_ERR_INVALID_ARGUMENT; -@@ -186,11 +197,21 @@ input_kex_gen_reply(int type, u_int32_t +@@ -189,15 +205,30 @@ input_kex_gen_reply(int type, u_int32_t break; #endif case KEX_C25519_SHA256: @@ -609,11 +625,22 @@ diff -up openssh-8.7p1/kexgen.c.fips3 openssh-8.7p1/kexgen.c + } else { + r = kex_kem_sntrup761x25519_dec(kex, server_blob, + &shared_secret); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_dec(kex, server_blob, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_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 +@@ -312,16 +343,31 @@ input_kex_gen_init(int type, u_int32_t s break; #endif case KEX_C25519_SHA256: @@ -636,6 +663,17 @@ diff -up openssh-8.7p1/kexgen.c.fips3 openssh-8.7p1/kexgen.c + } else { + r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, + &server_pubkey, &shared_secret); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, +- &server_pubkey, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); + } break; default: @@ -663,13 +701,33 @@ diff -up openssh-8.7p1/ssh-ed25519.c.fips3 openssh-8.7p1/ssh-ed25519.c 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) + dlen >= INT_MAX - crypto_sign_ed25519_BYTES || + sig == NULL || siglen == 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) + if ((b = sshbuf_from(sig, siglen)) == NULL) return SSH_ERR_ALLOC_FAIL; +diff -up openssh-9.9p1/kex.c.xxx openssh-9.9p1/kex.c +--- openssh-9.9p1/kex.c.xxx 2024-10-11 12:44:08.087426597 +0200 ++++ openssh-9.9p1/kex.c 2024-10-11 14:00:10.404714521 +0200 +@@ -40,6 +40,7 @@ + #ifdef WITH_OPENSSL + #include + #include ++#include + # ifdef HAVE_EVP_KDF_CTX_NEW + # include + # include +@@ -109,7 +110,7 @@ kex_proposal_populate_entries(struct ssh + + /* Append EXT_INFO signalling to KexAlgorithms */ + if (kexalgos == NULL) +- kexalgos = defprop[PROPOSAL_KEX_ALGS]; ++ kexalgos = FIPS_mode() ? KEX_DEFAULT_KEX_FIPS : defprop[PROPOSAL_KEX_ALGS]; + if ((cp = kex_names_cat(kexalgos, ssh->kex->server ? + "ext-info-s,kex-strict-s-v00@openssh.com" : + "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL) diff --git a/SOURCES/openssh-7.7p1-gssapi-new-unique.patch b/SOURCES/openssh-7.7p1-gssapi-new-unique.patch index b2d2209..0b8ab02 100644 --- a/SOURCES/openssh-7.7p1-gssapi-new-unique.patch +++ b/SOURCES/openssh-7.7p1-gssapi-new-unique.patch @@ -1,6 +1,6 @@ diff -up openssh-8.6p1/auth.h.ccache_name openssh-8.6p1/auth.h ---- openssh-8.6p1/auth.h.ccache_name 2021-05-06 11:15:36.345143341 +0200 -+++ openssh-8.6p1/auth.h 2021-05-06 11:15:36.387143654 +0200 +--- openssh-8.6p1/auth.h.ccache_name 2021-04-19 14:05:10.820744325 +0200 ++++ openssh-8.6p1/auth.h 2021-04-19 14:05:10.853744569 +0200 @@ -83,6 +83,7 @@ struct Authctxt { krb5_principal krb5_user; char *krb5_ticket_file; @@ -20,7 +20,7 @@ diff -up openssh-8.6p1/auth.h.ccache_name openssh-8.6p1/auth.h #endif /* AUTH_H */ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c --- openssh-8.6p1/auth-krb5.c.ccache_name 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/auth-krb5.c 2021-05-06 11:28:40.195242317 +0200 ++++ openssh-8.6p1/auth-krb5.c 2021-04-19 14:40:55.142832954 +0200 @@ -51,6 +51,7 @@ #include #include @@ -338,8 +338,8 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c #endif /* !HEIMDAL */ #endif /* KRB5 */ diff -up openssh-8.6p1/gss-serv.c.ccache_name openssh-8.6p1/gss-serv.c ---- openssh-8.6p1/gss-serv.c.ccache_name 2021-05-06 11:15:36.374143558 +0200 -+++ openssh-8.6p1/gss-serv.c 2021-05-06 11:15:36.387143654 +0200 +--- openssh-8.6p1/gss-serv.c.ccache_name 2021-04-19 14:05:10.844744503 +0200 ++++ openssh-8.6p1/gss-serv.c 2021-04-19 14:05:10.854744577 +0200 @@ -413,13 +413,15 @@ ssh_gssapi_cleanup_creds(void) } @@ -368,10 +368,10 @@ diff -up openssh-8.6p1/gss-serv.c.ccache_name openssh-8.6p1/gss-serv.c + if (gssapi_client.store.envval == NULL) return; - ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); + ok = mm_ssh_gssapi_update_creds(&gssapi_client.store); diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c ---- openssh-8.6p1/gss-serv-krb5.c.ccache_name 2021-05-06 11:15:36.384143632 +0200 -+++ openssh-8.6p1/gss-serv-krb5.c 2021-05-06 11:15:36.387143654 +0200 +--- openssh-8.6p1/gss-serv-krb5.c.ccache_name 2021-04-19 14:05:10.852744562 +0200 ++++ openssh-8.6p1/gss-serv-krb5.c 2021-04-19 14:05:10.854744577 +0200 @@ -267,7 +267,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri /* This writes out any forwarded credentials from the structure populated * during userauth. Called after we have setuid to the user */ @@ -484,8 +484,8 @@ diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c int diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c ---- openssh-8.6p1/servconf.c.ccache_name 2021-05-06 11:15:36.377143580 +0200 -+++ openssh-8.6p1/servconf.c 2021-05-06 11:15:36.388143662 +0200 +--- openssh-8.6p1/servconf.c.ccache_name 2021-04-19 14:05:10.848744532 +0200 ++++ openssh-8.6p1/servconf.c 2021-04-19 14:05:10.854744577 +0200 @@ -136,6 +136,7 @@ initialize_server_options(ServerOptions options->kerberos_or_local_passwd = -1; options->kerberos_ticket_cleanup = -1; @@ -503,16 +503,15 @@ diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c if (options->gss_authentication == -1) options->gss_authentication = 0; if (options->gss_keyex == -1) -@@ -506,7 +509,8 @@ typedef enum { +@@ -506,7 +509,7 @@ typedef enum { sPort, sHostKeyFile, sLoginGraceTime, sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, -- sKerberosGetAFSToken, sChallengeResponseAuthentication, -+ sKerberosGetAFSToken, sKerberosUniqueCCache, -+ sChallengeResponseAuthentication, - sPasswordAuthentication, sKbdInteractiveAuthentication, - sListenAddress, sAddressFamily, +- sKerberosGetAFSToken, sPasswordAuthentication, ++ sKerberosGetAFSToken, sKerberosUniqueCCache, sPasswordAuthentication, + sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, @@ -593,11 +597,13 @@ static struct { #else { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, @@ -547,8 +546,8 @@ diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); diff -up openssh-8.6p1/servconf.h.ccache_name openssh-8.6p1/servconf.h ---- openssh-8.6p1/servconf.h.ccache_name 2021-05-06 11:15:36.377143580 +0200 -+++ openssh-8.6p1/servconf.h 2021-05-06 11:15:36.397143729 +0200 +--- openssh-8.6p1/servconf.h.ccache_name 2021-04-19 14:05:10.848744532 +0200 ++++ openssh-8.6p1/servconf.h 2021-04-19 14:05:10.855744584 +0200 @@ -140,6 +140,8 @@ typedef struct { * file on logout. */ int kerberos_get_afs_token; /* If true, try to get AFS token if @@ -559,8 +558,8 @@ diff -up openssh-8.6p1/servconf.h.ccache_name openssh-8.6p1/servconf.h int gss_keyex; /* If true, permit GSSAPI key exchange */ int gss_cleanup_creds; /* If true, destroy cred cache on logout */ diff -up openssh-8.6p1/session.c.ccache_name openssh-8.6p1/session.c ---- openssh-8.6p1/session.c.ccache_name 2021-05-06 11:15:36.384143632 +0200 -+++ openssh-8.6p1/session.c 2021-05-06 11:15:36.397143729 +0200 +--- openssh-8.6p1/session.c.ccache_name 2021-04-19 14:05:10.852744562 +0200 ++++ openssh-8.6p1/session.c 2021-04-19 14:05:10.855744584 +0200 @@ -1038,7 +1038,8 @@ do_setup_env(struct ssh *ssh, Session *s /* Allow any GSSAPI methods that we've used to alter * the child's environment as they see fit @@ -580,9 +579,9 @@ diff -up openssh-8.6p1/session.c.ccache_name openssh-8.6p1/session.c child_set_env(&env, &envsize, "KRB5CCNAME", s->authctxt->krb5_ccname); #endif -diff -up openssh-8.6p1/sshd.c.ccache_name openssh-8.6p1/sshd.c ---- openssh-8.6p1/sshd.c.ccache_name 2021-05-06 11:15:36.380143602 +0200 -+++ openssh-8.6p1/sshd.c 2021-05-06 11:15:36.398143736 +0200 +diff -up openssh-8.6p1/sshd-session.c.ccache_name openssh-8.6p1/sshd-session.c +--- openssh-8.6p1/sshd-session.c.ccache_name 2021-04-19 14:05:10.849744540 +0200 ++++ openssh-8.6p1/sshd-session.c 2021-04-19 14:05:10.855744584 +0200 @@ -2284,7 +2284,7 @@ main(int ac, char **av) #ifdef GSSAPI if (options.gss_authentication) { @@ -593,8 +592,8 @@ diff -up openssh-8.6p1/sshd.c.ccache_name openssh-8.6p1/sshd.c } #endif diff -up openssh-8.6p1/sshd_config.5.ccache_name openssh-8.6p1/sshd_config.5 ---- openssh-8.6p1/sshd_config.5.ccache_name 2021-05-06 11:15:36.380143602 +0200 -+++ openssh-8.6p1/sshd_config.5 2021-05-06 11:15:36.398143736 +0200 +--- openssh-8.6p1/sshd_config.5.ccache_name 2021-04-19 14:05:10.849744540 +0200 ++++ openssh-8.6p1/sshd_config.5 2021-04-19 14:05:10.856744592 +0200 @@ -939,6 +939,14 @@ Specifies whether to automatically destr file on logout. The default is @@ -608,11 +607,11 @@ diff -up openssh-8.6p1/sshd_config.5.ccache_name openssh-8.6p1/sshd_config.5 +can lead to overwriting previous tickets by subseqent connections to the same +user account. .It Cm KexAlgorithms - Specifies the available KEX (Key Exchange) algorithms. - Multiple algorithms must be comma-separated. + Specifies the permitted KEX (Key Exchange) algorithms that the server will + offer to clients. diff -up openssh-8.6p1/ssh-gss.h.ccache_name openssh-8.6p1/ssh-gss.h ---- openssh-8.6p1/ssh-gss.h.ccache_name 2021-05-06 11:15:36.384143632 +0200 -+++ openssh-8.6p1/ssh-gss.h 2021-05-06 11:15:36.398143736 +0200 +--- openssh-8.6p1/ssh-gss.h.ccache_name 2021-04-19 14:05:10.852744562 +0200 ++++ openssh-8.6p1/ssh-gss.h 2021-04-19 14:05:10.855744584 +0200 @@ -114,7 +114,7 @@ typedef struct ssh_gssapi_mech_struct { int (*dochild) (ssh_gssapi_client *); int (*userok) (ssh_gssapi_client *, char *); diff --git a/SOURCES/openssh-7.8p1-UsePAM-warning.patch b/SOURCES/openssh-7.8p1-UsePAM-warning.patch index feedcba..f8d7042 100644 --- a/SOURCES/openssh-7.8p1-UsePAM-warning.patch +++ b/SOURCES/openssh-7.8p1-UsePAM-warning.patch @@ -1,13 +1,13 @@ diff -up openssh-8.6p1/sshd.c.log-usepam-no openssh-8.6p1/sshd.c ---- openssh-8.6p1/sshd.c.log-usepam-no 2021-04-19 14:00:45.099735129 +0200 -+++ openssh-8.6p1/sshd.c 2021-04-19 14:03:21.140920974 +0200 +--- openssh-8.6p1/sshd-session.c.log-usepam-no 2021-04-19 14:00:45.099735129 +0200 ++++ openssh-8.6p1/sshd-session.c 2021-04-19 14:03:21.140920974 +0200 @@ -1749,6 +1749,10 @@ main(int ac, char **av) - parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, - cfg, &includes, NULL); + "enabled authentication methods"); + } -+ /* 'UsePAM no' is not supported in RHEL */ ++ /* 'UsePAM no' is not supported in our builds */ + if (! options.use_pam) -+ logit("WARNING: 'UsePAM no' is not supported in RHEL and may cause several problems."); ++ logit("WARNING: 'UsePAM no' is not supported in this build and may cause several problems."); + #ifdef WITH_OPENSSL if (options.moduli_file != NULL) @@ -19,7 +19,7 @@ diff -up openssh-8.6p1/sshd_config.log-usepam-no openssh-8.6p1/sshd_config # If you just want the PAM account and session checks to run without # PAM authentication, then enable this but set PasswordAuthentication # and KbdInteractiveAuthentication to 'no'. -+# WARNING: 'UsePAM no' is not supported in RHEL and may cause several ++# WARNING: 'UsePAM no' is not supported in this build and may cause several +# problems. #UsePAM no diff --git a/SOURCES/openssh-7.8p1-role-mls.patch b/SOURCES/openssh-7.8p1-role-mls.patch index 48f9f10..7c6d0ca 100644 --- a/SOURCES/openssh-7.8p1-role-mls.patch +++ b/SOURCES/openssh-7.8p1-role-mls.patch @@ -23,23 +23,20 @@ diff -up openssh/auth2.c.role-mls openssh/auth2.c if ((style = strchr(user, ':')) != NULL) *style++ = 0; -@@ -296,8 +304,15 @@ input_userauth_request(int type, u_int32 - use_privsep ? " [net]" : ""); +@@ -314,7 +314,13 @@ input_userauth_request(int type, u_int32 + setproctitle("%s [net]", authctxt->valid ? user : "unknown"); authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; -- if (use_privsep) +#ifdef WITH_SELINUX + authctxt->role = role ? xstrdup(role) : NULL; +#endif -+ if (use_privsep) { - mm_inform_authserv(service, style); + mm_inform_authserv(service, style); +#ifdef WITH_SELINUX -+ mm_inform_authrole(role); ++ mm_inform_authrole(role); +#endif -+ } userauth_banner(ssh); - if (auth2_setup_methods_lists(authctxt) != 0) - ssh_packet_disconnect(ssh, + if ((r = kex_server_update_ext_info(ssh)) != 0) + fatal_fr(r, "kex_server_update_ext_info failed"); diff -up openssh/auth2-gss.c.role-mls openssh/auth2-gss.c --- openssh/auth2-gss.c.role-mls 2018-08-20 07:57:29.000000000 +0200 +++ openssh/auth2-gss.c 2018-08-22 11:15:42.459799171 +0200 @@ -50,7 +47,7 @@ diff -up openssh/auth2-gss.c.role-mls openssh/auth2-gss.c + char *micuser; struct sshbuf *b; gss_buffer_desc mic, gssbuf; - const char *displayname; + u_char *p; @@ -298,7 +299,13 @@ input_gssapi_mic(int type, u_int32_t ple fatal_f("sshbuf_new failed"); mic.value = p; @@ -74,7 +71,7 @@ diff -up openssh/auth2-gss.c.role-mls openssh/auth2-gss.c + free(micuser); free(mic.value); - if ((!use_privsep || mm_is_monitor()) && + authctxt->postponed = 0; diff -up openssh/auth2-hostbased.c.role-mls openssh/auth2-hostbased.c --- openssh/auth2-hostbased.c.role-mls 2018-08-20 07:57:29.000000000 +0200 +++ openssh/auth2-hostbased.c 2018-08-22 11:14:56.816430924 +0200 @@ -93,7 +90,7 @@ diff -up openssh/auth2-hostbased.c.role-mls openssh/auth2-hostbased.c (r = sshbuf_put_cstring(b, authctxt->user)) != 0 || +#endif (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || - (r = sshbuf_put_cstring(b, "hostbased")) != 0 || + (r = sshbuf_put_cstring(b, method)) != 0 || (r = sshbuf_put_string(b, pkalg, alen)) != 0 || diff -up openssh/auth2-pubkey.c.role-mls openssh/auth2-pubkey.c --- openssh/auth2-pubkey.c.role-mls 2018-08-22 11:14:56.816430924 +0200 @@ -147,7 +144,7 @@ diff -up openssh/auth-pam.h.role-mls openssh/auth-pam.h +++ openssh/auth-pam.h 2018-08-22 11:14:56.817430932 +0200 @@ -33,7 +33,7 @@ u_int do_pam_account(void); void do_pam_session(struct ssh *); - void do_pam_setcred(int ); + void do_pam_setcred(void); void do_pam_chauthtok(void); -int do_pam_putenv(char *, char *); +int do_pam_putenv(char *, const char *); @@ -240,14 +237,14 @@ diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c mm_answer_authpassword(struct ssh *ssh, int sock, struct sshbuf *m) { @@ -1251,7 +1280,7 @@ monitor_valid_userblob(struct ssh *ssh, - { struct sshbuf *b; + struct sshkey *hostkey = NULL; const u_char *p; - char *userstyle, *cp; + char *userstyle, *s, *cp; size_t len; u_char type; - int r, fail = 0; + int hostbound = 0, r, fail = 0; @@ -1282,6 +1311,8 @@ monitor_valid_userblob(struct ssh *ssh, fail++; if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) @@ -418,7 +415,7 @@ diff -up openssh/openbsd-compat/port-linux.h.role-mls openssh/openbsd-compat/por diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compat/port-linux-sshd.c --- openssh/openbsd-compat/port-linux-sshd.c.role-mls 2018-08-22 11:14:56.819430949 +0200 +++ openssh/openbsd-compat/port-linux-sshd.c 2018-08-22 11:14:56.819430949 +0200 -@@ -0,0 +1,421 @@ +@@ -0,0 +1,420 @@ +/* + * Copyright (c) 2005 Daniel Walsh + * Copyright (c) 2014 Petr Lautrbach @@ -472,7 +469,6 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compa +extern ServerOptions options; +extern Authctxt *the_authctxt; +extern int inetd_flag; -+extern int rexeced_flag; + +/* Send audit message */ +static int @@ -678,7 +674,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compa + + if (r == 0) { + /* If launched from xinetd, we must use current level */ -+ if (inetd_flag && !rexeced_flag) { ++ if (inetd_flag) { + security_context_t sshdsc=NULL; + + if (getcon_raw(&sshdsc) < 0) @@ -752,7 +748,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compa + + rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); + -+ if (inetd_flag && !rexeced_flag) { ++ if (inetd_flag) { + use_current = "1"; + } else { + use_current = ""; @@ -853,8 +849,8 @@ diff -up openssh/platform.c.role-mls openssh/platform.c } diff -up openssh/sshd.c.role-mls openssh/sshd.c ---- openssh/sshd.c.role-mls 2018-08-20 07:57:29.000000000 +0200 -+++ openssh/sshd.c 2018-08-22 11:14:56.820430957 +0200 +--- openssh/sshd-session.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/sshd-session.c 2018-08-22 11:14:56.820430957 +0200 @@ -2186,6 +2186,9 @@ main(int ac, char **av) restore_uid(); } @@ -864,4 +860,4 @@ diff -up openssh/sshd.c.role-mls openssh/sshd.c +#endif #ifdef USE_PAM if (options.use_pam) { - do_pam_setcred(1); + do_pam_setcred(); diff --git a/SOURCES/openssh-8.0p1-crypto-policies.patch b/SOURCES/openssh-8.0p1-crypto-policies.patch index 502e1de..a666c5c 100644 --- a/SOURCES/openssh-8.0p1-crypto-policies.patch +++ b/SOURCES/openssh-8.0p1-crypto-policies.patch @@ -1,9 +1,9 @@ -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 @@ - .Qq *.c.example.com - domains. +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/ssh_config.5 openssh-9.3p1-patched/ssh_config.5 +--- openssh-9.3p1/ssh_config.5 2023-06-07 10:26:48.284590156 +0200 ++++ openssh-9.3p1-patched/ssh_config.5 2023-06-07 10:26:00.623052194 +0200 +@@ -378,17 +378,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 . @@ -24,7 +24,7 @@ diff --color -ru a/ssh_config.5 b/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 @@ +@@ -450,20 +446,25 @@ (the default), the check will not be executed. .It Cm Ciphers @@ -54,7 +54,7 @@ diff --color -ru a/ssh_config.5 b/ssh_config.5 .Pp The supported ciphers are: .Bd -literal -offset indent -@@ -474,13 +475,6 @@ +@@ -479,13 +480,6 @@ chacha20-poly1305@openssh.com .Ed .Pp @@ -68,7 +68,7 @@ diff --color -ru a/ssh_config.5 b/ssh_config.5 The list of available ciphers may also be obtained using .Qq ssh -Q cipher . .It Cm ClearAllForwardings -@@ -874,6 +868,11 @@ +@@ -885,6 +879,11 @@ The default is .Dq no . .It Cm GSSAPIKexAlgorithms @@ -80,7 +80,7 @@ diff --color -ru a/ssh_config.5 b/ssh_config.5 The list of key exchange algorithms that are offered for GSSAPI key exchange. Possible values are .Bd -literal -offset 3n -@@ -886,10 +885,8 @@ +@@ -897,10 +896,8 @@ gss-curve25519-sha256- .Ed .Pp @@ -92,7 +92,70 @@ diff --color -ru a/ssh_config.5 b/ssh_config.5 .It Cm HashKnownHosts Indicates that .Xr ssh 1 -@@ -1219,29 +1216,25 @@ +@@ -919,36 +916,25 @@ + but may be manually hashed using + .Xr ssh-keygen 1 . + .It Cm HostbasedAcceptedAlgorithms ++The default is handled system-wide by ++.Xr crypto-policies 7 . ++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 hostbased + authentication as a comma-separated list of patterns. + Alternately if the specified list begins with a + .Sq + + character, then the specified signature algorithms will be appended +-to the default set instead of replacing them. ++to the built-in openssh default set instead of replacing them. + If the specified list begins with a + .Sq - + character, then the specified signature algorithms (including wildcards) +-will be removed from the default set instead of replacing them. ++will be removed from the built-in openssh default set instead of replacing them. + If the specified list begins with a + .Sq ^ + character, then the specified signature algorithms will be placed +-at the head of the default set. +-The default for this option is: +-.Bd -literal -offset 3n +-ssh-ed25519-cert-v01@openssh.com, +-ecdsa-sha2-nistp256-cert-v01@openssh.com, +-ecdsa-sha2-nistp384-cert-v01@openssh.com, +-ecdsa-sha2-nistp521-cert-v01@openssh.com, +-sk-ssh-ed25519-cert-v01@openssh.com, +-sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, +-rsa-sha2-512-cert-v01@openssh.com, +-rsa-sha2-256-cert-v01@openssh.com, +-ssh-ed25519, +-ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-sk-ssh-ed25519@openssh.com, +-sk-ecdsa-sha2-nistp256@openssh.com, +-rsa-sha2-512,rsa-sha2-256 +-.Ed ++at the head of the built-in openssh default set. + .Pp + The + .Fl Q +@@ -1001,6 +987,17 @@ + .Pp + The list of available signature algorithms may also be obtained using + .Qq ssh -Q HostKeyAlgorithms . ++.Pp ++The proposed ++.Cm HostKeyAlgorithms ++during KEX are limited to the set of algorithms that is defined in ++.Cm PubkeyAcceptedAlgorithms ++and therefore they are indirectly affected by system-wide ++.Xr crypto_policies 7 . ++.Xr crypto_policies 7 can not handle the list of host key algorithms directly as doing so ++would break the order given by the ++.Pa known_hosts ++file. + .It Cm HostKeyAlias + Specifies an alias that should be used instead of the + real host name when looking up or saving the host key +@@ -1330,6 +1330,11 @@ it may be zero or more of: and .Cm pam . .It Cm KexAlgorithms @@ -101,25 +164,31 @@ diff --color -ru a/ssh_config.5 b/ssh_config.5 +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. - Multiple algorithms must be comma-separated. + Specifies the permitted KEX (Key Exchange) algorithms that will be used and + their preference order. + The selected algorithm will be the first algorithm in this list that +@@ -1338,29 +1343,17 @@ Multiple algorithms must be comma-separa + .Pp If the specified list begins with a .Sq + --character, then the specified methods will be appended to the default set +-character, then the specified algorithms will be appended to the default set -instead of replacing them. +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 - - character, then the specified methods (including wildcards) will be removed + character, then the specified algorithms (including wildcards) will be removed -from the default set instead of replacing them. +from the built-in openssh default set instead of replacing them. If the specified list begins with a .Sq ^ - character, then the specified methods will be placed at the head of the + character, then the specified algorithms will be placed at the head of the -default set. +-.Pp -The default is: -.Bd -literal -offset indent +-sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com, +-mlkem768x25519-sha256, -curve25519-sha256,curve25519-sha256@libssh.org, -ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, -diffie-hellman-group-exchange-sha256, @@ -127,11 +196,12 @@ diff --color -ru a/ssh_config.5 b/ssh_config.5 -diffie-hellman-group18-sha512, -diffie-hellman-group14-sha256 -.Ed -+built-in openssh default set. .Pp - The list of available key exchange algorithms may also be obtained using ++built-in openssh default set. + The list of supported key exchange algorithms may also be obtained using .Qq ssh -Q kex . -@@ -1351,37 +1344,33 @@ + .It Cm KnownHostsCommand +@@ -1365,37 +1357,33 @@ file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs @@ -178,7 +248,7 @@ diff --color -ru a/ssh_config.5 b/ssh_config.5 The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . .It Cm NoHostAuthenticationForLocalhost -@@ -1553,37 +1542,25 @@ +@@ -1567,39 +1555,31 @@ The default is .Cm no . .It Cm PubkeyAcceptedAlgorithms @@ -214,21 +284,37 @@ diff --color -ru a/ssh_config.5 b/ssh_config.5 -sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, -rsa-sha2-512-cert-v01@openssh.com, -rsa-sha2-256-cert-v01@openssh.com, --ssh-rsa-cert-v01@openssh.com, -ssh-ed25519, -ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, -sk-ssh-ed25519@openssh.com, -sk-ecdsa-sha2-nistp256@openssh.com, --rsa-sha2-512,rsa-sha2-256,ssh-rsa +-rsa-sha2-512,rsa-sha2-256 -.Ed +built-in openssh default set. .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q PubkeyAcceptedAlgorithms . -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 @@ ++.Pp ++This option affects also ++.Cm HostKeyAlgorithms + .It Cm PubkeyAuthentication + Specifies whether to try public key authentication. + The argument to this keyword must be +@@ -2265,7 +2245,9 @@ + This file must be world-readable. + .El + .Sh SEE ALSO +-.Xr ssh 1 ++.Xr ssh 1 , ++.Xr crypto-policies 7 , ++.Xr update-crypto-policies 8 + .Sh AUTHORS + .An -nosplit + OpenSSH is a derivative of the original and free +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/sshd_config.5 openssh-9.3p1-patched/sshd_config.5 +--- openssh-9.3p1/sshd_config.5 2023-06-07 10:26:48.277590077 +0200 ++++ openssh-9.3p1-patched/sshd_config.5 2023-06-07 10:26:00.592051845 +0200 +@@ -379,17 +379,13 @@ then no banner is displayed. By default, no banner is displayed. .It Cm CASignatureAlgorithms @@ -251,7 +337,7 @@ diff --color -ru a/sshd_config.5 b/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 @@ +@@ -525,20 +521,25 @@ indicating not to .Xr chroot 2 . .It Cm Ciphers @@ -281,7 +367,7 @@ diff --color -ru a/sshd_config.5 b/sshd_config.5 .Pp The supported ciphers are: .Pp -@@ -490,13 +491,6 @@ +@@ -565,13 +566,6 @@ chacha20-poly1305@openssh.com .El .Pp @@ -295,7 +381,7 @@ diff --color -ru a/sshd_config.5 b/sshd_config.5 The list of available ciphers may also be obtained using .Qq ssh -Q cipher . .It Cm ClientAliveCountMax -@@ -685,21 +679,22 @@ +@@ -766,53 +760,43 @@ .Cm GSSAPIKeyExchange needs to be enabled in the server and also used by the client. .It Cm GSSAPIKexAlgorithms @@ -327,18 +413,27 @@ diff --color -ru a/sshd_config.5 b/sshd_config.5 -gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- . 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 @@ - .Ev SSH_AUTH_SOCK - environment variable. - .It Cm HostKeyAlgorithms +The default is handled system-wide by +.Xr crypto-policies 7 . +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 - that the server offers. + Specifies the signature algorithms that will be accepted for hostbased + authentication as a list of comma-separated patterns. + Alternately if the specified list begins with a + .Sq + + character, then the specified signature algorithms will be appended to +-the default set instead of replacing them. ++the built-in openssh default set instead of replacing them. + If the specified list begins with a + .Sq - + character, then the specified signature algorithms (including wildcards) +-will be removed from the default set instead of replacing them. ++will be removed from the built-in openssh default set instead of replacing them. + If the specified list begins with a + .Sq ^ + character, then the specified signature algorithms will be placed at +-the head of the default set. -The default for this option is: -.Bd -literal -offset 3n -ssh-ed25519-cert-v01@openssh.com, @@ -349,18 +444,48 @@ diff --color -ru a/sshd_config.5 b/sshd_config.5 -sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, -rsa-sha2-512-cert-v01@openssh.com, -rsa-sha2-256-cert-v01@openssh.com, --ssh-rsa-cert-v01@openssh.com, -ssh-ed25519, -ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, -sk-ssh-ed25519@openssh.com, -sk-ecdsa-sha2-nistp256@openssh.com, --rsa-sha2-512,rsa-sha2-256,ssh-rsa +-rsa-sha2-512,rsa-sha2-256 +-.Ed ++the head of the built-in openssh default set. + .Pp + The list of available signature algorithms may also be obtained using + .Qq ssh -Q HostbasedAcceptedAlgorithms . +@@ -879,25 +863,14 @@ + .Ev SSH_AUTH_SOCK + environment variable. + .It Cm HostKeyAlgorithms ++The default is handled system-wide by ++.Xr crypto-policies 7 . ++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 + that the server offers. + The default for this option is: +-.Bd -literal -offset 3n +-ssh-ed25519-cert-v01@openssh.com, +-ecdsa-sha2-nistp256-cert-v01@openssh.com, +-ecdsa-sha2-nistp384-cert-v01@openssh.com, +-ecdsa-sha2-nistp521-cert-v01@openssh.com, +-sk-ssh-ed25519-cert-v01@openssh.com, +-sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, +-rsa-sha2-512-cert-v01@openssh.com, +-rsa-sha2-256-cert-v01@openssh.com, +-ssh-ed25519, +-ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, +-sk-ssh-ed25519@openssh.com, +-sk-ecdsa-sha2-nistp256@openssh.com, +-rsa-sha2-512,rsa-sha2-256 -.Ed -.Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . .It Cm IgnoreRhosts -@@ -965,20 +947,25 @@ +@@ -1025,6 +1025,11 @@ Specifies whether to look at .k5login fi The default is .Cm yes . .It Cm KexAlgorithms @@ -369,33 +494,38 @@ diff --color -ru a/sshd_config.5 b/sshd_config.5 +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. - Multiple algorithms must be comma-separated. - Alternately if the specified list begins with a + Specifies the permitted KEX (Key Exchange) algorithms that the server will + offer to clients. + The ordering of this list is not important, as the client specifies the +@@ -1033,16 +1038,16 @@ Multiple algorithms must be comma-separa + .Pp + If the specified list begins with a .Sq + --character, then the specified methods will be appended to the default set +-character, then the specified algorithms will be appended to the default set -instead of replacing them. +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 - - character, then the specified methods (including wildcards) will be removed + character, then the specified algorithms (including wildcards) will be removed -from the default set instead of replacing them. +from the built-in openssh default set instead of replacing them. If the specified list begins with a .Sq ^ - character, then the specified methods will be placed at the head of the + character, then the specified algorithms will be placed at the head of the -default set. +built-in openssh default set. + .Pp The supported algorithms are: .Pp - .Bl -item -compact -offset indent -@@ -1010,15 +997,6 @@ +@@ -1075,17 +1080,6 @@ ecdh-sha2-nistp521 sntrup761x25519-sha512@openssh.com .El .Pp -The default is: -.Bd -literal -offset indent +-sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com, +-mlkem768x25519-sha256, -curve25519-sha256,curve25519-sha256@libssh.org, -ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, -diffie-hellman-group-exchange-sha256, @@ -403,10 +533,10 @@ diff --color -ru a/sshd_config.5 b/sshd_config.5 -diffie-hellman-group14-sha256 -.Ed -.Pp - The list of available key exchange algorithms may also be obtained using + The list of supported key exchange algorithms may also be obtained using .Qq ssh -Q KexAlgorithms . .It Cm ListenAddress -@@ -1104,21 +1082,26 @@ +@@ -1184,21 +1152,26 @@ file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs @@ -437,7 +567,7 @@ diff --color -ru a/sshd_config.5 b/sshd_config.5 .Pp The algorithms that contain .Qq -etm -@@ -1161,15 +1144,6 @@ +@@ -1241,15 +1214,6 @@ umac-128-etm@openssh.com .El .Pp @@ -453,7 +583,7 @@ diff --color -ru a/sshd_config.5 b/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 @@ +@@ -1633,36 +1597,25 @@ The default is .Cm yes . .It Cm PubkeyAcceptedAlgorithms @@ -489,14 +619,24 @@ diff --color -ru a/sshd_config.5 b/sshd_config.5 -sk-ecdsa-sha2-nistp256-cert-v01@openssh.com, -rsa-sha2-512-cert-v01@openssh.com, -rsa-sha2-256-cert-v01@openssh.com, --ssh-rsa-cert-v01@openssh.com, -ssh-ed25519, -ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521, -sk-ssh-ed25519@openssh.com, -sk-ecdsa-sha2-nistp256@openssh.com, --rsa-sha2-512,rsa-sha2-256,ssh-rsa +-rsa-sha2-512,rsa-sha2-256 -.Ed +built-in openssh default set. .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q PubkeyAcceptedAlgorithms . +@@ -2131,7 +2084,9 @@ + .El + .Sh SEE ALSO + .Xr sftp-server 8 , +-.Xr sshd 8 ++.Xr sshd 8 , ++.Xr crypto-policies 7 , ++.Xr update-crypto-policies 8 + .Sh AUTHORS + .An -nosplit + OpenSSH is a derivative of the original and free diff --git a/SOURCES/openssh-8.0p1-openssl-evp.patch b/SOURCES/openssh-8.0p1-openssl-evp.patch deleted file mode 100644 index ade0bbb..0000000 --- a/SOURCES/openssh-8.0p1-openssl-evp.patch +++ /dev/null @@ -1,720 +0,0 @@ -From ed7ec0cdf577ffbb0b15145340cf51596ca3eb89 Mon Sep 17 00:00:00 2001 -From: Jakub Jelen -Date: Tue, 14 May 2019 10:45:45 +0200 -Subject: [PATCH] Use high-level OpenSSL API for signatures - ---- - digest-openssl.c | 16 ++++ - digest.h | 6 ++ - ssh-dss.c | 65 ++++++++++------ - ssh-ecdsa.c | 69 ++++++++++------- - ssh-rsa.c | 193 +++++++++-------------------------------------- - sshkey.c | 77 +++++++++++++++++++ - sshkey.h | 4 + - 7 files changed, 221 insertions(+), 209 deletions(-) - -diff --git a/digest-openssl.c b/digest-openssl.c -index da7ed72bc..6a21d8adb 100644 ---- a/digest-openssl.c -+++ b/digest-openssl.c -@@ -63,6 +63,22 @@ const struct ssh_digest digests[] = { - { -1, NULL, 0, NULL }, - }; - -+const EVP_MD * -+ssh_digest_to_md(int digest_type) -+{ -+ switch (digest_type) { -+ case SSH_DIGEST_SHA1: -+ return EVP_sha1(); -+ case SSH_DIGEST_SHA256: -+ return EVP_sha256(); -+ case SSH_DIGEST_SHA384: -+ return EVP_sha384(); -+ case SSH_DIGEST_SHA512: -+ return EVP_sha512(); -+ } -+ return NULL; -+} -+ - static const struct ssh_digest * - ssh_digest_by_alg(int alg) - { -diff --git a/digest.h b/digest.h -index 274574d0e..c7ceeb36f 100644 ---- a/digest.h -+++ b/digest.h -@@ -32,6 +32,12 @@ - struct sshbuf; - struct ssh_digest_ctx; - -+#ifdef WITH_OPENSSL -+#include -+/* Converts internal digest representation to the OpenSSL one */ -+const EVP_MD *ssh_digest_to_md(int digest_type); -+#endif -+ - /* Looks up a digest algorithm by name */ - int ssh_digest_alg_by_name(const char *name); - -diff --git a/ssh-dss.c b/ssh-dss.c -index a23c383dc..ea45e7275 100644 ---- a/ssh-dss.c -+++ b/ssh-dss.c -@@ -52,11 +52,15 @@ int - ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - const u_char *data, size_t datalen, u_int compat) - { -+ EVP_PKEY *pkey = NULL; - DSA_SIG *sig = NULL; - const BIGNUM *sig_r, *sig_s; -- u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; -- size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); -+ u_char sigblob[SIGBLOB_LEN]; -+ size_t rlen, slen; -+ int len; - struct sshbuf *b = NULL; -+ u_char *sigb = NULL; -+ const u_char *psig = NULL; - int ret = SSH_ERR_INVALID_ARGUMENT; - - if (lenp != NULL) -@@ -67,17 +71,24 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - if (key == NULL || key->dsa == NULL || - sshkey_type_plain(key->type) != KEY_DSA) - return SSH_ERR_INVALID_ARGUMENT; -- if (dlen == 0) -- return SSH_ERR_INTERNAL_ERROR; - -- if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, -- digest, sizeof(digest))) != 0) -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_DSA(pkey, key->dsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ ret = sshkey_calculate_signature(pkey, SSH_DIGEST_SHA1, &sigb, &len, -+ data, datalen); -+ EVP_PKEY_free(pkey); -+ if (ret < 0) { - goto out; -+ } - -- if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { -+ psig = sigb; -+ if ((sig = d2i_DSA_SIG(NULL, &psig, len)) == NULL) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -+ free(sigb); -+ sigb = NULL; - - DSA_SIG_get0(sig, &sig_r, &sig_s); - rlen = BN_num_bytes(sig_r); -@@ -110,7 +121,7 @@ ssh_dss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - *lenp = len; - ret = 0; - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - DSA_SIG_free(sig); - sshbuf_free(b); - return ret; -@@ -121,20 +132,20 @@ ssh_dss_verify(const struct sshkey *key, - const u_char *signature, size_t signaturelen, - const u_char *data, size_t datalen, u_int compat) - { -+ EVP_PKEY *pkey = NULL; - DSA_SIG *sig = NULL; - BIGNUM *sig_r = NULL, *sig_s = NULL; -- u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; -- size_t len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); -+ u_char *sigblob = NULL; -+ size_t len, slen; - int ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; - char *ktype = NULL; -+ u_char *sigb = NULL, *psig = NULL; - - if (key == NULL || key->dsa == NULL || - sshkey_type_plain(key->type) != KEY_DSA || - signature == NULL || signaturelen == 0) - return SSH_ERR_INVALID_ARGUMENT; -- if (dlen == 0) -- return SSH_ERR_INTERNAL_ERROR; - - /* fetch signature */ - if ((b = sshbuf_from(signature, signaturelen)) == NULL) -@@ -176,25 +187,31 @@ ssh_dss_verify(const struct sshkey *key, - } - sig_r = sig_s = NULL; /* transferred */ - -- /* sha1 the data */ -- if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, -- digest, sizeof(digest))) != 0) -+ if ((slen = i2d_DSA_SIG(sig, NULL)) == 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; -- -- switch (DSA_do_verify(digest, dlen, sig, key->dsa)) { -- case 1: -- ret = 0; -- break; -- case 0: -- ret = SSH_ERR_SIGNATURE_INVALID; -+ } -+ if ((sigb = malloc(slen)) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; - goto out; -- default: -+ } -+ psig = sigb; -+ if ((slen = i2d_DSA_SIG(sig, &psig)) == 0) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_DSA(pkey, key->dsa) != 1) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ ret = sshkey_verify_signature(pkey, SSH_DIGEST_SHA1, data, datalen, -+ sigb, slen); -+ EVP_PKEY_free(pkey); -+ - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - DSA_SIG_free(sig); - BN_clear_free(sig_r); - BN_clear_free(sig_s); -diff --git a/ssh-ecdsa.c b/ssh-ecdsa.c -index 599c7199d..b036796e8 100644 ---- a/ssh-ecdsa.c -+++ b/ssh-ecdsa.c -@@ -50,11 +50,13 @@ int - ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - const u_char *data, size_t datalen, u_int compat) - { -+ EVP_PKEY *pkey = NULL; - ECDSA_SIG *sig = NULL; -+ unsigned char *sigb = NULL; -+ const unsigned char *psig; - const BIGNUM *sig_r, *sig_s; - int hash_alg; -- u_char digest[SSH_DIGEST_MAX_LENGTH]; -- size_t len, dlen; -+ int len; - struct sshbuf *b = NULL, *bb = NULL; - int ret = SSH_ERR_INTERNAL_ERROR; - -@@ -67,18 +69,24 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - sshkey_type_plain(key->type) != KEY_ECDSA) - return SSH_ERR_INVALID_ARGUMENT; - -- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || -- (dlen = ssh_digest_bytes(hash_alg)) == 0) -+ if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) - return SSH_ERR_INTERNAL_ERROR; -- if ((ret = ssh_digest_memory(hash_alg, data, datalen, -- digest, sizeof(digest))) != 0) -+ -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data, -+ datalen); -+ EVP_PKEY_free(pkey); -+ if (ret < 0) { - goto out; -+ } - -- if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) { -+ psig = sigb; -+ if ((sig = d2i_ECDSA_SIG(NULL, &psig, len)) == NULL) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- - if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; -@@ -102,7 +110,7 @@ ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - *lenp = len; - ret = 0; - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - sshbuf_free(b); - sshbuf_free(bb); - ECDSA_SIG_free(sig); -@@ -115,22 +123,21 @@ ssh_ecdsa_verify(const struct sshkey *key, - const u_char *signature, size_t signaturelen, - const u_char *data, size_t datalen, u_int compat) - { -+ EVP_PKEY *pkey = NULL; - ECDSA_SIG *sig = NULL; - BIGNUM *sig_r = NULL, *sig_s = NULL; -- int hash_alg; -- u_char digest[SSH_DIGEST_MAX_LENGTH]; -- size_t dlen; -+ int hash_alg, len; - int ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL, *sigbuf = NULL; - char *ktype = NULL; -+ unsigned char *sigb = NULL, *psig = NULL; - - if (key == NULL || key->ecdsa == NULL || - sshkey_type_plain(key->type) != KEY_ECDSA || - signature == NULL || signaturelen == 0) - return SSH_ERR_INVALID_ARGUMENT; - -- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || -- (dlen = ssh_digest_bytes(hash_alg)) == 0) -+ if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) - return SSH_ERR_INTERNAL_ERROR; - - /* fetch signature */ -@@ -166,28 +173,36 @@ ssh_ecdsa_verify(const struct sshkey *key, - } - sig_r = sig_s = NULL; /* transferred */ - -- if (sshbuf_len(sigbuf) != 0) { -- ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; -+ /* Figure out the length */ -+ if ((len = i2d_ECDSA_SIG(sig, NULL)) == 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((sigb = malloc(len)) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if ((ret = ssh_digest_memory(hash_alg, data, datalen, -- digest, sizeof(digest))) != 0) -+ psig = sigb; -+ if ((len = i2d_ECDSA_SIG(sig, &psig)) == 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; -+ } - -- switch (ECDSA_do_verify(digest, dlen, sig, key->ecdsa)) { -- case 1: -- ret = 0; -- break; -- case 0: -- ret = SSH_ERR_SIGNATURE_INVALID; -+ if (sshbuf_len(sigbuf) != 0) { -+ ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; - goto out; -- default: -- ret = SSH_ERR_LIBCRYPTO_ERROR; -+ } -+ -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) { -+ ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -+ ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, sigb, len); -+ EVP_PKEY_free(pkey); - - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - sshbuf_free(sigbuf); - sshbuf_free(b); - ECDSA_SIG_free(sig); -diff --git a/ssh-rsa.c b/ssh-rsa.c -index 9b14f9a9a..8ef3a6aca 100644 ---- a/ssh-rsa.c -+++ b/ssh-rsa.c -@@ -37,7 +37,7 @@ - - #include "openbsd-compat/openssl-compat.h" - --static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); -+static int openssh_RSA_verify(int, const u_char *, size_t, u_char *, size_t, EVP_PKEY *); - - static const char * - rsa_hash_alg_ident(int hash_alg) -@@ -90,21 +90,6 @@ rsa_hash_id_from_keyname(const char *alg) - return -1; - } - --static int --rsa_hash_alg_nid(int type) --{ -- switch (type) { -- case SSH_DIGEST_SHA1: -- return NID_sha1; -- case SSH_DIGEST_SHA256: -- return NID_sha256; -- case SSH_DIGEST_SHA512: -- return NID_sha512; -- default: -- return -1; -- } --} -- - int - ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) - { -@@ -164,11 +149,10 @@ int - ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - const u_char *data, size_t datalen, const char *alg_ident) - { -- const BIGNUM *rsa_n; -- u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; -- size_t slen = 0; -- u_int dlen, len; -- int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; -+ EVP_PKEY *pkey = NULL; -+ u_char *sig = NULL; -+ int len, slen = 0; -+ int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; - - if (lenp != NULL) -@@ -180,33 +164,24 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - hash_alg = SSH_DIGEST_SHA1; - else - hash_alg = rsa_hash_id_from_keyname(alg_ident); -+ - if (key == NULL || key->rsa == NULL || hash_alg == -1 || - sshkey_type_plain(key->type) != KEY_RSA) - return SSH_ERR_INVALID_ARGUMENT; -- RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); -- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) -- return SSH_ERR_KEY_LENGTH; - slen = RSA_size(key->rsa); -- if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) -- return SSH_ERR_INVALID_ARGUMENT; -- -- /* hash the data */ -- nid = rsa_hash_alg_nid(hash_alg); -- if ((dlen = ssh_digest_bytes(hash_alg)) == 0) -- return SSH_ERR_INTERNAL_ERROR; -- if ((ret = ssh_digest_memory(hash_alg, data, datalen, -- digest, sizeof(digest))) != 0) -- goto out; -+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) -+ return SSH_ERR_KEY_LENGTH; - -- if ((sig = malloc(slen)) == NULL) { -- ret = SSH_ERR_ALLOC_FAIL; -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, -+ datalen); -+ EVP_PKEY_free(pkey); -+ if (ret < 0) { - goto out; - } - -- if (RSA_sign(nid, digest, dlen, sig, &len, key->rsa) != 1) { -- ret = SSH_ERR_LIBCRYPTO_ERROR; -- goto out; -- } - if (len < slen) { - size_t diff = slen - len; - memmove(sig + diff, sig, len); -@@ -215,6 +190,7 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - ret = SSH_ERR_INTERNAL_ERROR; - goto out; - } -+ - /* encode signature */ - if ((b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; -@@ -235,7 +211,6 @@ ssh_rsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, - *lenp = len; - ret = 0; - out: -- explicit_bzero(digest, sizeof(digest)); - freezero(sig, slen); - sshbuf_free(b); - return ret; -@@ -246,10 +221,10 @@ ssh_rsa_verify(const struct sshkey *key, - const u_char *sig, size_t siglen, const u_char *data, size_t datalen, - const char *alg) - { -- const BIGNUM *rsa_n; -+ EVP_PKEY *pkey = NULL; - char *sigtype = NULL; - int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; -- size_t len = 0, diff, modlen, dlen; -+ size_t len = 0, diff, modlen; - struct sshbuf *b = NULL; - u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; - -@@ -257,8 +232,7 @@ ssh_rsa_verify(const struct sshkey *key, - sshkey_type_plain(key->type) != KEY_RSA || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; -- RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); -- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) -+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) - return SSH_ERR_KEY_LENGTH; - - if ((b = sshbuf_from(sig, siglen)) == NULL) -@@ -310,16 +284,15 @@ ssh_rsa_verify(const struct sshkey *key, - explicit_bzero(sigblob, diff); - len = modlen; - } -- if ((dlen = ssh_digest_bytes(hash_alg)) == 0) { -- ret = SSH_ERR_INTERNAL_ERROR; -+ -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) { -+ ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if ((ret = ssh_digest_memory(hash_alg, data, datalen, -- digest, sizeof(digest))) != 0) -- goto out; -+ ret = openssh_RSA_verify(hash_alg, data, datalen, sigblob, len, pkey); -+ EVP_PKEY_free(pkey); - -- ret = openssh_RSA_verify(hash_alg, digest, dlen, sigblob, len, -- key->rsa); - out: - freezero(sigblob, len); - free(sigtype); -@@ -328,122 +301,26 @@ ssh_rsa_verify(const struct sshkey *key, - return ret; - } - --/* -- * See: -- * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ -- * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn -- */ -- --/* -- * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) -- * oiw(14) secsig(3) algorithms(2) 26 } -- */ --static const u_char id_sha1[] = { -- 0x30, 0x21, /* type Sequence, length 0x21 (33) */ -- 0x30, 0x09, /* type Sequence, length 0x09 */ -- 0x06, 0x05, /* type OID, length 0x05 */ -- 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ --}; -- --/* -- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html -- * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) -- * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) -- * id-sha256(1) } -- */ --static const u_char id_sha256[] = { -- 0x30, 0x31, /* type Sequence, length 0x31 (49) */ -- 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ -- 0x06, 0x09, /* type OID, length 0x09 */ -- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ --}; -- --/* -- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html -- * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) -- * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) -- * id-sha256(3) } -- */ --static const u_char id_sha512[] = { -- 0x30, 0x51, /* type Sequence, length 0x51 (81) */ -- 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ -- 0x06, 0x09, /* type OID, length 0x09 */ -- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ --}; -- - static int --rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) -+openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, -+ u_char *sigbuf, size_t siglen, EVP_PKEY *pkey) - { -- switch (hash_alg) { -- case SSH_DIGEST_SHA1: -- *oidp = id_sha1; -- *oidlenp = sizeof(id_sha1); -- break; -- case SSH_DIGEST_SHA256: -- *oidp = id_sha256; -- *oidlenp = sizeof(id_sha256); -- break; -- case SSH_DIGEST_SHA512: -- *oidp = id_sha512; -- *oidlenp = sizeof(id_sha512); -- break; -- default: -- return SSH_ERR_INVALID_ARGUMENT; -- } -- return 0; --} -+ size_t rsasize = 0; -+ const RSA *rsa; -+ int ret; - --static int --openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, -- u_char *sigbuf, size_t siglen, RSA *rsa) --{ -- size_t rsasize = 0, oidlen = 0, hlen = 0; -- int ret, len, oidmatch, hashmatch; -- const u_char *oid = NULL; -- u_char *decrypted = NULL; -- -- if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) -- return ret; -- ret = SSH_ERR_INTERNAL_ERROR; -- hlen = ssh_digest_bytes(hash_alg); -- if (hashlen != hlen) { -- ret = SSH_ERR_INVALID_ARGUMENT; -- goto done; -- } -+ rsa = EVP_PKEY_get0_RSA(pkey); - rsasize = RSA_size(rsa); - if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || - siglen == 0 || siglen > rsasize) { - ret = SSH_ERR_INVALID_ARGUMENT; - goto done; - } -- if ((decrypted = malloc(rsasize)) == NULL) { -- ret = SSH_ERR_ALLOC_FAIL; -- goto done; -- } -- if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, -- RSA_PKCS1_PADDING)) < 0) { -- ret = SSH_ERR_LIBCRYPTO_ERROR; -- goto done; -- } -- if (len < 0 || (size_t)len != hlen + oidlen) { -- ret = SSH_ERR_INVALID_FORMAT; -- goto done; -- } -- oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; -- hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; -- if (!oidmatch || !hashmatch) { -- ret = SSH_ERR_SIGNATURE_INVALID; -- goto done; -- } -- ret = 0; -+ -+ ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, -+ sigbuf, siglen); -+ - done: -- freezero(decrypted, rsasize); - return ret; - } - #endif /* WITH_OPENSSL */ -diff --git a/sshkey.c b/sshkey.c -index ad1957762..b95ed0b10 100644 ---- a/sshkey.c -+++ b/sshkey.c -@@ -358,6 +358,83 @@ sshkey_type_plain(int type) - } - - #ifdef WITH_OPENSSL -+int -+sshkey_calculate_signature(EVP_PKEY *pkey, int hash_alg, u_char **sigp, -+ int *lenp, const u_char *data, size_t datalen) -+{ -+ EVP_MD_CTX *ctx = NULL; -+ u_char *sig = NULL; -+ int ret, slen, len; -+ -+ if (sigp == NULL || lenp == NULL) { -+ return SSH_ERR_INVALID_ARGUMENT; -+ } -+ -+ slen = EVP_PKEY_size(pkey); -+ if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) -+ return SSH_ERR_INVALID_ARGUMENT; -+ -+ len = slen; -+ if ((sig = malloc(slen)) == NULL) { -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ -+ if ((ctx = EVP_MD_CTX_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto error; -+ } -+ if (EVP_SignInit_ex(ctx, ssh_digest_to_md(hash_alg), NULL) <= 0 || -+ EVP_SignUpdate(ctx, data, datalen) <= 0 || -+ EVP_SignFinal(ctx, sig, &len, pkey) <= 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto error; -+ } -+ -+ *sigp = sig; -+ *lenp = len; -+ /* Now owned by the caller */ -+ sig = NULL; -+ ret = 0; -+ -+error: -+ EVP_MD_CTX_free(ctx); -+ free(sig); -+ return ret; -+} -+ -+int -+sshkey_verify_signature(EVP_PKEY *pkey, int hash_alg, const u_char *data, -+ size_t datalen, u_char *sigbuf, int siglen) -+{ -+ EVP_MD_CTX *ctx = NULL; -+ int ret; -+ -+ if ((ctx = EVP_MD_CTX_new()) == NULL) { -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ if (EVP_VerifyInit_ex(ctx, ssh_digest_to_md(hash_alg), NULL) <= 0 || -+ EVP_VerifyUpdate(ctx, data, datalen) <= 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto done; -+ } -+ ret = EVP_VerifyFinal(ctx, sigbuf, siglen, pkey); -+ switch (ret) { -+ case 1: -+ ret = 0; -+ break; -+ case 0: -+ ret = SSH_ERR_SIGNATURE_INVALID; -+ break; -+ default: -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ break; -+ } -+ -+done: -+ EVP_MD_CTX_free(ctx); -+ return ret; -+} -+ - /* XXX: these are really begging for a table-driven approach */ - int - sshkey_curve_name_to_nid(const char *name) -diff --git a/sshkey.h b/sshkey.h -index a91e60436..270901a87 100644 ---- a/sshkey.h -+++ b/sshkey.h -@@ -179,6 +179,10 @@ const char *sshkey_ssh_name(const struct sshkey *); - const char *sshkey_ssh_name_plain(const struct sshkey *); - int sshkey_names_valid2(const char *, int); - char *sshkey_alg_list(int, int, int, char); -+int sshkey_calculate_signature(EVP_PKEY*, int, u_char **, -+ int *, const u_char *, size_t); -+int sshkey_verify_signature(EVP_PKEY *, int, const u_char *, -+ size_t, u_char *, int); - - int sshkey_from_blob(const u_char *, size_t, struct sshkey **); - int sshkey_fromb(struct sshbuf *, struct sshkey **); - diff --git a/SOURCES/openssh-8.0p1-pkcs11-uri.patch b/SOURCES/openssh-8.0p1-pkcs11-uri.patch index d908981..bdc4722 100644 --- a/SOURCES/openssh-8.0p1-pkcs11-uri.patch +++ b/SOURCES/openssh-8.0p1-pkcs11-uri.patch @@ -1,7 +1,7 @@ -diff -up openssh-8.6p1/configure.ac.pkcs11-uri openssh-8.6p1/configure.ac ---- openssh-8.6p1/configure.ac.pkcs11-uri 2021-05-06 11:35:55.101653187 +0200 -+++ openssh-8.6p1/configure.ac 2021-05-06 11:35:55.111653265 +0200 -@@ -1974,12 +1974,14 @@ AC_LINK_IFELSE( +diff -up openssh-9.6p1/configure.ac.pkcs11-uri openssh-9.6p1/configure.ac +--- openssh-9.6p1/configure.ac.pkcs11-uri 2024-01-12 14:25:25.228942213 +0100 ++++ openssh-9.6p1/configure.ac 2024-01-12 14:25:25.233942336 +0100 +@@ -2066,12 +2066,14 @@ AC_LINK_IFELSE( [AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).]) ]) @@ -16,7 +16,7 @@ diff -up openssh-8.6p1/configure.ac.pkcs11-uri openssh-8.6p1/configure.ac fi ] ) -@@ -2008,6 +2010,40 @@ AC_SEARCH_LIBS([dlopen], [dl]) +@@ -2095,6 +2097,40 @@ AC_SEARCH_LIBS([dlopen], [dl]) AC_CHECK_FUNCS([dlopen]) AC_CHECK_DECL([RTLD_NOW], [], [], [#include ]) @@ -57,7 +57,7 @@ diff -up openssh-8.6p1/configure.ac.pkcs11-uri openssh-8.6p1/configure.ac # IRIX has a const char return value for gai_strerror() AC_CHECK_FUNCS([gai_strerror], [ AC_DEFINE([HAVE_GAI_STRERROR]) -@@ -5564,6 +5600,7 @@ echo " BSD Auth support +@@ -5708,6 +5744,7 @@ echo " BSD Auth support echo " Random number source: $RAND_MSG" echo " Privsep sandbox style: $SANDBOX_STYLE" echo " PKCS#11 support: $enable_pkcs11" @@ -65,10 +65,10 @@ diff -up openssh-8.6p1/configure.ac.pkcs11-uri openssh-8.6p1/configure.ac echo " U2F/FIDO support: $enable_sk" echo "" -diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in ---- openssh-8.6p1/Makefile.in.pkcs11-uri 2021-05-06 11:35:55.054652818 +0200 -+++ openssh-8.6p1/Makefile.in 2021-05-06 11:58:16.895135904 +0200 -@@ -103,7 +103,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ +diff -up openssh-9.6p1/Makefile.in.pkcs11-uri openssh-9.6p1/Makefile.in +--- openssh-9.6p1/Makefile.in.pkcs11-uri 2024-01-12 14:25:25.204941622 +0100 ++++ openssh-9.6p1/Makefile.in 2024-01-12 14:25:25.233942336 +0100 +@@ -105,7 +105,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \ ssh-ed25519-sk.o ssh-rsa.o dh.o \ msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ @@ -76,8 +76,8 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in + ssh-pkcs11.o ssh-pkcs11-uri.o smult_curve25519_ref.o \ poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \ ssh-ed25519.o digest-openssl.o digest-libc.o \ - hmac.o sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \ -@@ -300,6 +300,8 @@ clean: regressclean + hmac.o ed25519.o hash.o \ +@@ -299,6 +299,8 @@ clean: regressclean rm -f regress/unittests/sshsig/test_sshsig$(EXEEXT) rm -f regress/unittests/utf8/*.o rm -f regress/unittests/utf8/test_utf8$(EXEEXT) @@ -86,16 +86,16 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in rm -f regress/misc/sk-dummy/*.o rm -f regress/misc/sk-dummy/*.lo rm -f regress/misc/sk-dummy/sk-dummy.so -@@ -337,6 +339,8 @@ distclean: regressclean +@@ -336,6 +338,8 @@ distclean: regressclean rm -f regress/unittests/sshsig/test_sshsig rm -f regress/unittests/utf8/*.o rm -f regress/unittests/utf8/test_utf8 + rm -f regress/unittests/pkcs11/*.o + rm -f regress/unittests/pkcs11/test_pkcs11 - (cd openbsd-compat && $(MAKE) distclean) - if test -d pkg ; then \ - rm -fr pkg ; \ -@@ -511,6 +515,7 @@ regress-prep: + rm -f regress/misc/sk-dummy/*.o + rm -f regress/misc/sk-dummy/*.lo + rm -f regress/misc/sk-dummy/sk-dummy.so +@@ -513,6 +517,7 @@ regress-prep: $(MKDIR_P) `pwd`/regress/unittests/sshkey $(MKDIR_P) `pwd`/regress/unittests/sshsig $(MKDIR_P) `pwd`/regress/unittests/utf8 @@ -103,9 +103,9 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in $(MKDIR_P) `pwd`/regress/misc/sk-dummy [ -f `pwd`/regress/Makefile ] || \ ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile -@@ -674,6 +679,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT +@@ -685,6 +690,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT regress/unittests/test_helper/libtest_helper.a \ - -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) + -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS) +UNITTESTS_TEST_PKCS11_OBJS=\ + regress/unittests/pkcs11/tests.o @@ -115,12 +115,12 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in + regress/unittests/test_helper/libtest_helper.a libssh.a + $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_PKCS11_OBJS) \ + regress/unittests/test_helper/libtest_helper.a \ -+ -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) ++ -lssh -lopenbsd-compat -lcrypto $(LIBS) + # These all need to be compiled -fPIC, so they are treated differently. SK_DUMMY_OBJS=\ regress/misc/sk-dummy/sk-dummy.lo \ -@@ -711,7 +726,8 @@ regress-unit-binaries: regress-prep $(RE +@@ -720,7 +735,8 @@ regress-unit-binaries: regress-prep $(RE regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ regress/unittests/sshkey/test_sshkey$(EXEEXT) \ regress/unittests/sshsig/test_sshsig$(EXEEXT) \ @@ -128,24 +128,12 @@ diff -up openssh-8.6p1/Makefile.in.pkcs11-uri openssh-8.6p1/Makefile.in + regress/unittests/utf8/test_utf8$(EXEEXT) \ + regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ - tests: file-tests t-exec interop-tests unit + tests: file-tests t-exec interop-tests extra-tests unit echo all tests passed -diff -up openssh-8.6p1/regress/agent-pkcs11.sh.pkcs11-uri openssh-8.6p1/regress/agent-pkcs11.sh ---- openssh-8.6p1/regress/agent-pkcs11.sh.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/regress/agent-pkcs11.sh 2021-05-06 11:35:55.112653273 +0200 -@@ -113,7 +113,7 @@ else - done - - trace "remove pkcs11 keys" -- echo ${TEST_SSH_PIN} | notty ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1 -+ ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1 - r=$? - if [ $r -ne 0 ]; then - fail "ssh-add -e failed: exit code $r" -diff -up openssh-8.6p1/regress/Makefile.pkcs11-uri openssh-8.6p1/regress/Makefile ---- openssh-8.6p1/regress/Makefile.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/regress/Makefile 2021-05-06 11:59:24.465658383 +0200 -@@ -119,7 +119,8 @@ CLEANFILES= *.core actual agent-key.* au +diff -up openssh-9.6p1/regress/Makefile.pkcs11-uri openssh-9.6p1/regress/Makefile +--- openssh-9.6p1/regress/Makefile.pkcs11-uri 2023-12-18 15:59:50.000000000 +0100 ++++ openssh-9.6p1/regress/Makefile 2024-01-12 14:25:25.233942336 +0100 +@@ -134,7 +134,8 @@ CLEANFILES= *.core actual agent-key.* au known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \ modpipe netcat no_identity_config \ pidfile putty.rsa2 ready regress.log remote_pid \ @@ -155,17 +143,21 @@ diff -up openssh-8.6p1/regress/Makefile.pkcs11-uri openssh-8.6p1/regress/Makefil rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \ scp-ssh-wrapper.scp setuid-allowed sftp-server.log \ sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \ -@@ -249,6 +250,7 @@ unit: +@@ -273,8 +274,9 @@ unit: V="" ; \ test "x${USE_VALGRIND}" = "x" || \ V=${.CURDIR}/valgrind-unit.sh ; \ -+ $$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \ - $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ - $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ +- $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ +- $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ ++ $$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \ ++ $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \ ++ $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ -d ${.CURDIR}/unittests/sshkey/testdata ; \ -diff -up openssh-8.6p1/regress/pkcs11.sh.pkcs11-uri openssh-8.6p1/regress/pkcs11.sh ---- openssh-8.6p1/regress/pkcs11.sh.pkcs11-uri 2021-05-06 11:35:55.112653273 +0200 -+++ openssh-8.6p1/regress/pkcs11.sh 2021-05-06 11:35:55.112653273 +0200 + $$V ${.OBJDIR}/unittests/sshsig/test_sshsig \ + -d ${.CURDIR}/unittests/sshsig/testdata ; \ +diff -up openssh-9.6p1/regress/pkcs11.sh.pkcs11-uri openssh-9.6p1/regress/pkcs11.sh +--- openssh-9.6p1/regress/pkcs11.sh.pkcs11-uri 2024-01-12 14:25:25.233942336 +0100 ++++ openssh-9.6p1/regress/pkcs11.sh 2024-01-12 14:25:25.233942336 +0100 @@ -0,0 +1,349 @@ +# +# Copyright (c) 2017 Red Hat @@ -516,21 +508,21 @@ diff -up openssh-8.6p1/regress/pkcs11.sh.pkcs11-uri openssh-8.6p1/regress/pkcs11 + trace "kill agent" + ${SSHAGENT} -k > /dev/null +fi -diff -up openssh-8.6p1/regress/unittests/Makefile.pkcs11-uri openssh-8.6p1/regress/unittests/Makefile ---- openssh-8.6p1/regress/unittests/Makefile.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/regress/unittests/Makefile 2021-05-06 11:35:55.112653273 +0200 -@@ -2,6 +2,6 @@ +diff -up openssh-9.6p1/regress/unittests/Makefile.pkcs11-uri openssh-9.6p1/regress/unittests/Makefile +--- openssh-9.6p1/regress/unittests/Makefile.pkcs11-uri 2023-12-18 15:59:50.000000000 +0100 ++++ openssh-9.6p1/regress/unittests/Makefile 2024-01-12 14:25:25.233942336 +0100 +@@ -1,6 +1,6 @@ + # $OpenBSD: Makefile,v 1.13 2023/09/24 08:14:13 claudio Exp $ - REGRESS_FAIL_EARLY?= yes SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion -SUBDIR+=authopt misc sshsig +SUBDIR+=authopt misc sshsig pkcs11 .include -diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1/regress/unittests/pkcs11/tests.c ---- openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri 2021-05-06 11:35:55.112653273 +0200 -+++ openssh-8.6p1/regress/unittests/pkcs11/tests.c 2021-05-06 11:35:55.112653273 +0200 -@@ -0,0 +1,337 @@ +diff -up openssh-9.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-9.6p1/regress/unittests/pkcs11/tests.c +--- openssh-9.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri 2024-01-12 14:25:25.233942336 +0100 ++++ openssh-9.6p1/regress/unittests/pkcs11/tests.c 2024-01-12 14:25:25.233942336 +0100 +@@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -559,7 +551,7 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 +#include "sshbuf.h" +#include "ssh-pkcs11-uri.h" + -+#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL) ++#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL) + +/* prototypes are not public -- specify them here internally for tests */ +struct sshbuf *percent_encode(const char *, size_t, char *); @@ -592,6 +584,10 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 + ASSERT_STRING_EQ(a->lib_manuf, b->lib_manuf); + else /* both should be null */ + ASSERT_PTR_EQ(a->lib_manuf, b->lib_manuf); ++ if (b->serial != NULL) ++ ASSERT_STRING_EQ(a->serial, b->serial); ++ else /* both should be null */ ++ ASSERT_PTR_EQ(a->serial, b->serial); +} + +void @@ -626,7 +622,7 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 + +struct pkcs11_uri * +compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf, -+ char *manuf, char *module_path, char *object, char *pin) ++ char *manuf, char *serial, char *module_path, char *object, char *pin) +{ + struct pkcs11_uri *uri = pkcs11_uri_init(); + if (id_len > 0) { @@ -637,6 +633,7 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 + uri->token = token; + uri->lib_manuf = lib_manuf; + uri->manuf = manuf; ++ uri->serial = serial; + uri->object = object; + uri->pin = pin; + return uri; @@ -647,47 +644,49 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 +{ + /* path arguments */ + check_parse("pkcs11:id=%01", -+ compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + check_parse("pkcs11:id=%00%01", -+ compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + check_parse("pkcs11:token=SSH%20Keys", -+ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL, NULL)); + check_parse("pkcs11:library-manufacturer=OpenSC", -+ compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL, NULL)); + check_parse("pkcs11:manufacturer=piv_II", -+ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL)); ++ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL, NULL)); ++ check_parse("pkcs11:serial=IamSerial", ++ compose_uri(NULL, 0, NULL, NULL, NULL, "IamSerial", NULL, NULL, NULL)); + check_parse("pkcs11:object=SIGN%20Key", -+ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "SIGN Key", NULL)); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, "SIGN Key", NULL)); + /* query arguments */ + check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so", -+ compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); + check_parse("pkcs11:?pin-value=123456", -+ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, "123456")); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, "123456")); + + /* combinations */ + /* ID SHOULD be percent encoded */ + check_parse("pkcs11:token=SSH%20Key;id=0", -+ compose_uri("0", 1, "SSH Key", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("0", 1, "SSH Key", NULL, NULL, NULL, NULL, NULL, NULL)); + check_parse( + "pkcs11:manufacturer=CAC?module-path=/usr/lib64/p11-kit-proxy.so", -+ compose_uri(NULL, 0, NULL, NULL, "CAC", ++ compose_uri(NULL, 0, NULL, NULL, "CAC", NULL, + "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); + check_parse( + "pkcs11:object=RSA%20Key?module-path=/usr/lib64/pkcs11/opencryptoki.so", -+ compose_uri(NULL, 0, NULL, NULL, NULL, ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, + "/usr/lib64/pkcs11/opencryptoki.so", "RSA Key", NULL)); + check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so&pin-value=123456", -+ compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, "123456")); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, "123456")); + + /* empty path component matches everything */ + check_parse("pkcs11:", EMPTY_URI); + + /* empty string is a valid to match against (and different from NULL) */ + check_parse("pkcs11:token=", -+ compose_uri(NULL, 0, "", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "", NULL, NULL, NULL, NULL, NULL, NULL)); + /* Percent character needs to be percent-encoded */ + check_parse("pkcs11:token=%25", -+ compose_uri(NULL, 0, "%", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "%", NULL, NULL, NULL, NULL, NULL, NULL)); +} + +static void @@ -699,7 +698,7 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 + check_parse_rv("pkcs11:id=%ZZ", EMPTY_URI, -1); + /* Space MUST be percent encoded -- XXX not enforced yet */ + check_parse("pkcs11:token=SSH Keys", -+ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL, NULL)); + /* MUST NOT contain duplicate attributes of the same name */ + check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1); + /* MUST NOT contain duplicate attributes of the same name */ @@ -730,29 +729,31 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 +{ + /* path arguments */ + check_gen("pkcs11:id=%01", -+ compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + check_gen("pkcs11:id=%00%01", -+ compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + check_gen("pkcs11:token=SSH%20Keys", /* space must be percent encoded */ -+ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL, NULL)); + /* library-manufacturer is not implmented now */ + /*check_gen("pkcs11:library-manufacturer=OpenSC", -+ compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL));*/ ++ compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL, NULL));*/ + check_gen("pkcs11:manufacturer=piv_II", -+ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL)); ++ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL, NULL)); ++ check_gen("pkcs11:serial=IamSerial", ++ compose_uri(NULL, 0, NULL, NULL, NULL, "IamSerial", NULL, NULL, NULL)); + check_gen("pkcs11:object=RSA%20Key", -+ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "RSA Key", NULL)); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, "RSA Key", NULL)); + /* query arguments */ + check_gen("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so", -+ compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); + + /* combinations */ + check_gen("pkcs11:id=%02;token=SSH%20Keys", -+ compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL, NULL, NULL, NULL)); + check_gen("pkcs11:id=%EE%02?module-path=/usr/lib64/p11-kit-proxy.so", -+ compose_uri("\xEE\x02", 2, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); ++ compose_uri("\xEE\x02", 2, NULL, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); + check_gen("pkcs11:object=Encryption%20Key;manufacturer=piv_II", -+ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, "Encryption Key", NULL)); ++ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, "Encryption Key", NULL)); + + /* empty path component matches everything */ + check_gen("pkcs11:", EMPTY_URI); @@ -868,26 +869,31 @@ diff -up openssh-8.6p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.6p1 + test_parse_invalid(); + test_generate_valid(); +} -diff -up openssh-8.6p1/ssh-add.c.pkcs11-uri openssh-8.6p1/ssh-add.c ---- openssh-8.6p1/ssh-add.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-add.c 2021-05-06 11:35:55.112653273 +0200 -@@ -68,6 +68,7 @@ - #include "digest.h" +diff -up openssh-9.6p1/ssh-add.c.pkcs11-uri openssh-9.6p1/ssh-add.c +--- openssh-9.6p1/ssh-add.c.pkcs11-uri 2023-12-18 15:59:50.000000000 +0100 ++++ openssh-9.6p1/ssh-add.c 2024-01-12 14:25:25.233942336 +0100 +@@ -69,6 +69,7 @@ #include "ssh-sk.h" #include "sk-api.h" + #include "hostfile.h" +#include "ssh-pkcs11-uri.h" /* argv0 */ extern char *__progname; -@@ -229,6 +230,32 @@ delete_all(int agent_fd, int qflag) +@@ -240,6 +241,38 @@ delete_all(int agent_fd, int qflag) return ret; } +#ifdef ENABLE_PKCS11 -+static int update_card(int, int, const char *, int, char *); ++static int ++update_card(int agent_fd, int add, const char *id, int qflag, ++ int key_only, int cert_only, ++ struct dest_constraint **dest_constraints, size_t ndest_constraints, ++ struct sshkey **certs, size_t ncerts, char *pin); + +int -+update_pkcs11_uri(int agent_fd, int adding, const char *pkcs11_uri, int qflag) ++update_pkcs11_uri(int agent_fd, int adding, const char *pkcs11_uri, int qflag, ++ struct dest_constraint **dest_constraints, size_t ndest_constraints) +{ + char *pin = NULL; + struct pkcs11_uri *uri; @@ -905,58 +911,63 @@ diff -up openssh-8.6p1/ssh-add.c.pkcs11-uri openssh-8.6p1/ssh-add.c + } + pkcs11_uri_cleanup(uri); + -+ return update_card(agent_fd, adding, pkcs11_uri, qflag, pin); ++ return update_card(agent_fd, adding, pkcs11_uri, qflag, 1, 0, ++ dest_constraints, ndest_constraints, NULL, 0, pin); +} +#endif + static int - add_file(int agent_fd, const char *filename, int key_only, int qflag, - const char *skprovider) -@@ -445,12 +472,11 @@ add_file(int agent_fd, const char *filen - } - - static int --update_card(int agent_fd, int add, const char *id, int qflag) -+update_card(int agent_fd, int add, const char *id, int qflag, char *pin) + add_file(int agent_fd, const char *filename, int key_only, int cert_only, + int qflag, const char *skprovider, +@@ -460,15 +489,14 @@ static int + update_card(int agent_fd, int add, const char *id, int qflag, + int key_only, int cert_only, + struct dest_constraint **dest_constraints, size_t ndest_constraints, +- struct sshkey **certs, size_t ncerts) ++ struct sshkey **certs, size_t ncerts, char *pin) { - char *pin = NULL; int r, ret = -1; + if (key_only) + ncerts = 0; + - if (add) { + if (add && pin == NULL) { if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN)) == NULL) return -1; -@@ -630,6 +656,13 @@ static int - do_file(int agent_fd, int deleting, int key_only, char *file, int qflag, - const char *skprovider) +@@ -656,6 +684,14 @@ do_file(int agent_fd, int deleting, int + char *file, int qflag, const char *skprovider, + struct dest_constraint **dest_constraints, size_t ndest_constraints) { +#ifdef ENABLE_PKCS11 + if (strlen(file) >= strlen(PKCS11_URI_SCHEME) && + strncmp(file, PKCS11_URI_SCHEME, + strlen(PKCS11_URI_SCHEME)) == 0) { -+ return update_pkcs11_uri(agent_fd, !deleting, file, qflag); ++ return update_pkcs11_uri(agent_fd, !deleting, file, qflag, ++ dest_constraints, ndest_constraints); + } +#endif if (deleting) { - if (delete_file(agent_fd, file, key_only, qflag) == -1) - return -1; -@@ -813,7 +846,7 @@ main(int argc, char **argv) - } - if (pkcs11provider != NULL) { + if (delete_file(agent_fd, file, key_only, + cert_only, qflag) == -1) +@@ -999,7 +1035,7 @@ main(int argc, char **argv) if (update_card(agent_fd, !deleting, pkcs11provider, -- qflag) == -1) -+ qflag, NULL) == -1) + qflag, key_only, cert_only, + dest_constraints, ndest_constraints, +- certs, ncerts) == -1) ++ certs, ncerts, NULL) == -1) ret = 1; goto done; } -diff -up openssh-8.6p1/ssh-agent.c.pkcs11-uri openssh-8.6p1/ssh-agent.c ---- openssh-8.6p1/ssh-agent.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-agent.c 2021-05-06 11:35:55.113653281 +0200 -@@ -847,10 +847,72 @@ no_identities(SocketEntry *e) +diff -up openssh-9.6p1/ssh-agent.c.pkcs11-uri openssh-9.6p1/ssh-agent.c +--- openssh-9.6p1/ssh-agent.c.pkcs11-uri 2023-12-18 15:59:50.000000000 +0100 ++++ openssh-9.6p1/ssh-agent.c 2024-01-12 14:25:25.234942360 +0100 +@@ -1549,10 +1549,74 @@ add_p11_identity(struct sshkey *key, cha + idtab->nentries++; } - #ifdef ENABLE_PKCS11 +static char * +sanitize_pkcs11_provider(const char *provider) +{ @@ -967,6 +978,8 @@ diff -up openssh-8.6p1/ssh-agent.c.pkcs11-uri openssh-8.6p1/ssh-agent.c + if (provider == NULL) + return NULL; + ++ memset(canonical_provider, 0, sizeof(canonical_provider)); ++ + if (strlen(provider) >= strlen(PKCS11_URI_SCHEME) && + strncmp(provider, PKCS11_URI_SCHEME, + strlen(PKCS11_URI_SCHEME)) == 0) { @@ -1027,25 +1040,23 @@ diff -up openssh-8.6p1/ssh-agent.c.pkcs11-uri openssh-8.6p1/ssh-agent.c char **comments = NULL; int r, i, count = 0, success = 0, confirm = 0; u_int seconds = 0; -@@ -869,33 +931,28 @@ process_add_smartcard_key(SocketEntry *e - error_f("failed to parse constraints"); +@@ -1581,25 +1643,18 @@ process_add_smartcard_key(SocketEntry *e + "providers is disabled", provider); goto send; } - if (realpath(provider, canonical_provider) == NULL) { - verbose("failed PKCS#11 add of \"%.100s\": realpath: %s", - provider, strerror(errno)); -- goto send; -- } -- if (match_pattern_list(canonical_provider, allowed_providers, 0) != 1) { -- verbose("refusing PKCS#11 add of \"%.100s\": " -- "provider not allowed", canonical_provider); -+ + sane_uri = sanitize_pkcs11_provider(provider); + if (sane_uri == NULL) goto send; - } +- if (match_pattern_list(canonical_provider, allowed_providers, 0) != 1) { +- verbose("refusing PKCS#11 add of \"%.100s\": " +- "provider not allowed", canonical_provider); +- goto send; +- } - debug_f("add %.100s", canonical_provider); -+ if (lifetime && !death) death = monotime() + lifetime; @@ -1053,31 +1064,38 @@ diff -up openssh-8.6p1/ssh-agent.c.pkcs11-uri openssh-8.6p1/ssh-agent.c + debug_f("add %.100s", sane_uri); + count = pkcs11_add_provider(sane_uri, pin, &keys, &comments); for (i = 0; i < count; i++) { - k = keys[i]; - if (lookup_identity(k) == NULL) { - id = xcalloc(1, sizeof(Identity)); - id->key = k; - keys[i] = NULL; /* transferred */ -- id->provider = xstrdup(canonical_provider); -+ id->provider = xstrdup(sane_uri); - if (*comments[i] != '\0') { - id->comment = comments[i]; - comments[i] = NULL; /* transferred */ - } else { -- id->comment = xstrdup(canonical_provider); -+ id->comment = xstrdup(sane_uri); - } - id->death = death; - id->confirm = confirm; -@@ -910,6 +967,7 @@ process_add_smartcard_key(SocketEntry *e + if (comments[i] == NULL || comments[i][0] == '\0') { + free(comments[i]); +- comments[i] = xstrdup(canonical_provider); ++ comments[i] = xstrdup(sane_uri); + } + for (j = 0; j < ncerts; j++) { + if (!sshkey_is_cert(certs[j])) +@@ -1609,13 +1664,13 @@ process_add_smartcard_key(SocketEntry *e + if (pkcs11_make_cert(keys[i], certs[j], &k) != 0) + continue; + add_p11_identity(k, xstrdup(comments[i]), +- canonical_provider, death, confirm, ++ sane_uri, death, confirm, + dest_constraints, ndest_constraints); + success = 1; + } + if (!cert_only && lookup_identity(keys[i]) == NULL) { + add_p11_identity(keys[i], comments[i], +- canonical_provider, death, confirm, ++ sane_uri, death, confirm, + dest_constraints, ndest_constraints); + keys[i] = NULL; /* transferred */ + comments[i] = NULL; /* transferred */ +@@ -1628,6 +1683,7 @@ process_add_smartcard_key(SocketEntry *e send: free(pin); free(provider); + free(sane_uri); free(keys); free(comments); - send_status(e, success); -@@ -918,7 +976,7 @@ send: + free_dest_constraints(dest_constraints, ndest_constraints); +@@ -1640,7 +1696,7 @@ send: static void process_remove_smartcard_key(SocketEntry *e) { @@ -1086,7 +1104,7 @@ diff -up openssh-8.6p1/ssh-agent.c.pkcs11-uri openssh-8.6p1/ssh-agent.c int r, success = 0; Identity *id, *nxt; -@@ -930,30 +988,29 @@ process_remove_smartcard_key(SocketEntry +@@ -1652,30 +1708,29 @@ process_remove_smartcard_key(SocketEntry } free(pin); @@ -1123,10 +1141,10 @@ diff -up openssh-8.6p1/ssh-agent.c.pkcs11-uri openssh-8.6p1/ssh-agent.c send_status(e, success); } #endif /* ENABLE_PKCS11 */ -diff -up openssh-8.6p1/ssh_config.5.pkcs11-uri openssh-8.6p1/ssh_config.5 ---- openssh-8.6p1/ssh_config.5.pkcs11-uri 2021-05-06 11:35:55.061652873 +0200 -+++ openssh-8.6p1/ssh_config.5 2021-05-06 11:35:55.116653304 +0200 -@@ -1063,6 +1063,21 @@ may also be used in conjunction with +diff -up openssh-9.6p1/ssh_config.5.pkcs11-uri openssh-9.6p1/ssh_config.5 +--- openssh-9.6p1/ssh_config.5.pkcs11-uri 2024-01-12 14:25:25.208941721 +0100 ++++ openssh-9.6p1/ssh_config.5 2024-01-12 14:25:25.234942360 +0100 +@@ -1216,6 +1216,21 @@ may also be used in conjunction with .Cm CertificateFile in order to provide any certificate also needed for authentication with the identity. @@ -1148,10 +1166,10 @@ diff -up openssh-8.6p1/ssh_config.5.pkcs11-uri openssh-8.6p1/ssh_config.5 .It Cm IgnoreUnknown Specifies a pattern-list of unknown options to be ignored if they are encountered in configuration parsing. -diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c ---- openssh-8.6p1/ssh.c.pkcs11-uri 2021-05-06 11:35:55.060652865 +0200 -+++ openssh-8.6p1/ssh.c 2021-05-06 12:00:07.129988275 +0200 -@@ -843,6 +843,14 @@ main(int ac, char **av) +diff -up openssh-9.6p1/ssh.c.pkcs11-uri openssh-9.6p1/ssh.c +--- openssh-9.6p1/ssh.c.pkcs11-uri 2024-01-12 14:25:25.208941721 +0100 ++++ openssh-9.6p1/ssh.c 2024-01-12 14:25:25.234942360 +0100 +@@ -882,6 +882,14 @@ main(int ac, char **av) options.gss_deleg_creds = 1; break; case 'i': @@ -1166,7 +1184,7 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c p = tilde_expand_filename(optarg, getuid()); if (stat(p, &st) == -1) fprintf(stderr, "Warning: Identity file %s " -@@ -1695,6 +1703,7 @@ main(int ac, char **av) +@@ -1784,6 +1792,7 @@ main(int ac, char **av) #ifdef ENABLE_PKCS11 (void)pkcs11_del_provider(options.pkcs11_provider); #endif @@ -1174,7 +1192,7 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c skip_connect: exit_status = ssh_session2(ssh, cinfo); -@@ -2211,6 +2220,45 @@ ssh_session2(struct ssh *ssh, const stru +@@ -2307,6 +2316,45 @@ ssh_session2(struct ssh *ssh, const stru options.escape_char : SSH_ESCAPECHAR_NONE, id); } @@ -1220,7 +1238,7 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c /* Loads all IdentityFile and CertificateFile keys */ static void load_public_identity_files(const struct ssh_conn_info *cinfo) -@@ -2225,11 +2273,6 @@ load_public_identity_files(const struct +@@ -2321,11 +2369,6 @@ load_public_identity_files(const struct char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; @@ -1232,7 +1250,7 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c n_ids = n_certs = 0; memset(identity_files, 0, sizeof(identity_files)); -@@ -2242,33 +2285,46 @@ load_public_identity_files(const struct +@@ -2338,33 +2381,46 @@ load_public_identity_files(const struct sizeof(certificate_file_userprovided)); #ifdef ENABLE_PKCS11 @@ -1298,10 +1316,10 @@ diff -up openssh-8.6p1/ssh.c.pkcs11-uri openssh-8.6p1/ssh.c filename = default_client_percent_dollar_expand(cp, cinfo); free(cp); check_load(sshkey_load_public(filename, &public, NULL), -diff -up openssh-8.6p1/ssh-keygen.c.pkcs11-uri openssh-8.6p1/ssh-keygen.c ---- openssh-8.6p1/ssh-keygen.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-keygen.c 2021-05-06 11:35:55.114653289 +0200 -@@ -860,8 +860,11 @@ do_download(struct passwd *pw) +diff -up openssh-9.6p1/ssh-keygen.c.pkcs11-uri openssh-9.6p1/ssh-keygen.c +--- openssh-9.6p1/ssh-keygen.c.pkcs11-uri 2023-12-18 15:59:50.000000000 +0100 ++++ openssh-9.6p1/ssh-keygen.c 2024-01-12 14:25:25.234942360 +0100 +@@ -862,8 +862,11 @@ do_download(struct passwd *pw) free(fp); } else { (void) sshkey_write(keys[i], stdout); /* XXX check */ @@ -1315,19 +1333,19 @@ diff -up openssh-8.6p1/ssh-keygen.c.pkcs11-uri openssh-8.6p1/ssh-keygen.c } free(comments[i]); sshkey_free(keys[i]); -diff -up openssh-8.6p1/ssh-pkcs11-client.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-client.c ---- openssh-8.6p1/ssh-pkcs11-client.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-pkcs11-client.c 2021-05-06 11:35:55.114653289 +0200 -@@ -323,6 +323,8 @@ pkcs11_add_provider(char *name, char *pi - u_int nkeys, i; +diff -up openssh-9.6p1/ssh-pkcs11-client.c.pkcs11-uri openssh-9.6p1/ssh-pkcs11-client.c +--- openssh-9.6p1/ssh-pkcs11-client.c.pkcs11-uri 2023-12-18 15:59:50.000000000 +0100 ++++ openssh-9.6p1/ssh-pkcs11-client.c 2024-01-12 14:25:25.234942360 +0100 +@@ -592,6 +592,8 @@ pkcs11_add_provider(char *name, char *pi struct sshbuf *msg; + struct helper *helper; + debug_f("called, name = %s", name); + - if (fd < 0 && pkcs11_start_helper() < 0) - return (-1); - -@@ -342,6 +344,7 @@ pkcs11_add_provider(char *name, char *pi + if ((helper = helper_by_provider(name)) == NULL && + (helper = pkcs11_start_helper(name)) == NULL) + return -1; +@@ -612,6 +614,7 @@ pkcs11_add_provider(char *name, char *pi *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); if (labelsp) *labelsp = xcalloc(nkeys, sizeof(char *)); @@ -1335,9 +1353,17 @@ diff -up openssh-8.6p1/ssh-pkcs11-client.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-c for (i = 0; i < nkeys; i++) { /* XXX clean up properly instead of fatal() */ if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 || -diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c ---- openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-pkcs11.c 2021-05-06 11:35:55.115653297 +0200 +diff -up openssh-9.9p1/ssh-pkcs11.c.xxx openssh-9.9p1/ssh-pkcs11.c +--- openssh-9.9p1/ssh-pkcs11.c.xxx 2024-10-09 11:56:35.890126144 +0200 ++++ openssh-9.9p1/ssh-pkcs11.c 2024-10-09 11:56:48.528459585 +0200 +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #define CRYPTOKI_COMPAT + #include "pkcs11.h" @@ -55,8 +55,8 @@ struct pkcs11_slotinfo { int logged_in; }; @@ -1521,10 +1547,10 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c struct pkcs11_provider *p; + int rv = -1; + char *provider_uri = pkcs11_uri_get(uri); ++ ++ debug3_f("called with provider %s", provider_uri); - if ((p = pkcs11_provider_lookup(provider_id)) != NULL) { -+ debug3_f("called with provider %s", provider_uri); -+ + if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) { TAILQ_REMOVE(&pkcs11_providers, p, next); pkcs11_provider_finalize(p); @@ -1538,9 +1564,9 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c } static RSA_METHOD *rsa_method; -@@ -195,6 +283,55 @@ static EC_KEY_METHOD *ec_key_method; +@@ -195,6 +286,60 @@ static EC_KEY_METHOD *ec_key_method; static int ec_key_idx = 0; - #endif + #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ +/* + * This can't be in the ssh-pkcs11-uri, becase we can not depend on @@ -1555,13 +1581,17 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + + /* sanity - is it a RSA key with associated app_data? */ + switch (key->type) { -+ case KEY_RSA: -+ k11 = RSA_get_ex_data(key->rsa, rsa_idx); ++ case KEY_RSA: { ++ const RSA *rsa = EVP_PKEY_get0_RSA(key->pkey); ++ k11 = RSA_get_ex_data(rsa, rsa_idx); + break; ++ } +#ifdef HAVE_EC_KEY_METHOD_NEW -+ case KEY_ECDSA: -+ k11 = EC_KEY_get_ex_data(key->ecdsa, ec_key_idx); ++ case KEY_ECDSA: { ++ const EC_KEY * ecdsa = EVP_PKEY_get0_EC_KEY(key->pkey); ++ k11 = EC_KEY_get_ex_data(ecdsa, ec_key_idx); + break; ++ } +#endif + default: + error("Unknown key type %d", key->type); @@ -1580,6 +1610,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + uri.module_path = k11->provider->module->module_path; + uri.lib_manuf = k11->provider->module->info.manufacturerID; + uri.manuf = k11->provider->module->slotinfo[k11->slotidx].token.manufacturerID; ++ uri.serial = k11->provider->module->slotinfo[k11->slotidx].token.serialNumber; + + p = pkcs11_uri_get(&uri); + /* do not cleanup -- we do not allocate here, only reference */ @@ -1594,7 +1625,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c /* release a wrapped object */ static void pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, -@@ -208,6 +345,7 @@ pkcs11_k11_free(void *parent, void *ptr, +@@ -208,6 +349,7 @@ pkcs11_k11_free(void *parent, void *ptr, if (k11->provider) pkcs11_provider_unref(k11->provider); free(k11->keyid); @@ -1602,7 +1633,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c free(k11); } -@@ -222,8 +360,8 @@ pkcs11_find(struct pkcs11_provider *p, C +@@ -222,8 +364,8 @@ pkcs11_find(struct pkcs11_provider *p, C CK_RV rv; int ret = -1; @@ -1613,9 +1644,12 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); return (-1); -@@ -262,12 +400,12 @@ pkcs11_login_slot(struct pkcs11_provider +@@ -260,14 +402,14 @@ pkcs11_login_slot(struct pkcs11_provider + if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH) + verbose("Deferring PIN entry to reader keypad."); else { - snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", +- snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", ++ snprintf(prompt, sizeof(prompt), "Enter PIN for '%.32s': ", si->token.label); - if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) { + if ((pin = read_passphrase(prompt, RP_ALLOW_EOF|RP_ALLOW_STDIN)) == NULL) { @@ -1628,7 +1662,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c (pin != NULL) ? strlen(pin) : 0); if (pin != NULL) freezero(pin, strlen(pin)); -@@ -297,13 +435,14 @@ pkcs11_login_slot(struct pkcs11_provider +@@ -297,13 +439,14 @@ pkcs11_login_slot(struct pkcs11_provider static int pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type) { @@ -1645,7 +1679,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c } -@@ -319,13 +458,14 @@ pkcs11_check_obj_bool_attrib(struct pkcs +@@ -319,13 +462,14 @@ pkcs11_check_obj_bool_attrib(struct pkcs *val = 0; @@ -1663,7 +1697,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c attr.type = type; attr.pValue = &flag; -@@ -356,13 +496,14 @@ pkcs11_get_key(struct pkcs11_key *k11, C +@@ -356,13 +500,14 @@ pkcs11_get_key(struct pkcs11_key *k11, C int always_auth = 0; int did_login = 0; @@ -1681,7 +1715,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { if (pkcs11_login(k11, CKU_USER) < 0) { -@@ -439,8 +580,8 @@ pkcs11_rsa_private_encrypt(int flen, con +@@ -439,8 +584,8 @@ pkcs11_rsa_private_encrypt(int flen, con return (-1); } @@ -1692,7 +1726,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c tlen = RSA_size(rsa); /* XXX handle CKR_BUFFER_TOO_SMALL */ -@@ -484,7 +625,7 @@ pkcs11_rsa_start_wrapper(void) +@@ -484,7 +629,7 @@ pkcs11_rsa_start_wrapper(void) /* redirect private key operations for rsa key to pkcs11 token */ static int pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, @@ -1701,7 +1735,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c { struct pkcs11_key *k11; -@@ -502,6 +643,12 @@ pkcs11_rsa_wrap(struct pkcs11_provider * +@@ -502,6 +647,12 @@ pkcs11_rsa_wrap(struct pkcs11_provider * memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); } @@ -1711,10 +1745,10 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + k11->label[label_attrib->ulValueLen] = 0; + } + - RSA_set_method(rsa, rsa_method); - RSA_set_ex_data(rsa, rsa_idx, k11); - return (0); -@@ -532,8 +679,8 @@ ecdsa_do_sign(const unsigned char *dgst, + if (RSA_set_method(rsa, rsa_method) != 1) + fatal_f("RSA_set_method failed"); + if (RSA_set_ex_data(rsa, rsa_idx, k11) != 1) +@@ -532,8 +683,8 @@ ecdsa_do_sign(const unsigned char *dgst, return (NULL); } @@ -1725,7 +1759,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c siglen = ECDSA_size(ec); sig = xmalloc(siglen); -@@ -598,7 +745,7 @@ pkcs11_ecdsa_start_wrapper(void) +@@ -598,7 +749,7 @@ pkcs11_ecdsa_start_wrapper(void) static int pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, @@ -1734,20 +1768,30 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c { struct pkcs11_key *k11; -@@ -614,6 +761,12 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider - k11->keyid = xmalloc(k11->keyid_len); - memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); - +@@ -615,6 +766,12 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider + k11->keyid = xmalloc(k11->keyid_len); + memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); + } + if (label_attrib->ulValueLen > 0 ) { + k11->label = xmalloc(label_attrib->ulValueLen+1); + memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen); + k11->label[label_attrib->ulValueLen] = 0; + } + - EC_KEY_set_method(ec, ec_key_method); - EC_KEY_set_ex_data(ec, ec_key_idx, k11); + if (EC_KEY_set_method(ec, ec_key_method) != 1) + fatal_f("EC_KEY_set_method failed"); + if (EC_KEY_set_ex_data(ec, ec_key_idx, k11) != 1) +@@ -622,7 +779,8 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider + } + #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ -@@ -650,8 +803,8 @@ pkcs11_open_session(struct pkcs11_provid +-/* remove trailing spaces */ ++/* remove trailing spaces. Note, that this does NOT guarantee the buffer ++ * will be null terminated if there are no trailing spaces! */ + static char * + rmspace(u_char *buf, size_t len) + { +@@ -654,8 +812,8 @@ pkcs11_open_session(struct pkcs11_provid CK_SESSION_HANDLE session; int login_required, ret; @@ -1758,7 +1802,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c login_required = si->token.flags & CKF_LOGIN_REQUIRED; -@@ -661,9 +814,9 @@ pkcs11_open_session(struct pkcs11_provid +@@ -665,9 +823,9 @@ pkcs11_open_session(struct pkcs11_provid error("pin required"); return (-SSH_PKCS11_ERR_PIN_REQUIRED); } @@ -1770,7 +1814,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c return (-1); } if (login_required && pin != NULL && strlen(pin) != 0) { -@@ -699,7 +852,8 @@ static struct sshkey * +@@ -703,7 +861,8 @@ static struct sshkey * pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj) { @@ -1780,7 +1824,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -713,14 +867,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -717,14 +876,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ memset(&key_attr, 0, sizeof(key_attr)); key_attr[0].type = CKA_ID; @@ -1801,7 +1845,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); return (NULL); -@@ -731,19 +886,19 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -735,19 +895,19 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ * ensure that none of the others are zero length. * XXX assumes CKA_ID is always first. */ @@ -1825,7 +1869,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); goto fail; -@@ -755,8 +910,8 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -759,8 +919,8 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ goto fail; } @@ -1836,7 +1880,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (group == NULL) { ossl_error("d2i_ECPKParameters failed"); goto fail; -@@ -767,13 +922,13 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -771,13 +931,13 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ goto fail; } @@ -1853,7 +1897,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (octet == NULL) { ossl_error("d2i_ASN1_OCTET_STRING failed"); goto fail; -@@ -790,7 +945,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ +@@ -794,7 +954,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ goto fail; } @@ -1862,8 +1906,8 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto fail; key = sshkey_new(KEY_UNSPEC); -@@ -806,7 +961,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ - ec = NULL; /* now owned by key */ +@@ -810,7 +970,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ + key->flags |= SSHKEY_FLAG_EXT; fail: - for (i = 0; i < 3; i++) @@ -1871,7 +1915,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c free(key_attr[i].pValue); if (ec) EC_KEY_free(ec); -@@ -823,7 +978,8 @@ static struct sshkey * +@@ -827,7 +987,8 @@ static struct sshkey * pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj) { @@ -1881,7 +1925,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -834,14 +990,15 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -838,14 +999,15 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr memset(&key_attr, 0, sizeof(key_attr)); key_attr[0].type = CKA_ID; @@ -1902,7 +1946,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); return (NULL); -@@ -852,19 +1009,19 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -856,19 +1018,19 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr * ensure that none of the others are zero length. * XXX assumes CKA_ID is always first. */ @@ -1926,7 +1970,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); goto fail; -@@ -876,8 +1033,8 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -880,8 +1042,8 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr goto fail; } @@ -1937,7 +1981,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rsa_n == NULL || rsa_e == NULL) { error("BN_bin2bn failed"); goto fail; -@@ -886,7 +1043,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr +@@ -890,7 +1052,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr fatal_f("set key"); rsa_n = rsa_e = NULL; /* transferred */ @@ -1946,8 +1990,8 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto fail; key = sshkey_new(KEY_UNSPEC); -@@ -901,7 +1058,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr - rsa = NULL; /* now owned by key */ +@@ -905,7 +1067,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr + key->flags |= SSHKEY_FLAG_EXT; fail: - for (i = 0; i < 3; i++) @@ -1955,7 +1999,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c free(key_attr[i].pValue); RSA_free(rsa); -@@ -912,7 +1069,8 @@ static int +@@ -916,7 +1078,8 @@ static int pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp) { @@ -1965,7 +2009,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -936,14 +1094,15 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -940,14 +1103,15 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p memset(&cert_attr, 0, sizeof(cert_attr)); cert_attr[0].type = CKA_ID; @@ -1986,7 +2030,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); return -1; -@@ -955,18 +1114,19 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -959,18 +1123,19 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p * XXX assumes CKA_ID is always first. */ if (cert_attr[1].ulValueLen == 0 || @@ -2009,7 +2053,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c if (rv != CKR_OK) { error("C_GetAttributeValue failed: %lu", rv); goto out; -@@ -980,8 +1140,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -984,8 +1149,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p subject = xstrdup("invalid subject"); X509_NAME_free(x509_name); @@ -2020,7 +2064,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c error("d2i_x509 failed"); goto out; } -@@ -1001,7 +1161,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -1005,7 +1170,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p goto out; } @@ -2029,7 +2073,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto out; key = sshkey_new(KEY_UNSPEC); -@@ -1031,7 +1191,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -1035,7 +1200,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p goto out; } @@ -2038,7 +2082,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto out; key = sshkey_new(KEY_UNSPEC); -@@ -1051,7 +1211,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p +@@ -1055,7 +1220,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p goto out; } out: @@ -2047,7 +2091,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c free(cert_attr[i].pValue); X509_free(x509); RSA_free(rsa); -@@ -1102,11 +1262,12 @@ note_key(struct pkcs11_provider *p, CK_U +@@ -1106,11 +1271,12 @@ note_key(struct pkcs11_provider *p, CK_U */ static int pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, @@ -2062,7 +2106,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -1123,10 +1284,23 @@ pkcs11_fetch_certs(struct pkcs11_provide +@@ -1127,10 +1293,23 @@ pkcs11_fetch_certs(struct pkcs11_provide key_attr[0].pValue = &key_class; key_attr[0].ulValueLen = sizeof(key_class); @@ -2080,16 +2124,16 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + key_attr[nattr].ulValueLen = strlen(uri->object); + nattr++; + } -+ -+ session = p->module->slotinfo[slotidx].session; -+ f = p->module->function_list; - rv = f->C_FindObjectsInit(session, key_attr, 1); ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; ++ + rv = f->C_FindObjectsInit(session, key_attr, nattr); if (rv != CKR_OK) { error("C_FindObjectsInit failed: %lu", rv); goto fail; -@@ -1207,11 +1381,12 @@ fail: +@@ -1211,11 +1390,12 @@ fail: */ static int pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, @@ -2104,7 +2148,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c CK_SESSION_HANDLE session; CK_FUNCTION_LIST *f = NULL; CK_RV rv; -@@ -1227,10 +1402,23 @@ pkcs11_fetch_keys(struct pkcs11_provider +@@ -1231,10 +1411,23 @@ pkcs11_fetch_keys(struct pkcs11_provider key_attr[0].pValue = &key_class; key_attr[0].ulValueLen = sizeof(key_class); @@ -2122,16 +2166,16 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + key_attr[nattr].ulValueLen = strlen(uri->object); + nattr++; + } - -- rv = f->C_FindObjectsInit(session, key_attr, 1); ++ + session = p->module->slotinfo[slotidx].session; + f = p->module->function_list; -+ + +- rv = f->C_FindObjectsInit(session, key_attr, 1); + rv = f->C_FindObjectsInit(session, key_attr, nattr); if (rv != CKR_OK) { error("C_FindObjectsInit failed: %lu", rv); goto fail; -@@ -1499,16 +1690,10 @@ pkcs11_ecdsa_generate_private_key(struct +@@ -1503,16 +1696,10 @@ pkcs11_ecdsa_generate_private_key(struct } #endif /* WITH_PKCS11_KEYGEN */ @@ -2150,7 +2194,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c int ret = -1; struct pkcs11_provider *p = NULL; void *handle = NULL; -@@ -1517,164 +1699,298 @@ pkcs11_register_provider(char *provider_ +@@ -1521,162 +1708,309 @@ pkcs11_register_provider(char *provider_ CK_FUNCTION_LIST *f = NULL; CK_TOKEN_INFO *token; CK_ULONG i; @@ -2158,28 +2202,35 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + struct pkcs11_module *m = NULL; - if (providerp == NULL) +- goto fail; +- *providerp = NULL; +- +- if (keyp != NULL) +- *keyp = NULL; +- if (labelsp != NULL) +- *labelsp = NULL; + /* if no provider specified, fallback to p11-kit */ + if (uri->module_path == NULL) { +#ifdef PKCS11_DEFAULT_PROVIDER + provider_module = strdup(PKCS11_DEFAULT_PROVIDER); +#else + error_f("No module path provided"); - goto fail; -- *providerp = NULL; ++ goto fail; +#endif + } else { + provider_module = strdup(uri->module_path); + } - -- if (keyp != NULL) -- *keyp = NULL; -- if (labelsp != NULL) -- *labelsp = NULL; + p = xcalloc(1, sizeof(*p)); + p->name = pkcs11_uri_get(uri); - if (pkcs11_provider_lookup(provider_id) != NULL) { - debug_f("provider already registered: %s", provider_id); ++ if (lib_contains_symbol(provider_module, "C_GetFunctionList") != 0) { ++ error("provider %s is not a PKCS11 library", provider_module); + goto fail; + } +- if (lib_contains_symbol(provider_id, "C_GetFunctionList") != 0) { +- error("provider %s is not a PKCS11 library", provider_id); - goto fail; + if ((m = pkcs11_provider_lookup_module(provider_module)) != NULL + && m->valid) { @@ -2206,14 +2257,11 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + error("dlopen %s failed: %s", provider_module, dlerror()); goto fail; } - if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) { - error("dlsym(C_GetFunctionList) failed: %s", dlerror()); - goto fail; - } + if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) + fatal("dlsym(C_GetFunctionList) failed: %s", dlerror()); - p = xcalloc(1, sizeof(*p)); - p->name = xstrdup(provider_id); - p->handle = handle; -+ + p->module->handle = handle; /* setup the pkcs11 callbacks */ if ((rv = (*getfunctionlist)(&f)) != CKR_OK) { @@ -2236,28 +2284,28 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c error("C_GetInfo for provider %s failed: %lu", - provider_id, rv); + provider_module, rv); -+ goto fail; -+ } -+ rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID)); -+ if (uri->lib_manuf != NULL && -+ strcmp(uri->lib_manuf, m->info.manufacturerID)) { -+ debug_f("Skipping provider %s not matching library_manufacturer", -+ m->info.manufacturerID); goto fail; } -- rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID)); -- rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription)); -+ rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription)); - debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d" - " libraryDescription <%s> libraryVersion %d.%d", +- debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d" +- " libraryDescription <%.*s> libraryVersion %d.%d", - provider_id, -- p->info.manufacturerID, +- RMSPACE(p->info.manufacturerID), - p->info.cryptokiVersion.major, - p->info.cryptokiVersion.minor, -- p->info.libraryDescription, +- RMSPACE(p->info.libraryDescription), - p->info.libraryVersion.major, - p->info.libraryVersion.minor); - if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) { ++ rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID)); ++ if (uri->lib_manuf != NULL && ++ strncmp(uri->lib_manuf, m->info.manufacturerID, 32)) { ++ debug_f("Skipping provider %s not matching library_manufacturer", ++ m->info.manufacturerID); ++ goto fail; ++ } ++ rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription)); ++ debug("provider %s: manufacturerID <%.32s> cryptokiVersion %d.%d" ++ " libraryDescription <%.32s> libraryVersion %d.%d", + provider_module, + m->info.manufacturerID, + m->info.cryptokiVersion.major, @@ -2288,12 +2336,12 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c goto fail; } - p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo)); ++ m->slotinfo = xcalloc(m->nslots, sizeof(struct pkcs11_slotinfo)); p->valid = 1; - nkeys = 0; - for (i = 0; i < p->nslots; i++) { - token = &p->slotinfo[i].token; - if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) -+ m->slotinfo = xcalloc(m->nslots, sizeof(struct pkcs11_slotinfo)); + m->valid = 1; + for (i = 0; i < m->nslots; i++) { + token = &m->slotinfo[i].token; @@ -2310,20 +2358,25 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + token->flags = 0; continue; } - rmspace(token->label, sizeof(token->label)); - rmspace(token->manufacturerID, sizeof(token->manufacturerID)); - rmspace(token->model, sizeof(token->model)); - rmspace(token->serialNumber, sizeof(token->serialNumber)); + debug("provider %s slot %lu: label <%.*s> " + "manufacturerID <%.*s> model <%.*s> serial <%.*s> " + "flags 0x%lx", +- provider_id, (unsigned long)i, ++ provider_module, (unsigned long)i, + RMSPACE(token->label), RMSPACE(token->manufacturerID), + RMSPACE(token->model), RMSPACE(token->serialNumber), + token->flags); + } + m->module_path = provider_module; + provider_module = NULL; + -+ /* insert unconditionally -- remove if there will be no keys later */ ++ /* now owned by caller */ ++ *providerp = p; ++ + TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); + p->refcount++; /* add to provider list */ -+ *providerp = p; -+ return 0; + ++ return 0; +fail: + if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) + error("C_Finalize for provider %s failed: %lu", @@ -2339,7 +2392,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + } + if (handle) + dlclose(handle); -+ return ret; ++ return (ret); +} + +/* @@ -2382,29 +2435,35 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + continue; + } + if (uri->token != NULL && -+ strcmp(token->label, uri->token) != 0) { -+ debug2_f("ignoring token not matching label (%s) " ++ strncmp(token->label, uri->token, 32) != 0) { ++ debug2_f("ignoring token not matching label (%.32s) " + "specified by PKCS#11 URI in slot %lu", + token->label, (unsigned long)i); + continue; + } + if (uri->manuf != NULL && -+ strcmp(token->manufacturerID, uri->manuf) != 0) { ++ strncmp(token->manufacturerID, uri->manuf, 32) != 0) { + debug2_f("ignoring token not matching requrested " -+ "manufacturerID (%s) specified by PKCS#11 URI in " ++ "manufacturerID (%.32s) specified by PKCS#11 URI in " + "slot %lu", token->manufacturerID, (unsigned long)i); + continue; + } - debug("provider %s slot %lu: label <%s> manufacturerID <%s> " - "model <%s> serial <%s> flags 0x%lx", -- provider_id, (unsigned long)i, ++ if (uri->serial != NULL && ++ strncmp(token->serialNumber, uri->serial, 16) != 0) { ++ debug2_f("ignoring token not matching requrested " ++ "serialNumber (%s) specified by PKCS#11 URI in " ++ "slot %lu", token->serialNumber, (unsigned long)i); ++ continue; ++ } ++ debug("provider %s slot %lu: label <%.32s> manufacturerID <%.32s> " ++ "model <%.16s> serial <%.16s> flags 0x%lx", + provider_uri, (unsigned long)i, - token->label, token->manufacturerID, token->model, - token->serialNumber, token->flags); ++ token->label, token->manufacturerID, token->model, ++ token->serialNumber, token->flags); /* - * open session, login with pin and retrieve public - * keys (if keyp is provided) -+ * open session if not yet openend, login with pin and ++ * open session if not yet opened, login with pin and + * retrieve public keys (if keyp is provided) */ - if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 || @@ -2436,7 +2495,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c + pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); + } + if (nkeys == 0 && uri->object != NULL) { -+ debug3_f("No keys found. Retrying without label (%s) ", ++ debug3_f("No keys found. Retrying without label (%.32s) ", + uri->object); + /* Try once more without the label filter */ + char *label = uri->object; @@ -2465,8 +2524,8 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c - free(p->slotlist); - free(p->slotinfo); - free(p); -+ TAILQ_REMOVE(&pkcs11_providers, p, next); -+ pkcs11_provider_unref(p); ++ TAILQ_REMOVE(&pkcs11_providers, p, next); ++ pkcs11_provider_unref(p); } - if (handle) - dlclose(handle); @@ -2524,7 +2583,7 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c /* no keys found or some other error, de-register provider */ if (nkeys <= 0 && p != NULL) { -@@ -1683,7 +1999,37 @@ pkcs11_add_provider(char *provider_id, c +@@ -1685,7 +2019,37 @@ pkcs11_add_provider(char *provider_id, c pkcs11_provider_unref(p); } if (nkeys == 0) @@ -2563,9 +2622,9 @@ diff -up openssh-8.6p1/ssh-pkcs11.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11.c return (nkeys); } -diff -up openssh-8.6p1/ssh-pkcs11.h.pkcs11-uri openssh-8.6p1/ssh-pkcs11.h ---- openssh-8.6p1/ssh-pkcs11.h.pkcs11-uri 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/ssh-pkcs11.h 2021-05-06 11:35:55.115653297 +0200 +diff -up openssh-9.6p1/ssh-pkcs11.h.pkcs11-uri openssh-9.6p1/ssh-pkcs11.h +--- openssh-9.6p1/ssh-pkcs11.h.pkcs11-uri 2023-12-18 15:59:50.000000000 +0100 ++++ openssh-9.6p1/ssh-pkcs11.h 2024-01-12 14:25:25.235942385 +0100 @@ -22,10 +22,14 @@ #define SSH_PKCS11_ERR_PIN_REQUIRED 4 #define SSH_PKCS11_ERR_PIN_LOCKED 5 @@ -2581,10 +2640,10 @@ diff -up openssh-8.6p1/ssh-pkcs11.h.pkcs11-uri openssh-8.6p1/ssh-pkcs11.h #ifdef WITH_PKCS11_KEYGEN struct sshkey * pkcs11_gakp(char *, char *, unsigned int, char *, unsigned int, -diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri.c ---- openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri 2021-05-06 11:35:55.114653289 +0200 -+++ openssh-8.6p1/ssh-pkcs11-uri.c 2021-05-06 11:35:55.114653289 +0200 -@@ -0,0 +1,419 @@ +diff -up openssh-9.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-9.6p1/ssh-pkcs11-uri.c +--- openssh-9.6p1/ssh-pkcs11-uri.c.pkcs11-uri 2024-01-12 14:25:25.235942385 +0100 ++++ openssh-9.6p1/ssh-pkcs11-uri.c 2024-01-12 14:25:25.235942385 +0100 +@@ -0,0 +1,437 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -2627,13 +2686,14 @@ diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri. +#define PKCS11_URI_OBJECT "object" +#define PKCS11_URI_LIB_MANUF "library-manufacturer" +#define PKCS11_URI_MANUF "manufacturer" ++#define PKCS11_URI_SERIAL "serial" +#define PKCS11_URI_MODULE_PATH "module-path" +#define PKCS11_URI_PIN_VALUE "pin-value" + +/* Keyword tokens. */ +typedef enum { -+ pId, pToken, pObject, pLibraryManufacturer, pManufacturer, pModulePath, -+ pPinValue, pBadOption ++ pId, pToken, pObject, pLibraryManufacturer, pManufacturer, pSerial, ++ pModulePath, pPinValue, pBadOption +} pkcs11uriOpCodes; + +/* Textual representation of the tokens. */ @@ -2646,6 +2706,7 @@ diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri. + { PKCS11_URI_OBJECT, pObject }, + { PKCS11_URI_LIB_MANUF, pLibraryManufacturer }, + { PKCS11_URI_MANUF, pManufacturer }, ++ { PKCS11_URI_SERIAL, pSerial }, + { PKCS11_URI_MODULE_PATH, pModulePath }, + { PKCS11_URI_PIN_VALUE, pPinValue }, + { NULL, pBadOption } @@ -2804,6 +2865,16 @@ diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri. + goto err; + } + ++ /* Write serial */ ++ if (uri->serial) { ++ struct sshbuf *serial = percent_encode(uri->serial, ++ strlen(uri->serial), PKCS11_URI_WHITELIST); ++ path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR, ++ PKCS11_URI_SERIAL, serial); ++ if (path == NULL) ++ goto err; ++ } ++ + /* Write module_path */ + if (uri->module_path) { + struct sshbuf *module = percent_encode(uri->module_path, @@ -2846,6 +2917,7 @@ diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri. + free(pkcs11->object); + free(pkcs11->lib_manuf); + free(pkcs11->manuf); ++ free(pkcs11->serial); + if (pkcs11->pin) + freezero(pkcs11->pin, strlen(pkcs11->pin)); + free(pkcs11); @@ -2941,6 +3013,11 @@ diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri. + charptr = &pkcs11->manuf; + goto parse_string; + ++ case pSerial: ++ /* CK_TOKEN_INFO -> serialNumber */ ++ charptr = &pkcs11->serial; ++ goto parse_string; ++ + case pLibraryManufacturer: + /* CK_INFO -> manufacturerID */ + charptr = &pkcs11->lib_manuf; @@ -3004,10 +3081,10 @@ diff -up openssh-8.6p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri. +} + +#endif /* ENABLE_PKCS11 */ -diff -up openssh-8.6p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri.h ---- openssh-8.6p1/ssh-pkcs11-uri.h.pkcs11-uri 2021-05-06 11:35:55.114653289 +0200 -+++ openssh-8.6p1/ssh-pkcs11-uri.h 2021-05-06 11:35:55.114653289 +0200 -@@ -0,0 +1,42 @@ +diff -up openssh-9.6p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-9.6p1/ssh-pkcs11-uri.h +--- openssh-9.6p1/ssh-pkcs11-uri.h.pkcs11-uri 2024-01-12 14:25:25.235942385 +0100 ++++ openssh-9.6p1/ssh-pkcs11-uri.h 2024-01-12 14:25:25.235942385 +0100 +@@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -3039,6 +3116,7 @@ diff -up openssh-8.6p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-8.6p1/ssh-pkcs11-uri. + char *object; + char *lib_manuf; + char *manuf; ++ char *serial; + /* query */ + char *module_path; + char *pin; /* Only parsed, but not printed */ diff --git a/SOURCES/openssh-8.0p1-preserve-pam-errors.patch b/SOURCES/openssh-8.0p1-preserve-pam-errors.patch index dbdbe93..b7ab965 100644 --- a/SOURCES/openssh-8.0p1-preserve-pam-errors.patch +++ b/SOURCES/openssh-8.0p1-preserve-pam-errors.patch @@ -27,16 +27,15 @@ diff -up openssh-8.0p1/auth-pam.c.preserve-pam-errors openssh-8.0p1/auth-pam.c else if (sshpam_maxtries_reached) ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer); else -@@ -856,10 +862,12 @@ sshpam_query(void *ctx, char **name, cha - plen++; +@@ -856,9 +862,11 @@ sshpam_query(void *ctx, char **name, cha free(msg); break; -+ case PAM_USER_UNKNOWN: -+ case PAM_PERM_DENIED: case PAM_ACCT_EXPIRED: + sshpam_account_status = 0; + /* FALLTHROUGH */ case PAM_MAXTRIES: ++ case PAM_USER_UNKNOWN: ++ case PAM_PERM_DENIED: - if (type == PAM_ACCT_EXPIRED) - sshpam_account_status = 0; if (type == PAM_MAXTRIES) diff --git a/SOURCES/openssh-8.7p1-CVE-2023-25136.patch b/SOURCES/openssh-8.7p1-CVE-2023-25136.patch deleted file mode 100644 index ca661ee..0000000 --- a/SOURCES/openssh-8.7p1-CVE-2023-25136.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff --git a/compat.c b/compat.c -index 46dfe3a9c2e..478a9403eea 100644 ---- a/compat.c -+++ b/compat.c -@@ -190,26 +190,26 @@ compat_pkalg_proposal(struct ssh *ssh, char *pkalg_prop) - char * - compat_kex_proposal(struct ssh *ssh, char *p) - { -- char *cp = NULL; -+ char *cp = NULL, *cp2 = NULL; - - if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0) - return xstrdup(p); - debug2_f("original KEX proposal: %s", p); - if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0) -- if ((p = match_filter_denylist(p, -+ if ((cp = match_filter_denylist(p, - "curve25519-sha256@libssh.org")) == NULL) - fatal("match_filter_denylist failed"); - if ((ssh->compat & SSH_OLD_DHGEX) != 0) { -- cp = p; -- if ((p = match_filter_denylist(p, -+ if ((cp2 = match_filter_denylist(cp ? cp : p, - "diffie-hellman-group-exchange-sha256," - "diffie-hellman-group-exchange-sha1")) == NULL) - fatal("match_filter_denylist failed"); - free(cp); -+ cp = cp2; - } -- debug2_f("compat KEX proposal: %s", p); -- if (*p == '\0') -+ if (cp == NULL || *cp == '\0') - fatal("No supported key exchange algorithms found"); -- return p; -+ debug2_f("compat KEX proposal: %s", cp); -+ return cp; - } - diff --git a/SOURCES/openssh-8.7p1-UTC-time-parse.patch b/SOURCES/openssh-8.7p1-UTC-time-parse.patch deleted file mode 100644 index 1fd953d..0000000 --- a/SOURCES/openssh-8.7p1-UTC-time-parse.patch +++ /dev/null @@ -1,323 +0,0 @@ -diff --git a/misc.c b/misc.c -index a8e87430..f2135803 100644 ---- a/misc.c -+++ b/misc.c -@@ -2399,15 +2399,26 @@ parse_absolute_time(const char *s, uint64_t *tp) - struct tm tm; - time_t tt; - char buf[32], *fmt; -+ const char *cp; -+ size_t l; -+ int is_utc = 0; - - *tp = 0; - -+ l = strlen(s); -+ if (l > 1 && strcasecmp(s + l - 1, "Z") == 0) { -+ is_utc = 1; -+ l--; -+ } else if (l > 3 && strcasecmp(s + l - 3, "UTC") == 0) { -+ is_utc = 1; -+ l -= 3; -+ } - /* - * POSIX strptime says "The application shall ensure that there - * is white-space or other non-alphanumeric characters between - * any two conversion specifications" so arrange things this way. - */ -- switch (strlen(s)) { -+ switch (l) { - case 8: /* YYYYMMDD */ - fmt = "%Y-%m-%d"; - snprintf(buf, sizeof(buf), "%.4s-%.2s-%.2s", s, s + 4, s + 6); -@@ -2427,10 +2438,15 @@ parse_absolute_time(const char *s, uint64_t *tp) - } - - memset(&tm, 0, sizeof(tm)); -- if (strptime(buf, fmt, &tm) == NULL) -- return SSH_ERR_INVALID_FORMAT; -- if ((tt = mktime(&tm)) < 0) -+ if ((cp = strptime(buf, fmt, &tm)) == NULL || *cp != '\0') - return SSH_ERR_INVALID_FORMAT; -+ if (is_utc) { -+ if ((tt = timegm(&tm)) < 0) -+ return SSH_ERR_INVALID_FORMAT; -+ } else { -+ if ((tt = mktime(&tm)) < 0) -+ return SSH_ERR_INVALID_FORMAT; -+ } - /* success */ - *tp = (uint64_t)tt; - return 0; -diff --git a/regress/unittests/misc/test_convtime.c b/regress/unittests/misc/test_convtime.c -index ef6fd77d..4794dbd9 100644 ---- a/regress/unittests/misc/test_convtime.c -+++ b/regress/unittests/misc/test_convtime.c -@@ -20,6 +20,7 @@ - - #include "log.h" - #include "misc.h" -+#include "ssherr.h" - - void test_convtime(void); - -@@ -27,6 +28,7 @@ void - test_convtime(void) - { - char buf[1024]; -+ uint64_t t; - - TEST_START("misc_convtime"); - ASSERT_INT_EQ(convtime("0"), 0); -@@ -56,4 +58,64 @@ test_convtime(void) - ASSERT_INT_EQ(convtime("3550w5d3h14m8s"), -1); - #endif - TEST_DONE(); -+ -+ /* XXX timezones/DST make verification of this tricky */ -+ /* XXX maybe setenv TZ and tzset() to make it unambiguous? */ -+ TEST_START("misc_parse_absolute_time"); -+ ASSERT_INT_EQ(parse_absolute_time("20000101", &t), 0); -+ ASSERT_INT_EQ(parse_absolute_time("200001011223", &t), 0); -+ ASSERT_INT_EQ(parse_absolute_time("20000101122345", &t), 0); -+ -+ /* forced UTC TZ */ -+ ASSERT_INT_EQ(parse_absolute_time("20000101Z", &t), 0); -+ ASSERT_U64_EQ(t, 946684800); -+ ASSERT_INT_EQ(parse_absolute_time("200001011223Z", &t), 0); -+ ASSERT_U64_EQ(t, 946729380); -+ ASSERT_INT_EQ(parse_absolute_time("20000101122345Z", &t), 0); -+ ASSERT_U64_EQ(t, 946729425); -+ ASSERT_INT_EQ(parse_absolute_time("20000101UTC", &t), 0); -+ ASSERT_U64_EQ(t, 946684800); -+ ASSERT_INT_EQ(parse_absolute_time("200001011223UTC", &t), 0); -+ ASSERT_U64_EQ(t, 946729380); -+ ASSERT_INT_EQ(parse_absolute_time("20000101122345UTC", &t), 0); -+ ASSERT_U64_EQ(t, 946729425); -+ -+ /* Bad month */ -+ ASSERT_INT_EQ(parse_absolute_time("20001301", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("20000001", &t), -+ SSH_ERR_INVALID_FORMAT); -+ /* Incomplete */ -+ ASSERT_INT_EQ(parse_absolute_time("2", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("2000", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("20000", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("200001", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("2000010", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("200001010", &t), -+ SSH_ERR_INVALID_FORMAT); -+ /* Bad day, hour, minute, second */ -+ ASSERT_INT_EQ(parse_absolute_time("20000199", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("200001019900", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("200001010099", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("20000101000099", &t), -+ SSH_ERR_INVALID_FORMAT); -+ /* Invalid TZ specifier */ -+ ASSERT_INT_EQ(parse_absolute_time("20000101ZZ", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("20000101PDT", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("20000101U", &t), -+ SSH_ERR_INVALID_FORMAT); -+ ASSERT_INT_EQ(parse_absolute_time("20000101UTCUTC", &t), -+ SSH_ERR_INVALID_FORMAT); -+ -+ TEST_DONE(); - } -diff --git a/ssh-keygen.1 b/ssh-keygen.1 -index 5f429813..6aeab1cb 100644 ---- a/ssh-keygen.1 -+++ b/ssh-keygen.1 -@@ -511,8 +511,11 @@ Print the full public key to standard output after signature verification. - .It Cm verify-time Ns = Ns Ar timestamp - Specifies a time to use when validating signatures instead of the current - time. --The time may be specified as a date in YYYYMMDD format or a time --in YYYYMMDDHHMM[SS] format. -+The time may be specified as a date or time in the YYYYMMDD[Z] or -+in YYYYMMDDHHMM[SS][Z] formats. -+Dates and times will be interpreted in the current system time zone unless -+suffixed with a Z character, which causes them to be interpreted in the -+UTC time zone. - .El - .Pp - The -@@ -603,31 +606,67 @@ A validity interval may consist of a single time, indicating that the - certificate is valid beginning now and expiring at that time, or may consist - of two times separated by a colon to indicate an explicit time interval. - .Pp --The start time may be specified as the string -+The start time may be specified as: -+.Bl -bullet -compact -+.It -+The string - .Dq always --to indicate the certificate has no specified start time, --a date in YYYYMMDD format, a time in YYYYMMDDHHMM[SS] format, --a relative time (to the current time) consisting of a minus sign followed by --an interval in the format described in the -+to indicate the certificate has no specified start time. -+.It -+A date or time in the system time zone formatted as YYYYMMDD or -+YYYYMMDDHHMM[SS]. -+.It -+A date or time in the UTC time zone as YYYYMMDDZ or YYYYMMDDHHMM[SS]Z. -+.It -+A relative time before the current system time consisting of a minus sign -+followed by an interval in the format described in the - TIME FORMATS section of - .Xr sshd_config 5 . -+.It -+A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a hexadecimal -+number beginning with -+.Dq 0x . -+.El - .Pp --The end time may be specified as a YYYYMMDD date, a YYYYMMDDHHMM[SS] time, --a relative time starting with a plus character or the string -+The end time may be specified similarly to the start time: -+.Bl -bullet -compact -+.It -+The string - .Dq forever --to indicate that the certificate has no expiry date. -+to indicate the certificate has no specified end time. -+.It -+A date or time in the system time zone formatted as YYYYMMDD or -+YYYYMMDDHHMM[SS]. -+.It -+A date or time in the UTC time zone as YYYYMMDDZ or YYYYMMDDHHMM[SS]Z. -+.It -+A relative time after the current system time consisting of a plus sign -+followed by an interval in the format described in the -+TIME FORMATS section of -+.Xr sshd_config 5 . -+.It -+A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a hexadecimal -+number beginning with -+.Dq 0x . -+.El - .Pp - For example: --.Dq +52w1d --(valid from now to 52 weeks and one day from now), --.Dq -4w:+4w --(valid from four weeks ago to four weeks from now), --.Dq 20100101123000:20110101123000 --(valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011), --.Dq -1d:20110101 --(valid from yesterday to midnight, January 1st, 2011), --.Dq -1m:forever --(valid from one minute ago and never expiring). -+.Bl -tag -width Ds -+.It +52w1d -+Valid from now to 52 weeks and one day from now. -+.It -4w:+4w -+Valid from four weeks ago to four weeks from now. -+.It 20100101123000:20110101123000 -+Valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011. -+.It 20100101123000Z:20110101123000Z -+Similar, but interpreted in the UTC time zone rather than the system time zone. -+.It -1d:20110101 -+Valid from yesterday to midnight, January 1st, 2011. -+.It 0x1:0x2000000000 -+Valid from roughly early 1970 to May 2033. -+.It -1m:forever -+Valid from one minute ago and never expiring. -+.El - .It Fl v - Verbose mode. - Causes -@@ -1206,7 +1245,10 @@ signature object and presented on the verification command-line must - match the specified list before the key will be considered acceptable. - .It Cm valid-after Ns = Ns "timestamp" - Indicates that the key is valid for use at or after the specified timestamp, --which may be a date in YYYYMMDD format or a time in YYYYMMDDHHMM[SS] format. -+which may be a date or time in the YYYYMMDD[Z] or YYYYMMDDHHMM[SS][Z] formats. -+Dates and times will be interpreted in the current system time zone unless -+suffixed with a Z character, which causes them to be interpreted in the UTC -+time zone. - .It Cm valid-before Ns = Ns "timestamp" - Indicates that the key is valid for use at or before the specified timestamp. - .El -diff --git a/ssh-keygen.c b/ssh-keygen.c -index 20b321cc..9b2beda0 100644 ---- a/ssh-keygen.c -+++ b/ssh-keygen.c -@@ -1916,6 +1916,21 @@ parse_relative_time(const char *s, time_t now) - return now + (u_int64_t)(secs * mul); - } - -+static void -+parse_hex_u64(const char *s, uint64_t *up) -+{ -+ char *ep; -+ unsigned long long ull; -+ -+ errno = 0; -+ ull = strtoull(s, &ep, 16); -+ if (*s == '\0' || *ep != '\0') -+ fatal("Invalid certificate time: not a number"); -+ if (errno == ERANGE && ull == ULONG_MAX) -+ fatal_fr(SSH_ERR_SYSTEM_ERROR, "Invalid certificate time"); -+ *up = (uint64_t)ull; -+} -+ - static void - parse_cert_times(char *timespec) - { -@@ -1938,8 +1953,8 @@ parse_cert_times(char *timespec) - - /* - * from:to, where -- * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "always" -- * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | "forever" -+ * from := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | 0x... | "always" -+ * to := [+-]timespec | YYYYMMDD | YYYYMMDDHHMMSS | 0x... | "forever" - */ - from = xstrdup(timespec); - to = strchr(from, ':'); -@@ -1951,6 +1966,8 @@ parse_cert_times(char *timespec) - cert_valid_from = parse_relative_time(from, now); - else if (strcmp(from, "always") == 0) - cert_valid_from = 0; -+ else if (strncmp(from, "0x", 2) == 0) -+ parse_hex_u64(from, &cert_valid_from); - else if (parse_absolute_time(from, &cert_valid_from) != 0) - fatal("Invalid from time \"%s\"", from); - -@@ -1958,6 +1975,8 @@ parse_cert_times(char *timespec) - cert_valid_to = parse_relative_time(to, now); - else if (strcmp(to, "forever") == 0) - cert_valid_to = ~(u_int64_t)0; -+ else if (strncmp(to, "0x", 2) == 0) -+ parse_hex_u64(to, &cert_valid_to); - else if (parse_absolute_time(to, &cert_valid_to) != 0) - fatal("Invalid to time \"%s\"", to); - -diff --git a/sshd.8 b/sshd.8 -index 2b50514e..8ccc5bc0 100644 ---- a/sshd.8 -+++ b/sshd.8 -@@ -533,8 +533,9 @@ controlled via the - option. - .It Cm expiry-time="timespec" - Specifies a time after which the key will not be accepted. --The time may be specified as a YYYYMMDD date or a YYYYMMDDHHMM[SS] time --in the system time-zone. -+The time may be specified as a YYYYMMDD[Z] date or a YYYYMMDDHHMM[SS][Z] time. -+Dates and times will be interpreted in the system time zone unless suffixed -+by a Z character, in which case they will be interpreted in the UTC time zone. - .It Cm from="pattern-list" - Specifies that in addition to public key authentication, either the canonical - name of the remote host or its IP address must be present in the diff --git a/SOURCES/openssh-8.7p1-allow-duplicate-subsystem.patch b/SOURCES/openssh-8.7p1-allow-duplicate-subsystem.patch deleted file mode 100644 index 22fe73b..0000000 --- a/SOURCES/openssh-8.7p1-allow-duplicate-subsystem.patch +++ /dev/null @@ -1,32 +0,0 @@ -diff --git a/servconf.c b/servconf.c -index e16f9e90fc71..a3779a9d86ee 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -1942,13 +1942,22 @@ process_server_config_line_depth(ServerOptions *options, char *line, - fatal("%s line %d: %s missing argument.", - filename, linenum, keyword); - if (!*activep) { -- arg = argv_next(&ac, &av); -+ argv_consume(&ac); -+ break; -+ } -+ found = 0; -+ for (i = 0; i < options->num_subsystems; i++) { -+ if (strcmp(arg, options->subsystem_name[i]) == 0) { -+ found = 1; -+ break; -+ } -+ } -+ if (found) { -+ debug("%s line %d: Subsystem '%s' already defined.", -+ filename, linenum, arg); -+ argv_consume(&ac); - break; - } -- for (i = 0; i < options->num_subsystems; i++) -- if (strcmp(arg, options->subsystem_name[i]) == 0) -- fatal("%s line %d: Subsystem '%s' " -- "already defined.", filename, linenum, arg); - options->subsystem_name[options->num_subsystems] = xstrdup(arg); - arg = argv_next(&ac, &av); - if (!arg || *arg == '\0') diff --git a/SOURCES/openssh-8.7p1-evp-fips-compl-dh.patch b/SOURCES/openssh-8.7p1-evp-fips-compl-dh.patch deleted file mode 100644 index ec04910..0000000 --- a/SOURCES/openssh-8.7p1-evp-fips-compl-dh.patch +++ /dev/null @@ -1,292 +0,0 @@ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/dh.c openssh-8.7p1-patched/dh.c ---- openssh-8.7p1/dh.c 2023-05-25 09:01:23.295627077 +0200 -+++ openssh-8.7p1-patched/dh.c 2023-05-25 09:00:56.519332820 +0200 -@@ -37,6 +37,9 @@ - #include - #include - #include -+#include -+#include -+#include - - #include "dh.h" - #include "pathnames.h" -@@ -290,10 +293,15 @@ - int - dh_gen_key(DH *dh, int need) - { -- int pbits; -- const BIGNUM *dh_p, *pub_key; -+ const BIGNUM *dh_p, *dh_g; -+ BIGNUM *pub_key = NULL, *priv_key = NULL; -+ EVP_PKEY *pkey = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ OSSL_PARAM_BLD *param_bld = NULL; -+ OSSL_PARAM *params = NULL; -+ int pbits, r = 0; - -- DH_get0_pqg(dh, &dh_p, NULL, NULL); -+ DH_get0_pqg(dh, &dh_p, NULL, &dh_g); - - if (need < 0 || dh_p == NULL || - (pbits = BN_num_bits(dh_p)) <= 0 || -@@ -301,19 +309,85 @@ - return SSH_ERR_INVALID_ARGUMENT; - if (need < 256) - need = 256; -+ -+ if ((param_bld = OSSL_PARAM_BLD_new()) == NULL || -+ (ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) { -+ OSSL_PARAM_BLD_free(param_bld); -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ -+ if (OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 || -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) { -+ error_f("Could not set p,q,g parameters"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } - /* - * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), - * so double requested need here. - */ -- if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1))) -- return SSH_ERR_LIBCRYPTO_ERROR; -- -- if (DH_generate_key(dh) == 0) -- return SSH_ERR_LIBCRYPTO_ERROR; -- DH_get0_key(dh, &pub_key, NULL); -- if (!dh_pub_is_valid(dh, pub_key)) -- return SSH_ERR_INVALID_FORMAT; -- return 0; -+ if (OSSL_PARAM_BLD_push_int(param_bld, -+ OSSL_PKEY_PARAM_DH_PRIV_LEN, -+ MINIMUM(need * 2, pbits - 1)) != 1 || -+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_fromdata_init(ctx) != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_fromdata(ctx, &pkey, -+ EVP_PKEY_KEY_PARAMETERS, params) != 1) { -+ error_f("Failed key generation"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* reuse context for key generation */ -+ EVP_PKEY_CTX_free(ctx); -+ ctx = NULL; -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || -+ EVP_PKEY_keygen_init(ctx) != 1) { -+ error_f("Could not create or init context"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_generate(ctx, &pkey) != 1) { -+ error_f("Could not generate keys"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_public_check(ctx) != 1) { -+ error_f("The public key is incorrect"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, -+ &pub_key) != 1 || -+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, -+ &priv_key) != 1 || -+ DH_set0_key(dh, pub_key, priv_key) != 1) { -+ error_f("Could not set pub/priv keys to DH struct"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* transferred */ -+ pub_key = NULL; -+ priv_key = NULL; -+out: -+ OSSL_PARAM_free(params); -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(pkey); -+ BN_clear_free(pub_key); -+ BN_clear_free(priv_key); -+ return r; - } - - DH * -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/kex.c openssh-8.7p1-patched/kex.c ---- openssh-8.7p1/kex.c 2023-05-25 09:01:23.299627122 +0200 -+++ openssh-8.7p1-patched/kex.c 2023-05-25 09:00:56.519332820 +0200 -@@ -1603,3 +1603,47 @@ - return r; - } - -+#ifdef WITH_OPENSSL -+/* -+ * Creates an EVP_PKEY from the given parameters and keys. -+ * The private key can be omitted. -+ */ -+int -+kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, -+ const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ int r = 0; -+ -+ /* create EVP_PKEY-DH key */ -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { -+ error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { -+ error_f("Failed pushing params to OSSL_PARAM_BLD"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (priv != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { -+ error_f("Failed pushing private key to OSSL_PARAM_BLD"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ return r; -+} -+#endif /* WITH_OPENSSL */ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/kexdh.c openssh-8.7p1-patched/kexdh.c ---- openssh-8.7p1/kexdh.c 2023-05-25 09:01:23.237626425 +0200 -+++ openssh-8.7p1-patched/kexdh.c 2023-05-25 09:03:21.817957988 +0200 -@@ -35,6 +35,10 @@ - - #include "openbsd-compat/openssl-compat.h" - #include -+#include -+#include -+#include -+#include - - #include "sshkey.h" - #include "kex.h" -@@ -83,9 +87,12 @@ - kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) - { - BIGNUM *shared_secret = NULL; -+ const BIGNUM *pub, *priv, *p, *q, *g; -+ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; -+ EVP_PKEY_CTX *ctx = NULL; - u_char *kbuf = NULL; - size_t klen = 0; -- int kout, r; -+ int kout, r = 0; - - #ifdef DEBUG_KEXDH - fprintf(stderr, "dh_pub= "); -@@ -100,24 +107,59 @@ - r = SSH_ERR_MESSAGE_INCOMPLETE; - goto out; - } -- klen = DH_size(kex->dh); -+ -+ DH_get0_key(kex->dh, &pub, &priv); -+ DH_get0_pqg(kex->dh, &p, &q, &g); -+ /* import key */ -+ r = kex_create_evp_dh(&pkey, p, q, g, pub, priv); -+ if (r != 0) { -+ error_f("Could not create EVP_PKEY for dh"); -+ ERR_print_errors_fp(stderr); -+ goto out; -+ } -+ /* import peer key -+ * the parameters should be the same as with pkey -+ */ -+ r = kex_create_evp_dh(&dh_pkey, p, q, g, dh_pub, NULL); -+ if (r != 0) { -+ error_f("Could not import peer key for dh"); -+ ERR_print_errors_fp(stderr); -+ goto out; -+ } -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) { -+ error_f("Could not init EVP_PKEY_CTX for dh"); -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ if (EVP_PKEY_derive_init(ctx) != 1 || -+ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || -+ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { -+ error_f("Could not get key size"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } - if ((kbuf = malloc(klen)) == NULL || - (shared_secret = BN_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || -- BN_bin2bn(kbuf, kout, shared_secret) == NULL) { -+ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1 || -+ BN_bin2bn(kbuf, klen, shared_secret) == NULL) { -+ error_f("Could not derive key"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - #ifdef DEBUG_KEXDH -- dump_digest("shared secret", kbuf, kout); -+ dump_digest("shared secret", kbuf, klen); - #endif - r = sshbuf_put_bignum2(out, shared_secret); - out: - freezero(kbuf, klen); - BN_clear_free(shared_secret); -+ EVP_PKEY_free(pkey); -+ EVP_PKEY_free(dh_pkey); -+ EVP_PKEY_CTX_free(ctx); - return r; - } - -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/kex.h openssh-8.7p1-patched/kex.h ---- openssh-8.7p1/kex.h 2023-05-25 09:01:23.299627122 +0200 -+++ openssh-8.7p1-patched/kex.h 2023-05-25 09:00:56.519332820 +0200 -@@ -33,6 +33,9 @@ - # include - # include - # include -+# include -+# include -+# include - # ifdef OPENSSL_HAS_ECC - # include - # else /* OPENSSL_HAS_ECC */ -@@ -278,6 +281,8 @@ - const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int) - __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) - __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); -+int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, -+ const BIGNUM *, const BIGNUM *, const BIGNUM *); - - #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) - void dump_digest(const char *, const u_char *, int); diff --git a/SOURCES/openssh-8.7p1-evp-fips-compl-ecdh.patch b/SOURCES/openssh-8.7p1-evp-fips-compl-ecdh.patch deleted file mode 100644 index 0313c6f..0000000 --- a/SOURCES/openssh-8.7p1-evp-fips-compl-ecdh.patch +++ /dev/null @@ -1,207 +0,0 @@ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../openssh-8.7p1/kexecdh.c ./kexecdh.c ---- ../openssh-8.7p1/kexecdh.c 2021-08-20 06:03:49.000000000 +0200 -+++ ./kexecdh.c 2023-04-13 14:30:14.882449593 +0200 -@@ -35,17 +35,57 @@ - #include - - #include -+#include -+#include -+#include -+#include - - #include "sshkey.h" - #include "kex.h" - #include "sshbuf.h" - #include "digest.h" - #include "ssherr.h" -+#include "log.h" - - static int - kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, - const EC_GROUP *, struct sshbuf **); - -+static EC_KEY * -+generate_ec_keys(int ec_nid) -+{ -+ EC_KEY *client_key = NULL; -+ EVP_PKEY *pkey = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ OSSL_PARAM_BLD *param_bld = NULL; -+ OSSL_PARAM *params = NULL; -+ const char *group_name; -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) -+ goto out; -+ if ((group_name = OSSL_EC_curve_nid2name(ec_nid)) == NULL || -+ OSSL_PARAM_BLD_push_utf8_string(param_bld, -+ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || -+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ error_f("Could not create OSSL_PARAM"); -+ goto out; -+ } -+ if (EVP_PKEY_keygen_init(ctx) != 1 || -+ EVP_PKEY_CTX_set_params(ctx, params) != 1 || -+ EVP_PKEY_generate(ctx, &pkey) != 1 || -+ (client_key = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { -+ error_f("Could not generate ec keys"); -+ goto out; -+ } -+out: -+ EVP_PKEY_free(pkey); -+ EVP_PKEY_CTX_free(ctx); -+ OSSL_PARAM_BLD_free(param_bld); -+ OSSL_PARAM_free(params); -+ return client_key; -+} -+ - int - kex_ecdh_keypair(struct kex *kex) - { -@@ -55,11 +95,7 @@ - struct sshbuf *buf = NULL; - int r; - -- if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { -- r = SSH_ERR_ALLOC_FAIL; -- goto out; -- } -- if (EC_KEY_generate_key(client_key) != 1) { -+ if ((client_key = generate_ec_keys(kex->ec_nid)) == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -@@ -101,11 +137,7 @@ - *server_blobp = NULL; - *shared_secretp = NULL; - -- if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { -- r = SSH_ERR_ALLOC_FAIL; -- goto out; -- } -- if (EC_KEY_generate_key(server_key) != 1) { -+ if ((server_key = generate_ec_keys(kex->ec_nid)) == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -@@ -140,11 +172,21 @@ - { - struct sshbuf *buf = NULL; - BIGNUM *shared_secret = NULL; -- EC_POINT *dh_pub = NULL; -- u_char *kbuf = NULL; -- size_t klen = 0; -+ EVP_PKEY_CTX *ctx = NULL; -+ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; -+ OSSL_PARAM_BLD *param_bld = NULL; -+ OSSL_PARAM *params = NULL; -+ u_char *kbuf = NULL, *pub = NULL; -+ size_t klen = 0, publen; -+ const char *group_name; - int r; - -+ /* import EC_KEY to EVP_PKEY */ -+ if ((r = ssh_create_evp_ec(key, kex->ec_nid, &pkey)) != 0) { -+ error_f("Could not create EVP_PKEY"); -+ goto out; -+ } -+ - *shared_secretp = NULL; - - if ((buf = sshbuf_new()) == NULL) { -@@ -153,45 +195,82 @@ - } - if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) - goto out; -- if ((dh_pub = EC_POINT_new(group)) == NULL) { -+ -+ /* the public key is in the buffer in octet string UNCOMPRESSED -+ * format. See sshbuf_put_ec */ -+ if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0) -+ goto out; -+ sshbuf_reset(buf); -+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { -+ if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (OSSL_PARAM_BLD_push_octet_string(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, pub, publen) != 1 || -+ OSSL_PARAM_BLD_push_utf8_string(param_bld, -+ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || -+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ error_f("Failed to set params for dh_pkey"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_fromdata_init(ctx) != 1 || -+ EVP_PKEY_fromdata(ctx, &dh_pkey, -+ EVP_PKEY_PUBLIC_KEY, params) != 1 || -+ EVP_PKEY_public_check(ctx) != 1) { -+ error_f("Peer public key import failed"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- sshbuf_reset(buf); - - #ifdef DEBUG_KEXECDH - fputs("public key:\n", stderr); -- sshkey_dump_ec_point(group, dh_pub); -+ EVP_PKEY_print_public_fp(stderr, dh_pkey, 0, NULL); - #endif -- if (sshkey_ec_validate_public(group, dh_pub) != 0) { -- r = SSH_ERR_MESSAGE_INCOMPLETE; -+ EVP_PKEY_CTX_free(ctx); -+ ctx = NULL; -+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || -+ EVP_PKEY_derive_init(ctx) != 1 || -+ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || -+ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { -+ error_f("Failed to get derive information"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- klen = (EC_GROUP_get_degree(group) + 7) / 8; -- if ((kbuf = malloc(klen)) == NULL || -- (shared_secret = BN_new()) == NULL) { -+ if ((kbuf = malloc(klen)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || -- BN_bin2bn(kbuf, klen, shared_secret) == NULL) { -+ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - #ifdef DEBUG_KEXECDH - dump_digest("shared secret", kbuf, klen); - #endif -+ if ((shared_secret = BN_new()) == NULL || -+ (BN_bin2bn(kbuf, klen, shared_secret) == NULL)) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } - if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) - goto out; - *shared_secretp = buf; - buf = NULL; - out: -- EC_POINT_clear_free(dh_pub); -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(pkey); -+ EVP_PKEY_free(dh_pkey); -+ OSSL_PARAM_BLD_free(param_bld); -+ OSSL_PARAM_free(params); - BN_clear_free(shared_secret); - freezero(kbuf, klen); -+ freezero(pub, publen); - sshbuf_free(buf); - return r; - } diff --git a/SOURCES/openssh-8.7p1-evp-fips-compl-sign.patch b/SOURCES/openssh-8.7p1-evp-fips-compl-sign.patch deleted file mode 100644 index fc71678..0000000 --- a/SOURCES/openssh-8.7p1-evp-fips-compl-sign.patch +++ /dev/null @@ -1,468 +0,0 @@ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../../openssh-8.7p1/ssh-dss.c ./ssh-dss.c ---- ../../openssh-8.7p1/ssh-dss.c 2023-03-08 15:35:14.669943335 +0100 -+++ ./ssh-dss.c 2023-03-08 15:34:33.508578129 +0100 -@@ -32,6 +32,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -72,9 +74,8 @@ - sshkey_type_plain(key->type) != KEY_DSA) - return SSH_ERR_INVALID_ARGUMENT; - -- if ((pkey = EVP_PKEY_new()) == NULL || -- EVP_PKEY_set1_DSA(pkey, key->dsa) != 1) -- return SSH_ERR_ALLOC_FAIL; -+ if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) -+ return ret; - ret = sshkey_calculate_signature(pkey, SSH_DIGEST_SHA1, &sigb, &len, - data, datalen); - EVP_PKEY_free(pkey); -@@ -201,11 +202,8 @@ - goto out; - } - -- if ((pkey = EVP_PKEY_new()) == NULL || -- EVP_PKEY_set1_DSA(pkey, key->dsa) != 1) { -- ret = SSH_ERR_ALLOC_FAIL; -+ if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) - goto out; -- } - ret = sshkey_verify_signature(pkey, SSH_DIGEST_SHA1, data, datalen, - sigb, slen); - EVP_PKEY_free(pkey); -@@ -221,4 +219,63 @@ - freezero(sigblob, len); - return ret; - } -+ -+int -+ssh_create_evp_dss(const struct sshkey *k, EVP_PKEY **pkey) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub = NULL, *priv = NULL; -+ int ret = 0; -+ -+ if (k == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ DSA_get0_pqg(k->dsa, &p, &q, &g); -+ DSA_get0_key(k->dsa, &pub, &priv); -+ -+ if (p != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (q != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (g != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (pub != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, -+ pub) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (priv != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PRIV_KEY, -+ priv) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ return ret; -+} - #endif /* WITH_OPENSSL */ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../../openssh-8.7p1/ssh-ecdsa.c ./ssh-ecdsa.c ---- ../../openssh-8.7p1/ssh-ecdsa.c 2023-03-08 15:35:14.669943335 +0100 -+++ ./ssh-ecdsa.c 2023-03-08 15:40:52.628201267 +0100 -@@ -34,6 +34,8 @@ - #include - #include - #include -+#include -+#include - - #include - -@@ -72,9 +74,8 @@ - if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) - return SSH_ERR_INTERNAL_ERROR; - -- if ((pkey = EVP_PKEY_new()) == NULL || -- EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) -- return SSH_ERR_ALLOC_FAIL; -+ if ((ret = ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey)) != 0) -+ return ret; - ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data, - datalen); - EVP_PKEY_free(pkey); -@@ -193,11 +194,8 @@ - goto out; - } - -- if ((pkey = EVP_PKEY_new()) == NULL || -- EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) { -- ret = SSH_ERR_ALLOC_FAIL; -+ if (ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey) != 0) - goto out; -- } - ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, sigb, len); - EVP_PKEY_free(pkey); - -@@ -212,4 +210,76 @@ - return ret; - } - -+int -+ssh_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ BN_CTX *bn_ctx = NULL; -+ uint8_t *pub_ser = NULL; -+ const char *group_name; -+ const EC_POINT *pub = NULL; -+ const BIGNUM *priv = NULL; -+ int ret = 0; -+ -+ if (k == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL || -+ (bn_ctx = BN_CTX_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ if ((group_name = OSSL_EC_curve_nid2name(ecdsa_nid)) == NULL || -+ OSSL_PARAM_BLD_push_utf8_string(param_bld, -+ OSSL_PKEY_PARAM_GROUP_NAME, -+ group_name, -+ strlen(group_name)) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((pub = EC_KEY_get0_public_key(k)) != NULL) { -+ const EC_GROUP *group; -+ size_t len; -+ -+ group = EC_KEY_get0_group(k); -+ len = EC_POINT_point2oct(group, pub, -+ POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); -+ if ((pub_ser = malloc(len)) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ EC_POINT_point2oct(group, -+ pub, -+ POINT_CONVERSION_UNCOMPRESSED, -+ pub_ser, -+ len, -+ bn_ctx); -+ if (OSSL_PARAM_BLD_push_octet_string(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, -+ pub_ser, -+ len) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ } -+ if ((priv = EC_KEY_get0_private_key(k)) != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ BN_CTX_free(bn_ctx); -+ free(pub_ser); -+ return ret; -+} - #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../../openssh-8.7p1/sshkey.c ./sshkey.c ---- ../../openssh-8.7p1/sshkey.c 2023-03-08 15:35:14.702943628 +0100 -+++ ./sshkey.c 2023-03-08 15:39:03.354082015 +0100 -@@ -35,6 +35,8 @@ - #include - #include - #include -+#include -+#include - #endif - - #include "crypto_api.h" -@@ -492,13 +494,14 @@ - { - EVP_MD_CTX *ctx = NULL; - u_char *sig = NULL; -- int ret, slen, len; -+ int ret, slen; -+ size_t len; - - if (sigp == NULL || lenp == NULL) { - return SSH_ERR_INVALID_ARGUMENT; - } - -- slen = EVP_PKEY_size(pkey); -+ slen = EVP_PKEY_get_size(pkey); - if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) - return SSH_ERR_INVALID_ARGUMENT; - -@@ -511,9 +514,10 @@ - ret = SSH_ERR_ALLOC_FAIL; - goto error; - } -- if (EVP_SignInit_ex(ctx, ssh_digest_to_md(hash_alg), NULL) <= 0 || -- EVP_SignUpdate(ctx, data, datalen) <= 0 || -- EVP_SignFinal(ctx, sig, &len, pkey) <= 0) { -+ if (EVP_DigestSignInit(ctx, NULL, ssh_digest_to_md(hash_alg), -+ NULL, pkey) != 1 || -+ EVP_DigestSignUpdate(ctx, data, datalen) != 1 || -+ EVP_DigestSignFinal(ctx, sig, &len) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto error; - } -@@ -540,12 +544,13 @@ - if ((ctx = EVP_MD_CTX_new()) == NULL) { - return SSH_ERR_ALLOC_FAIL; - } -- if (EVP_VerifyInit_ex(ctx, ssh_digest_to_md(hash_alg), NULL) <= 0 || -- EVP_VerifyUpdate(ctx, data, datalen) <= 0) { -+ if (EVP_DigestVerifyInit(ctx, NULL, ssh_digest_to_md(hash_alg), -+ NULL, pkey) != 1 || -+ EVP_DigestVerifyUpdate(ctx, data, datalen) != 1) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto done; - } -- ret = EVP_VerifyFinal(ctx, sigbuf, siglen, pkey); -+ ret = EVP_DigestVerifyFinal(ctx, sigbuf, siglen); - switch (ret) { - case 1: - ret = 0; -@@ -5038,3 +5043,27 @@ - return 0; - } - #endif /* WITH_XMSS */ -+ -+#ifdef WITH_OPENSSL -+EVP_PKEY * -+sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) -+{ -+ EVP_PKEY *ret = NULL; -+ OSSL_PARAM *params = NULL; -+ if (param_bld == NULL || ctx == NULL) { -+ debug2_f("param_bld or ctx is NULL"); -+ return NULL; -+ } -+ if ((params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ debug2_f("Could not build param list"); -+ return NULL; -+ } -+ if (EVP_PKEY_fromdata_init(ctx) != 1 || -+ EVP_PKEY_fromdata(ctx, &ret, EVP_PKEY_KEYPAIR, params) != 1) { -+ debug2_f("EVP_PKEY_fromdata failed"); -+ OSSL_PARAM_free(params); -+ return NULL; -+ } -+ return ret; -+} -+#endif /* WITH_OPENSSL */ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../../openssh-8.7p1/sshkey.h ./sshkey.h ---- ../../openssh-8.7p1/sshkey.h 2023-03-08 15:35:14.702943628 +0100 -+++ ./sshkey.h 2023-03-08 15:34:33.509578138 +0100 -@@ -31,6 +31,9 @@ - #ifdef WITH_OPENSSL - #include - #include -+#include -+#include -+#include - # ifdef OPENSSL_HAS_ECC - # include - # include -@@ -293,6 +295,13 @@ - - void sshkey_sig_details_free(struct sshkey_sig_details *); - -+#ifdef WITH_OPENSSL -+EVP_PKEY *sshkey_create_evp(OSSL_PARAM_BLD *, EVP_PKEY_CTX *); -+int ssh_create_evp_dss(const struct sshkey *, EVP_PKEY **); -+int ssh_create_evp_rsa(const struct sshkey *, EVP_PKEY **); -+int ssh_create_evp_ec(EC_KEY *, int, EVP_PKEY **); -+#endif /* WITH_OPENSSL */ -+ - #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 --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../../openssh-8.7p1/ssh-rsa.c ./ssh-rsa.c ---- ../../openssh-8.7p1/ssh-rsa.c 2023-03-08 15:35:14.669943335 +0100 -+++ ./ssh-rsa.c 2023-03-08 15:34:33.509578138 +0100 -@@ -23,6 +23,8 @@ - - #include - #include -+#include -+#include - - #include - #include -@@ -172,9 +174,8 @@ - if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) - return SSH_ERR_KEY_LENGTH; - -- if ((pkey = EVP_PKEY_new()) == NULL || -- EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) -- return SSH_ERR_ALLOC_FAIL; -+ if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) -+ return ret; - ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, - datalen); - EVP_PKEY_free(pkey); -@@ -285,11 +286,8 @@ - len = modlen; - } - -- if ((pkey = EVP_PKEY_new()) == NULL || -- EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) { -- ret = SSH_ERR_ALLOC_FAIL; -+ if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) - goto out; -- } - ret = openssh_RSA_verify(hash_alg, data, datalen, sigblob, len, pkey); - EVP_PKEY_free(pkey); - -@@ -306,11 +304,9 @@ - u_char *sigbuf, size_t siglen, EVP_PKEY *pkey) - { - size_t rsasize = 0; -- const RSA *rsa; - int ret; - -- rsa = EVP_PKEY_get0_RSA(pkey); -- rsasize = RSA_size(rsa); -+ rsasize = EVP_PKEY_get_size(pkey); - if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || - siglen == 0 || siglen > rsasize) { - ret = SSH_ERR_INVALID_ARGUMENT; -@@ -323,4 +319,87 @@ - done: - return ret; - } -+ -+int -+ssh_create_evp_rsa(const struct sshkey *k, EVP_PKEY **pkey) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ int ret = 0; -+ const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL; -+ const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; -+ -+ if (k == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ RSA_get0_key(k->rsa, &n, &e, &d); -+ RSA_get0_factors(k->rsa, &p, &q); -+ RSA_get0_crt_params(k->rsa, &dmp1, &dmq1, &iqmp); -+ -+ if (n != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_N, n) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (e != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_E, e) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (d != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_D, d) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* setting this to param_build makes the creation process fail */ -+ if (p != NULL && -+ EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, p) != 1) { -+ debug2_f("failed to add 'p' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (q != NULL && -+ EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, q) != 1) { -+ debug2_f("failed to add 'q' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (dmp1 != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) != 1) { -+ debug2_f("failed to add 'dmp1' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (dmq1 != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) != 1) { -+ debug2_f("failed to add 'dmq1' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (iqmp != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp) != 1) { -+ debug2_f("failed to add 'iqmp' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ return ret; -+} - #endif /* WITH_OPENSSL */ diff --git a/SOURCES/openssh-8.7p1-evp-pkcs11.patch b/SOURCES/openssh-8.7p1-evp-pkcs11.patch deleted file mode 100644 index 44e0b8f..0000000 --- a/SOURCES/openssh-8.7p1-evp-pkcs11.patch +++ /dev/null @@ -1,131 +0,0 @@ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/ssh-ecdsa.c openssh-8.7p1-patched/ssh-ecdsa.c ---- openssh-8.7p1/ssh-ecdsa.c 2023-05-24 09:39:45.002631174 +0200 -+++ openssh-8.7p1-patched/ssh-ecdsa.c 2023-05-24 09:09:34.400853951 +0200 -@@ -74,8 +74,18 @@ - if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) - return SSH_ERR_INTERNAL_ERROR; - -- if ((ret = ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey)) != 0) -- return ret; -+#ifdef ENABLE_PKCS11 -+ if (is_ecdsa_pkcs11(key->ecdsa)) { -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ } else { -+#endif -+ if ((ret = ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey)) != 0) -+ return ret; -+#ifdef ENABLE_PKCS11 -+ } -+#endif - ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data, - datalen); - EVP_PKEY_free(pkey); -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/ssh-pkcs11.c openssh-8.7p1-patched/ssh-pkcs11.c ---- openssh-8.7p1/ssh-pkcs11.c 2023-05-24 09:39:44.950630607 +0200 -+++ openssh-8.7p1-patched/ssh-pkcs11.c 2023-05-24 09:33:59.153866357 +0200 -@@ -775,8 +775,24 @@ - - return (0); - } -+ -+int -+is_ecdsa_pkcs11(EC_KEY *ecdsa) -+{ -+ if (EC_KEY_get_ex_data(ecdsa, ec_key_idx) != NULL) -+ return 1; -+ return 0; -+} - #endif /* HAVE_EC_KEY_METHOD_NEW */ - -+int -+is_rsa_pkcs11(RSA *rsa) -+{ -+ if (RSA_get_ex_data(rsa, rsa_idx) != NULL) -+ return 1; -+ return 0; -+} -+ - /* remove trailing spaces */ - static void - rmspace(u_char *buf, size_t len) -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/ssh-pkcs11-client.c openssh-8.7p1-patched/ssh-pkcs11-client.c ---- openssh-8.7p1/ssh-pkcs11-client.c 2023-05-24 09:39:44.950630607 +0200 -+++ openssh-8.7p1-patched/ssh-pkcs11-client.c 2023-05-24 09:31:16.139092673 +0200 -@@ -225,8 +225,36 @@ - static RSA_METHOD *helper_rsa; - #ifdef HAVE_EC_KEY_METHOD_NEW - static EC_KEY_METHOD *helper_ecdsa; -+ -+int -+is_ecdsa_pkcs11(EC_KEY *ecdsa) -+{ -+ const EC_KEY_METHOD *meth; -+ ECDSA_SIG *(*sign_sig)(const unsigned char *dgst, int dgstlen, -+ const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey) = NULL; -+ -+ meth = EC_KEY_get_method(ecdsa); -+ EC_KEY_METHOD_get_sign(meth, NULL, NULL, &sign_sig); -+ if (sign_sig == ecdsa_do_sign) -+ return 1; -+ return 0; -+} - #endif /* HAVE_EC_KEY_METHOD_NEW */ - -+int -+is_rsa_pkcs11(RSA *rsa) -+{ -+ const RSA_METHOD *meth; -+ int (*priv_enc)(int flen, const unsigned char *from, -+ unsigned char *to, RSA *rsa, int padding) = NULL; -+ -+ meth = RSA_get_method(rsa); -+ priv_enc = RSA_meth_get_priv_enc(meth); -+ if (priv_enc == rsa_encrypt) -+ return 1; -+ return 0; -+} -+ - /* redirect private key crypto operations to the ssh-pkcs11-helper */ - static void - wrap_key(struct sshkey *k) -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/ssh-pkcs11.h openssh-8.7p1-patched/ssh-pkcs11.h ---- openssh-8.7p1/ssh-pkcs11.h 2023-05-24 09:39:44.950630607 +0200 -+++ openssh-8.7p1-patched/ssh-pkcs11.h 2023-05-24 09:36:49.055714975 +0200 -@@ -39,6 +39,11 @@ - u_int32_t *); - #endif - -+#ifdef HAVE_EC_KEY_METHOD_NEW -+int is_ecdsa_pkcs11(EC_KEY *ecdsa); -+#endif -+int is_rsa_pkcs11(RSA *rsa); -+ - #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) - #undef ENABLE_PKCS11 - #endif -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/ssh-rsa.c openssh-8.7p1-patched/ssh-rsa.c ---- openssh-8.7p1/ssh-rsa.c 2023-05-24 09:39:45.003631184 +0200 -+++ openssh-8.7p1-patched/ssh-rsa.c 2023-05-24 09:31:37.019319860 +0200 -@@ -174,8 +174,18 @@ - if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) - return SSH_ERR_KEY_LENGTH; - -- if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) -- return ret; -+#ifdef ENABLE_PKCS11 -+ if (is_rsa_pkcs11(key->rsa)) { -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ } else { -+#endif -+ if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) -+ return ret; -+#ifdef ENABLE_PKCS11 -+ } -+#endif - ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, - datalen); - EVP_PKEY_free(pkey); diff --git a/SOURCES/openssh-8.7p1-evpgenkey.patch b/SOURCES/openssh-8.7p1-evpgenkey.patch deleted file mode 100644 index 1af9b49..0000000 --- a/SOURCES/openssh-8.7p1-evpgenkey.patch +++ /dev/null @@ -1,110 +0,0 @@ -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/SOURCES/openssh-8.7p1-find-principals-fix.patch b/SOURCES/openssh-8.7p1-find-principals-fix.patch deleted file mode 100644 index 4c6594b..0000000 --- a/SOURCES/openssh-8.7p1-find-principals-fix.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff -up openssh-8.7p1/ssh-keygen.c.find-princ openssh-8.7p1/ssh-keygen.c ---- openssh-8.7p1/ssh-keygen.c.find-princ 2021-11-29 15:27:03.032070863 +0100 -+++ openssh-8.7p1/ssh-keygen.c 2021-11-29 15:27:34.736342968 +0100 -@@ -2700,7 +2700,8 @@ sig_process_opts(char * const *opts, siz - time_t now; - - *verify_timep = 0; -- *print_pubkey = 0; -+ if (print_pubkey) -+ *print_pubkey = 0; - for (i = 0; i < nopts; i++) { - if (strncasecmp(opts[i], "verify-time=", 12) == 0) { - if (parse_absolute_time(opts[i] + 12, diff --git a/SOURCES/openssh-8.7p1-gssapi-auth.patch b/SOURCES/openssh-8.7p1-gssapi-auth.patch deleted file mode 100644 index 6908cad..0000000 --- a/SOURCES/openssh-8.7p1-gssapi-auth.patch +++ /dev/null @@ -1,20 +0,0 @@ -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/SOURCES/openssh-8.7p1-host-based-auth.patch b/SOURCES/openssh-8.7p1-host-based-auth.patch deleted file mode 100644 index 23efe91..0000000 --- a/SOURCES/openssh-8.7p1-host-based-auth.patch +++ /dev/null @@ -1,151 +0,0 @@ -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/SOURCES/openssh-8.7p1-ibmca.patch b/SOURCES/openssh-8.7p1-ibmca.patch index c9c12ee..88914bf 100644 --- a/SOURCES/openssh-8.7p1-ibmca.patch +++ b/SOURCES/openssh-8.7p1-ibmca.patch @@ -4,9 +4,8 @@ #include "includes.h" --#ifndef HAVE_CLOSEFROM -+#if (!defined HAVE_CLOSEFROM) || (defined __s390__) +-#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) ++#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) || (defined __s390__) #include - #include - + #include diff --git a/SOURCES/openssh-8.7p1-man-hostkeyalgos.patch b/SOURCES/openssh-8.7p1-man-hostkeyalgos.patch deleted file mode 100644 index 92c53b1..0000000 --- a/SOURCES/openssh-8.7p1-man-hostkeyalgos.patch +++ /dev/null @@ -1,31 +0,0 @@ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-8.7p1/ssh_config.5 openssh-8.7p1-patched/ssh_config.5 ---- openssh-8.7p1/ssh_config.5 2023-06-02 09:14:40.279373577 +0200 -+++ openssh-8.7p1-patched/ssh_config.5 2023-05-30 16:01:04.533848172 +0200 -@@ -989,6 +989,17 @@ - .Pp - The list of available signature algorithms may also be obtained using - .Qq ssh -Q HostKeyAlgorithms . -+.Pp -+The proposed -+.Cm HostKeyAlgorithms -+during KEX are limited to the set of algorithms that is defined in -+.Cm PubkeyAcceptedAlgorithms -+and therefore they are indirectly affected by system-wide -+.Xr crypto_policies 7 . -+.Xr crypto_policies 7 can not handle the list of host key algorithms directly as doing so -+would break the order given by the -+.Pa known_hosts -+file. - .It Cm HostKeyAlias - Specifies an alias that should be used instead of the - real host name when looking up or saving the host key -@@ -1564,6 +1575,9 @@ - .Pp - The list of available signature algorithms may also be obtained using - .Qq ssh -Q PubkeyAcceptedAlgorithms . -+.Pp -+This option affects also -+.Cm HostKeyAlgorithms - .It Cm PubkeyAuthentication - Specifies whether to try public key authentication. - The argument to this keyword must be diff --git a/SOURCES/openssh-8.7p1-mem-leak.patch b/SOURCES/openssh-8.7p1-mem-leak.patch deleted file mode 100644 index 8c9ac80..0000000 --- a/SOURCES/openssh-8.7p1-mem-leak.patch +++ /dev/null @@ -1,156 +0,0 @@ -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/SOURCES/openssh-8.7p1-minimize-sha1-use.patch b/SOURCES/openssh-8.7p1-minimize-sha1-use.patch deleted file mode 100644 index fc517da..0000000 --- a/SOURCES/openssh-8.7p1-minimize-sha1-use.patch +++ /dev/null @@ -1,207 +0,0 @@ -diff --color -ru a/clientloop.c b/clientloop.c ---- a/clientloop.c 2022-06-29 16:35:06.677597259 +0200 -+++ b/clientloop.c 2022-06-29 16:40:29.737926205 +0200 -@@ -116,6 +116,9 @@ - #include "ssh-gss.h" - #endif - -+/* Permitted RSA signature algorithms for UpdateHostkeys proofs */ -+#define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256" -+ - /* import options */ - extern Options options; - -@@ -2110,8 +2113,10 @@ - struct hostkeys_update_ctx *ctx = (struct hostkeys_update_ctx *)_ctx; - size_t i, ndone; - struct sshbuf *signdata; -- int r, kexsigtype, use_kexsigtype; -+ int r, plaintype; - const u_char *sig; -+ const char *rsa_kexalg = NULL; -+ char *alg = NULL; - size_t siglen; - - if (ctx->nnew == 0) -@@ -2122,9 +2127,9 @@ - hostkeys_update_ctx_free(ctx); - return; - } -- kexsigtype = sshkey_type_plain( -- sshkey_type_from_name(ssh->kex->hostkey_alg)); -- -+ if (sshkey_type_plain(sshkey_type_from_name( -+ ssh->kex->hostkey_alg)) == KEY_RSA) -+ rsa_kexalg = ssh->kex->hostkey_alg; - if ((signdata = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); - /* -@@ -2135,6 +2140,7 @@ - for (ndone = i = 0; i < ctx->nkeys; i++) { - if (ctx->keys_match[i]) - continue; -+ plaintype = sshkey_type_plain(ctx->keys[i]->type); - /* Prepare data to be signed: session ID, unique string, key */ - sshbuf_reset(signdata); - if ( (r = sshbuf_put_cstring(signdata, -@@ -2148,19 +2154,33 @@ - error_fr(r, "parse sig"); - goto out; - } -+ if ((r = sshkey_get_sigtype(sig, siglen, &alg)) != 0) { -+ error_fr(r, "server gave unintelligible signature " -+ "for %s key %zu", sshkey_type(ctx->keys[i]), i); -+ goto out; -+ } - /* -- * For RSA keys, prefer to use the signature type negotiated -- * during KEX to the default (SHA1). -+ * Special case for RSA keys: if a RSA hostkey was negotiated, -+ * then use its signature type for verification of RSA hostkey -+ * proofs. Otherwise, accept only RSA-SHA256/512 signatures. - */ -- use_kexsigtype = kexsigtype == KEY_RSA && -- sshkey_type_plain(ctx->keys[i]->type) == KEY_RSA; -- debug3_f("verify %s key %zu using %s sigalg", -- sshkey_type(ctx->keys[i]), i, -- use_kexsigtype ? ssh->kex->hostkey_alg : "default"); -+ if (plaintype == KEY_RSA && rsa_kexalg == NULL && -+ match_pattern_list(alg, HOSTKEY_PROOF_RSA_ALGS, 0) != 1) { -+ debug_f("server used untrusted RSA signature algorithm " -+ "%s for key %zu, disregarding", alg, i); -+ free(alg); -+ /* zap the key from the list */ -+ sshkey_free(ctx->keys[i]); -+ ctx->keys[i] = NULL; -+ ndone++; -+ continue; -+ } -+ debug3_f("verify %s key %zu using sigalg %s", -+ sshkey_type(ctx->keys[i]), i, alg); -+ free(alg); - if ((r = sshkey_verify(ctx->keys[i], sig, siglen, - sshbuf_ptr(signdata), sshbuf_len(signdata), -- use_kexsigtype ? ssh->kex->hostkey_alg : NULL, 0, -- NULL)) != 0) { -+ plaintype == KEY_RSA ? rsa_kexalg : NULL, 0, NULL)) != 0) { - error_fr(r, "server gave bad signature for %s key %zu", - sshkey_type(ctx->keys[i]), i); - goto out; -diff --git a/hostfile.c b/hostfile.c -index a035b381..bd49e3ac 100644 ---- a/hostfile.c -+++ b/hostfile.c -@@ -642,7 +642,7 @@ hostfile_replace_entries(const char *filename, const char *host, const char *ip, - /* Re-add the requested keys */ - want = HKF_MATCH_HOST | (ip == NULL ? 0 : HKF_MATCH_IP); - for (i = 0; i < nkeys; i++) { -- if ((want & ctx.match_keys[i]) == want) -+ if (keys[i] == NULL || (want & ctx.match_keys[i]) == want) - continue; - if ((fp = sshkey_fingerprint(keys[i], hash_alg, - SSH_FP_DEFAULT)) == NULL) { -diff --color -ru a/kex.c b/kex.c ---- a/kex.c 2022-06-29 16:35:06.775599179 +0200 -+++ b/kex.c 2022-06-29 16:42:00.839710940 +0200 -@@ -959,6 +959,18 @@ - return (1); - } - -+/* returns non-zero if proposal contains any algorithm from algs */ -+static int -+has_any_alg(const char *proposal, const char *algs) -+{ -+ char *cp; -+ -+ if ((cp = match_list(proposal, algs, NULL)) == NULL) -+ return 0; -+ free(cp); -+ return 1; -+} -+ - static int - kex_choose_conf(struct ssh *ssh) - { -@@ -994,6 +1006,16 @@ - free(ext); - } - -+ /* Check whether client supports rsa-sha2 algorithms */ -+ if (kex->server && (kex->flags & KEX_INITIAL)) { -+ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], -+ "rsa-sha2-256,rsa-sha2-256-cert-v01@openssh.com")) -+ kex->flags |= KEX_RSA_SHA2_256_SUPPORTED; -+ if (has_any_alg(peer[PROPOSAL_SERVER_HOST_KEY_ALGS], -+ "rsa-sha2-512,rsa-sha2-512-cert-v01@openssh.com")) -+ kex->flags |= KEX_RSA_SHA2_512_SUPPORTED; -+ } -+ - /* Algorithm Negotiation */ - if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], - sprop[PROPOSAL_KEX_ALGS])) != 0) { -diff --color -ru a/kex.h b/kex.h ---- a/kex.h 2022-06-29 16:35:06.766599003 +0200 -+++ b/kex.h 2022-06-29 16:42:24.199168567 +0200 -@@ -116,6 +116,8 @@ - - #define KEX_INIT_SENT 0x0001 - #define KEX_INITIAL 0x0002 -+#define KEX_RSA_SHA2_256_SUPPORTED 0x0008 /* only set in server for now */ -+#define KEX_RSA_SHA2_512_SUPPORTED 0x0010 /* only set in server for now */ - - struct sshenc { - char *name; -diff --color -ru a/serverloop.c b/serverloop.c ---- a/serverloop.c 2021-08-20 06:03:49.000000000 +0200 -+++ b/serverloop.c 2022-06-29 16:45:05.902336428 +0200 -@@ -684,16 +684,18 @@ - struct sshbuf *resp = NULL; - struct sshbuf *sigbuf = NULL; - struct sshkey *key = NULL, *key_pub = NULL, *key_prv = NULL; -- int r, ndx, kexsigtype, use_kexsigtype, success = 0; -+ int r, ndx, success = 0; - const u_char *blob; -+ const char *sigalg, *kex_rsa_sigalg = NULL; - u_char *sig = 0; - size_t blen, slen; - - if ((resp = sshbuf_new()) == NULL || (sigbuf = sshbuf_new()) == NULL) - fatal_f("sshbuf_new"); - -- kexsigtype = sshkey_type_plain( -- sshkey_type_from_name(ssh->kex->hostkey_alg)); -+ if (sshkey_type_plain(sshkey_type_from_name( -+ ssh->kex->hostkey_alg)) == KEY_RSA) -+ kex_rsa_sigalg = ssh->kex->hostkey_alg; - while (ssh_packet_remaining(ssh) > 0) { - sshkey_free(key); - key = NULL; -@@ -726,16 +728,24 @@ - * For RSA keys, prefer to use the signature type negotiated - * during KEX to the default (SHA1). - */ -- use_kexsigtype = kexsigtype == KEY_RSA && -- sshkey_type_plain(key->type) == KEY_RSA; -+ sigalg = NULL; -+ if (sshkey_type_plain(key->type) == KEY_RSA) { -+ if (kex_rsa_sigalg != NULL) -+ sigalg = kex_rsa_sigalg; -+ else if (ssh->kex->flags & KEX_RSA_SHA2_512_SUPPORTED) -+ sigalg = "rsa-sha2-512"; -+ else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) -+ sigalg = "rsa-sha2-256"; -+ } -+ debug3_f("sign %s key (index %d) using sigalg %s", -+ sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); - if ((r = sshbuf_put_cstring(sigbuf, - "hostkeys-prove-00@openssh.com")) != 0 || - (r = sshbuf_put_stringb(sigbuf, - ssh->kex->session_id)) != 0 || - (r = sshkey_puts(key, sigbuf)) != 0 || - (r = ssh->kex->sign(ssh, key_prv, key_pub, &sig, &slen, -- sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), -- use_kexsigtype ? ssh->kex->hostkey_alg : NULL)) != 0 || -+ sshbuf_ptr(sigbuf), sshbuf_len(sigbuf), sigalg)) != 0 || - (r = sshbuf_put_string(resp, sig, slen)) != 0) { - error_fr(r, "assemble signature"); - goto out; diff --git a/SOURCES/openssh-8.7p1-minrsabits.patch b/SOURCES/openssh-8.7p1-minrsabits.patch index b53c383..d8577d2 100644 --- a/SOURCES/openssh-8.7p1-minrsabits.patch +++ b/SOURCES/openssh-8.7p1-minrsabits.patch @@ -1,446 +1,22 @@ -diff --git a/auth2-hostbased.c b/auth2-hostbased.c -index 36b9d2f5..6b517db4 100644 ---- a/auth2-hostbased.c -+++ b/auth2-hostbased.c -@@ -119,6 +119,11 @@ userauth_hostbased(struct ssh *ssh, const char *method) - "(null)" : key->cert->signature_type); - goto done; - } -+ if ((r = sshkey_check_rsa_length(key, -+ options.required_rsa_size)) != 0) { -+ logit_r(r, "refusing %s key", sshkey_type(key)); -+ goto done; -+ } - - if (!authctxt->valid || authctxt->user == NULL) { - debug2_f("disabled because of invalid user"); -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index 962fd342..5d59febc 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -175,6 +175,11 @@ userauth_pubkey(struct ssh *ssh, const char *method) - "(null)" : key->cert->signature_type); - goto done; - } -+ if ((r = sshkey_check_rsa_length(key, -+ options.required_rsa_size)) != 0) { -+ logit_r(r, "refusing %s key", sshkey_type(key)); -+ goto done; -+ } - key_s = format_key(key); - if (sshkey_is_cert(key)) - ca_s = format_key(key->cert->signature_key); diff --git a/readconf.c b/readconf.c -index 7f26c680..42be690b 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -174,7 +174,7 @@ typedef enum { - oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys, - oFingerprintHash, oUpdateHostkeys, oHostbasedAcceptedAlgorithms, - oPubkeyAcceptedAlgorithms, oCASignatureAlgorithms, oProxyJump, -- oSecurityKeyProvider, oKnownHostsCommand, -+ oSecurityKeyProvider, oKnownHostsCommand, oRequiredRSASize, - oIgnore, oIgnoredUnknownOption, oDeprecated, oUnsupported - } OpCodes; - -@@ -320,6 +320,8 @@ static struct { - { "proxyjump", oProxyJump }, +--- a/readconf.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/readconf.c (date 1703169891147) +@@ -326,6 +326,7 @@ { "securitykeyprovider", oSecurityKeyProvider }, { "knownhostscommand", oKnownHostsCommand }, -+ { "requiredrsasize", oRequiredRSASize }, + { "requiredrsasize", oRequiredRSASize }, + { "rsaminsize", oRequiredRSASize }, /* alias */ - - { NULL, oBadOption } - }; -@@ -2176,6 +2177,10 @@ parse_pubkey_algos: - *charptr = xstrdup(arg); - break; - -+ case oRequiredRSASize: -+ intptr = &options->required_rsa_size; -+ goto parse_int; -+ - case oDeprecated: - debug("%s line %d: Deprecated option \"%s\"", - filename, linenum, keyword); -@@ -2423,6 +2428,7 @@ initialize_options(Options * options) - options->hostbased_accepted_algos = NULL; - options->pubkey_accepted_algos = NULL; - options->known_hosts_command = NULL; -+ options->required_rsa_size = -1; - } - - /* -@@ -2619,6 +2625,8 @@ fill_default_options(Options * options) - if (options->sk_provider == NULL) - options->sk_provider = xstrdup("$SSH_SK_PROVIDER"); - #endif -+ if (options->required_rsa_size == -1) -+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; - - /* Expand KEX name lists */ - all_cipher = cipher_alg_list(',', 0); -@@ -3308,6 +3316,7 @@ dump_client_config(Options *o, const char *host) - dump_cfg_int(oNumberOfPasswordPrompts, o->number_of_password_prompts); - dump_cfg_int(oServerAliveCountMax, o->server_alive_count_max); - dump_cfg_int(oServerAliveInterval, o->server_alive_interval); -+ dump_cfg_int(oRequiredRSASize, o->required_rsa_size); - - /* String options */ - dump_cfg_string(oBindAddress, o->bind_address); -diff --git a/readconf.h b/readconf.h -index f647bd42..ffb5ec4f 100644 ---- a/readconf.h -+++ b/readconf.h -@@ -176,6 +176,8 @@ typedef struct { - - char *known_hosts_command; - -+ int required_rsa_size; /* minimum size of RSA keys */ -+ - char *ignored_unknown; /* Pattern list of unknown tokens to ignore */ - } Options; - + { "enableescapecommandline", oEnableEscapeCommandline }, + { "obscurekeystroketiming", oObscureKeystrokeTiming }, + { "channeltimeout", oChannelTimeout }, diff --git a/servconf.c b/servconf.c -index 29df0463..423772b1 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -195,6 +195,7 @@ initialize_server_options(ServerOptions *options) - options->fingerprint_hash = -1; - options->disable_forwarding = -1; - options->expose_userauth_info = -1; -+ options->required_rsa_size = -1; - } - - /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ -@@ -441,6 +442,8 @@ fill_default_server_options(ServerOptions *options) - options->expose_userauth_info = 0; - if (options->sk_provider == NULL) - options->sk_provider = xstrdup("internal"); -+ if (options->required_rsa_size == -1) -+ options->required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; - - assemble_algorithms(options); - -@@ -517,6 +520,7 @@ typedef enum { - sStreamLocalBindMask, sStreamLocalBindUnlink, - sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, - sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, -+ sRequiredRSASize, - sDeprecated, sIgnore, sUnsupported - } ServerOpCodes; - -@@ -676,6 +680,8 @@ static struct { - { "rdomain", sRDomain, SSHCFG_ALL }, +--- a/servconf.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/servconf.c (date 1703169891148) +@@ -691,6 +691,7 @@ { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, -+ { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, + { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, + { "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */ - { NULL, sBadOption, 0 } - }; - -@@ -2438,6 +2443,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, - *charptr = xstrdup(arg); - break; - -+ case sRequiredRSASize: -+ intptr = &options->required_rsa_size; -+ goto parse_int; -+ - case sDeprecated: - case sIgnore: - case sUnsupported: -@@ -2610,6 +2619,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) - M_CP_INTOPT(rekey_limit); - M_CP_INTOPT(rekey_interval); - M_CP_INTOPT(log_level); -+ M_CP_INTOPT(required_rsa_size); - - /* - * The bind_mask is a mode_t that may be unsigned, so we can't use -@@ -2874,6 +2884,7 @@ dump_config(ServerOptions *o) - dump_cfg_int(sMaxSessions, o->max_sessions); - dump_cfg_int(sClientAliveInterval, o->client_alive_interval); - dump_cfg_int(sClientAliveCountMax, o->client_alive_count_max); -+ dump_cfg_int(sRequiredRSASize, o->required_rsa_size); - dump_cfg_oct(sStreamLocalBindMask, o->fwd_opts.streamlocal_bind_mask); - - /* formatted integer arguments */ -diff --git a/servconf.h b/servconf.h -index 8a04463e..9346155c 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -229,6 +229,7 @@ typedef struct { - int expose_userauth_info; - u_int64_t timing_secret; - char *sk_provider; -+ int required_rsa_size; /* minimum size of RSA keys */ - } ServerOptions; - - /* Information about the incoming connection as used by Match */ -diff --git a/ssh.c b/ssh.c -index 559bf2af..25be53d5 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -516,14 +516,22 @@ resolve_canonicalize(char **hostp, int port) - } - - /* -- * Check the result of hostkey loading, ignoring some errors and -- * fatal()ing for others. -+ * Check the result of hostkey loading, ignoring some errors and either -+ * discarding the key or fatal()ing for others. - */ - static void --check_load(int r, const char *path, const char *message) -+check_load(int r, struct sshkey **k, const char *path, const char *message) - { - switch (r) { - case 0: -+ /* Check RSA keys size and discard if undersized */ -+ if (k != NULL && *k != NULL && -+ (r = sshkey_check_rsa_length(*k, -+ options.required_rsa_size)) != 0) { -+ error_r(r, "load %s \"%s\"", message, path); -+ free(*k); -+ *k = NULL; -+ } - break; - case SSH_ERR_INTERNAL_ERROR: - case SSH_ERR_ALLOC_FAIL: -@@ -1578,7 +1586,7 @@ main(int ac, char **av) - if ((o) >= sensitive_data.nkeys) \ - fatal_f("pubkey out of array bounds"); \ - check_load(sshkey_load_public(p, &(sensitive_data.keys[o]), NULL), \ -- p, "pubkey"); \ -+ &(sensitive_data.keys[o]), p, "pubkey"); \ - } while (0) - #define L_CERT(p,o) do { \ - if ((o) >= sensitive_data.nkeys) \ -@@ -1586,7 +1594,8 @@ main(int ac, char **av) - #define L_CERT(p,o) do { \ - if ((o) >= sensitive_data.nkeys) \ - fatal_f("cert out of array bounds"); \ -- check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), p, "cert"); \ -+ check_load(sshkey_load_cert(p, &(sensitive_data.keys[o])), \ -+ &(sensitive_data.keys[o]), p, "cert"); \ - } while (0) - - if (options.hostbased_authentication == 1) { -@@ -2244,7 +2253,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) - filename = default_client_percent_dollar_expand(cp, cinfo); - free(cp); - check_load(sshkey_load_public(filename, &public, NULL), -- filename, "pubkey"); -+ &public, filename, "pubkey"); - debug("identity file %s type %d", filename, - public ? public->type : -1); - free(options.identity_files[i]); -@@ -2284,7 +2293,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) - continue; - xasprintf(&cp, "%s-cert", filename); - check_load(sshkey_load_public(cp, &public, NULL), -- filename, "pubkey"); -+ &public, filename, "pubkey"); - debug("identity file %s type %d", cp, - public ? public->type : -1); - if (public == NULL) { -@@ -2315,7 +2324,7 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) - free(cp); - - check_load(sshkey_load_public(filename, &public, NULL), -- filename, "certificate"); -+ &public, filename, "certificate"); - debug("certificate file %s type %d", filename, - public ? public->type : -1); - free(options.certificate_files[i]); -diff --git a/sshconnect2.c b/sshconnect2.c -index f9bd19ea..58fe98db 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -96,6 +96,11 @@ static const struct ssh_conn_info *xxx_conn_info; - static int - verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh) - { -+ int r; -+ -+ if ((r = sshkey_check_rsa_length(hostkey, -+ options.required_rsa_size)) != 0) -+ fatal_r(r, "Bad server host key"); - if (verify_host_key(xxx_host, xxx_hostaddr, hostkey, - xxx_conn_info) == -1) - fatal("Host key verification failed."); -@@ -1606,6 +1611,13 @@ load_identity_file(Identity *id) - private = NULL; - quit = 1; - } -+ if (!quit && (r = sshkey_check_rsa_length(private, -+ options.required_rsa_size)) != 0) { -+ debug_fr(r, "Skipping key %s", id->filename); -+ sshkey_free(private); -+ private = NULL; -+ quit = 1; -+ } - if (!quit && private != NULL && id->agent_fd == -1 && - !(id->key && id->isprivate)) - maybe_add_key_to_agent(id->filename, private, comment, -@@ -1752,6 +1764,12 @@ pubkey_prepare(struct ssh *ssh, Authctxt *authctxt) - close(agent_fd); - } else { - for (j = 0; j < idlist->nkeys; j++) { -+ if ((r = sshkey_check_rsa_length(idlist->keys[j], -+ options.required_rsa_size)) != 0) { -+ debug_fr(r, "ignoring %s agent key", -+ sshkey_ssh_name(idlist->keys[j])); -+ continue; -+ } - found = 0; - TAILQ_FOREACH(id, &files, next) { - /* -diff --git a/sshd.c b/sshd.c -index 17eee9d8..395ef493 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -1870,6 +1870,13 @@ main(int ac, char **av) - fatal_r(r, "Could not demote key: \"%s\"", - options.host_key_files[i]); - } -+ if (pubkey != NULL && (r = sshkey_check_rsa_length(pubkey, -+ options.required_rsa_size)) != 0) { -+ error_fr(r, "Host key %s", options.host_key_files[i]); -+ sshkey_free(pubkey); -+ sshkey_free(key); -+ continue; -+ } - sensitive_data.host_keys[i] = key; - sensitive_data.host_pubkeys[i] = pubkey; - -diff --git a/sshkey.c b/sshkey.c -index ed2b5dff..77093235 100644 ---- a/sshkey.c -+++ b/sshkey.c -@@ -2365,18 +2365,24 @@ cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) - return ret; - } - --#ifdef WITH_OPENSSL --static int --check_rsa_length(const RSA *rsa) -+int -+sshkey_check_rsa_length(const struct sshkey *k, int min_size) - { -+#ifdef WITH_OPENSSL - const BIGNUM *rsa_n; -+ int nbits; - -- RSA_get0_key(rsa, &rsa_n, NULL, NULL); -- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) -+ if (k == NULL || k->rsa == NULL || -+ (k->type != KEY_RSA && k->type != KEY_RSA_CERT)) -+ return 0; -+ RSA_get0_key(k->rsa, &rsa_n, NULL, NULL); -+ nbits = BN_num_bits(rsa_n); -+ if (nbits < SSH_RSA_MINIMUM_MODULUS_SIZE || -+ (min_size > 0 && nbits < min_size)) - return SSH_ERR_KEY_LENGTH; -+#endif /* WITH_OPENSSL */ - return 0; - } --#endif - - static int - sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, -@@ -2439,7 +2445,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp, - goto out; - } - rsa_n = rsa_e = NULL; /* transferred */ -- if ((ret = check_rsa_length(key->rsa)) != 0) -+ if ((ret = sshkey_check_rsa_length(key, 0)) != 0) - goto out; - #ifdef DEBUG_PK - RSA_print_fp(stderr, key->rsa, 8); -@@ -3642,7 +3648,7 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) - goto out; - } - rsa_p = rsa_q = NULL; /* transferred */ -- if ((r = check_rsa_length(k->rsa)) != 0) -+ if ((r = sshkey_check_rsa_length(k, 0)) != 0) - goto out; - if ((r = ssh_rsa_complete_crt_parameters(k, rsa_iqmp)) != 0) - goto out; -@@ -4644,7 +4650,7 @@ sshkey_parse_private_pem_fileblob(struct sshbuf *blob, int type, - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- if ((r = check_rsa_length(prv->rsa)) != 0) -+ if ((r = sshkey_check_rsa_length(prv, 0)) != 0) - goto out; - } else if (EVP_PKEY_base_id(pk) == EVP_PKEY_DSA && - (type == KEY_UNSPEC || type == KEY_DSA)) { -diff --git a/sshkey.h b/sshkey.h -index 094815e0..be254e6b 100644 ---- a/sshkey.h -+++ b/sshkey.h -@@ -273,6 +273,7 @@ int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type, - int sshkey_parse_pubkey_from_private_fileblob_type(struct sshbuf *blob, - int type, struct sshkey **pubkeyp); - -+int sshkey_check_rsa_length(const struct sshkey *, int); - /* XXX should be internal, but used by ssh-keygen */ - int ssh_rsa_complete_crt_parameters(struct sshkey *, const BIGNUM *); - -diff --git a/ssh.1 b/ssh.1 -index b4956aec..e255b9b9 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -571,6 +571,7 @@ For full details of the options listed below, and their possible values, see - .It RemoteCommand - .It RemoteForward - .It RequestTTY -+.It RequiredRSASize - .It SendEnv - .It ServerAliveInterval - .It ServerAliveCountMax -diff --git a/ssh_config.5 b/ssh_config.5 -index 24a46460..d1ede18e 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -1634,6 +1634,17 @@ and - .Fl T - flags for - .Xr ssh 1 . -+.It Cm RequiredRSASize -+Specifies the minimum RSA key size (in bits) that -+.Xr ssh 1 -+will accept. -+User authentication keys smaller than this limit will be ignored. -+Servers that present host keys smaller than this limit will cause the -+connection to be terminated. -+The default is -+.Cm 1024 -+bits. -+Note that this limit may only be raised from the default. - .It Cm RevokedHostKeys - Specifies revoked host public keys. - Keys listed in this file will be refused for host authentication. -diff --git a/sshd_config.5 b/sshd_config.5 -index 867a747d..f5a06637 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -1596,6 +1596,16 @@ is - .Cm default none , - which means that rekeying is performed after the cipher's default amount - of data has been sent or received and no time based rekeying is done. -+.It Cm RequiredRSASize -+Specifies the minimum RSA key size (in bits) that -+.Xr sshd 8 -+will accept. -+User and host-based authentication keys smaller than this limit will be -+refused. -+The default is -+.Cm 1024 -+bits. -+Note that this limit may only be raised from the default. - .It Cm RevokedKeys - Specifies revoked public keys file, or - .Cm none + { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, + { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, + { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL }, diff --git a/SOURCES/openssh-8.7p1-negotiate-supported-algs.patch b/SOURCES/openssh-8.7p1-negotiate-supported-algs.patch index 2fb9297..c4d86e7 100644 --- a/SOURCES/openssh-8.7p1-negotiate-supported-algs.patch +++ b/SOURCES/openssh-8.7p1-negotiate-supported-algs.patch @@ -1,63 +1,118 @@ -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 +diff -up openssh-9.3p1/regress/hostkey-agent.sh.xxx openssh-9.3p1/regress/hostkey-agent.sh +--- openssh-9.3p1/regress/hostkey-agent.sh.xxx 2023-05-29 18:15:56.311236887 +0200 ++++ openssh-9.3p1/regress/hostkey-agent.sh 2023-05-29 18:16:07.598503551 +0200 +@@ -17,8 +17,21 @@ trace "make CA key" + + ${SSHKEYGEN} -qt ed25519 -f $OBJ/agent-ca -N '' || fatal "ssh-keygen CA" +PUBKEY_ACCEPTED_ALGOS=`$SSH -G "example.com" | \ + grep -i "PubkeyAcceptedAlgorithms" | cut -d ' ' -f2- | tr "," "|"` +SSH_ACCEPTED_KEYTYPES=`echo "$SSH_KEYTYPES" | egrep "$PUBKEY_ACCEPTED_ALGOS"` ++echo $PUBKEY_ACCEPTED_ALGOS | grep "rsa" ++r=$? ++if [ $r == 0 ]; then ++echo $SSH_ACCEPTED_KEYTYPES | grep "rsa" ++r=$? ++if [ $r -ne 0 ]; then ++SSH_ACCEPTED_KEYTYPES="$SSH_ACCEPTED_KEYTYPES ssh-rsa" ++fi ++fi + 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 + ${SSHKEYGEN} -s $OBJ/agent-ca -qh -n localhost-with-alias \ + -I localhost-with-alias $OBJ/agent-key.$k.pub || \ +@@ -32,12 +48,16 @@ rm $OBJ/agent-ca # Don't need CA private + 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 +-for k in $SSH_KEYTYPES ; do ++for k in $SSH_ACCEPTED_KEYTYPES ; do + verbose "key type $k" ++ hka=$k ++ if [ $k = "ssh-rsa" ]; then ++ hka="rsa-sha2-512" ++ fi + cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy +- echo "HostKeyAlgorithms $k" >> $OBJ/sshd_proxy ++ echo "HostKeyAlgorithms $hka" >> $OBJ/sshd_proxy + echo "Hostkey $OBJ/agent-key.${k}" >> $OBJ/sshd_proxy +- opts="-oHostKeyAlgorithms=$k -F $OBJ/ssh_proxy" ++ opts="-oHostKeyAlgorithms=$hka -F $OBJ/ssh_proxy" + ( printf 'localhost-with-alias,127.0.0.1,::1 ' ; + cat $OBJ/agent-key.$k.pub) > $OBJ/known_hosts + SSH_CONNECTION=`${SSH} $opts host 'echo $SSH_CONNECTION'` +@@ -50,15 +70,16 @@ for k in $SSH_KEYTYPES ; do + done + + SSH_CERTTYPES=`ssh -Q key-sig | grep 'cert-v01@openssh.com'` ++SSH_ACCEPTED_CERTTYPES=`echo "$SSH_CERTTYPES" | egrep "$PUBKEY_ACCEPTED_ALGOS"` + + # Prepare sshd_proxy for certificates. + cp $OBJ/sshd_proxy.orig $OBJ/sshd_proxy + HOSTKEYALGS="" +-for k in $SSH_CERTTYPES ; do ++for k in $SSH_ACCEPTED_CERTTYPES ; do + test -z "$HOSTKEYALGS" || HOSTKEYALGS="${HOSTKEYALGS}," + HOSTKEYALGS="${HOSTKEYALGS}${k}" + done +-for k in $SSH_KEYTYPES ; do ++for k in $SSH_ACCEPTED_KEYTYPES ; do + echo "Hostkey $OBJ/agent-key.${k}.pub" >> $OBJ/sshd_proxy + echo "HostCertificate $OBJ/agent-key.${k}-cert.pub" >> $OBJ/sshd_proxy + test -f $OBJ/agent-key.${k}.pub || fatal "no $k key" +@@ -70,7 +93,7 @@ echo "HostKeyAlgorithms $HOSTKEYALGS" >> + ( printf '@cert-authority localhost-with-alias ' ; + cat $OBJ/agent-ca.pub) > $OBJ/known_hosts + +-for k in $SSH_CERTTYPES ; do ++for k in $SSH_ACCEPTED_CERTTYPES ; do + verbose "cert type $k" + opts="-oHostKeyAlgorithms=$k -F $OBJ/ssh_proxy" + SSH_CONNECTION=`${SSH} $opts host 'echo $SSH_CONNECTION'` +diff -up openssh-9.3p1/sshconnect2.c.xxx openssh-9.3p1/sshconnect2.c +--- openssh-9.3p1/sshconnect2.c.xxx 2023-04-26 17:37:35.100827792 +0200 ++++ openssh-9.3p1/sshconnect2.c 2023-04-26 17:50:31.860748877 +0200 +@@ -221,7 +221,7 @@ ssh_kex2(struct ssh *ssh, char *host, st + const struct ssh_conn_info *cinfo) { - 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; + char *myproposal[PROPOSAL_MAX]; +- char *all_key, *hkalgs = NULL; ++ char *all_key, *hkalgs = NULL, *filtered_algs = 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) +@@ -260,10 +260,22 @@ ssh_kex2(struct ssh *ssh, char *host, st + if (use_known_hosts_order) + hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo); + ++ filtered_algs = hkalgs ? match_filter_allowlist(hkalgs, options.pubkey_accepted_algos) ++ : match_filter_allowlist(options.hostkeyalgorithms, ++ options.pubkey_accepted_algos); ++ if (filtered_algs == NULL) { ++ if (hkalgs) ++ fatal_f("No match between algorithms for %s (host %s) and pubkey accepted algorithms %s", ++ hkalgs, host, options.pubkey_accepted_algos); ++ else ++ fatal_f("No match between host key algorithms %s and pubkey accepted algorithms %s", ++ options.hostkeyalgorithms, options.pubkey_accepted_algos); ++ } ++ + kex_proposal_populate_entries(ssh, myproposal, + options.kex_algorithms, options.ciphers, options.macs, + compression_alg_list(options.compression), +- hkalgs ? hkalgs : options.hostkeyalgorithms); ++ filtered_algs); #if defined(GSSAPI) && defined(WITH_OPENSSL) if (options.gss_keyex) { +@@ -303,6 +315,7 @@ ssh_kex2(struct ssh *ssh, char *host, st + #endif + + free(hkalgs); ++ free(filtered_algs); + + /* start key exchange */ + if ((r = kex_setup(ssh, myproposal)) != 0) diff --git a/SOURCES/openssh-8.7p1-nohostsha1proof.patch b/SOURCES/openssh-8.7p1-nohostsha1proof.patch index 5c54e78..dae0932 100644 --- a/SOURCES/openssh-8.7p1-nohostsha1proof.patch +++ b/SOURCES/openssh-8.7p1-nohostsha1proof.patch @@ -94,47 +94,6 @@ diff -up openssh-8.7p1/monitor.c.sshrsacheck openssh-8.7p1/monitor.c is_proof ? "hostkey proof" : "KEX", siglen); sshbuf_reset(m); -diff -up openssh-8.7p1/regress/cert-userkey.sh.sshrsacheck openssh-8.7p1/regress/cert-userkey.sh ---- openssh-8.7p1/regress/cert-userkey.sh.sshrsacheck 2023-01-25 14:26:52.885963113 +0100 -+++ openssh-8.7p1/regress/cert-userkey.sh 2023-01-25 14:27:25.757219800 +0100 -@@ -7,7 +7,8 @@ rm -f $OBJ/authorized_keys_$USER $OBJ/us - cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak - cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak - --PLAIN_TYPES=`$SSH -Q key-plain | maybe_filter_sk | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` -+#ssh-dss keys are incompatible with DEFAULT crypto policy -+PLAIN_TYPES=`$SSH -Q key-plain | maybe_filter_sk | grep -v 'ssh-dss' | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` - EXTRA_TYPES="" - rsa="" - -diff -up openssh-8.7p1/regress/Makefile.sshrsacheck openssh-8.7p1/regress/Makefile ---- openssh-8.7p1/regress/Makefile.sshrsacheck 2023-01-20 13:07:54.169676051 +0100 -+++ openssh-8.7p1/regress/Makefile 2023-01-20 13:07:54.290677074 +0100 -@@ -2,7 +2,8 @@ - - tests: prep file-tests t-exec unit - --REGRESS_TARGETS= t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 -+#ssh-dss tests will not pass on DEFAULT crypto-policy because of SHA1, skipping -+REGRESS_TARGETS= t1 t2 t3 t4 t5 t7 t8 t9 t10 t11 t12 - - # File based tests - file-tests: $(REGRESS_TARGETS) -diff -up openssh-8.7p1/regress/test-exec.sh.sshrsacheck openssh-8.7p1/regress/test-exec.sh ---- openssh-8.7p1/regress/test-exec.sh.sshrsacheck 2023-01-25 14:24:54.778040819 +0100 -+++ openssh-8.7p1/regress/test-exec.sh 2023-01-25 14:26:39.500858590 +0100 -@@ -581,8 +581,9 @@ maybe_filter_sk() { - fi - } - --SSH_KEYTYPES=`$SSH -Q key-plain | maybe_filter_sk` --SSH_HOSTKEY_TYPES=`$SSH -Q key-plain | maybe_filter_sk` -+#ssh-dss keys are incompatible with DEFAULT crypto policy -+SSH_KEYTYPES=`$SSH -Q key-plain | maybe_filter_sk | grep -v 'ssh-dss'` -+SSH_HOSTKEY_TYPES=`$SSH -Q key-plain | maybe_filter_sk | grep -v 'ssh-dss'` - - for t in ${SSH_KEYTYPES}; do - # generate user key diff -up openssh-8.7p1/regress/unittests/kex/test_kex.c.sshrsacheck openssh-8.7p1/regress/unittests/kex/test_kex.c --- openssh-8.7p1/regress/unittests/kex/test_kex.c.sshrsacheck 2023-01-26 13:34:52.645743677 +0100 +++ openssh-8.7p1/regress/unittests/kex/test_kex.c 2023-01-26 13:36:56.220745823 +0100 @@ -148,15 +107,6 @@ diff -up openssh-8.7p1/regress/unittests/kex/test_kex.c.sshrsacheck openssh-8.7p ASSERT_PTR_NE(keyname, NULL); kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0); -@@ -180,7 +181,7 @@ do_kex(char *kex) - { - #ifdef WITH_OPENSSL - do_kex_with_key(kex, KEY_RSA, 2048); -- do_kex_with_key(kex, KEY_DSA, 1024); -+ /* do_kex_with_key(kex, KEY_DSA, 1024); */ - #ifdef OPENSSL_HAS_ECC - do_kex_with_key(kex, KEY_ECDSA, 256); - #endif /* OPENSSL_HAS_ECC */ diff -up openssh-8.7p1/regress/unittests/sshkey/test_file.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_file.c --- openssh-8.7p1/regress/unittests/sshkey/test_file.c.sshrsacheck 2023-01-26 12:04:55.946343408 +0100 +++ openssh-8.7p1/regress/unittests/sshkey/test_file.c 2023-01-26 12:06:35.235164432 +0100 @@ -196,22 +146,6 @@ diff -up openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c.sshrsacheck openssh- TEST_START("fuzz RSA SHA256 sig"); buf = load_file("rsa_1"); -@@ -357,6 +358,7 @@ sshkey_fuzz_tests(void) - sshkey_free(k1); - TEST_DONE(); - -+ /* Skip this test, SHA1 signatures are not supported - TEST_START("fuzz DSA sig"); - buf = load_file("dsa_1"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); -@@ -364,6 +366,7 @@ sshkey_fuzz_tests(void) - sig_fuzz(k1, NULL); - sshkey_free(k1); - TEST_DONE(); -+ */ - - #ifdef OPENSSL_HAS_ECC - TEST_START("fuzz ECDSA sig"); diff -up openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c --- openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c.sshrsacheck 2023-01-26 11:02:52.339413463 +0100 +++ openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c 2023-01-26 11:58:42.324253896 +0100 @@ -241,10 +175,10 @@ diff -up openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c.sshrsacheck openss { size_t len; u_char *sig; -+ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp */ -+ int expected = (sig_alg && strcmp(sig_alg, "ssh-rsa") == 0) ? SSH_ERR_LIBCRYPTO_ERROR : 0; ++ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp in RHEL, permitted in Fedora */ ++ int expected = (sig_alg && strcmp(sig_alg, "ssh-rsa") == 0) ? sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, NULL, 0) : 0; + if (k && (sshkey_type_plain(k->type) == KEY_DSA || sshkey_type_plain(k->type) == KEY_DSA_CERT)) -+ expected = SSH_ERR_LIBCRYPTO_ERROR; ++ expected = sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, NULL, 0); ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, - NULL, NULL, 0), 0); @@ -277,24 +211,17 @@ diff -up openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c.sshrsacheck openss ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4), SSH_ERR_KEY_CERT_INVALID_SIGN_KEY); ASSERT_PTR_EQ(k4, NULL); -diff -up openssh-8.7p1/regress/unittests/sshsig/tests.c.sshrsacheck openssh-8.7p1/regress/unittests/sshsig/tests.c ---- openssh-8.7p1/regress/unittests/sshsig/tests.c.sshrsacheck 2023-01-26 12:19:23.659513651 +0100 -+++ openssh-8.7p1/regress/unittests/sshsig/tests.c 2023-01-26 12:20:28.021044803 +0100 -@@ -102,9 +102,11 @@ tests(void) - check_sig("rsa.pub", "rsa.sig", msg, namespace); - TEST_DONE(); - -+ /* Skip this test, SHA1 signatures are not supported - TEST_START("check DSA signature"); - check_sig("dsa.pub", "dsa.sig", msg, namespace); - TEST_DONE(); -+ */ - - #ifdef OPENSSL_HAS_ECC - TEST_START("check ECDSA signature"); diff -up openssh-8.7p1/serverloop.c.sshrsacheck openssh-8.7p1/serverloop.c --- openssh-8.7p1/serverloop.c.sshrsacheck 2023-01-12 14:57:08.118400073 +0100 +++ openssh-8.7p1/serverloop.c 2023-01-12 14:59:17.330470518 +0100 +@@ -80,6 +80,7 @@ + #include "auth-options.h" + #include "serverloop.h" + #include "ssherr.h" ++#include "compat.h" + + extern ServerOptions options; + @@ -737,6 +737,10 @@ server_input_hostkeys_prove(struct ssh * else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) sigalg = "rsa-sha2-256"; @@ -304,7 +231,7 @@ diff -up openssh-8.7p1/serverloop.c.sshrsacheck openssh-8.7p1/serverloop.c + debug3_f("SHA1 signature is not supported, falling back to %s", sigalg); + } debug3_f("sign %s key (index %d) using sigalg %s", - sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); + sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); if ((r = sshbuf_put_cstring(sigbuf, diff -up openssh-8.7p1/sshconnect2.c.sshrsacheck openssh-8.7p1/sshconnect2.c --- openssh-8.7p1/sshconnect2.c.sshrsacheck 2023-01-25 15:33:29.140353651 +0100 @@ -318,99 +245,12 @@ diff -up openssh-8.7p1/sshconnect2.c.sshrsacheck openssh-8.7p1/sshconnect2.c + debug3_f("trying to fallback to algorithm %s", rsa_safe_alg); + + if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, -+ rsa_safe_alg, options.sk_provider, pin, compat)) != 0) ++ rsa_safe_alg, options.sk_provider, pin, compat)) != 0) + debug_fr(r, "sshkey_sign - RSA fallback"); + } goto out; } -diff -up openssh-8.7p1/sshd.c.sshrsacheck openssh-8.7p1/sshd.c ---- openssh-8.7p1/sshd.c.sshrsacheck 2023-01-12 13:29:06.355711140 +0100 -+++ openssh-8.7p1/sshd.c 2023-01-12 13:29:06.358711178 +0100 -@@ -1640,6 +1651,7 @@ main(int ac, char **av) - int keytype; - Authctxt *authctxt; - struct connection_info *connection_info = NULL; -+ int forbid_ssh_rsa = 0; - - #ifdef HAVE_SECUREWARE - (void)set_auth_parameters(ac, av); -@@ -1938,6 +1950,33 @@ main(int ac, char **av) - key = NULL; - continue; - } -+ if (key && (sshkey_type_plain(key->type) == KEY_RSA || sshkey_type_plain(key->type) == KEY_RSA_CERT)) { -+ size_t sign_size = 0; -+ u_char *tmp = NULL; -+ u_char data[] = "Test SHA1 vector"; -+ int res; -+ -+ res = sshkey_sign(key, &tmp, &sign_size, data, sizeof(data), NULL, NULL, NULL, 0); -+ free(tmp); -+ if (res == SSH_ERR_LIBCRYPTO_ERROR) { -+ verbose_f("sshd: SHA1 in signatures is disabled for RSA keys"); -+ forbid_ssh_rsa = 1; -+ } -+ } -+ if (key && (sshkey_type_plain(key->type) == KEY_DSA || sshkey_type_plain(key->type) == KEY_DSA_CERT)) { -+ size_t sign_size = 0; -+ u_char *tmp = NULL; -+ u_char data[] = "Test SHA1 vector"; -+ int res; -+ -+ res = sshkey_sign(key, &tmp, &sign_size, data, sizeof(data), NULL, NULL, NULL, 0); -+ free(tmp); -+ if (res == SSH_ERR_LIBCRYPTO_ERROR) { -+ logit_f("sshd: ssh-dss is disabled, skipping key file %s", options.host_key_files[i]); -+ key = NULL; -+ continue; -+ } -+ } - if (sshkey_is_sk(key) && - key->sk_flags & SSH_SK_USER_PRESENCE_REQD) { - debug("host key %s requires user presence, ignoring", -@@ -2275,6 +2306,9 @@ main(int ac, char **av) - - check_ip_options(ssh); - -+ if (forbid_ssh_rsa) -+ ssh->compat |= SSH_RH_RSASIGSHA; -+ - /* Prepare the channels layer */ - channel_init_channels(ssh); - channel_set_af(ssh, options.address_family); -diff -Nur openssh-8.7p1/ssh-keygen.c openssh-8.7p1_patched/ssh-keygen.c ---- openssh-8.7p1/ssh-keygen.c 2023-01-18 17:41:47.894515779 +0100 -+++ openssh-8.7p1_patched/ssh-keygen.c 2023-01-18 17:41:44.500488818 +0100 -@@ -491,6 +491,8 @@ - BIGNUM *dsa_pub_key = NULL, *dsa_priv_key = NULL; - BIGNUM *rsa_n = NULL, *rsa_e = NULL, *rsa_d = NULL; - BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_iqmp = NULL; -+ char rsa_safe_alg[] = "rsa-sha2-256"; -+ char *alg = NULL; - - if ((r = sshbuf_get_u32(b, &magic)) != 0) - fatal_fr(r, "parse magic"); -@@ -590,6 +592,7 @@ do_convert_private_ssh2(struct sshbuf *b - if ((r = ssh_rsa_complete_crt_parameters(key, rsa_iqmp)) != 0) - fatal_fr(r, "generate RSA parameters"); - BN_clear_free(rsa_iqmp); -+ alg = rsa_safe_alg; - break; - } - rlen = sshbuf_len(b); -@@ -598,9 +601,9 @@ do_convert_private_ssh2(struct sshbuf *b - - /* try the key */ - if (sshkey_sign(key, &sig, &slen, data, sizeof(data), -- NULL, NULL, NULL, 0) != 0 || -+ alg, NULL, NULL, 0) != 0 || - sshkey_verify(key, sig, slen, data, sizeof(data), -- NULL, 0, NULL) != 0) { -+ alg, 0, NULL) != 0) { - sshkey_free(key); - free(sig); - return NULL; diff -up openssh-8.7p1/ssh-rsa.c.sshrsacheck openssh-8.7p1/ssh-rsa.c --- openssh-8.7p1/ssh-rsa.c.sshrsacheck 2023-01-20 13:07:54.180676144 +0100 +++ openssh-8.7p1/ssh-rsa.c 2023-01-20 13:07:54.290677074 +0100 @@ -424,3 +264,34 @@ diff -up openssh-8.7p1/ssh-rsa.c.sshrsacheck openssh-8.7p1/ssh-rsa.c ret = SSH_ERR_SIGNATURE_INVALID; goto out; } +diff -up openssh-9.8p1/sshd-session.c.xxx openssh-9.8p1/sshd-session.c +--- openssh-9.8p1/sshd-session.c.xxx 2024-07-23 15:08:14.794350818 +0200 ++++ openssh-9.8p1/sshd-session.c 2024-07-23 15:40:21.658456636 +0200 +@@ -1305,6 +1305,27 @@ main(int ac, char **av) + + check_ip_options(ssh); + ++ { ++ struct sshkey *rsakey = NULL; ++ rsakey = get_hostkey_private_by_type(KEY_RSA, 0, ssh); ++ if (rsakey == NULL) ++ rsakey = get_hostkey_private_by_type(KEY_RSA_CERT, 0, ssh); ++ ++ if (rsakey != NULL) { ++ size_t sign_size = 0; ++ u_char *tmp = NULL; ++ u_char data[] = "Test SHA1 vector"; ++ int res; ++ ++ res = sshkey_sign(rsakey, &tmp, &sign_size, data, sizeof(data), NULL, NULL, NULL, 0); ++ free(tmp); ++ if (res == SSH_ERR_LIBCRYPTO_ERROR) { ++ verbose_f("SHA1 in signatures is disabled for RSA keys"); ++ ssh->compat |= SSH_RH_RSASIGSHA; ++ } ++ } ++ } ++ + /* Prepare the channels layer */ + channel_init_channels(ssh); + channel_set_af(ssh, options.address_family); diff --git a/SOURCES/openssh-8.7p1-openssl-log.patch b/SOURCES/openssh-8.7p1-openssl-log.patch index 9c9a3f5..35f444c 100644 --- a/SOURCES/openssh-8.7p1-openssl-log.patch +++ b/SOURCES/openssh-8.7p1-openssl-log.patch @@ -1,6 +1,16 @@ -diff -up openssh-8.7p1/log.c.xxx openssh-8.7p1/log.c ---- openssh-8.7p1/log.c.xxx 2024-10-18 13:00:56.419560563 +0200 -+++ openssh-8.7p1/log.c 2024-10-18 13:22:35.954819016 +0200 +diff -up openssh-9.9p1/log.c.xxx openssh-9.9p1/log.c +--- openssh-9.9p1/log.c.xxx 2024-10-22 11:55:44.281939275 +0200 ++++ openssh-9.9p1/log.c 2024-10-22 11:56:16.709676267 +0200 +@@ -52,6 +52,9 @@ + + #include "log.h" + #include "match.h" ++#ifdef WITH_OPENSSL ++#include ++#endif + + static LogLevel log_level = SYSLOG_LEVEL_INFO; + static int log_on_stderr = 1; @@ -438,6 +438,26 @@ sshlog(const char *file, const char *fun va_end(args); } @@ -38,7 +48,7 @@ diff -up openssh-8.7p1/log.h.xxx openssh-8.7p1/log.h +void sshlog_openssl(int); void sshlogv(const char *, const char *, int, int, LogLevel, const char *, const char *, va_list); - void sshsigdie(const char *, const char *, int, int, + void sshlogdie(const char *, const char *, int, int, diff -up openssh-8.7p1/auth2-pubkey.c.yyy openssh-8.7p1/auth2-pubkey.c --- openssh-8.7p1/auth2-pubkey.c.yyy 2024-10-18 13:27:00.709055845 +0200 +++ openssh-8.7p1/auth2-pubkey.c 2024-10-18 13:27:31.638784460 +0200 @@ -63,3 +73,40 @@ diff -up openssh-8.7p1/dispatch.c.yyy openssh-8.7p1/dispatch.c sshpkt_fatal(ssh, r, "%s", __func__); + } } +diff -up openssh-9.9p1/Makefile.in.xxx openssh-9.9p1/Makefile.in +--- openssh-9.9p1/Makefile.in.xxx 2025-01-27 12:56:58.533623367 +0100 ++++ openssh-9.9p1/Makefile.in 2025-01-27 12:57:41.635638843 +0100 +@@ -224,7 +224,7 @@ sshd-session$(EXEEXT): libssh.a $(LIBCOM + $(LD) -o $@ $(SSHD_SESSION_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS) + + scp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SCP_OBJS) +- $(LD) -o $@ $(SCP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) ++ $(LD) -o $@ $(SCP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lcrypto $(LIBS) + + ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHADD_OBJS) + $(LD) -o $@ $(SSHADD_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS) +@@ -245,20 +245,20 @@ ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) lib + $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2) $(CHANNELLIBS) + + ssh-keycat$(EXEEXT): $(LIBCOMPAT) $(SSHDOBJS) libssh.a ssh-keycat.o uidswap.o +- $(LD) -o $@ ssh-keycat.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat $(KEYCATLIBS) $(LIBS) ++ $(LD) -o $@ ssh-keycat.o uidswap.o $(LDFLAGS) -lssh -lopenbsd-compat -lcrypto $(KEYCATLIBS) $(LIBS) + + ssh-keyscan$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHKEYSCAN_OBJS) + $(LD) -o $@ $(SSHKEYSCAN_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) $(CHANNELLIBS) + + sftp-server$(EXEEXT): $(LIBCOMPAT) libssh.a $(SFTPSERVER_OBJS) +- $(LD) -o $@ $(SFTPSERVER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh $(LIBS) ++ $(LD) -o $@ $(SFTPSERVER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lcrypto $(LIBS) + + sftp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SFTP_OBJS) +- $(LD) -o $@ $(SFTP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(LIBEDIT) ++ $(LD) -o $@ $(SFTP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lcrypto $(LIBS) $(LIBEDIT) + + # test driver for the loginrec code - not built by default + logintest: logintest.o $(LIBCOMPAT) libssh.a loginrec.o +- $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh $(LIBS) ++ $(LD) -o $@ logintest.o $(LDFLAGS) loginrec.o -lopenbsd-compat -lssh -lcrypto $(LIBS) + + $(MANPAGES): $(MANPAGES_IN) + if test "$(MANTYPE)" = "cat"; then \ diff --git a/SOURCES/openssh-8.7p1-recursive-scp.patch b/SOURCES/openssh-8.7p1-recursive-scp.patch index 25765fb..17c340e 100644 --- a/SOURCES/openssh-8.7p1-recursive-scp.patch +++ b/SOURCES/openssh-8.7p1-recursive-scp.patch @@ -1,174 +1,182 @@ -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 - +diff --git a/scp.c b/scp.c +--- a/scp.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/scp.c (date 1703111453316) +@@ -1372,7 +1372,7 @@ + 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); + if (sftp_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, targ); 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 - + } +diff --git a/sftp-client.c b/sftp-client.c +--- a/sftp-client.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/sftp-client.c (date 1703169614263) +@@ -1003,7 +1003,7 @@ + /* 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) +-sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand) ++sftp_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) +@@ -1049,11 +1049,43 @@ + if ((r = sshbuf_get_u32(msg, &status)) != 0 || + (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0) fatal_fr(r, "parse status"); -- error("Couldn't canonicalize: %s", fx2txt(status)); +- error("%s %s: %s", expand ? "expand" : "realpath", +- path, *errmsg == '\0' ? fx2txt(status) : errmsg); +- free(errmsg); - 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) { ++ if ((r = sftp_mkdir(conn, path, &a, 0)) != 0) { + sshbuf_free(msg); + return NULL; + } -+ ++ debug2("Sending SSH2_FXP_REALPATH \"%s\" - create dir", path); + 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) ++ (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; ++ free(errmsg); + -+ if ((r = sshbuf_get_u32(msg, &status)) != 0) ++ if ((r = sshbuf_get_u32(msg, &status)) != 0 || ++ (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0) + fatal_fr(r, "parse status"); -+ error("Couldn't canonicalize: %s", fx2txt(status)); ++ error("%s %s: %s", expand ? "expand" : "realpath", ++ path, *errmsg == '\0' ? fx2txt(status) : errmsg); ++ free(errmsg); + sshbuf_free(msg); + return NULL; + } + } else { -+ error("Couldn't canonicalize: %s", fx2txt(status)); ++ error("%s %s: %s", expand ? "expand" : "realpath", ++ path, *errmsg == '\0' ? fx2txt(status) : errmsg); ++ free(errmsg); + 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 +@@ -1078,9 +1110,9 @@ } - + char * --do_realpath(struct sftp_conn *conn, const char *path) -+do_realpath(struct sftp_conn *conn, const char *path, int create_dir) +-sftp_realpath(struct sftp_conn *conn, const char *path) ++sftp_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); +- return sftp_realpath_expand(conn, path, 0); ++ return sftp_realpath_expand(conn, path, 0, create_dir); } - + int -@@ -1055,9 +1083,9 @@ do_expand_path(struct sftp_conn *conn, c +@@ -1094,9 +1126,9 @@ { - if (!can_expand_path(conn)) { + if (!sftp_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 sftp_realpath_expand(conn, path, 0); ++ return sftp_realpath_expand(conn, path, 0, 0); } -- return do_realpath_expand(conn, path, 1); -+ return do_realpath_expand(conn, path, 1, 0); +- return sftp_realpath_expand(conn, path, 1); ++ return sftp_realpath_expand(conn, path, 1, 0); } - + int -@@ -1807,7 +1835,7 @@ download_dir(struct sftp_conn *conn, con +@@ -2016,7 +2048,7 @@ 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); + +- if ((src_canon = sftp_realpath(conn, src)) == NULL) { ++ if ((src_canon = sftp_realpath(conn, src, 0)) == NULL) { + error("download \"%s\": path canonicalization failed", src); return -1; } -@@ -2115,12 +2143,12 @@ upload_dir_internal(struct sftp_conn *co +@@ -2365,12 +2397,12 @@ int - upload_dir(struct sftp_conn *conn, const char *src, const char *dst, + sftp_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) +- int follow_link_flag, int inplace_flag) ++ int follow_link_flag, int inplace_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); + +- if ((dst_canon = sftp_realpath(conn, dst)) == NULL) { ++ if ((dst_canon = sftp_realpath(conn, dst, create_dir)) == NULL) { + error("upload \"%s\": path canonicalization failed", dst); return -1; } -@@ -2557,7 +2585,7 @@ crossload_dir(struct sftp_conn *from, st +@@ -2825,7 +2857,7 @@ 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); + +- if ((from_path_canon = sftp_realpath(from, from_path)) == NULL) { ++ if ((from_path_canon = sftp_realpath(from, from_path, 0)) == NULL) { + error("crossload \"%s\": path canonicalization failed", + 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); - +diff --git a/sftp-client.h b/sftp-client.h +--- a/sftp-client.h (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/sftp-client.h (date 1703111691284) +@@ -111,7 +111,7 @@ + int sftp_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); - +-char *sftp_realpath(struct sftp_conn *, const char *); ++char *sftp_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 + char *sftp_expand_path(struct sftp_conn *, const char *); +@@ -163,7 +163,7 @@ * times if 'pflag' is set */ - int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int, -- int, int); -+ int, int, int); - + int sftp_upload_dir(struct sftp_conn *, const char *, const char *, +- int, int, int, int, int, 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, + +diff --git a/sftp.c b/sftp.c +--- a/sftp.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/sftp.c (date 1703168795365) +@@ -807,7 +807,7 @@ + (rflag || global_rflag)) { + if (sftp_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) +- 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, -@@ -1577,7 +1577,7 @@ parse_dispatch_command(struct sftp_conn + if (sftp_upload(conn, g.gl_pathv[i], abs_dst, +@@ -1642,7 +1642,7 @@ 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) { + path1 = sftp_make_absolute(path1, *pwd); +- if ((tmp = sftp_realpath(conn, path1)) == NULL) { ++ if ((tmp = sftp_realpath(conn, path1, 0)) == NULL) { err = 1; break; } -@@ -2160,7 +2160,7 @@ interactive_loop(struct sftp_conn *conn, +@@ -2247,7 +2247,7 @@ } #endif /* USE_LIBEDIT */ - -- remote_path = do_realpath(conn, "."); -+ remote_path = do_realpath(conn, ".", 0); - if (remote_path == NULL) + +- if ((remote_path = sftp_realpath(conn, ".")) == NULL) ++ if ((remote_path = sftp_realpath(conn, ".", 0)) == NULL) fatal("Need cwd"); startdir = xstrdup(remote_path); + diff --git a/SOURCES/openssh-8.7p1-redhat-help.patch b/SOURCES/openssh-8.7p1-redhat-help.patch index 0d1753b..35a3991 100644 --- a/SOURCES/openssh-8.7p1-redhat-help.patch +++ b/SOURCES/openssh-8.7p1-redhat-help.patch @@ -1,7 +1,7 @@ diff --color -ruNp a/ssh.c b/ssh.c ---- a/ssh.c 2025-07-21 16:24:30.348843762 +0200 -+++ b/ssh.c 2025-07-21 16:27:20.477953307 +0200 -@@ -174,6 +174,17 @@ static int forward_confirms_pending = -1 +--- a/ssh.c 2025-07-17 14:08:37.880551301 +0200 ++++ b/ssh.c 2025-07-17 15:02:09.224627879 +0200 +@@ -175,6 +175,17 @@ static int forward_confirms_pending = -1 extern int muxserver_sock; extern u_int muxclient_command; @@ -9,7 +9,7 @@ diff --color -ruNp a/ssh.c b/ssh.c +redhat_help_message(void) +{ + if (log_level_get() >= SYSLOG_LEVEL_DEBUG1 && -+ isatty(fileno(stderr))) { ++ isatty(fileno(stderr))) { + fprintf(stderr, +"\nThe link below provides guidance on resolving common SSH errors:\n" +" https://red.ht/support_rhel_ssh\n"); @@ -19,10 +19,10 @@ diff --color -ruNp a/ssh.c b/ssh.c /* Prints a help message to the user. This function never returns. */ static void -@@ -1609,8 +1620,10 @@ main(int ac, char **av) +@@ -1648,8 +1659,10 @@ main(int ac, char **av) /* Open a connection to the remote host. */ - if (ssh_connect(ssh, host, host_arg, addrs, &hostaddr, options.port, - options.connection_attempts, + if (ssh_connect(ssh, host, options.host_arg, addrs, &hostaddr, + options.port, options.connection_attempts, - &timeout_ms, options.tcp_keep_alive) != 0) + &timeout_ms, options.tcp_keep_alive) != 0) { + redhat_help_message(); diff --git a/SOURCES/openssh-8.7p1-scp-clears-file.patch b/SOURCES/openssh-8.7p1-scp-clears-file.patch deleted file mode 100644 index 4c033da..0000000 --- a/SOURCES/openssh-8.7p1-scp-clears-file.patch +++ /dev/null @@ -1,304 +0,0 @@ -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/SOURCES/openssh-8.7p1-scp-kill-switch.patch b/SOURCES/openssh-8.7p1-scp-kill-switch.patch index 6710304..161ab2d 100644 --- a/SOURCES/openssh-8.7p1-scp-kill-switch.patch +++ b/SOURCES/openssh-8.7p1-scp-kill-switch.patch @@ -13,8 +13,8 @@ diff -up openssh-8.7p1/scp.1.kill-scp openssh-8.7p1/scp.1 --- openssh-8.7p1/scp.1.kill-scp 2021-09-16 12:09:02.646714578 +0200 +++ openssh-8.7p1/scp.1 2021-09-16 12:26:49.978628226 +0200 @@ -278,6 +278,13 @@ to print debugging messages about their - This is helpful in - debugging connection, authentication, and configuration problems. + By default a 32KB buffer is used. + .El .El +.Pp +Usage of SCP protocol can be blocked by creating a world-readable diff --git a/SOURCES/openssh-8.7p1-sftp-default-protocol.patch b/SOURCES/openssh-8.7p1-sftp-default-protocol.patch deleted file mode 100644 index ec25944..0000000 --- a/SOURCES/openssh-8.7p1-sftp-default-protocol.patch +++ /dev/null @@ -1,129 +0,0 @@ -diff --git a/scp.1 b/scp.1 -index 68aac04b..a96e95ad 100644 ---- a/scp.1 -+++ b/scp.1 -@@ -8,9 +8,9 @@ - .\" - .\" Created: Sun May 7 00:14:37 1995 ylo - .\" --.\" $OpenBSD: scp.1,v 1.100 2021/08/11 14:07:54 naddy Exp $ -+.\" $OpenBSD: scp.1,v 1.101 2021/09/08 23:31:39 djm Exp $ - .\" --.Dd $Mdocdate: August 11 2021 $ -+.Dd $Mdocdate: September 8 2021 $ - .Dt SCP 1 - .Os - .Sh NAME -@@ -18,7 +18,7 @@ - .Nd OpenSSH secure file copy - .Sh SYNOPSIS - .Nm scp --.Op Fl 346ABCOpqRrsTv -+.Op Fl 346ABCOpqRrTv - .Op Fl c Ar cipher - .Op Fl D Ar sftp_server_path - .Op Fl F Ar ssh_config -@@ -37,9 +37,6 @@ It uses - .Xr ssh 1 - for data transfer, and uses the same authentication and provides the - same security as a login session. --The scp protocol requires execution of the remote user's shell to perform --.Xr glob 3 --pattern matching. - .Pp - .Nm - will ask for passwords or passphrases if they are needed for -@@ -79,7 +76,9 @@ The options are as follows: - Copies between two remote hosts are transferred through the local host. - Without this option the data is copied directly between the two remote - hosts. --Note that, when using the legacy SCP protocol (the default), this option -+Note that, when using the legacy SCP protocol (via the -+.Fl O -+flag), this option - selects batch mode for the second host as - .Nm - cannot ask for passwords or passphrases for both hosts. -@@ -146,9 +145,10 @@ Limits the used bandwidth, specified in Kbit/s. - .It Fl O - Use the legacy SCP protocol for file transfers instead of the SFTP protocol. - Forcing the use of the SCP protocol may be necessary for servers that do --not implement SFTP or for backwards-compatibility for particular filename --wildcard patterns. --This mode is the default. -+not implement SFTP, for backwards-compatibility for particular filename -+wildcard patterns and for expanding paths with a -+.Sq ~ -+prefix for older SFTP servers. - .It Fl o Ar ssh_option - Can be used to pass options to - .Nm ssh -@@ -258,16 +258,6 @@ to use for the encrypted connection. - The program must understand - .Xr ssh 1 - options. --.It Fl s --Use the SFTP protocol for file transfers instead of the legacy SCP protocol. --Using SFTP avoids invoking a shell on the remote side and provides --more predictable filename handling, as the SCP protocol --relied on the remote shell for expanding --.Xr glob 3 --wildcards. --.Pp --A near-future release of OpenSSH will make the SFTP protocol the default. --This option will be deleted before the end of 2022. - .It Fl T - Disable strict filename checking. - By default when copying files from a remote host to a local directory -@@ -299,11 +289,23 @@ debugging connection, authentication, and configuration problems. - .Xr ssh_config 5 , - .Xr sftp-server 8 , - .Xr sshd 8 -+.Sh CAVEATS -+The original scp protocol (selected by the -+.Fl O -+flag) requires execution of the remote user's shell to perform -+.Xr glob 3 -+pattern matching. -+This requires careful quoting of any characters that have special meaning to -+the remote shell, such as quote characters. - .Sh HISTORY - .Nm - is based on the rcp program in - .Bx - source code from the Regents of the University of California. -+.Pp -+Since OpenSSH 8.8 (8.7 in Red Hat/Fedora builds), -+.Nm -+has use the SFTP protocol for transfers by default. - .Sh AUTHORS - .An Timo Rinne Aq Mt tri@iki.fi - .An Tatu Ylonen Aq Mt ylo@cs.hut.fi -diff --git a/scp.c b/scp.c -index e039350c..c7cf7529 100644 ---- a/scp.c -+++ b/scp.c -@@ -1,4 +1,4 @@ --/* $OpenBSD: scp.c,v 1.232 2021/08/11 14:07:54 naddy Exp $ */ -+/* $OpenBSD: scp.c,v 1.233 2021/09/08 23:31:39 djm Exp $ */ - /* - * scp - secure remote copy. This is basically patched BSD rcp which - * uses ssh to do the data transfer (instead of using rcmd). -@@ -448,7 +448,7 @@ main(int argc, char **argv) - const char *errstr; - extern char *optarg; - extern int optind; -- enum scp_mode_e mode = MODE_SCP; -+ enum scp_mode_e mode = MODE_SFTP; - char *sftp_direct = NULL; - - /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ -@@ -1983,7 +1983,7 @@ void - usage(void) - { - (void) fprintf(stderr, -- "usage: scp [-346ABCOpqRrsTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n" -+ "usage: scp [-346ABCOpqRrTv] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n" - " [-i identity_file] [-J destination] [-l limit]\n" - " [-o ssh_option] [-P port] [-S program] source ... target\n"); - exit(1); diff --git a/SOURCES/openssh-8.7p1-sftpscp-dir-create.patch b/SOURCES/openssh-8.7p1-sftpscp-dir-create.patch deleted file mode 100644 index a549170..0000000 --- a/SOURCES/openssh-8.7p1-sftpscp-dir-create.patch +++ /dev/null @@ -1,167 +0,0 @@ -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" -@@ -660,7 +661,7 @@ main(int argc, char **argv) - * Finally check the exit status of the ssh process, if one was forked - * and no error has occurred yet - */ -- if (do_cmd_pid != -1 && errs == 0) { -+ if (do_cmd_pid != -1 && (mode == MODE_SFTP || errs == 0)) { - if (remin != -1) - (void) close(remin); - if (remout != -1) -@@ -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,14 +1322,17 @@ 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) { -- fatal("failed to upload directory %s to %s", -+ 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) -- fatal("failed to upload file %s to %s", src, abs_dst); -+ } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) { -+ error("failed to upload file %s to %s", src, abs_dst); -+ errs = 1; -+ } - - free(abs_dst); - free(target); -@@ -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); -@@ -1551,7 +1584,8 @@ out: - free(tmp); - globfree(&g); - if (err == -1) { -- fatal("Failed to download file '%s'", src); -+ error("Failed to download '%s'", src); -+ errs = 1; - } - } - diff --git a/SOURCES/openssh-8.7p1-sigpipe.patch b/SOURCES/openssh-8.7p1-sigpipe.patch deleted file mode 100644 index be73b2c..0000000 --- a/SOURCES/openssh-8.7p1-sigpipe.patch +++ /dev/null @@ -1,21 +0,0 @@ -diff --git a/ssh.c b/ssh.c -index 89ca1940..559bf2af 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -1124,6 +1124,8 @@ main(int ac, char **av) - } - } - -+ ssh_signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ -+ - /* - * Initialize "log" output. Since we are the client all output - * goes to stderr unless otherwise specified by -y or -E. -@@ -1652,7 +1654,6 @@ main(int ac, char **av) - options.num_system_hostfiles); - tilde_expand_paths(options.user_hostfiles, options.num_user_hostfiles); - -- ssh_signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ - ssh_signal(SIGCHLD, main_sigchld_handler); - - /* Log into the remote system. Never returns if the login fails. */ diff --git a/SOURCES/openssh-8.7p1-ssh-manpage.patch b/SOURCES/openssh-8.7p1-ssh-manpage.patch index 04e4c06..c7f6f1e 100644 --- a/SOURCES/openssh-8.7p1-ssh-manpage.patch +++ b/SOURCES/openssh-8.7p1-ssh-manpage.patch @@ -14,9 +14,9 @@ diff --color -ru a/ssh.1 b/ssh.1 .It ControlPersist .It DynamicForward +.It EnableSSHKeysign + .It EnableEscapeCommandline .It EscapeChar .It ExitOnForwardFailure - .It FingerprintHash @@ -538,6 +540,8 @@ .It IdentitiesOnly .It IdentityAgent diff --git a/SOURCES/openssh-8.7p1-upstream-cve-2021-41617.patch b/SOURCES/openssh-8.7p1-upstream-cve-2021-41617.patch deleted file mode 100644 index 15d49f2..0000000 --- a/SOURCES/openssh-8.7p1-upstream-cve-2021-41617.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/misc.c b/misc.c -index b8d1040d..0134d694 100644 ---- a/misc.c -+++ b/misc.c -@@ -56,6 +56,7 @@ - #ifdef HAVE_PATHS_H - # include - #include -+#include - #endif - #ifdef SSH_TUN_OPENBSD - #include -@@ -2695,6 +2696,12 @@ subprocess(const char *tag, const char *command, - } - closefrom(STDERR_FILENO + 1); - -+ if (geteuid() == 0 && -+ initgroups(pw->pw_name, pw->pw_gid) == -1) { -+ error("%s: initgroups(%s, %u): %s", tag, -+ pw->pw_name, (u_int)pw->pw_gid, strerror(errno)); -+ _exit(1); -+ } - if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1) { - error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, - strerror(errno)); diff --git a/SOURCES/openssh-8.7p1.tar.gz.asc b/SOURCES/openssh-8.7p1.tar.gz.asc deleted file mode 100644 index 1bdc93b..0000000 --- a/SOURCES/openssh-8.7p1.tar.gz.asc +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PGP SIGNATURE----- - -iQIzBAABCgAdFiEEcWi5g4FaXu9ZpK39Kj9BTnNgYLoFAmEfKn8ACgkQKj9BTnNg -YLo2qQ/9EHkk64DFIOZz9xmKdogiVvuYue9LE1ex52rgLhxkeAmXQ0Ta2VjK0S81 -9/oWJP5N+gcHLO01Og2bVuUPim/S1Op69a5hmFWaYvIlKCeCBONwE1O+n6IIhf+p -HUXkY9cFXOoSEHhQ1D+/f8axv7WtZ4ZtHlxejqcsjyyIDqG+i4kReiZJP0D06dUk -cv2U6YsQ9hTvXBTeUANCgLzH6DvEoyQyy7LOpaHsO1VKMlctslrVWdWRiAn7V934 -8TuhZB0NoHAGZIgFFCINSfFAxnqxPyZtLdTxSF5EwPXqdnwFfGk4nprLZA1vT2yT -HeZiXhx919L+trDVmCycqcSCj8vOlNWl9A8VaodTW01SG75D7b1f5XqLGmSP4ujf -+9UnYKVm0OAU8jpbGXd1D2REuXRspRU6NPNW/3MkO2I46sG+KHhD6OMipOaiY8p2 -WrCsryadBThUqSKAo/zdIAJgVVt23Y7ykIIkhxebaRBIS4v6fdXg4aIjHfOjlsDX -Mh2JFEbP93bKC0wCJWcR7NXFR4nN2ddTen1jLC+m+ABMae0AoMCFy7VW4FK33ZAJ -+Plovu62bBUXeVhXhLC76vdQo7geRpBs0RQV0gtj6HlZL5BReEKwApPEVce8K9F5 -+ZYbmF5ZQNMcdR9zZ+QV+ykv6y4SG1+rPI9/Ufo/ZZp5jRnsq+M= -=xI/+ ------END PGP SIGNATURE----- diff --git a/SOURCES/openssh-9.0p1-evp-fips-kex.patch b/SOURCES/openssh-9.0p1-evp-fips-kex.patch new file mode 100644 index 0000000..36fd1cf --- /dev/null +++ b/SOURCES/openssh-9.0p1-evp-fips-kex.patch @@ -0,0 +1,595 @@ +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/dh.c openssh-9.0p1-patched/dh.c +--- openssh-9.0p1/dh.c 2023-05-25 09:24:28.730868316 +0200 ++++ openssh-9.0p1-patched/dh.c 2023-05-25 09:23:44.841379532 +0200 +@@ -37,6 +37,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "dh.h" + #include "pathnames.h" +@@ -290,10 +293,15 @@ + int + dh_gen_key(DH *dh, int need) + { +- int pbits; +- const BIGNUM *dh_p, *pub_key; ++ const BIGNUM *dh_p, *dh_g; ++ BIGNUM *pub_key = NULL, *priv_key = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ int pbits, r = 0; + +- DH_get0_pqg(dh, &dh_p, NULL, NULL); ++ DH_get0_pqg(dh, &dh_p, NULL, &dh_g); + + if (need < 0 || dh_p == NULL || + (pbits = BN_num_bits(dh_p)) <= 0 || +@@ -301,19 +309,85 @@ + return SSH_ERR_INVALID_ARGUMENT; + if (need < 256) + need = 256; ++ ++ if ((param_bld = OSSL_PARAM_BLD_new()) == NULL || ++ (ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) { ++ OSSL_PARAM_BLD_free(param_bld); ++ return SSH_ERR_ALLOC_FAIL; ++ } ++ ++ if (OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) { ++ error_f("Could not set p,q,g parameters"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } + /* + * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), + * so double requested need here. + */ +- if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1))) +- return SSH_ERR_LIBCRYPTO_ERROR; +- +- if (DH_generate_key(dh) == 0) +- return SSH_ERR_LIBCRYPTO_ERROR; +- DH_get0_key(dh, &pub_key, NULL); +- if (!dh_pub_is_valid(dh, pub_key)) +- return SSH_ERR_INVALID_FORMAT; +- return 0; ++ if (OSSL_PARAM_BLD_push_int(param_bld, ++ OSSL_PKEY_PARAM_DH_PRIV_LEN, ++ MINIMUM(need * 2, pbits - 1)) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata(ctx, &pkey, ++ EVP_PKEY_KEY_PARAMETERS, params) != 1) { ++ error_f("Failed key generation"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ /* reuse context for key generation */ ++ EVP_PKEY_CTX_free(ctx); ++ ctx = NULL; ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ EVP_PKEY_keygen_init(ctx) != 1) { ++ error_f("Could not create or init context"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_generate(ctx, &pkey) != 1) { ++ error_f("Could not generate keys"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_public_check(ctx) != 1) { ++ error_f("The public key is incorrect"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, ++ &pub_key) != 1 || ++ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, ++ &priv_key) != 1 || ++ DH_set0_key(dh, pub_key, priv_key) != 1) { ++ error_f("Could not set pub/priv keys to DH struct"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ /* transferred */ ++ pub_key = NULL; ++ priv_key = NULL; ++out: ++ OSSL_PARAM_free(params); ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(pkey); ++ BN_clear_free(pub_key); ++ BN_clear_free(priv_key); ++ return r; + } + + DH * +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kex.c openssh-9.0p1-patched/kex.c +--- openssh-9.0p1/kex.c 2023-05-25 09:24:28.731868327 +0200 ++++ openssh-9.0p1-patched/kex.c 2023-05-25 09:23:44.841379532 +0200 +@@ -1623,3 +1623,142 @@ + return r; + } + ++#ifdef WITH_OPENSSL ++/* ++ * Creates an EVP_PKEY from the given parameters and keys. ++ * The private key can be omitted. ++ */ ++EVP_PKEY * ++sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) ++{ ++ EVP_PKEY *ret = NULL; ++ OSSL_PARAM *params = NULL; ++ if (param_bld == NULL || ctx == NULL) { ++ debug2_f("param_bld or ctx is NULL"); ++ return NULL; ++ } ++ if ((params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ debug2_f("Could not build param list"); ++ return NULL; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1 || ++ EVP_PKEY_fromdata(ctx, &ret, EVP_PKEY_KEYPAIR, params) != 1) { ++ debug2_f("EVP_PKEY_fromdata failed"); ++ OSSL_PARAM_free(params); ++ return NULL; ++ } ++ return ret; ++} ++ ++int ++kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) ++{ ++ OSSL_PARAM_BLD *param_bld = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ BN_CTX *bn_ctx = NULL; ++ uint8_t *pub_ser = NULL; ++ const char *group_name; ++ const EC_POINT *pub = NULL; ++ const BIGNUM *priv = NULL; ++ int ret = 0; ++ ++ if (k == NULL) ++ return SSH_ERR_INVALID_ARGUMENT; ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL || ++ (bn_ctx = BN_CTX_new()) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ if ((group_name = OSSL_EC_curve_nid2name(ecdsa_nid)) == NULL || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, ++ group_name, ++ strlen(group_name)) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((pub = EC_KEY_get0_public_key(k)) != NULL) { ++ const EC_GROUP *group; ++ size_t len; ++ ++ group = EC_KEY_get0_group(k); ++ len = EC_POINT_point2oct(group, pub, ++ POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); ++ if ((pub_ser = malloc(len)) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ EC_POINT_point2oct(group, ++ pub, ++ POINT_CONVERSION_UNCOMPRESSED, ++ pub_ser, ++ len, ++ bn_ctx); ++ if (OSSL_PARAM_BLD_push_octet_string(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, ++ pub_ser, ++ len) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ } ++ if ((priv = EC_KEY_get0_private_key(k)) != NULL && ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++out: ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ BN_CTX_free(bn_ctx); ++ free(pub_ser); ++ return ret; ++} ++ ++int ++kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, ++ const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) ++{ ++ OSSL_PARAM_BLD *param_bld = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = 0; ++ ++ /* create EVP_PKEY-DH key */ ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { ++ error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { ++ error_f("Failed pushing params to OSSL_PARAM_BLD"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (priv != NULL && ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { ++ error_f("Failed pushing private key to OSSL_PARAM_BLD"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++out: ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ return r; ++} ++#endif /* WITH_OPENSSL */ +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kexdh.c openssh-9.0p1-patched/kexdh.c +--- openssh-9.0p1/kexdh.c 2023-05-25 09:24:28.674867692 +0200 ++++ openssh-9.0p1-patched/kexdh.c 2023-05-25 09:25:28.494533889 +0200 +@@ -35,6 +35,10 @@ + + #include "openbsd-compat/openssl-compat.h" + #include ++#include ++#include ++#include ++#include + + #include "sshkey.h" + #include "kex.h" +@@ -83,9 +87,12 @@ + kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) + { + BIGNUM *shared_secret = NULL; ++ const BIGNUM *pub, *priv, *p, *q, *g; ++ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; + u_char *kbuf = NULL; + size_t klen = 0; +- int kout, r; ++ int r = 0; + + #ifdef DEBUG_KEXDH + fprintf(stderr, "dh_pub= "); +@@ -100,24 +107,59 @@ + r = SSH_ERR_MESSAGE_INCOMPLETE; + goto out; + } +- klen = DH_size(kex->dh); ++ ++ DH_get0_key(kex->dh, &pub, &priv); ++ DH_get0_pqg(kex->dh, &p, &q, &g); ++ /* import key */ ++ r = kex_create_evp_dh(&pkey, p, q, g, pub, priv); ++ if (r != 0) { ++ error_f("Could not create EVP_PKEY for dh"); ++ ERR_print_errors_fp(stderr); ++ goto out; ++ } ++ /* import peer key ++ * the parameters should be the same as with pkey ++ */ ++ r = kex_create_evp_dh(&dh_pkey, p, q, g, dh_pub, NULL); ++ if (r != 0) { ++ error_f("Could not import peer key for dh"); ++ ERR_print_errors_fp(stderr); ++ goto out; ++ } ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) { ++ error_f("Could not init EVP_PKEY_CTX for dh"); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (EVP_PKEY_derive_init(ctx) != 1 || ++ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || ++ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { ++ error_f("Could not get key size"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } + if ((kbuf = malloc(klen)) == NULL || + (shared_secret = BN_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || +- BN_bin2bn(kbuf, kout, shared_secret) == NULL) { ++ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1 || ++ BN_bin2bn(kbuf, klen, shared_secret) == NULL) { ++ error_f("Could not derive key"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + #ifdef DEBUG_KEXDH +- dump_digest("shared secret", kbuf, kout); ++ dump_digest("shared secret", kbuf, klen); + #endif + r = sshbuf_put_bignum2(out, shared_secret); + out: + freezero(kbuf, klen); + BN_clear_free(shared_secret); ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_free(dh_pkey); ++ EVP_PKEY_CTX_free(ctx); + return r; + } + +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kex.h openssh-9.0p1-patched/kex.h +--- openssh-9.0p1/kex.h 2023-05-25 09:24:28.725868260 +0200 ++++ openssh-9.0p1-patched/kex.h 2023-05-25 09:23:44.841379532 +0200 +@@ -33,6 +33,9 @@ + # include + # include + # include ++# include ++# include ++# include + # ifdef OPENSSL_HAS_ECC + # include + # else /* OPENSSL_HAS_ECC */ +@@ -283,6 +286,9@@ + const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); ++int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, ++ const BIGNUM *, const BIGNUM *, const BIGNUM *); ++int kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey); + + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) + void dump_digest(const char *, const u_char *, int); +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../openssh-8.7p1/kexecdh.c ./kexecdh.c +--- ../openssh-8.7p1/kexecdh.c 2021-08-20 06:03:49.000000000 +0200 ++++ ./kexecdh.c 2023-04-13 14:30:14.882449593 +0200 +@@ -35,17 +35,57 @@ + #include + + #include ++#include ++#include ++#include ++#include + + #include "sshkey.h" + #include "kex.h" + #include "sshbuf.h" + #include "digest.h" + #include "ssherr.h" ++#include "log.h" + + static int + kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, + const EC_GROUP *, struct sshbuf **); + ++static EC_KEY * ++generate_ec_keys(int ec_nid) ++{ ++ EC_KEY *client_key = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ const char *group_name; ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) ++ goto out; ++ if ((group_name = OSSL_EC_curve_nid2name(ec_nid)) == NULL || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ error_f("Could not create OSSL_PARAM"); ++ goto out; ++ } ++ if (EVP_PKEY_keygen_init(ctx) != 1 || ++ EVP_PKEY_CTX_set_params(ctx, params) != 1 || ++ EVP_PKEY_generate(ctx, &pkey) != 1 || ++ (client_key = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { ++ error_f("Could not generate ec keys"); ++ goto out; ++ } ++out: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ OSSL_PARAM_BLD_free(param_bld); ++ OSSL_PARAM_free(params); ++ return client_key; ++} ++ + int + kex_ecdh_keypair(struct kex *kex) + { +@@ -55,11 +95,7 @@ + struct sshbuf *buf = NULL; + int r; + +- if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { +- r = SSH_ERR_ALLOC_FAIL; +- goto out; +- } +- if (EC_KEY_generate_key(client_key) != 1) { ++ if ((client_key = generate_ec_keys(kex->ec_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +@@ -101,11 +137,7 @@ + *server_blobp = NULL; + *shared_secretp = NULL; + +- if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { +- r = SSH_ERR_ALLOC_FAIL; +- goto out; +- } +- if (EC_KEY_generate_key(server_key) != 1) { ++ if ((server_key = generate_ec_keys(kex->ec_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +@@ -140,11 +172,21 @@ + { + struct sshbuf *buf = NULL; + BIGNUM *shared_secret = NULL; +- EC_POINT *dh_pub = NULL; +- u_char *kbuf = NULL; +- size_t klen = 0; ++ EVP_PKEY_CTX *ctx = NULL; ++ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ u_char *kbuf = NULL, *pub = NULL; ++ size_t klen = 0, publen; ++ const char *group_name; + int r; + ++ /* import EC_KEY to EVP_PKEY */ ++ if ((r = kex_create_evp_ec(key, kex->ec_nid, &pkey)) != 0) { ++ error_f("Could not create EVP_PKEY"); ++ goto out; ++ } ++ + *shared_secretp = NULL; + + if ((buf = sshbuf_new()) == NULL) { +@@ -153,45 +195,82 @@ + } + if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) + goto out; +- if ((dh_pub = EC_POINT_new(group)) == NULL) { ++ ++ /* the public key is in the buffer in octet string UNCOMPRESSED ++ * format. See sshbuf_put_ec */ ++ if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0) ++ goto out; ++ sshbuf_reset(buf); ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { ++ if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (OSSL_PARAM_BLD_push_octet_string(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, pub, publen) != 1 || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ error_f("Failed to set params for dh_pkey"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1 || ++ EVP_PKEY_fromdata(ctx, &dh_pkey, ++ EVP_PKEY_PUBLIC_KEY, params) != 1 || ++ EVP_PKEY_public_check(ctx) != 1) { ++ error_f("Peer public key import failed"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- sshbuf_reset(buf); + + #ifdef DEBUG_KEXECDH + fputs("public key:\n", stderr); +- sshkey_dump_ec_point(group, dh_pub); ++ EVP_PKEY_print_public_fp(stderr, dh_pkey, 0, NULL); + #endif +- if (sshkey_ec_validate_public(group, dh_pub) != 0) { +- r = SSH_ERR_MESSAGE_INCOMPLETE; ++ EVP_PKEY_CTX_free(ctx); ++ ctx = NULL; ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ EVP_PKEY_derive_init(ctx) != 1 || ++ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || ++ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { ++ error_f("Failed to get derive information"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- klen = (EC_GROUP_get_degree(group) + 7) / 8; +- if ((kbuf = malloc(klen)) == NULL || +- (shared_secret = BN_new()) == NULL) { ++ if ((kbuf = malloc(klen)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || +- BN_bin2bn(kbuf, klen, shared_secret) == NULL) { ++ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + #ifdef DEBUG_KEXECDH + dump_digest("shared secret", kbuf, klen); + #endif ++ if ((shared_secret = BN_new()) == NULL || ++ (BN_bin2bn(kbuf, klen, shared_secret) == NULL)) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } + if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) + goto out; + *shared_secretp = buf; + buf = NULL; + out: +- EC_POINT_clear_free(dh_pub); ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_free(dh_pkey); ++ OSSL_PARAM_BLD_free(param_bld); ++ OSSL_PARAM_free(params); + BN_clear_free(shared_secret); + freezero(kbuf, klen); ++ freezero(pub, publen); + sshbuf_free(buf); + return r; + } diff --git a/SOURCES/openssh-9.1p1-sshbanner.patch b/SOURCES/openssh-9.1p1-sshbanner.patch deleted file mode 100644 index 57112be..0000000 --- a/SOURCES/openssh-9.1p1-sshbanner.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff --git a/ssh-keyscan.c b/ssh-keyscan.c -index d29a03b4..d7283136 100644 ---- a/ssh-keyscan.c -+++ b/ssh-keyscan.c -@@ -490,6 +490,15 @@ congreet(int s) - return; - } - -+ /* -+ * Read the server banner as per RFC4253 section 4.2. The "SSH-" -+ * protocol identification string may be preceeded by an arbitarily -+ * large banner which we must read and ignore. Loop while reading -+ * newline-terminated lines until we have one starting with "SSH-". -+ * The ID string cannot be longer than 255 characters although the -+ * preceeding banner lines may (in which case they'll be discarded -+ * in multiple iterations of the outer loop). -+ */ - for (;;) { - memset(buf, '\0', sizeof(buf)); - bufsiz = sizeof(buf); -@@ -517,6 +526,11 @@ congreet(int s) - conrecycle(s); - return; - } -+ if (cp >= buf + sizeof(buf)) { -+ error("%s: greeting exceeds allowable length", c->c_name); -+ confree(s); -+ return; -+ } - if (*cp != '\n' && *cp != '\r') { - error("%s: bad greeting", c->c_name); - confree(s); -diff --git a/sshsig.c b/sshsig.c -index 1e3b6398..eb2a931e 100644 ---- a/sshsig.c -+++ b/sshsig.c -@@ -491,7 +491,7 @@ hash_file(int fd, const char *hashalg, struct sshbuf **bp) - { - char *hex, rbuf[8192], hash[SSH_DIGEST_MAX_LENGTH]; - ssize_t n, total = 0; -- struct ssh_digest_ctx *ctx; -+ struct ssh_digest_ctx *ctx = NULL; - int alg, oerrno, r = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; - -@@ -549,9 +548,11 @@ hash_file(int fd, const char *hashalg, struct sshbuf **bp) - /* success */ - r = 0; - out: -+ oerrno = errno; - sshbuf_free(b); - ssh_digest_free(ctx); - explicit_bzero(hash, sizeof(hash)); -+ errno = oerrno; - return r; - } - diff --git a/SOURCES/openssh-9.3p1-openssl-compat.patch b/SOURCES/openssh-9.3p1-openssl-compat.patch deleted file mode 100644 index 0efbdec..0000000 --- a/SOURCES/openssh-9.3p1-openssl-compat.patch +++ /dev/null @@ -1,52 +0,0 @@ ---- openssh-9.3p1/openbsd-compat/openssl-compat.c 2023-03-15 22:28:19.000000000 +0100 -+++ /home/dbelyavs/work/upstream/openssh-portable/openbsd-compat/openssl-compat.c 2023-05-25 14:19:42.870841944 +0200 -@@ -33,10 +33,10 @@ - - /* - * OpenSSL version numbers: MNNFFPPS: major minor fix patch status -- * We match major, minor, fix and status (not patch) for <1.0.0. -- * After that, we acceptable compatible fix versions (so we -- * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed -- * within a patch series. -+ * Versions >=3 require only major versions to match. -+ * For versions <3, we accept compatible fix versions (so we allow 1.0.1 -+ * to work with 1.0.0). Going backwards is only allowed within a patch series. -+ * See https://www.openssl.org/policies/releasestrat.html - */ - - int -@@ -48,15 +48,17 @@ - if (headerver == libver) - return 1; - -- /* for versions < 1.0.0, major,minor,fix,status must match */ -- if (headerver < 0x1000000f) { -- mask = 0xfffff00fL; /* major,minor,fix,status */ -+ /* -+ * For versions >= 3.0, only the major and status must match. -+ */ -+ if (headerver >= 0x3000000f) { -+ mask = 0xf000000fL; /* major,status */ - return (headerver & mask) == (libver & mask); - } - - /* -- * For versions >= 1.0.0, major,minor,status must match and library -- * fix version must be equal to or newer than the header. -+ * For versions >= 1.0.0, but <3, major,minor,status must match and -+ * library fix version must be equal to or newer than the header. - */ - mask = 0xfff0000fL; /* major,minor,status */ - hfix = (headerver & 0x000ff000) >> 12; -diff -up openssh-8.7p1/configure.ac.check openssh-8.7p1/configure.ac ---- openssh-8.7p1/configure.ac.check 2023-11-27 14:54:32.959113758 +0100 -+++ openssh-8.7p1/configure.ac 2023-11-27 14:54:49.467500523 +0100 -@@ -2821,7 +2821,7 @@ if test "x$openssl" = "xyes" ; then - ;; - 101*) ;; # 1.1.x - 200*) ;; # LibreSSL -- 300*) ;; # OpenSSL development branch. -+ 30*) ;; # OpenSSL 3.x series - *) - AC_MSG_ERROR([Unknown/unsupported OpenSSL version ("$ssl_library_ver")]) - ;; diff --git a/SOURCES/openssh-9.3p1-upstream-cve-2023-38408.patch b/SOURCES/openssh-9.3p1-upstream-cve-2023-38408.patch deleted file mode 100644 index 5632ba1..0000000 --- a/SOURCES/openssh-9.3p1-upstream-cve-2023-38408.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c -index 6be647ec..ebddf6c3 100644 ---- a/ssh-pkcs11.c -+++ b/ssh-pkcs11.c -@@ -1537,10 +1537,8 @@ pkcs11_register_provider(char *provider_id, char *pin, - error("dlopen %s failed: %s", provider_module, dlerror()); - goto fail; - } -- if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) { -- error("dlsym(C_GetFunctionList) failed: %s", dlerror()); -- goto fail; -- } -+ if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) -+ fatal("dlsym(C_GetFunctionList) failed: %s", dlerror()); - - p->module->handle = handle; - /* setup the pkcs11 callbacks */ diff --git a/SOURCES/openssh-9.4p2-limit-delay.patch b/SOURCES/openssh-9.4p2-limit-delay.patch deleted file mode 100644 index 8c1cbcb..0000000 --- a/SOURCES/openssh-9.4p2-limit-delay.patch +++ /dev/null @@ -1,33 +0,0 @@ -diff -u -p -r1.166 auth2.c ---- a/auth2.c 8 Mar 2023 04:43:12 -0000 1.166 -+++ b/auth2.c 28 Aug 2023 08:32:44 -0000 -@@ -208,6 +208,7 @@ input_service_request(int type, u_int32_ - } - - #define MIN_FAIL_DELAY_SECONDS 0.005 -+#define MAX_FAIL_DELAY_SECONDS 5.0 - static double - user_specific_delay(const char *user) - { -@@ -233,6 +234,12 @@ ensure_minimum_time_since(double start, - struct timespec ts; - double elapsed = monotime_double() - start, req = seconds, remain; - -+ if (elapsed > MAX_FAIL_DELAY_SECONDS) { -+ debug3_f("elapsed %0.3lfms exceeded the max delay " -+ "requested %0.3lfms)", elapsed*1000, req*1000); -+ return; -+ } -+ - /* if we've already passed the requested time, scale up */ - while ((remain = seconds - elapsed) < 0.0) - seconds *= 2; -@@ -317,7 +324,7 @@ input_userauth_request(int type, u_int32 - debug2("input_userauth_request: try method %s", method); - authenticated = m->userauth(ssh); - } -- if (!authctxt->authenticated) -+ if (!authctxt->authenticated && strcmp(method, "none") != 0) - ensure_minimum_time_since(tstart, - user_specific_delay(authctxt->user)); - userauth_finish(ssh, authenticated, method, NULL); diff --git a/SOURCES/openssh-9.6p1-CVE-2023-48795.patch b/SOURCES/openssh-9.6p1-CVE-2023-48795.patch deleted file mode 100644 index 7f710db..0000000 --- a/SOURCES/openssh-9.6p1-CVE-2023-48795.patch +++ /dev/null @@ -1,447 +0,0 @@ -diff --git a/PROTOCOL b/PROTOCOL -index d453c779..ded935eb 100644 ---- a/PROTOCOL -+++ b/PROTOCOL -@@ -137,6 +137,32 @@ than as a named global or channel request to allow pings with very - described at: - http://git.libssh.org/users/aris/libssh.git/plain/doc/curve25519-sha256@libssh.org.txt?h=curve25519 - -+1.9 transport: strict key exchange extension -+ -+OpenSSH supports a number of transport-layer hardening measures under -+a "strict KEX" feature. This feature is signalled similarly to the -+RFC8308 ext-info feature: by including a additional algorithm in the -+initiial SSH2_MSG_KEXINIT kex_algorithms field. The client may append -+"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server -+may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms -+are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored -+if they are present in subsequent SSH2_MSG_KEXINIT packets. -+ -+When an endpoint that supports this extension observes this algorithm -+name in a peer's KEXINIT packet, it MUST make the following changes to -+the the protocol: -+ -+a) During initial KEX, terminate the connection if any unexpected or -+ out-of-sequence packet is received. This includes terminating the -+ connection if the first packet received is not SSH2_MSG_KEXINIT. -+ Unexpected packets for the purpose of strict KEX include messages -+ that are otherwise valid at any time during the connection such as -+ SSH2_MSG_DEBUG and SSH2_MSG_IGNORE. -+b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the -+ packet sequence number to zero. This behaviour persists for the -+ duration of the connection (i.e. not just the first -+ SSH2_MSG_NEWKEYS). -+ - 2. Connection protocol changes - - 2.1. connection: Channel write close extension "eow@openssh.com" -diff --git a/kex.c b/kex.c -index aa5e792d..d478ff6e 100644 ---- a/kex.c -+++ b/kex.c -@@ -65,7 +65,7 @@ - #endif - - /* prototype */ --static int kex_choose_conf(struct ssh *); -+static int kex_choose_conf(struct ssh *, uint32_t seq); - static int kex_input_newkeys(int, u_int32_t, struct ssh *); - - static const char *proposal_names[PROPOSAL_MAX] = { -@@ -177,6 +177,18 @@ kex_names_valid(const char *names) - return 1; - } - -+/* returns non-zero if proposal contains any algorithm from algs */ -+static int -+has_any_alg(const char *proposal, const char *algs) -+{ -+ char *cp; -+ -+ if ((cp = match_list(proposal, algs, NULL)) == NULL) -+ return 0; -+ free(cp); -+ return 1; -+} -+ - /* - * Concatenate algorithm names, avoiding duplicates in the process. - * Caller must free returned string. -@@ -184,7 +196,7 @@ kex_names_valid(const char *names) - char * - kex_names_cat(const char *a, const char *b) - { -- char *ret = NULL, *tmp = NULL, *cp, *p, *m; -+ char *ret = NULL, *tmp = NULL, *cp, *p; - size_t len; - - if (a == NULL || *a == '\0') -@@ -201,10 +213,8 @@ kex_names_cat(const char *a, const char *b) - } - strlcpy(ret, a, len); - for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { -- if ((m = match_list(ret, p, NULL)) != NULL) { -- free(m); -+ if (has_any_alg(ret, p)) - continue; /* Algorithm already present */ -- } - if (strlcat(ret, ",", len) >= len || - strlcat(ret, p, len) >= len) { - free(tmp); -@@ -466,7 +485,12 @@ kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh) - { - int r; - -- error("kex protocol error: type %d seq %u", type, seq); -+ /* If in strict mode, any unexpected message is an error */ -+ if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) { -+ ssh_packet_disconnect(ssh, "strict KEX violation: " -+ "unexpected packet type %u (seqnr %u)", type, seq); -+ } -+ error_f("type %u seq %u", type, seq); - if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || - (r = sshpkt_put_u32(ssh, seq)) != 0 || - (r = sshpkt_send(ssh)) != 0) -@@ -548,6 +572,11 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh) - ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &kex_protocol_error); - if ((r = sshpkt_get_u32(ssh, &ninfo)) != 0) - return r; -+ if (ninfo >= 1024) { -+ error("SSH2_MSG_EXT_INFO with too many entries, expected " -+ "<=1024, received %u", ninfo); -+ return dispatch_protocol_error(type, seq, ssh); -+ } - for (i = 0; i < ninfo; i++) { - if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) - return r; -@@ -681,7 +705,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) - error_f("no kex"); - return SSH_ERR_INTERNAL_ERROR; - } -- ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); -+ ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error); - ptr = sshpkt_ptr(ssh, &dlen); - if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) - return r; -@@ -717,7 +741,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) - if (!(kex->flags & KEX_INIT_SENT)) - if ((r = kex_send_kexinit(ssh)) != 0) - return r; -- if ((r = kex_choose_conf(ssh)) != 0) -+ if ((r = kex_choose_conf(ssh, seq)) != 0) - return r; - - if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) -@@ -981,20 +1005,14 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) - return (1); - } - --/* returns non-zero if proposal contains any algorithm from algs */ - static int --has_any_alg(const char *proposal, const char *algs) -+kexalgs_contains(char **peer, const char *ext) - { -- char *cp; -- -- if ((cp = match_list(proposal, algs, NULL)) == NULL) -- return 0; -- free(cp); -- return 1; -+ return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext); - } - - static int --kex_choose_conf(struct ssh *ssh) -+kex_choose_conf(struct ssh *ssh, uint32_t seq) - { - struct kex *kex = ssh->kex; - struct newkeys *newkeys; -@@ -1019,13 +1037,23 @@ kex_choose_conf(struct ssh *ssh) - sprop=peer; - } - -- /* Check whether client supports ext_info_c */ -- if (kex->server && (kex->flags & KEX_INITIAL)) { -- char *ext; -- -- ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); -- kex->ext_info_c = (ext != NULL); -- free(ext); -+ /* Check whether peer supports ext_info/kex_strict */ -+ if ((kex->flags & KEX_INITIAL) != 0) { -+ if (kex->server) { -+ kex->ext_info_c = kexalgs_contains(peer, "ext-info-c"); -+ kex->kex_strict = kexalgs_contains(peer, -+ "kex-strict-c-v00@openssh.com"); -+ } else { -+ kex->kex_strict = kexalgs_contains(peer, -+ "kex-strict-s-v00@openssh.com"); -+ } -+ if (kex->kex_strict) { -+ debug3_f("will use strict KEX ordering"); -+ if (seq != 0) -+ ssh_packet_disconnect(ssh, -+ "strict KEX violation: " -+ "KEXINIT was not the first packet"); -+ } - } - - /* Check whether client supports rsa-sha2 algorithms */ -diff --git a/kex.h b/kex.h -index 5f7ef784..272ebb43 100644 ---- a/kex.h -+++ b/kex.h -@@ -149,6 +149,7 @@ struct kex { - u_int kex_type; - char *server_sig_algs; - int ext_info_c; -+ int kex_strict; - struct sshbuf *my; - struct sshbuf *peer; - struct sshbuf *client_version; -diff --git a/packet.c b/packet.c -index 52017def..beb214f9 100644 ---- a/packet.c -+++ b/packet.c -@@ -1207,8 +1207,13 @@ ssh_packet_send2_wrapped(struct ssh *ssh) - sshbuf_dump(state->output, stderr); - #endif - /* increment sequence number for outgoing packets */ -- if (++state->p_send.seqnr == 0) -+ if (++state->p_send.seqnr == 0) { -+ if ((ssh->kex->flags & KEX_INITIAL) != 0) { -+ ssh_packet_disconnect(ssh, "outgoing sequence number " -+ "wrapped during initial key exchange"); -+ } - logit("outgoing seqnr wraps around"); -+ } - if (++state->p_send.packets == 0) - if (!(ssh->compat & SSH_BUG_NOREKEY)) - return SSH_ERR_NEED_REKEY; -@@ -1216,6 +1221,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh) - state->p_send.bytes += len; - sshbuf_reset(state->outgoing_packet); - -+ if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) { -+ debug_f("resetting send seqnr %u", state->p_send.seqnr); -+ state->p_send.seqnr = 0; -+ } -+ - if (type == SSH2_MSG_NEWKEYS) - r = ssh_set_newkeys(ssh, MODE_OUT); - else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side) -@@ -1344,8 +1354,7 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - /* Stay in the loop until we have received a complete packet. */ - for (;;) { - /* Try to read a packet from the buffer. */ -- r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p); -- if (r != 0) -+ if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p)) != 0) - break; - /* If we got a packet, return it. */ - if (*typep != SSH_MSG_NONE) -@@ -1629,10 +1615,16 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0) - goto out; - } -+ - if (seqnr_p != NULL) - *seqnr_p = state->p_read.seqnr; -- if (++state->p_read.seqnr == 0) -+ if (++state->p_read.seqnr == 0) { -+ if ((ssh->kex->flags & KEX_INITIAL) != 0) { -+ ssh_packet_disconnect(ssh, "incoming sequence number " -+ "wrapped during initial key exchange"); -+ } - logit("incoming seqnr wraps around"); -+ } - if (++state->p_read.packets == 0) - if (!(ssh->compat & SSH_BUG_NOREKEY)) - return SSH_ERR_NEED_REKEY; -@@ -1698,6 +1690,10 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - #endif - /* reset for next packet */ - state->packlen = 0; -+ if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) { -+ debug_f("resetting read seqnr %u", state->p_read.seqnr); -+ state->p_read.seqnr = 0; -+ } - - if ((r = ssh_packet_check_rekey(ssh)) != 0) - return r; -@@ -1720,10 +1716,39 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - r = ssh_packet_read_poll2(ssh, typep, seqnr_p); - if (r != 0) - return r; -- if (*typep) { -- state->keep_alive_timeouts = 0; -- DBG(debug("received packet type %d", *typep)); -+ if (*typep == 0) { -+ /* no message ready */ -+ return 0; - } -+ state->keep_alive_timeouts = 0; -+ DBG(debug("received packet type %d", *typep)); -+ -+ /* Always process disconnect messages */ -+ if (*typep == SSH2_MSG_DISCONNECT) { -+ if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) -+ return r; -+ /* Ignore normal client exit notifications */ -+ do_log2(ssh->state->server_side && -+ reason == SSH2_DISCONNECT_BY_APPLICATION ? -+ SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, -+ "Received disconnect from %s port %d:" -+ "%u: %.400s", ssh_remote_ipaddr(ssh), -+ ssh_remote_port(ssh), reason, msg); -+ free(msg); -+ return SSH_ERR_DISCONNECTED; -+ } -+ -+ /* -+ * Do not implicitly handle any messages here during initial -+ * KEX when in strict mode. They will be need to be allowed -+ * explicitly by the KEX dispatch table or they will generate -+ * protocol errors. -+ */ -+ if (ssh->kex != NULL && -+ (ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) -+ return 0; -+ /* Implicitly handle transport-level messages */ - switch (*typep) { - case SSH2_MSG_IGNORE: - debug3("Received SSH2_MSG_IGNORE"); -@@ -1738,19 +1763,6 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - debug("Remote: %.900s", msg); - free(msg); - break; -- case SSH2_MSG_DISCONNECT: -- if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || -- (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) -- return r; -- /* Ignore normal client exit notifications */ -- do_log2(ssh->state->server_side && -- reason == SSH2_DISCONNECT_BY_APPLICATION ? -- SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, -- "Received disconnect from %s port %d:" -- "%u: %.400s", ssh_remote_ipaddr(ssh), -- ssh_remote_port(ssh), reason, msg); -- free(msg); -- return SSH_ERR_DISCONNECTED; - case SSH2_MSG_UNIMPLEMENTED: - if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0) - return r; -@@ -2242,6 +2254,7 @@ kex_to_blob(struct sshbuf *m, struct kex *kex) - (r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 || - (r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 || - (r = sshbuf_put_u32(m, kex->kex_type)) != 0 || -+ (r = sshbuf_put_u32(m, kex->kex_strict)) != 0 || - (r = sshbuf_put_stringb(m, kex->my)) != 0 || - (r = sshbuf_put_stringb(m, kex->peer)) != 0 || - (r = sshbuf_put_stringb(m, kex->client_version)) != 0 || -@@ -2404,6 +2417,7 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp) - (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 || - (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 || - (r = sshbuf_get_u32(m, &kex->kex_type)) != 0 || -+ (r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 || - (r = sshbuf_get_stringb(m, kex->my)) != 0 || - (r = sshbuf_get_stringb(m, kex->peer)) != 0 || - (r = sshbuf_get_stringb(m, kex->client_version)) != 0 || -@@ -2732,6 +2746,7 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...) - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - -+ debug2_f("sending SSH2_MSG_DISCONNECT: %s", buf); - if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || - (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || - (r = sshpkt_put_cstring(ssh, buf)) != 0 || -diff --git a/sshconnect2.c b/sshconnect2.c -index df6caf81..0cccbcc4 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -253,7 +253,8 @@ ssh_kex2(struct ssh *ssh, char *host, st - fatal_fr(r, "kex_assemble_namelist"); - free(all_key); - -- if ((s = kex_names_cat(options.kex_algorithms, "ext-info-c")) == NULL) -+ if ((s = kex_names_cat(options.kex_algorithms, -+ "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL) - fatal_f("kex_names_cat"); - myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, s); - myproposal[PROPOSAL_ENC_ALGS_CTOS] = -@@ -358,7 +358,6 @@ struct cauthmethod { - }; - - static int input_userauth_service_accept(int, u_int32_t, struct ssh *); --static int input_userauth_ext_info(int, u_int32_t, struct ssh *); - static int input_userauth_success(int, u_int32_t, struct ssh *); - static int input_userauth_failure(int, u_int32_t, struct ssh *); - static int input_userauth_banner(int, u_int32_t, struct ssh *); -@@ -472,7 +471,7 @@ ssh_userauth2(struct ssh *ssh, const char *local_user, - - ssh->authctxt = &authctxt; - ssh_dispatch_init(ssh, &input_userauth_error); -- ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info); -+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info); - ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept); - ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */ - pubkey_cleanup(ssh); -@@ -531,12 +530,6 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh) - } - - /* ARGSUSED */ --static int --input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh) --{ -- return kex_input_ext_info(type, seqnr, ssh); --} -- - void - userauth(struct ssh *ssh, char *authlist) - { -@@ -615,6 +608,7 @@ input_userauth_success(int type, u_int32_t seq, struct ssh *ssh) - free(authctxt->methoddata); - authctxt->methoddata = NULL; - authctxt->success = 1; /* break out */ -+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error); - return 0; - } - -diff -up openssh-8.7p1/sshd.c.kexstrict openssh-8.7p1/sshd.c ---- openssh-8.7p1/sshd.c.kexstrict 2023-11-27 13:19:18.855433602 +0100 -+++ openssh-8.7p1/sshd.c 2023-11-27 13:28:10.441325314 +0100 -@@ -2531,10 +2531,14 @@ do_ssh2_kex(struct ssh *ssh) - struct kex *kex; - char *hostkey_types = NULL; - char *prop_kex = NULL, *prop_enc = NULL, *prop_hostkey = NULL; -+ char *cp; - int r; - -- myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, -- options.kex_algorithms); -+ if ((cp = kex_names_cat(options.kex_algorithms, -+ "kex-strict-s-v00@openssh.com")) == NULL) -+ fatal_f("kex_names_cat"); -+ -+ myproposal[PROPOSAL_KEX_ALGS] = prop_kex = compat_kex_proposal(ssh, cp); - myproposal[PROPOSAL_ENC_ALGS_CTOS] = - myproposal[PROPOSAL_ENC_ALGS_STOC] = prop_enc = - compat_cipher_proposal(ssh, options.ciphers); -@@ -2586,7 +2586,7 @@ do_ssh2_kex(struct ssh *ssh) - if (gss && orig) - xasprintf(&newstr, "%s,%s", gss, orig); - else if (gss) -- newstr = gss; -+ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com"); - else if (orig) - newstr = orig; - -@@ -2650,6 +2654,7 @@ do_ssh2_kex(struct ssh *ssh) - #endif - free(prop_kex); - free(prop_enc); -+ free(cp); - free(prop_hostkey); - debug("KEX done"); - } diff --git a/SOURCES/openssh-9.6p1-CVE-2023-51385.patch b/SOURCES/openssh-9.6p1-CVE-2023-51385.patch deleted file mode 100644 index 3b83b5c..0000000 --- a/SOURCES/openssh-9.6p1-CVE-2023-51385.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff --git a/ssh.c b/ssh.c -index 35c48e62..48d93ddf 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -626,6 +626,41 @@ ssh_conn_info_free(struct ssh_conn_info *cinfo) - free(cinfo); - } - -+static int -+valid_hostname(const char *s) -+{ -+ size_t i; -+ -+ if (*s == '-') -+ return 0; -+ for (i = 0; s[i] != 0; i++) { -+ if (strchr("'`\"$\\;&<>|(){}", s[i]) != NULL || -+ isspace((u_char)s[i]) || iscntrl((u_char)s[i])) -+ return 0; -+ } -+ return 1; -+} -+ -+static int -+valid_ruser(const char *s) -+{ -+ size_t i; -+ -+ if (*s == '-') -+ return 0; -+ for (i = 0; s[i] != 0; i++) { -+ if (strchr("'`\";&<>|(){}", s[i]) != NULL) -+ return 0; -+ /* Disallow '-' after whitespace */ -+ if (isspace((u_char)s[i]) && s[i + 1] == '-') -+ return 0; -+ /* Disallow \ in last position */ -+ if (s[i] == '\\' && s[i + 1] == '\0') -+ return 0; -+ } -+ return 1; -+} -+ - /* - * Main program for the ssh client. - */ -@@ -1118,6 +1153,10 @@ main(int ac, char **av) - if (!host) - usage(); - -+ if (!valid_hostname(host)) -+ fatal("hostname contains invalid characters"); -+ if (options.user != NULL && !valid_ruser(options.user)) -+ fatal("remote username contains invalid characters"); - host_arg = xstrdup(host); - - /* Initialize the command to execute on remote host. */ diff --git a/SOURCES/openssh-8.0p1-gssapi-keyex.patch b/SOURCES/openssh-9.6p1-gssapi-keyex.patch similarity index 64% rename from SOURCES/openssh-8.0p1-gssapi-keyex.patch rename to SOURCES/openssh-9.6p1-gssapi-keyex.patch index 64d8925..ef1f97e 100644 --- a/SOURCES/openssh-8.0p1-gssapi-keyex.patch +++ b/SOURCES/openssh-9.6p1-gssapi-keyex.patch @@ -1,157 +1,41 @@ -diff --git a/Makefile.in b/Makefile.in -index e7549470..b68c1710 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -109,6 +109,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ - kexgexc.o kexgexs.o \ - kexsntrup761x25519.o sntrup761.o kexgen.o \ -+ kexgssc.o \ - sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ - sshbuf-io.o +diff --color -ruNp a/auth2.c b/auth2.c +--- a/auth2.c 2024-09-16 11:45:56.858133241 +0200 ++++ b/auth2.c 2024-09-16 11:46:34.688939755 +0200 +@@ -71,6 +71,7 @@ extern Authmethod method_passwd; + extern Authmethod method_kbdint; + extern Authmethod method_hostbased; + #ifdef GSSAPI ++extern Authmethod method_gsskeyex; + extern Authmethod method_gssapi; + #endif -@@ -125,7 +126,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ - auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ - auth2-none.o auth2-passwd.o auth2-pubkey.o \ - monitor.o monitor_wrap.o auth-krb5.o \ -- auth2-gss.o gss-serv.o gss-serv-krb5.o \ -+ auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ - loginrec.o auth-pam.o auth-shadow.o auth-sia.o md5crypt.o \ - srclimit.o sftp-server.o sftp-common.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ -diff -up a/auth.c.gsskex b/auth.c ---- a/auth.c.gsskex 2021-08-20 06:03:49.000000000 +0200 -+++ b/auth.c 2021-08-27 12:41:51.262788953 +0200 -@@ -402,7 +402,8 @@ auth_root_allowed(struct ssh *ssh, const - case PERMIT_NO_PASSWD: - if (strcmp(method, "publickey") == 0 || - strcmp(method, "hostbased") == 0 || -- strcmp(method, "gssapi-with-mic") == 0) -+ strcmp(method, "gssapi-with-mic") == 0 || -+ strcmp(method, "gssapi-keyex") == 0) - return 1; - break; - case PERMIT_FORCED_ONLY: -@@ -730,97 +731,6 @@ fakepw(void) - } +@@ -78,6 +79,7 @@ Authmethod *authmethods[] = { + &method_none, + &method_pubkey, + #ifdef GSSAPI ++ &method_gsskeyex, + &method_gssapi, + #endif + &method_passwd, +diff --color -ruNp a/auth2-gss.c b/auth2-gss.c +--- a/auth2-gss.c 2024-09-16 11:45:56.858133241 +0200 ++++ b/auth2-gss.c 2024-09-16 11:46:34.689939776 +0200 +@@ -51,6 +51,7 @@ + #define SSH_GSSAPI_MAX_MECHS 2048 - /* -- * Returns the remote DNS hostname as a string. The returned string must not -- * be freed. NB. this will usually trigger a DNS query the first time it is -- * called. -- * This function does additional checks on the hostname to mitigate some -- * attacks on based on conflation of hostnames and IP addresses. -- */ -- --static char * --remote_hostname(struct ssh *ssh) --{ -- struct sockaddr_storage from; -- socklen_t fromlen; -- struct addrinfo hints, *ai, *aitop; -- char name[NI_MAXHOST], ntop2[NI_MAXHOST]; -- const char *ntop = ssh_remote_ipaddr(ssh); -- -- /* Get IP address of client. */ -- fromlen = sizeof(from); -- memset(&from, 0, sizeof(from)); -- if (getpeername(ssh_packet_get_connection_in(ssh), -- (struct sockaddr *)&from, &fromlen) == -1) { -- debug("getpeername failed: %.100s", strerror(errno)); -- return xstrdup(ntop); -- } -- -- ipv64_normalise_mapped(&from, &fromlen); -- if (from.ss_family == AF_INET6) -- fromlen = sizeof(struct sockaddr_in6); -- -- debug3("Trying to reverse map address %.100s.", ntop); -- /* Map the IP address to a host name. */ -- if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), -- NULL, 0, NI_NAMEREQD) != 0) { -- /* Host name not found. Use ip address. */ -- return xstrdup(ntop); -- } -- -- /* -- * if reverse lookup result looks like a numeric hostname, -- * someone is trying to trick us by PTR record like following: -- * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 -- */ -- memset(&hints, 0, sizeof(hints)); -- hints.ai_socktype = SOCK_DGRAM; /*dummy*/ -- hints.ai_flags = AI_NUMERICHOST; -- if (getaddrinfo(name, NULL, &hints, &ai) == 0) { -- logit("Nasty PTR record \"%s\" is set up for %s, ignoring", -- name, ntop); -- freeaddrinfo(ai); -- return xstrdup(ntop); -- } -- -- /* Names are stored in lowercase. */ -- lowercase(name); -- -- /* -- * Map it back to an IP address and check that the given -- * address actually is an address of this host. This is -- * necessary because anyone with access to a name server can -- * define arbitrary names for an IP address. Mapping from -- * name to IP address can be trusted better (but can still be -- * fooled if the intruder has access to the name server of -- * the domain). -- */ -- memset(&hints, 0, sizeof(hints)); -- hints.ai_family = from.ss_family; -- hints.ai_socktype = SOCK_STREAM; -- if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { -- logit("reverse mapping checking getaddrinfo for %.700s " -- "[%s] failed.", name, ntop); -- return xstrdup(ntop); -- } -- /* Look for the address from the list of addresses. */ -- for (ai = aitop; ai; ai = ai->ai_next) { -- if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, -- sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && -- (strcmp(ntop, ntop2) == 0)) -- break; -- } -- freeaddrinfo(aitop); -- /* If we reached the end of the list, the address was not there. */ -- if (ai == NULL) { -- /* Address not found for the host name. */ -- logit("Address %.100s maps to %.600s, but this does not " -- "map back to the address.", ntop, name); -- return xstrdup(ntop); -- } -- return xstrdup(name); --} -- --/* - * Return the canonical name of the host in the other side of the current - * connection. The host name is cached, so it is efficient to call this - * several times. -diff --git a/auth2-gss.c b/auth2-gss.c -index 9351e042..d6446c0c 100644 ---- a/auth2-gss.c -+++ b/auth2-gss.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: auth2-gss.c,v 1.32 2021/01/27 10:15:08 djm Exp $ */ + extern ServerOptions options; ++extern struct authmethod_cfg methodcfg_gsskeyex; + extern struct authmethod_cfg methodcfg_gssapi; - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -54,6 +54,48 @@ static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh); - static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh); + static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh); +@@ -59,6 +60,48 @@ static int input_gssapi_exchange_complet static int input_gssapi_errtok(int, u_int32_t, struct ssh *); -+/* + /* + * The 'gssapi_keyex' userauth mechanism. + */ +static int -+userauth_gsskeyex(struct ssh *ssh) ++userauth_gsskeyex(struct ssh *ssh, const char *method) +{ + Authctxt *authctxt = ssh->authctxt; + int r, authenticated = 0; @@ -178,10 +62,10 @@ index 9351e042..d6446c0c 100644 + gssbuf.length = sshbuf_len(b); + + /* gss_kex_context is NULL with privsep, so we can't check it here */ -+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -+ &gssbuf, &mic)))) -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); ++ if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gss_kex_context, ++ &gssbuf, &mic))) ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1); + + sshbuf_free(b); + free(mic.value); @@ -189,66 +73,79 @@ index 9351e042..d6446c0c 100644 + return (authenticated); +} + - /* ++/* * We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like) -@@ -260,7 +302,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) + */ +@@ -267,7 +310,7 @@ input_gssapi_exchange_complete(int type, if ((r = sshpkt_get_end(ssh)) != 0) fatal_fr(r, "parse packet"); -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); +- authenticated = mm_ssh_gssapi_userok(authctxt->user); ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, authctxt->pw, 1); - if ((!use_privsep || mm_is_monitor()) && - (displayname = ssh_gssapi_displayname()) != NULL) -@@ -306,7 +349,8 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) + authctxt->postponed = 0; + ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); +@@ -315,7 +358,7 @@ input_gssapi_mic(int type, u_int32_t ple gssbuf.length = sshbuf_len(b); - if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 0)); + if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))) +- authenticated = mm_ssh_gssapi_userok(authctxt->user); ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, authctxt->pw, 0); else logit("GSSAPI MIC check failed"); -@@ -326,6 +370,12 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) +@@ -333,6 +376,11 @@ input_gssapi_mic(int type, u_int32_t ple return 0; } +Authmethod method_gsskeyex = { -+ "gssapi-keyex", ++ &methodcfg_gsskeyex, + userauth_gsskeyex, -+ &options.gss_authentication +}; + Authmethod method_gssapi = { - "gssapi-with-mic", + &methodcfg_gssapi, userauth_gssapi, -diff --git a/auth2.c b/auth2.c -index 0e776224..1c217268 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -73,6 +73,7 @@ extern Authmethod method_passwd; - extern Authmethod method_kbdint; - extern Authmethod method_hostbased; +diff --color -ruNp a/auth2-methods.c b/auth2-methods.c +--- a/auth2-methods.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/auth2-methods.c 2024-09-16 11:46:34.689939776 +0200 +@@ -50,6 +50,11 @@ struct authmethod_cfg methodcfg_pubkey = + &options.pubkey_authentication + }; #ifdef GSSAPI -+extern Authmethod method_gsskeyex; - extern Authmethod method_gssapi; - #endif - -@@ -80,6 +81,7 @@ Authmethod *authmethods[] = { - &method_none, - &method_pubkey, ++struct authmethod_cfg methodcfg_gsskeyex = { ++ "gssapi-keyex", ++ NULL, ++ &options.gss_authentication ++}; + struct authmethod_cfg methodcfg_gssapi = { + "gssapi-with-mic", + NULL, +@@ -76,6 +81,7 @@ static struct authmethod_cfg *authmethod + &methodcfg_none, + &methodcfg_pubkey, #ifdef GSSAPI -+ &method_gsskeyex, - &method_gssapi, ++ &methodcfg_gsskeyex, + &methodcfg_gssapi, #endif - &method_passwd, -diff --git a/canohost.c b/canohost.c -index abea9c6e..8e81b519 100644 ---- a/canohost.c -+++ b/canohost.c + &methodcfg_passwd, +diff --color -ruNp a/auth.c b/auth.c +--- a/auth.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/auth.c 2024-09-16 11:46:34.690939798 +0200 +@@ -356,7 +356,8 @@ auth_root_allowed(struct ssh *ssh, const + case PERMIT_NO_PASSWD: + if (strcmp(method, "publickey") == 0 || + strcmp(method, "hostbased") == 0 || +- strcmp(method, "gssapi-with-mic") == 0) ++ strcmp(method, "gssapi-with-mic") == 0 || ++ strcmp(method, "gssapi-keyex") == 0) + return 1; + break; + case PERMIT_FORCED_ONLY: +diff --color -ruNp a/canohost.c b/canohost.c +--- a/canohost.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/canohost.c 2024-09-16 11:46:34.690939798 +0200 @@ -35,6 +35,99 @@ #include "canohost.h" #include "misc.h" @@ -349,10 +246,9 @@ index abea9c6e..8e81b519 100644 void ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) { -diff --git a/canohost.h b/canohost.h -index 26d62855..0cadc9f1 100644 ---- a/canohost.h -+++ b/canohost.h +diff --color -ruNp a/canohost.h b/canohost.h +--- a/canohost.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/canohost.h 2024-09-16 11:46:34.690939798 +0200 @@ -15,6 +15,9 @@ #ifndef _CANOHOST_H #define _CANOHOST_H @@ -363,11 +259,10 @@ index 26d62855..0cadc9f1 100644 char *get_peer_ipaddr(int); int get_peer_port(int); char *get_local_ipaddr(int); -diff --git a/clientloop.c b/clientloop.c -index ebd0dbca..1bdac6a4 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -112,6 +112,10 @@ +diff --color -ruNp a/clientloop.c b/clientloop.c +--- a/clientloop.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/clientloop.c 2024-09-16 11:46:34.690939798 +0200 +@@ -115,6 +115,10 @@ #include "ssherr.h" #include "hostfile.h" @@ -375,16 +270,12 @@ index ebd0dbca..1bdac6a4 100644 +#include "ssh-gss.h" +#endif + - /* import options */ - extern Options options; + /* Permitted RSA signature algorithms for UpdateHostkeys proofs */ + #define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256" -@@ -1379,9 +1383,18 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, - break; - - /* Do channel operations unless rekeying in progress. */ -- if (!ssh_packet_is_rekeying(ssh)) -+ if (!ssh_packet_is_rekeying(ssh)) { - channel_after_select(ssh, readset, writeset); +@@ -1590,6 +1594,14 @@ client_loop(struct ssh *ssh, int have_pt + /* Do channel operations. */ + channel_after_poll(ssh, pfd, npfd_active); +#ifdef GSSAPI + if (options.gss_renewal_rekey && @@ -393,16 +284,14 @@ index ebd0dbca..1bdac6a4 100644 + need_rekeying = 1; + } +#endif -+ } + /* Buffer input from the connection. */ - client_process_net_input(ssh, readset); - -diff --git a/configure.ac b/configure.ac -index b689db4b..efafb6bd 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -674,6 +674,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) + if (conn_in_ready) + client_process_net_input(ssh); +diff --color -ruNp a/configure.ac b/configure.ac +--- a/configure.ac 2024-09-16 11:45:56.870133497 +0200 ++++ b/configure.ac 2024-09-16 11:46:34.691939819 +0200 +@@ -774,6 +774,30 @@ int main(void) { if (NSVersionOfRunTimeL [Use tunnel device compatibility to OpenBSD]) AC_DEFINE([SSH_TUN_PREPEND_AF], [1], [Prepend the address family to IP tunnel traffic]) @@ -433,20 +322,10 @@ index b689db4b..efafb6bd 100644 m4_pattern_allow([AU_IPv]) AC_CHECK_DECL([AU_IPv4], [], AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) -diff --git a/gss-genr.c b/gss-genr.c -index d56257b4..763a63ff 100644 ---- a/gss-genr.c -+++ b/gss-genr.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: gss-genr.c,v 1.28 2021/01/27 10:05:28 djm Exp $ */ - - /* -- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -41,9 +41,33 @@ +diff --color -ruNp a/gss-genr.c b/gss-genr.c +--- a/gss-genr.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/gss-genr.c 2024-09-16 11:46:34.708940181 +0200 +@@ -42,9 +42,33 @@ #include "sshbuf.h" #include "log.h" #include "ssh2.h" @@ -480,7 +359,7 @@ index d56257b4..763a63ff 100644 /* sshbuf_get for gss_buffer_desc */ int ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) -@@ -62,6 +86,159 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) +@@ -60,6 +84,159 @@ ssh_gssapi_get_buffer_desc(struct sshbuf return 0; } @@ -640,7 +519,28 @@ index d56257b4..763a63ff 100644 /* Check that the OID in a data stream matches that in the context */ int ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) -@@ -218,7 +398,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, +@@ -168,6 +345,7 @@ ssh_gssapi_build_ctx(Gssctxt **ctx) + (*ctx)->creds = GSS_C_NO_CREDENTIAL; + (*ctx)->client = GSS_C_NO_NAME; + (*ctx)->client_creds = GSS_C_NO_CREDENTIAL; ++ (*ctx)->first = 1; + } + + /* Delete our context, providing it has been built correctly */ +@@ -193,6 +371,12 @@ ssh_gssapi_delete_ctx(Gssctxt **ctx) + gss_release_name(&ms, &(*ctx)->client); + if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&ms, &(*ctx)->client_creds); ++ sshbuf_free((*ctx)->shared_secret); ++ sshbuf_free((*ctx)->server_pubkey); ++ sshbuf_free((*ctx)->server_host_key_blob); ++ sshbuf_free((*ctx)->server_blob); ++ explicit_bzero((*ctx)->hash, sizeof((*ctx)->hash)); ++ BN_clear_free((*ctx)->dh_client_pub); + + free(*ctx); + *ctx = NULL; +@@ -216,7 +400,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de } ctx->major = gss_init_sec_context(&ctx->minor, @@ -649,11 +549,10 @@ index d56257b4..763a63ff 100644 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 0, NULL, recv_tok, NULL, send_tok, flags, NULL); -@@ -247,9 +427,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) - return (ctx->major); +@@ -246,8 +430,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con } -+OM_uint32 + OM_uint32 +ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) +{ + gss_buffer_desc gssbuf; @@ -684,7 +583,7 @@ index d56257b4..763a63ff 100644 + return(ctx->major); +} + - OM_uint32 ++OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) { + if (ctx == NULL) @@ -693,7 +592,7 @@ index d56257b4..763a63ff 100644 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, GSS_C_QOP_DEFAULT, buffer, hash))) ssh_gssapi_error(ctx); -@@ -257,6 +471,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) +@@ -255,6 +473,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer return (ctx->major); } @@ -713,7 +612,7 @@ index d56257b4..763a63ff 100644 void ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, const char *context, const struct sshbuf *session_id) -@@ -273,11 +500,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, +@@ -271,11 +502,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, co } int @@ -730,8 +629,8 @@ index d56257b4..763a63ff 100644 + ctx = &intctx; /* RFC 4462 says we MUST NOT do SPNEGO */ - if (oid->length == spnego_oid.length && -@@ -287,6 +519,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) + if (oid->length == spnego_oid.length && +@@ -285,6 +521,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx ssh_gssapi_build_ctx(ctx); ssh_gssapi_set_oid(*ctx, oid); major = ssh_gssapi_import_name(*ctx, host); @@ -740,13 +639,13 @@ index d56257b4..763a63ff 100644 + major = ssh_gssapi_client_identity(*ctx, client); + if (!GSS_ERROR(major)) { - major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, + major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL); -@@ -296,10 +532,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) +@@ -294,10 +534,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx GSS_C_NO_BUFFER); } -- if (GSS_ERROR(major)) +- if (GSS_ERROR(major)) + if (GSS_ERROR(major) || intctx != NULL) ssh_gssapi_delete_ctx(ctx); @@ -810,10 +709,303 @@ index d56257b4..763a63ff 100644 +} + #endif /* GSSAPI */ -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index a151bc1e..8d2b677f 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c +diff --color -ruNp a/gss-serv.c b/gss-serv.c +--- a/gss-serv.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/gss-serv.c 2024-09-16 11:46:34.692939840 +0200 +@@ -1,7 +1,7 @@ + /* $OpenBSD: gss-serv.c,v 1.32 2020/03/13 03:17:07 djm Exp $ */ + + /* +- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. ++ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions +@@ -44,17 +44,19 @@ + #include "session.h" + #include "misc.h" + #include "servconf.h" ++#include "uidswap.h" + + #include "ssh-gss.h" ++#include "monitor_wrap.h" + + extern ServerOptions options; + + static ssh_gssapi_client gssapi_client = +- { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, +- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}}; ++ { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, ++ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0}; + + ssh_gssapi_mech gssapi_null_mech = +- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; ++ { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; + + #ifdef KRB5 + extern ssh_gssapi_mech gssapi_kerberos_mech; +@@ -141,6 +143,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss + } + + /* Unprivileged */ ++char * ++ssh_gssapi_server_mechanisms(void) { ++ if (supported_oids == NULL) ++ ssh_gssapi_prepare_supported_oids(); ++ return (ssh_gssapi_kex_mechs(supported_oids, ++ &ssh_gssapi_server_check_mech, NULL, NULL, ++ options.gss_kex_algorithms)); ++} ++ ++/* Unprivileged */ ++int ++ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, ++ const char *dummy) { ++ Gssctxt *ctx = NULL; ++ int res; ++ ++ res = !GSS_ERROR(mm_ssh_gssapi_server_ctx(&ctx, oid)); ++ ssh_gssapi_delete_ctx(&ctx); ++ ++ return (res); ++} ++ ++/* Unprivileged */ + void + ssh_gssapi_supported_oids(gss_OID_set *oidset) + { +@@ -150,7 +175,9 @@ ssh_gssapi_supported_oids(gss_OID_set *o + gss_OID_set supported; + + gss_create_empty_oid_set(&min_status, oidset); +- gss_indicate_mechs(&min_status, &supported); ++ ++ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) ++ return; + + while (supported_mechs[i]->name != NULL) { + if (GSS_ERROR(gss_test_oid_set_member(&min_status, +@@ -276,8 +303,48 @@ OM_uint32 + ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) + { + int i = 0; ++ int equal = 0; ++ gss_name_t new_name = GSS_C_NO_NAME; ++ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; ++ ++ if (options.gss_store_rekey && client->used && ctx->client_creds) { ++ if (client->mech->oid.length != ctx->oid->length || ++ (memcmp(client->mech->oid.elements, ++ ctx->oid->elements, ctx->oid->length) !=0)) { ++ debug("Rekeyed credentials have different mechanism"); ++ return GSS_S_COMPLETE; ++ } + +- gss_buffer_desc ename; ++ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ++ ctx->client_creds, ctx->oid, &new_name, ++ NULL, NULL, NULL))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ ++ ctx->major = gss_compare_name(&ctx->minor, client->name, ++ new_name, &equal); ++ ++ if (GSS_ERROR(ctx->major)) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ ++ if (!equal) { ++ debug("Rekeyed credentials have different name"); ++ return GSS_S_COMPLETE; ++ } ++ ++ debug("Marking rekeyed credentials for export"); ++ ++ gss_release_name(&ctx->minor, &client->name); ++ gss_release_cred(&ctx->minor, &client->creds); ++ client->name = new_name; ++ client->creds = ctx->client_creds; ++ ctx->client_creds = GSS_C_NO_CREDENTIAL; ++ client->updated = 1; ++ return GSS_S_COMPLETE; ++ } + + client->mech = NULL; + +@@ -292,6 +359,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + if (client->mech == NULL) + return GSS_S_FAILURE; + ++ if (ctx->client_creds && ++ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, ++ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } ++ + if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, + &client->displayname, NULL))) { + ssh_gssapi_error(ctx); +@@ -309,6 +383,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + return (ctx->major); + } + ++ gss_release_buffer(&ctx->minor, &ename); ++ + /* We can't copy this structure, so we just move the pointer to it */ + client->creds = ctx->client_creds; + ctx->client_creds = GSS_C_NO_CREDENTIAL; +@@ -319,11 +395,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_g + void + ssh_gssapi_cleanup_creds(void) + { +- if (gssapi_client.store.filename != NULL) { +- /* Unlink probably isn't sufficient */ +- debug("removing gssapi cred file\"%s\"", +- gssapi_client.store.filename); +- unlink(gssapi_client.store.filename); ++ krb5_ccache ccache = NULL; ++ krb5_error_code problem; ++ ++ if (gssapi_client.store.data != NULL) { ++ if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) { ++ debug_f("krb5_cc_resolve(): %.100s", ++ krb5_get_err_text(gssapi_client.store.data, problem)); ++ } else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) { ++ debug_f("krb5_cc_destroy(): %.100s", ++ krb5_get_err_text(gssapi_client.store.data, problem)); ++ } else { ++ krb5_free_context(gssapi_client.store.data); ++ gssapi_client.store.data = NULL; ++ } + } + } + +@@ -356,19 +441,23 @@ ssh_gssapi_do_child(char ***envp, u_int + + /* Privileged */ + int +-ssh_gssapi_userok(char *user) ++ssh_gssapi_userok(char *user, struct passwd *pw, int kex) + { + OM_uint32 lmin; + ++ (void) kex; /* used in privilege separation */ ++ + if (gssapi_client.exportedname.length == 0 || + gssapi_client.exportedname.value == NULL) { + debug("No suitable client data"); + return 0; + } + if (gssapi_client.mech && gssapi_client.mech->userok) +- if ((*gssapi_client.mech->userok)(&gssapi_client, user)) ++ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { ++ gssapi_client.used = 1; ++ gssapi_client.store.owner = pw; + return 1; +- else { ++ } else { + /* Destroy delegated credentials if userok fails */ + gss_release_buffer(&lmin, &gssapi_client.displayname); + gss_release_buffer(&lmin, &gssapi_client.exportedname); +@@ -382,14 +471,85 @@ ssh_gssapi_userok(char *user) + return (0); + } + +-/* Privileged */ +-OM_uint32 +-ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) ++/* These bits are only used for rekeying. The unpriviledged child is running ++ * as the user, the monitor is root. ++ * ++ * In the child, we want to : ++ * *) Ask the monitor to store our credentials into the store we specify ++ * *) If it succeeds, maybe do a PAM update ++ */ ++ ++/* Stuff for PAM */ ++ ++#ifdef USE_PAM ++static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, ++ struct pam_response **resp, void *data) + { +- ctx->major = gss_verify_mic(&ctx->minor, ctx->context, +- gssbuf, gssmic, NULL); ++ return (PAM_CONV_ERR); ++} ++#endif + +- return (ctx->major); ++void ++ssh_gssapi_rekey_creds(void) { ++ int ok; ++#ifdef USE_PAM ++ int ret; ++ pam_handle_t *pamh = NULL; ++ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; ++ char *envstr; ++#endif ++ ++ if (gssapi_client.store.filename == NULL && ++ gssapi_client.store.envval == NULL && ++ gssapi_client.store.envvar == NULL) ++ return; ++ ++ ok = mm_ssh_gssapi_update_creds(&gssapi_client.store); ++ ++ if (!ok) ++ return; ++ ++ debug("Rekeyed credentials stored successfully"); ++ ++ /* Actually managing to play with the ssh pam stack from here will ++ * be next to impossible. In any case, we may want different options ++ * for rekeying. So, use our own :) ++ */ ++#ifdef USE_PAM ++ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, ++ &pamconv, &pamh); ++ if (ret) ++ return; ++ ++ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, ++ gssapi_client.store.envval); ++ ++ ret = pam_putenv(pamh, envstr); ++ if (!ret) ++ pam_setcred(pamh, PAM_REINITIALIZE_CRED); ++ pam_end(pamh, PAM_SUCCESS); ++#endif ++} ++ ++int ++ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { ++ int ok = 0; ++ ++ /* Check we've got credentials to store */ ++ if (!gssapi_client.updated) ++ return 0; ++ ++ gssapi_client.updated = 0; ++ ++ temporarily_use_uid(gssapi_client.store.owner); ++ if (gssapi_client.mech && gssapi_client.mech->updatecreds) ++ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); ++ else ++ debug("No update function for this mechanism"); ++ ++ restore_uid(); ++ ++ return ok; + } + + /* Privileged */ +diff --color -ruNp a/gss-serv-krb5.c b/gss-serv-krb5.c +--- a/gss-serv-krb5.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/gss-serv-krb5.c 2024-09-16 11:46:34.692939840 +0200 @@ -1,7 +1,7 @@ /* $OpenBSD: gss-serv-krb5.c,v 1.9 2018/07/09 21:37:55 markus Exp $ */ @@ -823,7 +1015,7 @@ index a151bc1e..8d2b677f 100644 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions -@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl krb5_error_code problem; krb5_principal princ; OM_uint32 maj_status, min_status; @@ -832,7 +1024,7 @@ index a151bc1e..8d2b677f 100644 const char *errmsg; if (client->creds == NULL) { -@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl return; } @@ -863,7 +1055,7 @@ index a151bc1e..8d2b677f 100644 #ifdef USE_PAM if (options.use_pam) -@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl krb5_cc_close(krb_context, ccache); @@ -950,504 +1142,67 @@ index a151bc1e..8d2b677f 100644 }; #endif /* KRB5 */ -diff --git a/gss-serv.c b/gss-serv.c -index ab3a15f0..6ce56e92 100644 ---- a/gss-serv.c -+++ b/gss-serv.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: gss-serv.c,v 1.32 2020/03/13 03:17:07 djm Exp $ */ - - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -44,17 +44,19 @@ - #include "session.h" - #include "misc.h" - #include "servconf.h" -+#include "uidswap.h" - - #include "ssh-gss.h" -+#include "monitor_wrap.h" - - extern ServerOptions options; - - static ssh_gssapi_client gssapi_client = -- { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, -- GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL, NULL}}; -+ { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, -+ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0}; - - ssh_gssapi_mech gssapi_null_mech = -- { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL}; -+ { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; - - #ifdef KRB5 - extern ssh_gssapi_mech gssapi_kerberos_mech; -@@ -140,6 +142,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) - return (ssh_gssapi_acquire_cred(*ctx)); - } - -+/* Unprivileged */ -+char * -+ssh_gssapi_server_mechanisms(void) { -+ if (supported_oids == NULL) -+ ssh_gssapi_prepare_supported_oids(); -+ return (ssh_gssapi_kex_mechs(supported_oids, -+ &ssh_gssapi_server_check_mech, NULL, NULL, -+ options.gss_kex_algorithms)); -+} -+ -+/* Unprivileged */ -+int -+ssh_gssapi_server_check_mech(Gssctxt **dum, gss_OID oid, const char *data, -+ const char *dummy) { -+ Gssctxt *ctx = NULL; -+ int res; -+ -+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); -+ ssh_gssapi_delete_ctx(&ctx); -+ -+ return (res); -+} -+ - /* Unprivileged */ - void - ssh_gssapi_supported_oids(gss_OID_set *oidset) -@@ -150,7 +175,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) - gss_OID_set supported; - - gss_create_empty_oid_set(&min_status, oidset); -- gss_indicate_mechs(&min_status, &supported); -+ -+ if (GSS_ERROR(gss_indicate_mechs(&min_status, &supported))) -+ return; - - while (supported_mechs[i]->name != NULL) { - if (GSS_ERROR(gss_test_oid_set_member(&min_status, -@@ -276,8 +303,48 @@ OM_uint32 - ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) +diff --color -ruNp a/kex.c b/kex.c +--- a/kex.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/kex.c 2024-09-16 11:46:34.692939840 +0200 +@@ -297,17 +297,37 @@ static int + kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m) { - int i = 0; -+ int equal = 0; -+ gss_name_t new_name = GSS_C_NO_NAME; -+ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; + int r; ++ int have_key = 0; ++ int ext_count = 2; + -+ if (options.gss_store_rekey && client->used && ctx->client_creds) { -+ if (client->mech->oid.length != ctx->oid->length || -+ (memcmp(client->mech->oid.elements, -+ ctx->oid->elements, ctx->oid->length) !=0)) { -+ debug("Rekeyed credentials have different mechanism"); -+ return GSS_S_COMPLETE; -+ } -+ -+ if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -+ ctx->client_creds, ctx->oid, &new_name, -+ NULL, NULL, NULL))) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } - -- gss_buffer_desc ename; -+ ctx->major = gss_compare_name(&ctx->minor, client->name, -+ new_name, &equal); -+ -+ if (GSS_ERROR(ctx->major)) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ -+ if (!equal) { -+ debug("Rekeyed credentials have different name"); -+ return GSS_S_COMPLETE; -+ } -+ -+ debug("Marking rekeyed credentials for export"); -+ -+ gss_release_name(&ctx->minor, &client->name); -+ gss_release_cred(&ctx->minor, &client->creds); -+ client->name = new_name; -+ client->creds = ctx->client_creds; -+ ctx->client_creds = GSS_C_NO_CREDENTIAL; -+ client->updated = 1; -+ return GSS_S_COMPLETE; -+ } - - client->mech = NULL; - -@@ -292,6 +359,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - if (client->mech == NULL) - return GSS_S_FAILURE; - -+ if (ctx->client_creds && -+ (ctx->major = gss_inquire_cred_by_mech(&ctx->minor, -+ ctx->client_creds, ctx->oid, &client->name, NULL, NULL, NULL))) { -+ ssh_gssapi_error(ctx); -+ return (ctx->major); -+ } -+ - if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, - &client->displayname, NULL))) { - ssh_gssapi_error(ctx); -@@ -309,6 +383,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - return (ctx->major); - } - -+ gss_release_buffer(&ctx->minor, &ename); -+ - /* We can't copy this structure, so we just move the pointer to it */ - client->creds = ctx->client_creds; - ctx->client_creds = GSS_C_NO_CREDENTIAL; -@@ -319,11 +395,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) - void - ssh_gssapi_cleanup_creds(void) - { -- if (gssapi_client.store.filename != NULL) { -- /* Unlink probably isn't sufficient */ -- debug("removing gssapi cred file\"%s\"", -- gssapi_client.store.filename); -- unlink(gssapi_client.store.filename); -+ krb5_ccache ccache = NULL; -+ krb5_error_code problem; -+ -+ if (gssapi_client.store.data != NULL) { -+ if ((problem = krb5_cc_resolve(gssapi_client.store.data, gssapi_client.store.envval, &ccache))) { -+ debug_f("krb5_cc_resolve(): %.100s", -+ krb5_get_err_text(gssapi_client.store.data, problem)); -+ } else if ((problem = krb5_cc_destroy(gssapi_client.store.data, ccache))) { -+ debug_f("krb5_cc_destroy(): %.100s", -+ krb5_get_err_text(gssapi_client.store.data, problem)); -+ } else { -+ krb5_free_context(gssapi_client.store.data); -+ gssapi_client.store.data = NULL; -+ } - } - } - -@@ -356,19 +441,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) - - /* Privileged */ - int --ssh_gssapi_userok(char *user) -+ssh_gssapi_userok(char *user, struct passwd *pw, int kex) - { - OM_uint32 lmin; - -+ (void) kex; /* used in privilege separation */ -+ - if (gssapi_client.exportedname.length == 0 || - gssapi_client.exportedname.value == NULL) { - debug("No suitable client data"); - return 0; - } - if (gssapi_client.mech && gssapi_client.mech->userok) -- if ((*gssapi_client.mech->userok)(&gssapi_client, user)) -+ if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { -+ gssapi_client.used = 1; -+ gssapi_client.store.owner = pw; - return 1; -- else { -+ } else { - /* Destroy delegated credentials if userok fails */ - gss_release_buffer(&lmin, &gssapi_client.displayname); - gss_release_buffer(&lmin, &gssapi_client.exportedname); -@@ -382,14 +471,90 @@ ssh_gssapi_userok(char *user) - return (0); - } - --/* Privileged */ --OM_uint32 --ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) -+/* These bits are only used for rekeying. The unpriviledged child is running -+ * as the user, the monitor is root. -+ * -+ * In the child, we want to : -+ * *) Ask the monitor to store our credentials into the store we specify -+ * *) If it succeeds, maybe do a PAM update -+ */ -+ -+/* Stuff for PAM */ -+ -+#ifdef USE_PAM -+static int ssh_gssapi_simple_conv(int n, const struct pam_message **msg, -+ struct pam_response **resp, void *data) - { -- ctx->major = gss_verify_mic(&ctx->minor, ctx->context, -- gssbuf, gssmic, NULL); -+ return (PAM_CONV_ERR); -+} -+#endif - -- return (ctx->major); -+void -+ssh_gssapi_rekey_creds(void) { -+ int ok; -+#ifdef USE_PAM -+ int ret; -+ pam_handle_t *pamh = NULL; -+ struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; -+ char *envstr; -+#endif -+ -+ if (gssapi_client.store.filename == NULL && -+ gssapi_client.store.envval == NULL && -+ gssapi_client.store.envvar == NULL) -+ return; -+ -+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); -+ -+ if (!ok) -+ return; -+ -+ debug("Rekeyed credentials stored successfully"); -+ -+ /* Actually managing to play with the ssh pam stack from here will -+ * be next to impossible. In any case, we may want different options -+ * for rekeying. So, use our own :) ++#ifdef GSSAPI ++ /* ++ * Currently GSS KEX don't provide host keys as optional message, so ++ * no reasons to announce the publickey-hostbound extension + */ -+#ifdef USE_PAM -+ if (!use_privsep) { -+ debug("Not even going to try and do PAM with privsep disabled"); -+ return; ++ if (ssh->kex->gss == NULL) ++ have_key = 1; ++#endif ++ ext_count += have_key; ++ + + if (ssh->kex->server_sig_algs == NULL && + (ssh->kex->server_sig_algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) + return SSH_ERR_ALLOC_FAIL; +- if ((r = sshbuf_put_u32(m, 3)) != 0 || ++ if ((r = sshbuf_put_u32(m, ext_count)) != 0 || + (r = sshbuf_put_cstring(m, "server-sig-algs")) != 0 || +- (r = sshbuf_put_cstring(m, ssh->kex->server_sig_algs)) != 0 || +- (r = sshbuf_put_cstring(m, +- "publickey-hostbound@openssh.com")) != 0 || +- (r = sshbuf_put_cstring(m, "0")) != 0 || +- (r = sshbuf_put_cstring(m, "ping@openssh.com")) != 0 || ++ (r = sshbuf_put_cstring(m, ssh->kex->server_sig_algs)) != 0) { ++ error_fr(r, "compose"); ++ return r; + } -+ -+ ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, -+ &pamconv, &pamh); -+ if (ret) -+ return; -+ -+ xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, -+ gssapi_client.store.envval); -+ -+ ret = pam_putenv(pamh, envstr); -+ if (!ret) -+ pam_setcred(pamh, PAM_REINITIALIZE_CRED); -+ pam_end(pamh, PAM_SUCCESS); -+#endif -+} -+ -+int -+ssh_gssapi_update_creds(ssh_gssapi_ccache *store) { -+ int ok = 0; -+ -+ /* Check we've got credentials to store */ -+ if (!gssapi_client.updated) -+ return 0; -+ -+ gssapi_client.updated = 0; -+ -+ temporarily_use_uid(gssapi_client.store.owner); -+ if (gssapi_client.mech && gssapi_client.mech->updatecreds) -+ ok = (*gssapi_client.mech->updatecreds)(store, &gssapi_client); -+ else -+ debug("No update function for this mechanism"); -+ -+ restore_uid(); -+ -+ return ok; - } - - /* Privileged */ -diff --git a/kex.c b/kex.c -index ce85f043..574c7609 100644 ---- a/kex.c -+++ b/kex.c -@@ -57,11 +57,16 @@ - #include "misc.h" - #include "dispatch.h" - #include "monitor.h" -+#include "xmalloc.h" - - #include "ssherr.h" - #include "sshbuf.h" - #include "digest.h" - -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - /* prototype */ - static int kex_choose_conf(struct ssh *); - static int kex_input_newkeys(int, u_int32_t, struct ssh *); -@@ -115,15 +120,28 @@ static const struct kexalg kexalgs[] = { - #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ - { NULL, 0, -1, -1}, - }; -+static const struct kexalg gss_kexalgs[] = { -+#ifdef GSSAPI -+ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, -+ { KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, -+ { KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, -+ { KEX_GSS_NISTP256_SHA256_ID, KEX_GSS_NISTP256_SHA256, -+ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, -+ { KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, -+#endif -+ { NULL, 0, -1, -1}, -+}; - --char * --kex_alg_list(char sep) -+static char * -+kex_alg_list_internal(char sep, const struct kexalg *algs) - { - char *ret = NULL, *tmp; - size_t nlen, rlen = 0; - const struct kexalg *k; - -- for (k = kexalgs; k->name != NULL; k++) { -+ for (k = algs; k->name != NULL; k++) { - if (ret != NULL) - ret[rlen++] = sep; - nlen = strlen(k->name); -@@ -138,6 +156,18 @@ kex_alg_list(char sep) - return ret; - } - -+char * -+kex_alg_list(char sep) -+{ -+ return kex_alg_list_internal(sep, kexalgs); -+} -+ -+char * -+kex_gss_alg_list(char sep) -+{ -+ return kex_alg_list_internal(sep, gss_kexalgs); -+} -+ - static const struct kexalg * - kex_alg_by_name(const char *name) - { -@@ -147,6 +177,10 @@ kex_alg_by_name(const char *name) - if (strcmp(k->name, name) == 0) - return k; - } -+ for (k = gss_kexalgs; k->name != NULL; k++) { -+ if (strncmp(k->name, name, strlen(k->name)) == 0) -+ return k; -+ } - return NULL; - } - -@@ -315,6 +349,29 @@ kex_assemble_names(char **listp, const char *def, const char *all) - return r; - } - -+/* Validate GSS KEX method name list */ -+int -+kex_gss_names_valid(const char *names) -+{ -+ char *s, *cp, *p; -+ -+ if (names == NULL || *names == '\0') -+ return 0; -+ s = cp = xstrdup(names); -+ for ((p = strsep(&cp, ",")); p && *p != '\0'; -+ (p = strsep(&cp, ","))) { -+ if (strncmp(p, "gss-", 4) != 0 -+ || kex_alg_by_name(p) == NULL) { -+ error("Unsupported KEX algorithm \"%.100s\"", p); -+ free(s); -+ return 0; ++ if (have_key) { ++ if ((r = sshbuf_put_cstring(m, "publickey-hostbound@openssh.com")) != 0 || ++ (r = sshbuf_put_cstring(m, "0")) != 0) { ++ error_fr(r, "compose"); ++ return r; + } + } -+ debug3("gss kex names ok: [%s]", names); -+ free(s); -+ return 1; -+} -+ - /* put algorithm proposal into buffer */ - int - kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) -@@ -698,6 +755,9 @@ kex_free(struct kex *kex) ++ if ((r = sshbuf_put_cstring(m, "ping@openssh.com")) != 0 || + (r = sshbuf_put_cstring(m, "0")) != 0) { + error_fr(r, "compose"); + return r; +@@ -737,6 +757,9 @@ kex_free(struct kex *kex) sshbuf_free(kex->server_version); sshbuf_free(kex->client_pub); sshbuf_free(kex->session_id); +#ifdef GSSAPI + free(kex->gss_host); +#endif /* GSSAPI */ + sshbuf_free(kex->initial_sig); + sshkey_free(kex->initial_hostkey); free(kex->failed_choice); - free(kex->hostkey_alg); - free(kex->name); -diff --git a/kex.h b/kex.h -index a5ae6ac0..fe714141 100644 ---- a/kex.h -+++ b/kex.h -@@ -102,6 +102,15 @@ enum kex_exchange { - KEX_ECDH_SHA2, - KEX_C25519_SHA256, - KEX_KEM_SNTRUP761X25519_SHA512, -+#ifdef GSSAPI -+ KEX_GSS_GRP1_SHA1, -+ KEX_GSS_GRP14_SHA1, -+ KEX_GSS_GRP14_SHA256, -+ KEX_GSS_GRP16_SHA512, -+ KEX_GSS_GEX_SHA1, -+ KEX_GSS_NISTP256_SHA256, -+ KEX_GSS_C25519_SHA256, -+#endif - KEX_MAX - }; - -@@ -153,6 +162,12 @@ struct kex { - u_int flags; - int hash_alg; - int ec_nid; -+#ifdef GSSAPI -+ int gss_deleg_creds; -+ int gss_trust_dns; -+ char *gss_host; -+ char *gss_client; -+#endif - char *failed_choice; - int (*verify_host_key)(struct sshkey *, struct ssh *); - struct sshkey *(*load_host_public_key)(int, int, struct ssh *); -@@ -174,8 +189,10 @@ struct kex { - - int kex_names_valid(const char *); - char *kex_alg_list(char); -+char *kex_gss_alg_list(char); - char *kex_names_cat(const char *, const char *); - int kex_assemble_names(char **, const char *, const char *); -+int kex_gss_names_valid(const char *); - - int kex_exchange_identification(struct ssh *, int, const char *); - -@@ -202,6 +219,12 @@ int kexgex_client(struct ssh *); - int kexgex_server(struct ssh *); - int kex_gen_client(struct ssh *); - int kex_gen_server(struct ssh *); -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+int kexgssgex_client(struct ssh *); -+int kexgssgex_server(struct ssh *); -+int kexgss_client(struct ssh *); -+int kexgss_server(struct ssh *); -+#endif - - int kex_dh_keypair(struct kex *); - int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, -@@ -234,6 +257,12 @@ int kexgex_hash(int, const struct sshbuf *, const struct sshbuf *, - const BIGNUM *, const u_char *, size_t, - u_char *, size_t *); - -+int kex_gen_hash(int hash_alg, const struct sshbuf *client_version, -+ const struct sshbuf *server_version, const struct sshbuf *client_kexinit, -+ const struct sshbuf *server_kexinit, const struct sshbuf *server_host_key_blob, -+ const struct sshbuf *client_pub, const struct sshbuf *server_pub, -+ const struct sshbuf *shared_secret, u_char *hash, size_t *hashlen); -+ - void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) - __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) - __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); -diff --git a/kexdh.c b/kexdh.c -index 67133e33..edaa4676 100644 ---- a/kexdh.c -+++ b/kexdh.c -@@ -48,13 +48,23 @@ kex_dh_keygen(struct kex *kex) +diff --color -ruNp a/kexdh.c b/kexdh.c +--- a/kexdh.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/kexdh.c 2024-09-16 11:46:34.693939862 +0200 +@@ -49,13 +49,23 @@ kex_dh_keygen(struct kex *kex) { switch (kex->kex_type) { case KEX_DH_GRP1_SHA1: @@ -1471,10 +1226,9 @@ index 67133e33..edaa4676 100644 kex->dh = dh_new_group16(); break; case KEX_DH_GRP18_SHA512: -diff --git a/kexgen.c b/kexgen.c -index 69348b96..c0e8c2f4 100644 ---- a/kexgen.c -+++ b/kexgen.c +diff --color -ruNp a/kexgen.c b/kexgen.c +--- a/kexgen.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/kexgen.c 2024-09-16 11:46:34.693939862 +0200 @@ -44,7 +44,7 @@ static int input_kex_gen_init(int, u_int32_t, struct ssh *); static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh); @@ -1484,12 +1238,10 @@ index 69348b96..c0e8c2f4 100644 kex_gen_hash( int hash_alg, const struct sshbuf *client_version, -diff --git a/kexgssc.c b/kexgssc.c -new file mode 100644 -index 00000000..f6e1405e ---- /dev/null -+++ b/kexgssc.c -@@ -0,0 +1,611 @@ +diff --color -ruNp a/kexgssc.c b/kexgssc.c +--- a/kexgssc.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/kexgssc.c 2024-10-14 15:18:02.491798105 +0200 +@@ -0,0 +1,706 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1539,38 +1291,206 @@ index 00000000..f6e1405e + +#include "ssh-gss.h" + ++static int input_kexgss_hostkey(int, u_int32_t, struct ssh *); ++static int input_kexgss_continue(int, u_int32_t, struct ssh *); ++static int input_kexgss_complete(int, u_int32_t, struct ssh *); ++static int input_kexgss_error(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_group(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_continue(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_complete(int, u_int32_t, struct ssh *); ++ ++static int ++kexgss_final(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ struct sshbuf *empty = NULL; ++ struct sshbuf *shared_secret = NULL; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ int r; ++ ++ /* ++ * We _must_ have received a COMPLETE message in reply from the ++ * server, which will have set server_blob and msg_tok ++ */ ++ ++ /* compute shared secret */ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ case KEX_GSS_GRP14_SHA1: ++ case KEX_GSS_GRP14_SHA256: ++ case KEX_GSS_GRP16_SHA512: ++ r = kex_dh_dec(kex, gss->server_blob, &shared_secret); ++ break; ++ case KEX_GSS_C25519_SHA256: ++ if (sshbuf_ptr(gss->server_blob)[sshbuf_len(gss->server_blob)] & 0x80) ++ fatal("The received key has MSB of last octet set!"); ++ r = kex_c25519_dec(kex, gss->server_blob, &shared_secret); ++ break; ++ case KEX_GSS_NISTP256_SHA256: ++ if (sshbuf_len(gss->server_blob) != 65) ++ fatal("The received NIST-P256 key did not match " ++ "expected length (expected 65, got %zu)", ++ sshbuf_len(gss->server_blob)); ++ ++ if (sshbuf_ptr(gss->server_blob)[0] != POINT_CONVERSION_UNCOMPRESSED) ++ fatal("The received NIST-P256 key does not have first octet 0x04"); ++ ++ r = kex_ecdh_dec(kex, gss->server_blob, &shared_secret); ++ break; ++ default: ++ r = SSH_ERR_INVALID_ARGUMENT; ++ break; ++ } ++ if (r != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ goto out; ++ } ++ ++ if ((empty = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ hashlen = sizeof(hash); ++ r = kex_gen_hash(kex->hash_alg, kex->client_version, ++ kex->server_version, kex->my, kex->peer, ++ (gss->server_host_key_blob ? gss->server_host_key_blob : empty), ++ kex->client_pub, gss->server_blob, shared_secret, ++ hash, &hashlen); ++ sshbuf_free(empty); ++ if (r != 0) ++ fatal_f("Unexpected KEX type %d", kex->kex_type); ++ ++ gss->buf.value = hash; ++ gss->buf.length = hashlen; ++ ++ /* Verify that the hash matches the MIC we just got. */ ++ if (GSS_ERROR(ssh_gssapi_checkmic(gss, &gss->buf, &gss->msg_tok))) ++ sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); ++ ++ gss_release_buffer(&gss->minor, &gss->msg_tok); ++ ++ if (kex->gss_deleg_creds) ++ ssh_gssapi_credentials_updated(gss); ++ ++ if (gss_kex_context == NULL) ++ gss_kex_context = gss; ++ else ++ ssh_gssapi_delete_ctx(&kex->gss); ++ ++ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) ++ r = kex_send_newkeys(ssh); ++ ++ if (kex->gss != NULL) { ++ sshbuf_free(gss->server_host_key_blob); ++ gss->server_host_key_blob = NULL; ++ sshbuf_free(gss->server_blob); ++ gss->server_blob = NULL; ++ } ++out: ++ explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); ++ explicit_bzero(hash, sizeof(hash)); ++ sshbuf_free(shared_secret); ++ sshbuf_free(kex->client_pub); ++ kex->client_pub = NULL; ++ return r; ++} ++ ++static int ++kexgss_init_ctx(struct ssh *ssh, ++ gss_buffer_desc *token_ptr) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags; ++ int r; ++ ++ debug("Calling gss_init_sec_context"); ++ ++ gss->major = ssh_gssapi_init_ctx(gss, kex->gss_deleg_creds, ++ token_ptr, &send_tok, &ret_flags); ++ ++ if (GSS_ERROR(gss->major)) { ++ /* XXX Useless code: Missing send? */ ++ if (send_tok.length != 0) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ fatal("gss_init_context failed"); ++ } ++ ++ /* If we've got an old receive buffer get rid of it */ ++ if (token_ptr != GSS_C_NO_BUFFER) ++ gss_release_buffer(&gss->minor, token_ptr); ++ ++ if (gss->major == GSS_S_COMPLETE) { ++ /* If mutual state flag is not true, kex fails */ ++ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual authentication failed"); ++ ++ /* If integ avail flag is not true kex fails */ ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity check failed"); ++ } ++ ++ /* ++ * If we have data to send, then the last message that we ++ * received cannot have been a 'complete'. ++ */ ++ if (send_tok.length != 0) { ++ if (gss->first) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || ++ (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ gss->first = 0; ++ } else { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ } ++ if ((r = sshpkt_send(ssh)) != 0) ++ fatal("failed to send packet: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, &send_tok); ++ ++ /* If we've sent them data, they should reply */ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, &input_kexgss_hostkey); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgss_continue); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, &input_kexgss_complete); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, &input_kexgss_error); ++ return 0; ++ } ++ /* No data, and not complete */ ++ if (gss->major != GSS_S_COMPLETE) ++ fatal("Not complete, and no token output"); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgss_init_ctx(ssh, token_ptr); ++ ++ return kexgss_final(ssh); ++} ++ +int +kexgss_client(struct ssh *ssh) +{ + struct kex *kex = ssh->kex; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER, -+ recv_tok = GSS_C_EMPTY_BUFFER, -+ gssbuf, msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ struct sshbuf *server_blob = NULL; -+ struct sshbuf *shared_secret = NULL; -+ struct sshbuf *server_host_key_blob = NULL; -+ struct sshbuf *empty = NULL; -+ u_char *msg; -+ int type = 0; -+ int first = 1; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ u_char c; + int r; + + /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (ssh_gssapi_id_kex(kex->gss, kex->name, kex->kex_type) == GSS_C_NO_OID) + fatal("Couldn't identify host exchange"); + -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) ++ if (ssh_gssapi_import_name(kex->gss, kex->gss_host)) + fatal("Couldn't import hostname"); + + if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) ++ ssh_gssapi_client_identity(kex->gss, kex->gss_client)) + fatal("Couldn't acquire client credentials"); + + /* Step 1 */ @@ -1591,522 +1511,447 @@ index 00000000..f6e1405e + fatal_f("Unexpected KEX type %d", kex->kex_type); + } + if (r != 0) { -+ ssh_gssapi_delete_ctx(&ctxt); ++ ssh_gssapi_delete_ctx(&kex->gss); + return r; + } ++ return kexgss_init_ctx(ssh, GSS_C_NO_BUFFER); ++} + -+ token_ptr = GSS_C_NO_BUFFER; ++static int ++input_kexgss_hostkey(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ u_char *tmp = NULL; ++ size_t tmp_len = 0; ++ int r; + -+ do { -+ debug("Calling gss_init_sec_context"); ++ debug("Received KEXGSS_HOSTKEY"); ++ if (gss->server_host_key_blob) ++ fatal("Server host key received more than once"); ++ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) ++ fatal("Failed to read server host key: %s", ssh_err(r)); ++ if ((gss->server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) ++ fatal("sshbuf_from failed"); ++ return 0; ++} + -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); ++static int ++input_kexgss_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ int r; + -+ if (GSS_ERROR(maj_status)) { -+ /* XXX Useles code: Missing send? */ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_start(ssh, -+ SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("gss_init_context failed"); -+ } ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); + -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ gss_release_buffer(&min_status, &recv_tok); ++ debug("Received GSSAPI_CONTINUE"); ++ if (gss->major == GSS_S_COMPLETE) ++ fatal("GSSAPI Continue received from server when complete"); ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ if (!(gss->major & GSS_S_CONTINUE_NEEDED)) ++ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); ++ return kexgss_init_ctx(ssh, &recv_tok); ++} + -+ if (maj_status == GSS_S_COMPLETE) { -+ /* If mutual state flag is not true, kex fails */ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual authentication failed"); ++static int ++input_kexgss_complete(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ u_char c; ++ int r; + -+ /* If integ avail flag is not true kex fails */ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity check failed"); -+ } ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); + -+ /* -+ * If we have data to send, then the last message that we -+ * received cannot have been a 'complete'. -+ */ -+ if (send_tok.length != 0) { -+ if (first) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0 || -+ (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0) -+ fatal("failed to construct packet: %s", ssh_err(r)); -+ first = 0; -+ } else { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("failed to construct packet: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("failed to send packet: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); ++ debug("Received GSSAPI_COMPLETE"); ++ if (gss->msg_tok.value != NULL) ++ fatal("Received GSSAPI_COMPLETE twice?"); ++ if ((r = sshpkt_getb_froms(ssh, &gss->server_blob)) != 0 || ++ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &gss->msg_tok)) != 0) ++ fatal("Failed to read message: %s", ssh_err(r)); + -+ /* If we've sent them data, they should reply */ -+ do { -+ type = ssh_packet_read(ssh); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ char *tmp = NULL; -+ size_t tmp_len = 0; ++ /* Is there a token included? */ ++ if ((r = sshpkt_get_u8(ssh, &c)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ if (c) { ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ /* If we're already complete - protocol error */ ++ if (gss->major == GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); ++ } else { ++ if (gss->major != GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); ++ } ++ if ((r = sshpkt_get_end(ssh)) != 0) ++ fatal("Expecting end of packet."); + -+ debug("Received KEXGSS_HOSTKEY"); -+ if (server_host_key_blob) -+ fatal("Server host key received more than once"); -+ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) -+ fatal("Failed to read server host key: %s", ssh_err(r)); -+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) -+ fatal("sshbuf_from failed"); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgss_init_ctx(ssh, &recv_tok); + -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("Failed to read token: %s", ssh_err(r)); -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ if (msg_tok.value != NULL) -+ fatal("Received GSSAPI_COMPLETE twice?"); -+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || -+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &msg_tok)) != 0) -+ fatal("Failed to read message: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ return kexgss_final(ssh); ++} + -+ /* Is there a token included? */ -+ if ((r = sshpkt_get_u8(ssh, &c)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if (c) { -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc( -+ ssh, &recv_tok)) != 0) -+ fatal("Failed to read token: %s", ssh_err(r)); -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); -+ } -+ if ((r = sshpkt_get_end(ssh)) != 0) { -+ fatal("Expecting end of packet."); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 || -+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || -+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt_get failed: %s", ssh_err(r)); -+ fatal("GSSAPI Error: \n%.400s", msg); -+ default: -+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); ++static int ++input_kexgss_error(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ u_char *msg; ++ int r; ++ ++ debug("Received Error"); ++ if ((r = sshpkt_get_u32(ssh, &gss->major)) != 0 || ++ (r = sshpkt_get_u32(ssh, &gss->minor)) != 0 || ++ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || ++ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt_get failed: %s", ssh_err(r)); ++ fatal("GSSAPI Error: \n%.400s", msg); ++ return 0; ++} ++ ++/*******************************************************/ ++/******************** KEXGSSGEX ************************/ ++/*******************************************************/ ++ ++int ++kexgssgex_client(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ int r; ++ ++ /* Initialise our GSSAPI world */ ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (ssh_gssapi_id_kex(kex->gss, kex->name, kex->kex_type) == GSS_C_NO_OID) ++ fatal("Couldn't identify host exchange"); ++ ++ if (ssh_gssapi_import_name(kex->gss, kex->gss_host)) ++ fatal("Couldn't import hostname"); ++ ++ if (kex->gss_client && ++ ssh_gssapi_client_identity(kex->gss, kex->gss_client)) ++ fatal("Couldn't acquire client credentials"); ++ ++ debug("Doing group exchange"); ++ kex->min = DH_GRP_MIN; ++ kex->max = DH_GRP_MAX; ++ kex->nbits = dh_estimate(kex->dh_need * 8); ++ ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->min)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->max)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("Failed to construct a packet: %s", ssh_err(r)); ++ ++ debug("Wait SSH2_MSG_KEXGSS_GROUP"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUP, &input_kexgssgex_group); ++ return 0; ++} ++ ++static int ++kexgssgex_final(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ struct sshbuf *buf = NULL; ++ struct sshbuf *empty = NULL; ++ struct sshbuf *shared_secret = NULL; ++ BIGNUM *dh_server_pub = NULL; ++ const BIGNUM *pub_key, *dh_p, *dh_g; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ int r = SSH_ERR_INTERNAL_ERROR; + + /* + * We _must_ have received a COMPLETE message in reply from the + * server, which will have set server_blob and msg_tok + */ + -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) -+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); -+ -+ /* compute shared secret */ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_dec(kex, server_blob, &shared_secret); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ if (sshbuf_ptr(server_blob)[sshbuf_len(server_blob)] & 0x80) -+ fatal("The received key has MSB of last octet set!"); -+ r = kex_c25519_dec(kex, server_blob, &shared_secret); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ if (sshbuf_len(server_blob) != 65) -+ fatal("The received NIST-P256 key did not match" -+ "expected length (expected 65, got %zu)", sshbuf_len(server_blob)); -+ -+ if (sshbuf_ptr(server_blob)[0] != POINT_CONVERSION_UNCOMPRESSED) -+ fatal("The received NIST-P256 key does not have first octet 0x04"); -+ -+ r = kex_ecdh_dec(kex, server_blob, &shared_secret); -+ break; -+ default: -+ r = SSH_ERR_INVALID_ARGUMENT; -+ break; -+ } -+ if (r != 0) ++ /* 7. C verifies that the key Q_S is valid */ ++ /* 8. C computes shared secret */ ++ if ((buf = sshbuf_new()) == NULL || ++ (r = sshbuf_put_stringb(buf, gss->server_blob)) != 0 || ++ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); + goto out; ++ } ++ sshbuf_free(buf); ++ buf = NULL; + -+ if ((empty = sshbuf_new()) == NULL) { ++ if ((shared_secret = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->my, -+ kex->peer, -+ (server_host_key_blob ? server_host_key_blob : empty), -+ kex->client_pub, -+ server_blob, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ fatal_f("Unexpected KEX type %d", kex->kex_type); ++ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ goto out; ++ } + -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; ++ if ((empty = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); ++ hashlen = sizeof(hash); ++ r = kexgex_hash(kex->hash_alg, kex->client_version, ++ kex->server_version, kex->my, kex->peer, ++ (gss->server_host_key_blob ? gss->server_host_key_blob : empty), ++ kex->min, kex->nbits, kex->max, dh_p, dh_g, pub_key, ++ dh_server_pub, sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), ++ hash, &hashlen); ++ sshbuf_free(empty); ++ if (r != 0) ++ fatal("Failed to calculate hash: %s", ssh_err(r)); ++ ++ gss->buf.value = hash; ++ gss->buf.length = hashlen; + + /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) ++ if (GSS_ERROR(ssh_gssapi_checkmic(gss, &gss->buf, &gss->msg_tok))) + sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); + -+ gss_release_buffer(&min_status, &msg_tok); ++ gss_release_buffer(&gss->minor, &gss->msg_tok); + + if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); ++ ssh_gssapi_credentials_updated(gss); + + if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; ++ gss_kex_context = gss; + else -+ ssh_gssapi_delete_ctx(&ctxt); ++ ssh_gssapi_delete_ctx(&kex->gss); + ++ /* Finally derive the keys and send them */ + if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); + ++ if (kex->gss != NULL) { ++ sshbuf_free(gss->server_host_key_blob); ++ gss->server_host_key_blob = NULL; ++ sshbuf_free(gss->server_blob); ++ gss->server_blob = NULL; ++ } +out: + explicit_bzero(hash, sizeof(hash)); -+ explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); -+ sshbuf_free(empty); -+ sshbuf_free(server_host_key_blob); -+ sshbuf_free(server_blob); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ BN_clear_free(dh_server_pub); + sshbuf_free(shared_secret); -+ sshbuf_free(kex->client_pub); -+ kex->client_pub = NULL; + return r; +} + -+int -+kexgssgex_client(struct ssh *ssh) ++static int ++kexgssgex_init_ctx(struct ssh *ssh, ++ gss_buffer_desc *token_ptr) +{ + struct kex *kex = ssh->kex; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER, -+ recv_tok = GSS_C_EMPTY_BUFFER, gssbuf, -+ msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ struct sshbuf *shared_secret = NULL; -+ BIGNUM *p = NULL; -+ BIGNUM *g = NULL; -+ struct sshbuf *buf = NULL; -+ struct sshbuf *server_host_key_blob = NULL; -+ struct sshbuf *server_blob = NULL; -+ BIGNUM *dh_server_pub = NULL; -+ u_char *msg; -+ int type = 0; -+ int first = 1; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ const BIGNUM *pub_key, *dh_p, *dh_g; -+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; -+ struct sshbuf *empty = NULL; -+ u_char c; ++ Gssctxt *gss = kex->gss; ++ const BIGNUM *pub_key; ++ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags; + int r; + -+ /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) -+ fatal("Couldn't identify host exchange"); ++ /* Step 2 - call GSS_Init_sec_context() */ ++ debug("Calling gss_init_sec_context"); + -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) -+ fatal("Couldn't import hostname"); ++ gss->major = ssh_gssapi_init_ctx(gss, kex->gss_deleg_creds, ++ token_ptr, &send_tok, &ret_flags); + -+ if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) -+ fatal("Couldn't acquire client credentials"); ++ if (GSS_ERROR(gss->major)) { ++ /* XXX Useless code: Missing send? */ ++ if (send_tok.length != 0) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ fatal("gss_init_context failed"); ++ } + -+ debug("Doing group exchange"); -+ nbits = dh_estimate(kex->dh_need * 8); ++ /* If we've got an old receive buffer get rid of it */ ++ if (token_ptr != GSS_C_NO_BUFFER) ++ gss_release_buffer(&gss->minor, token_ptr); + -+ kex->min = DH_GRP_MIN; -+ kex->max = DH_GRP_MAX; -+ kex->nbits = nbits; -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 || -+ (r = sshpkt_put_u32(ssh, min)) != 0 || -+ (r = sshpkt_put_u32(ssh, nbits)) != 0 || -+ (r = sshpkt_put_u32(ssh, max)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("Failed to construct a packet: %s", ssh_err(r)); ++ if (gss->major == GSS_S_COMPLETE) { ++ /* If mutual state flag is not true, kex fails */ ++ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual authentication failed"); + -+ if ((r = ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0) -+ fatal("Error: %s", ssh_err(r)); ++ /* If integ avail flag is not true kex fails */ ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity check failed"); ++ } ++ ++ /* ++ * If we have data to send, then the last message that we ++ * received cannot have been a 'complete'. ++ */ ++ if (send_tok.length != 0) { ++ if (gss->first) { ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ gss->first = 0; ++ } else { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ } ++ if ((r = sshpkt_send(ssh)) != 0) ++ fatal("failed to send packet: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, &send_tok); ++ ++ /* If we've sent them data, they should reply */ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, &input_kexgss_hostkey); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgssgex_continue); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, &input_kexgssgex_complete); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, &input_kexgss_error); ++ return 0; ++ } ++ /* No data, and not complete */ ++ if (gss->major != GSS_S_COMPLETE) ++ fatal("Not complete, and no token output"); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgssgex_init_ctx(ssh, token_ptr); ++ ++ return kexgssgex_final(ssh); ++} ++ ++static int ++input_kexgssgex_group(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ BIGNUM *p = NULL; ++ BIGNUM *g = NULL; ++ int r; ++ ++ debug("Received SSH2_MSG_KEXGSS_GROUP"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUP, NULL); + + if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 || + (r = sshpkt_get_bignum2(ssh, &g)) != 0 || + (r = sshpkt_get_end(ssh)) != 0) + fatal("shpkt_get_bignum2 failed: %s", ssh_err(r)); + -+ if (BN_num_bits(p) < min || BN_num_bits(p) > max) ++ if (BN_num_bits(p) < kex->min || BN_num_bits(p) > kex->max) + fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", -+ min, BN_num_bits(p), max); ++ kex->min, BN_num_bits(p), kex->max); + + if ((kex->dh = dh_new_group(g, p)) == NULL) + fatal("dn_new_group() failed"); + p = g = NULL; /* belong to kex->dh now */ + -+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) -+ goto out; -+ DH_get0_key(kex->dh, &pub_key, NULL); -+ -+ token_ptr = GSS_C_NO_BUFFER; -+ -+ do { -+ /* Step 2 - call GSS_Init_sec_context() */ -+ debug("Calling gss_init_sec_context"); -+ -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); -+ -+ if (GSS_ERROR(maj_status)) { -+ /* XXX Useles code: Missing send? */ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_start(ssh, -+ SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("gss_init_context failed"); -+ } -+ -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ gss_release_buffer(&min_status, &recv_tok); -+ -+ if (maj_status == GSS_S_COMPLETE) { -+ /* If mutual state flag is not true, kex fails */ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual authentication failed"); -+ -+ /* If integ avail flag is not true kex fails */ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity check failed"); -+ } -+ -+ /* -+ * If we have data to send, then the last message that we -+ * received cannot have been a 'complete'. -+ */ -+ if (send_tok.length != 0) { -+ if (first) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ first = 0; -+ } else { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh,send_tok.value, -+ send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt_send failed: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ -+ /* If we've sent them data, they should reply */ -+ do { -+ type = ssh_packet_read(ssh); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ char *tmp = NULL; -+ size_t tmp_len = 0; -+ -+ debug("Received KEXGSS_HOSTKEY"); -+ if (server_host_key_blob) -+ fatal("Server host key received more than once"); -+ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) -+ fatal("sshbuf_from failed"); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); -+ -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ if (msg_tok.value != NULL) -+ fatal("Received GSSAPI_COMPLETE twice?"); -+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || -+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &msg_tok)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ /* Is there a token included? */ -+ if ((r = sshpkt_get_u8(ssh, &c)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if (c) { -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc( -+ ssh, &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 || -+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || -+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ fatal("GSSAPI Error: \n%.400s", msg); -+ default: -+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ /* -+ * We _must_ have received a COMPLETE message in reply from the -+ * server, which will have set dh_server_pub and msg_tok -+ */ -+ -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) -+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); -+ -+ /* 7. C verifies that the key Q_S is valid */ -+ /* 8. C computes shared secret */ -+ if ((buf = sshbuf_new()) == NULL || -+ (r = sshbuf_put_stringb(buf, server_blob)) != 0 || -+ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0) -+ goto out; -+ sshbuf_free(buf); -+ buf = NULL; -+ -+ if ((shared_secret = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; ++ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ return r; + } + -+ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) -+ goto out; -+ if ((empty = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); -+ hashlen = sizeof(hash); -+ if ((r = kexgex_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->my, -+ kex->peer, -+ (server_host_key_blob ? server_host_key_blob : empty), -+ kex->min, kex->nbits, kex->max, -+ dh_p, dh_g, -+ pub_key, -+ dh_server_pub, -+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), -+ hash, &hashlen)) != 0) -+ fatal("Failed to calculate hash: %s", ssh_err(r)); -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) -+ sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); -+ -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ /* Finally derive the keys and send them */ -+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) -+ r = kex_send_newkeys(ssh); -+out: -+ sshbuf_free(buf); -+ sshbuf_free(server_blob); -+ sshbuf_free(empty); -+ explicit_bzero(hash, sizeof(hash)); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ BN_clear_free(dh_server_pub); -+ sshbuf_free(shared_secret); -+ sshbuf_free(server_host_key_blob); -+ return r; ++ return kexgssgex_init_ctx(ssh, GSS_C_NO_BUFFER); +} ++ ++static int ++input_kexgssgex_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ int r; ++ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); ++ ++ debug("Received GSSAPI_CONTINUE"); ++ if (gss->major == GSS_S_COMPLETE) ++ fatal("GSSAPI Continue received from server when complete"); ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ if (!(gss->major & GSS_S_CONTINUE_NEEDED)) ++ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); ++ return kexgssgex_init_ctx(ssh, &recv_tok); ++} ++ ++static int ++input_kexgssgex_complete(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ u_char c; ++ int r; ++ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); ++ ++ debug("Received GSSAPI_COMPLETE"); ++ if (gss->msg_tok.value != NULL) ++ fatal("Received GSSAPI_COMPLETE twice?"); ++ if ((r = sshpkt_getb_froms(ssh, &gss->server_blob)) != 0 || ++ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &gss->msg_tok)) != 0) ++ fatal("Failed to read message: %s", ssh_err(r)); ++ ++ /* Is there a token included? */ ++ if ((r = sshpkt_get_u8(ssh, &c)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ if (c) { ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ /* If we're already complete - protocol error */ ++ if (gss->major == GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); ++ } else { ++ if (gss->major != GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); ++ } ++ if ((r = sshpkt_get_end(ssh)) != 0) ++ fatal("Expecting end of packet."); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgssgex_init_ctx(ssh, &recv_tok); ++ ++ gss_release_buffer(&gss->minor, &recv_tok); ++ return kexgssgex_final(ssh); ++} ++ +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ -diff --git a/kexgsss.c b/kexgsss.c -new file mode 100644 -index 00000000..60bc02de ---- /dev/null -+++ b/kexgsss.c -@@ -0,0 +1,482 @@ +diff --color -ruNp a/kexgsss.c b/kexgsss.c +--- a/kexgsss.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/kexgsss.c 2024-10-14 15:18:02.491798105 +0200 +@@ -0,0 +1,601 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -2159,33 +2004,18 @@ index 00000000..60bc02de + +extern ServerOptions options; + ++static int input_kexgss_init(int, u_int32_t, struct ssh *); ++static int input_kexgss_continue(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_groupreq(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_init(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_continue(int, u_int32_t, struct ssh *); ++ +int +kexgss_server(struct ssh *ssh) +{ + struct kex *kex = ssh->kex; -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf = {0, NULL}, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ struct sshbuf *shared_secret = NULL; -+ struct sshbuf *client_pubkey = NULL; -+ struct sshbuf *server_pubkey = NULL; -+ struct sshbuf *empty = sshbuf_new(); -+ int type = 0; + gss_OID oid; + char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ int r; + + /* Initialise GSSAPI */ + @@ -2201,135 +2031,94 @@ index 00000000..60bc02de + debug2_f("Identifying %s", kex->name); + oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); + if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); ++ fatal("Unknown gssapi mechanism"); + + debug2_f("Acquiring credentials"); + -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ if (GSS_ERROR(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) + fatal("Unable to acquire credentials for the server"); + -+ do { -+ debug("Wait SSH2_MSG_KEXGSS_INIT"); -+ type = ssh_packet_read(ssh); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (gssbuf.value != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (kex->gss == NULL) ++ fatal("Unable to allocate memory for gss context"); + -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ default: -+ fatal_f("Unexpected KEX type %d", kex->kex_type); -+ } -+ if (r != 0) -+ goto out; ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, &input_kexgss_init); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgss_continue); ++ debug("Wait SSH2_MSG_KEXGSS_INIT"); ++ return 0; ++} + -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ ++static inline void ++kexgss_accept_ctx(struct ssh *ssh, ++ gss_buffer_desc *recv_tok, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ int r; + -+ /* Calculate the hash early so we can free the -+ * client_pubkey, which has reference to the parent -+ * buffer state->incoming_packet -+ */ -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->peer, -+ kex->my, -+ empty, -+ client_pubkey, -+ server_pubkey, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ goto out; ++ gss->major = mm_ssh_gssapi_accept_ctx(gss, recv_tok, send_tok, ret_flags); ++ gss_release_buffer(&gss->minor, recv_tok); + -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; ++ if (gss->major != GSS_S_COMPLETE && send_tok->length == 0) ++ fatal("Zero length token output when incomplete"); + -+ sshbuf_free(client_pubkey); -+ client_pubkey = NULL; ++ if (gss->buf.value == NULL) ++ fatal("No client public key"); + -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ default: -+ sshpkt_disconnect(ssh, -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } ++ if (gss->major & GSS_S_CONTINUE_NEEDED) { ++ debug("Sending GSSAPI_CONTINUE"); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, send_tok); ++ } ++} + -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); ++static inline int ++kexgss_final(struct ssh *ssh, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ gss_buffer_desc msg_tok; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ struct sshbuf *shared_secret = NULL; ++ int r; + -+ gss_release_buffer(&min_status, &recv_tok); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); + -+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) -+ fatal("Zero length token output when incomplete"); -+ -+ if (gssbuf.value == NULL) -+ fatal("No client public key"); -+ -+ if (maj_status & GSS_S_CONTINUE_NEEDED) { -+ debug("Sending GSSAPI_CONTINUE"); ++ if (GSS_ERROR(gss->major)) { ++ if (send_tok->length > 0) { + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length > 0) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || + (r = sshpkt_send(ssh)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + } + fatal("accept_ctx died"); + } + -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ if (!(*ret_flags & GSS_C_MUTUAL_FLAG)) + fatal("Mutual Authentication flag wasn't set"); + -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ if (!(*ret_flags & GSS_C_INTEG_FLAG)) + fatal("Integrity flag wasn't set"); + -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) ++ if (GSS_ERROR(mm_ssh_gssapi_sign(gss, &gss->buf, &msg_tok))) + fatal("Couldn't get MIC"); + + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || -+ (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 || ++ (r = sshpkt_put_stringb(ssh, gss->server_pubkey)) != 0 || + (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + -+ if (send_tok.length != 0) { ++ if (send_tok->length != 0) { + if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + } else { + if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ @@ -2338,13 +2127,19 @@ index 00000000..60bc02de + if ((r = sshpkt_send(ssh)) != 0) + fatal("sshpkt_send failed: %s", ssh_err(r)); + -+ gss_release_buffer(&min_status, &send_tok); -+ gss_release_buffer(&min_status, &msg_tok); ++ gss_release_buffer(&gss->minor, send_tok); ++ gss_release_buffer(&gss->minor, &msg_tok); ++ ++ hashlen = gss->hashlen; ++ memcpy(hash, gss->hash, hashlen); ++ explicit_bzero(gss->hash, sizeof(gss->hash)); ++ shared_secret = gss->shared_secret; ++ gss->shared_secret = NULL; + + if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; ++ gss_kex_context = gss; + else -+ ssh_gssapi_delete_ctx(&ctxt); ++ ssh_gssapi_delete_ctx(&kex->gss); + + if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); @@ -2353,44 +2148,126 @@ index 00000000..60bc02de + * just exchanged. */ + if (options.gss_store_rekey) + ssh_gssapi_rekey_creds(); -+out: -+ sshbuf_free(empty); ++ ++ if (kex->gss != NULL) { ++ sshbuf_free(gss->server_pubkey); ++ gss->server_pubkey = NULL; ++ } + explicit_bzero(hash, sizeof(hash)); + sshbuf_free(shared_secret); -+ sshbuf_free(client_pubkey); -+ sshbuf_free(server_pubkey); + return r; +} + ++static int ++input_kexgss_init(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ struct sshbuf *empty; ++ struct sshbuf *client_pubkey = NULL; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ debug("SSH2_MSG_KEXGSS_INIT received"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ case KEX_GSS_GRP14_SHA1: ++ case KEX_GSS_GRP14_SHA256: ++ case KEX_GSS_GRP16_SHA512: ++ r = kex_dh_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ case KEX_GSS_NISTP256_SHA256: ++ r = kex_ecdh_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ case KEX_GSS_C25519_SHA256: ++ r = kex_c25519_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ default: ++ fatal_f("Unexpected KEX type %d", kex->kex_type); ++ } ++ if (r != 0) { ++ sshbuf_free(client_pubkey); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return r; ++ } ++ ++ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ ++ ++ if ((empty = sshbuf_new()) == NULL) { ++ sshbuf_free(client_pubkey); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return SSH_ERR_ALLOC_FAIL; ++ } ++ ++ /* Calculate the hash early so we can free the ++ * client_pubkey, which has reference to the parent ++ * buffer state->incoming_packet ++ */ ++ gss->hashlen = sizeof(gss->hash); ++ r = kex_gen_hash(kex->hash_alg, kex->client_version, kex->server_version, ++ kex->peer, kex->my, empty, client_pubkey, gss->server_pubkey, ++ gss->shared_secret, gss->hash, &gss->hashlen); ++ sshbuf_free(empty); ++ sshbuf_free(client_pubkey); ++ if (r != 0) { ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return r; ++ } ++ ++ gss->buf.value = gss->hash; ++ gss->buf.length = gss->hashlen; ++ ++ kexgss_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgss_final(ssh, &send_tok, &ret_flags); ++} ++ ++static int ++input_kexgss_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ kexgss_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgss_final(ssh, &send_tok, &ret_flags); ++} ++ ++/*******************************************************/ ++/******************** KEXGSSGEX ************************/ ++/*******************************************************/ ++ +int +kexgssgex_server(struct ssh *ssh) +{ + struct kex *kex = ssh->kex; -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ struct sshbuf *shared_secret = NULL; -+ int type = 0; + gss_OID oid; + char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ BIGNUM *dh_client_pub = NULL; -+ const BIGNUM *pub_key, *dh_p, *dh_g; -+ int min = -1, max = -1, nbits = -1; -+ int cmin = -1, cmax = -1; /* client proposal */ -+ struct sshbuf *empty = sshbuf_new(); -+ int r; + + /* Initialise GSSAPI */ + @@ -2398,29 +2275,194 @@ index 00000000..60bc02de + * in the GSSAPI code are no longer available. This kludges them back + * into life + */ -+ if (!ssh_gssapi_oid_table_ok()) -+ if ((mechs = ssh_gssapi_server_mechanisms())) -+ free(mechs); ++ if (!ssh_gssapi_oid_table_ok()) { ++ mechs = ssh_gssapi_server_mechanisms(); ++ free(mechs); ++ } + + debug2_f("Identifying %s", kex->name); + oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); + if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); ++ fatal("Unknown gssapi mechanism"); + + debug2_f("Acquiring credentials"); + -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ if (GSS_ERROR(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) + fatal("Unable to acquire credentials for the server"); + -+ /* 5. S generates an ephemeral key pair (do the allocations early) */ ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (kex->gss == NULL) ++ fatal("Unable to allocate memory for gss context"); ++ + debug("Doing group exchange"); -+ ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUPREQ); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUPREQ, &input_kexgssgex_groupreq); ++ return 0; ++} ++ ++static inline void ++kexgssgex_accept_ctx(struct ssh *ssh, ++ gss_buffer_desc *recv_tok, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ int r; ++ ++ gss->major = mm_ssh_gssapi_accept_ctx(gss, recv_tok, send_tok, ret_flags); ++ gss_release_buffer(&gss->minor, recv_tok); ++ ++ if (gss->major != GSS_S_COMPLETE && send_tok->length == 0) ++ fatal("Zero length token output when incomplete"); ++ ++ if (gss->dh_client_pub == NULL) ++ fatal("No client public key"); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) { ++ debug("Sending GSSAPI_CONTINUE"); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, send_tok); ++ } ++} ++ ++static inline int ++kexgssgex_final(struct ssh *ssh, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ gss_buffer_desc msg_tok; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ const BIGNUM *pub_key, *dh_p, *dh_g; ++ struct sshbuf *shared_secret = NULL; ++ struct sshbuf *empty = NULL; ++ int r; ++ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ++ if (GSS_ERROR(gss->major)) { ++ if (send_tok->length > 0) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ fatal("accept_ctx died"); ++ } ++ ++ if (!(*ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual Authentication flag wasn't set"); ++ ++ if (!(*ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity flag wasn't set"); ++ ++ /* calculate shared secret */ ++ shared_secret = sshbuf_new(); ++ if (shared_secret == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if ((r = kex_dh_compute_key(kex, gss->dh_client_pub, shared_secret)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ goto out; ++ } ++ ++ if ((empty = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); ++ hashlen = sizeof(hash); ++ r = kexgex_hash(kex->hash_alg, kex->client_version, kex->server_version, ++ kex->peer, kex->my, empty, kex->min, kex->nbits, kex->max, dh_p, dh_g, ++ gss->dh_client_pub, pub_key, sshbuf_ptr(shared_secret), ++ sshbuf_len(shared_secret), hash, &hashlen); ++ sshbuf_free(empty); ++ if (r != 0) ++ fatal("kexgex_hash failed: %s", ssh_err(r)); ++ ++ gss->buf.value = hash; ++ gss->buf.length = hashlen; ++ ++ if (GSS_ERROR(mm_ssh_gssapi_sign(gss, &gss->buf, &msg_tok))) ++ fatal("Couldn't get MIC"); ++ ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || ++ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ if (send_tok->length != 0) { ++ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } else { ++ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ if ((r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt_send failed: %s", ssh_err(r)); ++ ++ gss_release_buffer(&gss->minor, send_tok); ++ gss_release_buffer(&gss->minor, &msg_tok); ++ ++ if (gss_kex_context == NULL) ++ gss_kex_context = gss; ++ else ++ ssh_gssapi_delete_ctx(&kex->gss); ++ ++ /* Finally derive the keys and send them */ ++ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) ++ r = kex_send_newkeys(ssh); ++ ++ /* If this was a rekey, then save out any delegated credentials we ++ * just exchanged. */ ++ if (options.gss_store_rekey) ++ ssh_gssapi_rekey_creds(); ++ ++ if (kex->gss != NULL) ++ BN_clear_free(gss->dh_client_pub); ++ ++out: ++ explicit_bzero(hash, sizeof(hash)); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ sshbuf_free(shared_secret); ++ return r; ++} ++ ++static int ++input_kexgssgex_groupreq(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ const BIGNUM *dh_p, *dh_g; ++ int min = -1, max = -1, nbits = -1; ++ int cmin = -1, cmax = -1; /* client proposal */ ++ int r; ++ ++ /* 5. S generates an ephemeral key pair (do the allocations early) */ ++ ++ debug("SSH2_MSG_KEXGSS_GROUPREQ received"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUPREQ, NULL); ++ + /* store client proposal to provide valid signature */ + if ((r = sshpkt_get_u32(ssh, &cmin)) != 0 || + (r = sshpkt_get_u32(ssh, &nbits)) != 0 || + (r = sshpkt_get_u32(ssh, &cmax)) != 0 || + (r = sshpkt_get_end(ssh)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); ++ + kex->nbits = nbits; + kex->min = cmin; + kex->max = cmax; @@ -2428,10 +2470,11 @@ index 00000000..60bc02de + max = MIN(DH_GRP_MAX, cmax); + nbits = MAXIMUM(DH_GRP_MIN, nbits); + nbits = MINIMUM(DH_GRP_MAX, nbits); ++ + if (max < min || nbits < min || max < nbits) -+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", -+ min, nbits, max); -+ kex->dh = PRIVSEP(choose_dh(min, nbits, max)); ++ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", min, nbits, max); ++ ++ kex->dh = mm_choose_dh(min, nbits, max); + if (kex->dh == NULL) { + sshpkt_disconnect(ssh, "Protocol error: no matching group found"); + fatal("Protocol error: no matching group found"); @@ -2448,152 +2491,285 @@ index 00000000..60bc02de + fatal("ssh_packet_write_wait: %s", ssh_err(r)); + + /* Compute our exchange value in parallel with the client */ -+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) -+ goto out; -+ -+ do { -+ debug("Wait SSH2_MSG_GSSAPI_INIT"); -+ type = ssh_packet_read(ssh); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (dh_client_pub != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ default: -+ sshpkt_disconnect(ssh, -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); -+ -+ gss_release_buffer(&min_status, &recv_tok); -+ -+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) -+ fatal("Zero length token output when incomplete"); -+ -+ if (dh_client_pub == NULL) -+ fatal("No client public key"); -+ -+ if (maj_status & GSS_S_CONTINUE_NEEDED) { -+ debug("Sending GSSAPI_CONTINUE"); -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length > 0) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("accept_ctx died"); ++ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ return r; + } + -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual Authentication flag wasn't set"); -+ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity flag wasn't set"); -+ -+ /* calculate shared secret */ -+ if ((shared_secret = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0) -+ goto out; -+ -+ DH_get0_key(kex->dh, &pub_key, NULL); -+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); -+ hashlen = sizeof(hash); -+ if ((r = kexgex_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->peer, -+ kex->my, -+ empty, -+ cmin, nbits, cmax, -+ dh_p, dh_g, -+ dh_client_pub, -+ pub_key, -+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), -+ hash, &hashlen)) != 0) -+ fatal("kexgex_hash failed: %s", ssh_err(r)); -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) -+ fatal("Couldn't get MIC"); -+ -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || -+ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } else { -+ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ gss_release_buffer(&min_status, &send_tok); -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ /* Finally derive the keys and send them */ -+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) -+ r = kex_send_newkeys(ssh); -+ -+ /* If this was a rekey, then save out any delegated credentials we -+ * just exchanged. */ -+ if (options.gss_store_rekey) -+ ssh_gssapi_rekey_creds(); -+out: -+ sshbuf_free(empty); -+ explicit_bzero(hash, sizeof(hash)); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ BN_clear_free(dh_client_pub); -+ sshbuf_free(shared_secret); -+ return r; ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, &input_kexgssgex_init); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgssgex_continue); ++ debug("Wait SSH2_MSG_KEXGSS_INIT"); ++ return 0; +} ++ ++static int ++input_kexgssgex_init(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ debug("SSH2_MSG_KEXGSS_INIT received"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_bignum2(ssh, &gss->dh_client_pub)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ ++ ++ kexgssgex_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgssgex_final(ssh, &send_tok, &ret_flags); ++} ++ ++static int ++input_kexgssgex_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ kexgssgex_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgssgex_final(ssh, &send_tok, &ret_flags); ++} ++ +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ -diff --git a/monitor.c b/monitor.c -index 2ce89fe9..ebf76c7f 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -148,6 +148,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); +diff --color -ruNp a/kex.h b/kex.h +--- a/kex.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/kex.h 2024-09-16 11:46:34.710940224 +0200 +@@ -29,6 +29,10 @@ + #include "mac.h" + #include "crypto_api.h" + ++#ifdef GSSAPI ++# include "ssh-gss.h" /* Gssctxt */ ++#endif ++ + #ifdef WITH_OPENSSL + # include + # include +@@ -102,6 +106,15 @@ enum kex_exchange { + KEX_C25519_SHA256, + KEX_KEM_SNTRUP761X25519_SHA512, + KEX_KEM_MLKEM768X25519_SHA256, ++#ifdef GSSAPI ++ KEX_GSS_GRP1_SHA1, ++ KEX_GSS_GRP14_SHA1, ++ KEX_GSS_GRP14_SHA256, ++ KEX_GSS_GRP16_SHA512, ++ KEX_GSS_GEX_SHA1, ++ KEX_GSS_NISTP256_SHA256, ++ KEX_GSS_C25519_SHA256, ++#endif + KEX_MAX + }; + +@@ -164,6 +177,13 @@ struct kex { + u_int flags; + int hash_alg; + int ec_nid; ++#ifdef GSSAPI ++ Gssctxt *gss; ++ int gss_deleg_creds; ++ int gss_trust_dns; ++ char *gss_host; ++ char *gss_client; ++#endif + char *failed_choice; + int (*verify_host_key)(struct sshkey *, struct ssh *); + struct sshkey *(*load_host_public_key)(int, int, struct ssh *); +@@ -189,8 +209,10 @@ int kex_hash_from_name(const char *); + int kex_nid_from_name(const char *); + int kex_names_valid(const char *); + char *kex_alg_list(char); ++char *kex_gss_alg_list(char); + char *kex_names_cat(const char *, const char *); + int kex_has_any_alg(const char *, const char *); ++int kex_gss_names_valid(const char *); + int kex_assemble_names(char **, const char *, const char *); + void kex_proposal_populate_entries(struct ssh *, char *prop[PROPOSAL_MAX], + const char *, const char *, const char *, const char *, const char *); +@@ -224,6 +246,12 @@ int kexgex_client(struct ssh *); + int kexgex_server(struct ssh *); + int kex_gen_client(struct ssh *); + int kex_gen_server(struct ssh *); ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++int kexgssgex_client(struct ssh *); ++int kexgssgex_server(struct ssh *); ++int kexgss_client(struct ssh *); ++int kexgss_server(struct ssh *); ++#endif + + int kex_dh_keypair(struct kex *); + int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, +@@ -256,6 +284,12 @@ int kexgex_hash(int, const struct sshbu + const BIGNUM *, const u_char *, size_t, + u_char *, size_t *); + ++int kex_gen_hash(int hash_alg, const struct sshbuf *client_version, ++ const struct sshbuf *server_version, const struct sshbuf *client_kexinit, ++ const struct sshbuf *server_kexinit, const struct sshbuf *server_host_key_blob, ++ const struct sshbuf *client_pub, const struct sshbuf *server_pub, ++ const struct sshbuf *shared_secret, u_char *hash, size_t *hashlen); ++ + void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); +diff --color -ruNp a/kex-names.c b/kex-names.c +--- a/kex-names.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/kex-names.c 2024-09-16 11:46:34.694939883 +0200 +@@ -45,6 +45,10 @@ + #include "ssherr.h" + #include "xmalloc.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + struct kexalg { + char *name; + u_int type; +@@ -83,15 +87,28 @@ static const struct kexalg kexalgs[] = { + #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ + { NULL, 0, -1, -1}, + }; ++static const struct kexalg gss_kexalgs[] = { ++#ifdef GSSAPI ++ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, ++ { KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, ++ { KEX_GSS_NISTP256_SHA256_ID, KEX_GSS_NISTP256_SHA256, ++ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, ++ { KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, ++#endif ++ { NULL, 0, -1, -1}, ++}; + +-char * +-kex_alg_list(char sep) ++static char * ++kex_alg_list_internal(char sep, const struct kexalg *algs) + { + char *ret = NULL, *tmp; + size_t nlen, rlen = 0; + const struct kexalg *k; + +- for (k = kexalgs; k->name != NULL; k++) { ++ for (k = algs; k->name != NULL; k++) { + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(k->name); +@@ -106,6 +123,18 @@ kex_alg_list(char sep) + return ret; + } + ++char * ++kex_alg_list(char sep) ++{ ++ return kex_alg_list_internal(sep, kexalgs); ++} ++ ++char * ++kex_gss_alg_list(char sep) ++{ ++ return kex_alg_list_internal(sep, gss_kexalgs); ++} ++ + static const struct kexalg * + kex_alg_by_name(const char *name) + { +@@ -115,6 +144,10 @@ kex_alg_by_name(const char *name) + if (strcmp(k->name, name) == 0) + return k; + } ++ for (k = gss_kexalgs; k->name != NULL; k++) { ++ if (strncmp(k->name, name, strlen(k->name)) == 0) ++ return k; ++ } + return NULL; + } + +@@ -328,3 +361,26 @@ kex_assemble_names(char **listp, const c + free(ret); + return r; + } ++ ++/* Validate GSS KEX method name list */ ++int ++kex_gss_names_valid(const char *names) ++{ ++ char *s, *cp, *p; ++ ++ if (names == NULL || *names == '\0') ++ return 0; ++ s = cp = xstrdup(names); ++ for ((p = strsep(&cp, ",")); p && *p != '\0'; ++ (p = strsep(&cp, ","))) { ++ if (strncmp(p, "gss-", 4) != 0 ++ || kex_alg_by_name(p) == NULL) { ++ error("Unsupported KEX algorithm \"%.100s\"", p); ++ free(s); ++ return 0; ++ } ++ } ++ debug3("gss kex names ok: [%s]", names); ++ free(s); ++ return 1; ++} +diff --color -ruNp a/Makefile.in b/Makefile.in +--- a/Makefile.in 2024-09-16 11:45:56.868133454 +0200 ++++ b/Makefile.in 2024-09-16 11:46:34.695939904 +0200 +@@ -114,6 +114,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ + kexgexc.o kexgexs.o \ + kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \ ++ kexgssc.o \ + sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ + sshbuf-io.o + +@@ -135,7 +136,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rh + auth2-chall.o groupaccess.o \ + auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ + auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-pubkeyfile.o \ +- monitor.o monitor_wrap.o auth-krb5.o \ ++ monitor.o monitor_wrap.o auth-krb5.o kexgsss.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.o \ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ + sftp-server.o sftp-common.o \ +@@ -529,7 +530,7 @@ regress-prep: + ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile + + REGRESSLIBS=libssh.a $(LIBCOMPAT) +-TESTLIBS=$(LIBS) $(CHANNELLIBS) ++TESTLIBS=$(LIBS) $(CHANNELLIBS) $(GSSLIBS) + + regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS) + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \ +diff --color -ruNp a/monitor.c b/monitor.c +--- a/monitor.c 2024-09-16 11:45:56.861133305 +0200 ++++ b/monitor.c 2024-09-16 11:46:34.696939926 +0200 +@@ -143,6 +143,8 @@ int mm_answer_gss_setup_ctx(struct ssh * int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *); int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *); int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *); @@ -2602,7 +2778,7 @@ index 2ce89fe9..ebf76c7f 100644 #endif #ifdef SSH_AUDIT_EVENTS -@@ -220,11 +222,18 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -219,11 +221,18 @@ struct mon_table mon_dispatch_proto20[] {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, @@ -2621,7 +2797,7 @@ index 2ce89fe9..ebf76c7f 100644 #ifdef WITH_OPENSSL {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, #endif -@@ -293,6 +302,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) +@@ -292,6 +301,10 @@ monitor_child_preauth(struct ssh *ssh, s /* Permit requests for moduli and signatures */ monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); @@ -2632,7 +2808,24 @@ index 2ce89fe9..ebf76c7f 100644 /* The first few requests do not require asynchronous access */ while (!authenticated) { -@@ -406,6 +419,10 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) +@@ -344,8 +357,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); +@@ -413,6 +433,10 @@ monitor_child_postauth(struct ssh *ssh, monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); @@ -2643,7 +2836,7 @@ index 2ce89fe9..ebf76c7f 100644 if (auth_opts->permit_pty_flag) { monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); -@@ -1713,6 +1730,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) +@@ -1793,6 +1817,17 @@ monitor_apply_keystate(struct ssh *ssh, # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kex_gen_server; # endif @@ -2661,7 +2854,7 @@ index 2ce89fe9..ebf76c7f 100644 #endif /* WITH_OPENSSL */ kex->kex[KEX_C25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; -@@ -1806,8 +1834,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1885,8 +1920,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, u_char *p; int r; @@ -2672,7 +2865,7 @@ index 2ce89fe9..ebf76c7f 100644 if ((r = sshbuf_get_string(m, &p, &len)) != 0) fatal_fr(r, "parse"); -@@ -1839,8 +1867,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1918,8 +1953,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh OM_uint32 flags = 0; /* GSI needs this */ int r; @@ -2683,7 +2876,7 @@ index 2ce89fe9..ebf76c7f 100644 if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) fatal_fr(r, "ssh_gssapi_get_buffer_desc"); -@@ -1860,6 +1888,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1939,6 +1974,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); @@ -2691,7 +2884,7 @@ index 2ce89fe9..ebf76c7f 100644 } return (0); } -@@ -1871,8 +1900,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1950,8 +1986,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, OM_uint32 ret; int r; @@ -2702,7 +2895,7 @@ index 2ce89fe9..ebf76c7f 100644 if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0) -@@ -1898,13 +1927,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1977,13 +2013,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) { @@ -2724,7 +2917,7 @@ index 2ce89fe9..ebf76c7f 100644 sshbuf_reset(m); if ((r = sshbuf_put_u32(m, authenticated)) != 0) -@@ -1913,7 +1946,11 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1992,7 +2032,11 @@ mm_answer_gss_userok(struct ssh *ssh, in debug3_f("sending result %d", authenticated); mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); @@ -2737,7 +2930,7 @@ index 2ce89fe9..ebf76c7f 100644 if ((displayname = ssh_gssapi_displayname()) != NULL) auth2_record_info(authctxt, "%s", displayname); -@@ -1921,5 +1958,84 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -2000,5 +2044,84 @@ mm_answer_gss_userok(struct ssh *ssh, in /* Monitor loop will terminate if authenticated */ return (authenticated); } @@ -2822,11 +3015,10 @@ index 2ce89fe9..ebf76c7f 100644 + #endif /* GSSAPI */ -diff --git a/monitor.h b/monitor.h -index 683e5e07..2b1a2d59 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -63,6 +63,8 @@ enum monitor_reqtype { +diff --color -ruNp a/monitor.h b/monitor.h +--- a/monitor.h 2024-09-16 11:45:56.861133305 +0200 ++++ b/monitor.h 2024-09-16 11:46:34.696939926 +0200 +@@ -67,6 +67,8 @@ enum monitor_reqtype { MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, @@ -2835,11 +3027,10 @@ index 683e5e07..2b1a2d59 100644 }; struct ssh; -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 001a8fa1..6edb509a 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -993,13 +993,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) +diff --color -ruNp a/monitor_wrap.c b/monitor_wrap.c +--- a/monitor_wrap.c 2024-09-16 11:45:56.862133326 +0200 ++++ b/monitor_wrap.c 2024-09-16 11:46:34.697939947 +0200 +@@ -1075,13 +1075,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss } int @@ -2856,7 +3047,7 @@ index 001a8fa1..6edb509a 100644 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, m); mm_request_receive_expect(pmonitor->m_recvfd, -@@ -1012,4 +1014,57 @@ mm_ssh_gssapi_userok(char *user) +@@ -1094,6 +1096,59 @@ mm_ssh_gssapi_userok(char *user) debug3_f("user %sauthenticated", authenticated ? "" : "not "); return (authenticated); } @@ -2914,11 +3105,12 @@ index 001a8fa1..6edb509a 100644 +} + #endif /* GSSAPI */ -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 23ab096a..485590c1 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -64,8 +64,10 @@ int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, + + /* +diff --color -ruNp a/monitor_wrap.h b/monitor_wrap.h +--- a/monitor_wrap.h 2024-09-16 11:45:56.862133326 +0200 ++++ b/monitor_wrap.h 2024-09-16 11:46:34.697939947 +0200 +@@ -67,8 +67,10 @@ void mm_decode_activate_server_options(s OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); @@ -2930,10 +3122,10 @@ index 23ab096a..485590c1 100644 #endif #ifdef USE_PAM -diff -up a/readconf.c.gsskex b/readconf.c ---- a/readconf.c.gsskex 2021-08-20 06:03:49.000000000 +0200 -+++ b/readconf.c 2021-08-27 12:25:42.556421509 +0200 -@@ -67,6 +67,7 @@ +diff --color -ruNp a/readconf.c b/readconf.c +--- a/readconf.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/readconf.c 2024-09-16 11:46:34.699939990 +0200 +@@ -70,6 +70,7 @@ #include "uidswap.h" #include "myproposal.h" #include "digest.h" @@ -2941,7 +3133,7 @@ diff -up a/readconf.c.gsskex b/readconf.c /* Format of the configuration file: -@@ -161,6 +162,8 @@ typedef enum { +@@ -164,6 +165,8 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, @@ -2950,7 +3142,7 @@ diff -up a/readconf.c.gsskex b/readconf.c oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, -@@ -206,10 +209,22 @@ static struct { +@@ -210,10 +213,22 @@ static struct { /* Sometimes-unsupported options */ #if defined(GSSAPI) { "gssapiauthentication", oGssAuthentication }, @@ -2973,7 +3165,7 @@ diff -up a/readconf.c.gsskex b/readconf.c #endif #ifdef ENABLE_PKCS11 { "pkcs11provider", oPKCS11Provider }, -@@ -1113,10 +1128,42 @@ parse_time: +@@ -1227,10 +1242,42 @@ parse_time: intptr = &options->gss_authentication; goto parse_flag; @@ -3016,7 +3208,7 @@ diff -up a/readconf.c.gsskex b/readconf.c case oBatchMode: intptr = &options->batch_mode; goto parse_flag; -@@ -2306,7 +2353,13 @@ initialize_options(Options * options) +@@ -2542,7 +2589,13 @@ initialize_options(Options * options) options->fwd_opts.streamlocal_bind_unlink = -1; options->pubkey_authentication = -1; options->gss_authentication = -1; @@ -3030,8 +3222,8 @@ diff -up a/readconf.c.gsskex b/readconf.c options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; -@@ -2463,8 +2516,18 @@ fill_default_options(Options * options) - options->pubkey_authentication = 1; +@@ -2705,8 +2758,18 @@ fill_default_options(Options * options) + options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL; if (options->gss_authentication == -1) options->gss_authentication = 0; + if (options->gss_keyex == -1) @@ -3049,7 +3241,7 @@ diff -up a/readconf.c.gsskex b/readconf.c if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -3246,7 +3309,14 @@ dump_client_config(Options *o, const cha +@@ -3533,7 +3596,14 @@ dump_client_config(Options *o, const cha dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); #ifdef GSSAPI dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); @@ -3064,10 +3256,10 @@ diff -up a/readconf.c.gsskex b/readconf.c #endif /* GSSAPI */ dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); -diff -up a/readconf.h.gsskex b/readconf.h ---- a/readconf.h.gsskex 2021-08-27 12:05:29.248142431 +0200 -+++ b/readconf.h 2021-08-27 12:22:19.270679852 +0200 -@@ -39,7 +39,13 @@ typedef struct { +diff --color -ruNp a/readconf.h b/readconf.h +--- a/readconf.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/readconf.h 2024-09-16 11:46:34.699939990 +0200 +@@ -40,7 +40,13 @@ typedef struct { int pubkey_authentication; /* Try ssh2 pubkey authentication. */ int hostbased_authentication; /* ssh2's rhosts_rsa */ int gss_authentication; /* Try GSS authentication */ @@ -3081,18 +3273,18 @@ diff -up a/readconf.h.gsskex b/readconf.h int password_authentication; /* Try password * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -diff -up a/servconf.c.gsskex b/servconf.c ---- a/servconf.c.gsskex 2021-08-20 06:03:49.000000000 +0200 -+++ b/servconf.c 2021-08-27 12:28:15.887735189 +0200 -@@ -70,6 +70,7 @@ +diff --color -ruNp a/servconf.c b/servconf.c +--- a/servconf.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/servconf.c 2024-09-16 11:46:34.700940011 +0200 +@@ -68,6 +68,7 @@ #include "auth.h" #include "myproposal.h" #include "digest.h" +#include "ssh-gss.h" - static void add_listen_addr(ServerOptions *, const char *, - const char *, int); -@@ -136,8 +137,11 @@ initialize_server_options(ServerOptions + #if !defined(SSHD_PAM_SERVICE) + # define SSHD_PAM_SERVICE "sshd" +@@ -137,8 +138,11 @@ initialize_server_options(ServerOptions options->kerberos_ticket_cleanup = -1; options->kerberos_get_afs_token = -1; options->gss_authentication=-1; @@ -3104,7 +3296,7 @@ diff -up a/servconf.c.gsskex b/servconf.c options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->permit_empty_passwd = -1; -@@ -356,10 +360,18 @@ fill_default_server_options(ServerOption +@@ -376,10 +380,18 @@ fill_default_server_options(ServerOption options->kerberos_get_afs_token = 0; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3123,15 +3315,15 @@ diff -up a/servconf.c.gsskex b/servconf.c if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -506,6 +518,7 @@ typedef enum { - sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, +@@ -558,6 +570,7 @@ typedef enum { + sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -587,12 +600,22 @@ static struct { +@@ -643,12 +656,22 @@ static struct { #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, @@ -3154,7 +3346,7 @@ diff -up a/servconf.c.gsskex b/servconf.c { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, { "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */ -@@ -1576,6 +1599,10 @@ process_server_config_line_depth(ServerO +@@ -1585,6 +1608,10 @@ process_server_config_line_depth(ServerO intptr = &options->gss_authentication; goto parse_flag; @@ -3165,7 +3357,7 @@ diff -up a/servconf.c.gsskex b/servconf.c case sGssCleanupCreds: intptr = &options->gss_cleanup_creds; goto parse_flag; -@@ -1584,6 +1611,22 @@ process_server_config_line_depth(ServerO +@@ -1593,6 +1620,22 @@ process_server_config_line_depth(ServerO intptr = &options->gss_strict_acceptor; goto parse_flag; @@ -3188,7 +3380,7 @@ diff -up a/servconf.c.gsskex b/servconf.c case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -@@ -2892,6 +2935,10 @@ dump_config(ServerOptions *o) +@@ -3178,6 +3221,10 @@ dump_config(ServerOptions *o) #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); @@ -3199,11 +3391,10 @@ diff -up a/servconf.c.gsskex b/servconf.c #endif dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); dump_cfg_fmtint(sKbdInteractiveAuthentication, -diff --git a/servconf.h b/servconf.h -index 4202a2d0..3f47ea25 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -132,8 +132,11 @@ typedef struct { +diff --color -ruNp a/servconf.h b/servconf.h +--- a/servconf.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/servconf.h 2024-09-16 11:46:34.700940011 +0200 +@@ -149,8 +149,11 @@ typedef struct { int kerberos_get_afs_token; /* If true, try to get AFS token if * authenticated with Kerberos. */ int gss_authentication; /* If true, permit GSSAPI authentication */ @@ -3215,11 +3406,10 @@ index 4202a2d0..3f47ea25 100644 int password_authentication; /* If true, permit password * authentication. */ int kbd_interactive_authentication; /* If true, permit */ -diff --git a/session.c b/session.c -index 8c0e54f7..06a33442 100644 ---- a/session.c -+++ b/session.c -@@ -2678,13 +2678,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) +diff --color -ruNp a/session.c b/session.c +--- a/session.c 2024-09-16 11:45:56.866133411 +0200 ++++ b/session.c 2024-09-16 11:46:34.701940032 +0200 +@@ -2674,13 +2674,19 @@ do_cleanup(struct ssh *ssh, Authctxt *au #ifdef KRB5 if (options.kerberos_ticket_cleanup && @@ -3241,135 +3431,10 @@ index 8c0e54f7..06a33442 100644 #endif /* remove agent socket */ -diff --git a/ssh-gss.h b/ssh-gss.h -index 36180d07..70dd3665 100644 ---- a/ssh-gss.h -+++ b/ssh-gss.h -@@ -1,6 +1,6 @@ - /* $OpenBSD: ssh-gss.h,v 1.15 2021/01/27 10:05:28 djm Exp $ */ - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -61,10 +61,34 @@ - - #define SSH_GSS_OIDTYPE 0x06 - -+#define SSH2_MSG_KEXGSS_INIT 30 -+#define SSH2_MSG_KEXGSS_CONTINUE 31 -+#define SSH2_MSG_KEXGSS_COMPLETE 32 -+#define SSH2_MSG_KEXGSS_HOSTKEY 33 -+#define SSH2_MSG_KEXGSS_ERROR 34 -+#define SSH2_MSG_KEXGSS_GROUPREQ 40 -+#define SSH2_MSG_KEXGSS_GROUP 41 -+#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" -+#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" -+#define KEX_GSS_GRP14_SHA256_ID "gss-group14-sha256-" -+#define KEX_GSS_GRP16_SHA512_ID "gss-group16-sha512-" -+#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" -+#define KEX_GSS_NISTP256_SHA256_ID "gss-nistp256-sha256-" -+#define KEX_GSS_C25519_SHA256_ID "gss-curve25519-sha256-" -+ -+#define GSS_KEX_DEFAULT_KEX \ -+ KEX_GSS_GRP14_SHA256_ID "," \ -+ KEX_GSS_GRP16_SHA512_ID "," \ -+ KEX_GSS_NISTP256_SHA256_ID "," \ -+ KEX_GSS_C25519_SHA256_ID "," \ -+ KEX_GSS_GRP14_SHA1_ID "," \ -+ KEX_GSS_GEX_SHA1_ID -+ - typedef struct { - char *filename; - char *envvar; - char *envval; -+ struct passwd *owner; - void *data; - } ssh_gssapi_ccache; - -@@ -72,8 +92,11 @@ typedef struct { - gss_buffer_desc displayname; - gss_buffer_desc exportedname; - gss_cred_id_t creds; -+ gss_name_t name; - struct ssh_gssapi_mech_struct *mech; - ssh_gssapi_ccache store; -+ int used; -+ int updated; - } ssh_gssapi_client; - - typedef struct ssh_gssapi_mech_struct { -@@ -84,6 +107,7 @@ typedef struct ssh_gssapi_mech_struct { - int (*userok) (ssh_gssapi_client *, char *); - int (*localname) (ssh_gssapi_client *, char **); - void (*storecreds) (ssh_gssapi_client *); -+ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); - } ssh_gssapi_mech; - - typedef struct { -@@ -94,10 +118,11 @@ typedef struct { - gss_OID oid; /* client */ - gss_cred_id_t creds; /* server */ - gss_name_t client; /* server */ -- gss_cred_id_t client_creds; /* server */ -+ gss_cred_id_t client_creds; /* both */ - } Gssctxt; - - extern ssh_gssapi_mech *supported_mechs[]; -+extern Gssctxt *gss_kex_context; - - int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); - void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); -@@ -109,6 +134,7 @@ OM_uint32 ssh_gssapi_test_oid_supported(OM_uint32 *, gss_OID, int *); - - struct sshbuf; - int ssh_gssapi_get_buffer_desc(struct sshbuf *, gss_buffer_desc *); -+int ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *, gss_buffer_desc *); - - OM_uint32 ssh_gssapi_import_name(Gssctxt *, const char *); - OM_uint32 ssh_gssapi_init_ctx(Gssctxt *, int, -@@ -123,17 +149,33 @@ void ssh_gssapi_delete_ctx(Gssctxt **); - OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_buildmic(struct sshbuf *, const char *, - const char *, const char *, const struct sshbuf *); --int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); -+int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); -+OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); -+int ssh_gssapi_credentials_updated(Gssctxt *); - - /* In the server */ -+typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, -+ const char *); -+char *ssh_gssapi_client_mechanisms(const char *, const char *, const char *); -+char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, -+ const char *, const char *); -+gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); -+int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, -+ const char *); - OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); --int ssh_gssapi_userok(char *name); -+int ssh_gssapi_userok(char *name, struct passwd *, int kex); - OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); - void ssh_gssapi_do_child(char ***, u_int *); - void ssh_gssapi_cleanup_creds(void); - void ssh_gssapi_storecreds(void); - const char *ssh_gssapi_displayname(void); - -+char *ssh_gssapi_server_mechanisms(void); -+int ssh_gssapi_oid_table_ok(void); -+ -+int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); -+void ssh_gssapi_rekey_creds(void); -+ - #endif /* GSSAPI */ - - #endif /* _SSH_GSS_H */ -diff --git a/ssh.1 b/ssh.1 -index 60de6087..db5c65bc 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -503,7 +503,13 @@ For full details of the options listed below, and their possible values, see +diff --color -ruNp a/ssh.1 b/ssh.1 +--- a/ssh.1 2024-09-16 11:45:56.875133603 +0200 ++++ b/ssh.1 2024-09-16 11:46:34.701940032 +0200 +@@ -536,7 +536,13 @@ For full details of the options listed b .It GatewayPorts .It GlobalKnownHostsFile .It GSSAPIAuthentication @@ -3383,7 +3448,7 @@ index 60de6087..db5c65bc 100644 .It HashKnownHosts .It Host .It HostbasedAcceptedAlgorithms -@@ -579,6 +585,8 @@ flag), +@@ -624,6 +630,8 @@ flag), (supported message integrity codes), .Ar kex (key exchange algorithms), @@ -3391,12 +3456,11 @@ index 60de6087..db5c65bc 100644 +(GSSAPI key exchange algorithms), .Ar key (key types), - .Ar key-cert -diff --git a/ssh.c b/ssh.c -index 15aee569..110cf9c1 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -747,6 +747,8 @@ main(int ac, char **av) + .Ar key-ca-sign +diff --color -ruNp a/ssh.c b/ssh.c +--- a/ssh.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/ssh.c 2024-09-16 11:46:34.702940054 +0200 +@@ -827,6 +827,8 @@ main(int ac, char **av) else if (strcmp(optarg, "kex") == 0 || strcasecmp(optarg, "KexAlgorithms") == 0) cp = kex_alg_list('\n'); @@ -3405,7 +3469,7 @@ index 15aee569..110cf9c1 100644 else if (strcmp(optarg, "key") == 0) cp = sshkey_alg_list(0, 0, 0, '\n'); else if (strcmp(optarg, "key-cert") == 0) -@@ -772,8 +774,8 @@ main(int ac, char **av) +@@ -857,8 +859,8 @@ main(int ac, char **av) } else if (strcmp(optarg, "help") == 0) { cp = xstrdup( "cipher\ncipher-auth\ncompression\nkex\n" @@ -3416,10 +3480,9 @@ index 15aee569..110cf9c1 100644 } if (cp == NULL) fatal("Unsupported query \"%s\"", optarg); -diff --git a/ssh_config b/ssh_config -index 5e8ef548..1ff999b6 100644 ---- a/ssh_config -+++ b/ssh_config +diff --color -ruNp a/ssh_config b/ssh_config +--- a/ssh_config 2024-09-16 11:45:56.884133795 +0200 ++++ b/ssh_config 2024-09-16 11:46:34.702940054 +0200 @@ -24,6 +24,8 @@ # HostbasedAuthentication no # GSSAPIAuthentication no @@ -3427,13 +3490,12 @@ index 5e8ef548..1ff999b6 100644 +# GSSAPIKeyExchange no +# GSSAPITrustDNS no # BatchMode no - # CheckHostIP yes + # CheckHostIP no # AddressFamily any -diff --git a/ssh_config.5 b/ssh_config.5 -index 06a32d31..3f490697 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -766,10 +766,68 @@ The default is +diff --color -ruNp a/ssh_config.5 b/ssh_config.5 +--- a/ssh_config.5 2024-07-01 06:36:28.000000000 +0200 ++++ b/ssh_config.5 2024-09-16 11:46:34.703940075 +0200 +@@ -938,10 +938,68 @@ The default is Specifies whether user authentication based on GSSAPI is allowed. The default is .Cm no . @@ -3502,21 +3564,11 @@ index 06a32d31..3f490697 100644 .It Cm HashKnownHosts Indicates that .Xr ssh 1 -diff --git a/sshconnect2.c b/sshconnect2.c -index af00fb30..03bc87eb 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -80,8 +80,6 @@ - #endif - - /* import */ --extern char *client_version_string; --extern char *server_version_string; - extern Options options; - - /* -@@ -163,6 +161,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) - char *s, *all_key; +diff --color -ruNp a/sshconnect2.c b/sshconnect2.c +--- a/sshconnect2.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/sshconnect2.c 2024-09-16 11:46:34.703940075 +0200 +@@ -222,6 +222,11 @@ ssh_kex2(struct ssh *ssh, char *host, st + char *all_key, *hkalgs = NULL; int r, use_known_hosts_order = 0; +#if defined(GSSAPI) && defined(WITH_OPENSSL) @@ -3527,9 +3579,9 @@ index af00fb30..03bc87eb 100644 xxx_host = host; xxx_hostaddr = hostaddr; xxx_conn_info = cinfo; -@@ -206,6 +209,42 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) - compat_pkalg_proposal(ssh, options.hostkeyalgorithms); - } +@@ -255,6 +260,42 @@ ssh_kex2(struct ssh *ssh, char *host, st + compression_alg_list(options.compression), + hkalgs ? hkalgs : options.hostkeyalgorithms); +#if defined(GSSAPI) && defined(WITH_OPENSSL) + if (options.gss_keyex) { @@ -3567,10 +3619,10 @@ index af00fb30..03bc87eb 100644 + } +#endif + - if (options.rekey_limit || options.rekey_interval) - ssh_packet_set_rekey_limits(ssh, options.rekey_limit, - options.rekey_interval); -@@ -224,16 +256,46 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) + free(hkalgs); + + /* start key exchange */ +@@ -271,15 +312,45 @@ ssh_kex2(struct ssh *ssh, char *host, st # ifdef OPENSSL_HAS_ECC ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; # endif @@ -3588,7 +3640,8 @@ index af00fb30..03bc87eb 100644 +# endif +#endif /* WITH_OPENSSL */ ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; - ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; + ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; + ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client; ssh->kex->verify_host_key=&verify_host_key_callback; +#if defined(GSSAPI) && defined(WITH_OPENSSL) @@ -3601,10 +3654,8 @@ index af00fb30..03bc87eb 100644 +#endif + ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); + kex_proposal_free_entries(myproposal); - /* remove ext-info from the KEX proposals for rekeying */ - myproposal[PROPOSAL_KEX_ALGS] = - compat_kex_proposal(ssh, options.kex_algorithms); +#if defined(GSSAPI) && defined(WITH_OPENSSL) + /* repair myproposal after it was crumpled by the */ + /* ext-info removal above */ @@ -3615,10 +3666,10 @@ index af00fb30..03bc87eb 100644 + free(gss); + } +#endif - if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) - fatal_r(r, "kex_prop2buf"); - -@@ -330,6 +392,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *); + #ifdef DEBUG_KEXDH + /* send 1st encrypted/maced/compressed message */ + if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || +@@ -368,6 +439,7 @@ static int input_gssapi_response(int typ static int input_gssapi_token(int type, u_int32_t, struct ssh *); static int input_gssapi_error(int, u_int32_t, struct ssh *); static int input_gssapi_errtok(int, u_int32_t, struct ssh *); @@ -3626,7 +3677,7 @@ index af00fb30..03bc87eb 100644 #endif void userauth(struct ssh *, char *); -@@ -346,6 +409,11 @@ static char *authmethods_get(void); +@@ -384,6 +456,11 @@ static char *authmethods_get(void); Authmethod authmethods[] = { #ifdef GSSAPI @@ -3638,7 +3689,7 @@ index af00fb30..03bc87eb 100644 {"gssapi-with-mic", userauth_gssapi, userauth_gssapi_cleanup, -@@ -716,12 +784,32 @@ userauth_gssapi(struct ssh *ssh) +@@ -755,12 +832,32 @@ userauth_gssapi(struct ssh *ssh) OM_uint32 min; int r, ok = 0; gss_OID mech = NULL; @@ -3672,7 +3723,7 @@ index af00fb30..03bc87eb 100644 /* Check to see whether the mechanism is usable before we offer it */ while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && -@@ -730,13 +811,15 @@ userauth_gssapi(struct ssh *ssh) +@@ -769,13 +866,15 @@ userauth_gssapi(struct ssh *ssh) elements[authctxt->mech_tried]; /* My DER encoding requires length<128 */ if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, @@ -3689,7 +3740,7 @@ index af00fb30..03bc87eb 100644 if (!ok || mech == NULL) return 0; -@@ -976,6 +1059,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) +@@ -1009,6 +1108,55 @@ input_gssapi_error(int type, u_int32_t p free(lang); return r; } @@ -3745,22 +3796,10 @@ index af00fb30..03bc87eb 100644 #endif /* GSSAPI */ static int -diff --git a/sshd.c b/sshd.c -index 60b2aaf7..d92f03aa 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -817,8 +817,8 @@ notify_hostkeys(struct ssh *ssh) - } - debug3_f("sent %u hostkeys", nkeys); - if (nkeys == 0) -- fatal_f("no hostkeys"); -- if ((r = sshpkt_send(ssh)) != 0) -+ debug3_f("no hostkeys"); -+ else if ((r = sshpkt_send(ssh)) != 0) - sshpkt_fatal(ssh, r, "%s: send", __func__); - sshbuf_free(buf); - } -@@ -1852,7 +1852,8 @@ main(int ac, char **av) +diff --color -ruNp a/sshd.c b/sshd.c +--- a/sshd.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/sshd.c 2024-09-16 11:46:34.704940096 +0200 +@@ -1551,7 +1551,8 @@ main(int ac, char **av) free(fp); } accumulate_host_timing_secret(cfg, NULL); @@ -3770,80 +3809,10 @@ index 60b2aaf7..d92f03aa 100644 logit("sshd: no hostkeys available -- exiting."); exit(1); } -@@ -2347,6 +2348,48 @@ do_ssh2_kex(struct ssh *ssh) - myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = compat_pkalg_proposal( - ssh, list_hostkey_types()); - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ { -+ char *orig; -+ char *gss = NULL; -+ char *newstr = NULL; -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ /* -+ * If we don't have a host key, then there's no point advertising -+ * the other key exchange algorithms -+ */ -+ -+ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) -+ orig = NULL; -+ -+ if (options.gss_keyex) -+ gss = ssh_gssapi_server_mechanisms(); -+ else -+ gss = NULL; -+ -+ if (gss && orig) -+ xasprintf(&newstr, "%s,%s", gss, orig); -+ else if (gss) -+ newstr = gss; -+ else if (orig) -+ newstr = orig; -+ -+ /* -+ * If we've got GSSAPI mechanisms, then we've got the 'null' host -+ * key alg, but we can't tell people about it unless its the only -+ * host key algorithm we support -+ */ -+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) -+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; -+ -+ if (newstr) -+ myproposal[PROPOSAL_KEX_ALGS] = newstr; -+ else -+ fatal("No supported key exchange algorithms"); -+ } -+#endif -+ - /* start key exchange */ - if ((r = kex_setup(ssh, myproposal)) != 0) - fatal_r(r, "kex_setup"); -@@ -2362,7 +2405,18 @@ do_ssh2_kex(struct ssh *ssh) - # ifdef OPENSSL_HAS_ECC - kex->kex[KEX_ECDH_SHA2] = kex_gen_server; - # endif --#endif -+# ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server; -+ kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server; -+ kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server; -+ kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server; -+ } -+# endif -+#endif /* WITH_OPENSSL */ - kex->kex[KEX_C25519_SHA256] = kex_gen_server; - kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; - kex->load_host_public_key=&get_hostkey_public_by_type; -diff --git a/sshd_config b/sshd_config -index 19b7c91a..2c48105f 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -69,6 +69,8 @@ AuthorizedKeysFile .ssh/authorized_keys +diff --color -ruNp a/sshd_config b/sshd_config +--- a/sshd_config 2024-09-16 11:45:56.888133880 +0200 ++++ b/sshd_config 2024-09-16 11:46:34.704940096 +0200 +@@ -77,6 +77,8 @@ AuthorizedKeysFile .ssh/authorized_keys # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes @@ -3852,11 +3821,10 @@ index 19b7c91a..2c48105f 100644 # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will -diff --git a/sshd_config.5 b/sshd_config.5 -index 70ccea44..f6b41a2f 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -646,6 +646,11 @@ Specifies whether to automatically destroy the user's credentials cache +diff --color -ruNp a/sshd_config.5 b/sshd_config.5 +--- a/sshd_config.5 2024-09-16 11:45:56.885133816 +0200 ++++ b/sshd_config.5 2024-09-16 11:46:34.704940096 +0200 +@@ -739,6 +739,11 @@ Specifies whether to automatically destr on logout. The default is .Cm yes . @@ -3868,7 +3836,7 @@ index 70ccea44..f6b41a2f 100644 .It Cm GSSAPIStrictAcceptorCheck Determines whether to be strict about the identity of the GSSAPI acceptor a client authenticates against. -@@ -660,6 +665,32 @@ machine's default store. +@@ -753,6 +758,32 @@ machine's default store. This facility is provided to assist with operation on multi homed machines. The default is .Cm yes . @@ -3901,32 +3869,328 @@ index 70ccea44..f6b41a2f 100644 .It Cm HostbasedAcceptedAlgorithms Specifies the signature algorithms that will be accepted for hostbased authentication as a list of comma-separated patterns. -diff --git a/sshkey.c b/sshkey.c -index 57995ee6..fd5b7724 100644 ---- a/sshkey.c -+++ b/sshkey.c -@@ -154,6 +154,7 @@ static const struct keytype keytypes[] = { - KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 }, - # endif /* OPENSSL_HAS_ECC */ - #endif /* WITH_OPENSSL */ -+ { "null", "null", NULL, KEY_NULL, 0, 0, 0 }, - { NULL, NULL, NULL, -1, -1, 0, 0 } +diff --color -ruNp a/sshd-session.c b/sshd-session.c +--- a/sshd-session.c 2024-09-16 11:45:56.888133880 +0200 ++++ b/sshd-session.c 2024-09-16 11:46:34.705940118 +0200 +@@ -660,8 +660,8 @@ notify_hostkeys(struct ssh *ssh) + } + debug3_f("sent %u hostkeys", nkeys); + if (nkeys == 0) +- fatal_f("no hostkeys"); +- if ((r = sshpkt_send(ssh)) != 0) ++ debug3_f("no hostkeys"); ++ else if ((r = sshpkt_send(ssh)) != 0) + sshpkt_fatal(ssh, r, "%s: send", __func__); + sshbuf_free(buf); + } +@@ -1180,8 +1180,9 @@ main(int ac, char **av) + break; + } + } +- if (!have_key) +- fatal("internal error: monitor received no hostkeys"); ++ /* The GSSAPI key exchange can run without a host key */ ++ if (!have_key && !options.gss_keyex) ++ fatal("internal error: monitor received no hostkeys and GSS KEX is not configured"); + + /* Ensure that umask disallows at least group and world write */ + new_umask = umask(0077) | 0022; +@@ -1462,6 +1463,48 @@ do_ssh2_kex(struct ssh *ssh) + + free(hkalgs); + ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++ { ++ char *orig; ++ char *gss = NULL; ++ char *newstr = NULL; ++ orig = myproposal[PROPOSAL_KEX_ALGS]; ++ ++ /* ++ * If we don't have a host key, then there's no point advertising ++ * the other key exchange algorithms ++ */ ++ ++ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) ++ orig = NULL; ++ ++ if (options.gss_keyex) ++ gss = ssh_gssapi_server_mechanisms(); ++ else ++ gss = NULL; ++ ++ if (gss && orig) ++ xasprintf(&newstr, "%s,%s", gss, orig); ++ else if (gss) ++ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com"); ++ else if (orig) ++ newstr = orig; ++ ++ /* ++ * If we've got GSSAPI mechanisms, then we've got the 'null' host ++ * key alg, but we can't tell people about it unless its the only ++ * host key algorithm we support ++ */ ++ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) ++ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xstrdup("null"); ++ ++ if (newstr) ++ myproposal[PROPOSAL_KEX_ALGS] = newstr; ++ else ++ fatal("No supported key exchange algorithms"); ++ } ++#endif ++ + /* start key exchange */ + if ((r = kex_setup(ssh, myproposal)) != 0) + fatal_r(r, "kex_setup"); +@@ -1479,7 +1522,18 @@ do_ssh2_kex(struct ssh *ssh) + #ifdef OPENSSL_HAS_ECC + kex->kex[KEX_ECDH_SHA2] = kex_gen_server; + #endif +-#endif ++# ifdef GSSAPI ++ if (options.gss_keyex) { ++ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; ++ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; ++ kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server; ++ kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server; ++ kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server; ++ kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server; ++ kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server; ++ } ++# endif ++#endif /* WITH_OPENSSL */ + kex->kex[KEX_C25519_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; + kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; +diff --color -ruNp a/ssh-gss.h b/ssh-gss.h +--- a/ssh-gss.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/ssh-gss.h 2024-09-16 11:46:34.710940224 +0200 +@@ -61,10 +61,36 @@ + + #define SSH_GSS_OIDTYPE 0x06 + ++#define SSH2_MSG_KEXGSS_INIT 30 ++#define SSH2_MSG_KEXGSS_CONTINUE 31 ++#define SSH2_MSG_KEXGSS_COMPLETE 32 ++#define SSH2_MSG_KEXGSS_HOSTKEY 33 ++#define SSH2_MSG_KEXGSS_ERROR 34 ++#define SSH2_MSG_KEXGSS_GROUPREQ 40 ++#define SSH2_MSG_KEXGSS_GROUP 41 ++#define KEX_GSS_GRP1_SHA1_ID "gss-group1-sha1-" ++#define KEX_GSS_GRP14_SHA1_ID "gss-group14-sha1-" ++#define KEX_GSS_GRP14_SHA256_ID "gss-group14-sha256-" ++#define KEX_GSS_GRP16_SHA512_ID "gss-group16-sha512-" ++#define KEX_GSS_GEX_SHA1_ID "gss-gex-sha1-" ++#define KEX_GSS_NISTP256_SHA256_ID "gss-nistp256-sha256-" ++#define KEX_GSS_C25519_SHA256_ID "gss-curve25519-sha256-" ++ ++#define GSS_KEX_DEFAULT_KEX \ ++ KEX_GSS_GRP14_SHA256_ID "," \ ++ KEX_GSS_GRP16_SHA512_ID "," \ ++ KEX_GSS_NISTP256_SHA256_ID "," \ ++ KEX_GSS_C25519_SHA256_ID "," \ ++ KEX_GSS_GRP14_SHA1_ID "," \ ++ KEX_GSS_GEX_SHA1_ID ++ ++#include "digest.h" /* SSH_DIGEST_MAX_LENGTH */ ++ + typedef struct { + char *filename; + char *envvar; + char *envval; ++ struct passwd *owner; + void *data; + } ssh_gssapi_ccache; + +@@ -72,8 +98,11 @@ typedef struct { + gss_buffer_desc displayname; + gss_buffer_desc exportedname; + gss_cred_id_t creds; ++ gss_name_t name; + struct ssh_gssapi_mech_struct *mech; + ssh_gssapi_ccache store; ++ int used; ++ int updated; + } ssh_gssapi_client; + + typedef struct ssh_gssapi_mech_struct { +@@ -84,6 +113,7 @@ typedef struct ssh_gssapi_mech_struct { + int (*userok) (ssh_gssapi_client *, char *); + int (*localname) (ssh_gssapi_client *, char **); + void (*storecreds) (ssh_gssapi_client *); ++ int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); + } ssh_gssapi_mech; + + typedef struct { +@@ -94,10 +124,21 @@ typedef struct { + gss_OID oid; /* client */ + gss_cred_id_t creds; /* server */ + gss_name_t client; /* server */ +- gss_cred_id_t client_creds; /* server */ ++ gss_cred_id_t client_creds; /* both */ ++ struct sshbuf *shared_secret; /* both */ ++ struct sshbuf *server_pubkey; /* server */ ++ struct sshbuf *server_blob; /* client */ ++ struct sshbuf *server_host_key_blob; /* client */ ++ gss_buffer_desc msg_tok; /* client */ ++ gss_buffer_desc buf; /* both */ ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; /* both */ ++ size_t hashlen; /* both */ ++ int first; /* client */ ++ BIGNUM *dh_client_pub; /* server (gex) */ + } Gssctxt; + + extern ssh_gssapi_mech *supported_mechs[]; ++extern Gssctxt *gss_kex_context; + + int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); + void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); +@@ -108,6 +149,7 @@ OM_uint32 ssh_gssapi_test_oid_supported( + + struct sshbuf; + int ssh_gssapi_get_buffer_desc(struct sshbuf *, gss_buffer_desc *); ++int ssh_gssapi_sshpkt_get_buffer_desc(struct ssh *, gss_buffer_desc *); + + OM_uint32 ssh_gssapi_import_name(Gssctxt *, const char *); + OM_uint32 ssh_gssapi_init_ctx(Gssctxt *, int, +@@ -122,17 +164,33 @@ void ssh_gssapi_delete_ctx(Gssctxt **); + OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); + void ssh_gssapi_buildmic(struct sshbuf *, const char *, + const char *, const char *, const struct sshbuf *); +-int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *); ++int ssh_gssapi_check_mechanism(Gssctxt **, gss_OID, const char *, const char *); ++OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); ++int ssh_gssapi_credentials_updated(Gssctxt *); + + /* In the server */ ++typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, ++ const char *); ++char *ssh_gssapi_client_mechanisms(const char *, const char *, const char *); ++char *ssh_gssapi_kex_mechs(gss_OID_set, ssh_gssapi_check_fn *, const char *, ++ const char *, const char *); ++gss_OID ssh_gssapi_id_kex(Gssctxt *, char *, int); ++int ssh_gssapi_server_check_mech(Gssctxt **,gss_OID, const char *, ++ const char *); + OM_uint32 ssh_gssapi_server_ctx(Gssctxt **, gss_OID); +-int ssh_gssapi_userok(char *name); ++int ssh_gssapi_userok(char *name, struct passwd *, int kex); + OM_uint32 ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); + void ssh_gssapi_do_child(char ***, u_int *); + void ssh_gssapi_cleanup_creds(void); + void ssh_gssapi_storecreds(void); + const char *ssh_gssapi_displayname(void); + ++char *ssh_gssapi_server_mechanisms(void); ++int ssh_gssapi_oid_table_ok(void); ++ ++int ssh_gssapi_update_creds(ssh_gssapi_ccache *store); ++void ssh_gssapi_rekey_creds(void); ++ + #endif /* GSSAPI */ + + #endif /* _SSH_GSS_H */ +diff --color -ruNp a/sshkey.c b/sshkey.c +--- a/sshkey.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/sshkey.c 2024-09-16 11:46:34.706940139 +0200 +@@ -131,6 +131,75 @@ extern const struct sshkey_impl sshkey_x + extern const struct sshkey_impl sshkey_xmss_cert_impl; + #endif + ++static int ssh_gss_equal(const struct sshkey *, const struct sshkey *) ++{ ++ return SSH_ERR_FEATURE_UNSUPPORTED; ++} ++ ++static int ssh_gss_serialize_public(const struct sshkey *, struct sshbuf *, ++ enum sshkey_serialize_rep) ++{ ++ return SSH_ERR_FEATURE_UNSUPPORTED; ++} ++ ++static int ssh_gss_deserialize_public(const char *, struct sshbuf *, ++ struct sshkey *) ++{ ++ return SSH_ERR_FEATURE_UNSUPPORTED; ++} ++ ++static int ssh_gss_serialize_private(const struct sshkey *, struct sshbuf *, ++ enum sshkey_serialize_rep) ++{ ++ return SSH_ERR_FEATURE_UNSUPPORTED; ++} ++ ++static int ssh_gss_deserialize_private(const char *, struct sshbuf *, ++ struct sshkey *) ++{ ++ return SSH_ERR_FEATURE_UNSUPPORTED; ++} ++ ++static int ssh_gss_copy_public(const struct sshkey *, struct sshkey *) ++{ ++ return SSH_ERR_FEATURE_UNSUPPORTED; ++} ++ ++static int ssh_gss_verify(const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int, ++ struct sshkey_sig_details **) ++{ ++ return SSH_ERR_FEATURE_UNSUPPORTED; ++} ++ ++static const struct sshkey_impl_funcs sshkey_gss_funcs = { ++ /* .size = */ NULL, ++ /* .alloc = */ NULL, ++ /* .cleanup = */ NULL, ++ /* .equal = */ ssh_gss_equal, ++ /* .ssh_serialize_public = */ ssh_gss_serialize_public, ++ /* .ssh_deserialize_public = */ ssh_gss_deserialize_public, ++ /* .ssh_serialize_private = */ ssh_gss_serialize_private, ++ /* .ssh_deserialize_private = */ ssh_gss_deserialize_private, ++ /* .generate = */ NULL, ++ /* .copy_public = */ ssh_gss_copy_public, ++ /* .sign = */ NULL, ++ /* .verify = */ ssh_gss_verify, ++}; ++ ++/* The struct is intentionally dummy and has no gss calls */ ++static const struct sshkey_impl sshkey_gss_kex_impl = { ++ /* .name = */ "null", ++ /* .shortname = */ "null", ++ /* .sigalg = */ NULL, ++ /* .type = */ KEY_NULL, ++ /* .nid = */ 0, ++ /* .cert = */ 0, ++ /* .sigonly = */ 0, ++ /* .keybits = */ 0, /* FIXME */ ++ /* .funcs = */ &sshkey_gss_funcs, ++}; ++ + const struct sshkey_impl * const keyimpls[] = { + &sshkey_ed25519_impl, + &sshkey_ed25519_cert_impl, +@@ -169,6 +238,7 @@ const struct sshkey_impl * const keyimpl + &sshkey_xmss_impl, + &sshkey_xmss_cert_impl, + #endif ++ &sshkey_gss_kex_impl, + NULL }; -@@ -255,7 +256,7 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) - const struct keytype *kt; +@@ -324,7 +394,7 @@ sshkey_alg_list(int certs_only, int plai - for (kt = keytypes; kt->type != -1; kt++) { -- if (kt->name == NULL) -+ if (kt->name == NULL || kt->type == KEY_NULL) + for (i = 0; keyimpls[i] != NULL; i++) { + impl = keyimpls[i]; +- if (impl->name == NULL) ++ if (impl->name == NULL || impl->type == KEY_NULL) continue; - if (!include_sigonly && kt->sigonly) + if (!include_sigonly && impl->sigonly) continue; -diff --git a/sshkey.h b/sshkey.h -index 71a3fddc..37a43a67 100644 ---- a/sshkey.h -+++ b/sshkey.h -@@ -69,6 +69,7 @@ enum sshkey_types { +diff --color -ruNp a/sshkey.h b/sshkey.h +--- a/sshkey.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/sshkey.h 2024-09-16 11:46:34.706940139 +0200 +@@ -71,6 +71,7 @@ enum sshkey_types { KEY_ECDSA_SK_CERT, KEY_ED25519_SK, KEY_ED25519_SK_CERT, diff --git a/SOURCES/openssh-9.6p1-pam-rhost.patch b/SOURCES/openssh-9.6p1-pam-rhost.patch new file mode 100644 index 0000000..b1b0d04 --- /dev/null +++ b/SOURCES/openssh-9.6p1-pam-rhost.patch @@ -0,0 +1,32 @@ +From 26f366e263e575c4e1a18e2e64ba418f58878b37 Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Mon, 20 Mar 2023 20:22:14 +0100 +Subject: [PATCH] Only set PAM_RHOST if the remote host is not "UNKNOWN" + +When using sshd's -i option with stdio that is not a AF_INET/AF_INET6 +socket, auth_get_canonical_hostname() returns "UNKNOWN" which is then +set as the value of PAM_RHOST, causing pam to try to do a reverse DNS +query of "UNKNOWN", which times out multiple times, causing a +substantial slowdown when logging in. + +To fix this, let's only set PAM_RHOST if the hostname is not "UNKNOWN". +--- + auth-pam.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/auth-pam.c b/auth-pam.c +index e143304e3..39b4e4563 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -735,7 +735,7 @@ sshpam_init(struct ssh *ssh, Authctxt *authctxt) + sshpam_laddr = get_local_ipaddr( + ssh_packet_get_connection_in(ssh)); + } +- if (sshpam_rhost != NULL) { ++ if (sshpam_rhost != NULL && strcmp(sshpam_rhost, "UNKNOWN") != 0) { + debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost); + sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, + sshpam_rhost); +-- +2.44.0 + diff --git a/SOURCES/openssh-9.8p1-upstream-cve-2024-6387.patch b/SOURCES/openssh-9.8p1-upstream-cve-2024-6387.patch deleted file mode 100644 index fffd50a..0000000 --- a/SOURCES/openssh-9.8p1-upstream-cve-2024-6387.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff -up openssh-8.7p1/log.c.xxx openssh-8.7p1/log.c ---- openssh-8.7p1/log.c.xxx 2024-06-28 11:02:43.949912398 +0200 -+++ openssh-8.7p1/log.c 2024-06-28 11:02:58.652297885 +0200 -@@ -455,12 +455,14 @@ void - sshsigdie(const char *file, const char *func, int line, int showfunc, - LogLevel level, const char *suffix, const char *fmt, ...) - { -+#if 0 - va_list args; - - va_start(args, fmt); - sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_FATAL, - suffix, fmt, args); - va_end(args); -+#endif - _exit(1); - } - -diff -up openssh-8.7p1/sshd.c.xxx openssh-8.7p1/sshd.c ---- openssh-8.7p1/sshd.c.xxx 2024-07-01 10:33:04.332907749 +0200 -+++ openssh-8.7p1/sshd.c 2024-07-01 10:33:47.843998038 +0200 -@@ -384,7 +384,7 @@ grace_alarm_handler(int sig) - - /* Log error and exit. */ - if (use_privsep && pmonitor != NULL && pmonitor->m_pid <= 0) -- cleanup_exit(255); /* don't log in privsep child */ -+ _exit(255); /* don't log in privsep child */ - else { - sigdie("Timeout before authentication for %s port %d", - ssh_remote_ipaddr(the_active_state), diff --git a/SOURCES/openssh-9.9p1-bad-hostkey.patch b/SOURCES/openssh-9.9p1-bad-hostkey.patch new file mode 100644 index 0000000..d4f11f1 --- /dev/null +++ b/SOURCES/openssh-9.9p1-bad-hostkey.patch @@ -0,0 +1,68 @@ +diff --color -ruNp a/hostfile.c b/hostfile.c +--- a/hostfile.c 2024-09-20 00:20:48.000000000 +0200 ++++ b/hostfile.c 2025-04-30 15:52:02.792091018 +0200 +@@ -63,6 +63,14 @@ + #include "hmac.h" + #include "sshbuf.h" + ++static int required_rsa_size = SSH_RSA_MINIMUM_MODULUS_SIZE; ++ ++void ++hostfile_set_minimum_rsa_size(int size) ++{ ++ required_rsa_size = size; ++} ++ + /* XXX hmac is too easy to dictionary attack; use bcrypt? */ + + static int +@@ -233,6 +241,7 @@ record_hostkey(struct hostkey_foreach_li + struct load_callback_ctx *ctx = (struct load_callback_ctx *)_ctx; + struct hostkeys *hostkeys = ctx->hostkeys; + struct hostkey_entry *tmp; ++ int r = 0; + + if (l->status == HKF_STATUS_INVALID) { + /* XXX make this verbose() in the future */ +@@ -241,6 +250,12 @@ record_hostkey(struct hostkey_foreach_li + return 0; + } + ++ if ((r = sshkey_check_rsa_length(l->key, required_rsa_size)) != 0) { ++ debug2_f("%s:%ld: ignoring hostkey: %s", ++ l->path, l->linenum, ssh_err(r)); ++ return 0; ++ } ++ + debug3_f("found %skey type %s in file %s:%lu", + l->marker == MRK_NONE ? "" : + (l->marker == MRK_CA ? "ca " : "revoked "), +diff --color -ruNp a/hostfile.h b/hostfile.h +--- a/hostfile.h 2024-09-20 00:20:48.000000000 +0200 ++++ b/hostfile.h 2025-04-30 15:17:44.789206468 +0200 +@@ -119,5 +119,6 @@ int hostkeys_foreach_file(const char *pa + const char *host, const char *ip, u_int options, u_int note); + + void hostfile_create_user_ssh_dir(const char *, int); ++void hostfile_set_minimum_rsa_size(int); + + #endif +diff --color -ruNp a/ssh.c b/ssh.c +--- a/ssh.c 2025-04-29 15:40:27.916735894 +0200 ++++ b/ssh.c 2025-04-30 15:19:48.856855308 +0200 +@@ -109,6 +109,7 @@ + #include "ssherr.h" + #include "myproposal.h" + #include "utf8.h" ++#include "hostfile.h" + + #ifdef ENABLE_PKCS11 + #include "ssh-pkcs11.h" +@@ -1395,6 +1396,7 @@ main(int ac, char **av) + options.update_hostkeys = 0; + } + } ++ hostfile_set_minimum_rsa_size(options.required_rsa_size); + if (options.connection_attempts <= 0) + fatal("Invalid number of ConnectionAttempts"); + diff --git a/SOURCES/openssh-9.9p1-canonical-match-user.patch b/SOURCES/openssh-9.9p1-canonical-match-user.patch new file mode 100644 index 0000000..1adf688 --- /dev/null +++ b/SOURCES/openssh-9.9p1-canonical-match-user.patch @@ -0,0 +1,120 @@ +diff --color -ruNp a/auth.c b/auth.c +--- a/auth.c 2025-10-29 09:57:20.440640281 +0100 ++++ b/auth.c 2025-10-29 09:57:54.747956792 +0100 +@@ -476,8 +476,12 @@ getpwnamallow(struct ssh *ssh, const cha + u_int i; + + ci = server_get_connection_info(ssh, 1, options.use_dns); +- ci->user = user; +- ci->user_invalid = getpwnam(user) == NULL; ++ pw = getpwnam(user); ++ if (pw != NULL && options.canonical_match_user) ++ ci->user = pw->pw_name; ++ else ++ ci->user = user; ++ ci->user_invalid = pw == NULL; + parse_server_match_config(&options, &includes, ci); + log_change_level(options.log_level); + log_verbose_reset(); +diff --color -ruNp a/servconf.c b/servconf.c +--- a/servconf.c 2025-10-29 09:57:20.502465586 +0100 ++++ b/servconf.c 2025-10-29 09:57:54.748205464 +0100 +@@ -225,6 +225,7 @@ initialize_server_options(ServerOptions + options->unused_connection_timeout = -1; + options->sshd_session_path = NULL; + options->refuse_connection = -1; ++ options->canonical_match_user = -1; + } + + /* Returns 1 if a string option is unset or set to "none" or 0 otherwise. */ +@@ -526,6 +527,8 @@ fill_default_server_options(ServerOption + options->sshd_session_path = xstrdup(_PATH_SSHD_SESSION); + if (options->refuse_connection == -1) + options->refuse_connection = 0; ++ if (options->canonical_match_user == -1) ++ options->canonical_match_user = 0; + + assemble_algorithms(options); + +@@ -609,7 +612,7 @@ typedef enum { + sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding, + sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider, + sRequiredRSASize, sChannelTimeout, sUnusedConnectionTimeout, +- sSshdSessionPath, sRefuseConnection, ++ sSshdSessionPath, sRefuseConnection, sCanonicalMatchUser, + sDeprecated, sIgnore, sUnsupported + } ServerOpCodes; + +@@ -798,6 +801,7 @@ static struct { + { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, + { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL }, + { "refuseconnection", sRefuseConnection, SSHCFG_ALL }, ++ { "canonicalmatchuser", sCanonicalMatchUser, SSHCFG_GLOBAL }, + { NULL, sBadOption, 0 } + }; + +@@ -2807,6 +2811,11 @@ process_server_config_line_depth(ServerO + multistate_ptr = multistate_flag; + goto parse_multistate; + ++ case sCanonicalMatchUser: ++ intptr = &options->canonical_match_user; ++ multistate_ptr = multistate_flag; ++ goto parse_multistate; ++ + case sDeprecated: + case sIgnore: + case sUnsupported: +@@ -3028,6 +3037,7 @@ copy_set_server_options(ServerOptions *d + M_CP_INTOPT(required_rsa_size); + M_CP_INTOPT(unused_connection_timeout); + M_CP_INTOPT(refuse_connection); ++ M_CP_INTOPT(canonical_match_user); + + /* + * The bind_mask is a mode_t that may be unsigned, so we can't use +@@ -3368,6 +3378,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); + dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info); + dump_cfg_fmtint(sRefuseConnection, o->refuse_connection); ++ dump_cfg_fmtint(sCanonicalMatchUser, o->canonical_match_user); + + /* string arguments */ + dump_cfg_string(sPidFile, o->pid_file); +diff --color -ruNp a/servconf.h b/servconf.h +--- a/servconf.h 2025-10-29 09:57:20.503199202 +0100 ++++ b/servconf.h 2025-10-29 09:57:54.749236422 +0100 +@@ -261,6 +261,8 @@ typedef struct { + char *sshd_session_path; + + int refuse_connection; ++ ++ int canonical_match_user; + } ServerOptions; + + /* Information about the incoming connection as used by Match */ +diff --color -ruNp a/sshd_config.5 b/sshd_config.5 +--- a/sshd_config.5 2025-10-29 09:57:20.503465608 +0100 ++++ b/sshd_config.5 2025-10-29 09:57:54.749544972 +0100 +@@ -1384,6 +1384,7 @@ Available keywords are + .Cm PubkeyAuthentication , + .Cm PubkeyAuthOptions , + .Cm RefuseConnection , ++.Cm CanonicalMatchUser , + .Cm RekeyLimit , + .Cm RevokedKeys , + .Cm RDomain , +@@ -1828,6 +1829,13 @@ are enabled. + This option is only really useful in a + .Cm Match + block. ++.It Cm CanonicalMatchUser ++Some password databases allow users to define aliases for their username. ++This directive indicates that ++.Xr sshd 8 ++should attempt to first obtain a canonical username from a password database before evaluating a ++.Cm Match User ++conditional block. + .It Cm RekeyLimit + Specifies the maximum amount of data that may be transmitted or received + before the session key is renegotiated, optionally followed by a maximum diff --git a/SOURCES/openssh-9.9p1-compat-mlkem.patch b/SOURCES/openssh-9.9p1-compat-mlkem.patch new file mode 100644 index 0000000..bc2393c --- /dev/null +++ b/SOURCES/openssh-9.9p1-compat-mlkem.patch @@ -0,0 +1,101 @@ +diff -up openssh-9.9p1/compat.c.xxx openssh-9.9p1/compat.c +--- openssh-9.9p1/compat.c.xxx 2026-02-25 12:58:14.083760269 +0100 ++++ openssh-9.9p1/compat.c 2026-02-25 13:28:21.154300255 +0100 +@@ -36,6 +36,9 @@ + #include "compat.h" + #include "log.h" + #include "match.h" ++#include ++#include ++#include + + /* determine bug flags from SSH protocol banner */ + void +@@ -143,13 +145,40 @@ compat_banner(struct ssh *ssh, const cha + ssh->compat |= SSH_RH_RSASIGSHA; + } + ++/* ++ * 0 - unavailable ++ * 1 - available in non-FIPS mode ++ * 2 - available always ++ */ ++static int is_mlkem768_available() ++{ ++ static int is_fetched = -1; ++ ++ if (is_fetched == -1) { ++ EVP_KEM *mlkem768 = NULL; ++ ++ ERR_set_mark(); ++ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ is_fetched = (mlkem768 == NULL) ? 0 : 2; ++ if (is_fetched == 0 && FIPS_mode() == 1) { ++ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", "provider=default,-fips"); ++ is_fetched = (mlkem768 == NULL) ? 0 : 1; ++ } ++ EVP_KEM_free(mlkem768); ++ ERR_pop_to_mark(); ++ } ++ ++ return is_fetched; ++} ++ + /* Always returns pointer to allocated memory, caller must free. */ + char * + compat_kex_proposal(struct ssh *ssh, const char *p) + { + char *cp = NULL, *cp2 = NULL; ++ int ml_kem_available = is_mlkem768_available(); + +- if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0) ++ if ((ssh->compat & (SSH_BUG_CURVE25519PAD|SSH_OLD_DHGEX)) == 0 && is_mlkem768_available() == 2) + return xstrdup(p); + debug2_f("original KEX proposal: %s", p); + if ((ssh->compat & SSH_BUG_CURVE25519PAD) != 0) +@@ -164,6 +199,25 @@ compat_kex_proposal(struct ssh *ssh, con + free(cp); + cp = cp2; + } ++ if (ml_kem_available == 2) ++ return cp ? cp : xstrdup(p); ++ if (ml_kem_available == 1 && FIPS_mode()) { ++ if ((cp2 = match_filter_denylist(cp ? cp : p, ++ "mlkem768x25519-sha256")) == NULL) ++ fatal("match_filter_denylist failed"); ++ free(cp); ++ cp = cp2; ++ } ++ if (ml_kem_available == 0) { ++ if ((cp2 = match_filter_denylist(cp ? cp : p, ++ "mlkem768x25519-sha256," ++ "mlkem768nistp256-sha256," ++ "mlkem1024nistp384-sha384")) == NULL) ++ fatal("match_filter_denylist failed"); ++ free(cp); ++ cp = cp2; ++ } ++ + if (cp == NULL || *cp == '\0') + fatal("No supported key exchange algorithms found"); + debug2_f("compat KEX proposal: %s", cp); +diff -up openssh-9.9p1/kex-names.c.xxx openssh-9.9p1/kex-names.c +--- openssh-9.9p1/kex-names.c.xxx 2026-02-25 14:52:59.802597974 +0100 ++++ openssh-9.9p1/kex-names.c 2026-02-25 15:31:13.376020525 +0100 +@@ -291,8 +291,14 @@ kex_names_valid(const char *names) + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + if (kex_alg_by_name(p) == NULL) { +- if (FIPS_mode()) +- error("\"%.100s\" is not allowed in FIPS mode", p); ++ if (FIPS_mode()) { ++ if ((strcmp(p, KEX_MLKEM768X25519_SHA256) == 0)) { ++ debug("\"%.100s\" is not allowed in FIPS mode", p); ++ continue; ++ } ++ else ++ error("\"%.100s\" is not allowed in FIPS mode", p); ++ } + else + error("Unsupported KEX algorithm \"%.100s\"", p); + free(s); diff --git a/SOURCES/openssh-9.9p1-compression-directive.patch b/SOURCES/openssh-9.9p1-compression-directive.patch new file mode 100644 index 0000000..96d44e1 --- /dev/null +++ b/SOURCES/openssh-9.9p1-compression-directive.patch @@ -0,0 +1,13 @@ +diff --git a/readconf.c b/readconf.c +index 9f559269..777739d6 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -3410,6 +3410,8 @@ fmt_intarg(OpCodes code, int val) + switch (code) { + case oAddressFamily: + return fmt_multistate_int(val, multistate_addressfamily); ++ case oCompression: ++ return fmt_multistate_int(val, multistate_compression); + case oVerifyHostKeyDNS: + case oUpdateHostkeys: + return fmt_multistate_int(val, multistate_yesnoask); diff --git a/SOURCES/openssh-9.9p1-disable-forwarding.patch b/SOURCES/openssh-9.9p1-disable-forwarding.patch new file mode 100644 index 0000000..45a021e --- /dev/null +++ b/SOURCES/openssh-9.9p1-disable-forwarding.patch @@ -0,0 +1,22 @@ +diff --color -ruNp a/session.c b/session.c +--- a/session.c 2025-04-29 11:20:59.475107377 +0200 ++++ b/session.c 2025-04-29 11:23:16.638538968 +0200 +@@ -2284,7 +2284,8 @@ session_auth_agent_req(struct ssh *ssh, + if ((r = sshpkt_get_end(ssh)) != 0) + sshpkt_fatal(ssh, r, "%s: parse packet", __func__); + if (!auth_opts->permit_agent_forwarding_flag || +- !options.allow_agent_forwarding) { ++ !options.allow_agent_forwarding || ++ options.disable_forwarding) { + debug_f("agent forwarding disabled"); + return 0; + } +@@ -2709,7 +2710,7 @@ session_setup_x11fwd(struct ssh *ssh, Se + ssh_packet_send_debug(ssh, "X11 forwarding disabled by key options."); + return 0; + } +- if (!options.x11_forwarding) { ++ if (!options.x11_forwarding || options.disable_forwarding) { + debug("X11 forwarding disabled in server configuration file."); + return 0; + } diff --git a/SOURCES/openssh-9.9p1-fips-gss.patch b/SOURCES/openssh-9.9p1-fips-gss.patch new file mode 100644 index 0000000..c94e34c --- /dev/null +++ b/SOURCES/openssh-9.9p1-fips-gss.patch @@ -0,0 +1,42 @@ +diff -up openssh-9.9p1-build/openssh-9.9p1/gss-genr.c.xxx openssh-9.9p1-build/openssh-9.9p1/gss-genr.c +--- a/gss-genr.c.xxx 2025-09-01 17:15:41.070677784 +0200 ++++ b/gss-genr.c 2025-09-01 17:31:20.376362078 +0200 +@@ -149,19 +149,29 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup + for (i = 0; i < gss_supported->count; i++) { + if (gss_supported->elements[i].length < 128 && + (*check)(NULL, &(gss_supported->elements[i]), host, client)) { ++ EVP_MD_CTX * ctx = NULL; ++ EVP_MD *md5 = NULL; /* Here we don't use MD5 for crypto purposes */ ++ unsigned int md_size = sizeof(digest); + + deroid[0] = SSH_GSS_OIDTYPE; + deroid[1] = gss_supported->elements[i].length; +- +- if ((md = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || +- (r = ssh_digest_update(md, deroid, 2)) != 0 || +- (r = ssh_digest_update(md, +- gss_supported->elements[i].elements, +- gss_supported->elements[i].length)) != 0 || +- (r = ssh_digest_final(md, digest, sizeof(digest))) != 0) ++ if ((md5 = EVP_MD_fetch(NULL, "MD5", "provider=default,-fips")) == NULL) ++ fatal_fr(r, "MD5 fetch failed"); ++ if ((ctx = EVP_MD_CTX_new()) == NULL) { ++ EVP_MD_free(md5); ++ fatal_fr(r, "digest ctx failed"); ++ } ++ if (EVP_DigestInit(ctx, md5) <= 0 ++ || EVP_DigestUpdate(ctx, deroid, 2) <= 0 ++ || EVP_DigestUpdate(ctx, gss_supported->elements[i].elements, ++ gss_supported->elements[i].length) <= 0 ++ || EVP_DigestFinal(ctx, digest, &md_size) <= 0) { ++ EVP_MD_free(md5); ++ EVP_MD_CTX_free(ctx); + fatal_fr(r, "digest failed"); +- ssh_digest_free(md); +- md = NULL; ++ } ++ EVP_MD_free(md5); md5 = NULL; ++ EVP_MD_CTX_free(ctx); ctx = NULL; + + encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5) + * 2); diff --git a/SOURCES/openssh-9.9p1-match-regression.patch b/SOURCES/openssh-9.9p1-match-regression.patch new file mode 100644 index 0000000..73ea964 --- /dev/null +++ b/SOURCES/openssh-9.9p1-match-regression.patch @@ -0,0 +1,471 @@ +diff --git a/misc.c b/misc.c +index afdf5142..1b4b55c5 100644 +--- a/misc.c ++++ b/misc.c +@@ -107,6 +107,27 @@ rtrim(char *s) + } + } + ++/* ++ * returns pointer to character after 'prefix' in 's' or otherwise NULL ++ * if the prefix is not present. ++ */ ++const char * ++strprefix(const char *s, const char *prefix, int ignorecase) ++{ ++ size_t prefixlen; ++ ++ if ((prefixlen = strlen(prefix)) == 0) ++ return s; ++ if (ignorecase) { ++ if (strncasecmp(s, prefix, prefixlen) != 0) ++ return NULL; ++ } else { ++ if (strncmp(s, prefix, prefixlen) != 0) ++ return NULL; ++ } ++ return s + prefixlen; ++} ++ + /* set/unset filedescriptor to non-blocking */ + int + set_nonblock(int fd) +diff --git a/misc.h b/misc.h +index 11340389..efecdf1a 100644 +--- a/misc.h ++++ b/misc.h +@@ -56,6 +56,7 @@ struct ForwardOptions { + char *chop(char *); + void rtrim(char *); + void skip_space(char **); ++const char *strprefix(const char *, const char *, int); + char *strdelim(char **); + char *strdelimw(char **); + int set_nonblock(int); +diff --git a/readconf.c b/readconf.c +index 3d9cc6db..9f559269 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -710,7 +710,7 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + struct passwd *pw, const char *host_arg, const char *original_host, + int final_pass, int *want_final_pass, const char *filename, int linenum) + { +- char *arg, *oattrib, *attrib, *cmd, *host, *criteria; ++ char *arg, *oattrib = NULL, *attrib = NULL, *cmd, *host, *criteria; + const char *ruser; + int r, this_result, result = 1, attributes = 0, negate; + +@@ -731,7 +731,8 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + + debug2("checking match for '%s' host %s originally %s", + full_line, host, original_host); +- while ((oattrib = attrib = argv_next(acp, avp)) != NULL) { ++ while ((attrib = argv_next(acp, avp)) != NULL) { ++ attrib = oattrib = xstrdup(attrib); + /* Terminate on comment */ + if (*attrib == '#') { + argv_consume(acp); +@@ -777,9 +778,23 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + this_result ? "" : "not ", oattrib); + continue; + } ++ ++ /* Keep this list in sync with below */ ++ if (strprefix(attrib, "host=", 1) != NULL || ++ strprefix(attrib, "originalhost=", 1) != NULL || ++ strprefix(attrib, "user=", 1) != NULL || ++ strprefix(attrib, "localuser=", 1) != NULL || ++ strprefix(attrib, "localnetwork=", 1) != NULL || ++ strprefix(attrib, "tagged=", 1) != NULL || ++ strprefix(attrib, "exec=", 1) != NULL) { ++ arg = strchr(attrib, '='); ++ *(arg++) = '\0'; ++ } else { ++ arg = argv_next(acp, avp); ++ } ++ + /* All other criteria require an argument */ +- if ((arg = argv_next(acp, avp)) == NULL || +- *arg == '\0' || *arg == '#') { ++ if (arg == NULL || *arg == '\0' || *arg == '#') { + error("Missing Match criteria for %s", attrib); + result = -1; + goto out; +@@ -856,6 +871,8 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + criteria == NULL ? "" : criteria, + criteria == NULL ? "" : "\""); + free(criteria); ++ free(oattrib); ++ oattrib = attrib = NULL; + } + if (attributes == 0) { + error("One or more attributes required for Match"); +@@ -865,6 +882,7 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + out: + if (result != -1) + debug2("match %sfound", result ? "" : "not "); ++ free(oattrib); + free(host); + return result; + } +diff --git a/servconf.c b/servconf.c +index 89b8413e..dd774f46 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -1,4 +1,4 @@ +-/* $OpenBSD: servconf.c,v 1.418 2024/09/15 03:09:44 djm Exp $ */ ++/* $OpenBSD: servconf.c,v 1.419 2024/09/25 01:24:04 djm Exp $ */ + /* + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved +@@ -1033,7 +1033,7 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + int line, struct connection_info *ci) + { + int result = 1, attributes = 0, port; +- char *arg, *attrib; ++ char *arg, *attrib = NULL, *oattrib; + + if (ci == NULL) + debug3("checking syntax for 'Match %s'", full_line); +@@ -1047,7 +1047,8 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + ci->laddress ? ci->laddress : "(null)", ci->lport); + } + +- while ((attrib = argv_next(acp, avp)) != NULL) { ++ while ((oattrib = argv_next(acp, avp)) != NULL) { ++ attrib = xstrdup(oattrib); + /* Terminate on comment */ + if (*attrib == '#') { + argv_consume(acp); /* mark all arguments consumed */ +@@ -1062,16 +1063,20 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + *arg != '\0' && *arg != '#')) { + error("'all' cannot be combined with other " + "Match attributes"); +- return -1; ++ result = -1; ++ goto out; + } + if (arg != NULL && *arg == '#') + argv_consume(acp); /* consume remaining args */ +- return 1; ++ result = 1; ++ goto out; + } + /* Criterion "invalid-user" also has no argument */ + if (strcasecmp(attrib, "invalid-user") == 0) { +- if (ci == NULL) ++ if (ci == NULL) { ++ result = 0; + continue; ++ } + if (ci->user_invalid == 0) + result = 0; + else +@@ -1078,11 +1081,26 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + debug("matched invalid-user at line %d", line); + continue; + } ++ ++ /* Keep this list in sync with below */ ++ if (strprefix(attrib, "user=", 1) != NULL || ++ strprefix(attrib, "group=", 1) != NULL || ++ strprefix(attrib, "host=", 1) != NULL || ++ strprefix(attrib, "address=", 1) != NULL || ++ strprefix(attrib, "localaddress=", 1) != NULL || ++ strprefix(attrib, "localport=", 1) != NULL || ++ strprefix(attrib, "rdomain=", 1) != NULL) { ++ arg = strchr(attrib, '='); ++ *(arg++) = '\0'; ++ } else { ++ arg = argv_next(acp, avp); ++ } ++ + /* All other criteria require an argument */ +- if ((arg = argv_next(acp, avp)) == NULL || +- *arg == '\0' || *arg == '#') { ++ if (arg == NULL || *arg == '\0' || *arg == '#') { + error("Missing Match criteria for %s", attrib); +- return -1; ++ result = -1; ++ goto out; + } + if (strcasecmp(attrib, "user") == 0) { + if (ci == NULL || (ci->test && ci->user == NULL)) { +@@ -1105,7 +1123,8 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + match_test_missing_fatal("Group", "user"); + switch (match_cfg_line_group(arg, line, ci->user)) { + case -1: +- return -1; ++ result = -1; ++ goto out; + case 0: + result = 0; + } +@@ -1141,7 +1160,8 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + result = 0; + break; + case -2: +- return -1; ++ result = -1; ++ goto out; + } + } else if (strcasecmp(attrib, "localaddress") == 0){ + if (ci == NULL || (ci->test && ci->laddress == NULL)) { +@@ -1166,13 +1186,15 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + result = 0; + break; + case -2: +- return -1; ++ result = -1; ++ goto out; + } + } else if (strcasecmp(attrib, "localport") == 0) { + if ((port = a2port(arg)) == -1) { + error("Invalid LocalPort '%s' on Match line", + arg); +- return -1; ++ result = -1; ++ goto out; + } + if (ci == NULL || (ci->test && ci->lport == -1)) { + result = 0; +@@ -1200,16 +1222,21 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + debug("user %.100s matched 'RDomain %.100s' at " + "line %d", ci->rdomain, arg, line); + } else { +- error("Unsupported Match attribute %s", attrib); +- return -1; ++ error("Unsupported Match attribute %s", oattrib); ++ result = -1; ++ goto out; + } ++ free(attrib); ++ attrib = NULL; + } + if (attributes == 0) { + error("One or more attributes required for Match"); + return -1; + } +- if (ci != NULL) ++ out: ++ if (ci != NULL && result != -1) + debug3("match %sfound", result ? "" : "not "); ++ free(attrib); + return result; + } + +diff --git a/regress/cfginclude.sh b/regress/cfginclude.sh +index d442cdd6..97fd816f 100644 +--- a/regress/cfginclude.sh ++++ b/regress/cfginclude.sh +@@ -1,4 +1,4 @@ +-# $OpenBSD: cfginclude.sh,v 1.4 2024/09/03 05:58:56 djm Exp $ ++# $OpenBSD: cfginclude.sh,v 1.5 2024/09/27 01:05:54 djm Exp $ + # Placed in the Public Domain. + + tid="config include" +@@ -10,7 +10,7 @@ cat > $OBJ/ssh_config.i << _EOF + Match host a + Hostname aa + +-Match host b # comment ++Match host=b # comment + Hostname bb + Include $OBJ/ssh_config.i.* + +@@ -18,7 +18,7 @@ Match host c + Include $OBJ/ssh_config.i.* + Hostname cc + +-Match host m ++Match host=m !user xxxyfake + Include $OBJ/ssh_config.i.* # comment + + Host d +@@ -41,7 +41,7 @@ Match host xxxxxx + _EOF + + cat > $OBJ/ssh_config.i.1 << _EOF +-Match host a ++Match host=a + Hostname aaa + + Match host b +@@ -64,10 +64,10 @@ cat > $OBJ/ssh_config.i.2 << _EOF + Match host a + Hostname aaaa + +-Match host b ++Match host=b !user blahblahfake + Hostname bbbb + +-Match host c ++Match host=c + Hostname cccc + + Host d +@@ -142,7 +142,7 @@ trial a aa + + # cleanup + rm -f $OBJ/ssh_config.i $OBJ/ssh_config.i.* $OBJ/ssh_config.out +-# $OpenBSD: cfginclude.sh,v 1.4 2024/09/03 05:58:56 djm Exp $ ++# $OpenBSD: cfginclude.sh,v 1.5 2024/09/27 01:05:54 djm Exp $ + # Placed in the Public Domain. + + tid="config include" +diff --git a/regress/cfgmatch.sh b/regress/cfgmatch.sh +index 05a66685..2737a5f9 100644 +--- a/regress/cfgmatch.sh ++++ b/regress/cfgmatch.sh +@@ -1,4 +1,4 @@ +-# $OpenBSD: cfgmatch.sh,v 1.13 2021/06/08 06:52:43 djm Exp $ ++# $OpenBSD: cfgmatch.sh,v 1.14 2024/09/27 01:05:54 djm Exp $ + # Placed in the Public Domain. + + tid="sshd_config match" +@@ -26,7 +26,7 @@ start_client() + kill $client_pid + fatal "timeout waiting for background ssh" + fi +- done ++ done + } + + stop_client() +@@ -119,40 +119,42 @@ stop_client + # requires knowledge of actual group memberships user running the test). + params="user:user:u1 host:host:h1 address:addr:1.2.3.4 \ + localaddress:laddr:5.6.7.8 rdomain:rdomain:rdom1" +-cp $OBJ/sshd_proxy_bak $OBJ/sshd_config +-echo 'Banner /nomatch' >>$OBJ/sshd_config +-for i in $params; do +- config=`echo $i | cut -f1 -d:` +- criteria=`echo $i | cut -f2 -d:` +- value=`echo $i | cut -f3 -d:` +- cat >>$OBJ/sshd_config </dev/null || \ ++ fail "validate config for w/out spec" ++ ++ # Test matching each criteria. ++ for i in $params; do ++ testcriteria=`echo $i | cut -f2 -d:` ++ expected=/`echo $i | cut -f3 -d:` ++ spec="" ++ for j in $params; do ++ config=`echo $j | cut -f1 -d:` ++ criteria=`echo $j | cut -f2 -d:` ++ value=`echo $j | cut -f3 -d:` ++ if [ "$criteria" = "$testcriteria" ]; then ++ spec="$criteria=$value,$spec" ++ else ++ spec="$criteria=1$value,$spec" ++ fi ++ done ++ trace "test spec $spec" ++ result=`${SUDO} ${SSHD} -f $OBJ/sshd_config -T -C "$spec" | \ ++ awk '$1=="banner"{print $2}'` ++ if [ "$result" != "$expected" ]; then ++ fail "match $config expected $expected got $result" + fi + done +- trace "test spec $spec" +- result=`${SUDO} ${SSHD} -f $OBJ/sshd_config -T -C "$spec" | \ +- awk '$1=="banner"{print $2}'` +- if [ "$result" != "$expected" ]; then +- fail "match $config expected $expected got $result" +- fi + done +diff --git a/regress/servcfginclude.sh b/regress/servcfginclude.sh +index 518a703d..f67c3caa 100644 +--- a/regress/servcfginclude.sh ++++ b/regress/servcfginclude.sh +@@ -4,14 +4,14 @@ tid="server config include" + + cat > $OBJ/sshd_config.i << _EOF + HostKey $OBJ/host.ssh-ed25519 +-Match host a ++Match host=a + Banner /aa + + Match host b + Banner /bb + Include $OBJ/sshd_config.i.* # comment + +-Match host c ++Match host=c + Include $OBJ/sshd_config.i.* # comment + Banner /cc + +@@ -25,7 +25,7 @@ Match Host e + Banner /ee + Include $OBJ/sshd_config.i.* + +-Match Host f ++Match Host=f + Include $OBJ/sshd_config.i.* + Banner /ff + +@@ -47,13 +47,13 @@ Match host b + Match host c + Banner /ccc + +-Match Host d ++Match Host=d + Banner /ddd + + Match Host e + Banner /eee + +-Match Host f ++Match Host=f + Banner /fff + _EOF + +@@ -61,13 +61,13 @@ cat > $OBJ/sshd_config.i.2 << _EOF + Match host a + Banner /aaaa + +-Match host b ++Match host=b + Banner /bbbb + + Match host c # comment + Banner /cccc + +-Match Host d ++Match Host=d + Banner /dddd + + Match Host e diff --git a/SOURCES/openssh-9.9p1-mlkembe.patch b/SOURCES/openssh-9.9p1-mlkembe.patch new file mode 100644 index 0000000..aa0c26c --- /dev/null +++ b/SOURCES/openssh-9.9p1-mlkembe.patch @@ -0,0 +1,98 @@ +diff --git a/kexmlkem768x25519.c b/kexmlkem768x25519.c +index 679446e9..2b5d3960 100644 +--- a/kexmlkem768x25519.c ++++ b/kexmlkem768x25519.c +@@ -1,4 +1,4 @@ +-/* $OpenBSD: kexmlkem768x25519.c,v 1.1 2024/09/02 12:13:56 djm Exp $ */ ++/* $OpenBSD: kexmlkem768x25519.c,v 1.2 2024/10/27 02:06:59 djm Exp $ */ + /* + * Copyright (c) 2023 Markus Friedl. All rights reserved. + * +@@ -34,6 +34,9 @@ + #include + #include + #include ++#ifdef HAVE_ENDIAN_H ++# include ++#endif + + #include "sshkey.h" + #include "kex.h" +diff --git a/libcrux_mlkem768_sha3.h b/libcrux_mlkem768_sha3.h +index a82d60e8..b8ac1436 100644 +--- a/libcrux_mlkem768_sha3.h ++++ b/libcrux_mlkem768_sha3.h +@@ -1,4 +1,5 @@ +-/* $OpenBSD: libcrux_mlkem768_sha3.h,v 1.1 2024/09/02 12:13:56 djm Exp $ */ ++/* $OpenBSD: libcrux_mlkem768_sha3.h,v 1.2 2024/10/27 02:06:01 djm Exp $ */ ++ + /* Extracted from libcrux revision 84c5d87b3092c59294345aa269ceefe0eb97cc35 */ + + /* +@@ -160,18 +161,19 @@ static inline void Eurydice_slice_to_array3(uint8_t *dst_tag, char *dst_ok, + // CORE STUFF (conversions, endianness, ...) + + static inline void core_num__u64_9__to_le_bytes(uint64_t v, uint8_t buf[8]) { ++ v = htole64(v); + memcpy(buf, &v, sizeof(v)); + } + static inline uint64_t core_num__u64_9__from_le_bytes(uint8_t buf[8]) { + uint64_t v; + memcpy(&v, buf, sizeof(v)); +- return v; ++ return le64toh(v); + } + + static inline uint32_t core_num__u32_8__from_le_bytes(uint8_t buf[4]) { + uint32_t v; + memcpy(&v, buf, sizeof(v)); +- return v; ++ return le32toh(v); + } + + static inline uint32_t core_num__u8_6__count_ones(uint8_t x0) { +diff --git a/mlkem768.sh b/mlkem768.sh +index 2fdc2831..3d12b2ed 100644 +--- a/mlkem768.sh ++++ b/mlkem768.sh +@@ -1,9 +1,10 @@ + #!/bin/sh +-# $OpenBSD: mlkem768.sh,v 1.2 2024/09/04 05:11:33 djm Exp $ ++# $OpenBSD: mlkem768.sh,v 1.3 2024/10/27 02:06:01 djm Exp $ + # Placed in the Public Domain. + # + +-WANT_LIBCRUX_REVISION="origin/main" ++#WANT_LIBCRUX_REVISION="origin/main" ++WANT_LIBCRUX_REVISION="84c5d87b3092c59294345aa269ceefe0eb97cc35" + + FILES=" + libcrux/libcrux-ml-kem/cg/eurydice_glue.h +@@ -47,6 +48,7 @@ echo '#define KRML_NOINLINE __attribute__((noinline, unused))' + echo '#define KRML_HOST_EPRINTF(...)' + echo '#define KRML_HOST_EXIT(x) fatal_f("internal error")' + echo ++ + for i in $FILES; do + echo "/* from $i */" + # Changes to all files: +@@ -56,11 +58,16 @@ for i in $FILES; do + -e 's/[ ]*$//' \ + $i | \ + case "$i" in +- # XXX per-file handling goes here. ++ */libcrux-ml-kem/cg/eurydice_glue.h) ++ # Replace endian functions with versions that work. ++ perl -0777 -pe 's/(static inline void core_num__u64_9__to_le_bytes.*\n)([^}]*\n)/\1 v = htole64(v);\n\2/' | ++ perl -0777 -pe 's/(static inline uint64_t core_num__u64_9__from_le_bytes.*?)return v;/\1return le64toh(v);/s' | ++ perl -0777 -pe 's/(static inline uint32_t core_num__u32_8__from_le_bytes.*?)return v;/\1return le32toh(v);/s' ++ ;; + # Default: pass through. + *) +- cat +- ;; ++ cat ++ ;; + esac + echo + done diff --git a/SOURCES/openssh-9.9p1-non-supported-keys-err-msg.patch b/SOURCES/openssh-9.9p1-non-supported-keys-err-msg.patch new file mode 100644 index 0000000..e2adce4 --- /dev/null +++ b/SOURCES/openssh-9.9p1-non-supported-keys-err-msg.patch @@ -0,0 +1,12 @@ +diff --color -ruNp a/sshkey.c b/sshkey.c +--- a/sshkey.c 2025-04-29 11:20:59.484832762 +0200 ++++ b/sshkey.c 2025-04-29 11:28:32.349323029 +0200 +@@ -3599,6 +3599,8 @@ translate_libcrypto_error(unsigned long + } + case ERR_LIB_ASN1: + return SSH_ERR_INVALID_FORMAT; ++ case ERR_LIB_OSSL_DECODER: ++ return SSH_ERR_INVALID_FORMAT; + } + return SSH_ERR_LIBCRYPTO_ERROR; + } diff --git a/SOURCES/openssh-9.9p1-openssl-mlkem.patch b/SOURCES/openssh-9.9p1-openssl-mlkem.patch new file mode 100644 index 0000000..e39bb67 --- /dev/null +++ b/SOURCES/openssh-9.9p1-openssl-mlkem.patch @@ -0,0 +1,385 @@ +diff --git a/kex-names.c b/kex-names.c +index ec840c1f..c0d3be11 100644 +--- a/kex-names.c ++++ b/kex-names.c +@@ -90,6 +90,19 @@ static const struct kexalg kexalgs[] = { + { NULL, 0, -1, -1}, + }; + ++static int is_mlkem768_available() ++{ ++ static int is_fetched = -1; ++ ++ if (is_fetched == -1) { ++ EVP_KEM *mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ is_fetched = mlkem768 != NULL ? 1 : 0; ++ EVP_KEM_free(mlkem768); ++ } ++ ++ return is_fetched; ++} ++ + static char * + kex_alg_list_internal(char sep, const struct kexalg *algs) + { +@@ -98,6 +111,9 @@ kex_alg_list_internal(char sep, const struct kexalg *algs) + const struct kexalg *k; + + for (k = algs; k->name != NULL; k++) { ++ if (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0 ++ && !is_mlkem768_available()) ++ continue; + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(k->name); +@@ -117,6 +133,10 @@ kex_alg_by_name(const char *name) + { + const struct kexalg *k; + ++ if (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0 ++ && !is_mlkem768_available()) ++ return NULL; ++ + for (k = kexalgs; k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; +diff --git a/kexmlkem768x25519.c b/kexmlkem768x25519.c +index 2b5d3960..670049dc 100644 +--- a/kexmlkem768x25519.c ++++ b/kexmlkem768x25519.c +@@ -48,10 +48,127 @@ + #ifdef USE_MLKEM768X25519 + + #include "libcrux_mlkem768_sha3.h" ++#include ++#include ++#include ++ ++static int ++mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) ++{ ++ EVP_PKEY_CTX *ctx = NULL; ++ EVP_PKEY *pkey = NULL; ++ int ret = SSH_ERR_INTERNAL_ERROR; ++ size_t pubkey_size = crypto_kem_mlkem768_PUBLICKEYBYTES, privkey_size = crypto_kem_mlkem768_SECRETKEYBYTES; ++ ++ ctx = EVP_PKEY_CTX_new_from_name(NULL, "mlkem768", NULL); ++ if (ctx == NULL) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (EVP_PKEY_keygen_init(ctx) <= 0 ++ || EVP_PKEY_keygen(ctx, &pkey) <= 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (EVP_PKEY_get_raw_public_key(pkey, pubkeybuf, &pubkey_size) <= 0 ++ || EVP_PKEY_get_raw_private_key(pkey, privkeybuf, &privkey_size) <= 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (privkey_size != crypto_kem_mlkem768_SECRETKEYBYTES ++ || pubkey_size != crypto_kem_mlkem768_PUBLICKEYBYTES) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ret = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ if (ret == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ return ret; ++} ++ ++static int ++mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) ++{ ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ size_t outlen = crypto_kem_mlkem768_CIPHERTEXTBYTES, ++ secretlen = crypto_kem_mlkem768_BYTES; ++ ++ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, "mlkem768", NULL, ++ pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES); ++ if (pkey == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); ++ if (ctx == NULL ++ || EVP_PKEY_encapsulate_init(ctx, NULL) <= 0 ++ || EVP_PKEY_encapsulate(ctx, out, &outlen, secret, &secretlen) <= 0 ++ || secretlen != crypto_kem_mlkem768_BYTES ++ || outlen != crypto_kem_mlkem768_CIPHERTEXTBYTES) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ r = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ if (r == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ ++ return r; ++} ++ ++static int ++mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) ++{ ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ size_t wrappedlen = crypto_kem_mlkem768_CIPHERTEXTBYTES, ++ secretlen = crypto_kem_mlkem768_BYTES; ++ ++ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, "mlkem768", NULL, ++ privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES); ++ if (pkey == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); ++ if (ctx == NULL ++ || EVP_PKEY_decapsulate_init(ctx, NULL) <= 0 ++ || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrappedlen) <= 0 ++ || secretlen != crypto_kem_mlkem768_BYTES) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ r = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ ++ if (r == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ ++ return r; ++} + + int + kex_kem_mlkem768x25519_keypair(struct kex *kex) + { ++#if 0 + struct sshbuf *buf = NULL; + u_char rnd[LIBCRUX_ML_KEM_KEY_PAIR_PRNG_LEN], *cp = NULL; + size_t need; +@@ -86,6 +203,36 @@ kex_kem_mlkem768x25519_keypair(struct kex *kex) + explicit_bzero(rnd, sizeof(rnd)); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *buf = NULL; ++ u_char *cp = NULL; ++ size_t need; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ ++ if ((buf = sshbuf_new()) == NULL) ++ return SSH_ERR_ALLOC_FAIL; ++ need = crypto_kem_mlkem768_PUBLICKEYBYTES + CURVE25519_SIZE; ++ if ((r = sshbuf_reserve(buf, need, &cp)) != 0) ++ goto out; ++ if ((r = mlkem768_keypair_gen(cp, kex->mlkem768_client_key)) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key mlkem768:", cp, ++ crypto_kem_mlkem768_PUBLICKEYBYTES); ++#endif ++ cp += crypto_kem_mlkem768_PUBLICKEYBYTES; ++ kexc25519_keygen(kex->c25519_client_key, cp); ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key c25519:", cp, CURVE25519_SIZE); ++#endif ++ /* success */ ++ r = 0; ++ kex->client_pub = buf; ++ buf = NULL; ++ out: ++ sshbuf_free(buf); ++ return r; ++#endif + } + + int +@@ -93,6 +240,7 @@ kex_kem_mlkem768x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) + { ++#if 0 + struct sshbuf *server_blob = NULL; + struct sshbuf *buf = NULL; + const u_char *client_pub; +@@ -185,12 +333,97 @@ kex_kem_mlkem768x25519_enc(struct kex *kex, + sshbuf_free(server_blob); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *server_blob = NULL; ++ struct sshbuf *buf = NULL; ++ const u_char *client_pub; ++ u_char server_pub[CURVE25519_SIZE], server_key[CURVE25519_SIZE]; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t need; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ struct libcrux_mlkem768_enc_result enc; /* FIXME */ ++ ++ *server_blobp = NULL; ++ *shared_secretp = NULL; ++ ++ /* client_blob contains both KEM and ECDH client pubkeys */ ++ need = crypto_kem_mlkem768_PUBLICKEYBYTES + CURVE25519_SIZE; ++ if (sshbuf_len(client_blob) != need) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ client_pub = sshbuf_ptr(client_blob); ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key mlkem768:", client_pub, ++ crypto_kem_mlkem768_PUBLICKEYBYTES); ++ dump_digest("client public key 25519:", ++ client_pub + crypto_kem_mlkem768_PUBLICKEYBYTES, ++ CURVE25519_SIZE); ++#endif ++ ++ /* allocate buffer for concatenation of KEM key and ECDH shared key */ ++ /* the buffer will be hashed and the result is the shared secret */ ++ if ((buf = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ /* allocate space for encrypted KEM key and ECDH pub key */ ++ if ((server_blob = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (mlkem768_encap_secret(client_pub, enc.snd, enc.fst.value) != 0) ++ goto out; ++ ++ /* generate ECDH key pair, store server pubkey after ciphertext */ ++ kexc25519_keygen(server_key, server_pub); ++ if ((r = sshbuf_put(buf, enc.snd, sizeof(enc.snd))) != 0 || ++ (r = sshbuf_put(server_blob, enc.fst.value, sizeof(enc.fst.value))) != 0 || ++ (r = sshbuf_put(server_blob, server_pub, sizeof(server_pub))) != 0) ++ goto out; ++ /* append ECDH shared key */ ++ client_pub += crypto_kem_mlkem768_PUBLICKEYBYTES; ++ if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0) ++ goto out; ++ if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE); ++ dump_digest("server cipher text:", ++ enc.fst.value, sizeof(enc.fst.value)); ++ dump_digest("server kem key:", enc.snd, sizeof(enc.snd)); ++ dump_digest("concatenation of KEM key and ECDH shared key:", ++ sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* string-encoded hash is resulting shared secret */ ++ sshbuf_reset(buf); ++ if ((r = sshbuf_put_string(buf, hash, ++ ssh_digest_bytes(kex->hash_alg))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* success */ ++ r = 0; ++ *server_blobp = server_blob; ++ *shared_secretp = buf; ++ server_blob = NULL; ++ buf = NULL; ++ out: ++ explicit_bzero(hash, sizeof(hash)); ++ explicit_bzero(server_key, sizeof(server_key)); ++ explicit_bzero(&enc, sizeof(enc)); ++ sshbuf_free(server_blob); ++ sshbuf_free(buf); ++ return r; ++#endif + } + + int + kex_kem_mlkem768x25519_dec(struct kex *kex, + const struct sshbuf *server_blob, struct sshbuf **shared_secretp) + { ++#if 0 + struct sshbuf *buf = NULL; + u_char mlkem_key[crypto_kem_mlkem768_BYTES]; + const u_char *ciphertext, *server_pub; +@@ -258,6 +491,64 @@ kex_kem_mlkem768x25519_dec(struct kex *kex, + explicit_bzero(mlkem_key, sizeof(mlkem_key)); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *buf = NULL; ++ const u_char *ciphertext, *server_pub; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ u_char decap[crypto_kem_mlkem768_BYTES]; ++ size_t need; ++ int r; ++ ++ *shared_secretp = NULL; ++ ++ need = crypto_kem_mlkem768_CIPHERTEXTBYTES + CURVE25519_SIZE; ++ if (sshbuf_len(server_blob) != need) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ ciphertext = sshbuf_ptr(server_blob); ++ server_pub = ciphertext + crypto_kem_mlkem768_CIPHERTEXTBYTES; ++ /* hash concatenation of KEM key and ECDH shared key */ ++ if ((buf = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++#ifdef DEBUG_KEXECDH ++ dump_digest("server cipher text:", ciphertext, crypto_kem_mlkem768_CIPHERTEXTBYTES); ++ dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE); ++#endif ++ if ((r = mlkem768_decap_secret(kex->mlkem768_client_key, ciphertext, decap)) != 0) ++ goto out; ++ if ((r = sshbuf_put(buf, decap, sizeof(decap))) != 0) ++ goto out; ++ if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub, ++ buf, 1)) < 0) ++ goto out; ++ if ((r = ssh_digest_buffer(kex->hash_alg, buf, ++ hash, sizeof(hash))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("client kem key:", decap, sizeof(decap)); ++ dump_digest("concatenation of KEM key and ECDH shared key:", ++ sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ sshbuf_reset(buf); ++ if ((r = sshbuf_put_string(buf, hash, ++ ssh_digest_bytes(kex->hash_alg))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* success */ ++ r = 0; ++ *shared_secretp = buf; ++ buf = NULL; ++ out: ++ explicit_bzero(hash, sizeof(hash)); ++ explicit_bzero(decap, sizeof(decap)); ++ sshbuf_free(buf); ++ return r; ++#endif + } + #else /* USE_MLKEM768X25519 */ + int diff --git a/SOURCES/openssh-9.9p1-reject-cntrl-chars-in-username.patch b/SOURCES/openssh-9.9p1-reject-cntrl-chars-in-username.patch new file mode 100644 index 0000000..05bbe4d --- /dev/null +++ b/SOURCES/openssh-9.9p1-reject-cntrl-chars-in-username.patch @@ -0,0 +1,59 @@ +diff --color -ruNp a/ssh.c b/ssh.c +--- a/ssh.c 2025-12-03 15:22:36.754555231 +0100 ++++ b/ssh.c 2025-12-03 16:12:16.715320349 +0100 +@@ -662,6 +662,8 @@ valid_ruser(const char *s) + if (*s == '-') + return 0; + for (i = 0; s[i] != 0; i++) { ++ if (iscntrl((u_char)s[i])) ++ return 0; + if (strchr("'`\";&<>|(){}", s[i]) != NULL) + return 0; + /* Disallow '-' after whitespace */ +@@ -683,6 +685,7 @@ main(int ac, char **av) + struct ssh *ssh = NULL; + int i, r, opt, exit_status, use_syslog, direct, timeout_ms; + int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0; ++ int user_on_commandline = 0; + char *p, *cp, *line, *argv0, *logfile; + char cname[NI_MAXHOST], thishost[NI_MAXHOST]; + struct stat st; +@@ -1039,8 +1042,10 @@ main(int ac, char **av) + } + break; + case 'l': +- if (options.user == NULL) ++ if (options.user == NULL) { + options.user = optarg; ++ user_on_commandline = 1; ++ } + break; + + case 'L': +@@ -1143,6 +1148,7 @@ main(int ac, char **av) + if (options.user == NULL) { + options.user = tuser; + tuser = NULL; ++ user_on_commandline = 1; + } + free(tuser); + if (options.port == -1 && tport != -1) +@@ -1157,6 +1163,7 @@ main(int ac, char **av) + if (options.user == NULL) { + options.user = p; + p = NULL; ++ user_on_commandline = 1; + } + *cp++ = '\0'; + host = xstrdup(cp); +@@ -1459,6 +1466,10 @@ main(int ac, char **av) + cinfo->locuser = xstrdup(pw->pw_name); + cinfo->jmphost = xstrdup(options.jump_host == NULL ? + "" : options.jump_host); ++ ++ if (user_on_commandline && !valid_ruser(options.user)) ++ fatal("remote username contains invalid characters"); ++ + cinfo->conn_hash_hex = ssh_connection_hash(cinfo->thishost, + cinfo->remhost, cinfo->portstr, cinfo->remuser, cinfo->jmphost); + diff --git a/SOURCES/openssh-9.9p1-reject-null-char-in-url-string.patch b/SOURCES/openssh-9.9p1-reject-null-char-in-url-string.patch new file mode 100644 index 0000000..9b2d378 --- /dev/null +++ b/SOURCES/openssh-9.9p1-reject-null-char-in-url-string.patch @@ -0,0 +1,24 @@ +diff --color -ruNp a/misc.c b/misc.c +--- a/misc.c 2025-12-03 16:19:11.255135131 +0100 ++++ b/misc.c 2025-12-03 16:21:53.769590836 +0100 +@@ -998,7 +998,7 @@ urldecode(const char *src) + size_t srclen; + + if ((srclen = strlen(src)) >= SIZE_MAX) +- fatal_f("input too large"); ++ return NULL; + ret = xmalloc(srclen + 1); + for (dst = ret; *src != '\0'; src++) { + switch (*src) { +@@ -1006,9 +1006,10 @@ urldecode(const char *src) + *dst++ = ' '; + break; + case '%': ++ /* note: don't allow \0 characters */ + if (!isxdigit((unsigned char)src[1]) || + !isxdigit((unsigned char)src[2]) || +- (ch = hexchar(src + 1)) == -1) { ++ (ch = hexchar(src + 1)) == -1 || ch == 0) { + free(ret); + return NULL; + } diff --git a/SOURCES/openssh-9.9p1-scp-traversing.patch b/SOURCES/openssh-9.9p1-scp-traversing.patch new file mode 100644 index 0000000..2378b3a --- /dev/null +++ b/SOURCES/openssh-9.9p1-scp-traversing.patch @@ -0,0 +1,437 @@ +diff --color -ruNp a/regress/scp3.sh b/regress/scp3.sh +--- a/regress/scp3.sh 2024-09-20 00:20:48.000000000 +0200 ++++ b/regress/scp3.sh 2025-10-29 16:00:59.815068193 +0100 +@@ -6,6 +6,12 @@ tid="scp3" + COPY2=${OBJ}/copy2 + DIR=${COPY}.dd + DIR2=${COPY}.dd2 ++DIFFOPT="-rN" ++ ++# Figure out if diff does not understand "-N" ++if ! diff -N ${SRC}/scp.sh ${SRC}/scp.sh 2>/dev/null; then ++ DIFFOPT="-r" ++fi + + maybe_add_scp_path_to_sshd + +@@ -63,6 +69,15 @@ for mode in scp sftp ; do + echo b > ${COPY2} + $SCP $scpopts -3 hostA:${DATA} hostA:${COPY} hostB:${COPY2} + cmp ${COPY} ${COPY2} >/dev/null && fail "corrupt target" ++ ++ # scp /blah/.. is only supported via the sftp protocol. ++ # Original protocol scp just refuses it. ++ test $mode != sftp && continue ++ verbose "$tag: recursive .." ++ forest ++ $SCP $scpopts -r hostA:${DIR}/subdir/.. hostB:${DIR2} || \ ++ fail "copy failed" ++ diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy" + done + + scpclean +diff --color -ruNp a/regress/scp.sh b/regress/scp.sh +--- a/regress/scp.sh 2024-09-20 00:20:48.000000000 +0200 ++++ b/regress/scp.sh 2025-10-29 16:00:59.810765653 +0100 +@@ -199,6 +199,19 @@ for mode in scp sftp ; do + echo b > ${COPY2} + $SCP $scpopts ${DATA} ${COPY} ${COPY2} + cmp ${COPY} ${COPY2} >/dev/null && fail "corrupt target" ++ ++ # scp /blah/.. is only supported via the sftp protocol. ++ # Original protocol scp just refuses it. ++ test $mode != sftp && continue ++ verbose "$tag: recursive local .. to remote dir" ++ forest ++ $SCP $scpopts -r ${DIR}/subdir/.. somehost:${DIR2} || fail "copy failed" ++ diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy" ++ ++ verbose "$tag: recursive remote .. to local dir" ++ forest ++ $SCP $scpopts -r somehost:${DIR}/subdir/.. ${DIR2} || fail "copy failed" ++ diff ${DIFFOPT} ${DIR} ${DIR2} || fail "corrupted copy" + done + + scpclean +diff --color -ruNp a/regress/sftp-cmds.sh b/regress/sftp-cmds.sh +--- a/regress/sftp-cmds.sh 2024-09-20 00:20:48.000000000 +0200 ++++ b/regress/sftp-cmds.sh 2025-10-29 16:00:59.813392901 +0100 +@@ -7,6 +7,12 @@ + + tid="sftp commands" + ++DIFFOPT="-rN" ++# Figure out if diff does not understand "-N" ++if ! diff -N ${SRC}/sftp-cmds.sh ${SRC}/sftp-cmds.sh 2>/dev/null; then ++ DIFFOPT="-r" ++fi ++ + # test that these files are readable! + for i in `(cd /bin;echo l*)` + do +@@ -24,207 +30,246 @@ SPACECOPY_ARG="${COPY}\ this\ has\ space + # File with glob metacharacters + GLOBMETACOPY="${COPY} [metachar].txt" + ++sftpserver() { ++ ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 ++} ++ ++sftpserver_with_stdout() { ++ ${SFTP} -D ${SFTPSERVER} 2>&1 ++} ++ ++forest() { ++ rm -rf ${COPY}.dd/* ++ rm -rf ${COPY}.dd2 ++ mkdir -p ${COPY}.dd/a ${COPY}.dd/b ${COPY}.dd/c ${COPY}.dd/a/d ++ echo 'A' > ${COPY}.dd/a/A ++ echo 'B' > ${COPY}.dd/a/B ++ echo 'C' > ${COPY}.dd/a/C ++ echo 'D' > ${COPY}.dd/a/D ++} ++ + rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd ${COPY}.dd2 + mkdir ${COPY}.dd + + verbose "$tid: lls" +-printf "lcd ${OBJ}\nlls\n" | ${SFTP} -D ${SFTPSERVER} 2>&1 | \ ++printf "lcd ${OBJ}\nlls\n" | sftpserver_with_stdout | \ + grep copy.dd >/dev/null || fail "lls failed" + + verbose "$tid: lls w/path" +-echo "lls ${OBJ}" | ${SFTP} -D ${SFTPSERVER} 2>&1 | \ ++echo "lls ${OBJ}" | sftpserver_with_stdout | \ + grep copy.dd >/dev/null || fail "lls w/path failed" + + verbose "$tid: ls" +-echo "ls ${OBJ}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "ls failed" ++echo "ls ${OBJ}" | sftpserver || fail "ls failed" + # XXX always successful + + verbose "$tid: shell" +-echo "!echo hi there" | ${SFTP} -D ${SFTPSERVER} 2>&1 | \ ++echo "!echo hi there" | sftpserver_with_stdout | \ + egrep '^hi there$' >/dev/null || fail "shell failed" + + verbose "$tid: pwd" +-echo "pwd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "pwd failed" ++echo "pwd" | sftpserver || fail "pwd failed" + # XXX always successful + + verbose "$tid: lpwd" +-echo "lpwd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "lpwd failed" ++echo "lpwd" | sftpserver || fail "lpwd failed" + # XXX always successful + + verbose "$tid: quit" +-echo "quit" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "quit failed" ++echo "quit" | sftpserver || fail "quit failed" + # XXX always successful + + verbose "$tid: help" +-echo "help" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "help failed" ++echo "help" | sftpserver || fail "help failed" + # XXX always successful + + rm -f ${COPY} + verbose "$tid: get" +-echo "get $DATA $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "get failed" ++echo "get $DATA $COPY" | sftpserver || fail "get failed" + cmp $DATA ${COPY} || fail "corrupted copy after get" + + rm -f ${COPY} + verbose "$tid: get quoted" +-echo "get \"$DATA\" $COPY" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "get failed" ++echo "get \"$DATA\" $COPY" | sftpserver || fail "get failed" + cmp $DATA ${COPY} || fail "corrupted copy after get" + + rm -f ${QUOTECOPY} + cp $DATA ${QUOTECOPY} + verbose "$tid: get filename with quotes" +-echo "get \"$QUOTECOPY_ARG\" ${COPY}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "get failed" ++echo "get \"$QUOTECOPY_ARG\" ${COPY}" | sftpserver || fail "get failed" + cmp ${COPY} ${QUOTECOPY} || fail "corrupted copy after get with quotes" + rm -f ${QUOTECOPY} ${COPY} + + rm -f "$SPACECOPY" ${COPY} + cp $DATA "$SPACECOPY" + verbose "$tid: get filename with spaces" +-echo "get ${SPACECOPY_ARG} ${COPY}" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "get failed" ++echo "get ${SPACECOPY_ARG} ${COPY}" | sftpserver || fail "get failed" + cmp ${COPY} "$SPACECOPY" || fail "corrupted copy after get with spaces" + + rm -f "$GLOBMETACOPY" ${COPY} + cp $DATA "$GLOBMETACOPY" + verbose "$tid: get filename with glob metacharacters" +-echo "get \"${GLOBMETACOPY}\" ${COPY}" | \ +- ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "get failed" ++echo "get \"${GLOBMETACOPY}\" ${COPY}" | sftpserver || fail "get failed" + cmp ${COPY} "$GLOBMETACOPY" || \ + fail "corrupted copy after get with glob metacharacters" + +-rm -f ${COPY}.dd/* ++rm -rf ${COPY}.dd/* + verbose "$tid: get to directory" +-echo "get $DATA ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "get failed" ++echo "get $DATA ${COPY}.dd" | sftpserver || fail "get failed" + cmp $DATA ${COPY}.dd/${DATANAME} || fail "corrupted copy after get" + +-rm -f ${COPY}.dd/* ++rm -rf ${COPY}.dd/* + verbose "$tid: glob get to directory" +-echo "get /bin/l* ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "get failed" ++echo "get /bin/l* ${COPY}.dd" | sftpserver || fail "get failed" + for x in $GLOBFILES; do + cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after get" + done + +-rm -f ${COPY}.dd/* ++rm -rf ${COPY}.dd/* + verbose "$tid: get to local dir" +-printf "lcd ${COPY}.dd\nget $DATA\n" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "get failed" ++printf "lcd ${COPY}.dd\nget $DATA\n" | sftpserver || fail "get failed" + cmp $DATA ${COPY}.dd/${DATANAME} || fail "corrupted copy after get" + +-rm -f ${COPY}.dd/* ++rm -rf ${COPY}.dd/* + verbose "$tid: glob get to local dir" +-printf "lcd ${COPY}.dd\nget /bin/l*\n" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "get failed" ++printf "lcd ${COPY}.dd\nget /bin/l*\n" | sftpserver || fail "get failed" + for x in $GLOBFILES; do + cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after get" + done + ++forest ++verbose "$tid: get recursive absolute" ++echo "get -R ${COPY}.dd ${COPY}.dd2" | sftpserver || fail "get failed" ++diff ${DIFFOPT} ${COPY}.dd ${COPY}.dd2 || fail "corrupted copy" ++ ++forest ++verbose "$tid: get recursive relative src" ++printf "cd ${COPY}.dd\n get -R . ${COPY}.dd2\n" | sftpserver || \ ++ fail "get failed" ++diff ${DIFFOPT} ${COPY}.dd ${COPY}.dd2 || fail "corrupted copy" ++ ++forest ++verbose "$tid: get relative .." ++printf "cd ${COPY}.dd/b\n get -R .. ${COPY}.dd2\n" | sftpserver || \ ++ fail "get failed" ++diff ${DIFFOPT} ${COPY}.dd ${COPY}.dd2 || fail "corrupted copy" ++ ++forest ++mkdir ${COPY}.dd2 ++verbose "$tid: get recursive relative .." ++printf "cd ${COPY}.dd/b\n lcd ${COPY}.dd2\n get -R ..\n" | sftpserver || \ ++ fail "get failed" ++diff ${DIFFOPT} ${COPY}.dd ${COPY}.dd2 || fail "corrupted copy" ++ + rm -f ${COPY} + verbose "$tid: put" +-echo "put $DATA $COPY" | \ +- ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed" ++echo "put $DATA $COPY" | sftpserver || fail "put failed" + cmp $DATA ${COPY} || fail "corrupted copy after put" + + rm -f ${QUOTECOPY} + verbose "$tid: put filename with quotes" +-echo "put $DATA \"$QUOTECOPY_ARG\"" | \ +- ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed" ++echo "put $DATA \"$QUOTECOPY_ARG\"" | sftpserver || fail "put failed" + cmp $DATA ${QUOTECOPY} || fail "corrupted copy after put with quotes" + + rm -f "$SPACECOPY" + verbose "$tid: put filename with spaces" +-echo "put $DATA ${SPACECOPY_ARG}" | \ +- ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "put failed" ++echo "put $DATA ${SPACECOPY_ARG}" | sftpserver || fail "put failed" + cmp $DATA "$SPACECOPY" || fail "corrupted copy after put with spaces" + +-rm -f ${COPY}.dd/* ++rm -rf ${COPY}.dd/* + verbose "$tid: put to directory" +-echo "put $DATA ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "put failed" ++echo "put $DATA ${COPY}.dd" | sftpserver || fail "put failed" + cmp $DATA ${COPY}.dd/${DATANAME} || fail "corrupted copy after put" + +-rm -f ${COPY}.dd/* ++rm -rf ${COPY}.dd/* + verbose "$tid: glob put to directory" +-echo "put /bin/l? ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "put failed" ++echo "put /bin/l? ${COPY}.dd" | sftpserver || fail "put failed" + for x in $GLOBFILES; do + cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after put" + done + +-rm -f ${COPY}.dd/* ++rm -rf ${COPY}.dd/* + verbose "$tid: put to local dir" +-printf "cd ${COPY}.dd\nput $DATA\n" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "put failed" ++printf "cd ${COPY}.dd\nput $DATA\n" | sftpserver || fail "put failed" + cmp $DATA ${COPY}.dd/${DATANAME} || fail "corrupted copy after put" + +-rm -f ${COPY}.dd/* ++rm -rf ${COPY}.dd/* + verbose "$tid: glob put to local dir" +-printf "cd ${COPY}.dd\nput /bin/l*\n" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "put failed" ++printf "cd ${COPY}.dd\nput /bin/l*\n" | sftpserver || fail "put failed" + for x in $GLOBFILES; do + cmp /bin/$x ${COPY}.dd/$x || fail "corrupted copy after put" + done + ++forest ++verbose "$tid: put recursive absolute" ++echo "put -R ${COPY}.dd ${COPY}.dd2" | sftpserver || fail "put failed" ++diff ${DIFFOPT} ${COPY}.dd ${COPY}.dd2 || fail "corrupted copy" ++ ++forest ++verbose "$tid: put recursive relative src" ++printf "lcd ${COPY}.dd\n put -R . ${COPY}.dd2\n" | sftpserver || \ ++ fail "put failed" ++diff ${DIFFOPT} ${COPY}.dd ${COPY}.dd2 || fail "corrupted copy" ++ ++forest ++verbose "$tid: put recursive .." ++printf "lcd ${COPY}.dd/b\n put -R .. ${COPY}.dd2\n" | sftpserver || \ ++ fail "put failed" ++diff ${DIFFOPT} ${COPY}.dd ${COPY}.dd2 || fail "corrupted copy" ++ ++forest ++mkdir ${COPY}.dd2 ++verbose "$tid: put recursive .. relative" ++printf "lcd ${COPY}.dd/b\n cd ${COPY}.dd2\n put -R ..\n" | sftpserver || \ ++ fail "put failed" ++diff ${DIFFOPT} ${COPY}.dd ${COPY}.dd2 || fail "corrupted copy" ++ + verbose "$tid: rename" +-echo "rename $COPY ${COPY}.1" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "rename failed" ++echo "rename $COPY ${COPY}.1" | sftpserver || fail "rename failed" + test -f ${COPY}.1 || fail "missing file after rename" + cmp $DATA ${COPY}.1 >/dev/null 2>&1 || fail "corrupted copy after rename" + + verbose "$tid: rename directory" +-echo "rename ${COPY}.dd ${COPY}.dd2" | \ +- ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || \ ++rm -rf ${COPY}.dd2 ++echo "rename ${COPY}.dd ${COPY}.dd2" | sftpserver || \ + fail "rename directory failed" + test -d ${COPY}.dd && fail "oldname exists after rename directory" + test -d ${COPY}.dd2 || fail "missing newname after rename directory" + + verbose "$tid: ln" +-echo "ln ${COPY}.1 ${COPY}.2" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "ln failed" ++echo "ln ${COPY}.1 ${COPY}.2" | sftpserver || fail "ln failed" + test -f ${COPY}.2 || fail "missing file after ln" + cmp ${COPY}.1 ${COPY}.2 || fail "created file is not equal after ln" + + verbose "$tid: ln -s" + rm -f ${COPY}.2 +-echo "ln -s ${COPY}.1 ${COPY}.2" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "ln -s failed" ++echo "ln -s ${COPY}.1 ${COPY}.2" | sftpserver || fail "ln -s failed" + test -h ${COPY}.2 || fail "missing file after ln -s" + + verbose "$tid: cp" + rm -f ${COPY}.2 +-echo "cp ${COPY}.1 ${COPY}.2" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 || fail "cp failed" ++echo "cp ${COPY}.1 ${COPY}.2" | sftpserver || fail "cp failed" + cmp ${COPY}.1 ${COPY}.2 || fail "created file is not equal after cp" + + verbose "$tid: mkdir" +-echo "mkdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "mkdir failed" ++echo "mkdir ${COPY}.dd" | sftpserver || fail "mkdir failed" + test -d ${COPY}.dd || fail "missing directory after mkdir" + + # XXX do more here + verbose "$tid: chdir" +-echo "chdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "chdir failed" ++echo "chdir ${COPY}.dd" | sftpserver || fail "chdir failed" + + verbose "$tid: rmdir" +-echo "rmdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "rmdir failed" ++echo "rmdir ${COPY}.dd" | sftpserver || fail "rmdir failed" + test -d ${COPY}.1 && fail "present directory after rmdir" + + verbose "$tid: lmkdir" +-echo "lmkdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "lmkdir failed" ++echo "lmkdir ${COPY}.dd" | sftpserver || fail "lmkdir failed" + test -d ${COPY}.dd || fail "missing directory after lmkdir" + + # XXX do more here + verbose "$tid: lchdir" +-echo "lchdir ${COPY}.dd" | ${SFTP} -D ${SFTPSERVER} >/dev/null 2>&1 \ +- || fail "lchdir failed" ++echo "lchdir ${COPY}.dd" | sftpserver || fail "lchdir failed" + + rm -rf ${COPY} ${COPY}.1 ${COPY}.2 ${COPY}.dd ${COPY}.dd2 + rm -rf ${QUOTECOPY} "$SPACECOPY" "$GLOBMETACOPY" +diff --color -ruNp a/scp.c b/scp.c +--- a/scp.c 2025-10-29 15:49:51.795813258 +0100 ++++ b/scp.c 2025-10-29 16:00:59.817393000 +0100 +@@ -1362,6 +1362,10 @@ source_sftp(int argc, char *src, char *t + if ((filename = basename(src)) == NULL) + fatal("basename \"%s\": %s", src, strerror(errno)); + ++ /* Special handling for source of '..' */ ++ if (strcmp(filename, "..") == 0) ++ filename = "."; /* Upload to dest, not dest/.. */ ++ + /* + * No need to glob here - the local shell already took care of + * the expansions +@@ -1635,6 +1639,10 @@ sink_sftp(int argc, char *dst, const cha + goto out; + } + ++ /* Special handling for destination of '..' */ ++ if (strcmp(filename, "..") == 0) ++ filename = "."; /* Download to dest, not dest/.. */ ++ + if (dst_is_dir) + abs_dst = sftp_path_append(dst, filename); + else +diff --color -ruNp a/sftp.c b/sftp.c +--- a/sftp.c 2025-10-29 15:49:51.796907436 +0100 ++++ b/sftp.c 2025-10-29 16:00:59.819803948 +0100 +@@ -687,6 +687,10 @@ process_get(struct sftp_conn *conn, cons + goto out; + } + ++ /* Special handling for dest of '..' */ ++ if (strcmp(filename, "..") == 0) ++ filename = "."; /* Download to dest, not dest/.. */ ++ + if (g.gl_matchc == 1 && dst) { + if (local_is_dir(dst)) { + abs_dst = sftp_path_append(dst, filename); +@@ -781,6 +785,9 @@ process_put(struct sftp_conn *conn, cons + err = -1; + goto out; + } ++ /* Special handling for source of '..' */ ++ if (strcmp(filename, "..") == 0) ++ filename = "."; /* Upload to dest, not dest/.. */ + + free(abs_dst); + abs_dst = NULL; diff --git a/SOURCES/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch b/SOURCES/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch new file mode 100644 index 0000000..237e45d --- /dev/null +++ b/SOURCES/openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch @@ -0,0 +1,450 @@ +From 5d5a66e96ad03132f65371070f4fa475f10207d9 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 10 Jun 2024 23:00:03 +0300 +Subject: [PATCH] support authentication indicators in GSSAPI + +RFC 6680 defines a set of GSSAPI extensions to handle attributes +associated with the GSSAPI names. MIT Kerberos and FreeIPA use +name attributes to add information about pre-authentication methods used +to acquire the initial Kerberos ticket. The attribute 'auth-indicators' +may contain list of strings that KDC has associated with the ticket +issuance process. + +Use authentication indicators to authorise or deny access to SSH server. +GSSAPIIndicators setting allows to specify a list of possible indicators +that a Kerberos ticket presented must or must not contain. More details +on the syntax are provided in sshd_config(5) man page. + +Fixes: https://bugzilla.mindrot.org/show_bug.cgi?id=2696 + +Signed-off-by: Alexander Bokovoy +--- + configure.ac | 1 + + gss-serv-krb5.c | 64 +++++++++++++++++++++++++++--- + gss-serv.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++- + servconf.c | 15 ++++++- + servconf.h | 2 + + ssh-gss.h | 7 ++++ + sshd_config.5 | 44 +++++++++++++++++++++ + 7 files changed, 228 insertions(+), 8 deletions(-) + +diff --git a/configure.ac b/configure.ac +index d92a85809..2cbe20bf3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -5004,6 +5004,7 @@ AC_ARG_WITH([kerberos5], + AC_CHECK_HEADERS([gssapi.h gssapi/gssapi.h]) + AC_CHECK_HEADERS([gssapi_krb5.h gssapi/gssapi_krb5.h]) + AC_CHECK_HEADERS([gssapi_generic.h gssapi/gssapi_generic.h]) ++ AC_CHECK_HEADERS([gssapi_ext.h gssapi/gssapi_ext.h]) + + AC_SEARCH_LIBS([k_hasafs], [kafs], [AC_DEFINE([USE_AFS], [1], + [Define this if you want to use libkafs' AFS support])]) +diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c +index 03188d9b3..2c786ef14 100644 +--- a/gss-serv-krb5.c ++++ b/gss-serv-krb5.c +@@ -43,6 +43,7 @@ + #include "log.h" + #include "misc.h" + #include "servconf.h" ++#include "match.h" + + #include "ssh-gss.h" + +@@ -87,6 +88,32 @@ ssh_gssapi_krb5_init(void) + return 1; + } + ++/* Check if any of the indicators in the Kerberos ticket match ++ * one of indicators in the list of allowed/denied rules. ++ * In case of the match, apply the decision from the rule. ++ * In case of no indicator from the ticket matching the rule, deny ++ */ ++ ++static int ++ssh_gssapi_check_indicators(ssh_gssapi_client *client, int *matched) ++{ ++ int ret; ++ u_int i; ++ ++ /* Check indicators */ ++ for (i = 0; client->indicators[i] != NULL; i++) { ++ ret = match_pattern_list(client->indicators[i], ++ options.gss_indicators, 1); ++ /* negative or positive match */ ++ if (ret != 0) { ++ *matched = i; ++ return ret; ++ } ++ } ++ /* No rule matched */ ++ return 0; ++} ++ + /* Check if this user is OK to login. This only works with krb5 - other + * GSSAPI mechanisms will need their own. + * Returns true if the user is OK to log in, otherwise returns 0 +@@ -193,7 +220,7 @@ static int + ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) + { + krb5_principal princ; +- int retval; ++ int retval, matched; + const char *errmsg; + int k5login_exists; + +@@ -216,17 +243,42 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) + if (k5login_exists && + ssh_krb5_kuserok(krb_context, princ, name, k5login_exists)) { + retval = 1; +- logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", +- name, (char *)client->displayname.value); ++ errmsg = "krb5_kuserok"; + } else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value, + name, k5login_exists)) { + retval = 1; +- logit("Authorized to %s, krb5 principal %s " +- "(ssh_gssapi_krb5_cmdok)", +- name, (char *)client->displayname.value); ++ errmsg = "ssh_gssapi_krb5_cmdok"; + } else + retval = 0; + ++ if ((retval == 1) && (options.gss_indicators != NULL)) { ++ /* At this point the configuration enforces presence of indicators ++ * so we drop the authorization result again */ ++ retval = 0; ++ if (client->indicators) { ++ matched = -1; ++ retval = ssh_gssapi_check_indicators(client, &matched); ++ if (retval != 0) { ++ retval = (retval == 1); ++ logit("Ticket contains indicator %s, " ++ "krb5 principal %s is %s", ++ client->indicators[matched], ++ (char *)client->displayname.value, ++ retval ? "allowed" : "denied"); ++ goto cont; ++ } ++ } ++ if (retval == 0) { ++ logit("GSSAPI authentication indicators enforced " ++ "but not matched. krb5 principal %s denied", ++ (char *)client->displayname.value); ++ } ++ } ++cont: ++ if (retval == 1) { ++ logit("Authorized to %s, krb5 principal %s (%s)", ++ name, (char *)client->displayname.value, errmsg); ++ } + krb5_free_principal(krb_context, princ); + return retval; + } +diff --git a/gss-serv.c b/gss-serv.c +index 9d5435eda..5c0491cf1 100644 +--- a/gss-serv.c ++++ b/gss-serv.c +@@ -54,7 +54,7 @@ extern ServerOptions options; + + static ssh_gssapi_client gssapi_client = + { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, +- GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0}; ++ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0, NULL}; + + ssh_gssapi_mech gssapi_null_mech = + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; +@@ -296,6 +296,92 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name) + return GSS_S_COMPLETE; + } + ++ ++/* Extract authentication indicators from the Kerberos ticket. Authentication ++ * indicators are GSSAPI name attributes for the name "auth-indicators". ++ * Multiple indicators might be present in the ticket. ++ * Each indicator is a utf8 string. */ ++ ++#define AUTH_INDICATORS_TAG "auth-indicators" ++ ++/* Privileged (called from accept_secure_ctx) */ ++static OM_uint32 ++ssh_gssapi_getindicators(Gssctxt *ctx, gss_name_t gss_name, ssh_gssapi_client *client) ++{ ++ gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; ++ gss_buffer_desc value = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc display_value = GSS_C_EMPTY_BUFFER; ++ int is_mechname, authenticated, complete, more; ++ size_t count, i; ++ ++ ctx->major = gss_inquire_name(&ctx->minor, gss_name, ++ &is_mechname, NULL, &attrs); ++ if (ctx->major != GSS_S_COMPLETE) { ++ return (ctx->major); ++ } ++ ++ if (attrs == GSS_C_NO_BUFFER_SET) { ++ /* No indicators in the ticket */ ++ return (0); ++ } ++ ++ count = 0; ++ for (i = 0; i < attrs->count; i++) { ++ /* skip anything but auth-indicators */ ++ if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) || ++ strncmp(AUTH_INDICATORS_TAG, ++ attrs->elements[i].value, ++ sizeof(AUTH_INDICATORS_TAG) - 1) != 0) ++ continue; ++ count++; ++ } ++ ++ if (count == 0) { ++ /* No auth-indicators in the ticket */ ++ (void) gss_release_buffer_set(&ctx->minor, &attrs); ++ return (0); ++ } ++ ++ client->indicators = recallocarray(NULL, 0, count + 1, sizeof(char*)); ++ count = 0; ++ for (i = 0; i < attrs->count; i++) { ++ authenticated = 0; ++ complete = 0; ++ more = -1; ++ /* skip anything but auth-indicators */ ++ if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) || ++ strncmp(AUTH_INDICATORS_TAG, ++ attrs->elements[i].value, ++ sizeof(AUTH_INDICATORS_TAG) - 1) != 0) ++ continue; ++ /* retrieve all indicators */ ++ while (more != 0) { ++ value.value = NULL; ++ display_value.value = NULL; ++ ctx->major = gss_get_name_attribute(&ctx->minor, gss_name, ++ &attrs->elements[i], &authenticated, ++ &complete, &value, &display_value, &more); ++ if (ctx->major != GSS_S_COMPLETE) { ++ goto out; ++ } ++ ++ if ((value.value != NULL) && authenticated) { ++ client->indicators[count] = xmalloc(value.length + 1); ++ memcpy(client->indicators[count], value.value, value.length); ++ client->indicators[count][value.length] = '\0'; ++ count++; ++ } ++ } ++ } ++ ++out: ++ (void) gss_release_buffer(&ctx->minor, &value); ++ (void) gss_release_buffer(&ctx->minor, &display_value); ++ (void) gss_release_buffer_set(&ctx->minor, &attrs); ++ return (ctx->major); ++} ++ ++ + /* Extract the client details from a given context. This can only reliably + * be called once for a context */ + +@@ -385,6 +471,12 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) + } + + gss_release_buffer(&ctx->minor, &ename); ++ /* Retrieve authentication indicators, if they exist */ ++ if ((ctx->major = ssh_gssapi_getindicators(ctx, ++ ctx->client, client))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } + + /* We can't copy this structure, so we just move the pointer to it */ + client->creds = ctx->client_creds; +@@ -447,6 +539,7 @@ int + ssh_gssapi_userok(char *user, struct passwd *pw, int kex) + { + OM_uint32 lmin; ++ size_t i; + + (void) kex; /* used in privilege separation */ + +@@ -465,6 +558,14 @@ ssh_gssapi_userok(char *user, struct passwd *pw, int kex) + gss_release_buffer(&lmin, &gssapi_client.displayname); + gss_release_buffer(&lmin, &gssapi_client.exportedname); + gss_release_cred(&lmin, &gssapi_client.creds); ++ ++ if (gssapi_client.indicators != NULL) { ++ for(i = 0; gssapi_client.indicators[i] != NULL; i++) { ++ free(gssapi_client.indicators[i]); ++ } ++ free(gssapi_client.indicators); ++ } ++ + explicit_bzero(&gssapi_client, + sizeof(ssh_gssapi_client)); + return 0; +diff --git a/servconf.c b/servconf.c +index e7e4ad046..aab653244 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -147,6 +147,7 @@ initialize_server_options(ServerOptions *options) + options->gss_strict_acceptor = -1; + options->gss_store_rekey = -1; + options->gss_kex_algorithms = NULL; ++ options->gss_indicators = NULL; + options->use_kuserok = -1; + options->enable_k5users = -1; + options->password_authentication = -1; +@@ -598,7 +599,7 @@ typedef enum { + sPerSourcePenalties, sPerSourcePenaltyExemptList, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, +- sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, ++ sGssKeyEx, sGssIndicators, sGssKexAlgorithms, sGssStoreRekey, + sAcceptEnv, sSetEnv, sPermitTunnel, + sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, +@@ -694,6 +695,7 @@ static struct { + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, + { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, + { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL }, ++ { "gssapiindicators", sGssIndicators, SSHCFG_ALL }, + #else + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, +@@ -703,6 +705,7 @@ static struct { + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL }, + { "gssapienablek5users", sUnsupported, SSHCFG_ALL }, ++ { "gssapiindicators", sUnsupported, SSHCFG_ALL }, + #endif + { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, + { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, +@@ -1730,6 +1733,15 @@ process_server_config_line_depth(ServerOptions *options, char *line, + options->gss_kex_algorithms = xstrdup(arg); + break; + ++ case sGssIndicators: ++ arg = argv_next(&ac, &av); ++ if (!arg || *arg == '\0') ++ fatal("%s line %d: %s missing argument.", ++ filename, linenum, keyword); ++ if (options->gss_indicators == NULL) ++ options->gss_indicators = xstrdup(arg); ++ break; ++ + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; +@@ -3351,6 +3363,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); + dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms); ++ dump_cfg_string(sGssIndicators, o->gss_indicators); + #endif + dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); + dump_cfg_fmtint(sKbdInteractiveAuthentication, +diff --git a/servconf.h b/servconf.h +index 7c7e5d434..7c41df417 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -181,6 +181,7 @@ typedef struct { + char **allow_groups; + u_int num_deny_groups; + char **deny_groups; ++ char *gss_indicators; + + u_int num_subsystems; + char **subsystem_name; +@@ -310,6 +311,7 @@ TAILQ_HEAD(include_list, include_item); + M_CP_STROPT(routing_domain); \ + M_CP_STROPT(permit_user_env_allowlist); \ + M_CP_STROPT(pam_service_name); \ ++ M_CP_STROPT(gss_indicators); \ + M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \ + M_CP_STRARRAYOPT(allow_users, num_allow_users); \ + M_CP_STRARRAYOPT(deny_users, num_deny_users); \ +diff --git a/ssh-gss.h b/ssh-gss.h +index a894e23c9..59cf46d47 100644 +--- a/ssh-gss.h ++++ b/ssh-gss.h +@@ -34,6 +34,12 @@ + #include + #endif + ++#ifdef HAVE_GSSAPI_EXT_H ++#include ++#elif defined(HAVE_GSSAPI_GSSAPI_EXT_H) ++#include ++#endif ++ + #ifdef KRB5 + # ifndef HEIMDAL + # ifdef HAVE_GSSAPI_GENERIC_H +@@ -107,6 +113,7 @@ typedef struct { + ssh_gssapi_ccache store; + int used; + int updated; ++ char **indicators; /* auth indicators */ + } ssh_gssapi_client; + + typedef struct ssh_gssapi_mech_struct { +diff --git a/sshd_config.5 b/sshd_config.5 +index 583a01cdb..90ab87edd 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -785,6 +785,50 @@ gss-nistp256-sha256- + gss-curve25519-sha256- + .Ed + This option only applies to connections using GSSAPI. ++.It Cm GSSAPIIndicators ++Specifies whether to accept or deny GSSAPI authenticated access if Kerberos ++mechanism is used and Kerberos ticket contains a particular set of ++authentication indicators. The values can be specified as a comma-separated list ++.Cm [!]name1,[!]name2,... . ++When indicator's name is prefixed with !, the authentication indicator 'name' ++will deny access to the system. Otherwise, one of non-negated authentication ++indicators must be present in the Kerberos ticket to allow access. If ++.Cm GSSAPIIndicators ++is defined, a Kerberos ticket that has indicators but does not match the ++policy will get denial. If at least one indicator is configured, whether for ++access or denial, tickets without authentication indicators will be explicitly ++rejected. ++.Pp ++By default systems using MIT Kerberos 1.17 or later will not assign any ++indicators. SPAKE and PKINIT methods add authentication indicators ++to all successful authentications. The SPAKE pre-authentication method is ++preferred over an encrypted timestamp pre-authentication when passwords used to ++authenticate user principals. Kerberos KDCs built with Heimdal Kerberos ++(including Samba AD DC built with Heimdal) do not add authentication ++indicators. However, OpenSSH built against Heimdal Kerberos library is able to ++inquire authentication indicators and thus can be used to check for their presence. ++.Pp ++Indicator name is case-sensitive and depends on the configuration of a ++particular Kerberos deployment. Indicators available in MIT Kerberos and ++FreeIPA environments: ++.Pp ++.Bl -tag -width XXXX -offset indent -compact ++.It Cm hardened ++SPAKE or encrypted timestamp pre-authentication mechanisms in MIT Kerberos and FreeIPA ++.It Cm pkinit ++smartcard or PKCS11 token-based pre-authentication in MIT Kerberos and FreeIPA ++.It Cm radius ++pre-authentication based on a RADIUS server in MIT Kerberos and FreeIPA ++.It Cm otp ++TOTP/HOTP-based two-factor pre-authentication in FreeIPA ++.It Cm idp ++OAuth2-based pre-authentication in FreeIPA using an external identity provider ++and device authorization grant flow ++.It Cm passkey ++FIDO2-based pre-authentication in FreeIPA, using FIDO2 USB and NFC tokens ++.El ++.Pp ++The default is to not use GSSAPI authentication indicators for access decisions. + .It Cm HostbasedAcceptedAlgorithms + The default is handled system-wide by + .Xr crypto-policies 7 . +-- +2.49.0 + diff --git a/SOURCES/openssh-9.9p1.tar.gz.asc b/SOURCES/openssh-9.9p1.tar.gz.asc new file mode 100644 index 0000000..9937cba --- /dev/null +++ b/SOURCES/openssh-9.9p1.tar.gz.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP SIGNATURE----- + +iQIzBAABCgAdFiEEcWi5g4FaXu9ZpK39Kj9BTnNgYLoFAmbspccACgkQKj9BTnNg +YLppxRAAv7eU/Xd2w9MX9vWQdhugiPByEcKg7KuKXUUs9xJGy+HbLqPqUCvn1UW6 +qodKoSAdeBuSB7AjzuIQ1lTVX7C67OmZaVPRq25ar5b+Wq4SSlv23KMRq0b4EVyw +pOW6R9tsxqYBwYaiXQ50APcYL8SpepnGU+b/iR15f7q3SU2XMVVtkVb149UdLOqK +smfurbDGwUKFb2Q009MUfEV/d9zq31tdSjphvkqAXCcmxc8siuOYWYcByuysie+m +NpaOpee0047L5JIxNSLsa2yZrJZhClP8LbTCH1Vfwr7l0KE5nvL2qAtPKI2XxGQC +3jXrDLzp10RFxV8sCym+QlY9pZyzGj9d3G7vCHtxWGQ1Y0Qt+xs18OeBpjiehRhl +WM3Y+cjoN35jBaGhOoHdh3ePZQdTUyZ16aSv0h/cUHOohiM7i/4XW+dQtkqsJsw4 +a81O0E64WrL8ho3Ju9mwcVZ9A0aEaftJsmJPDB+qYBjF/i7xcnH32LginzP5pel7 +/W0aS2C1ZNo3QKHezI6IA9MyENMZiAMy2ybvfmN0HgLBaBY1plJ8a5GvMwJc+Qwh +iCHLCQ6Qgf/1hh+F6liTXnhtedtFHneJdyqvd7XOoardDEipZjxcnGa4HthbDFU+ +8XdHKnWWhn4BLA+y7KB3ZGURniQK+qibwkF6J63CuMU+LmG+bvQ= +=Ukrb +-----END PGP SIGNATURE----- diff --git a/SOURCES/openssh-9.9p2-error_processing.patch b/SOURCES/openssh-9.9p2-error_processing.patch index d42a370..692c6ac 100644 --- a/SOURCES/openssh-9.9p2-error_processing.patch +++ b/SOURCES/openssh-9.9p2-error_processing.patch @@ -11,13 +11,96 @@ index e2efdf06..0d0f6953 100644 goto out; } @@ -1059,6 +1060,7 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp) - goto out; + } if ((krl = ssh_krl_init()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; error_f("alloc failed"); goto out; } +diff --git a/packet.c b/packet.c +index 486f8515..9dea2cfc 100644 +--- a/packet.c ++++ b/packet.c +@@ -1864,6 +1864,14 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) + if ((r = sshpkt_get_string_direct(ssh, &d, &len)) != 0) + return r; + DBG(debug("Received SSH2_MSG_PING len %zu", len)); ++ if (!ssh->state->after_authentication) { ++ DBG(debug("Won't reply to PING in preauth")); ++ break; ++ } ++ if (ssh_packet_is_rekeying(ssh)) { ++ DBG(debug("Won't reply to PING during KEX")); ++ break; ++ } + if ((r = sshpkt_start(ssh, SSH2_MSG_PONG)) != 0 || + (r = sshpkt_put_string(ssh, d, len)) != 0 || + (r = sshpkt_send(ssh)) != 0) +diff --git a/ssh-agent.c b/ssh-agent.c +index 48973b2c..c27c5a95 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c +@@ -1220,6 +1220,7 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp, + "restrict-destination-v00@openssh.com") == 0) { + if (*dcsp != NULL) { + error_f("%s already set", ext_name); ++ r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if ((r = sshbuf_froms(m, &b)) != 0) { +@@ -1229,6 +1230,7 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp, + while (sshbuf_len(b) != 0) { + if (*ndcsp >= AGENT_MAX_DEST_CONSTRAINTS) { + error_f("too many %s constraints", ext_name); ++ r = SSH_ERR_INVALID_FORMAT; + goto out; + } + *dcsp = xrecallocarray(*dcsp, *ndcsp, *ndcsp + 1, +@@ -1246,6 +1248,7 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp, + } + if (*certs != NULL) { + error_f("%s already set", ext_name); ++ r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if ((r = sshbuf_get_u8(m, &v)) != 0 || +@@ -1257,6 +1260,7 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp, + while (sshbuf_len(b) != 0) { + if (*ncerts >= AGENT_MAX_EXT_CERTS) { + error_f("too many %s constraints", ext_name); ++ r = SSH_ERR_INVALID_FORMAT; + goto out; + } + *certs = xrecallocarray(*certs, *ncerts, *ncerts + 1, +@@ -1757,6 +1761,7 @@ process_ext_session_bind(SocketEntry *e) + /* record new key/sid */ + if (e->nsession_ids >= AGENT_MAX_SESSION_IDS) { + error_f("too many session IDs recorded"); ++ r = -1; + goto out; + } + e->session_ids = xrecallocarray(e->session_ids, e->nsession_ids, +diff --git a/ssh-sk-client.c b/ssh-sk-client.c +index 321fe53a..06fad221 100644 +--- a/ssh-sk-client.c ++++ b/ssh-sk-client.c +@@ -439,6 +439,7 @@ sshsk_load_resident(const char *provider_path, const char *device, + } + if ((srk = calloc(1, sizeof(*srk))) == NULL) { + error_f("calloc failed"); ++ r = SSH_ERR_ALLOC_FAIL; + goto out; + } + srk->key = key; +@@ -450,6 +451,7 @@ sshsk_load_resident(const char *provider_path, const char *device, + if ((tmp = recallocarray(srks, nsrks, nsrks + 1, + sizeof(*srks))) == NULL) { + error_f("recallocarray keys failed"); ++ r = SSH_ERR_ALLOC_FAIL; + goto out; + } + debug_f("srks[%zu]: %s %s uidlen %zu", nsrks, diff --git a/sshconnect2.c b/sshconnect2.c index a69c4da1..1ee6000a 100644 --- a/sshconnect2.c diff --git a/SPECS/openssh.spec b/SPECS/openssh.spec index 4cb5799..5477a86 100644 --- a/SPECS/openssh.spec +++ b/SPECS/openssh.spec @@ -46,10 +46,10 @@ %{?static_openssl:%global static_libcrypto 1} # Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 -%global openssh_ver 8.7p1 -%global openssh_rel 46 +%global openssh_ver 9.9p1 +%global openssh_rel 4 %global pam_ssh_agent_ver 0.10.4 -%global pam_ssh_agent_rel 5 +%global pam_ssh_agent_rel 7 Summary: An open source implementation of SSH protocol version 2 Name: openssh @@ -133,12 +133,10 @@ Patch703: openssh-4.3p2-askpass-grab-info.patch Patch707: openssh-7.7p1-redhat.patch # warn users for unsupported UsePAM=no (#757545) Patch711: openssh-7.8p1-UsePAM-warning.patch -# make aes-ctr ciphers use EVP engines such as AES-NI from OpenSSL -Patch712: openssh-6.3p1-ctr-evp-fast.patch # GSSAPI Key Exchange (RFC 4462 + RFC 8732) # from https://github.com/openssh-gsskex/openssh-gsskex/tree/fedora/master -Patch800: openssh-8.0p1-gssapi-keyex.patch +Patch800: openssh-9.6p1-gssapi-keyex.patch #http://www.mail-archive.com/kerberos@mit.edu/msg17591.html Patch801: openssh-6.6p1-force_krb.patch # add new option GSSAPIEnablek5users and disable using ~/.k5users by default (#1169843) @@ -169,8 +167,6 @@ Patch926: openssh-6.7p1-sftp-force-permission.patch Patch939: openssh-7.2p2-s390-closefrom.patch # Move MAX_DISPLAYS to a configuration option (#1341302) Patch944: openssh-7.3p1-x11-max-displays.patch -# Help systemd to track the running service -Patch948: openssh-7.4p1-systemd.patch # Pass inetd flags for SELinux down to openbsd compat level Patch949: openssh-7.6p1-cleanup-selinux.patch # Sandbox adjustments for s390 and audit @@ -183,8 +179,6 @@ Patch951: openssh-8.0p1-pkcs11-uri.patch Patch953: openssh-7.8p1-scp-ipv6.patch # Mention crypto-policies in manual pages (#1668325) Patch962: openssh-8.0p1-crypto-policies.patch -# Use OpenSSL high-level API to produce and verify signatures (#1707485) -Patch963: openssh-8.0p1-openssl-evp.patch # Use OpenSSL KDF (#1631761) Patch964: openssh-8.0p1-openssl-kdf.patch # sk-dummy.so built with -fvisibility=hidden does not work @@ -195,20 +189,8 @@ Patch966: openssh-8.2p1-x11-without-ipv6.patch Patch974: openssh-8.0p1-keygen-strip-doseol.patch # sshd provides PAM an incorrect error code (#1879503) Patch975: openssh-8.0p1-preserve-pam-errors.patch -# Use SFTP protocol by default for scp command -Patch976: openssh-8.7p1-sftp-default-protocol.patch # Implement kill switch for SCP protocol Patch977: openssh-8.7p1-scp-kill-switch.patch -# CVE-2021-41617 -Patch978: openssh-8.7p1-upstream-cve-2021-41617.patch -# fix for `ssh-keygen -Y find-principals -f /dev/null -s /dev/null` (#2024902) -Patch979: openssh-8.7p1-find-principals-fix.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 @@ -216,90 +198,53 @@ Patch980: openssh-8.7p1-sftpscp-dir-create.patch 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 -# Upstream ff89b1bed80721295555bd083b173247a9c0484e, 5062ad48814b06162511c4f5924a33d97b6b2566 -Patch986: openssh-9.1p1-sshbanner.patch - -# Minimize the use of SHA1 as a proof of possession for RSA key (#2031868) -# upstream commits: -# 291721bc7c840d113a49518f3fca70e86248b8e8 -# 0fa33683223c76289470a954404047bc762be84c -# Avoid dubious diagnostics on update known hosts (#2115246) -# 8832402bd500d1661ccc80a476fd563335ef6cdc -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 # Patch1007: openssh-8.7p1-nohostsha1proof.patch -# CVE-2023-25136 -# upstream 12da7823336434a403f25c7cc0c2c6aed0737a35 -# to fix 1005 -Patch1008: openssh-8.7p1-CVE-2023-25136.patch - -# fips compliance for signing, dh, ecdh -Patch1009: openssh-8.7p1-evp-fips-compl-sign.patch -Patch1010: openssh-8.7p1-evp-fips-compl-dh.patch -Patch1011: openssh-8.7p1-evp-fips-compl-ecdh.patch -Patch1012: openssh-8.7p1-evp-pkcs11.patch - -# clarify rhbz#2068423 on the man page of ssh_config -Patch1013: openssh-8.7p1-man-hostkeyalgos.patch -# upstream commits -# ec1ddb72a146fd66d18df9cd423517453a5d8044 -# b98a42afb69d60891eb0488935990df6ee571c4 -# a00f59a645072e5f5a8d207af15916a7b23e2642 -Patch1014: openssh-8.7p1-UTC-time-parse.patch -# upsream commit -# b23fe83f06ee7e721033769cfa03ae840476d280 -Patch1015: openssh-9.3p1-upstream-cve-2023-38408.patch -#upstream commit b7afd8a4ecaca8afd3179b55e9db79c0ff210237 -Patch1016: openssh-9.3p1-openssl-compat.patch -#upstream commit 01dbf3d46651b7d6ddf5e45d233839bbfffaeaec -Patch1017: openssh-9.4p2-limit-delay.patch -#upstream commit 1edb00c58f8a6875fad6a497aa2bacf37f9e6cd5 -Patch1018: openssh-9.6p1-CVE-2023-48795.patch -#upstream commit 7ef3787c84b6b524501211b11a26c742f829af1a -Patch1019: openssh-9.6p1-CVE-2023-51385.patch -#upstream commit 96faa0de6c673a2ce84736eba37fc9fb723d9e5c -Patch1020: openssh-8.7p1-sigpipe.patch -Patch1021: openssh-9.8p1-upstream-cve-2024-6387.patch +Patch1012: openssh-9.0p1-evp-fips-kex.patch +Patch1015: openssh-9.6p1-pam-rhost.patch Patch1022: openssh-8.7p1-redhat-help.patch Patch1023: openssh-8.7p1-openssl-log.patch -#upstream commit 52dfe3c72d98503d8b7c6f64fc7e19d685636c0b -Patch1024: openssh-8.7p1-allow-duplicate-subsystem.patch # upstream 6ce00f0c2ecbb9f75023dbe627ee6460bcec78c2 # upstream 0832aac79517611dd4de93ad0a83577994d9c907 Patch1025: openssh-9.9p2-error_processing.patch +# upstream cf3e48ee8ba1beeccddd2f203b558fa102be67a2 +# upstream 0c3927c45f8a57b511c874c4d51a8c89414f74ef +Patch1026: openssh-9.9p1-mlkembe.patch +# upstream 3f02368e8e9121847727c46b280efc280e5eb615 +# upstream 67a115e7a56dbdc3f5a58c64b29231151f3670f5 +Patch1027: openssh-9.9p1-match-regression.patch +# Downstream patch, OpenSSL based MLKEM implementation +Patch1028: openssh-9.9p1-openssl-mlkem.patch +# upstream 8eabd2ae2ca1d7756417a1ee5b41f09c5d997634 +Patch1029: openssh-9.9p1-compression-directive.patch +# upstream fc86875e6acb36401dfc1dfb6b628a9d1460f367 +Patch1030: openssh-9.9p1-disable-forwarding.patch +Patch1031: openssh-9.9p1-non-supported-keys-err-msg.patch +Patch1032: openssh-9.9p1-bad-hostkey.patch +# https://github.com/openssh/openssh-portable/pull/500 +Patch1033: openssh-9.9p1-support-authentication-indicators-in-GSSAPI.patch +# +Patch1034: openssh-9.9p1-fips-gss.patch +#upstream 6432b9f6a216d0f5fb43df500e9bc30bebb3f58b +#upstream 4f14ca8633a2c8c0a1a19165663421f0ab32f6ab +Patch1035: openssh-9.9p1-scp-traversing.patch +Patch1036: openssh-9.9p1-canonical-match-user.patch +# upstream 35d5917652106aede47621bb3f64044604164043 +Patch1037: openssh-9.9p1-reject-cntrl-chars-in-username.patch +# upstream 43b3bff47bb029f2299bacb6a36057981b39fdb0 +Patch1038: openssh-9.9p1-reject-null-char-in-url-string.patch +Patch1039: openssh-9.9p1-compat-mlkem.patch License: BSD Requires: /sbin/nologin @@ -454,7 +399,6 @@ popd %patch703 -p1 -b .grab-info %patch707 -p1 -b .redhat %patch711 -p1 -b .log-usepam-no -%patch712 -p1 -b .evp-ctr # %patch800 -p1 -b .gsskex %patch801 -p1 -b .force_krb @@ -471,65 +415,51 @@ popd %patch926 -p1 -b .sftp-force-mode %patch939 -p1 -b .s390-dev %patch944 -p1 -b .x11max -%patch948 -p1 -b .systemd %patch949 -p1 -b .refactor %patch950 -p1 -b .sandbox %patch951 -p1 -b .pkcs11-uri %patch953 -p1 -b .scp-ipv6 %patch962 -p1 -b .crypto-policies -%patch963 -p1 -b .openssl-evp %patch964 -p1 -b .openssl-kdf %patch965 -p1 -b .visibility %patch966 -p1 -b .x11-ipv6 %patch974 -p1 -b .keygen-strip-doseol %patch975 -p1 -b .preserve-pam-errors -%patch976 -p1 -b .sftp-by-default %patch977 -p1 -b .kill-scp -%patch978 -p1 -b .cve-2021-41617 -%patch979 -p1 -b .find-principals -%patch980 -p1 -b .sftpdirs %patch981 -p1 -b .scp-sftpdirs %patch982 -p1 -b .minrsabits -%patch983 -p1 -b .evpgenrsa %patch984 -p1 -b .ibmca -%patch986 -p1 -b .91cleanup %patch200 -p1 -b .audit %patch201 -p1 -b .audit-race %patch202 -p1 -b .audit-hostname %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 %patch100 -p1 -b .coverity %patch1007 -p1 -b .sshrsacheck -%patch1008 -p1 -b .cve-2023-25136 - -%patch1009 -p1 -b .evp_fips_sign -%patch1010 -p1 -b .evp_fips_dh -%patch1011 -p1 -b .evp_fips_ecdh -%patch1012 -p1 -b .evp_pkcs11 - -%patch1013 -p1 -b .man-hostkeyalgos -%patch1014 -p1 -b .utc_parse -%patch1015 -p1 -b .cve-2023-38408 -%patch1016 -p1 -b .openssl3compat -%patch1017 -p1 -b .limitdelay -%patch1018 -p1 -b .cve-2023-48795 -%patch1019 -p1 -b .cve-2023-51385 -%patch1020 -p1 -b .earlypipe -%patch1021 -p1 -b .cve-2024-6387 +%patch1012 -p1 -b .evp-fips-kex +%patch1015 -p1 -b .pam-rhost %patch1022 -p1 -b .redhat-help %patch1023 -p1 -b .openssl-log -%patch1024 -p1 -b .allow-dup-subsystem %patch1025 -p1 -b .errcode_set +%patch1026 -p1 -b .mlkembe +%patch1027 -p1 -b .match +%patch1028 -p1 -b .openssl-mlkem +%patch1029 -p1 -b .compression +%patch1030 -p1 -b .disable-forwarding +%patch1031 -p1 -b .non-supported-keys-err-msg +%patch1032 -p1 -b .bad-hostkey +%patch1033 -p1 -b .gss-indicators +%patch1034 -p1 -b .gss-fips +%patch1035 -p1 -b .scp-traversing +%patch1036 -p1 -b .canonical-match-user +%patch1037 -p1 -b .reject-cntrl-chars-in-username +%patch1038 -p1 -b .reject-null-char-in-url-string +%patch1039 -p1 -b .skip-mlkem-when-na autoreconf pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} @@ -582,10 +512,10 @@ fi --with-ipaddr-display \ --with-pie=no \ --without-hardening `# The hardening flags are configured by system` \ - --with-systemd \ --with-default-pkcs11-provider=yes \ --with-security-key-builtin=yes \ --with-pam \ + --enable-dsa-keys \ %if %{WITH_SELINUX} --with-selinux --with-audit=linux \ --with-sandbox=seccomp_filter \ @@ -776,6 +706,7 @@ test -f %{sysconfig_anaconda} && \ %files server %dir %attr(0711,root,root) %{_datadir}/empty.sshd %attr(0755,root,root) %{_sbindir}/sshd +%attr(0755,root,root) %{_libexecdir}/openssh/sshd-session %attr(0755,root,root) %{_libexecdir}/openssh/sftp-server %attr(0755,root,root) %{_libexecdir}/openssh/sshd-keygen %attr(0644,root,root) %{_mandir}/man5/sshd_config.5* @@ -817,6 +748,28 @@ test -f %{sysconfig_anaconda} && \ %endif %changelog +* Wed Feb 25 2026 Dmitry Belyavskiy - 9.9p1-4 +- Provide a way to skip unsupported ML-KEM hybrid algorithms in FIPS mode + Resolves: RHEL-151580 + +* Tue Dec 09 2025 Zoltan Fridrich - 9.9p1-3 +- Enable support for DSA keys + Resolves: RHEL-127624 +- CVE-2025-61984: Reject usernames with control characters + Resolves: RHEL-133959 +- CVE-2025-61985: Reject URL-strings with NULL characters + Resolves: RHEL-133960 + +* Mon Oct 27 2025 Zoltan Fridrich - 9.9p1-2 +- Fix implicit destination path selection when source path ends with ".." + Resolves: RHEL-119515 +- Canonicalize username when matching a user + Resolves: RHEL-118372 + +* Wed Sep 10 2025 Pavol Žáčik - 9.9p1-1 +- Rebase to version 9.9 + Resolves: RHEL-108912 + * Mon Jul 21 2025 Zoltan Fridrich - 8.7p1-46 - Move the redhat help message to debug1 log level Resolves: RHEL-104580