diff --git a/.fmf/version b/.fmf/version deleted file mode 100644 index d00491f..0000000 --- a/.fmf/version +++ /dev/null @@ -1 +0,0 @@ -1 diff --git a/.gitignore b/.gitignore index 98996cc..6988bb2 100644 --- a/.gitignore +++ b/.gitignore @@ -60,11 +60,3 @@ pam_ssh_agent_auth-0.9.2.tar.bz2 /openssh-9.3p1.tar.gz.asc /openssh-9.6p1.tar.gz /openssh-9.6p1.tar.gz.asc -/openssh-9.8p1.tar.gz -/openssh-9.8p1.tar.gz.asc -/openssh-9.9p1.tar.gz -/openssh-9.9p1.tar.gz.asc -/openssh-10.0p1.tar.gz -/openssh-10.0p1.tar.gz.asc -/openssh-10.2p1.tar.gz -/openssh-10.2p1.tar.gz.asc diff --git a/0005-openssh-5.8p2-sigpipe.patch b/0005-openssh-5.8p2-sigpipe.patch deleted file mode 100644 index a2a3714..0000000 --- a/0005-openssh-5.8p2-sigpipe.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 6ac14fb92cf0d0676f19282f30b9e427025be31b Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 05/53] openssh-5.8p2-sigpipe - ---- - ssh-keyscan.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/ssh-keyscan.c b/ssh-keyscan.c -index f9788114d..11618ae8a 100644 ---- a/ssh-keyscan.c -+++ b/ssh-keyscan.c -@@ -776,6 +776,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 = xcalloc(maxfd, sizeof(struct pollfd)); - for (j = 0; j < maxfd; j++) - read_wait[j].fd = -1; --- -2.52.0 - diff --git a/0010-openssh-7.8p1-UsePAM-warning.patch b/0010-openssh-7.8p1-UsePAM-warning.patch deleted file mode 100644 index 521abe4..0000000 --- a/0010-openssh-7.8p1-UsePAM-warning.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 5f6dbc98a184ce485aef90321ae9fc1ba45293f8 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 10/53] openssh-7.8p1-UsePAM-warning - ---- - sshd-session.c | 4 ++++ - sshd_config | 2 ++ - 2 files changed, 6 insertions(+) - -diff --git a/sshd-session.c b/sshd-session.c -index 1c72e664a..9804dc334 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -1103,6 +1103,10 @@ main(int ac, char **av) - "enabled authentication methods"); - } - -+ /* 'UsePAM no' is not supported in our builds */ -+ if (! options.use_pam) -+ logit("WARNING: 'UsePAM no' is not supported in this build and may cause several problems."); -+ - #ifdef WITH_OPENSSL - if (options.moduli_file != NULL) - dh_set_moduli_file(options.moduli_file); -diff --git a/sshd_config b/sshd_config -index 608203e4b..48af6321b 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -89,6 +89,8 @@ AuthorizedKeysFile .ssh/authorized_keys - # 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 this build and may cause several -+# problems. - #UsePAM no - - #AllowAgentForwarding yes --- -2.52.0 - diff --git a/0016-openssh-6.4p1-fromto-remote.patch b/0016-openssh-6.4p1-fromto-remote.patch deleted file mode 100644 index 2a2575e..0000000 --- a/0016-openssh-6.4p1-fromto-remote.patch +++ /dev/null @@ -1,28 +0,0 @@ -From d755d647c33f96cd4ec7d5499d11ecd443bdb098 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 16/53] openssh-6.4p1-fromto-remote - ---- - scp.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/scp.c b/scp.c -index c5f573cc1..d97a54cc4 100644 ---- a/scp.c -+++ b/scp.c -@@ -1148,7 +1148,10 @@ toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct) - addargs(&alist, "%s", ssh_program); - addargs(&alist, "-x"); - addargs(&alist, "-oClearAllForwardings=yes"); -- addargs(&alist, "-n"); -+ if (isatty(fileno(stdin))) -+ addargs(&alist, "-t"); -+ else -+ addargs(&alist, "-n"); - for (j = 0; j < remote_remote_args.num; j++) { - addargs(&alist, "%s", - remote_remote_args.list[j]); --- -2.52.0 - diff --git a/0018-openssh-6.6.1p1-scp-non-existing-directory.patch b/0018-openssh-6.6.1p1-scp-non-existing-directory.patch deleted file mode 100644 index e50e1c2..0000000 --- a/0018-openssh-6.6.1p1-scp-non-existing-directory.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 931f22f77ab2b9cebd96e113f1e3ab179dd1b6cb Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 18/53] openssh-6.6.1p1-scp-non-existing-directory - ---- - scp.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/scp.c b/scp.c -index d97a54cc4..e1992622f 100644 ---- a/scp.c -+++ b/scp.c -@@ -1866,6 +1866,10 @@ sink(int argc, char **argv, const char *src) - free(vect[0]); - continue; - } -+ if (buf[0] == 'C' && ! exists && np[strlen(np)-1] == '/') { -+ errno = ENOTDIR; -+ goto bad; -+ } - omode = mode; - mode |= S_IWUSR; - if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) == -1) { --- -2.52.0 - diff --git a/0020-openssh-6.8p1-sshdT-output.patch b/0020-openssh-6.8p1-sshdT-output.patch deleted file mode 100644 index ed2379e..0000000 --- a/0020-openssh-6.8p1-sshdT-output.patch +++ /dev/null @@ -1,25 +0,0 @@ -From cce18d636f4137a4e5401170538868b8b80651c1 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 20/53] openssh-6.8p1-sshdT-output - ---- - servconf.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/servconf.c b/servconf.c -index 5e40f1b00..b63a7f0b0 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -3368,7 +3368,7 @@ dump_config(ServerOptions *o) - dump_cfg_string(sXAuthLocation, o->xauth_location); - dump_cfg_string(sCiphers, o->ciphers); - dump_cfg_string(sMacs, o->macs); -- dump_cfg_string(sBanner, o->banner); -+ dump_cfg_string(sBanner, o->banner != NULL ? o->banner : "none"); - dump_cfg_string(sForceCommand, o->adm_forced_command); - dump_cfg_string(sChrootDirectory, o->chroot_directory); - dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); --- -2.52.0 - diff --git a/0024-openssh-7.5p1-sandbox.patch b/0024-openssh-7.5p1-sandbox.patch deleted file mode 100644 index 32b56db..0000000 --- a/0024-openssh-7.5p1-sandbox.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 503297ec6f6eef3bb4906271d170fab848e27298 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 24/53] openssh-7.5p1-sandbox - ---- - sandbox-seccomp-filter.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c -index a0692dd2f..e0f2d4289 100644 ---- a/sandbox-seccomp-filter.c -+++ b/sandbox-seccomp-filter.c -@@ -305,6 +305,9 @@ static const struct sock_filter preauth_insns[] = { - #ifdef __NR_exit_group - SC_ALLOW(__NR_exit_group), - #endif -+#if defined(__NR_flock) && defined(__s390__) -+ SC_ALLOW(__NR_flock), -+#endif - #ifdef __NR_futex - SC_FUTEX(__NR_futex), - #endif -@@ -323,6 +326,21 @@ static const struct sock_filter preauth_insns[] = { - #ifdef __NR_getpid - SC_ALLOW(__NR_getpid), - #endif -+#ifdef __NR_getuid -+ SC_ALLOW(__NR_getuid), -+#endif -+#ifdef __NR_getuid32 -+ SC_ALLOW(__NR_getuid32), -+#endif -+#ifdef __NR_geteuid -+ SC_ALLOW(__NR_geteuid), -+#endif -+#ifdef __NR_geteuid32 -+ SC_ALLOW(__NR_geteuid32), -+#endif -+#ifdef __NR_gettid -+ SC_ALLOW(__NR_gettid), -+#endif - #ifdef __NR_getrandom - SC_ALLOW(__NR_getrandom), - #endif -@@ -332,6 +350,9 @@ static const struct sock_filter preauth_insns[] = { - #ifdef __NR_gettimeofday - SC_ALLOW(__NR_gettimeofday), - #endif -+#if defined(__NR_ipc) && defined(__s390__) -+ SC_ALLOW(__NR_ipc), -+#endif - #ifdef __NR_getuid - SC_ALLOW(__NR_getuid), - #endif --- -2.52.0 - diff --git a/0027-openssh-8.0p1-openssl-kdf.patch b/0027-openssh-8.0p1-openssl-kdf.patch deleted file mode 100644 index 6f7f49b..0000000 --- a/0027-openssh-8.0p1-openssl-kdf.patch +++ /dev/null @@ -1,157 +0,0 @@ -From d73633dd9770bea0c3802075842398faf3e55e30 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 27/53] openssh-8.0p1-openssl-kdf - ---- - configure.ac | 1 + - kex.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 108 insertions(+) - -diff --git a/configure.ac b/configure.ac -index adccaebd4..805be4b5e 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3182,6 +3182,7 @@ if test "x$openssl" = "xyes" ; then - HMAC_CTX_init \ - RSA_generate_key_ex \ - RSA_get_default_method \ -+ EVP_KDF_CTX_new \ - ]) - - # OpenSSL_add_all_algorithms may be a macro. -diff --git a/kex.c b/kex.c -index 9a2ce6d88..5f9530908 100644 ---- a/kex.c -+++ b/kex.c -@@ -38,6 +38,11 @@ - #ifdef WITH_OPENSSL - #include - #include -+# ifdef HAVE_EVP_KDF_CTX_NEW -+# include -+# include -+# include -+# endif - #endif - - #include "ssh.h" -@@ -1077,6 +1082,107 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) - return r; - } - -+#ifdef HAVE_EVP_KDF_CTX_NEW -+static const char * -+digest_to_md(int digest_type) -+{ -+ switch (digest_type) { -+ case SSH_DIGEST_SHA1: -+ return SN_sha1; -+ case SSH_DIGEST_SHA256: -+ return SN_sha256; -+ case SSH_DIGEST_SHA384: -+ return SN_sha384; -+ case SSH_DIGEST_SHA512: -+ return SN_sha512; -+ } -+ return NULL; -+} -+ -+static int -+derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, -+ const struct sshbuf *shared_secret, u_char **keyp) -+{ -+ struct kex *kex = ssh->kex; -+ u_char *key = NULL; -+ int r, key_len; -+ -+ EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSHKDF", NULL); -+ EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf); -+ OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new(); -+ OSSL_PARAM *params = NULL; -+ const char *md = digest_to_md(kex->hash_alg); -+ char keytype = (char)id; -+ -+ EVP_KDF_free(kdf); -+ if (!ctx) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (md == NULL) { -+ r = SSH_ERR_INVALID_ARGUMENT; -+ goto out; -+ } -+ -+ if (param_bld == NULL) { -+ EVP_KDF_CTX_free(ctx); -+ return -1; -+ } -+ if ((key_len = ssh_digest_bytes(kex->hash_alg)) == 0) { -+ r = SSH_ERR_INVALID_ARGUMENT; -+ goto out; -+ } -+ -+ key_len = ROUNDUP(need, key_len); -+ if ((key = calloc(1, key_len)) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ r = OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_DIGEST, -+ md, strlen(md)) && /* SN */ -+ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_KEY, -+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)) && -+ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_XCGHASH, -+ hash, hashlen) && -+ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_SESSION_ID, -+ sshbuf_ptr(kex->session_id), sshbuf_len(kex->session_id)) && -+ OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_SSHKDF_TYPE, -+ &keytype, 1); -+ if (r != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ params = OSSL_PARAM_BLD_to_param(param_bld); -+ if (params == NULL) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ r = EVP_KDF_derive(ctx, key, key_len, params); -+ if (r != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+#ifdef DEBUG_KEX -+ fprintf(stderr, "key '%c'== ", id); -+ dump_digest("key", key, key_len); -+#endif -+ *keyp = key; -+ key = NULL; -+ r = 0; -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ OSSL_PARAM_free(params); -+ free (key); -+ EVP_KDF_CTX_free(ctx); -+ if (r < 0) { -+ return r; -+ } -+ return 0; -+} -+#else - static int - derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, - const struct sshbuf *shared_secret, u_char **keyp) -@@ -1140,6 +1246,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, - ssh_digest_free(hashctx); - return r; - } -+#endif /* HAVE_OPENSSL_EVP_KDF_CTX_NEW */ - - #define NKEYS 6 - int --- -2.52.0 - diff --git a/0034-openssh-8.7p1-ibmca.patch b/0034-openssh-8.7p1-ibmca.patch deleted file mode 100644 index 803c899..0000000 --- a/0034-openssh-8.7p1-ibmca.patch +++ /dev/null @@ -1,25 +0,0 @@ -From e2c0fb233119584b04d61d243cd58433072559c2 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 34/53] openssh-8.7p1-ibmca - ---- - openbsd-compat/bsd-closefrom.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c -index f61124585..417c20484 100644 ---- a/openbsd-compat/bsd-closefrom.c -+++ b/openbsd-compat/bsd-closefrom.c -@@ -16,7 +16,7 @@ - - #include "includes.h" - --#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) -+#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) || (defined __s390__) - - #include - #include --- -2.52.0 - diff --git a/0037-openssh-9.0p1-audit-log.patch b/0037-openssh-9.0p1-audit-log.patch deleted file mode 100644 index c58a5fe..0000000 --- a/0037-openssh-9.0p1-audit-log.patch +++ /dev/null @@ -1,265 +0,0 @@ -From ef05b1fceddc64cfc7eb40daac60a137634d0a9f Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 37/53] openssh-9.0p1-audit-log - ---- - audit-bsm.c | 2 +- - audit-linux.c | 76 +++++++++++++++++++++++++++++++++++++++++++-------- - audit.c | 18 +++++++++--- - audit.h | 2 +- - 4 files changed, 81 insertions(+), 17 deletions(-) - -diff --git a/audit-bsm.c b/audit-bsm.c -index a6292cb8f..0f2ef8235 100644 ---- a/audit-bsm.c -+++ b/audit-bsm.c -@@ -405,7 +405,7 @@ audit_session_close(struct logininfo *li) - } - - int --audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) -+audit_keyusage(struct ssh *ssh, int host_user, char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) - { - /* not implemented */ - } -diff --git a/audit-linux.c b/audit-linux.c -index 4d3e9d41e..d2bc0b526 100644 ---- a/audit-linux.c -+++ b/audit-linux.c -@@ -52,7 +52,7 @@ extern u_int utmp_len; - const char *audit_username(void); - - static void --linux_audit_user_logxxx(int uid, const char *username, -+linux_audit_user_logxxx(int uid, const char *username, const char *hostname, - const char *ip, const char *ttyn, int success, int event) - { - int audit_fd, rc, saved_errno; -@@ -68,7 +68,7 @@ linux_audit_user_logxxx(int uid, const char *username, - hostname = NULL; - rc = audit_log_acct_message(audit_fd, event, - NULL, "login", username ? username : "(unknown)", -- username == NULL ? uid : -1, NULL, ip, ttyn, success); -+ username == NULL ? uid : -1, hostname, ip, ttyn, success); - saved_errno = errno; - close(audit_fd); - -@@ -139,10 +139,12 @@ fatal_report: - } - - int --audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) -+audit_keyusage(struct ssh *ssh, int host_user, const char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) - { - char buf[AUDIT_LOG_SIZE]; - int audit_fd, rc, saved_errno; -+ const char *rip; -+ u_int i; - - audit_fd = audit_open(); - if (audit_fd < 0) { -@@ -152,14 +154,44 @@ audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) - else - return 0; /* Must prevent login */ - } -+ rip = ssh_remote_ipaddr(ssh); - snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased"); - rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -- buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv); -+ buf, audit_username(), -1, NULL, rip, NULL, rv); - if ((rc < 0) && ((rc != -1) || (getuid() == 0))) - goto out; -- snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp); -+ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", key_fp); - rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, -- ssh_remote_ipaddr(ssh), NULL, rv); -+ rip, NULL, rv); -+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) -+ goto out; -+ -+ if (cert) { -+ char *pbuf; -+ -+ pbuf = audit_encode_nv_string("key_id", cert->key_id, 0); -+ if (pbuf == NULL) -+ goto out; -+ snprintf(buf, sizeof(buf), "cert %s cert_serial=%llu cert_issuer_alg=\"%s\" cert_issuer_fp=\"%s\"", -+ pbuf, (unsigned long long)cert->serial, sshkey_type(cert->signature_key), issuer_fp); -+ free(pbuf); -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, rip, NULL, rv); -+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) -+ goto out; -+ -+ for (i = 0; cert->principals != NULL && i < cert->nprincipals; i++) { -+ pbuf = audit_encode_nv_string("cert_principal", cert->principals[i], 0); -+ if (pbuf == NULL) -+ goto out; -+ snprintf(buf, sizeof(buf), "principal %s", pbuf); -+ free(pbuf); -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, rip, NULL, rv); -+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) -+ goto out; -+ } -+ } - out: - saved_errno = errno; - audit_close(audit_fd); -@@ -181,26 +213,34 @@ audit_connection_from(const char *host, int port) - int - audit_run_command(struct ssh *ssh, const char *command) - { -+ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; - if (!user_login_count++) - linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ audit_hostname, - ssh_remote_ipaddr(ssh), - "ssh", 1, AUDIT_USER_LOGIN); - linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ audit_hostname, - ssh_remote_ipaddr(ssh), - "ssh", 1, AUDIT_USER_START); -+ free(audit_hostname); - return 0; - } - - void - audit_end_command(struct ssh *ssh, int handle, const char *command) - { -+ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; - linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ audit_hostname, - ssh_remote_ipaddr(ssh), - "ssh", 1, AUDIT_USER_END); - if (user_login_count && !--user_login_count) - linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ audit_hostname, - ssh_remote_ipaddr(ssh), - "ssh", 1, AUDIT_USER_LOGOUT); -+ free(audit_hostname); - } - - void -@@ -213,31 +253,41 @@ void - audit_session_open(struct logininfo *li) - { - if (!user_login_count++) -- linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ linux_audit_user_logxxx(li->uid, NULL, -+ options.use_dns ? li->hostname : NULL, -+ options.use_dns ? NULL : li->hostname, - li->line, 1, AUDIT_USER_LOGIN); -- linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ linux_audit_user_logxxx(li->uid, NULL, -+ options.use_dns ? li->hostname : NULL, -+ options.use_dns ? NULL : li->hostname, - li->line, 1, AUDIT_USER_START); - } - - void - audit_session_close(struct logininfo *li) - { -- linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ linux_audit_user_logxxx(li->uid, NULL, -+ options.use_dns ? li->hostname : NULL, -+ options.use_dns ? NULL : li->hostname, - li->line, 1, AUDIT_USER_END); - if (user_login_count && !--user_login_count) -- linux_audit_user_logxxx(li->uid, NULL, li->hostname, -+ linux_audit_user_logxxx(li->uid, NULL, -+ options.use_dns ? li->hostname : NULL, -+ options.use_dns ? NULL : li->hostname, - li->line, 1, AUDIT_USER_LOGOUT); - } - - void - audit_event(struct ssh *ssh, ssh_audit_event_t event) - { -+ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; -+ - switch(event) { - case SSH_NOLOGIN: - case SSH_LOGIN_ROOT_DENIED: - linux_audit_user_auth(-1, audit_username(), - ssh_remote_ipaddr(ssh), "ssh", 0, event); -- linux_audit_user_logxxx(-1, audit_username(), -+ linux_audit_user_logxxx(-1, audit_username(), audit_hostname, - ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); - break; - case SSH_AUTH_FAIL_PASSWD: -@@ -257,9 +307,11 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) - if (user_login_count) { - while (user_login_count--) - linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ audit_hostname, - ssh_remote_ipaddr(ssh), - "ssh", 1, AUDIT_USER_END); - linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, -+ audit_hostname, - ssh_remote_ipaddr(ssh), - "ssh", 1, AUDIT_USER_LOGOUT); - } -@@ -268,12 +320,14 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) - case SSH_CONNECTION_ABANDON: - case SSH_INVALID_USER: - linux_audit_user_logxxx(-1, audit_username(), -+ audit_hostname, - ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); - break; - default: - debug_f("unhandled event %d", event); - break; - } -+ free(audit_hostname); - } - - void -diff --git a/audit.c b/audit.c -index d0433c3a0..28d51a146 100644 ---- a/audit.c -+++ b/audit.c -@@ -116,12 +116,22 @@ audit_event_lookup(ssh_audit_event_t ev) - void - audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) - { -- char *fp; -+ char *key_fp = NULL; -+ char *issuer_fp = NULL; -+ struct sshkey_cert *cert = NULL; - -- fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); -- if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) -+ key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); -+ if (sshkey_is_cert(key) && key->cert != NULL && key->cert->signature_key != NULL) { -+ cert = key->cert; -+ issuer_fp = sshkey_fingerprint(cert->signature_key, -+ options.fingerprint_hash, SSH_FP_DEFAULT); -+ } -+ if (audit_keyusage(ssh, host_user, key_fp, cert, issuer_fp, (*rv == 0)) == 0) - *rv = -SSH_ERR_INTERNAL_ERROR; -- free(fp); -+ if (key_fp) -+ free(key_fp); -+ if (issuer_fp) -+ free(issuer_fp); - } - - void -diff --git a/audit.h b/audit.h -index 45d66ccff..05ac132cf 100644 ---- a/audit.h -+++ b/audit.h -@@ -64,7 +64,7 @@ void audit_session_close(struct logininfo *); - int audit_run_command(struct ssh *, const char *); - void audit_end_command(struct ssh *, int, const char *); - ssh_audit_event_t audit_classify_auth(const char *); --int audit_keyusage(struct ssh *, int, char *, int); -+int audit_keyusage(struct ssh *, int, const char *, const struct sshkey_cert *, const char *, int); - void audit_key(struct ssh *, int, int *, const struct sshkey *); - void audit_unsupported(struct ssh *, int); - void audit_kex(struct ssh *, int, char *, char *, char *, char *); --- -2.52.0 - diff --git a/0039-openssh-8.7p1-ssh-manpage.patch b/0039-openssh-8.7p1-ssh-manpage.patch deleted file mode 100644 index d0e984d..0000000 --- a/0039-openssh-8.7p1-ssh-manpage.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 7167a191776dacf7e31cf8a8a2ed89887e49f4ee Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 39/53] openssh-8.7p1-ssh-manpage - ---- - ssh.1 | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/ssh.1 b/ssh.1 -index 6a9fbdc5b..755cdef2b 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -510,12 +510,12 @@ For full details of the options listed below, and their possible values, see - .It BatchMode - .It BindAddress - .It BindInterface --.It CASignatureAlgorithms - .It CanonicalDomains - .It CanonicalizeFallbackLocal - .It CanonicalizeHostname - .It CanonicalizeMaxDots - .It CanonicalizePermittedCNAMEs -+.It CASignatureAlgorithms - .It CertificateFile - .It ChannelTimeout - .It CheckHostIP -@@ -528,6 +528,7 @@ For full details of the options listed below, and their possible values, see - .It ControlPath - .It ControlPersist - .It DynamicForward -+.It EnableSSHKeysign - .It EnableEscapeCommandline - .It EnableSSHKeysign - .It EscapeChar -@@ -588,6 +589,8 @@ For full details of the options listed below, and their possible values, see - .It RemoteCommand - .It RemoteForward - .It RequestTTY -+.It RevokedHostKeys -+.It SecurityKeyProvider - .It RequiredRSASize - .It RevokedHostKeys - .It SecurityKeyProvider --- -2.52.0 - diff --git a/0041-openssh-9.0p1-evp-fips-kex.patch b/0041-openssh-9.0p1-evp-fips-kex.patch deleted file mode 100644 index 24ef8e8..0000000 --- a/0041-openssh-9.0p1-evp-fips-kex.patch +++ /dev/null @@ -1,616 +0,0 @@ -From 1c0d3b6e9868ef31b97be1679389e3db2616eccd Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 41/53] openssh-9.0p1-evp-fips-kex - ---- - dh.c | 98 +++++++++++++++++++++++++++++++++----- - kex.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ - kex.h | 6 +++ - kexdh.c | 52 ++++++++++++++++++-- - kexecdh.c | 129 ++++++++++++++++++++++++++++++++++++++++---------- - 5 files changed, 382 insertions(+), 42 deletions(-) - -diff --git a/dh.c b/dh.c -index 8c9a29fa7..ea0a0b093 100644 ---- a/dh.c -+++ b/dh.c -@@ -37,6 +37,9 @@ - #include - #include - #include -+#include -+#include -+#include - - #include "dh.h" - #include "pathnames.h" -@@ -290,10 +293,15 @@ dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub) - 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 @@ dh_gen_key(DH *dh, int need) - 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 --git a/kex.c b/kex.c -index da2a537ce..56c80395c 100644 ---- a/kex.c -+++ b/kex.c -@@ -1613,3 +1613,142 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms, - 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 --git a/kex.h b/kex.h -index cb06e85a3..6daafb159 100644 ---- a/kex.h -+++ b/kex.h -@@ -37,6 +37,9 @@ - # include - # include - # include -+# include -+# include -+# include - # ifdef OPENSSL_HAS_ECC - # include - # else /* OPENSSL_HAS_ECC */ -@@ -316,6 +319,9 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE], - 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 --git a/kexdh.c b/kexdh.c -index 6d5a7813d..b05277aa1 100644 ---- a/kexdh.c -+++ b/kexdh.c -@@ -36,6 +36,10 @@ - #include "openbsd-compat/openssl-compat.h" - #include - #include -+#include -+#include -+#include -+#include - - #include "sshkey.h" - #include "kex.h" -@@ -84,9 +88,12 @@ int - 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= "); -@@ -101,24 +108,59 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) - 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 --git a/kexecdh.c b/kexecdh.c -index 500ec5725..1a1bae35e 100644 ---- a/kexecdh.c -+++ b/kexecdh.c -@@ -36,17 +36,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) - { -@@ -56,11 +96,7 @@ kex_ecdh_keypair(struct kex *kex) - 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; - } -@@ -102,11 +138,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, - *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; - } -@@ -141,11 +173,21 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, - { - 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) { -@@ -154,45 +196,82 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, - } - 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; - } --- -2.52.0 - diff --git a/0042-openssh-8.7p1-nohostsha1proof.patch b/0042-openssh-8.7p1-nohostsha1proof.patch deleted file mode 100644 index 681d051..0000000 --- a/0042-openssh-8.7p1-nohostsha1proof.patch +++ /dev/null @@ -1,332 +0,0 @@ -From 1cd47036353899fe066f5241d3d70778f103c0e0 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 42/53] openssh-8.7p1-nohostsha1proof - ---- - compat.c | 6 ++++++ - compat.h | 2 +- - monitor.c | 27 +++++++++++++++++------ - regress/unittests/kex/test_kex.c | 3 ++- - regress/unittests/sshkey/test_file.c | 3 ++- - regress/unittests/sshkey/test_fuzz.c | 3 ++- - regress/unittests/sshkey/test_sshkey.c | 30 ++++++++++++++++---------- - serverloop.c | 6 +++++- - ssh-rsa.c | 3 ++- - sshconnect2.c | 8 +++++++ - sshd-session.c | 21 ++++++++++++++++++ - 11 files changed, 88 insertions(+), 24 deletions(-) - -diff --git a/compat.c b/compat.c -index b59f0bfc0..4e611dc39 100644 ---- a/compat.c -+++ b/compat.c -@@ -42,6 +42,7 @@ void - compat_banner(struct ssh *ssh, const char *version) - { - int i; -+ int forbid_ssh_rsa = 0; - static struct { - char *pat; - int bugs; -@@ -125,16 +126,21 @@ compat_banner(struct ssh *ssh, const char *version) - }; - - /* process table, return first match */ -+ forbid_ssh_rsa = (ssh->compat & SSH_RH_RSASIGSHA); - ssh->compat = 0; - for (i = 0; check[i].pat; i++) { - if (match_pattern_list(version, check[i].pat, 0) == 1) { - debug_f("match: %s pat %s compat 0x%08x", - version, check[i].pat, check[i].bugs); - ssh->compat = check[i].bugs; -+ if (forbid_ssh_rsa) -+ ssh->compat |= SSH_RH_RSASIGSHA; - return; - } - } - debug_f("no match: %s", version); -+ if (forbid_ssh_rsa) -+ ssh->compat |= SSH_RH_RSASIGSHA; - } - - /* Always returns pointer to allocated memory, caller must free. */ -diff --git a/compat.h b/compat.h -index 1a19060fc..2e6db5bf9 100644 ---- a/compat.h -+++ b/compat.h -@@ -30,7 +30,7 @@ - #define SSH_BUG_UTF8TTYMODE 0x00000001 - #define SSH_BUG_SIGTYPE 0x00000002 - #define SSH_BUG_SIGTYPE74 0x00000004 --/* #define unused 0x00000008 */ -+#define SSH_RH_RSASIGSHA 0x00000008 - #define SSH_OLD_SESSIONID 0x00000010 - /* #define unused 0x00000020 */ - #define SSH_BUG_DEBUG 0x00000040 -diff --git a/monitor.c b/monitor.c -index b2f501790..6c83739ee 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -754,11 +754,12 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m) - struct sshkey *pubkey, *key; - struct sshbuf *sigbuf = NULL; - u_char *p = NULL, *signature = NULL; -- char *alg = NULL; -- size_t datlen, siglen; -- int r, is_proof = 0, keyid; -- u_int compat; -+ char *alg = NULL, *effective_alg; -+ size_t datlen, siglen, alglen; -+ int r, is_proof = 0; -+ u_int keyid, compat; - const char proof_req[] = "hostkeys-prove-00@openssh.com"; -+ const char safe_rsa[] = "rsa-sha2-256"; - - debug3_f("entering"); - -@@ -816,18 +817,30 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m) - } - - if ((key = get_hostkey_by_index(keyid)) != NULL) { -- if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg, -+ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 -+ && (sshkey_type_plain(key->type) == KEY_RSA)) { -+ effective_alg = safe_rsa; -+ } else { -+ effective_alg = alg; -+ } -+ if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, effective_alg, - options.sk_provider, NULL, compat)) != 0) - fatal_fr(r, "sign"); - } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && - auth_sock > 0) { -+ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 -+ && (sshkey_type_plain(key->type) == KEY_RSA)) { -+ effective_alg = safe_rsa; -+ } else { -+ effective_alg = alg; -+ } - if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, -- p, datlen, alg, compat)) != 0) -+ p, datlen, effective_alg, compat)) != 0) - fatal_fr(r, "agent sign"); - } else - fatal_f("no hostkey from index %d", keyid); - -- debug3_f("%s %s signature len=%zu", alg, -+ debug3_f("%s (effective: %s) %s signature len=%zu", alg, effective_alg, - is_proof ? "hostkey proof" : "KEX", siglen); - - sshbuf_reset(m); -diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c -index 16c2f2dff..f4700deeb 100644 ---- a/regress/unittests/kex/test_kex.c -+++ b/regress/unittests/kex/test_kex.c -@@ -110,7 +110,8 @@ do_kex_with_key(char *kex, char *cipher, char *mac, - kex_params.proposal[PROPOSAL_MAC_ALGS_CTOS] = mac; - kex_params.proposal[PROPOSAL_MAC_ALGS_STOC] = mac; - } -- keyname = strdup(sshkey_ssh_name(private)); -+ keyname = (strcmp(sshkey_ssh_name(private), "ssh-rsa")) ? -+ strdup(sshkey_ssh_name(private)) : strdup("rsa-sha2-256"); - ASSERT_PTR_NE(keyname, NULL); - kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; - ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0); -diff --git a/regress/unittests/sshkey/test_file.c b/regress/unittests/sshkey/test_file.c -index e412b75d8..5b06bc905 100644 ---- a/regress/unittests/sshkey/test_file.c -+++ b/regress/unittests/sshkey/test_file.c -@@ -106,6 +106,7 @@ sshkey_file_tests(void) - sshkey_free(k2); - TEST_DONE(); - -+ /* Skip this test, SHA1 signatures are not supported - TEST_START("load RSA cert with SHA1 signature"); - ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha1"), &k2), 0); - ASSERT_PTR_NE(k2, NULL); -@@ -113,7 +114,7 @@ sshkey_file_tests(void) - ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1); - ASSERT_STRING_EQ(k2->cert->signature_type, "ssh-rsa"); - sshkey_free(k2); -- TEST_DONE(); -+ TEST_DONE(); */ - - TEST_START("load RSA cert with SHA512 signature"); - ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha512"), &k2), 0); -diff --git a/regress/unittests/sshkey/test_fuzz.c b/regress/unittests/sshkey/test_fuzz.c -index d0f47d7cf..ba4d506d5 100644 ---- a/regress/unittests/sshkey/test_fuzz.c -+++ b/regress/unittests/sshkey/test_fuzz.c -@@ -273,13 +273,14 @@ sshkey_fuzz_tests(void) - TEST_DONE(); - - #ifdef WITH_OPENSSL -+ /* Skip this test, SHA1 signatures are not supported - TEST_START("fuzz RSA sig"); - buf = load_file("rsa_1"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); - sshbuf_free(buf); - sig_fuzz(k1, "ssh-rsa"); - sshkey_free(k1); -- TEST_DONE(); -+ TEST_DONE();*/ - - TEST_START("fuzz RSA SHA256 sig"); - buf = load_file("rsa_1"); -diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c -index d0c46a90b..7b5e51b83 100644 ---- a/regress/unittests/sshkey/test_sshkey.c -+++ b/regress/unittests/sshkey/test_sshkey.c -@@ -59,6 +59,9 @@ build_cert(struct sshbuf *b, struct sshkey *k, const char *type, - u_char *sigblob; - size_t siglen; - -+ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp */ -+ int expected = (sig_alg == NULL || strcmp(sig_alg, "ssh-rsa") == 0) ? SSH_ERR_LIBCRYPTO_ERROR : 0; -+ - ca_buf = sshbuf_new(); - ASSERT_PTR_NE(ca_buf, NULL); - ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0); -@@ -100,8 +103,9 @@ build_cert(struct sshbuf *b, struct sshkey *k, const char *type, - ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ - ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ - ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, -- sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), 0); -- ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ -+ sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), expected); -+ if (expected == 0) -+ ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ - - free(sigblob); - sshbuf_free(ca_buf); -@@ -118,16 +122,20 @@ signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg, - { - size_t len; - u_char *sig; -+ /* ssh-rsa implies SHA1, forbidden in DEFAULT crypto policies */ -+ int expected = (sig_alg && strcmp(sig_alg, "ssh-rsa") == 0) ? sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, NULL, 0) : 0; - - ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, -- NULL, NULL, 0), 0); -- ASSERT_SIZE_T_GT(len, 8); -- ASSERT_PTR_NE(sig, NULL); -- ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); -- ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); -- /* Fuzz test is more comprehensive, this is just a smoke test */ -- sig[len - 5] ^= 0x10; -- ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); -+ NULL, NULL, 0), expected); -+ if (expected == 0) { -+ ASSERT_SIZE_T_GT(len, 8); -+ ASSERT_PTR_NE(sig, NULL); -+ ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); -+ ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); -+ /* Fuzz test is more comprehensive, this is just a smoke test */ -+ sig[len - 5] ^= 0x10; -+ ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); -+ } - free(sig); - } - -@@ -552,7 +560,7 @@ sshkey_tests(void) - ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, - NULL), 0); - k3 = get_private("rsa_1"); -- build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, NULL); -+ build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, "rsa-sha2-256"); - 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 --git a/serverloop.c b/serverloop.c -index 5d3b194d1..55411a6b4 100644 ---- a/serverloop.c -+++ b/serverloop.c -@@ -76,6 +76,7 @@ - #include "auth-options.h" - #include "serverloop.h" - #include "ssherr.h" -+#include "compat.h" - - extern ServerOptions options; - -@@ -721,7 +722,10 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp) - else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) - sigalg = "rsa-sha2-256"; - } -- -+ if (ssh->compat & SSH_RH_RSASIGSHA && sigalg == NULL) { -+ sigalg = "rsa-sha2-512"; -+ 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); - if ((r = sshbuf_put_cstring(sigbuf, -diff --git a/ssh-rsa.c b/ssh-rsa.c -index 9428df8d1..7843f3e26 100644 ---- a/ssh-rsa.c -+++ b/ssh-rsa.c -@@ -533,7 +533,8 @@ ssh_rsa_verify(const struct sshkey *key, - ret = SSH_ERR_INVALID_ARGUMENT; - goto out; - } -- if (hash_alg != want_alg) { -+ if (hash_alg != want_alg && want_alg != SSH_DIGEST_SHA1) { -+ debug_f("Unexpected digest algorithm: got %d, wanted %d", hash_alg, want_alg); - ret = SSH_ERR_SIGNATURE_INVALID; - goto out; - } -diff --git a/sshconnect2.c b/sshconnect2.c -index f43c81ad9..2d98fc3da 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -1434,6 +1434,14 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, - retried = 1; - goto retry_pin; - } -+ if ((r == SSH_ERR_LIBCRYPTO_ERROR) && strcmp("ssh-rsa", alg)) { -+ char rsa_safe_alg[] = "rsa-sha2-512"; -+ 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) -+ debug_fr(r, "sshkey_sign - RSA fallback"); -+ } - goto out; - } - -diff --git a/sshd-session.c b/sshd-session.c -index e49e4fb51..a558bbc33 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -1288,6 +1288,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); --- -2.52.0 - diff --git a/0043-openssh-9.9p1-separate-keysign.patch b/0043-openssh-9.9p1-separate-keysign.patch deleted file mode 100644 index 60a6d4f..0000000 --- a/0043-openssh-9.9p1-separate-keysign.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 1799ea7ad21a579b864a536709d732f4a8e533dc Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 43/53] openssh-9.9p1-separate-keysign - ---- - ssh_config.5 | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/ssh_config.5 b/ssh_config.5 -index 8ac5e1633..a06fbfa11 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -797,7 +797,7 @@ or - This option should be placed in the non-hostspecific section. - See - .Xr ssh-keysign 8 --for more information. -+for more information. ssh-keysign should be installed explicitly. - .It Cm EscapeChar - Sets the escape character (default: - .Ql ~ ) . --- -2.52.0 - diff --git a/0044-openssh-9.9p1-openssl-mlkem.patch b/0044-openssh-9.9p1-openssl-mlkem.patch deleted file mode 100644 index 3e72647..0000000 --- a/0044-openssh-9.9p1-openssl-mlkem.patch +++ /dev/null @@ -1,402 +0,0 @@ -From 21202362f4ddaeb630d873fb426039004ac82338 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 44/53] openssh-9.9p1-openssl-mlkem - ---- - kex-names.c | 23 +++- - kexmlkem768x25519.c | 291 ++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 313 insertions(+), 1 deletion(-) - -diff --git a/kex-names.c b/kex-names.c -index 1360a4095..9c96e5cb0 100644 ---- a/kex-names.c -+++ b/kex-names.c -@@ -109,6 +109,19 @@ static const struct kexalg gss_kexalgs[] = { - { NULL, 0, -1, -1, 0}, - }; - -+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) - { -@@ -116,8 +129,12 @@ kex_alg_list_internal(char sep, const struct kexalg *algs) - const struct kexalg *k; - char sep_str[2] = {sep, '\0'}; - -- for (k = kexalgs; k->name != NULL; k++) -+ for (k = kexalgs; k->name != NULL; k++) { -+ if (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0 -+ && !is_mlkem768_available()) -+ continue; - xextendf(&ret, sep_str, "%s", k->name); -+ } - - return ret; - } -@@ -139,6 +156,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 2585d1db3..ab6167221 100644 ---- a/kexmlkem768x25519.c -+++ b/kexmlkem768x25519.c -@@ -44,10 +44,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; -@@ -82,6 +199,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 -@@ -89,6 +236,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; -@@ -181,12 +329,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; -@@ -254,6 +487,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 --- -2.52.0 - diff --git a/0045-openssh-9.9p2-error_processing.patch b/0045-openssh-9.9p2-error_processing.patch deleted file mode 100644 index 48aa76a..0000000 --- a/0045-openssh-9.9p2-error_processing.patch +++ /dev/null @@ -1,25 +0,0 @@ -From edbbdc306c1710dae777ef315a0d2c5f43134d33 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Fri, 16 May 2025 14:53:54 +0200 -Subject: [PATCH 45/53] openssh-9.9p2-error_processing - ---- - ssh-agent.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/ssh-agent.c b/ssh-agent.c -index df241379c..dc246066d 100644 ---- a/ssh-agent.c -+++ b/ssh-agent.c -@@ -1346,6 +1346,8 @@ process_add_identity(SocketEntry *e) - if ((r = sshkey_private_deserialize(e->request, &k)) != 0 || - k == NULL || - (r = sshbuf_get_cstring(e->request, &comment, NULL)) != 0) { -+ if (!r) /* k == NULL */ -+ r = SSH_ERR_INTERNAL_ERROR; - error_fr(r, "parse"); - goto out; - } --- -2.52.0 - diff --git a/0046-Provide-better-error-for-non-supported-private-keys.patch b/0046-Provide-better-error-for-non-supported-private-keys.patch deleted file mode 100644 index dd30967..0000000 --- a/0046-Provide-better-error-for-non-supported-private-keys.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0772377e00b13f5afaa1b146ce32d0218e9f0d24 Mon Sep 17 00:00:00 2001 -From: Zoltan Fridrich -Date: Wed, 16 Apr 2025 15:11:59 +0200 -Subject: [PATCH 46/53] Provide better error for non-supported private keys - -Signed-off-by: Zoltan Fridrich ---- - sshkey.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/sshkey.c b/sshkey.c -index 394d9b105..eba55ef92 100644 ---- a/sshkey.c -+++ b/sshkey.c -@@ -3539,6 +3539,9 @@ translate_libcrypto_error(unsigned long pem_err) - return SSH_ERR_LIBCRYPTO_ERROR; - } - case ERR_LIB_ASN1: -+#ifdef ERR_LIB_OSSL_DECODER -+ case ERR_LIB_OSSL_DECODER: -+#endif - return SSH_ERR_INVALID_FORMAT; - } - return SSH_ERR_LIBCRYPTO_ERROR; --- -2.52.0 - diff --git a/0047-Ignore-bad-hostkeys-in-known_hosts-file.patch b/0047-Ignore-bad-hostkeys-in-known_hosts-file.patch deleted file mode 100644 index 3bfab92..0000000 --- a/0047-Ignore-bad-hostkeys-in-known_hosts-file.patch +++ /dev/null @@ -1,86 +0,0 @@ -From d458a65ccac2283563c0fc0962519bb5a9bbd315 Mon Sep 17 00:00:00 2001 -From: Zoltan Fridrich -Date: Mon, 5 May 2025 11:52:25 +0200 -Subject: [PATCH 47/53] Ignore bad hostkeys in known_hosts file - -Signed-off-by: Zoltan Fridrich ---- - hostfile.c | 15 +++++++++++++++ - hostfile.h | 1 + - ssh.c | 2 ++ - 3 files changed, 18 insertions(+) - -diff --git a/hostfile.c b/hostfile.c -index 4cec57da5..652d15762 100644 ---- a/hostfile.c -+++ b/hostfile.c -@@ -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_line *l, void *_ctx) - 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_line *l, void *_ctx) - 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 --git a/hostfile.h b/hostfile.h -index a24a4e329..0e9b1a19a 100644 ---- a/hostfile.h -+++ b/hostfile.h -@@ -119,5 +119,6 @@ int hostkeys_foreach_file(const char *path, FILE *f, - 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 --git a/ssh.c b/ssh.c -index 7d6ba516e..320ac6834 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -106,6 +106,7 @@ - #include "ssherr.h" - #include "myproposal.h" - #include "utf8.h" -+#include "hostfile.h" - - #ifdef ENABLE_PKCS11 - #include "ssh-pkcs11.h" -@@ -1409,6 +1410,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"); - --- -2.52.0 - diff --git a/0048-support-authentication-indicators-in-GSSAPI.patch b/0048-support-authentication-indicators-in-GSSAPI.patch deleted file mode 100644 index 664a006..0000000 --- a/0048-support-authentication-indicators-in-GSSAPI.patch +++ /dev/null @@ -1,450 +0,0 @@ -From 1cf5e40e14d707de2318747758b012fc7245cb7b Mon Sep 17 00:00:00 2001 -From: Alexander Bokovoy -Date: Mon, 10 Jun 2024 23:00:03 +0300 -Subject: [PATCH 48/53] 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 805be4b5e..9d3b19925 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -5050,6 +5050,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 d2bc03486..be80e17ca 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 f78615c28..e53e8ea30 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -146,6 +146,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; -@@ -591,7 +592,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, -@@ -687,6 +688,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 }, -@@ -696,6 +698,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 }, -@@ -1722,6 +1725,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; -@@ -3344,6 +3356,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 c08cf6a7a..c7cec5ece 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -179,6 +179,7 @@ typedef struct { - char **allow_groups; - u_int num_deny_groups; - char **deny_groups; -+ char *gss_indicators; - - u_int num_subsystems; - char **subsystem_name; -@@ -308,6 +309,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 329dc9da0..1506719a9 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 -@@ -112,6 +118,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 c172d5aab..676d6d4d2 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.52.0 - diff --git a/0049-NIST-curves-hybrid-KEX-implementation.patch b/0049-NIST-curves-hybrid-KEX-implementation.patch deleted file mode 100644 index 9ce23be..0000000 --- a/0049-NIST-curves-hybrid-KEX-implementation.patch +++ /dev/null @@ -1,1216 +0,0 @@ -From 3642efdf9be4d377cfd802d6a33cb083f0d846b8 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Mon, 20 Oct 2025 16:07:31 +0200 -Subject: [PATCH 49/53] NIST curves hybrid KEX implementation - ---- - crypto_api.h | 4 + - kex-names.c | 78 +++- - kex.c | 1 + - kex.h | 19 + - kexgen.c | 56 ++- - kexmlkem768x25519.c | 678 +++++++++++++++++++++++++++++-- - monitor.c | 2 + - myproposal.h | 4 + - regress/unittests/kex/test_kex.c | 4 + - ssh-keyscan.c | 2 + - ssh_api.c | 4 + - sshconnect2.c | 2 + - sshd-auth.c | 2 + - 13 files changed, 819 insertions(+), 37 deletions(-) - -diff --git a/crypto_api.h b/crypto_api.h -index 693b67bbc..ec3d2f277 100644 ---- a/crypto_api.h -+++ b/crypto_api.h -@@ -56,4 +56,8 @@ int crypto_kem_sntrup761_keypair(unsigned char *pk, unsigned char *sk); - #define crypto_kem_mlkem768_CIPHERTEXTBYTES 1088 - #define crypto_kem_mlkem768_BYTES 32 - -+#define crypto_kem_mlkem1024_PUBLICKEYBYTES 1568 -+#define crypto_kem_mlkem1024_SECRETKEYBYTES 3168 -+#define crypto_kem_mlkem1024_CIPHERTEXTBYTES 1568 -+ - #endif /* crypto_api_h */ -diff --git a/kex-names.c b/kex-names.c -index 9c96e5cb0..ceecd9312 100644 ---- a/kex-names.c -+++ b/kex-names.c -@@ -91,6 +91,10 @@ static const struct kexalg kexalgs[] = { - #ifdef USE_MLKEM768X25519 - { KEX_MLKEM768X25519_SHA256, KEX_KEM_MLKEM768X25519_SHA256, 0, - SSH_DIGEST_SHA256, KEX_IS_PQ }, -+ { KEX_MLKEM768NISTP256_SHA256, KEX_KEM_MLKEM768NISTP256_SHA256, 0, -+ SSH_DIGEST_SHA256, KEX_IS_PQ }, -+ { KEX_MLKEM1024NISTP384_SHA384, KEX_KEM_MLKEM1024NISTP384_SHA384, 0, -+ SSH_DIGEST_SHA384, KEX_IS_PQ }, - #endif - #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ - { NULL, 0, -1, -1, 0 }, -@@ -109,13 +113,30 @@ static const struct kexalg gss_kexalgs[] = { - { NULL, 0, -1, -1, 0}, - }; - -+/* -+ * 0 - unavailable -+ * 1 - available in non-FIPS mode -+ * 2 - available in FIPS mode -+ */ - 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 *mlkem768 = NULL; -+ -+ if (FIPS_mode() == 1) { -+ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); -+ is_fetched = mlkem768 != NULL ? 2 : 0; -+ -+ if (is_fetched == 0) { -+ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", "provider=default,-fips"); -+ is_fetched = mlkem768 != NULL ? 1 : 0; -+ } -+ } else { -+ mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); -+ is_fetched = mlkem768 != NULL ? 1 : 0; -+ } - EVP_KEM_free(mlkem768); - } - -@@ -128,11 +149,32 @@ kex_alg_list_internal(char sep, const struct kexalg *algs) - char *ret = NULL; - const struct kexalg *k; - char sep_str[2] = {sep, '\0'}; -+ int x25519mlkem_available = 0, nistmlkem_available = 0; - -- for (k = kexalgs; k->name != NULL; k++) { -- if (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0 -- && !is_mlkem768_available()) -+ /* -+ * FIPS provider can provide ML-KEMs and then all hybrids are available -+ * Otherwise only NIST hybrids are available -+ * */ -+ if (FIPS_mode()) { -+ if (is_mlkem768_available() == 2) { -+ x25519mlkem_available = 1; -+ nistmlkem_available = 1; -+ } else if (is_mlkem768_available() == 1) { -+ nistmlkem_available = 1; -+ } -+ } else { -+ if (is_mlkem768_available() > 0) { -+ x25519mlkem_available = 1; -+ nistmlkem_available = 1; -+ } -+ } -+ -+ for (k = algs; k->name != NULL; k++) { -+ if ( (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0 && x25519mlkem_available == 0) -+ || (strcmp(k->name, KEX_MLKEM768NISTP256_SHA256) == 0 && nistmlkem_available == 0) -+ || (strcmp(k->name, KEX_MLKEM1024NISTP384_SHA384) == 0 && nistmlkem_available == 0)) - continue; -+ - xextendf(&ret, sep_str, "%s", k->name); - } - -@@ -155,10 +197,30 @@ static const struct kexalg * - kex_alg_by_name(const char *name) - { - const struct kexalg *k; -+ int x25519mlkem_available = 0, nistmlkem_available = 0; - -- if (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0 -- && !is_mlkem768_available()) -- return NULL; -+ /* -+ * FIPS provider can provide ML-KEMs and then all hybrids are available -+ * Otherwise only NIST hybrids are available -+ * */ -+ if (FIPS_mode()) { -+ if (is_mlkem768_available() == 2) { -+ x25519mlkem_available = 1; -+ nistmlkem_available = 1; -+ } else if (is_mlkem768_available() == 1) { -+ nistmlkem_available = 1; -+ } -+ } else { -+ if (is_mlkem768_available() > 0) { -+ x25519mlkem_available = 1; -+ nistmlkem_available = 1; -+ } -+ } -+ -+ if ( (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0 && x25519mlkem_available == 0) -+ || (strcmp(name, KEX_MLKEM768NISTP256_SHA256) == 0 && nistmlkem_available == 0) -+ || (strcmp(name, KEX_MLKEM1024NISTP384_SHA384) == 0 && nistmlkem_available == 0)) -+ return NULL; - - for (k = kexalgs; k->name != NULL; k++) { - if (strcmp(k->name, name) == 0) -diff --git a/kex.c b/kex.c -index 56c80395c..7dd16ba2b 100644 ---- a/kex.c -+++ b/kex.c -@@ -751,6 +751,7 @@ kex_free(struct kex *kex) - #ifdef OPENSSL_HAS_ECC - EC_KEY_free(kex->ec_client_key); - #endif /* OPENSSL_HAS_ECC */ -+ EVP_PKEY_free(kex->ec_hybrid_client_key); - #endif /* WITH_OPENSSL */ - for (mode = 0; mode < MODE_MAX; mode++) { - kex_free_newkeys(kex->newkeys[mode]); -diff --git a/kex.h b/kex.h -index 6daafb159..354f312e8 100644 ---- a/kex.h -+++ b/kex.h -@@ -72,6 +72,8 @@ - #define KEX_SNTRUP761X25519_SHA512 "sntrup761x25519-sha512" - #define KEX_SNTRUP761X25519_SHA512_OLD "sntrup761x25519-sha512@openssh.com" - #define KEX_MLKEM768X25519_SHA256 "mlkem768x25519-sha256" -+#define KEX_MLKEM768NISTP256_SHA256 "mlkem768nistp256-sha256" -+#define KEX_MLKEM1024NISTP384_SHA384 "mlkem1024nistp384-sha384" - - #define COMP_NONE 0 - #define COMP_DELAYED 2 -@@ -110,6 +112,8 @@ enum kex_exchange { - KEX_C25519_SHA256, - KEX_KEM_SNTRUP761X25519_SHA512, - KEX_KEM_MLKEM768X25519_SHA256, -+ KEX_KEM_MLKEM768NISTP256_SHA256, -+ KEX_KEM_MLKEM1024NISTP384_SHA384, - #ifdef GSSAPI - KEX_GSS_GRP1_SHA1, - KEX_GSS_GRP14_SHA1, -@@ -210,6 +214,9 @@ struct kex { - u_char sntrup761_client_key[crypto_kem_sntrup761_SECRETKEYBYTES]; /* KEM */ - u_char mlkem768_client_key[crypto_kem_mlkem768_SECRETKEYBYTES]; /* KEM */ - struct sshbuf *client_pub; -+ /* FIXME */ -+ EVP_PKEY *ec_hybrid_client_key; /* NIST hybrids */ -+ u_char mlkem1024_client_key[crypto_kem_mlkem1024_SECRETKEYBYTES]; /* ML-KEM 1024 + NIST */ - }; - - int kex_name_valid(const char *); -@@ -292,6 +299,18 @@ int kex_kem_mlkem768x25519_enc(struct kex *, const struct sshbuf *, - int kex_kem_mlkem768x25519_dec(struct kex *, const struct sshbuf *, - struct sshbuf **); - -+int kex_kem_mlkem768nistp256_keypair(struct kex *); -+int kex_kem_mlkem768nistp256_enc(struct kex *, const struct sshbuf *, -+ struct sshbuf **, struct sshbuf **); -+int kex_kem_mlkem768nistp256_dec(struct kex *, const struct sshbuf *, -+ struct sshbuf **); -+ -+int kex_kem_mlkem1024nistp384_keypair(struct kex *); -+int kex_kem_mlkem1024nistp384_enc(struct kex *, const struct sshbuf *, -+ struct sshbuf **, struct sshbuf **); -+int kex_kem_mlkem1024nistp384_dec(struct kex *, const struct sshbuf *, -+ struct sshbuf **); -+ - int kex_dh_keygen(struct kex *); - int kex_dh_compute_key(struct kex *, BIGNUM *, struct sshbuf *); - -diff --git a/kexgen.c b/kexgen.c -index 9a970adf1..79faa0b3e 100644 ---- a/kexgen.c -+++ b/kexgen.c -@@ -133,12 +133,24 @@ kex_gen_client(struct ssh *ssh) - break; - case KEX_KEM_MLKEM768X25519_SHA256: - if (FIPS_mode()) { -- logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); -- r = SSH_ERR_INVALID_ARGUMENT; -+ EVP_KEM *mlkem = EVP_KEM_fetch(NULL, "mlkem768", NULL); -+ if (mlkem == NULL) { -+ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ EVP_KEM_free(mlkem); -+ r = kex_kem_mlkem768x25519_keypair(kex); -+ } - } else { - r = kex_kem_mlkem768x25519_keypair(kex); - } - break; -+ case KEX_KEM_MLKEM768NISTP256_SHA256: -+ r = kex_kem_mlkem768nistp256_keypair(kex); -+ break; -+ case KEX_KEM_MLKEM1024NISTP384_SHA384: -+ r = kex_kem_mlkem1024nistp384_keypair(kex); -+ break; - default: - r = SSH_ERR_INVALID_ARGUMENT; - break; -@@ -223,13 +235,28 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) - break; - case KEX_KEM_MLKEM768X25519_SHA256: - if (FIPS_mode()) { -- logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); -- r = SSH_ERR_INVALID_ARGUMENT; -+ EVP_KEM *mlkem = EVP_KEM_fetch(NULL, "mlkem768", NULL); -+ if (mlkem == NULL) { -+ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ EVP_KEM_free(mlkem); -+ r = kex_kem_mlkem768x25519_dec(kex, server_blob, -+ &shared_secret); -+ } - } else { - r = kex_kem_mlkem768x25519_dec(kex, server_blob, - &shared_secret); - } - break; -+ case KEX_KEM_MLKEM768NISTP256_SHA256: -+ r = kex_kem_mlkem768nistp256_dec(kex, server_blob, -+ &shared_secret); -+ break; -+ case KEX_KEM_MLKEM1024NISTP384_SHA384: -+ r = kex_kem_mlkem1024nistp384_dec(kex, server_blob, -+ &shared_secret); -+ break; - default: - r = SSH_ERR_INVALID_ARGUMENT; - break; -@@ -283,6 +310,8 @@ out: - sizeof(kex->sntrup761_client_key)); - explicit_bzero(kex->mlkem768_client_key, - sizeof(kex->mlkem768_client_key)); -+ explicit_bzero(kex->mlkem1024_client_key, -+ sizeof(kex->mlkem1024_client_key)); - sshbuf_free(server_host_key_blob); - free(signature); - sshbuf_free(tmp); -@@ -362,13 +391,28 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) - break; - case KEX_KEM_MLKEM768X25519_SHA256: - if (FIPS_mode()) { -- logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); -- r = SSH_ERR_INVALID_ARGUMENT; -+ EVP_KEM *mlkem = EVP_KEM_fetch(NULL, "mlkem768", NULL); -+ if (mlkem == NULL) { -+ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ EVP_KEM_free(mlkem); -+ r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, -+ &server_pubkey, &shared_secret); -+ } - } else { - r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, - &server_pubkey, &shared_secret); - } - break; -+ case KEX_KEM_MLKEM768NISTP256_SHA256: -+ r = kex_kem_mlkem768nistp256_enc(kex, client_pubkey, -+ &server_pubkey, &shared_secret); -+ break; -+ case KEX_KEM_MLKEM1024NISTP384_SHA384: -+ r = kex_kem_mlkem1024nistp384_enc(kex, client_pubkey, -+ &server_pubkey, &shared_secret); -+ break; - default: - r = SSH_ERR_INVALID_ARGUMENT; - break; -diff --git a/kexmlkem768x25519.c b/kexmlkem768x25519.c -index ab6167221..c56d67ff4 100644 ---- a/kexmlkem768x25519.c -+++ b/kexmlkem768x25519.c -@@ -44,19 +44,33 @@ - #ifdef USE_MLKEM768X25519 - - #include "libcrux_mlkem768_sha3.h" -+#include -+#include - #include - #include -+#include - #include - -+#define FIPS_FALLBACK_PROPQ "provider=default,-fips" -+ - static int --mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) -+mlkem_keypair_gen(const char *algname, unsigned char *pubkeybuf, size_t pubkey_size, -+ unsigned char *privkeybuf, size_t privkey_size) - { - 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; -+ size_t got_pub_size = pubkey_size, got_priv_size = privkey_size; -+ -+ ctx = EVP_PKEY_CTX_new_from_name(NULL, algname, NULL); -+ -+ if (ctx == NULL && FIPS_mode()) { -+ /* We have filtered x25519 + ML-KEM in FIPS mode earlier -+ * so if we are in FIPS mode and ML-KEM is not available with default propq, -+ * we can fetch it from the default provider */ -+ ctx = EVP_PKEY_CTX_new_from_name(NULL, algname, FIPS_FALLBACK_PROPQ); -+ } - -- ctx = EVP_PKEY_CTX_new_from_name(NULL, "mlkem768", NULL); - if (ctx == NULL) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto err; -@@ -68,17 +82,23 @@ mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) - 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) { -+ if (EVP_PKEY_get_raw_public_key(pkey, NULL, &got_pub_size) <= 0 -+ || EVP_PKEY_get_raw_private_key(pkey, NULL, &got_priv_size) <= 0) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto err; - } - -- if (privkey_size != crypto_kem_mlkem768_SECRETKEYBYTES -- || pubkey_size != crypto_kem_mlkem768_PUBLICKEYBYTES) { -+ if (privkey_size != got_priv_size || pubkey_size != got_pub_size) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto err; - } -+ -+ if (EVP_PKEY_get_raw_public_key(pkey, pubkeybuf, &got_pub_size) <= 0 -+ || EVP_PKEY_get_raw_private_key(pkey, privkeybuf, &got_priv_size) <= 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto err; -+ } -+ - ret = 0; - - err: -@@ -90,27 +110,57 @@ mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) - } - - static int --mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) -+mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) -+{ -+ return mlkem_keypair_gen("mlkem768", pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES, -+ privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES); -+} -+ -+static int -+mlkem1024_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) -+{ -+ return mlkem_keypair_gen("mlkem1024", pubkeybuf, crypto_kem_mlkem1024_PUBLICKEYBYTES, -+ privkeybuf, crypto_kem_mlkem1024_SECRETKEYBYTES); -+} -+ -+static int -+mlkem_encap_secret(const char *mlkem_alg, 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; -+ size_t outlen, expected_outlen, publen, secretlen = crypto_kem_mlkem768_BYTES; -+ int fips_fallback = 0; -+ -+ if (strcmp(mlkem_alg, "mlkem768") == 0) { -+ outlen = crypto_kem_mlkem768_CIPHERTEXTBYTES; -+ publen = crypto_kem_mlkem768_PUBLICKEYBYTES; -+ } else if (strcmp(mlkem_alg, "mlkem1024") == 0) { -+ outlen = crypto_kem_mlkem1024_CIPHERTEXTBYTES; -+ publen = crypto_kem_mlkem1024_PUBLICKEYBYTES; -+ } else -+ return r; - -- pkey = EVP_PKEY_new_raw_public_key_ex(NULL, "mlkem768", NULL, -- pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES); -+ expected_outlen = outlen; -+ -+ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, mlkem_alg, NULL, -+ pubkeybuf, publen); -+ if (pkey == NULL && FIPS_mode()) { -+ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, mlkem_alg, FIPS_FALLBACK_PROPQ, -+ pubkeybuf, publen); -+ fips_fallback = 1; -+ } - if (pkey == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto err; - } - -- ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); -+ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, fips_fallback ? FIPS_FALLBACK_PROPQ : NULL); - if (ctx == NULL - || EVP_PKEY_encapsulate_init(ctx, NULL) <= 0 -- || EVP_PKEY_encapsulate(ctx, out, &outlen, secret, &secretlen) <= 0 -+ || EVP_PKEY_encapsulate(ctx, out, &expected_outlen, secret, &secretlen) <= 0 - || secretlen != crypto_kem_mlkem768_BYTES -- || outlen != crypto_kem_mlkem768_CIPHERTEXTBYTES) { -+ || outlen != expected_outlen) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto err; - } -@@ -126,25 +176,45 @@ mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) - } - - static int --mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) -+mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) -+{ -+ return mlkem_encap_secret("mlkem768", pubkeybuf, secret, out); -+} -+ -+static int -+mlkem1024_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) -+{ -+ return mlkem_encap_secret("mlkem1024", pubkeybuf, secret, out); -+} -+ -+static int -+mlkem_decap_secret(const char *algname, -+ const u_char *privkeybuf, size_t privkey_len, -+ const u_char *wrapped, size_t wrapped_len, -+ 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; -+ size_t secretlen = crypto_kem_mlkem768_BYTES; -+ int fips_fallback = 0; - -- pkey = EVP_PKEY_new_raw_private_key_ex(NULL, "mlkem768", NULL, -- privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES); -+ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, algname, -+ NULL, privkeybuf, privkey_len); -+ if (pkey == NULL && FIPS_mode()) { -+ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, algname, -+ FIPS_FALLBACK_PROPQ, privkeybuf, privkey_len); -+ fips_fallback = 1; -+ } - if (pkey == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto err; - } - -- ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); -+ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, fips_fallback ? FIPS_FALLBACK_PROPQ : NULL); - if (ctx == NULL - || EVP_PKEY_decapsulate_init(ctx, NULL) <= 0 -- || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrappedlen) <= 0 -+ || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrapped_len) <= 0 - || secretlen != crypto_kem_mlkem768_BYTES) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto err; -@@ -161,6 +231,20 @@ mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *s - return r; - } - -+static int -+mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) -+{ -+ return mlkem_decap_secret("mlkem768", privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES, -+ wrapped, crypto_kem_mlkem768_CIPHERTEXTBYTES, secret); -+} -+ -+static int -+mlkem1024_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) -+{ -+ return mlkem_decap_secret("mlkem1024", privkeybuf, crypto_kem_mlkem1024_SECRETKEYBYTES, -+ wrapped, crypto_kem_mlkem1024_CIPHERTEXTBYTES, secret); -+} -+ - int - kex_kem_mlkem768x25519_keypair(struct kex *kex) - { -@@ -337,7 +421,7 @@ kex_kem_mlkem768x25519_enc(struct kex *kex, - u_char hash[SSH_DIGEST_MAX_LENGTH]; - size_t need; - int r = SSH_ERR_INTERNAL_ERROR; -- struct libcrux_mlkem768_enc_result enc; /* FIXME */ -+ struct libcrux_mlkem768_enc_result enc; - - *server_blobp = NULL; - *shared_secretp = NULL; -@@ -546,6 +630,519 @@ kex_kem_mlkem768x25519_dec(struct kex *kex, - return r; - #endif - } -+ -+#define NIST_P256_COMPRESSED_LEN 33 -+#define NIST_P256_UNCOMPRESSED_LEN 65 -+#define NIST_P384_COMPRESSED_LEN 49 -+#define NIST_P384_UNCOMPRESSED_LEN 97 -+#define NIST_BUF_MAX_SIZE NIST_P384_UNCOMPRESSED_LEN -+ -+static const char ec256[] = "P-256"; -+static const char ec384[] = "P-384"; -+static const char *len2curve_name(size_t len) -+{ -+ switch (len) { -+ case NIST_P256_COMPRESSED_LEN: -+ case NIST_P256_UNCOMPRESSED_LEN: -+ return ec256; -+ break; -+ case NIST_P384_COMPRESSED_LEN: -+ case NIST_P384_UNCOMPRESSED_LEN: -+ return ec384; -+ break; -+ } -+ return NULL; -+} -+ -+static EVP_PKEY * -+buf2nist_key(const unsigned char *pub_key_buf, size_t pub_key_len) -+{ -+ EVP_PKEY *pkey = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ OSSL_PARAM params[3]; -+ const char *curve_name = len2curve_name(pub_key_len); -+ -+ if (curve_name == NULL) -+ return NULL; -+ -+ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); -+ if (!ctx) -+ goto err; -+ -+ if (EVP_PKEY_fromdata_init(ctx) <= 0) -+ goto err; -+ -+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, curve_name, 0); -+ params[1] = OSSL_PARAM_construct_octet_string( -+ OSSL_PKEY_PARAM_PUB_KEY, (void *)pub_key_buf, pub_key_len); -+ params[2] = OSSL_PARAM_construct_end(); -+ -+ if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) -+ goto err; -+ -+ EVP_PKEY_CTX_free(ctx); -+ return pkey; -+ -+err: -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(pkey); -+ return NULL; -+} -+ -+static int -+kex_nist_shared_key_ext(EVP_PKEY *priv_key, -+ const u_char *pub_key_buf, size_t pub_key_len, struct sshbuf *out) -+{ -+ EVP_PKEY_CTX *ctx = NULL; -+ unsigned char *shared_secret = NULL; -+ size_t shared_secret_len = 0; -+ EVP_PKEY *peer_key = buf2nist_key(pub_key_buf, pub_key_len); -+ int r = SSH_ERR_INTERNAL_ERROR; -+ -+ if (peer_key == NULL) -+ return SSH_ERR_KEY_LENGTH; -+ -+ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, priv_key, NULL); -+ if (!ctx) -+ goto end; -+ -+ if ((EVP_PKEY_derive_init(ctx) <= 0) -+ || EVP_PKEY_derive_set_peer(ctx, peer_key) <= 0 -+ || EVP_PKEY_derive(ctx, NULL, &shared_secret_len) <= 0) -+ goto end; -+ -+ shared_secret = OPENSSL_malloc(shared_secret_len); -+ if (shared_secret == NULL) -+ goto end; -+ -+ if (EVP_PKEY_derive(ctx, shared_secret, &shared_secret_len) <= 0) -+ goto end; -+ -+ if ((r = sshbuf_put(out, shared_secret, shared_secret_len)) != 0) -+ goto end; -+ -+ r = 0; -+ -+end: -+ EVP_PKEY_free(peer_key); -+ if (shared_secret) -+ OPENSSL_clear_free(shared_secret, shared_secret_len); -+ EVP_PKEY_CTX_free(ctx); -+ -+ return r; -+} -+ -+static EVP_PKEY * -+nist_pkey_keygen(size_t pub_key_len) -+{ -+ const char *curve_name = len2curve_name(pub_key_len); -+ EVP_PKEY_CTX *pctx = NULL; -+ EVP_PKEY *pkey = NULL; -+ OSSL_PARAM params[2]; -+ -+ if (curve_name == NULL) -+ return NULL; -+ -+ pctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL); -+ if (!pctx) -+ return NULL; -+ -+ if (EVP_PKEY_keygen_init(pctx) <= 0) { -+ EVP_PKEY_CTX_free(pctx); -+ return NULL; -+ } -+ -+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, curve_name, 0); -+ params[1] = OSSL_PARAM_construct_end(); -+ -+ if (EVP_PKEY_CTX_set_params(pctx, params) <= 0 -+ || EVP_PKEY_keygen(pctx, &pkey) <= 0) { -+ EVP_PKEY_CTX_free(pctx); -+ return NULL; -+ } -+ -+ EVP_PKEY_CTX_free(pctx); -+ return pkey; -+} -+ -+static size_t decompress_pub_key(void *pub, size_t compressed_len, size_t decompressed_len) -+{ -+ EC_GROUP *group = NULL; -+ EC_POINT *point = NULL; -+ BN_CTX *ctx = NULL; -+ size_t len = 0; -+ int group_nid = NID_undef; -+ -+ switch (compressed_len) { -+ case NIST_P256_COMPRESSED_LEN: -+ group_nid = NID_X9_62_prime256v1; -+ break; -+ case NIST_P384_COMPRESSED_LEN: -+ group_nid = NID_secp384r1; -+ break; -+ default: -+ return 0; -+ break; -+ } -+ -+ ctx = BN_CTX_new(); -+ group = EC_GROUP_new_by_curve_name(group_nid); -+ if (ctx == NULL || group == NULL) -+ goto err; -+ -+ point = EC_POINT_new(group); -+ if (point == NULL) -+ goto err; -+ -+ if (!EC_POINT_oct2point(group, point, pub, compressed_len, ctx)) -+ goto err; -+ -+ len = EC_POINT_point2oct(group, point, POINT_CONVERSION_UNCOMPRESSED, pub, decompressed_len, ctx); -+ -+err: -+ EC_POINT_free(point); -+ EC_GROUP_free(group); -+ BN_CTX_free(ctx); -+ -+ return len; -+} -+ -+static int -+get_uncompressed_ec_pubkey(EVP_PKEY *pkey, unsigned char *buf, size_t buf_len) -+{ -+ OSSL_PARAM params[2]; -+ size_t required_len = 0, out_len = 0; -+ -+ params[0] = OSSL_PARAM_construct_utf8_string( -+ OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, -+ "uncompressed", 0); -+ params[1] = OSSL_PARAM_construct_end(); -+ -+ if (EVP_PKEY_set_params(pkey, params) <= 0 -+ || EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, -+ buf, buf_len, &required_len) <= 0) { -+ return SSH_ERR_LIBCRYPTO_ERROR; -+ } -+ -+ if (required_len != buf_len) { -+ /* Red Hat certified FIPS provider ignores OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT -+ * We may have to perform the conversion manually */ -+ if (len2curve_name(required_len) == len2curve_name(buf_len)) { -+ out_len = decompress_pub_key(buf, required_len, buf_len); -+ if (out_len != buf_len) { -+ debug_f("Error decompressing the compressed public key"); -+ return SSH_ERR_LIBCRYPTO_ERROR; -+ } else { -+ return 0; -+ } -+ } else { -+ debug_f("Unexpected length of uncompressed public key: expected %d, got %d", buf_len, required_len); -+ return SSH_ERR_LIBCRYPTO_ERROR; -+ } -+ } -+ -+ return 0; -+} -+/* nist_bytes_len should always be uncompressed */ -+static int -+kex_kem_mlkem_nist_keypair(struct kex *kex, size_t mlkem_bytes_len, size_t nist_bytes_len) -+{ -+ struct sshbuf *buf = NULL; -+ u_char *cp = NULL; -+ size_t need; -+ int r = SSH_ERR_INTERNAL_ERROR; -+ u_char *client_key = NULL; -+ -+ if ((buf = sshbuf_new()) == NULL) -+ return SSH_ERR_ALLOC_FAIL; -+ need = mlkem_bytes_len + nist_bytes_len; -+ if ((r = sshbuf_reserve(buf, need, &cp)) != 0) -+ goto out; -+ -+ if (mlkem_bytes_len == crypto_kem_mlkem768_PUBLICKEYBYTES) { -+ client_key = kex->mlkem768_client_key; -+ r = mlkem768_keypair_gen(cp, client_key); -+ } -+ -+ if (mlkem_bytes_len == crypto_kem_mlkem1024_PUBLICKEYBYTES) { -+ client_key = kex->mlkem1024_client_key; -+ r = mlkem1024_keypair_gen(cp, client_key); -+ } -+ -+ if (client_key == NULL) -+ goto out; -+ -+ if (r != 0) -+ goto out; -+#ifdef DEBUG_KEXECDH -+ dump_digest("client public key mlkemXXX:", cp, mlkem_bytes_len); -+#endif -+ cp += mlkem_bytes_len; -+ if ((kex->ec_hybrid_client_key = nist_pkey_keygen(nist_bytes_len)) == NULL) -+ goto out; -+ -+ if ((r = get_uncompressed_ec_pubkey(kex->ec_hybrid_client_key, cp, nist_bytes_len)) != 0) -+ goto out; -+ -+#ifdef DEBUG_KEXECDH -+ dump_digest("client public key NIST:", cp, nist_bytes_len); -+#endif -+ /* success */ -+ r = 0; -+ kex->client_pub = buf; -+ buf = NULL; -+ out: -+ sshbuf_free(buf); -+ if (r == SSH_ERR_LIBCRYPTO_ERROR) -+ ERR_print_errors_fp(stderr); -+ -+ return r; -+} -+ -+static int -+kex_kem_mlkem_nist_enc(struct kex *kex, const char *nist_curve, -+ const struct sshbuf *client_blob, struct sshbuf **server_blobp, -+ struct sshbuf **shared_secretp) -+{ -+ struct sshbuf *server_blob = NULL; -+ struct sshbuf *buf = NULL; -+ const u_char *client_pub; -+ u_char server_pub[NIST_BUF_MAX_SIZE]; -+ u_char enc_out[crypto_kem_mlkem1024_CIPHERTEXTBYTES]; -+ u_char secret[crypto_kem_mlkem768_BYTES]; -+ EVP_PKEY *server_key = NULL; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t client_buf_len, mlkem_buf_len, ecdh_buf_len, server_key_len, enc_out_len; -+ int r = SSH_ERR_INTERNAL_ERROR; -+ -+ *server_blobp = NULL; -+ *shared_secretp = NULL; -+ -+ client_buf_len = sshbuf_len(client_blob); -+ /* client_blob contains both KEM and ECDH client pubkeys */ -+ if (strcmp(nist_curve, "P-256") == 0) { -+ if (crypto_kem_mlkem768_PUBLICKEYBYTES > client_buf_len) -+ return r; -+ -+ ecdh_buf_len = client_buf_len - crypto_kem_mlkem768_PUBLICKEYBYTES; -+ if (ecdh_buf_len != NIST_P256_COMPRESSED_LEN && -+ ecdh_buf_len != NIST_P256_UNCOMPRESSED_LEN) -+ return r; -+ mlkem_buf_len = crypto_kem_mlkem768_PUBLICKEYBYTES; -+ enc_out_len = crypto_kem_mlkem768_CIPHERTEXTBYTES; -+ server_key_len = NIST_P256_UNCOMPRESSED_LEN; -+ } else if (strcmp(nist_curve, "P-384") == 0) { -+ if (crypto_kem_mlkem1024_PUBLICKEYBYTES > client_buf_len) -+ return r; -+ -+ ecdh_buf_len = client_buf_len - crypto_kem_mlkem1024_PUBLICKEYBYTES; -+ if (ecdh_buf_len != NIST_P384_COMPRESSED_LEN && -+ ecdh_buf_len != NIST_P384_UNCOMPRESSED_LEN) -+ return r; -+ mlkem_buf_len = crypto_kem_mlkem1024_PUBLICKEYBYTES; -+ enc_out_len = crypto_kem_mlkem1024_CIPHERTEXTBYTES; -+ server_key_len = NIST_P384_UNCOMPRESSED_LEN; -+ } else -+ return r; -+ -+ client_pub = sshbuf_ptr(client_blob); -+#ifdef DEBUG_KEXECDH -+ dump_digest("client public key mlkem:", client_pub, mlkem_buf_len); -+ dump_digest("client public key NIST:", client_pub + mlkem_buf_len, ecdh_buf_len); -+#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; -+ } -+ r = (mlkem_buf_len == crypto_kem_mlkem768_PUBLICKEYBYTES) ? -+ mlkem768_encap_secret(client_pub, secret, enc_out) : -+ mlkem1024_encap_secret(client_pub, secret, enc_out); -+ -+ if (r != 0) -+ goto out; -+ -+ /* generate ECDH key pair, store server pubkey after ciphertext */ -+ server_key = nist_pkey_keygen(server_key_len); -+ -+ if ((r = get_uncompressed_ec_pubkey(server_key, server_pub, server_key_len) != 0) || -+ (r = sshbuf_put(buf, secret, sizeof(secret))) != 0 || -+ (r = sshbuf_put(server_blob, enc_out, enc_out_len) != 0)|| -+ (r = sshbuf_put(server_blob, server_pub, server_key_len)) != 0) -+ goto out; -+ -+ /* append ECDH shared key */ -+ client_pub += mlkem_buf_len; -+ if ((r = kex_nist_shared_key_ext(server_key, client_pub, ecdh_buf_len, buf)) < 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 NIST:", server_pub, server_key_len); -+ dump_digest("server cipher text:", enc_out, enc_out_len); -+ dump_digest("server kem key:", secret, sizeof(secret)); -+ 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)); -+ EVP_PKEY_free(server_key); -+ explicit_bzero(enc_out, sizeof(enc_out)); -+ explicit_bzero(secret, sizeof(secret)); -+ sshbuf_free(server_blob); -+ sshbuf_free(buf); -+ return r; -+} -+ -+static int -+kex_kem_mlkem_nist_dec(struct kex *kex, -+ const struct sshbuf *server_blob, struct sshbuf **shared_secretp, -+ size_t mlkem_len) -+{ -+ struct sshbuf *buf = NULL; -+ const u_char *ciphertext, *server_pub; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ u_char decap[crypto_kem_mlkem768_BYTES]; -+ int r; -+ size_t nist_len; -+ -+ *shared_secretp = NULL; -+ -+ if (sshbuf_len(server_blob) < mlkem_len) { -+ r = SSH_ERR_SIGNATURE_INVALID; -+ goto out; -+ } -+ -+ nist_len = sshbuf_len(server_blob) - mlkem_len; -+ -+ switch (mlkem_len) { -+ case crypto_kem_mlkem768_CIPHERTEXTBYTES: -+ if (nist_len != NIST_P256_COMPRESSED_LEN -+ && nist_len != NIST_P256_UNCOMPRESSED_LEN) { -+ r = SSH_ERR_SIGNATURE_INVALID; -+ goto out; -+ } -+ break; -+ case crypto_kem_mlkem1024_CIPHERTEXTBYTES: -+ if (nist_len != NIST_P384_COMPRESSED_LEN -+ && nist_len != NIST_P384_UNCOMPRESSED_LEN) { -+ r = SSH_ERR_SIGNATURE_INVALID; -+ goto out; -+ } -+ break; -+ } -+ -+ ciphertext = sshbuf_ptr(server_blob); -+ server_pub = ciphertext + mlkem_len; -+ /* 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, mlkem_len); -+ dump_digest("server public key NIST:", server_pub, nist_len); -+#endif -+ r = (mlkem_len == crypto_kem_mlkem768_CIPHERTEXTBYTES) ? -+ mlkem768_decap_secret(kex->mlkem768_client_key, ciphertext, decap) : -+ mlkem1024_decap_secret(kex->mlkem1024_client_key, ciphertext, decap); -+ -+ if (r != 0) -+ goto out; -+ if ((r = sshbuf_put(buf, decap, sizeof(decap))) != 0) -+ goto out; -+ if ((r = kex_nist_shared_key_ext(kex->ec_hybrid_client_key, server_pub, -+ nist_len, buf)) < 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; -+} -+ -+int -+kex_kem_mlkem768nistp256_keypair(struct kex *kex) -+{ -+ return kex_kem_mlkem_nist_keypair(kex, crypto_kem_mlkem768_PUBLICKEYBYTES, NIST_P256_UNCOMPRESSED_LEN); -+} -+ -+int -+kex_kem_mlkem768nistp256_enc(struct kex *kex, const struct sshbuf *client_blob, -+ struct sshbuf **server_blobp, struct sshbuf **shared_secretp) -+{ -+ return kex_kem_mlkem_nist_enc(kex, "P-256", client_blob, server_blobp, shared_secretp); -+} -+ -+int -+kex_kem_mlkem768nistp256_dec(struct kex *kex, const struct sshbuf *server_blob, -+ struct sshbuf **shared_secretp) -+{ -+ return kex_kem_mlkem_nist_dec(kex, server_blob, shared_secretp, -+ crypto_kem_mlkem768_CIPHERTEXTBYTES); -+} -+ -+int -+kex_kem_mlkem1024nistp384_keypair(struct kex *kex) -+{ -+ return kex_kem_mlkem_nist_keypair(kex, crypto_kem_mlkem1024_PUBLICKEYBYTES, NIST_P384_UNCOMPRESSED_LEN); -+} -+ -+int -+kex_kem_mlkem1024nistp384_enc(struct kex *kex, const struct sshbuf *client_blob, -+ struct sshbuf **server_blobp, struct sshbuf **shared_secretp) -+{ -+ return kex_kem_mlkem_nist_enc(kex, "P-384", client_blob, server_blobp, shared_secretp); -+} -+ -+int -+kex_kem_mlkem1024nistp384_dec(struct kex *kex, const struct sshbuf *server_blob, -+ struct sshbuf **shared_secretp) -+{ -+ return kex_kem_mlkem_nist_dec(kex, server_blob, shared_secretp, -+ crypto_kem_mlkem1024_CIPHERTEXTBYTES); -+} -+ - #else /* USE_MLKEM768X25519 */ - int - kex_kem_mlkem768x25519_keypair(struct kex *kex) -@@ -567,4 +1164,39 @@ kex_kem_mlkem768x25519_dec(struct kex *kex, - { - return SSH_ERR_SIGN_ALG_UNSUPPORTED; - } -+ -+int kex_kem_mlkem768nistp256_keypair(struct kex *) -+{ -+ return SSH_ERR_SIGN_ALG_UNSUPPORTED; -+} -+ -+int kex_kem_mlkem768nistp256_enc(struct kex *, const struct sshbuf *, -+ struct sshbuf **, struct sshbuf **) -+{ -+ return SSH_ERR_SIGN_ALG_UNSUPPORTED; -+} -+ -+int kex_kem_mlkem768nistp256_dec(struct kex *, const struct sshbuf *, -+ struct sshbuf **) -+{ -+ return SSH_ERR_SIGN_ALG_UNSUPPORTED; -+} -+ -+int kex_kem_mlkem1024nistp384_keypair(struct kex *) -+{ -+ return SSH_ERR_SIGN_ALG_UNSUPPORTED; -+} -+ -+int kex_kem_mlkem1024nistp384_enc(struct kex *, const struct sshbuf *, -+ struct sshbuf **, struct sshbuf **) -+{ -+ return SSH_ERR_SIGN_ALG_UNSUPPORTED; -+} -+ -+int kex_kem_mlkem1024nistp384_dec(struct kex *, const struct sshbuf *, -+ struct sshbuf **) -+{ -+ return SSH_ERR_SIGN_ALG_UNSUPPORTED; -+} -+ - #endif /* USE_MLKEM768X25519 */ -diff --git a/monitor.c b/monitor.c -index 6c83739ee..2f154a3d7 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -2014,6 +2014,8 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) - 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; -+ kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server; -+ kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server; - kex->load_host_public_key=&get_hostkey_public_by_type; - kex->load_host_private_key=&get_hostkey_private_by_type; - kex->host_key_index=&get_hostkey_index; -diff --git a/myproposal.h b/myproposal.h -index 3e0ec6826..007347fc3 100644 ---- a/myproposal.h -+++ b/myproposal.h -@@ -26,6 +26,8 @@ - - #define KEX_SERVER_KEX \ - "mlkem768x25519-sha256," \ -+ "mlkem768nistp256-sha256," \ -+ "mlkem1024nistp384-sha384," \ - "sntrup761x25519-sha512," \ - "sntrup761x25519-sha512@openssh.com," \ - "curve25519-sha256," \ -@@ -97,6 +99,8 @@ - "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \ - "aes128-gcm@openssh.com,aes256-gcm@openssh.com" - #define KEX_DEFAULT_KEX_FIPS \ -+ "mlkem768nistp256-sha256," \ -+ "mlkem1024nistp384-sha384," \ - "ecdh-sha2-nistp256," \ - "ecdh-sha2-nistp384," \ - "ecdh-sha2-nistp521," \ -diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c -index f4700deeb..99a8e3b46 100644 ---- a/regress/unittests/kex/test_kex.c -+++ b/regress/unittests/kex/test_kex.c -@@ -171,6 +171,8 @@ do_kex_with_key(char *kex, char *cipher, char *mac, - server2->kex->kex[KEX_C25519_SHA256] = kex_gen_server; - server2->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; - server2->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; -+ server2->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server; -+ server2->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server; - server2->kex->load_host_public_key = server->kex->load_host_public_key; - server2->kex->load_host_private_key = server->kex->load_host_private_key; - server2->kex->sign = server->kex->sign; -@@ -248,6 +250,8 @@ kex_tests(void) - } - # ifdef USE_MLKEM768X25519 - do_kex("mlkem768x25519-sha256"); -+ do_kex("mlkem768nistp256-sha256"); -+ do_kex("mlkem1024nistp384-sha384"); - # endif /* USE_MLKEM768X25519 */ - # ifdef USE_SNTRUP761X25519 - do_kex("sntrup761x25519-sha512"); -diff --git a/ssh-keyscan.c b/ssh-keyscan.c -index 11618ae8a..2f4037972 100644 ---- a/ssh-keyscan.c -+++ b/ssh-keyscan.c -@@ -290,6 +290,8 @@ keygrab_ssh2(con *c) - c->c_ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; - c->c_ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; - c->c_ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client; -+ c->c_ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client; -+ c->c_ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client; - ssh_set_verify_host_key_callback(c->c_ssh, key_print_wrapper); - /* - * do the key-exchange until an error occurs or until -diff --git a/ssh_api.c b/ssh_api.c -index 7bdcee148..d20b03a00 100644 ---- a/ssh_api.c -+++ b/ssh_api.c -@@ -135,6 +135,8 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) - ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_server; - ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; - ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; -+ ssh->kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server; -+ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server; - ssh->kex->load_host_public_key=&_ssh_host_public_key; - ssh->kex->load_host_private_key=&_ssh_host_private_key; - ssh->kex->sign=&_ssh_host_key_sign; -@@ -154,6 +156,8 @@ ssh_init(struct ssh **sshp, int is_server, struct kex_params *kex_params) - ssh->kex->kex[KEX_C25519_SHA256] = 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->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client; -+ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client; - ssh->kex->verify_host_key =&_ssh_verify_host_key; - } - *sshp = ssh; -diff --git a/sshconnect2.c b/sshconnect2.c -index 2d98fc3da..88e27955a 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -347,6 +347,8 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, - ssh->kex->kex[KEX_C25519_SHA256] = 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->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_client; -+ ssh->kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_client; - ssh->kex->verify_host_key=&verify_host_key_callback; - - #if defined(GSSAPI) && defined(WITH_OPENSSL) -diff --git a/sshd-auth.c b/sshd-auth.c -index f3c38a7d1..698ef83f3 100644 ---- a/sshd-auth.c -+++ b/sshd-auth.c -@@ -893,6 +893,8 @@ do_ssh2_kex(struct ssh *ssh) - 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; -+ kex->kex[KEX_KEM_MLKEM768NISTP256_SHA256] = kex_gen_server; -+ kex->kex[KEX_KEM_MLKEM1024NISTP384_SHA384] = kex_gen_server; - kex->load_host_public_key=&get_hostkey_public_by_type; - kex->load_host_private_key=&get_hostkey_private_by_type; - kex->host_key_index=&get_hostkey_index; --- -2.52.0 - diff --git a/0050-Provide-a-way-to-disable-GSSAPIDelegateCredentials-s.patch b/0050-Provide-a-way-to-disable-GSSAPIDelegateCredentials-s.patch deleted file mode 100644 index 85c4140..0000000 --- a/0050-Provide-a-way-to-disable-GSSAPIDelegateCredentials-s.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 71190d3d862113d97708a42b4a7daa7aa3c4e0ec Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Fri, 5 Dec 2025 14:55:38 +0100 -Subject: [PATCH 50/53] Provide a way to disable GSSAPIDelegateCredentials - server-side - ---- - gss-serv.c | 5 +++++ - servconf.c | 13 ++++++++++++- - servconf.h | 1 + - sshd_config.0 | 3 +++ - sshd_config.5 | 3 +++ - 5 files changed, 24 insertions(+), 1 deletion(-) - -diff --git a/gss-serv.c b/gss-serv.c -index be80e17ca..165484db0 100644 ---- a/gss-serv.c -+++ b/gss-serv.c -@@ -509,6 +509,11 @@ ssh_gssapi_cleanup_creds(void) - int - ssh_gssapi_storecreds(void) - { -+ if (options.gss_deleg_creds == 0) { -+ debug_f("delegate credential is disabled, doing nothing"); -+ return 0; -+ } -+ - if (gssapi_client.mech && gssapi_client.mech->storecreds) { - return (*gssapi_client.mech->storecreds)(&gssapi_client); - } else -diff --git a/servconf.c b/servconf.c -index e53e8ea30..fb1d150cd 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -143,6 +143,7 @@ initialize_server_options(ServerOptions *options) - options->gss_authentication=-1; - options->gss_keyex = -1; - options->gss_cleanup_creds = -1; -+ options->gss_deleg_creds = -1; - options->gss_strict_acceptor = -1; - options->gss_store_rekey = -1; - options->gss_kex_algorithms = NULL; -@@ -396,6 +397,8 @@ fill_default_server_options(ServerOptions *options) - options->gss_keyex = 0; - if (options->gss_cleanup_creds == -1) - options->gss_cleanup_creds = 1; -+ if (options->gss_deleg_creds == -1) -+ options->gss_deleg_creds = 1; - if (options->gss_strict_acceptor == -1) - options->gss_strict_acceptor = 1; - if (options->gss_store_rekey == -1) -@@ -591,7 +594,8 @@ typedef enum { - sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, - sPerSourcePenalties, sPerSourcePenaltyExemptList, - sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, -- sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, -+ sGssAuthentication, sGssCleanupCreds, sGssDelegateCreds, -+ sGssEnablek5users, sGssStrictAcceptor, - sGssKeyEx, sGssIndicators, sGssKexAlgorithms, sGssStoreRekey, - sAcceptEnv, sSetEnv, sPermitTunnel, - sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, -@@ -683,6 +687,7 @@ static struct { - { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, - { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, - { "gssapicleanupcreds", sGssCleanupCreds, SSHCFG_GLOBAL }, -+ { "gssapidelegatecredentials", sGssDelegateCreds, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, - { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, - { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, -@@ -693,6 +698,7 @@ static struct { - { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, - { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, -+ { "gssapidelegatecredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, - { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, -@@ -1705,6 +1711,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, - intptr = &options->gss_cleanup_creds; - goto parse_flag; - -+ case sGssDelegateCreds: -+ intptr = &options->gss_deleg_creds; -+ goto parse_flag; -+ - case sGssStrictAcceptor: - intptr = &options->gss_strict_acceptor; - goto parse_flag; -@@ -3352,6 +3362,7 @@ dump_config(ServerOptions *o) - #ifdef GSSAPI - dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); - dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); -+ dump_cfg_fmtint(sGssDelegateCreds, o->gss_deleg_creds); - dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); - dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); - dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); -diff --git a/servconf.h b/servconf.h -index c7cec5ece..9b1a73b8d 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -156,6 +156,7 @@ typedef struct { - int gss_authentication; /* If true, permit GSSAPI authentication */ - int gss_keyex; /* If true, permit GSSAPI key exchange */ - int gss_cleanup_creds; /* If true, destroy cred cache on logout */ -+ int gss_deleg_creds; /* If true, accept delegated GSS credentials */ - int gss_strict_acceptor; /* If true, restrict the GSSAPI acceptor name */ - int gss_store_rekey; - char *gss_kex_algorithms; /* GSSAPI kex methods to be offered by client. */ -diff --git a/sshd_config.0 b/sshd_config.0 -index 8c5217c0b..cda9c9182 100644 ---- a/sshd_config.0 -+++ b/sshd_config.0 -@@ -453,6 +453,9 @@ DESCRIPTION - Specifies whether to automatically destroy the user's credentials - cache on logout. The default is yes. - -+ GSSAPIDelegateCredentials -+ Accept delegated credentials on the server side. The default is yes. -+ - GSSAPIStrictAcceptorCheck - Determines whether to be strict about the identity of the GSSAPI - acceptor a client authenticates against. If set to yes then the -diff --git a/sshd_config.5 b/sshd_config.5 -index 676d6d4d2..4ae4bebee 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -733,6 +733,9 @@ Specifies whether to automatically destroy the user's credentials cache - on logout. - The default is - .Cm yes . -+.It Cm GSSAPIDelegateCredentials -+Accept delegated credentials on the server side. The default is -+.CM yes . - .It Cm GSSAPIEnablek5users - Specifies whether to look at .k5users file for GSSAPI authentication - access control. Further details are described in --- -2.52.0 - diff --git a/1000-openssh-6.7p1-coverity.patch b/1000-openssh-6.7p1-coverity.patch deleted file mode 100644 index 40c298e..0000000 --- a/1000-openssh-6.7p1-coverity.patch +++ /dev/null @@ -1,229 +0,0 @@ -From aecc5861e1cf7094a32f893ae4bfd8409b77e5cd Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Fri, 12 Dec 2025 14:25:41 +0100 -Subject: [PATCH 53/53] openssh-6.7p1-coverity - ---- - auth-krb5.c | 2 ++ - gss-genr.c | 3 ++- - krl.c | 3 +++ - loginrec.c | 2 ++ - misc.c | 3 +++ - monitor.c | 4 ++-- - openbsd-compat/bindresvport.c | 2 +- - openbsd-compat/bsd-pselect.c | 8 ++++---- - readconf.c | 1 + - servconf.c | 5 +++-- - serverloop.c | 2 +- - 11 files changed, 24 insertions(+), 11 deletions(-) - -diff --git a/auth-krb5.c b/auth-krb5.c -index b9c261a24..a37be93c3 100644 ---- a/auth-krb5.c -+++ b/auth-krb5.c -@@ -427,6 +427,7 @@ ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environm - umask(old_umask); - if (tmpfd == -1) { - logit("mkstemp(): %.100s", strerror(oerrno)); -+ free(ccname); - return oerrno; - } - -@@ -434,6 +435,7 @@ ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environm - oerrno = errno; - logit("fchmod(): %.100s", strerror(oerrno)); - close(tmpfd); -+ free(ccname); - return oerrno; - } - /* make sure the KRB5CCNAME is set for non-standard location */ -diff --git a/gss-genr.c b/gss-genr.c -index f2d6f59e5..91602e045 100644 ---- a/gss-genr.c -+++ b/gss-genr.c -@@ -178,8 +178,9 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_supported, ssh_gssapi_check_fn *check, - enclen = __b64_ntop(digest, - ssh_digest_bytes(SSH_DIGEST_MD5), encoded, - ssh_digest_bytes(SSH_DIGEST_MD5) * 2); -- -+#pragma GCC diagnostic ignored "-Wstringop-overflow" - cp = strncpy(s, kex, strlen(kex)); -+#pragma GCC diagnostic pop - for ((p = strsep(&cp, ",")); p && *p != '\0'; - (p = strsep(&cp, ","))) { - if (sshbuf_len(buf) != 0 && -diff --git a/krl.c b/krl.c -index bea5b1b98..4dd8a24a9 100644 ---- a/krl.c -+++ b/krl.c -@@ -1205,6 +1205,7 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) - return r; - erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); - free(rb.blob); -+ rb.blob = NULL; /* make coverity happy */ - if (erb != NULL) { - KRL_DBG(("revoked by key SHA1")); - return SSH_ERR_KEY_REVOKED; -@@ -1215,6 +1216,7 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) - return r; - erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb); - free(rb.blob); -+ rb.blob = NULL; /* make coverity happy */ - if (erb != NULL) { - KRL_DBG(("revoked by key SHA256")); - return SSH_ERR_KEY_REVOKED; -@@ -1226,6 +1228,7 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key) - return r; - erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); - free(rb.blob); -+ rb.blob = NULL; /* make coverity happy */ - if (erb != NULL) { - KRL_DBG(("revoked by explicit key")); - return SSH_ERR_KEY_REVOKED; -diff --git a/loginrec.c b/loginrec.c -index 7d1c9dd43..a017e173b 100644 ---- a/loginrec.c -+++ b/loginrec.c -@@ -677,9 +677,11 @@ construct_utmp(struct logininfo *li, - */ - - /* Use strncpy because we don't necessarily want null termination */ -+ /* coverity[buffer_size_warning : FALSE] */ - strncpy(ut->ut_name, li->username, - MIN_SIZEOF(ut->ut_name, li->username)); - # ifdef HAVE_HOST_IN_UTMP -+ /* coverity[buffer_size_warning : FALSE] */ - strncpy(ut->ut_host, li->hostname, - MIN_SIZEOF(ut->ut_host, li->hostname)); - # endif -diff --git a/misc.c b/misc.c -index 2fd14159d..d4c4e4164 100644 ---- a/misc.c -+++ b/misc.c -@@ -1573,6 +1573,8 @@ sanitise_stdfd(void) - } - if (nullfd > STDERR_FILENO) - close(nullfd); -+ /* coverity[leaked_handle : FALSE]*/ -+ /* coverity[leaked_handle : FALSE]*/ - } - - char * -@@ -2773,6 +2775,7 @@ stdfd_devnull(int do_stdin, int do_stdout, int do_stderr) - } - if (devnull > STDERR_FILENO) - close(devnull); -+ /* coverity[leaked_handle : FALSE]*/ - return ret; - } - -diff --git a/monitor.c b/monitor.c -index 2f154a3d7..f959e0124 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -405,7 +405,7 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) - mm_get_keystate(ssh, pmonitor); - - /* Drain any buffered messages from the child */ -- while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0) -+ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) - ; - - /* Wait for the child's exit status */ -@@ -1819,7 +1819,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m) - s->ptymaster = s->ptyfd; - - debug3_f("tty %s ptyfd %d", s->tty, s->ttyfd); -- -+ /* coverity[leaked_handle : FALSE] */ - return (0); - - error: -diff --git a/openbsd-compat/bindresvport.c b/openbsd-compat/bindresvport.c -index 346c7fe56..f42792fde 100644 ---- a/openbsd-compat/bindresvport.c -+++ b/openbsd-compat/bindresvport.c -@@ -59,7 +59,7 @@ bindresvport_sa(int sd, struct sockaddr *sa) - struct sockaddr_in6 *in6; - u_int16_t *portp; - u_int16_t port; -- socklen_t salen; -+ socklen_t salen = sizeof(struct sockaddr_storage); - int i; - - if (sa == NULL) { -diff --git a/openbsd-compat/bsd-pselect.c b/openbsd-compat/bsd-pselect.c -index 26bdc3e08..8e2939b95 100644 ---- a/openbsd-compat/bsd-pselect.c -+++ b/openbsd-compat/bsd-pselect.c -@@ -85,13 +85,13 @@ pselect_notify_setup(void) - static void - pselect_notify_parent(void) - { -- if (notify_pipe[1] != -1) -+ if (notify_pipe[1] >= 0) - (void)write(notify_pipe[1], "", 1); - } - static void - pselect_notify_prepare(fd_set *readset) - { -- if (notify_pipe[0] != -1) -+ if (notify_pipe[0] >= 0) - FD_SET(notify_pipe[0], readset); - } - static void -@@ -99,8 +99,8 @@ pselect_notify_done(fd_set *readset) - { - char c; - -- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) { -- while (read(notify_pipe[0], &c, 1) != -1) -+ if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) { -+ while (read(notify_pipe[0], &c, 1) >= 0) - debug2_f("reading"); - FD_CLR(notify_pipe[0], readset); - } -diff --git a/readconf.c b/readconf.c -index b6ad47b49..75e1c953c 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -2170,6 +2170,7 @@ parse_pubkey_algos: - } else if (r != 0) { - error("%.200s line %d: glob failed for %s.", - filename, linenum, arg2); -+ free(arg2); - goto out; - } - free(arg2); -diff --git a/servconf.c b/servconf.c -index 956205f6d..1093dcbac 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -2307,8 +2307,9 @@ process_server_config_line_depth(ServerOptions *options, char *line, - if (*activep && *charptr == NULL) { - *charptr = tilde_expand_filename(arg, getuid()); - /* increase optional counter */ -- if (intptr != NULL) -- *intptr = *intptr + 1; -+ /* DEAD CODE intptr is still NULL ;) -+ if (intptr != NULL) -+ *intptr = *intptr + 1; */ - } - break; - -diff --git a/serverloop.c b/serverloop.c -index 55411a6b4..acc721cd1 100644 ---- a/serverloop.c -+++ b/serverloop.c -@@ -533,7 +533,7 @@ server_request_tun(struct ssh *ssh) - debug_f("invalid tun"); - goto done; - } -- if (auth_opts->force_tun_device != -1) { -+ if (auth_opts->force_tun_device >= 0) { - if (tun != SSH_TUNID_ANY && - auth_opts->force_tun_device != (int)tun) - goto done; --- -2.52.0 - diff --git a/0008-openssh-4.3p2-askpass-grab-info.patch b/openssh-4.3p2-askpass-grab-info.patch similarity index 53% rename from 0008-openssh-4.3p2-askpass-grab-info.patch rename to openssh-4.3p2-askpass-grab-info.patch index 8108482..120ed1b 100644 --- a/0008-openssh-4.3p2-askpass-grab-info.patch +++ b/openssh-4.3p2-askpass-grab-info.patch @@ -1,17 +1,7 @@ -From d124ab0f6eea910dc5f03cdd808f6fa792bf2b7a Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 08/53] openssh-4.3p2-askpass-grab-info - ---- - contrib/gnome-ssh-askpass2.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass2.c -index cb7152dc8..bbe93d838 100644 ---- a/contrib/gnome-ssh-askpass2.c -+++ b/contrib/gnome-ssh-askpass2.c -@@ -70,8 +70,12 @@ report_failed_grab (GtkWidget *parent_window, const char *what) +diff -up openssh-8.6p1/contrib/gnome-ssh-askpass2.c.grab-info openssh-8.6p1/contrib/gnome-ssh-askpass2.c +--- openssh-8.6p1/contrib/gnome-ssh-askpass2.c.grab-info 2021-04-19 13:57:11.720113536 +0200 ++++ openssh-8.6p1/contrib/gnome-ssh-askpass2.c 2021-04-19 13:59:29.842163204 +0200 +@@ -70,8 +70,12 @@ report_failed_grab (GtkWidget *parent_wi err = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, @@ -26,6 +16,3 @@ index cb7152dc8..bbe93d838 100644 gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER); gtk_dialog_run(GTK_DIALOG(err)); --- -2.52.0 - diff --git a/0007-openssh-5.1p1-askpass-progress.patch b/openssh-5.1p1-askpass-progress.patch similarity index 66% rename from 0007-openssh-5.1p1-askpass-progress.patch rename to openssh-5.1p1-askpass-progress.patch index 66b351e..ff609da 100644 --- a/0007-openssh-5.1p1-askpass-progress.patch +++ b/openssh-5.1p1-askpass-progress.patch @@ -1,17 +1,7 @@ -From c62cd7ce2539c1eac6d0133c07441c617cbc7bc3 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 07/53] openssh-5.1p1-askpass-progress - ---- - contrib/gnome-ssh-askpass2.c | 39 +++++++++++++++++++++++++++++++++--- - 1 file changed, 36 insertions(+), 3 deletions(-) - -diff --git a/contrib/gnome-ssh-askpass2.c b/contrib/gnome-ssh-askpass2.c -index a62f98152..cb7152dc8 100644 ---- a/contrib/gnome-ssh-askpass2.c -+++ b/contrib/gnome-ssh-askpass2.c -@@ -58,6 +58,7 @@ +diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contrib/gnome-ssh-askpass2.c +--- openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/contrib/gnome-ssh-askpass2.c 2016-12-23 13:31:16.545211926 +0100 +@@ -53,6 +53,7 @@ #include #include @@ -19,7 +9,7 @@ index a62f98152..cb7152dc8 100644 #include #include #include -@@ -146,6 +147,17 @@ parse_env_hex_color(const char *env, GdkColor *c) +@@ -81,14 +82,25 @@ ok_dialog(GtkWidget *entry, gpointer dia return 1; } @@ -37,7 +27,7 @@ index a62f98152..cb7152dc8 100644 static int passphrase_dialog(char *message, int prompt_type) { -@@ -153,7 +165,7 @@ passphrase_dialog(char *message, int prompt_type) + const char *failed; char *passphrase, *local; int result, grab_tries, grab_server, grab_pointer; int buttons, default_response; @@ -46,7 +36,7 @@ index a62f98152..cb7152dc8 100644 GdkGrabStatus status; GdkColor fg, bg; int fg_set = 0, bg_set = 0; -@@ -199,14 +211,19 @@ passphrase_dialog(char *message, int prompt_type) +@@ -104,14 +116,19 @@ passphrase_dialog(char *message) gtk_widget_modify_bg(dialog, GTK_STATE_NORMAL, &bg); if (prompt_type == PROMPT_ENTRY || prompt_type == PROMPT_NONE) { @@ -55,12 +45,12 @@ index a62f98152..cb7152dc8 100644 + FALSE, 0); + gtk_widget_show(hbox); + - entry = gtk_entry_new(); - if (fg_set) - gtk_widget_modify_fg(entry, GTK_STATE_NORMAL, &fg); - if (bg_set) - gtk_widget_modify_bg(entry, GTK_STATE_NORMAL, &bg); - gtk_box_pack_start( + entry = gtk_entry_new(); + if (fg_set) + gtk_widget_modify_fg(entry, GTK_STATE_NORMAL, &fg); + if (bg_set) + gtk_widget_modify_bg(entry, GTK_STATE_NORMAL, &bg); + gtk_box_pack_start( - GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), - entry, FALSE, FALSE, 0); + GTK_BOX(hbox), entry, TRUE, FALSE, 0); @@ -68,7 +58,7 @@ index a62f98152..cb7152dc8 100644 gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); gtk_widget_grab_focus(entry); if (prompt_type == PROMPT_ENTRY) { -@@ -225,6 +242,22 @@ passphrase_dialog(char *message, int prompt_type) +@@ -130,6 +145,22 @@ passphrase_dialog(char *message) g_signal_connect(G_OBJECT(entry), "key_press_event", G_CALLBACK(check_none), dialog); } @@ -91,6 +81,3 @@ index a62f98152..cb7152dc8 100644 } /* Grab focus */ --- -2.52.0 - diff --git a/openssh-5.8p2-sigpipe.patch b/openssh-5.8p2-sigpipe.patch new file mode 100644 index 0000000..554e346 --- /dev/null +++ b/openssh-5.8p2-sigpipe.patch @@ -0,0 +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,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 = xcalloc(maxfd, sizeof(struct pollfd)); + for (j = 0; j < maxfd; j++) + read_wait[j].fd = -1; + diff --git a/0004-openssh-5.9p1-ipv6man.patch b/openssh-5.9p1-ipv6man.patch similarity index 54% rename from 0004-openssh-5.9p1-ipv6man.patch rename to openssh-5.9p1-ipv6man.patch index 6ec8afc..ece1a73 100644 --- a/0004-openssh-5.9p1-ipv6man.patch +++ b/openssh-5.9p1-ipv6man.patch @@ -1,18 +1,7 @@ -From f653eed40e15c4c521ce683a604b46ed81cade6a Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 04/53] openssh-5.9p1-ipv6man - ---- - ssh.1 | 2 ++ - sshd.8 | 2 ++ - 2 files changed, 4 insertions(+) - -diff --git a/ssh.1 b/ssh.1 -index 697f4e42a..db92ac9af 100644 ---- a/ssh.1 -+++ b/ssh.1 -@@ -1663,6 +1663,8 @@ manual page for more information. +diff -up openssh-5.9p0/ssh.1.ipv6man openssh-5.9p0/ssh.1 +--- openssh-5.9p0/ssh.1.ipv6man 2011-08-05 22:17:32.000000000 +0200 ++++ openssh-5.9p0/ssh.1 2011-08-31 13:08:34.880024485 +0200 +@@ -1400,6 +1400,8 @@ manual page for more information. .Nm exits with the exit status of the remote command or with 255 if an error occurred. @@ -21,11 +10,10 @@ index 697f4e42a..db92ac9af 100644 .Sh SEE ALSO .Xr scp 1 , .Xr sftp 1 , -diff --git a/sshd.8 b/sshd.8 -index 7fbca776a..0226a8303 100644 ---- a/sshd.8 -+++ b/sshd.8 -@@ -1018,6 +1018,8 @@ concurrently for different ports, this contains the process ID of the one +diff -up openssh-5.9p0/sshd.8.ipv6man openssh-5.9p0/sshd.8 +--- openssh-5.9p0/sshd.8.ipv6man 2011-08-05 22:17:32.000000000 +0200 ++++ openssh-5.9p0/sshd.8 2011-08-31 13:10:34.129039094 +0200 +@@ -940,6 +940,8 @@ concurrently for different ports, this c started last). The content of this file is not sensitive; it can be world-readable. .El @@ -34,6 +22,3 @@ index 7fbca776a..0226a8303 100644 .Sh SEE ALSO .Xr scp 1 , .Xr sftp 1 , --- -2.52.0 - diff --git a/openssh-6.4p1-fromto-remote.patch b/openssh-6.4p1-fromto-remote.patch new file mode 100644 index 0000000..4a7d849 --- /dev/null +++ b/openssh-6.4p1-fromto-remote.patch @@ -0,0 +1,16 @@ +diff --git a/scp.c b/scp.c +index d98fa67..25d347b 100644 +--- a/scp.c ++++ b/scp.c +@@ -638,7 +638,10 @@ toremote(char *targ, int argc, char **argv) + addargs(&alist, "%s", ssh_program); + addargs(&alist, "-x"); + addargs(&alist, "-oClearAllForwardings=yes"); +- addargs(&alist, "-n"); ++ if (isatty(fileno(stdin))) ++ addargs(&alist, "-t"); ++ else ++ addargs(&alist, "-n"); + for (j = 0; j < remote_remote_args.num; j++) { + addargs(&alist, "%s", + remote_remote_args.list[j]); diff --git a/0017-openssh-6.6.1p1-log-in-chroot.patch b/openssh-6.6.1p1-log-in-chroot.patch similarity index 53% rename from 0017-openssh-6.6.1p1-log-in-chroot.patch rename to openssh-6.6.1p1-log-in-chroot.patch index 6704616..941c694 100644 --- a/0017-openssh-6.6.1p1-log-in-chroot.patch +++ b/openssh-6.6.1p1-log-in-chroot.patch @@ -1,25 +1,7 @@ -From 674851677d1e38cf6992948f8f452e46107a2014 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 17/53] openssh-6.6.1p1-log-in-chroot - ---- - log.c | 11 +++++++++-- - log.h | 1 + - monitor.c | 17 +++++++++++++++-- - monitor.h | 2 +- - session.c | 26 +++++++++++++++----------- - sftp-server-main.c | 2 +- - sftp-server.c | 6 +++--- - sftp.h | 2 +- - sshd-session.c | 7 ++++++- - 9 files changed, 52 insertions(+), 22 deletions(-) - -diff --git a/log.c b/log.c -index 5969c4a16..49b0c8a68 100644 ---- a/log.c -+++ b/log.c -@@ -196,6 +196,11 @@ void +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-04-19 14:43:08.544843434 +0200 +@@ -194,6 +194,11 @@ void log_init(const char *av0, LogLevel level, SyslogFacility facility, int on_stderr) { @@ -31,7 +13,7 @@ index 5969c4a16..49b0c8a68 100644 #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) struct syslog_data sdata = SYSLOG_DATA_INIT; #endif -@@ -208,8 +213,10 @@ log_init(const char *av0, LogLevel level, SyslogFacility facility, +@@ -206,8 +211,10 @@ log_init(const char *av0, LogLevel level exit(1); } @@ -44,10 +26,9 @@ index 5969c4a16..49b0c8a68 100644 log_on_stderr = on_stderr; if (on_stderr) -diff --git a/log.h b/log.h -index 8e8dfc23f..70048a8af 100644 ---- a/log.h -+++ b/log.h +diff -up openssh-8.6p1/log.h.log-in-chroot openssh-8.6p1/log.h +--- 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 *); @@ -56,11 +37,43 @@ index 8e8dfc23f..70048a8af 100644 LogLevel log_level_get(void); int log_change_level(LogLevel); int log_is_on_stderr(void); -diff --git a/monitor.c b/monitor.c -index d463d6a9c..453469665 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -2007,9 +2007,22 @@ monitor_init(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-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; + ++ pmonitor->m_state = "preauth"; ++ + authctxt = (Authctxt *)ssh->authctxt; + memset(authctxt, 0, sizeof(*authctxt)); + ssh->authctxt = authctxt; +@@ -408,6 +410,8 @@ monitor_child_postauth(struct ssh *ssh, + close(pmonitor->m_recvfd); + pmonitor->m_recvfd = -1; + ++ pmonitor->m_state = "postauth"; ++ + monitor_set_child_handler(pmonitor->m_pid); + ssh_signal(SIGHUP, &monitor_child_handler); + ssh_signal(SIGTERM, &monitor_child_handler); +@@ -480,7 +484,7 @@ monitor_read_log(struct monitor *pmonito + /* Log it */ + if (log_level_name(level) == NULL) + fatal_f("invalid log level %u (corrupted message?)", level); +- sshlogdirect(level, forced, "%s [preauth]", msg); ++ sshlogdirect(level, forced, "%s [%s]", msg, pmonitor->m_state); + + sshbuf_free(logmsg); + free(msg); +@@ -1868,13 +1872,28 @@ monitor_init(void) + mon = xcalloc(1, sizeof(*mon)); + monitor_openfds(mon, 1); + ++ mon->m_state = ""; ++ + return mon; } void @@ -85,11 +98,14 @@ index d463d6a9c..453469665 100644 } #ifdef GSSAPI -diff --git a/monitor.h b/monitor.h -index dbc7e0037..d4d631ddc 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -85,7 +85,7 @@ struct monitor { +diff -up openssh-8.6p1/monitor.h.log-in-chroot openssh-8.6p1/monitor.h +--- 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; + pid_t m_pid; ++ char *m_state; }; struct monitor *monitor_init(void); @@ -98,11 +114,10 @@ index dbc7e0037..d4d631ddc 100644 struct Authctxt; void monitor_child_preauth(struct ssh *, struct monitor *); -diff --git a/session.c b/session.c -index b8a2dae92..d034f5c65 100644 ---- a/session.c -+++ b/session.c -@@ -162,6 +162,7 @@ login_cap_t *lc; +diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c +--- 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; static int in_chroot = 0; @@ -110,7 +125,7 @@ index b8a2dae92..d034f5c65 100644 /* File containing userauth info, if ExposeAuthInfo set */ static char *auth_info_file = NULL; -@@ -632,6 +633,7 @@ do_exec(struct ssh *ssh, Session *s, const char *command) +@@ -661,6 +662,7 @@ do_exec(struct ssh *ssh, Session *s, con int ret; const char *forced = NULL, *tty = NULL; char session_type[1024]; @@ -118,7 +133,7 @@ index b8a2dae92..d034f5c65 100644 if (options.adm_forced_command) { original_command = command; -@@ -691,6 +693,10 @@ do_exec(struct ssh *ssh, Session *s, const char *command) +@@ -720,6 +722,10 @@ do_exec(struct ssh *ssh, Session *s, con tty += 5; } @@ -129,7 +144,7 @@ index b8a2dae92..d034f5c65 100644 verbose("Starting session: %s%s%s for %s from %.200s port %d id %d", session_type, tty == NULL ? "" : " on ", -@@ -1469,14 +1475,6 @@ child_close_fds(struct ssh *ssh) +@@ -1524,14 +1530,6 @@ child_close_fds(struct ssh *ssh) /* Stop directing logs to a high-numbered fd before we close it */ log_redirect_stderr_to(NULL); @@ -144,7 +159,7 @@ index b8a2dae92..d034f5c65 100644 } /* -@@ -1609,8 +1607,6 @@ do_child(struct ssh *ssh, Session *s, const char *command) +@@ -1665,8 +1663,6 @@ do_child(struct ssh *ssh, Session *s, co exit(1); } @@ -153,10 +168,10 @@ index b8a2dae92..d034f5c65 100644 do_rc_files(ssh, s, shell); /* restore SIGPIPE for child */ -@@ -1638,9 +1634,17 @@ do_child(struct ssh *ssh, Session *s, const char *command) - #ifdef WITH_SELINUX - ssh_selinux_change_context("sftpd_t"); - #endif +@@ -1691,9 +1687,17 @@ do_child(struct ssh *ssh, Session *s, co + argv[i] = NULL; + optind = optreset = 1; + __progname = argv[0]; - exit(sftp_server_main(i, argv, s->pw)); + exit(sftp_server_main(i, argv, s->pw, have_dev_log)); } @@ -172,31 +187,29 @@ index b8a2dae92..d034f5c65 100644 fflush(NULL); /* Get the last component of the shell name. */ -diff --git a/sftp-server-main.c b/sftp-server-main.c -index 2c70f89bc..bbb79f278 100644 ---- a/sftp-server-main.c -+++ b/sftp-server-main.c -@@ -48,5 +48,5 @@ main(int argc, char **argv) - return 1; - } +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-04-19 14:43:08.545843441 +0200 +@@ -97,5 +97,5 @@ -- return (sftp_server_main(argc, argv, user_pw)); -+ return (sftp_server_main(argc, argv, user_pw, 0)); - } -diff --git a/sftp-server.c b/sftp-server.c -index 777821acd..185ad1459 100644 ---- a/sftp-server.c -+++ b/sftp-server.c -@@ -1897,7 +1897,7 @@ sftp_server_usage(void) + struct passwd; + +-int sftp_server_main(int, char **, struct passwd *); ++int sftp_server_main(int, char **, struct passwd *, int); + 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-04-19 14:43:08.545843441 +0200 +@@ -1644,7 +1644,7 @@ sftp_server_usage(void) } int -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) { - int i, r, in, out, ch, skipargs = 0, log_stderr = 0; - ssize_t len, olen; -@@ -1909,7 +1909,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) + 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; __progname = ssh_get_progname(argv[0]); @@ -205,7 +218,7 @@ index 777821acd..185ad1459 100644 pw = pwcopy(user_pw); -@@ -1982,7 +1982,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) +@@ -1730,7 +1730,7 @@ sftp_server_main(int argc, char **argv, } } @@ -214,23 +227,21 @@ index 777821acd..185ad1459 100644 /* * On platforms where we can, avoid making /proc/self/{mem,maps} -diff --git a/sftp.h b/sftp.h -index 2bde8bb7f..ddf1a3968 100644 ---- a/sftp.h -+++ b/sftp.h -@@ -97,5 +97,5 @@ +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-04-19 14:43:08.545843441 +0200 +@@ -50,5 +50,5 @@ main(int argc, char **argv) + return 1; + } - struct passwd; - --int sftp_server_main(int, char **, struct passwd *); -+int sftp_server_main(int, char **, struct passwd *, int); - void sftp_server_cleanup_exit(int) __attribute__((noreturn)); -diff --git a/sshd-session.c b/sshd-session.c -index 028d5850e..4a5eaa1ff 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -415,7 +415,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) - #endif +- 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-04-19 14:43:08.543843426 +0200 ++++ openssh-8.6p1/sshd.c 2021-04-19 14:43:08.545843441 +0200 +@@ -559,7 +559,7 @@ privsep_postauth(struct ssh *ssh, Authct + } /* New socket pair */ - monitor_reinit(pmonitor); @@ -238,7 +249,7 @@ index 028d5850e..4a5eaa1ff 100644 pmonitor->m_pid = fork(); if (pmonitor->m_pid == -1) -@@ -434,6 +434,11 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) +@@ -578,6 +578,11 @@ privsep_postauth(struct ssh *ssh, Authct close(pmonitor->m_sendfd); pmonitor->m_sendfd = -1; @@ -250,6 +261,3 @@ index 028d5850e..4a5eaa1ff 100644 /* Demote the private keys to public keys. */ demote_sensitive_data(); --- -2.52.0 - diff --git a/openssh-6.6.1p1-scp-non-existing-directory.patch b/openssh-6.6.1p1-scp-non-existing-directory.patch new file mode 100644 index 0000000..bb55c0b --- /dev/null +++ b/openssh-6.6.1p1-scp-non-existing-directory.patch @@ -0,0 +1,14 @@ +--- a/scp.c ++++ a/scp.c +@@ -1084,6 +1084,10 @@ sink(int argc, char **argv) + free(vect[0]); + continue; + } ++ if (buf[0] == 'C' && ! exists && np[strlen(np)-1] == '/') { ++ errno = ENOTDIR; ++ goto bad; ++ } + omode = mode; + mode |= S_IWUSR; + if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) == -1) { +-- diff --git a/openssh-6.6.1p1-selinux-contexts.patch b/openssh-6.6.1p1-selinux-contexts.patch new file mode 100644 index 0000000..eab724a --- /dev/null +++ b/openssh-6.6.1p1-selinux-contexts.patch @@ -0,0 +1,131 @@ +diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c +index 8f32464..18a2ca4 100644 +--- a/openbsd-compat/port-linux-sshd.c ++++ b/openbsd-compat/port-linux-sshd.c +@@ -32,6 +32,7 @@ + #include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ + #include "servconf.h" + #include "port-linux.h" ++#include "misc.h" + #include "sshkey.h" + #include "hostfile.h" + #include "auth.h" +@@ -445,7 +446,7 @@ sshd_selinux_setup_exec_context(char *pwname) + void + sshd_selinux_copy_context(void) + { +- security_context_t *ctx; ++ char *ctx; + + if (!sshd_selinux_enabled()) + return; +@@ -461,6 +462,72 @@ sshd_selinux_copy_context(void) + } + } + ++void ++sshd_selinux_change_privsep_preauth_context(void) ++{ ++ int len; ++ char line[1024], *preauth_context = NULL, *cp, *arg; ++ const char *contexts_path; ++ FILE *contexts_file; ++ struct stat sb; ++ ++ contexts_path = selinux_openssh_contexts_path(); ++ if (contexts_path == NULL) { ++ debug3_f("Failed to get the path to SELinux context"); ++ return; ++ } ++ ++ if ((contexts_file = fopen(contexts_path, "r")) == NULL) { ++ debug_f("Failed to open SELinux context file"); ++ return; ++ } ++ ++ if (fstat(fileno(contexts_file), &sb) != 0 || ++ sb.st_uid != 0 || (sb.st_mode & 022) != 0) { ++ logit_f("SELinux context file needs to be owned by root" ++ " and not writable by anyone else"); ++ fclose(contexts_file); ++ return; ++ } ++ ++ while (fgets(line, sizeof(line), contexts_file)) { ++ /* Strip trailing whitespace */ ++ for (len = strlen(line) - 1; len > 0; len--) { ++ if (strchr(" \t\r\n", line[len]) == NULL) ++ break; ++ line[len] = '\0'; ++ } ++ ++ if (line[0] == '\0') ++ continue; ++ ++ cp = line; ++ arg = strdelim(&cp); ++ if (arg && *arg == '\0') ++ arg = strdelim(&cp); ++ ++ if (arg && strcmp(arg, "privsep_preauth") == 0) { ++ arg = strdelim(&cp); ++ if (!arg || *arg == '\0') { ++ debug_f("privsep_preauth is empty"); ++ fclose(contexts_file); ++ return; ++ } ++ preauth_context = xstrdup(arg); ++ } ++ } ++ fclose(contexts_file); ++ ++ if (preauth_context == NULL) { ++ debug_f("Unable to find 'privsep_preauth' option in" ++ " SELinux context file"); ++ return; ++ } ++ ++ ssh_selinux_change_context(preauth_context); ++ free(preauth_context); ++} ++ + #endif + #endif + +diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c +--- 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_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 ++++ b/openbsd-compat/port-linux.h +@@ -29,6 +29,7 @@ int sshd_selinux_enabled(void); + void sshd_selinux_copy_context(void); + void sshd_selinux_setup_exec_context(char *); + int sshd_selinux_setup_env_variables(void); ++void sshd_selinux_change_privsep_preauth_context(void); + #endif + + #ifdef LINUX_OOM_ADJUST +diff --git a/sshd.c b/sshd.c +index 2871fe9..39b9c08 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -629,7 +629,7 @@ privsep_preauth_child(void) + demote_sensitive_data(); + + #ifdef WITH_SELINUX +- ssh_selinux_change_context("sshd_net_t"); ++ sshd_selinux_change_privsep_preauth_context(); + #endif + + /* Demote the child */ diff --git a/0019-openssh-6.6p1-GSSAPIEnablek5users.patch b/openssh-6.6p1-GSSAPIEnablek5users.patch similarity index 62% rename from 0019-openssh-6.6p1-GSSAPIEnablek5users.patch rename to openssh-6.6p1-GSSAPIEnablek5users.patch index 4c0a60b..cccb3e0 100644 --- a/0019-openssh-6.6p1-GSSAPIEnablek5users.patch +++ b/openssh-6.6p1-GSSAPIEnablek5users.patch @@ -1,21 +1,7 @@ -From ef91c84a26a282adaf95e165ebcdd44a410c4328 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 19/53] openssh-6.6p1-GSSAPIEnablek5users - ---- - gss-serv-krb5.c | 3 +-- - servconf.c | 13 ++++++++++++- - servconf.h | 1 + - sshd_config | 1 + - sshd_config.5 | 6 ++++++ - 5 files changed, 21 insertions(+), 3 deletions(-) - -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 187faf929..03188d9b3 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c -@@ -278,7 +278,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, +diff -up openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users openssh-7.4p1/gss-serv-krb5.c +--- openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users 2016-12-23 15:18:40.615216100 +0100 ++++ openssh-7.4p1/gss-serv-krb5.c 2016-12-23 15:18:40.628216102 +0100 +@@ -279,7 +279,6 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri FILE *fp; char file[MAXPATHLEN]; char *line = NULL; @@ -23,7 +9,7 @@ index 187faf929..03188d9b3 100644 struct stat st; struct passwd *pw = the_authctxt->pw; int found_principal = 0; -@@ -288,7 +287,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, +@@ -288,7 +287,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); /* If both .k5login and .k5users DNE, self-login is ok. */ @@ -32,19 +18,18 @@ index 187faf929..03188d9b3 100644 return ssh_krb5_kuserok(krb_context, principal, luser, k5login_exists); } -diff --git a/servconf.c b/servconf.c -index 8f4b2b43e..5e40f1b00 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -144,6 +144,7 @@ initialize_server_options(ServerOptions *options) +diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.GSSAPIEnablek5users 2016-12-23 15:18:40.615216100 +0100 ++++ openssh-7.4p1/servconf.c 2016-12-23 15:35:36.354401156 +0100 +@@ -168,6 +168,7 @@ initialize_server_options(ServerOptions options->gss_store_rekey = -1; options->gss_kex_algorithms = NULL; options->use_kuserok = -1; + options->enable_k5users = -1; options->password_authentication = -1; options->kbd_interactive_authentication = -1; - options->permit_empty_passwd = -1; -@@ -396,6 +397,8 @@ fill_default_server_options(ServerOptions *options) + options->permit_empty_passwd = -1; +@@ -345,6 +346,8 @@ fill_default_server_options(ServerOption #endif if (options->use_kuserok == -1) options->use_kuserok = 1; @@ -53,16 +38,16 @@ index 8f4b2b43e..5e40f1b00 100644 if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -579,7 +582,7 @@ typedef enum { +@@ -418,7 +421,7 @@ typedef enum { + sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, 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, -@@ -675,6 +678,7 @@ static struct { +@@ -497,14 +500,16 @@ static struct { { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, @@ -70,7 +55,8 @@ index 8f4b2b43e..5e40f1b00 100644 #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, -@@ -683,6 +687,7 @@ static struct { + { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, + { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL }, @@ -78,7 +64,7 @@ index 8f4b2b43e..5e40f1b00 100644 #endif { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, -@@ -2440,6 +2445,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, +@@ -1653,6 +1658,10 @@ process_server_config_line(ServerOptions intptr = &options->use_kuserok; goto parse_flag; @@ -86,10 +72,10 @@ index 8f4b2b43e..5e40f1b00 100644 + intptr = &options->enable_k5users; + goto parse_flag; + - case sMatch: - if (cmdline) - fatal("Match directive not supported as a command-line " -@@ -3007,6 +3016,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) + case sMatch: + if (cmdline) + fatal("Match directive not supported as a command-line " +@@ -2026,6 +2035,7 @@ copy_set_server_options(ServerOptions *d M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); M_CP_INTOPT(use_kuserok); @@ -97,7 +83,7 @@ index 8f4b2b43e..5e40f1b00 100644 M_CP_INTOPT(rekey_limit); M_CP_INTOPT(rekey_interval); M_CP_INTOPT(log_level); -@@ -3316,6 +3326,7 @@ dump_config(ServerOptions *o) +@@ -2320,6 +2330,7 @@ dump_config(ServerOptions *o) # endif dump_cfg_fmtint(sKerberosUniqueCCache, o->kerberos_unique_ccache); dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); @@ -105,35 +91,21 @@ index 8f4b2b43e..5e40f1b00 100644 #endif #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); -diff --git a/servconf.h b/servconf.h -index 11de36a23..c08cf6a7a 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -152,6 +152,7 @@ typedef struct { - int kerberos_unique_ccache; /* If true, the acquired ticket will - * be stored in per-session ccache */ +diff -up openssh-7.4p1/servconf.h.GSSAPIEnablek5users openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.GSSAPIEnablek5users 2016-12-23 15:18:40.616216100 +0100 ++++ openssh-7.4p1/servconf.h 2016-12-23 15:18:40.629216102 +0100 +@@ -174,6 +174,7 @@ typedef struct { + int kerberos_unique_ccache; /* If true, the acquired ticket will + * be stored in per-session ccache */ int use_kuserok; + int enable_k5users; int gss_authentication; /* If true, permit GSSAPI authentication */ int gss_keyex; /* If true, permit GSSAPI key exchange */ int gss_cleanup_creds; /* If true, destroy cred cache on logout */ -diff --git a/sshd_config b/sshd_config -index ea5a878e6..33713c886 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -82,6 +82,7 @@ AuthorizedKeysFile .ssh/authorized_keys - #GSSAPICleanupCredentials yes - #GSSAPIStrictAcceptorCheck yes - #GSSAPIKeyExchange no -+#GSSAPIEnablek5users no - - # 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 c360fcfff..a0fc6064f 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -739,6 +739,12 @@ Specifies whether to automatically destroy the user's credentials cache +diff -up openssh-7.4p1/sshd_config.5.GSSAPIEnablek5users openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.GSSAPIEnablek5users 2016-12-23 15:18:40.630216103 +0100 ++++ openssh-7.4p1/sshd_config.5 2016-12-23 15:36:21.607408435 +0100 +@@ -628,6 +628,12 @@ Specifies whether to automatically destr on logout. The default is .Cm yes . @@ -146,6 +118,14 @@ index c360fcfff..a0fc6064f 100644 .It Cm GSSAPIKeyExchange Specifies whether key exchange based on GSSAPI is allowed. GSSAPI key exchange doesn't rely on ssh keys to verify host identity. --- -2.52.0 - +diff -up openssh-7.4p1/sshd_config.GSSAPIEnablek5users openssh-7.4p1/sshd_config +--- openssh-7.4p1/sshd_config.GSSAPIEnablek5users 2016-12-23 15:18:40.616216100 +0100 ++++ openssh-7.4p1/sshd_config 2016-12-23 15:18:40.631216103 +0100 +@@ -80,6 +80,7 @@ GSSAPIAuthentication yes + #GSSAPICleanupCredentials yes + #GSSAPIStrictAcceptorCheck yes + #GSSAPIKeyExchange no ++#GSSAPIEnablek5users no + + # Set this to 'yes' to enable PAM authentication, account processing, + # and session processing. If this is enabled, PAM authentication will diff --git a/0003-openssh-6.6p1-allow-ip-opts.patch b/openssh-6.6p1-allow-ip-opts.patch similarity index 67% rename from 0003-openssh-6.6p1-allow-ip-opts.patch rename to openssh-6.6p1-allow-ip-opts.patch index ea11b6c..be8d340 100644 --- a/0003-openssh-6.6p1-allow-ip-opts.patch +++ b/openssh-6.6p1-allow-ip-opts.patch @@ -1,17 +1,7 @@ -From 7ffeef7e8218c544b6f4a09c5d43e9b748de5a5f Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 03/53] openssh-6.6p1-allow-ip-opts - ---- - sshd-session.c | 32 ++++++++++++++++++++++++++------ - 1 file changed, 26 insertions(+), 6 deletions(-) - -diff --git a/sshd-session.c b/sshd-session.c -index cb4b0523d..1c72e664a 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -754,12 +754,32 @@ check_ip_options(struct ssh *ssh) +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,32 @@ check_ip_options(struct ssh *ssh) if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts, &option_size) >= 0 && option_size != 0) { @@ -48,8 +38,5 @@ index cb4b0523d..1c72e664a 100644 + } + } while (i < option_size); } + return; #endif /* IP_OPTIONS */ - } --- -2.52.0 - diff --git a/0012-openssh-6.6p1-force_krb.patch b/openssh-6.6p1-force_krb.patch similarity index 88% rename from 0012-openssh-6.6p1-force_krb.patch rename to openssh-6.6p1-force_krb.patch index 70f75fb..90f8322 100644 --- a/0012-openssh-6.6p1-force_krb.patch +++ b/openssh-6.6p1-force_krb.patch @@ -1,17 +1,5 @@ -From 577b0fea53270292bd0b4979eb5369619b2f5adb Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 12/53] openssh-6.6p1-force_krb - ---- - gss-serv-krb5.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++- - session.c | 23 +++++++ - ssh-gss.h | 4 ++ - sshd.8 | 7 +++ - 4 files changed, 189 insertions(+), 1 deletion(-) - diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 8d2b677f7..14502c5a6 100644 +index 413b845..54dd383 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c @@ -32,7 +32,9 @@ @@ -24,7 +12,7 @@ index 8d2b677f7..14502c5a6 100644 #include "xmalloc.h" #include "sshkey.h" -@@ -44,6 +46,7 @@ +@@ -45,6 +47,7 @@ #include "ssh-gss.h" @@ -32,7 +20,7 @@ index 8d2b677f7..14502c5a6 100644 extern ServerOptions options; #ifdef HEIMDAL -@@ -55,6 +58,13 @@ extern ServerOptions options; +@@ -56,6 +59,13 @@ extern ServerOptions options; # include #endif @@ -46,7 +34,7 @@ index 8d2b677f7..14502c5a6 100644 static krb5_context krb_context = NULL; /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ -@@ -87,6 +97,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -88,6 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) krb5_principal princ; int retval; const char *errmsg; @@ -54,7 +42,7 @@ index 8d2b677f7..14502c5a6 100644 if (ssh_gssapi_krb5_init() == 0) return 0; -@@ -98,10 +109,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -99,10 +110,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) krb5_free_error_message(krb_context, errmsg); return 0; } @@ -78,7 +66,7 @@ index 8d2b677f7..14502c5a6 100644 } else retval = 0; -@@ -109,6 +132,137 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -110,6 +133,137 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) return retval; } @@ -217,10 +205,10 @@ index 8d2b677f7..14502c5a6 100644 /* This writes out any forwarded credentials from the structure populated * during userauth. Called after we have setuid to the user */ diff --git a/session.c b/session.c -index b8f0c1a58..3eae5bdf3 100644 +index 28659ec..9c94d8e 100644 --- a/session.c +++ b/session.c -@@ -642,6 +642,29 @@ do_exec(struct ssh *ssh, Session *s, const char *command) +@@ -789,6 +789,29 @@ do_exec(Session *s, const char *command) command = auth_opts->force_command; forced = "(key-option)"; } @@ -251,7 +239,7 @@ index b8f0c1a58..3eae5bdf3 100644 if (forced != NULL) { s->forced = 1; diff --git a/ssh-gss.h b/ssh-gss.h -index 8ec451926..db34d77f4 100644 +index 0374c88..509109a 100644 --- a/ssh-gss.h +++ b/ssh-gss.h @@ -49,6 +49,10 @@ @@ -266,10 +254,10 @@ index 8ec451926..db34d77f4 100644 /* draft-ietf-secsh-gsskeyex-06 */ diff --git a/sshd.8 b/sshd.8 -index 0226a8303..e2d8ff003 100644 +index adcaaf9..824163b 100644 --- a/sshd.8 +++ b/sshd.8 -@@ -286,6 +286,7 @@ Finally, the server and the client enter an authentication dialog. +@@ -324,6 +324,7 @@ Finally, the server and the client enter an authentication dialog. The client tries to authenticate itself using host-based authentication, public key authentication, @@ -277,7 +265,7 @@ index 0226a8303..e2d8ff003 100644 challenge-response authentication, or password authentication. .Pp -@@ -874,6 +875,12 @@ This file is used in exactly the same way as +@@ -800,6 +801,12 @@ This file is used in exactly the same way as but allows host-based authentication without permitting login with rlogin/rsh. .Pp @@ -290,6 +278,3 @@ index 0226a8303..e2d8ff003 100644 .It Pa ~/.ssh/ This directory is the default location for all user-specific configuration and authentication information. --- -2.52.0 - diff --git a/0002-openssh-6.6p1-keycat.patch b/openssh-6.6p1-keycat.patch similarity index 76% rename from 0002-openssh-6.6p1-keycat.patch rename to openssh-6.6p1-keycat.patch index b196636..529b508 100644 --- a/0002-openssh-6.6p1-keycat.patch +++ b/openssh-6.6p1-keycat.patch @@ -1,129 +1,7 @@ -From 5f16fff915643a515adbbd2e0cd12717938e3570 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 02/53] openssh-6.6p1-keycat - ---- - HOWTO.ssh-keycat | 12 ++ - Makefile.in | 8 +- - configure.ac | 6 + - misc.c | 7 + - openbsd-compat/port-linux-sshd.c | 42 +++++- - openbsd-compat/port-linux.h | 1 + - platform.c | 2 +- - ssh-keycat.c | 241 +++++++++++++++++++++++++++++++ - 8 files changed, 312 insertions(+), 7 deletions(-) - create mode 100644 HOWTO.ssh-keycat - create mode 100644 ssh-keycat.c - -diff --git a/HOWTO.ssh-keycat b/HOWTO.ssh-keycat -new file mode 100644 -index 000000000..630ec628c ---- /dev/null -+++ b/HOWTO.ssh-keycat -@@ -0,0 +1,12 @@ -+The ssh-keycat retrieves the content of the ~/.ssh/authorized_keys -+of an user in any environment. This includes environments with -+polyinstantiation of home directories and SELinux MLS policy enabled. -+ -+To use ssh-keycat, set these options in /etc/ssh/sshd_config file: -+ AuthorizedKeysCommand /usr/libexec/openssh/ssh-keycat -+ AuthorizedKeysCommandUser root -+ -+Do not forget to enable public key authentication: -+ PubkeyAuthentication yes -+ -+ -diff --git a/Makefile.in b/Makefile.in -index ba17a79f0..a3a495c1b 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -23,6 +23,7 @@ SSH_PROGRAM=@bindir@/ssh - ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass - SFTP_SERVER=$(libexecdir)/sftp-server - SSH_KEYSIGN=$(libexecdir)/ssh-keysign -+SSH_KEYCAT=$(libexecdir)/ssh-keycat - SSHD_SESSION=$(libexecdir)/sshd-session - SSHD_AUTH=$(libexecdir)/sshd-auth - SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper -@@ -58,6 +59,7 @@ CHANNELLIBS=@CHANNELLIBS@ - K5LIBS=@K5LIBS@ - GSSLIBS=@GSSLIBS@ - SSHDLIBS=@SSHDLIBS@ -+KEYCATLIBS=@KEYCATLIBS@ - LIBEDIT=@LIBEDIT@ - LIBFIDO2=@LIBFIDO2@ - LIBWTMPDB=@LIBWTMPDB@ -@@ -75,7 +77,7 @@ MKDIR_P=@MKDIR_P@ - - .SUFFIXES: .lo - --TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) sshd-auth$(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) $(SK_STANDALONE) -+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) sshd-auth$(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) $(SK_STANDALONE) - - LIBOPENSSH_OBJS=\ - ssh_api.o \ -@@ -252,6 +254,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(P11HELPER_OBJS) - ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(SKHELPER_OBJS) - $(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) $(CHANNELLIBS) - -@@ -439,6 +444,7 @@ install-files: - $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) - $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) - $(INSTALL) -m 0755 $(STRIP_OPT) ssh-sk-helper$(EXEEXT) $(DESTDIR)$(SSH_SK_HELPER)$(EXEEXT) -+ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT) - $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) - $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) - $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 -diff --git a/configure.ac b/configure.ac -index db5211013..fd632a5a8 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -3648,6 +3648,7 @@ AC_ARG_WITH([pam], - PAM_MSG="yes" - - SSHDLIBS="$SSHDLIBS -lpam" -+ KEYCATLIBS="$KEYCATLIBS -lpam" - AC_DEFINE([USE_PAM], [1], - [Define if you want to enable PAM support]) - -@@ -3658,6 +3659,7 @@ AC_ARG_WITH([pam], - ;; - *) - SSHDLIBS="$SSHDLIBS -ldl" -+ KEYCATLIBS="$KEYCATLIBS -ldl" - ;; - esac - fi -@@ -4883,6 +4885,7 @@ AC_ARG_WITH([selinux], - fi ] - ) - AC_SUBST([SSHDLIBS]) -+AC_SUBST([KEYCATLIBS]) - - # Check whether user wants Kerberos 5 support - KRB5_MSG="no" -@@ -5894,6 +5897,9 @@ fi - if test ! -z "${SSHDLIBS}"; then - echo " +for sshd: ${SSHDLIBS}" - fi -+if test ! -z "${KEYCATLIBS}"; then -+echo " +for ssh-keycat: ${KEYCATLIBS}" -+fi - - echo "" - -diff --git a/misc.c b/misc.c -index 5bed34735..7e27a38d1 100644 ---- a/misc.c -+++ b/misc.c -@@ -2921,6 +2921,13 @@ subprocess(const char *tag, const char *command, +diff -up openssh/misc.c.keycat openssh/misc.c +--- openssh/misc.c.keycat 2015-06-24 10:57:50.158849606 +0200 ++++ openssh/misc.c 2015-06-24 11:04:23.989868638 +0200 +@@ -966,6 +966,13 @@ subprocess(const char *tag, struct passw error("%s: dup2: %s", tag, strerror(errno)); _exit(1); } @@ -137,13 +15,88 @@ index 5bed34735..7e27a38d1 100644 if (env != NULL) execve(av[0], av, env); else -diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -index b9fbe38b7..4d56745f7 100644 ---- a/openbsd-compat/port-linux-sshd.c -+++ b/openbsd-compat/port-linux-sshd.c -@@ -52,6 +52,20 @@ extern ServerOptions options; - extern Authctxt *the_authctxt; +diff -up openssh/HOWTO.ssh-keycat.keycat openssh/HOWTO.ssh-keycat +--- openssh/HOWTO.ssh-keycat.keycat 2015-06-24 10:57:50.157849608 +0200 ++++ openssh/HOWTO.ssh-keycat 2015-06-24 10:57:50.157849608 +0200 +@@ -0,0 +1,12 @@ ++The ssh-keycat retrieves the content of the ~/.ssh/authorized_keys ++of an user in any environment. This includes environments with ++polyinstantiation of home directories and SELinux MLS policy enabled. ++ ++To use ssh-keycat, set these options in /etc/ssh/sshd_config file: ++ AuthorizedKeysCommand /usr/libexec/openssh/ssh-keycat ++ AuthorizedKeysCommandUser root ++ ++Do not forget to enable public key authentication: ++ PubkeyAuthentication yes ++ ++ +diff -up openssh/Makefile.in.keycat openssh/Makefile.in +--- openssh/Makefile.in.keycat 2015-06-24 10:57:50.152849621 +0200 ++++ openssh/Makefile.in 2015-06-24 10:57:50.157849608 +0200 +@@ -27,6 +27,7 @@ SFTP_SERVER=$(libexecdir)/sftp-server + ASKPASS_PROGRAM=$(libexecdir)/ssh-askpass + SFTP_SERVER=$(libexecdir)/sftp-server + SSH_KEYSIGN=$(libexecdir)/ssh-keysign ++SSH_KEYCAT=$(libexecdir)/ssh-keycat + 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@ + SSHDLIBS=@SSHDLIBS@ ++KEYCATLIBS=@KEYCATLIBS@ + LIBEDIT=@LIBEDIT@ + LIBFIDO2=@LIBFIDO2@ + AR=@AR@ +@@ -65,7 +66,7 @@ EXEEXT=@EXEEXT@ + + .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) + + 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) $(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) $(CHANNELLIBS) + +@@ -321,6 +325,7 @@ install-files: + $(INSTALL) -m 4711 $(STRIP_OPT) ssh-keysign$(EXEEXT) $(DESTDIR)$(SSH_KEYSIGN)$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-pkcs11-helper$(EXEEXT) $(DESTDIR)$(SSH_PKCS11_HELPER)$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) ssh-sk-helper$(EXEEXT) $(DESTDIR)$(SSH_SK_HELPER)$(EXEEXT) ++ $(INSTALL) -m 0755 $(STRIP_OPT) ssh-keycat$(EXEEXT) $(DESTDIR)$(libexecdir)/ssh-keycat$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp$(EXEEXT) $(DESTDIR)$(bindir)/sftp$(EXEEXT) + $(INSTALL) -m 0755 $(STRIP_OPT) sftp-server$(EXEEXT) $(DESTDIR)$(SFTP_SERVER)$(EXEEXT) + $(INSTALL) -m 644 ssh.1.out $(DESTDIR)$(mandir)/$(mansubdir)1/ssh.1 +diff -up openssh/openbsd-compat/port-linux.h.keycat openssh/openbsd-compat/port-linux.h +--- openssh/openbsd-compat/port-linux.h.keycat 2015-06-24 10:57:50.150849626 +0200 ++++ openssh/openbsd-compat/port-linux.h 2015-06-24 10:57:50.160849601 +0200 +@@ -25,8 +25,10 @@ void ssh_selinux_setup_pty(char *, const + void ssh_selinux_change_context(const char *); + void ssh_selinux_setfscreatecon(const char *); + ++int sshd_selinux_enabled(void); + void sshd_selinux_copy_context(void); + void sshd_selinux_setup_exec_context(char *); ++int sshd_selinux_setup_env_variables(void); + #endif + + #ifdef LINUX_OOM_ADJUST +diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/port-linux-sshd.c +--- 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 int inetd_flag; + extern int rexeced_flag; +/* Wrapper around is_selinux_enabled() to log its return value once only */ +int @@ -162,7 +115,7 @@ index b9fbe38b7..4d56745f7 100644 /* Send audit message */ static int sshd_selinux_send_audit_message(int success, security_context_t default_context, -@@ -317,7 +331,7 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -308,7 +322,7 @@ sshd_selinux_getctxbyname(char *pwname, /* Setup environment variables for pam_selinux */ static int @@ -171,14 +124,14 @@ index b9fbe38b7..4d56745f7 100644 { const char *reqlvl; char *role; -@@ -328,16 +342,16 @@ sshd_selinux_setup_pam_variables(void) +@@ -319,16 +333,16 @@ sshd_selinux_setup_pam_variables(void) ssh_selinux_get_role_level(&role, &reqlvl); - rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); + rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : ""); - if (inetd_flag) { + if (inetd_flag && !rexeced_flag) { use_current = "1"; } else { use_current = ""; @@ -191,7 +144,7 @@ index b9fbe38b7..4d56745f7 100644 if (role != NULL) free(role); -@@ -345,6 +359,24 @@ sshd_selinux_setup_pam_variables(void) +@@ -336,6 +350,24 @@ sshd_selinux_setup_pam_variables(void) return rv; } @@ -216,7 +169,7 @@ index b9fbe38b7..4d56745f7 100644 /* Set the execution context to the default for the specified user */ void sshd_selinux_setup_exec_context(char *pwname) -@@ -353,7 +385,7 @@ sshd_selinux_setup_exec_context(char *pwname) +@@ -344,7 +376,7 @@ sshd_selinux_setup_exec_context(char *pw int r = 0; security_context_t default_ctx = NULL; @@ -225,23 +178,19 @@ index b9fbe38b7..4d56745f7 100644 return; if (options.use_pam) { -diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h -index 055c825e4..c004071d1 100644 ---- a/openbsd-compat/port-linux.h -+++ b/openbsd-compat/port-linux.h -@@ -24,6 +24,7 @@ void ssh_selinux_change_context(const char *); - void ssh_selinux_setfscreatecon(const char *); +@@ -415,7 +447,7 @@ sshd_selinux_copy_context(void) + { + security_context_t *ctx; - void sshd_selinux_setup_exec_context(char *); -+int sshd_selinux_setup_env_variables(void); - #endif +- if (!ssh_selinux_enabled()) ++ if (!sshd_selinux_enabled()) + return; - #ifdef LINUX_OOM_ADJUST -diff --git a/platform.c b/platform.c -index bcf1b0491..c92a0cba6 100644 ---- a/platform.c -+++ b/platform.c -@@ -55,7 +55,7 @@ platform_setusercontext(struct passwd *pw) + if (getexeccon((security_context_t *)&ctx) != 0) { +diff -up openssh/platform.c.keycat openssh/platform.c +--- openssh/platform.c.keycat 2015-06-24 10:57:50.147849633 +0200 ++++ openssh/platform.c 2015-06-24 10:57:50.160849601 +0200 +@@ -103,7 +103,7 @@ platform_setusercontext(struct passwd *p { #ifdef WITH_SELINUX /* Cache selinux status for later use */ @@ -250,11 +199,9 @@ index bcf1b0491..c92a0cba6 100644 #endif #ifdef USE_SOLARIS_PROJECTS -diff --git a/ssh-keycat.c b/ssh-keycat.c -new file mode 100644 -index 000000000..5678be079 ---- /dev/null -+++ b/ssh-keycat.c +diff -up openssh/ssh-keycat.c.keycat openssh/ssh-keycat.c +--- openssh/ssh-keycat.c.keycat 2015-06-24 10:57:50.161849599 +0200 ++++ openssh/ssh-keycat.c 2015-06-24 10:57:50.161849599 +0200 @@ -0,0 +1,241 @@ +/* + * Redistribution and use in source and binary forms, with or without @@ -497,6 +444,41 @@ index 000000000..5678be079 + } + return ev; +} --- -2.52.0 - +diff --git a/configure.ac b/configure.ac +index 3bbccfd..6481f1f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2952,6 +2952,7 @@ AC_ARG_WITH([pam], + PAM_MSG="yes" + + SSHDLIBS="$SSHDLIBS -lpam" ++ KEYCATLIBS="$KEYCATLIBS -lpam" + AC_DEFINE([USE_PAM], [1], + [Define if you want to enable PAM support]) + +@@ -3105,6 +3106,7 @@ + ;; + *) + SSHDLIBS="$SSHDLIBS -ldl" ++ KEYCATLIBS="$KEYCATLIBS -ldl" + ;; + esac + fi +@@ -4042,6 +4044,7 @@ AC_ARG_WITH([selinux], + fi ] + ) + AC_SUBST([SSHDLIBS]) ++AC_SUBST([KEYCATLIBS]) + + # Check whether user wants Kerberos 5 support + KRB5_MSG="no" +@@ -5031,6 +5034,9 @@ fi + if test ! -z "${SSHDLIBS}"; then + echo " +for sshd: ${SSHDLIBS}" + fi ++if test ! -z "${KEYCATLIBS}"; then ++echo " +for ssh-keycat: ${KEYCATLIBS}" ++fi + + echo "" + diff --git a/0015-openssh-6.6p1-kuserok.patch b/openssh-6.6p1-kuserok.patch similarity index 79% rename from 0015-openssh-6.6p1-kuserok.patch rename to openssh-6.6p1-kuserok.patch index a403c7c..eaf4453 100644 --- a/0015-openssh-6.6p1-kuserok.patch +++ b/openssh-6.6p1-kuserok.patch @@ -1,22 +1,7 @@ -From d0c2e8ddde548c79144547152b523346ae9f0358 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 15/53] openssh-6.6p1-kuserok - ---- - auth-krb5.c | 20 ++++++++- - gss-serv-krb5.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++-- - servconf.c | 13 +++++- - servconf.h | 1 + - sshd_config | 1 + - sshd_config.5 | 5 +++ - 6 files changed, 139 insertions(+), 7 deletions(-) - -diff --git a/auth-krb5.c b/auth-krb5.c -index 4910aa38a..b9c261a24 100644 ---- a/auth-krb5.c -+++ b/auth-krb5.c -@@ -55,6 +55,21 @@ +diff -up openssh-7.4p1/auth-krb5.c.kuserok openssh-7.4p1/auth-krb5.c +--- openssh-7.4p1/auth-krb5.c.kuserok 2016-12-23 14:36:07.640465939 +0100 ++++ openssh-7.4p1/auth-krb5.c 2016-12-23 14:36:07.644465936 +0100 +@@ -56,6 +56,21 @@ extern ServerOptions options; @@ -38,7 +23,7 @@ index 4910aa38a..b9c261a24 100644 static int krb5_init(void *context) { -@@ -158,8 +173,9 @@ auth_krb5_password(Authctxt *authctxt, const char *password) +@@ -160,8 +175,9 @@ auth_krb5_password(Authctxt *authctxt, c if (problem) goto out; @@ -50,11 +35,10 @@ index 4910aa38a..b9c261a24 100644 problem = -1; goto out; } -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 820f794cf..187faf929 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c -@@ -66,6 +66,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_principal, const char *, const char *, +diff -up openssh-7.4p1/gss-serv-krb5.c.kuserok openssh-7.4p1/gss-serv-krb5.c +--- openssh-7.4p1/gss-serv-krb5.c.kuserok 2016-12-23 14:36:07.640465939 +0100 ++++ openssh-7.4p1/gss-serv-krb5.c 2016-12-23 14:36:07.644465936 +0100 +@@ -67,6 +67,7 @@ static int ssh_gssapi_krb5_cmdok(krb5_pr int); static krb5_context krb_context = NULL; @@ -62,7 +46,7 @@ index 820f794cf..187faf929 100644 /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ -@@ -91,6 +92,103 @@ ssh_gssapi_krb5_init(void) +@@ -92,6 +93,103 @@ ssh_gssapi_krb5_init(void) * Returns true if the user is OK to log in, otherwise returns 0 */ @@ -166,7 +150,7 @@ index 820f794cf..187faf929 100644 static int ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) { -@@ -115,7 +213,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -116,7 +214,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client /* NOTE: .k5login and .k5users must opened as root, not the user, * because if they are on a krb5-protected filesystem, user credentials * to access these files aren't available yet. */ @@ -176,7 +160,7 @@ index 820f794cf..187faf929 100644 retval = 1; logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", name, (char *)client->displayname.value); -@@ -190,9 +289,8 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, +@@ -190,9 +289,8 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); /* If both .k5login and .k5users DNE, self-login is ok. */ if (!k5login_exists && (access(file, F_OK) == -1)) { @@ -188,19 +172,18 @@ index 820f794cf..187faf929 100644 } if ((fp = fopen(file, "r")) == NULL) { int saved_errno = errno; -diff --git a/servconf.c b/servconf.c -index 7bf1507df..8f4b2b43e 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -143,6 +143,7 @@ initialize_server_options(ServerOptions *options) +diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.kuserok 2016-12-23 14:36:07.630465944 +0100 ++++ openssh-7.4p1/servconf.c 2016-12-23 15:11:52.278133344 +0100 +@@ -116,6 +116,7 @@ initialize_server_options(ServerOptions options->gss_strict_acceptor = -1; options->gss_store_rekey = -1; options->gss_kex_algorithms = NULL; + options->use_kuserok = -1; options->password_authentication = -1; options->kbd_interactive_authentication = -1; - options->permit_empty_passwd = -1; -@@ -393,6 +394,8 @@ fill_default_server_options(ServerOptions *options) + options->permit_empty_passwd = -1; +@@ -278,6 +279,8 @@ fill_default_server_options(ServerOption if (options->gss_kex_algorithms == NULL) options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); #endif @@ -209,16 +192,16 @@ index 7bf1507df..8f4b2b43e 100644 if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -561,7 +564,7 @@ typedef enum { - sPort, sHostKeyFile, sLoginGraceTime, - sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, +@@ -399,7 +402,7 @@ typedef enum { + sPort, sHostKeyFile, sLoginGraceTime, + sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, - sKerberosGetAFSToken, sKerberosUniqueCCache, sPasswordAuthentication, + sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication, - sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, - sPrintMotd, sPrintLastLog, sIgnoreRhosts, - sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, -@@ -653,12 +656,14 @@ static struct { + sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, +@@ -478,12 +481,14 @@ static struct { { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, #endif { "kerberosuniqueccache", sKerberosUniqueCCache, SSHCFG_GLOBAL }, @@ -233,18 +216,18 @@ index 7bf1507df..8f4b2b43e 100644 #endif { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, -@@ -2431,6 +2436,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, - } - break; - +@@ -1644,6 +1649,10 @@ process_server_config_line(ServerOptions + } + break; + + case sKerberosUseKuserok: + intptr = &options->use_kuserok; + goto parse_flag; + - case sMatch: - if (cmdline) - fatal("Match directive not supported as a command-line " -@@ -2997,6 +3006,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) + case sMatch: + if (cmdline) + fatal("Match directive not supported as a command-line " +@@ -2016,6 +2025,7 @@ copy_set_server_options(ServerOptions *d M_CP_INTOPT(client_alive_interval); M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); @@ -252,19 +235,18 @@ index 7bf1507df..8f4b2b43e 100644 M_CP_INTOPT(rekey_limit); M_CP_INTOPT(rekey_interval); M_CP_INTOPT(log_level); -@@ -3305,6 +3315,7 @@ dump_config(ServerOptions *o) +@@ -2309,6 +2319,7 @@ dump_config(ServerOptions *o) dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token); # endif dump_cfg_fmtint(sKerberosUniqueCCache, o->kerberos_unique_ccache); + dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); #endif #ifdef GSSAPI - dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); -diff --git a/servconf.h b/servconf.h -index a4a38d6d7..11de36a23 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -151,6 +151,7 @@ typedef struct { + dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); +diff -up openssh-7.4p1/servconf.h.kuserok openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.kuserok 2016-12-23 14:36:07.630465944 +0100 ++++ openssh-7.4p1/servconf.h 2016-12-23 14:36:07.645465936 +0100 +@@ -118,6 +118,7 @@ typedef struct { * authenticated with Kerberos. */ int kerberos_unique_ccache; /* If true, the acquired ticket will * be stored in per-session ccache */ @@ -272,23 +254,10 @@ index a4a38d6d7..11de36a23 100644 int gss_authentication; /* If true, permit GSSAPI authentication */ int gss_keyex; /* If true, permit GSSAPI key exchange */ int gss_cleanup_creds; /* If true, destroy cred cache on logout */ -diff --git a/sshd_config b/sshd_config -index 8db9f0fb1..ea5a878e6 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -75,6 +75,7 @@ AuthorizedKeysFile .ssh/authorized_keys - #KerberosOrLocalPasswd yes - #KerberosTicketCleanup yes - #KerberosGetAFSToken no -+#KerberosUseKuserok yes - - # GSSAPI options - #GSSAPIAuthentication no -diff --git a/sshd_config.5 b/sshd_config.5 -index cae0fd0b4..c360fcfff 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -1040,6 +1040,10 @@ The default value +diff -up openssh-7.4p1/sshd_config.5.kuserok openssh-7.4p1/sshd_config.5 +--- openssh-7.4p1/sshd_config.5.kuserok 2016-12-23 14:36:07.637465940 +0100 ++++ openssh-7.4p1/sshd_config.5 2016-12-23 15:14:03.117162222 +0100 +@@ -850,6 +850,10 @@ Specifies whether to automatically destr .Cm no can lead to overwriting previous tickets by subseqent connections to the same user account. @@ -297,9 +266,9 @@ index cae0fd0b4..c360fcfff 100644 +The default is +.Cm yes . .It Cm KexAlgorithms - Specifies the permitted KEX (Key Exchange) algorithms that the server will - offer to clients. -@@ -1354,6 +1358,7 @@ Available keywords are + Specifies the available KEX (Key Exchange) algorithms. + Multiple algorithms must be comma-separated. +@@ -1078,6 +1082,7 @@ Available keywords are .Cm IPQoS , .Cm KbdInteractiveAuthentication , .Cm KerberosAuthentication , @@ -307,6 +276,14 @@ index cae0fd0b4..c360fcfff 100644 .Cm LogLevel , .Cm MaxAuthTries , .Cm MaxSessions , --- -2.52.0 - +diff -up openssh-7.4p1/sshd_config.kuserok openssh-7.4p1/sshd_config +--- openssh-7.4p1/sshd_config.kuserok 2016-12-23 14:36:07.631465943 +0100 ++++ openssh-7.4p1/sshd_config 2016-12-23 14:36:07.646465935 +0100 +@@ -73,6 +73,7 @@ ChallengeResponseAuthentication no + #KerberosOrLocalPasswd yes + #KerberosTicketCleanup yes + #KerberosGetAFSToken no ++#KerberosUseKuserok yes + + # GSSAPI options + #GSSAPIAuthentication no diff --git a/openssh-6.6p1-privsep-selinux.patch b/openssh-6.6p1-privsep-selinux.patch new file mode 100644 index 0000000..8047fc3 --- /dev/null +++ b/openssh-6.6p1-privsep-selinux.patch @@ -0,0 +1,121 @@ +diff -up openssh-7.4p1/openbsd-compat/port-linux.h.privsep-selinux openssh-7.4p1/openbsd-compat/port-linux.h +--- openssh-7.4p1/openbsd-compat/port-linux.h.privsep-selinux 2016-12-23 18:58:52.972122201 +0100 ++++ openssh-7.4p1/openbsd-compat/port-linux.h 2016-12-23 18:58:52.974122201 +0100 +@@ -23,6 +23,7 @@ void ssh_selinux_setup_pty(char *, const + void ssh_selinux_change_context(const char *); + void ssh_selinux_setfscreatecon(const char *); + ++void sshd_selinux_copy_context(void); + void sshd_selinux_setup_exec_context(char *); + #endif + +diff -up openssh-7.4p1/openbsd-compat/port-linux-sshd.c.privsep-selinux openssh-7.4p1/openbsd-compat/port-linux-sshd.c +--- openssh-7.4p1/openbsd-compat/port-linux-sshd.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100 ++++ openssh-7.4p1/openbsd-compat/port-linux-sshd.c 2016-12-23 18:58:52.974122201 +0100 +@@ -419,6 +419,28 @@ sshd_selinux_setup_exec_context(char *pw + debug3_f("done"); + } + ++void ++sshd_selinux_copy_context(void) ++{ ++ security_context_t *ctx; ++ ++ if (!ssh_selinux_enabled()) ++ return; ++ ++ if (getexeccon((security_context_t *)&ctx) != 0) { ++ logit_f("getexeccon failed with %s", strerror(errno)); ++ return; ++ } ++ if (ctx != NULL) { ++ /* unset exec context before we will lose this capabililty */ ++ if (setexeccon(NULL) != 0) ++ fatal_f("setexeccon failed with %s", strerror(errno)); ++ if (setcon(ctx) != 0) ++ fatal_f("setcon failed with %s", strerror(errno)); ++ freecon(ctx); ++ } ++} ++ + #endif + #endif + +diff -up openssh-7.4p1/session.c.privsep-selinux openssh-7.4p1/session.c +--- openssh-7.4p1/session.c.privsep-selinux 2016-12-19 05:59:41.000000000 +0100 ++++ openssh-7.4p1/session.c 2016-12-23 18:58:52.974122201 +0100 +@@ -1331,7 +1331,7 @@ do_setusercontext(struct passwd *pw) + + platform_setusercontext(pw); + +- if (platform_privileged_uidswap()) { ++ if (platform_privileged_uidswap() && (!is_child || !use_privsep)) { + #ifdef HAVE_LOGIN_CAP + if (setusercontext(lc, pw, pw->pw_uid, + (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { +@@ -1361,6 +1361,9 @@ do_setusercontext(struct passwd *pw) + (unsigned long long)pw->pw_uid); + chroot_path = percent_expand(tmp, "h", pw->pw_dir, + "u", pw->pw_name, "U", uidstr, (char *)NULL); ++#ifdef WITH_SELINUX ++ sshd_selinux_copy_context(); ++#endif + safely_chroot(chroot_path, pw->pw_uid); + free(tmp); + free(chroot_path); +@@ -1396,6 +1399,11 @@ do_setusercontext(struct passwd *pw) + /* Permanently switch to the desired uid. */ + permanently_set_uid(pw); + #endif ++ ++#ifdef WITH_SELINUX ++ if (in_chroot == 0) ++ sshd_selinux_copy_context(); ++#endif + } else if (options.chroot_directory != NULL && + strcasecmp(options.chroot_directory, "none") != 0) { + fatal("server lacks privileges to chroot to ChrootDirectory"); +@@ -1413,9 +1421,6 @@ do_pwchange(Session *s) + if (s->ttyfd != -1) { + fprintf(stderr, + "You must change your password now and login again!\n"); +-#ifdef WITH_SELINUX +- setexeccon(NULL); +-#endif + #ifdef PASSWD_NEEDS_USERNAME + execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name, + (char *)NULL); +@@ -1625,9 +1630,6 @@ do_child(Session *s, const char *command + argv[i] = NULL; + optind = optreset = 1; + __progname = argv[0]; +-#ifdef WITH_SELINUX +- ssh_selinux_change_context("sftpd_t"); +-#endif + exit(sftp_server_main(i, argv, s->pw)); + } + +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 +@@ -540,6 +540,10 @@ privsep_preauth_child(void) + /* Demote the private keys to public keys. */ + demote_sensitive_data(); + ++#ifdef WITH_SELINUX ++ ssh_selinux_change_context("sshd_net_t"); ++#endif ++ + /* 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) { + #endif diff --git a/openssh-6.7p1-coverity.patch b/openssh-6.7p1-coverity.patch new file mode 100644 index 0000000..01a061b --- /dev/null +++ b/openssh-6.7p1-coverity.patch @@ -0,0 +1,264 @@ +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 +@@ -426,6 +426,7 @@ ssh_krb5_cc_new_unique(krb5_context ctx, + umask(old_umask); + if (tmpfd == -1) { + logit("mkstemp(): %.100s", strerror(oerrno)); ++ free(ccname); + return oerrno; + } + +@@ -433,6 +434,7 @@ ssh_krb5_cc_new_unique(krb5_context ctx, + oerrno = errno; + logit("fchmod(): %.100s", strerror(oerrno)); + close(tmpfd); ++ free(ccname); + return oerrno; + } + /* make sure the KRB5CCNAME is set for non-standard location */ +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 +@@ -167,8 +167,9 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup + enclen = __b64_ntop(digest, + ssh_digest_bytes(SSH_DIGEST_MD5), encoded, + ssh_digest_bytes(SSH_DIGEST_MD5) * 2); +- ++#pragma GCC diagnostic ignored "-Wstringop-overflow" + cp = strncpy(s, kex, strlen(kex)); ++#pragma 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 +@@ -1261,6 +1262,7 @@ is_key_revoked(struct ssh_krl *krl, cons + return r; + erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); + free(rb.blob); ++ rb.blob = NULL; /* make coverity happy */ + if (erb != NULL) { + KRL_DBG(("revoked by key SHA1")); + return SSH_ERR_KEY_REVOKED; +@@ -1271,6 +1273,7 @@ is_key_revoked(struct ssh_krl *krl, cons + return r; + erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb); + free(rb.blob); ++ rb.blob = NULL; /* make coverity happy */ + if (erb != NULL) { + KRL_DBG(("revoked by key SHA256")); + return SSH_ERR_KEY_REVOKED; +@@ -1282,6 +1285,7 @@ is_key_revoked(struct ssh_krl *krl, cons + return r; + erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); + free(rb.blob); ++ rb.blob = NULL; /* make coverity happy */ + if (erb != NULL) { + KRL_DBG(("revoked by explicit key")); + return SSH_ERR_KEY_REVOKED; +diff -up openssh-8.5p1/loginrec.c.coverity openssh-8.5p1/loginrec.c +--- openssh-8.5p1/loginrec.c.coverity 2021-03-24 13:18:53.793225885 +0100 ++++ openssh-8.5p1/loginrec.c 2021-03-24 13:21:27.948404751 +0100 +@@ -690,9 +690,11 @@ construct_utmp(struct logininfo *li, + */ + + /* Use strncpy because we don't necessarily want null termination */ ++ /* coverity[buffer_size_warning : FALSE] */ + strncpy(ut->ut_name, li->username, + MIN_SIZEOF(ut->ut_name, li->username)); + # ifdef HAVE_HOST_IN_UTMP ++ /* coverity[buffer_size_warning : FALSE] */ + 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 +@@ -1425,6 +1425,8 @@ sanitise_stdfd(void) + } + if (nullfd > STDERR_FILENO) + close(nullfd); ++ /* coverity[leaked_handle : FALSE]*/ ++ /* coverity[leaked_handle : FALSE]*/ + } + + char * +@@ -2511,6 +2513,7 @@ stdfd_devnull(int do_stdin, int do_stdou + } + if (devnull > STDERR_FILENO) + close(devnull); ++ /* coverity[leaked_handle : FALSE]*/ + return ret; + } + +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 +@@ -411,7 +411,7 @@ monitor_child_preauth(Authctxt *_authctx + mm_get_keystate(ssh, pmonitor); + + /* Drain any buffered messages from the child */ +- while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0) ++ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) + ; + + if (pmonitor->m_recvfd >= 0) +@@ -1678,7 +1678,7 @@ mm_answer_pty(struct ssh *ssh, int sock, + s->ptymaster = s->ptyfd; + + debug3_f("tty %s ptyfd %d", s->tty, s->ttyfd); +- ++ /* coverity[leaked_handle : FALSE] */ + return (0); + + error: +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 +@@ -58,7 +58,7 @@ bindresvport_sa(int sd, struct sockaddr + struct sockaddr_in6 *in6; + u_int16_t *portp; + u_int16_t port; +- socklen_t salen; ++ socklen_t salen = sizeof(struct sockaddr_storage); + int i; + + if (sa == NULL) { +diff -up openssh-8.7p1/openbsd-compat/bsd-pselect.c.coverity openssh-8.7p1/openbsd-compat/bsd-pselect.c +--- openssh-8.7p1/openbsd-compat/bsd-pselect.c.coverity 2021-08-30 16:36:11.357288009 +0200 ++++ openssh-8.7p1/openbsd-compat/bsd-pselect.c 2021-08-30 16:37:21.791897976 +0200 +@@ -113,13 +113,13 @@ pselect_notify_setup(void) + static void + pselect_notify_parent(void) + { +- if (notify_pipe[1] != -1) ++ if (notify_pipe[1] >= 0) + (void)write(notify_pipe[1], "", 1); + } + static void + pselect_notify_prepare(fd_set *readset) + { +- if (notify_pipe[0] != -1) ++ if (notify_pipe[0] >= 0) + FD_SET(notify_pipe[0], readset); + } + static void +@@ -127,8 +127,8 @@ pselect_notify_done(fd_set *readset) + { + char c; + +- if (notify_pipe[0] != -1 && FD_ISSET(notify_pipe[0], readset)) { +- while (read(notify_pipe[0], &c, 1) != -1) ++ if (notify_pipe[0] >= 0 && FD_ISSET(notify_pipe[0], readset)) { ++ while (read(notify_pipe[0], &c, 1) >= 0) + debug2_f("reading"); + FD_CLR(notify_pipe[0], readset); + } +diff -up openssh-8.5p1/readconf.c.coverity openssh-8.5p1/readconf.c +--- openssh-8.5p1/readconf.c.coverity 2021-03-24 12:03:33.778968131 +0100 ++++ openssh-8.5p1/readconf.c 2021-03-24 12:03:33.785968180 +0100 +@@ -1847,6 +1847,7 @@ parse_pubkey_algos: + } else if (r != 0) { + error("%.200s line %d: glob failed for %s.", + filename, linenum, arg2); ++ free(arg2); + goto out; + } + free(arg2); +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 +@@ -1638,8 +1638,9 @@ process_server_config_line(ServerOptions + if (*activep && *charptr == NULL) { + *charptr = tilde_expand_filename(arg, getuid()); + /* increase optional counter */ +- if (intptr != NULL) +- *intptr = *intptr + 1; ++ /* DEAD CODE intptr is still NULL ;) ++ if (intptr != NULL) ++ *intptr = *intptr + 1; */ + } + break; + +diff -up openssh-8.7p1/serverloop.c.coverity openssh-8.7p1/serverloop.c +--- openssh-8.7p1/serverloop.c.coverity 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/serverloop.c 2021-08-30 16:28:22.416226981 +0200 +@@ -547,7 +547,7 @@ server_request_tun(struct ssh *ssh) + debug_f("invalid tun"); + goto done; + } +- if (auth_opts->force_tun_device != -1) { ++ if (auth_opts->force_tun_device >= 0) { + if (tun != SSH_TUNID_ANY && + auth_opts->force_tun_device != (int)tun) + goto done; +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 +@@ -869,6 +869,7 @@ sanitize_pkcs11_provider(const char *pro + + if (pkcs11_uri_parse(provider, uri) != 0) { + error("Failed to parse PKCS#11 URI"); ++ pkcs11_uri_cleanup(uri); + return NULL; + } + /* validate also provider from URI */ +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 +@@ -691,8 +691,10 @@ privsep_preauth(Authctxt *authctxt) + + privsep_preauth_child(ssh); + setproctitle("%s", "[net]"); +- if (box != NULL) ++ if (box != NULL) { + ssh_sandbox_child(box); ++ free(box); ++ } + + return 0; + } +@@ -2519,8 +2524,11 @@ do_ssh2_kex(struct ssh *ssh) + + if (newstr) + myproposal[PROPOSAL_KEX_ALGS] = newstr; +- else ++ else { + fatal("No supported key exchange algorithms"); ++ free(gss); ++ } ++ /* coverity[leaked_storage: FALSE]*/ + } + #endif + +diff -up openssh-8.5p1/ssh-keygen.c.coverity openssh-8.5p1/ssh-keygen.c +--- openssh-8.5p1/ssh-keygen.c.coverity 2021-03-24 12:03:33.780968145 +0100 ++++ openssh-8.5p1/ssh-keygen.c 2021-03-24 12:03:33.787968194 +0100 +@@ -2332,6 +2332,9 @@ update_krl_from_file(struct passwd *pw, + r = ssh_krl_revoke_key_sha256(krl, blob, blen); + if (r != 0) + fatal_fr(r, "revoke key failed"); ++ freezero(blob, blen); ++ blob = NULL; ++ blen = 0; + } else { + if (strncasecmp(cp, "key:", 4) == 0) { + cp += 4; diff --git a/0021-openssh-6.7p1-sftp-force-permission.patch b/openssh-6.7p1-sftp-force-permission.patch similarity index 72% rename from 0021-openssh-6.7p1-sftp-force-permission.patch rename to openssh-6.7p1-sftp-force-permission.patch index 737430d..1cfa309 100644 --- a/0021-openssh-6.7p1-sftp-force-permission.patch +++ b/openssh-6.7p1-sftp-force-permission.patch @@ -1,17 +1,6 @@ -From 57ae33c2f43425725345c910d90ef6fed75d3b85 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 21/53] openssh-6.7p1-sftp-force-permission - ---- - sftp-server.8 | 7 +++++++ - sftp-server.c | 24 ++++++++++++++++++++++-- - 2 files changed, 29 insertions(+), 2 deletions(-) - -diff --git a/sftp-server.8 b/sftp-server.8 -index 5311bf929..5e6e3aa44 100644 ---- a/sftp-server.8 -+++ b/sftp-server.8 +diff -up openssh-7.2p2/sftp-server.8.sftp-force-mode openssh-7.2p2/sftp-server.8 +--- openssh-7.2p2/sftp-server.8.sftp-force-mode 2016-03-09 19:04:48.000000000 +0100 ++++ openssh-7.2p2/sftp-server.8 2016-06-23 16:18:20.463854117 +0200 @@ -38,6 +38,7 @@ .Op Fl P Ar denied_requests .Op Fl p Ar allowed_requests @@ -33,11 +22,10 @@ index 5311bf929..5e6e3aa44 100644 .El .Pp On some systems, -diff --git a/sftp-server.c b/sftp-server.c -index 185ad1459..e04fc63b3 100644 ---- a/sftp-server.c -+++ b/sftp-server.c -@@ -72,6 +72,10 @@ struct sshbuf *oqueue; +diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c +--- openssh-7.2p2/sftp-server.c.sftp-force-mode 2016-06-23 16:18:20.446854128 +0200 ++++ openssh-7.2p2/sftp-server.c 2016-06-23 16:20:37.950766082 +0200 +@@ -69,6 +69,10 @@ struct sshbuf *oqueue; /* Version of client */ static u_int version; @@ -48,7 +36,7 @@ index 185ad1459..e04fc63b3 100644 /* SSH2_FXP_INIT received */ static int init_done; -@@ -741,6 +745,7 @@ process_open(u_int32_t id) +@@ -683,6 +687,7 @@ process_open(u_int32_t id) Attrib a; char *name; int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE; @@ -56,7 +44,7 @@ index 185ad1459..e04fc63b3 100644 if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || (r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */ -@@ -750,6 +755,10 @@ process_open(u_int32_t id) +@@ -692,6 +697,10 @@ process_open(u_int32_t id) debug3("request %u: open flags %d", id, pflags); flags = flags_from_portable(pflags); mode = (a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) ? a.perm : 0666; @@ -67,7 +55,7 @@ index 185ad1459..e04fc63b3 100644 logit("open \"%s\" flags %s mode 0%o", name, string_from_portable(pflags), mode); if (readonly && -@@ -771,6 +780,8 @@ process_open(u_int32_t id) +@@ -713,6 +722,8 @@ process_open(u_int32_t id) } } } @@ -76,7 +64,7 @@ index 185ad1459..e04fc63b3 100644 if (status != SSH2_FX_OK) send_status(id, status); free(name); -@@ -1890,7 +1901,7 @@ sftp_server_usage(void) +@@ -1494,7 +1505,7 @@ sftp_server_usage(void) fprintf(stderr, "usage: %s [-ehR] [-d start_directory] [-f log_facility] " "[-l log_level]\n\t[-P denied_requests] " @@ -85,7 +73,7 @@ index 185ad1459..e04fc63b3 100644 " %s -Q protocol_feature\n", __progname, __progname); exit(1); -@@ -1914,7 +1925,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handle +@@ -1520,7 +1531,7 @@ sftp_server_main(int argc, char **argv, pw = pwcopy(user_pw); while (!skipargs && (ch = getopt(argc, argv, @@ -94,7 +82,7 @@ index 185ad1459..e04fc63b3 100644 switch (ch) { case 'Q': if (strcasecmp(optarg, "requests") != 0) { -@@ -1976,6 +1987,15 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handle +@@ -1580,6 +1591,15 @@ sftp_server_main(int argc, char **argv, fatal("Invalid umask \"%s\"", optarg); (void)umask((mode_t)mask); break; @@ -110,6 +98,3 @@ index 185ad1459..e04fc63b3 100644 case 'h': default: sftp_server_usage(); --- -2.52.0 - diff --git a/openssh-6.8p1-sshdT-output.patch b/openssh-6.8p1-sshdT-output.patch new file mode 100644 index 0000000..156e66d --- /dev/null +++ b/openssh-6.8p1-sshdT-output.patch @@ -0,0 +1,12 @@ +diff -up openssh/servconf.c.sshdt openssh/servconf.c +--- openssh/servconf.c.sshdt 2015-06-24 11:42:29.041078704 +0200 ++++ openssh/servconf.c 2015-06-24 11:44:39.734745802 +0200 +@@ -2317,7 +2317,7 @@ dump_config(ServerOptions *o) + dump_cfg_string(sXAuthLocation, o->xauth_location); + dump_cfg_string(sCiphers, o->ciphers); + dump_cfg_string(sMacs, o->macs); +- dump_cfg_string(sBanner, o->banner); ++ dump_cfg_string(sBanner, o->banner != NULL ? o->banner : "none"); + dump_cfg_string(sForceCommand, o->adm_forced_command); + dump_cfg_string(sChrootDirectory, o->chroot_directory); + dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys); diff --git a/0036-openssh-7.1p2-audit-race-condition.patch b/openssh-7.1p2-audit-race-condition.patch similarity index 70% rename from 0036-openssh-7.1p2-audit-race-condition.patch rename to openssh-7.1p2-audit-race-condition.patch index 863f700..b5895f7 100644 --- a/0036-openssh-7.1p2-audit-race-condition.patch +++ b/openssh-7.1p2-audit-race-condition.patch @@ -1,19 +1,7 @@ -From ffa3fdb2ad2c7afc91993d9301e35d2e9a83ea47 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 36/53] openssh-7.1p2-audit-race-condition - ---- - monitor_wrap.c | 46 +++++++++++++++++++++++++++++++++++++ - monitor_wrap.h | 2 ++ - session.c | 61 ++++++++++++++++++++++++++++++++++++++++++++------ - 3 files changed, 102 insertions(+), 7 deletions(-) - -diff --git a/monitor_wrap.c b/monitor_wrap.c -index fb44ae733..17a6c9786 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -1426,4 +1426,50 @@ mm_audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_ +diff -up openssh-7.4p1/monitor_wrap.c.audit-race openssh-7.4p1/monitor_wrap.c +--- openssh-7.4p1/monitor_wrap.c.audit-race 2016-12-23 16:35:52.694685771 +0100 ++++ openssh-7.4p1/monitor_wrap.c 2016-12-23 16:35:52.697685772 +0100 +@@ -1107,4 +1107,50 @@ mm_audit_destroy_sensitive_data(const ch mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m); sshbuf_free(m); } @@ -64,11 +52,10 @@ index fb44ae733..17a6c9786 100644 + pmonitor->m_recvfd = fd; +} #endif /* SSH_AUDIT_EVENTS */ -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 1bcbfd305..2b814dbd1 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -97,6 +97,8 @@ void mm_audit_unsupported_body(struct ssh *, int); +diff -up openssh-7.4p1/monitor_wrap.h.audit-race openssh-7.4p1/monitor_wrap.h +--- openssh-7.4p1/monitor_wrap.h.audit-race 2016-12-23 16:35:52.694685771 +0100 ++++ openssh-7.4p1/monitor_wrap.h 2016-12-23 16:35:52.698685772 +0100 +@@ -83,6 +83,8 @@ void mm_audit_unsupported_body(int); void mm_audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); void mm_audit_session_key_free_body(struct ssh *, int, pid_t, uid_t); void mm_audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); @@ -77,11 +64,10 @@ index 1bcbfd305..2b814dbd1 100644 #endif struct Session; -diff --git a/session.c b/session.c -index 107edcf91..80282dfd8 100644 ---- a/session.c -+++ b/session.c -@@ -161,6 +161,10 @@ static Session *sessions = NULL; +diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c +--- openssh-7.4p1/session.c.audit-race 2016-12-23 16:35:52.695685771 +0100 ++++ openssh-7.4p1/session.c 2016-12-23 16:37:26.339730596 +0100 +@@ -162,6 +162,10 @@ static Session *sessions = NULL; login_cap_t *lc; #endif @@ -92,7 +78,7 @@ index 107edcf91..80282dfd8 100644 static int is_child = 0; static int in_chroot = 0; static int have_dev_log = 1; -@@ -358,6 +362,8 @@ xauth_valid_string(const char *s) +@@ -289,6 +293,8 @@ xauth_valid_string(const char *s) return 1; } @@ -101,7 +87,7 @@ index 107edcf91..80282dfd8 100644 #define USE_PIPES 1 /* * This is called to fork and execute a command when we have no tty. This -@@ -481,6 +487,8 @@ do_exec_no_pty(struct ssh *ssh, Session *s, const char *command) +@@ -424,6 +430,8 @@ do_exec_no_pty(Session *s, const char *c close(err[0]); #endif @@ -110,7 +96,7 @@ index 107edcf91..80282dfd8 100644 /* Do processing for the child (exec command etc). */ do_child(ssh, s, command); /* NOTREACHED */ -@@ -595,6 +603,9 @@ do_exec_pty(struct ssh *ssh, Session *s, const char *command) +@@ -547,6 +555,9 @@ do_exec_pty(Session *s, const char *comm /* Close the extra descriptor for the pseudo tty. */ close(ttyfd); @@ -120,22 +106,22 @@ index 107edcf91..80282dfd8 100644 /* record login, etc. similar to login(1) */ #ifndef HAVE_OSF_SIA do_login(ssh, s, command); -@@ -729,6 +740,8 @@ do_exec(struct ssh *ssh, Session *s, const char *command) +@@ -717,6 +728,8 @@ do_exec(Session *s, const char *command) } if (s->command != NULL && s->ptyfd == -1) - s->command_handle = mm_audit_run_command(ssh, s->command); + s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); + if (pipe(paudit) < 0) + fatal("pipe: %s", strerror(errno)); #endif if (s->ttyfd != -1) ret = do_exec_pty(ssh, s, command); -@@ -744,6 +757,20 @@ do_exec(struct ssh *ssh, Session *s, const char *command) +@@ -732,6 +745,20 @@ do_exec(Session *s, const char *command) */ sshbuf_reset(loginmsg); +#ifdef SSH_AUDIT_EVENTS + close(paudit[1]); -+ if (ret == 0) { ++ if (use_privsep && ret == 0) { + /* + * Read the audit messages from forked child and send them + * back to monitor. We don't want to communicate directly, @@ -150,7 +136,7 @@ index 107edcf91..80282dfd8 100644 return ret; } -@@ -1490,6 +1517,33 @@ child_close_fds(struct ssh *ssh) +@@ -1538,6 +1565,34 @@ child_close_fds(void) log_redirect_stderr_to(NULL); } @@ -161,11 +147,12 @@ index 107edcf91..80282dfd8 100644 + int pparent = paudit[1]; + close(paudit[0]); + /* Hack the monitor pipe to avoid race condition with parent */ -+ mm_set_monitor_pipe(pparent); ++ if (use_privsep) ++ mm_set_monitor_pipe(pparent); +#endif + + /* remove hostkey from the child's memory */ -+ /* FIXME beldmit destroy_sensitive_data(ssh); */ ++ destroy_sensitive_data(ssh, use_privsep); + /* + * We can audit this, because we hacked the pipe to direct the + * messages over postauth child. But this message requires answer @@ -184,12 +171,12 @@ index 107edcf91..80282dfd8 100644 /* * Performs common processing for the child, such as setting up the * environment, closing extra file descriptors, setting the user and group -@@ -1507,13 +1561,6 @@ do_child(struct ssh *ssh, Session *s, const char *command) +@@ -1554,13 +1608,6 @@ do_child(Session *s, const char *command sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); -- /* remove keys from memory */ -- destroy_sensitive_data(ssh); +- /* remove hostkey from the child's memory */ +- destroy_sensitive_data(ssh, 1); - 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. */ @@ -198,6 +185,3 @@ index 107edcf91..80282dfd8 100644 /* Force a password change */ if (s->authctxt->force_pwchange) { do_setusercontext(pw); --- -2.52.0 - diff --git a/0014-openssh-7.2p2-k5login_directory.patch b/openssh-7.2p2-k5login_directory.patch similarity index 74% rename from 0014-openssh-7.2p2-k5login_directory.patch rename to openssh-7.2p2-k5login_directory.patch index fa07e55..80e7678 100644 --- a/0014-openssh-7.2p2-k5login_directory.patch +++ b/openssh-7.2p2-k5login_directory.patch @@ -1,20 +1,8 @@ -From 0b19c3dabb1e23837238e90238f1ab5fa3c99df8 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 14/53] openssh-7.2p2-k5login_directory - ---- - auth-krb5.c | 16 ++++++++++++++++ - auth.h | 2 ++ - gss-serv-krb5.c | 21 ++++++++++++++++++++- - sshd.8 | 4 ++++ - 4 files changed, 42 insertions(+), 1 deletion(-) - diff --git a/auth-krb5.c b/auth-krb5.c -index 035032221..4910aa38a 100644 +index 2b02a04..19b9364 100644 --- a/auth-krb5.c +++ b/auth-krb5.c -@@ -465,5 +465,21 @@ ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environm +@@ -375,5 +375,21 @@ cleanup: return (krb5_cc_resolve(ctx, ccname, ccache)); } } @@ -37,10 +25,10 @@ index 035032221..4910aa38a 100644 #endif /* !HEIMDAL */ #endif /* KRB5 */ diff --git a/auth.h b/auth.h -index 10e88e11f..391630350 100644 +index f9d191c..c432d2f 100644 --- a/auth.h +++ b/auth.h -@@ -247,6 +247,8 @@ int sys_auth_passwd(struct ssh *, const char *); +@@ -222,6 +222,8 @@ int sys_auth_passwd(Authctxt *, const char *); #if defined(KRB5) && !defined(HEIMDAL) krb5_error_code ssh_krb5_cc_new_unique(krb5_context, krb5_ccache *, int *); @@ -50,10 +38,10 @@ index 10e88e11f..391630350 100644 #endif /* AUTH_H */ diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index df55512d3..820f794cf 100644 +index a7c0c5f..df8cc9a 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c -@@ -144,8 +144,27 @@ ssh_gssapi_k5login_exists() +@@ -244,8 +244,27 @@ ssh_gssapi_k5login_exists() { char file[MAXPATHLEN]; struct passwd *pw = the_authctxt->pw; @@ -83,10 +71,10 @@ index df55512d3..820f794cf 100644 } diff --git a/sshd.8 b/sshd.8 -index e2d8ff003..fa33f5232 100644 +index 5c4f15b..135e290 100644 --- a/sshd.8 +++ b/sshd.8 -@@ -880,6 +880,10 @@ rlogin/rsh. +@@ -806,6 +806,10 @@ rlogin/rsh. These files enforce GSSAPI/Kerberos authentication access control. Further details are described in .Xr ksu 1 . @@ -97,6 +85,3 @@ index e2d8ff003..fa33f5232 100644 .Pp .It Pa ~/.ssh/ This directory is the default location for all user-specific configuration --- -2.52.0 - diff --git a/0022-openssh-7.2p2-s390-closefrom.patch b/openssh-7.2p2-s390-closefrom.patch similarity index 66% rename from 0022-openssh-7.2p2-s390-closefrom.patch rename to openssh-7.2p2-s390-closefrom.patch index fa59fd6..363538c 100644 --- a/0022-openssh-7.2p2-s390-closefrom.patch +++ b/openssh-7.2p2-s390-closefrom.patch @@ -1,17 +1,21 @@ -From 25b593f41fa85bcaf1bbdc9c368325c4af033208 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 22/53] openssh-7.2p2-s390-closefrom +Zseries only: Leave the hardware filedescriptors open. + +All filedescriptors above 2 are getting closed when a new +sshd process to handle a new client connection is +spawned. As the process also chroot into an empty filesystem +without any device nodes, there is no chance to reopen the +files. This patch filters out the reqired fds in the +closefrom function so these are skipped in the close loop. + +Author: Harald Freudenberger --- - openbsd-compat/bsd-closefrom.c | 26 ++++++++++++++++++++++++++ + openbsd-compat/bsd-closefrom.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) -diff --git a/openbsd-compat/bsd-closefrom.c b/openbsd-compat/bsd-closefrom.c -index 49a4f35ff..f61124585 100644 --- a/openbsd-compat/bsd-closefrom.c +++ b/openbsd-compat/bsd-closefrom.c -@@ -140,7 +140,33 @@ closefrom(int lowfd) +@@ -82,7 +82,33 @@ closefrom(int lowfd) fd = strtol(dent->d_name, &endp, 10); if (dent->d_name != endp && *endp == '\0' && fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) @@ -45,6 +49,4 @@ index 49a4f35ff..f61124585 100644 } (void) closedir(dirp); return; --- -2.52.0 diff --git a/0006-openssh-7.2p2-x11.patch b/openssh-7.2p2-x11.patch similarity index 69% rename from 0006-openssh-7.2p2-x11.patch rename to openssh-7.2p2-x11.patch index dceef7b..b27d7c4 100644 --- a/0006-openssh-7.2p2-x11.patch +++ b/openssh-7.2p2-x11.patch @@ -1,32 +1,22 @@ -From d6dc5be6e969ecffe30b9972706b3c92d930d81f Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 06/53] openssh-7.2p2-x11 - ---- - channels.c | 25 +++++++++++++++++++------ - 1 file changed, 19 insertions(+), 6 deletions(-) - diff --git a/channels.c b/channels.c -index 80014ff34..5ce6bd400 100644 ---- a/channels.c -+++ b/channels.c -@@ -5169,11 +5169,13 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, +--- 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; + ++ if (len <= 0) ++ return -1; sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock == -1) { error("socket: %.100s", strerror(errno)); -@@ -5181,11 +5183,12 @@ connect_local_xsocket_path(const char *pathname) +@@ -5087,11 +5089,12 @@ } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; @@ -41,8 +31,8 @@ index 80014ff34..5ce6bd400 100644 - error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); return -1; } - -@@ -5193,8 +5196,18 @@ static int + +@@ -5099,8 +5102,18 @@ connect_local_xsocket(u_int dnr) { char buf[1024]; @@ -63,6 +53,3 @@ index 80014ff34..5ce6bd400 100644 } #ifdef __APPLE__ --- -2.52.0 - diff --git a/0051-openssh-7.3p1-x11-max-displays.patch b/openssh-7.3p1-x11-max-displays.patch similarity index 52% rename from 0051-openssh-7.3p1-x11-max-displays.patch rename to openssh-7.3p1-x11-max-displays.patch index 422107c..2b702d4 100644 --- a/0051-openssh-7.3p1-x11-max-displays.patch +++ b/openssh-7.3p1-x11-max-displays.patch @@ -1,22 +1,18 @@ -From 763c65f6f349a7bab344a58991246891700e4fa0 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Fri, 12 Dec 2025 15:35:14 +0100 -Subject: [PATCH 51/53] openssh-7.3p1-x11-max-displays - ---- - channels.c | 9 ++++++--- - channels.h | 2 +- - servconf.c | 12 +++++++++++- - servconf.h | 2 ++ - session.c | 5 +++-- - sshd_config.5 | 7 +++++++ - 6 files changed, 30 insertions(+), 7 deletions(-) - -diff --git a/channels.c b/channels.c -index 26ed9945f..c26380e25 100644 ---- a/channels.c -+++ b/channels.c -@@ -5067,7 +5067,7 @@ rdynamic_connect_finish(struct ssh *ssh, Channel *c) +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 "*" + + /* -- X11 forwarding */ +-/* Maximum number of fake X11 displays to try. */ +-#define MAX_DISPLAYS 1000 ++/* Minimum port number for X11 forwarding */ ++#define X11_PORT_MIN 6000 + + /* 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 x11_create_display_inet(struct ssh *ssh, int x11_display_offset, @@ -25,33 +21,66 @@ index 26ed9945f..c26380e25 100644 u_int *display_numberp, int **chanids) { Channel *nc = NULL; -@@ -5080,8 +5080,11 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, - x11_display_offset > UINT16_MAX - X11_BASE_PORT - MAX_DISPLAYS) +@@ -4240,10 +4241,15 @@ x11_create_display_inet(int x11_display_ + if (chanids == NULL) return -1; + /* Try to bind ports starting at 6000+X11DisplayOffset */ + x11_max_displays = x11_max_displays + x11_display_offset; + for (display_number = x11_display_offset; -- display_number < x11_display_offset + MAX_DISPLAYS; +- display_number < MAX_DISPLAYS; + display_number < x11_max_displays; display_number++) { - port = X11_BASE_PORT + display_number; +- port = 6000 + display_number; ++ port = X11_PORT_MIN + display_number; ++ if (port < X11_PORT_MIN) /* overflow */ ++ break; memset(&hints, 0, sizeof(hints)); -@@ -5146,7 +5149,7 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, + hints.ai_family = ssh->chanctxt->IPv4or6; + hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; +@@ -4295,7 +4301,7 @@ x11_create_display_inet(int x11_display_ if (num_socks > 0) break; } -- if (display_number >= x11_display_offset + MAX_DISPLAYS) { -+ if (display_number >= x11_max_displays || port < X11_BASE_PORT ) { +- if (display_number >= MAX_DISPLAYS) { ++ if (display_number >= x11_max_displays || port < X11_PORT_MIN ) { error("Failed to allocate internet-domain X11 display socket."); return -1; } -diff --git a/channels.h b/channels.h -index 7456541f8..754bd98ee 100644 ---- a/channels.h -+++ b/channels.h -@@ -389,7 +389,7 @@ int permitopen_port(const char *); +@@ -4441,7 +4447,7 @@ x11_connect_display(void) + memset(&hints, 0, sizeof(hints)); + hints.ai_family = ssh->chanctxt->IPv4or6; + hints.ai_socktype = SOCK_STREAM; +- snprintf(strport, sizeof strport, "%u", 6000 + display_number); ++ snprintf(strport, sizeof strport, "%u", X11_PORT_MIN + display_number); + if ((gaierr = getaddrinfo(buf, strport, &hints, &aitop)) != 0) { + error("%.100s: unknown host. (%s)", buf, + ssh_gai_strerror(gaierr)); +@@ -4457,7 +4463,7 @@ x11_connect_display(void) + /* Connect it to the display. */ + if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1) { + debug2("connect %.100s port %u: %.100s", buf, +- 6000 + display_number, strerror(errno)); ++ X11_PORT_MIN + display_number, strerror(errno)); + close(sock); + continue; + } +@@ -4466,8 +4472,8 @@ x11_connect_display(void) + } + freeaddrinfo(aitop); + if (!ai) { +- error("connect %.100s port %u: %.100s", buf, +- 6000 + display_number, strerror(errno)); ++ error("connect %.100s port %u: %.100s", buf, ++ X11_PORT_MIN + display_number, strerror(errno)); + return -1; + } + set_nodelay(sock); +diff -up openssh-7.4p1/channels.h.x11max openssh-7.4p1/channels.h +--- openssh-7.4p1/channels.h.x11max 2016-12-19 05:59:41.000000000 +0100 ++++ 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 *, time_t); int x11_connect_display(struct ssh *); @@ -59,12 +88,11 @@ index 7456541f8..754bd98ee 100644 +int x11_create_display_inet(struct ssh *, int, int, int, int, u_int *, int **); void x11_request_forwarding_with_spoofing(struct ssh *, int, const char *, const char *, const char *, int); - int x11_channel_used_recently(struct ssh *ssh); -diff --git a/servconf.c b/servconf.c -index fb1d150cd..956205f6d 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -118,6 +118,7 @@ initialize_server_options(ServerOptions *options) + +diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c +--- openssh-7.4p1/servconf.c.x11max 2016-12-23 15:46:32.133506635 +0100 ++++ openssh-7.4p1/servconf.c 2016-12-23 15:47:27.320519121 +0100 +@@ -95,6 +95,7 @@ initialize_server_options(ServerOptions options->print_lastlog = -1; options->x11_forwarding = -1; options->x11_display_offset = -1; @@ -72,7 +100,7 @@ index fb1d150cd..956205f6d 100644 options->x11_use_localhost = -1; options->permit_tty = -1; options->permit_user_rc = -1; -@@ -357,6 +358,8 @@ fill_default_server_options(ServerOptions *options) +@@ -243,6 +244,8 @@ fill_default_server_options(ServerOption options->x11_forwarding = 0; if (options->x11_display_offset == -1) options->x11_display_offset = 10; @@ -81,16 +109,16 @@ index fb1d150cd..956205f6d 100644 if (options->x11_use_localhost == -1) options->x11_use_localhost = 1; if (options->xauth_location == NULL) -@@ -582,7 +585,7 @@ typedef enum { - sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication, - sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, - sPrintMotd, sPrintLastLog, sIgnoreRhosts, +@@ -419,7 +422,7 @@ typedef enum { + sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication, + sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, - sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, + sX11Forwarding, sX11DisplayOffset, sX11MaxDisplays, sX11UseLocalhost, sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, sPermitUserEnvironment, sAllowTcpForwarding, sCompression, sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, -@@ -725,6 +728,7 @@ static struct { +@@ -540,6 +543,7 @@ static struct { { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL }, { "x11forwarding", sX11Forwarding, SSHCFG_ALL }, { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL }, @@ -98,7 +126,7 @@ index fb1d150cd..956205f6d 100644 { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, { "strictmodes", sStrictModes, SSHCFG_GLOBAL }, -@@ -1775,6 +1779,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, +@@ -1316,6 +1320,10 @@ process_server_config_line(ServerOptions *intptr = value; break; @@ -109,7 +137,7 @@ index fb1d150cd..956205f6d 100644 case sX11UseLocalhost: intptr = &options->x11_use_localhost; goto parse_flag; -@@ -3037,6 +3045,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) +@@ -2063,6 +2071,7 @@ copy_set_server_options(ServerOptions *d M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); M_CP_INTOPT(x11_display_offset); M_CP_INTOPT(x11_forwarding); @@ -117,7 +145,7 @@ index fb1d150cd..956205f6d 100644 M_CP_INTOPT(x11_use_localhost); M_CP_INTOPT(permit_tty); M_CP_INTOPT(permit_user_rc); -@@ -3332,6 +3341,7 @@ dump_config(ServerOptions *o) +@@ -2315,6 +2324,7 @@ dump_config(ServerOptions *o) #endif dump_cfg_int(sLoginGraceTime, o->login_grace_time); dump_cfg_int(sX11DisplayOffset, o->x11_display_offset); @@ -125,11 +153,10 @@ index fb1d150cd..956205f6d 100644 dump_cfg_int(sMaxAuthTries, o->max_authtries); dump_cfg_int(sMaxSessions, o->max_sessions); dump_cfg_int(sClientAliveInterval, o->client_alive_interval); -diff --git a/servconf.h b/servconf.h -index 9b1a73b8d..6bfdf6305 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -38,6 +38,7 @@ +diff -up openssh-7.4p1/servconf.h.x11max openssh-7.4p1/servconf.h +--- openssh-7.4p1/servconf.h.x11max 2016-12-23 15:46:32.133506635 +0100 ++++ openssh-7.4p1/servconf.h 2016-12-23 15:46:32.140506636 +0100 +@@ -55,6 +55,7 @@ #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ #define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ @@ -137,7 +164,7 @@ index 9b1a73b8d..6bfdf6305 100644 /* Magic name for internal sftp-server */ #define INTERNAL_SFTP_NAME "internal-sftp" -@@ -114,6 +115,7 @@ typedef struct { +@@ -85,6 +86,7 @@ typedef struct { int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */ int x11_display_offset; /* What DISPLAY number to start * searching at */ @@ -145,14 +172,13 @@ index 9b1a73b8d..6bfdf6305 100644 int x11_use_localhost; /* If true, use localhost for fake X11 server. */ char *xauth_location; /* Location of xauth program */ int permit_tty; /* If false, deny pty allocation */ -diff --git a/session.c b/session.c -index 80282dfd8..e53d044a0 100644 ---- a/session.c -+++ b/session.c -@@ -2681,8 +2681,9 @@ session_setup_x11fwd(struct ssh *ssh, Session *s) +diff -up openssh-7.4p1/session.c.x11max openssh-7.4p1/session.c +--- openssh-7.4p1/session.c.x11max 2016-12-23 15:46:32.136506636 +0100 ++++ openssh-7.4p1/session.c 2016-12-23 15:46:32.141506636 +0100 +@@ -2518,8 +2518,9 @@ session_setup_x11fwd(Session *s) return 0; } - if (x11_create_display_inet(ssh, options.x11_display_offset, + if (x11_create_display_inet(ssh, options.x11_display_offset, - options.x11_use_localhost, s->single_connection, - &s->display_number, &s->x11_chanids) == -1) { + options.x11_use_localhost, options.x11_max_displays, @@ -161,11 +187,10 @@ index 80282dfd8..e53d044a0 100644 debug("x11_create_display_inet failed."); return 0; } -diff --git a/sshd_config.5 b/sshd_config.5 -index 4ae4bebee..3dbce55fc 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -1403,6 +1403,7 @@ Available keywords are +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 TrustedUserCAKeys , .Cm UnusedConnectionTimeout , .Cm X11DisplayOffset , @@ -173,7 +198,7 @@ index 4ae4bebee..3dbce55fc 100644 .Cm X11Forwarding and .Cm X11UseLocalhost . -@@ -2112,6 +2113,12 @@ Specifies the first display number available for +@@ -1566,6 +1567,12 @@ Specifies the first display number avail X11 forwarding. This prevents sshd from interfering with real X11 servers. The default is 10. @@ -186,6 +211,3 @@ index 4ae4bebee..3dbce55fc 100644 .It Cm X11Forwarding Specifies whether X11 forwarding is permitted. The argument must be --- -2.52.0 - diff --git a/openssh-7.4p1-systemd.patch b/openssh-7.4p1-systemd.patch new file mode 100644 index 0000000..1242aac --- /dev/null +++ b/openssh-7.4p1-systemd.patch @@ -0,0 +1,98 @@ +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([K5LIBS]) + AC_SUBST([CHANNELLIBS]) + ++# 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/openssh-7.5p1-sandbox.patch b/openssh-7.5p1-sandbox.patch new file mode 100644 index 0000000..90640a0 --- /dev/null +++ b/openssh-7.5p1-sandbox.patch @@ -0,0 +1,86 @@ +In order to use the OpenSSL-ibmpkcs11 engine it is needed to allow flock +and ipc calls, because this engine calls OpenCryptoki (a PKCS#11 +implementation) which calls the libraries that will communicate with the +crypto cards. OpenCryptoki makes use of flock and ipc and, as of now, +this is only need on s390 architecture. + +Signed-off-by: Eduardo Barretto +--- + sandbox-seccomp-filter.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c +index ca75cc7..6e7de31 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -166,6 +166,9 @@ static const struct sock_filter preauth_insns[] = { + #ifdef __NR_exit_group + SC_ALLOW(__NR_exit_group), + #endif ++#if defined(__NR_flock) && defined(__s390__) ++ SC_ALLOW(__NR_flock), ++#endif + #ifdef __NR_futex + SC_FUTEX(__NR_futex), + #endif +@@ -178,6 +181,9 @@ static const struct sock_filter preauth_insns[] = { + #ifdef __NR_gettimeofday + SC_ALLOW(__NR_gettimeofday), + #endif ++#if defined(__NR_ipc) && defined(__s390__) ++ SC_ALLOW(__NR_ipc), ++#endif + #ifdef __NR_getuid + SC_ALLOW(__NR_getuid), + #endif +-- +1.9.1 + +getuid and geteuid are needed when using an openssl engine that calls a +crypto card, e.g. ICA (libica). +Those syscalls are also needed by the distros for audit code. + +Signed-off-by: Eduardo Barretto +--- + sandbox-seccomp-filter.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c +index 6e7de31..e86aa2c 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -175,6 +175,18 @@ static const struct sock_filter preauth_insns[] = { + #ifdef __NR_getpid + SC_ALLOW(__NR_getpid), + #endif ++#ifdef __NR_getuid ++ SC_ALLOW(__NR_getuid), ++#endif ++#ifdef __NR_getuid32 ++ SC_ALLOW(__NR_getuid32), ++#endif ++#ifdef __NR_geteuid ++ SC_ALLOW(__NR_geteuid), ++#endif ++#ifdef __NR_geteuid32 ++ SC_ALLOW(__NR_geteuid32), ++#endif + #ifdef __NR_getrandom + SC_ALLOW(__NR_getrandom), + #endif +-- 1.9.1 +1.9.1 +diff -up openssh-7.6p1/sandbox-seccomp-filter.c.sandbox openssh-7.6p1/sandbox-seccomp-filter.c +--- openssh-7.6p1/sandbox-seccomp-filter.c.sandbox 2017-12-12 13:59:30.563874059 +0100 ++++ openssh-7.6p1/sandbox-seccomp-filter.c 2017-12-12 13:59:14.842784083 +0100 +@@ -190,6 +190,9 @@ static const struct sock_filter preauth_ + #ifdef __NR_geteuid32 + SC_ALLOW(__NR_geteuid32), + #endif ++#ifdef __NR_gettid ++ SC_ALLOW(__NR_gettid), ++#endif + #ifdef __NR_getrandom + SC_ALLOW(__NR_getrandom), + #endif + diff --git a/0035-openssh-7.6p1-audit.patch b/openssh-7.6p1-audit.patch similarity index 77% rename from 0035-openssh-7.6p1-audit.patch rename to openssh-7.6p1-audit.patch index 1635f9f..748c4b6 100644 --- a/0035-openssh-7.6p1-audit.patch +++ b/openssh-7.6p1-audit.patch @@ -1,57 +1,7 @@ -From c64eb340d925f3f7e29bb1c45b7d7b537ffa6197 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 35/53] openssh-7.6p1-audit - ---- - Makefile.in | 2 +- - audit-bsm.c | 45 ++++++- - audit-linux.c | 302 +++++++++++++++++++++++++++++++++++++++++++--- - audit.c | 129 ++++++++++++++++++-- - audit.h | 22 +++- - auditstub.c | 52 ++++++++ - auth.c | 3 - - auth.h | 4 + - auth2-hostbased.c | 16 ++- - auth2-pubkey.c | 16 ++- - auth2.c | 3 - - cipher.c | 21 +--- - cipher.h | 20 ++- - kex.c | 61 ++++++++-- - kex.h | 2 + - mac.c | 14 +++ - mac.h | 1 + - monitor.c | 193 +++++++++++++++++++++++++++-- - monitor.h | 8 +- - monitor_wrap.c | 130 +++++++++++++++++++- - monitor_wrap.h | 11 +- - packet.c | 98 +++++++++++++-- - packet.h | 1 + - session.c | 82 ++++++++++++- - session.h | 10 +- - sshd-session.c | 98 +++++++++++++-- - sshd.c | 10 ++ - 27 files changed, 1251 insertions(+), 103 deletions(-) - create mode 100644 auditstub.c - -diff --git a/Makefile.in b/Makefile.in -index a36eb82ed..20d134c02 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -110,7 +110,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - 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 misc-agent.o -+ sshbuf-io.o misc-agent.o auditstub.o - - P11OBJS= ssh-pkcs11-client.o - -diff --git a/audit-bsm.c b/audit-bsm.c -index 4bce22c37..a6292cb8f 100644 ---- a/audit-bsm.c -+++ b/audit-bsm.c -@@ -373,12 +373,25 @@ audit_connection_from(const char *host, int port) +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-04-19 16:47:35.753062106 +0200 +@@ -373,13 +373,26 @@ audit_connection_from(const char *host, #endif } @@ -69,16 +19,17 @@ index 4bce22c37..a6292cb8f 100644 /* not implemented */ } -+void + void +audit_count_session_open(void) +{ + /* not necessary */ +} + - void ++void audit_session_open(struct logininfo *li) { -@@ -391,6 +404,12 @@ audit_session_close(struct logininfo *li) + /* not implemented */ +@@ -391,6 +404,12 @@ audit_session_close(struct logininfo *li /* not implemented */ } @@ -91,8 +42,8 @@ index 4bce22c37..a6292cb8f 100644 void audit_event(struct ssh *ssh, ssh_audit_event_t event) { -@@ -452,4 +471,28 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) - debug_f("unhandled event %d", event); +@@ -452,4 +471,28 @@ audit_event(struct ssh *ssh, ssh_audit_e + debug("%s: unhandled event %d", __func__, event); } } + @@ -120,11 +71,235 @@ index 4bce22c37..a6292cb8f 100644 + /* not implemented */ +} #endif /* BSM */ -diff --git a/audit-linux.c b/audit-linux.c -index 954eabe27..4d3e9d41e 100644 ---- a/audit-linux.c -+++ b/audit-linux.c -@@ -33,29 +33,42 @@ +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-04-19 16:47:35.753062106 +0200 +@@ -34,6 +34,12 @@ + #include "log.h" + #include "hostfile.h" + #include "auth.h" ++#include "ssh-gss.h" ++#include "monitor_wrap.h" ++#include "xmalloc.h" ++#include "misc.h" ++#include "servconf.h" ++#include "ssherr.h" + + /* + * Care must be taken when using this since it WILL NOT be initialized when +@@ -41,6 +47,7 @@ + * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. + */ + extern Authctxt *the_authctxt; ++extern ServerOptions options; + + /* Maybe add the audit class to struct Authmethod? */ + ssh_audit_event_t +@@ -69,13 +76,10 @@ audit_classify_auth(const char *method) + const char * + audit_username(void) + { +- static const char unknownuser[] = "(unknown user)"; +- static const char invaliduser[] = "(invalid user)"; ++ static const char unknownuser[] = "(unknown)"; + +- if (the_authctxt == NULL || the_authctxt->user == NULL) ++ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) + return (unknownuser); +- if (!the_authctxt->valid) +- return (invaliduser); + return (the_authctxt->user); + } + +@@ -109,6 +113,35 @@ audit_event_lookup(ssh_audit_event_t ev) + return(event_lookup[i].name); + } + ++void ++audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) ++{ ++ char *fp; ++ ++ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) ++ *rv = -SSH_ERR_INTERNAL_ERROR; ++ free(fp); ++} ++ ++void ++audit_unsupported(struct ssh *ssh, int what) ++{ ++ PRIVSEP(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())); ++} ++ ++void ++audit_session_key_free(struct ssh *ssh, int ctos) ++{ ++ PRIVSEP(audit_session_key_free_body(ssh, ctos, getpid(), getuid())); ++} ++ + # ifndef CUSTOM_SSH_AUDIT_EVENTS + /* + * Null implementations of audit functions. +@@ -138,6 +171,17 @@ audit_event(struct ssh *ssh, ssh_audit_e + } + + /* ++ * Called when a child process has called, or will soon call, ++ * audit_session_open. ++ */ ++void ++audit_count_session_open(void) ++{ ++ debug("audit count session open euid %d user %s", geteuid(), ++ audit_username()); ++} ++ ++/* + * Called when a user session is started. Argument is the tty allocated to + * the session, or NULL if no tty was allocated. + * +@@ -172,13 +216,82 @@ audit_session_close(struct logininfo *li + /* + * This will be called when a user runs a non-interactive command. Note that + * it may be called multiple times for a single connection since SSH2 allows +- * multiple sessions within a single connection. ++ * multiple sessions within a single connection. Returns a "handle" for ++ * audit_end_command. + */ +-void +-audit_run_command(const char *command) ++int ++audit_run_command(struct ssh *ssh, const char *command) + { + debug("audit run command euid %d user %s command '%.200s'", geteuid(), + audit_username(), command); ++ return 0; ++} ++ ++/* ++ * This will be called when the non-interactive command finishes. Note that ++ * it may be called multiple times for a single connection since SSH2 allows ++ * multiple sessions within a single connection. "handle" should come from ++ * the corresponding audit_run_command. ++ */ ++void ++audit_end_command(struct ssh *ssh, int handle, const char *command) ++{ ++ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), ++ audit_username(), command); ++} ++ ++/* ++ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. ++ * ++ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. ++ */ ++int ++audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++{ ++ debug("audit %s key usage euid %d user %s fingerprint %s, result %d", ++ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), ++ fp, rv); ++} ++ ++/* ++ * This will be called when the protocol negotiation fails. ++ */ ++void ++audit_unsupported_body(struct ssh *ssh, int what) ++{ ++ debug("audit unsupported protocol euid %d type %d", geteuid(), what); ++} ++ ++/* ++ * This will be called on succesfull protocol negotiation. ++ */ ++void ++audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, ++ uid_t uid) ++{ ++ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, ++ (unsigned)uid); ++} ++ ++/* ++ * This will be called on succesfull session key discard ++ */ ++void ++audit_session_key_free_body(struct ssh *, int ctos, pid_t pid, uid_t uid) ++{ ++ debug("audit session key discard euid %u direction %d from pid %ld uid %u", ++ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); ++} ++ ++/* ++ * This will be called on destroy private part of the server key ++ */ ++void ++audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) ++{ ++ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", ++ geteuid(), fp, (long)pid, (unsigned)uid); + } + # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ + #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-04-19 16:47:35.753062106 +0200 +@@ -26,6 +26,7 @@ + # define _SSH_AUDIT_H + + #include "loginrec.h" ++#include "sshkey.h" + + struct ssh; + +@@ -45,13 +46,32 @@ enum ssh_audit_event_type { + SSH_CONNECTION_ABANDON, /* closed without completing auth */ + SSH_AUDIT_UNKNOWN + }; ++ ++enum ssh_audit_kex { ++ SSH_AUDIT_UNSUPPORTED_CIPHER, ++ SSH_AUDIT_UNSUPPORTED_MAC, ++ SSH_AUDIT_UNSUPPORTED_COMPRESSION ++}; + typedef enum ssh_audit_event_type ssh_audit_event_t; + ++int listening_for_clients(void); ++ + void audit_connection_from(const char *, int); + void audit_event(struct ssh *, ssh_audit_event_t); ++void audit_count_session_open(void); + void audit_session_open(struct logininfo *); + void audit_session_close(struct logininfo *); +-void audit_run_command(const char *); ++int audit_run_command(struct ssh *, const char *); ++void audit_end_command(struct ssh *, int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); ++int audit_keyusage(struct ssh *, int, char *, int); ++void audit_key(struct ssh *, int, int *, const struct sshkey *); ++void audit_unsupported(struct ssh *, int); ++void audit_kex(struct ssh *, int, char *, char *, char *, char *); ++void audit_unsupported_body(struct ssh *, int); ++void audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); ++void audit_session_key_free(struct ssh *, int ctos); ++void audit_session_key_free_body(struct ssh *, int ctos, pid_t, uid_t); ++void audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); + + #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-04-19 16:47:35.753062106 +0200 +@@ -33,27 +33,40 @@ #include "log.h" #include "audit.h" @@ -135,10 +310,11 @@ index 954eabe27..4d3e9d41e 100644 +#include "servconf.h" #include "canohost.h" #include "packet.h" +- +#include "cipher.h" +#include "channels.h" +#include "session.h" - ++ +#define AUDIT_LOG_SIZE 256 + +extern ServerOptions options; @@ -164,8 +340,6 @@ index 954eabe27..4d3e9d41e 100644 - return 0; /* Must prevent login */ + goto fatal_report; /* Must prevent login */ } - if (hostname != NULL && strcmp(hostname, "UNKNOWN") == 0) - hostname = NULL; - rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN, + rc = audit_log_acct_message(audit_fd, event, NULL, "login", username ? username : "(unknown)", @@ -174,7 +348,7 @@ index 954eabe27..4d3e9d41e 100644 saved_errno = errno; close(audit_fd); -@@ -67,9 +80,96 @@ linux_audit_record_event(int uid, const char *username, const char *hostname, +@@ -65,9 +78,96 @@ linux_audit_record_event(int uid, const rc = 0; errno = saved_errno; @@ -272,7 +446,7 @@ index 954eabe27..4d3e9d41e 100644 /* Below is the sshd audit API code */ void -@@ -78,49 +178,211 @@ audit_connection_from(const char *host, int port) +@@ -76,49 +176,210 @@ audit_connection_from(const char *host, /* not implemented */ } @@ -351,7 +525,6 @@ index 954eabe27..4d3e9d41e 100644 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: @@ -381,7 +554,7 @@ index 954eabe27..4d3e9d41e 100644 + ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); break; default: - debug_f("unhandled event %d", event); + debug("%s: unhandled event %d", __func__, event); break; } } @@ -391,7 +564,7 @@ index 954eabe27..4d3e9d41e 100644 +{ +#ifdef AUDIT_CRYPTO_SESSION + char buf[AUDIT_LOG_SIZE]; -+ static const char *name[] = { "cipher", "mac", "comp" }; ++ const static char *name[] = { "cipher", "mac", "comp" }; + char *s; + int audit_fd; + @@ -409,7 +582,7 @@ index 954eabe27..4d3e9d41e 100644 +#endif +} + -+static const char *direction[] = { "from-server", "from-client", "both" }; ++const static char *direction[] = { "from-server", "from-client", "both" }; + +void +audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, @@ -488,7 +661,7 @@ index 954eabe27..4d3e9d41e 100644 + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, + buf, NULL, -+ ssh_remote_ipaddr(ssh), /*FIXME listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh) */ ++ 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 */ @@ -496,238 +669,9 @@ index 954eabe27..4d3e9d41e 100644 + error("cannot write into audit"); +} #endif /* USE_LINUX_AUDIT */ -diff --git a/audit.c b/audit.c -index dd2f03558..d0433c3a0 100644 ---- a/audit.c -+++ b/audit.c -@@ -34,6 +34,12 @@ - #include "log.h" - #include "hostfile.h" - #include "auth.h" -+#include "ssh-gss.h" -+#include "monitor_wrap.h" -+#include "xmalloc.h" -+#include "misc.h" -+#include "servconf.h" -+#include "ssherr.h" - - /* - * Care must be taken when using this since it WILL NOT be initialized when -@@ -41,6 +47,7 @@ - * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. - */ - extern Authctxt *the_authctxt; -+extern ServerOptions options; - - /* Maybe add the audit class to struct Authmethod? */ - ssh_audit_event_t -@@ -69,13 +76,10 @@ audit_classify_auth(const char *method) - const char * - audit_username(void) - { -- static const char unknownuser[] = "(unknown user)"; -- static const char invaliduser[] = "(invalid user)"; -+ static const char unknownuser[] = "(unknown)"; - -- if (the_authctxt == NULL || the_authctxt->user == NULL) -+ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) - return (unknownuser); -- if (!the_authctxt->valid) -- return (invaliduser); - return (the_authctxt->user); - } - -@@ -109,6 +113,35 @@ audit_event_lookup(ssh_audit_event_t ev) - return(event_lookup[i].name); - } - -+void -+audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) -+{ -+ char *fp; -+ -+ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); -+ if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) -+ *rv = -SSH_ERR_INTERNAL_ERROR; -+ free(fp); -+} -+ -+void -+audit_unsupported(struct ssh *ssh, int what) -+{ -+ mm_audit_unsupported_body(ssh, what); -+} -+ -+void -+audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs) -+{ -+ mm_audit_kex_body(ssh, ctos, enc, mac, comp, pfs, getpid(), getuid()); -+} -+ -+void -+audit_session_key_free(struct ssh *ssh, int ctos) -+{ -+ mm_audit_session_key_free_body(ssh, ctos, getpid(), getuid()); -+} -+ - # ifndef CUSTOM_SSH_AUDIT_EVENTS - /* - * Null implementations of audit functions. -@@ -137,6 +170,17 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) - audit_username(), event, audit_event_lookup(event)); - } - -+/* -+ * Called when a child process has called, or will soon call, -+ * audit_session_open. -+ */ -+void -+audit_count_session_open(void) -+{ -+ debug("audit count session open euid %d user %s", geteuid(), -+ audit_username()); -+} -+ - /* - * Called when a user session is started. Argument is the tty allocated to - * the session, or NULL if no tty was allocated. -@@ -172,13 +216,82 @@ audit_session_close(struct logininfo *li) - /* - * This will be called when a user runs a non-interactive command. Note that - * it may be called multiple times for a single connection since SSH2 allows -- * multiple sessions within a single connection. -+ * multiple sessions within a single connection. Returns a "handle" for -+ * audit_end_command. - */ --void --audit_run_command(const char *command) -+int -+audit_run_command(struct ssh *ssh, const char *command) - { - debug("audit run command euid %d user %s command '%.200s'", geteuid(), - audit_username(), command); -+ return 0; -+} -+ -+/* -+ * This will be called when the non-interactive command finishes. Note that -+ * it may be called multiple times for a single connection since SSH2 allows -+ * multiple sessions within a single connection. "handle" should come from -+ * the corresponding audit_run_command. -+ */ -+void -+audit_end_command(struct ssh *ssh, int handle, const char *command) -+{ -+ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), -+ audit_username(), command); -+} -+ -+/* -+ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. -+ * -+ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. -+ */ -+int -+audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) -+{ -+ debug("audit %s key usage euid %d user %s fingerprint %s, result %d", -+ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), -+ fp, rv); -+} -+ -+/* -+ * This will be called when the protocol negotiation fails. -+ */ -+void -+audit_unsupported_body(struct ssh *ssh, int what) -+{ -+ debug("audit unsupported protocol euid %d type %d", geteuid(), what); -+} -+ -+/* -+ * This will be called on succesfull protocol negotiation. -+ */ -+void -+audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, -+ uid_t uid) -+{ -+ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, -+ (unsigned)uid); -+} -+ -+/* -+ * This will be called on succesfull session key discard -+ */ -+void -+audit_session_key_free_body(struct ssh *, int ctos, pid_t pid, uid_t uid) -+{ -+ debug("audit session key discard euid %u direction %d from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); -+} -+ -+/* -+ * This will be called on destroy private part of the server key -+ */ -+void -+audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) -+{ -+ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", -+ geteuid(), fp, (long)pid, (unsigned)uid); - } - # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ - #endif /* SSH_AUDIT_EVENTS */ -diff --git a/audit.h b/audit.h -index 38cb5ad31..45d66ccff 100644 ---- a/audit.h -+++ b/audit.h -@@ -26,6 +26,7 @@ - # define _SSH_AUDIT_H - - #include "loginrec.h" -+#include "sshkey.h" - - struct ssh; - -@@ -45,13 +46,32 @@ enum ssh_audit_event_type { - SSH_CONNECTION_ABANDON, /* closed without completing auth */ - SSH_AUDIT_UNKNOWN - }; -+ -+enum ssh_audit_kex { -+ SSH_AUDIT_UNSUPPORTED_CIPHER, -+ SSH_AUDIT_UNSUPPORTED_MAC, -+ SSH_AUDIT_UNSUPPORTED_COMPRESSION -+}; - typedef enum ssh_audit_event_type ssh_audit_event_t; - -+int listening_for_clients(void); -+ - void audit_connection_from(const char *, int); - void audit_event(struct ssh *, ssh_audit_event_t); -+void audit_count_session_open(void); - void audit_session_open(struct logininfo *); - void audit_session_close(struct logininfo *); --void audit_run_command(const char *); -+int audit_run_command(struct ssh *, const char *); -+void audit_end_command(struct ssh *, int, const char *); - ssh_audit_event_t audit_classify_auth(const char *); -+int audit_keyusage(struct ssh *, int, char *, int); -+void audit_key(struct ssh *, int, int *, const struct sshkey *); -+void audit_unsupported(struct ssh *, int); -+void audit_kex(struct ssh *, int, char *, char *, char *, char *); -+void audit_unsupported_body(struct ssh *, int); -+void audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); -+void audit_session_key_free(struct ssh *, int ctos); -+void audit_session_key_free_body(struct ssh *, int ctos, pid_t, uid_t); -+void audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); - - #endif /* _SSH_AUDIT_H */ -diff --git a/auditstub.c b/auditstub.c -new file mode 100644 -index 000000000..639a798df ---- /dev/null -+++ b/auditstub.c +diff -up openssh-8.6p1/auditstub.c.audit openssh-8.6p1/auditstub.c +--- 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 $ */ + @@ -781,56 +725,32 @@ index 000000000..639a798df +audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid) +{ +} -diff --git a/auth.c b/auth.c -index d25653ee4..38c34298e 100644 ---- a/auth.c -+++ b/auth.c -@@ -499,9 +499,6 @@ getpwnamallow(struct ssh *ssh, const char *user) - record_failed_login(ssh, user, - auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); - #endif +diff -up openssh-8.6p1/auth2.c.audit openssh-8.6p1/auth2.c +--- 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 + authctxt->valid = 0; + /* Invalid user, fake password information */ + authctxt->pw = fakepw(); -#ifdef SSH_AUDIT_EVENTS -- audit_event(ssh, SSH_INVALID_USER); --#endif /* SSH_AUDIT_EVENTS */ - return (NULL); - } - if (!allowed_user(ssh, pw)) -diff --git a/auth.h b/auth.h -index 391630350..6be52d70b 100644 ---- a/auth.h -+++ b/auth.h -@@ -215,6 +215,8 @@ struct sshkey *get_hostkey_private_by_type(int, int, struct ssh *); - int get_hostkey_index(struct sshkey *, int, struct ssh *); - int sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *, - u_char **, size_t *, const u_char *, size_t, const char *); -+int hostbased_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 **); - - /* Key / cert options linkage to auth layer */ - int auth_activate_options(struct ssh *, struct sshauthopt *); -@@ -240,6 +242,8 @@ int auth_check_authkey_line(struct passwd *, struct sshkey *, - 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 --git a/auth2-hostbased.c b/auth2-hostbased.c -index 976484fc5..e9421a868 100644 ---- a/auth2-hostbased.c -+++ b/auth2-hostbased.c -@@ -157,7 +157,7 @@ userauth_hostbased(struct ssh *ssh, const char *method) +- PRIVSEP(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-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 (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) + 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) authenticated = 1; -@@ -174,6 +174,20 @@ done: +@@ -175,6 +175,20 @@ done: return authenticated; } @@ -851,20 +771,19 @@ index 976484fc5..e9421a868 100644 /* return 1 if given hostkey is allowed */ int hostbased_key_allowed(struct ssh *ssh, struct passwd *pw, -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index b7300ca9e..9f3371c07 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -233,7 +233,7 @@ userauth_pubkey(struct ssh *ssh, const char *method) +diff -up openssh-8.6p1/auth2-pubkey.c.audit openssh-8.6p1/auth2-pubkey.c +--- 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 (mm_user_key_allowed(ssh, pw, key, 1, &authopts) && -- mm_sshkey_verify(key, sig, slen, -+ mm_user_key_verify(ssh, key, sig, slen, + if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && +- PRIVSEP(sshkey_verify(key, sig, slen, ++ PRIVSEP(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) { -@@ -326,6 +326,20 @@ done: + ssh->compat, &sig_details)) == 0) { +@@ -305,6 +305,20 @@ done: return authenticated; } @@ -885,24 +804,43 @@ index b7300ca9e..9f3371c07 100644 static int match_principals_file(struct passwd *pw, char *file, struct sshkey_cert *cert, struct sshauthopt **authoptsp) -diff --git a/auth2.c b/auth2.c -index 5a4b932a9..da24f7bcb 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -310,9 +310,6 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) - authctxt->valid = 0; - /* Invalid user, fake password information */ - authctxt->pw = fakepw(); +diff -up openssh-8.6p1/auth.c.audit openssh-8.6p1/auth.c +--- 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"); + #endif -#ifdef SSH_AUDIT_EVENTS -- mm_audit_event(ssh, SSH_INVALID_USER); --#endif - } - #ifdef USE_PAM - if (options.use_pam) -diff --git a/cipher.c b/cipher.c -index 5e096cebf..9b42ffb9a 100644 ---- a/cipher.c -+++ b/cipher.c +- audit_event(ssh, SSH_INVALID_USER); +-#endif /* SSH_AUDIT_EVENTS */ + return (NULL); + } + 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-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 *, + u_char **, size_t *, const u_char *, size_t, const char *); ++int hostbased_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 **); + + /* Key / cert options linkage to auth layer */ + const struct sshauthopt *auth_options(struct ssh *); +@@ -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-04-19 16:47:35.755062122 +0200 @@ -64,25 +64,6 @@ struct sshcipher_ctx { const struct sshcipher *cipher; }; @@ -929,7 +867,7 @@ index 5e096cebf..9b42ffb9a 100644 static const struct sshcipher ciphers[] = { #ifdef WITH_OPENSSL #ifndef OPENSSL_NO_DES -@@ -411,7 +392,7 @@ cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr, +@@ -422,7 +403,7 @@ cipher_get_length(struct sshcipher_ctx * void cipher_free(struct sshcipher_ctx *cc) { @@ -938,10 +876,9 @@ index 5e096cebf..9b42ffb9a 100644 return; if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { chachapoly_free(cc->cp_ctx); -diff --git a/cipher.h b/cipher.h -index 6533ff2bb..2e05a0210 100644 ---- a/cipher.h -+++ b/cipher.h +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-04-19 16:47:35.755062122 +0200 @@ -47,7 +47,25 @@ #define CIPHER_ENCRYPT 1 #define CIPHER_DECRYPT 0 @@ -969,19 +906,18 @@ index 6533ff2bb..2e05a0210 100644 struct sshcipher_ctx; const struct sshcipher *cipher_by_name(const char *); -diff --git a/kex.c b/kex.c -index 5f9530908..44f350ce8 100644 ---- a/kex.c -+++ b/kex.c -@@ -66,6 +66,7 @@ +diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c +--- 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 "sshbuf.h" #include "digest.h" #include "xmalloc.h" +#include "audit.h" - /* prototype */ - static int kex_choose_conf(struct ssh *, uint32_t seq); -@@ -820,12 +821,16 @@ kex_start_rekex(struct ssh *ssh) + #ifdef GSSAPI + #include "ssh-gss.h" +@@ -816,12 +817,16 @@ kex_start_rekex(struct ssh *ssh) } static int @@ -1000,7 +936,7 @@ index 5f9530908..44f350ce8 100644 if ((enc->cipher = cipher_by_name(name)) == NULL) { error_f("unsupported cipher %s", name); free(name); -@@ -846,8 +851,12 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) +@@ -842,8 +847,12 @@ choose_mac(struct ssh *ssh, struct sshma { char *name = match_list(client, server, NULL); @@ -1014,7 +950,7 @@ index 5f9530908..44f350ce8 100644 if (mac_setup(mac, name) < 0) { error_f("unsupported MAC %s", name); free(name); -@@ -860,12 +869,16 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) +@@ -856,12 +865,16 @@ choose_mac(struct ssh *ssh, struct sshma } static int @@ -1033,7 +969,7 @@ index 5f9530908..44f350ce8 100644 #ifdef WITH_ZLIB if (strcmp(name, "zlib@openssh.com") == 0) { comp->type = COMP_DELAYED; -@@ -1029,7 +1042,7 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) +@@ -1002,7 +1015,7 @@ kex_choose_conf(struct ssh *ssh) nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; @@ -1042,7 +978,7 @@ index 5f9530908..44f350ce8 100644 sprop[nenc])) != 0) { kex->failed_choice = peer[nenc]; peer[nenc] = NULL; -@@ -1044,7 +1057,7 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) +@@ -1017,7 +1030,7 @@ kex_choose_conf(struct ssh *ssh) peer[nmac] = NULL; goto out; } @@ -1051,7 +987,7 @@ index 5f9530908..44f350ce8 100644 sprop[ncomp])) != 0) { kex->failed_choice = peer[ncomp]; peer[ncomp] = NULL; -@@ -1067,6 +1080,10 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) +@@ -1040,6 +1053,10 @@ kex_choose_conf(struct ssh *ssh) dh_need = MAXIMUM(dh_need, newkeys->enc.block_size); dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len); dh_need = MAXIMUM(dh_need, newkeys->mac.key_len); @@ -1062,7 +998,7 @@ index 5f9530908..44f350ce8 100644 } /* XXX need runden? */ kex->we_need = need; -@@ -1336,6 +1353,36 @@ dump_digest(const char *msg, const u_char *digest, int len) +@@ -1297,6 +1314,36 @@ dump_digest(const char *msg, const u_cha } #endif @@ -1099,11 +1035,10 @@ index 5f9530908..44f350ce8 100644 /* * Send a plaintext error message to the peer, suffixed by \r\n. * Only used during banner exchange, and there only for the server. -diff --git a/kex.h b/kex.h -index 206ce60ed..cb06e85a3 100644 ---- a/kex.h -+++ b/kex.h -@@ -260,6 +260,8 @@ int kexgss_client(struct ssh *); +diff -up openssh-8.6p1/kex.h.audit openssh-8.6p1/kex.h +--- 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 @@ -1112,11 +1047,10 @@ index 206ce60ed..cb06e85a3 100644 int kex_dh_keypair(struct kex *); int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); -diff --git a/mac.c b/mac.c -index c95f5ea06..354cfb408 100644 ---- a/mac.c -+++ b/mac.c -@@ -230,6 +230,20 @@ mac_clear(struct sshmac *mac) +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-04-19 16:47:35.756062129 +0200 +@@ -239,6 +239,20 @@ mac_clear(struct sshmac *mac) mac->umac_ctx = NULL; } @@ -1137,22 +1071,32 @@ index c95f5ea06..354cfb408 100644 /* XXX copied from ciphers_valid */ #define MAC_SEP "," int -diff --git a/mac.h b/mac.h -index 0b119d7a1..5fb593b9e 100644 ---- a/mac.h -+++ b/mac.h -@@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int32_t, const u_char *, 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-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); void mac_clear(struct sshmac *); +void mac_destroy(struct sshmac *); #endif /* SSHMAC_H */ -diff --git a/monitor.c b/monitor.c -index 453469665..b2f501790 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -83,6 +83,7 @@ +diff -up openssh-8.6p1/Makefile.in.audit openssh-8.6p1/Makefile.in +--- 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 \ + kexgssc.o \ + sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ +- sshbuf-io.o ++ sshbuf-io.o auditstub.o + + 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-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" #include "authfd.h" @@ -1160,16 +1104,16 @@ index 453469665..b2f501790 100644 #include "match.h" #include "ssherr.h" #include "sk-api.h" -@@ -100,6 +101,8 @@ extern struct sshbuf *loginmsg; - extern struct include_list includes; +@@ -107,6 +108,8 @@ extern u_int utmp_len; + extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ -+extern void destroy_sensitive_data(struct ssh *); ++extern void destroy_sensitive_data(struct ssh *, int); + /* State exported from the child */ static struct sshbuf *child_state; -@@ -144,6 +147,11 @@ int mm_answer_gss_updatecreds(struct ssh *, int, struct sshbuf *); +@@ -157,6 +160,11 @@ int mm_answer_gss_updatecreds(struct ssh #ifdef SSH_AUDIT_EVENTS int mm_answer_audit_event(struct ssh *, int, struct sshbuf *); int mm_answer_audit_command(struct ssh *, int, struct sshbuf *); @@ -1181,7 +1125,7 @@ index 453469665..b2f501790 100644 #endif static Authctxt *authctxt; -@@ -204,6 +212,10 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -215,6 +223,10 @@ struct mon_table mon_dispatch_proto20[] #endif #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, @@ -1192,7 +1136,7 @@ index 453469665..b2f501790 100644 #endif #ifdef BSD_AUTH {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, -@@ -239,6 +251,11 @@ struct mon_table mon_dispatch_postauth20[] = { +@@ -249,6 +261,11 @@ struct mon_table mon_dispatch_postauth20 #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, {MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command}, @@ -1204,7 +1148,7 @@ index 453469665..b2f501790 100644 #endif {0, 0, NULL} }; -@@ -1575,8 +1592,10 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1444,8 +1461,10 @@ mm_answer_keyverify(struct ssh *ssh, int int r, ret, req_presence = 0, req_verify = 0, valid_data = 0; int encoded_ret; struct sshkey_sig_details *sig_details = NULL; @@ -1216,7 +1160,7 @@ index 453469665..b2f501790 100644 (r = sshbuf_get_string_direct(m, &signature, &signaturelen)) != 0 || (r = sshbuf_get_string_direct(m, &data, &datalen)) != 0 || (r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0) -@@ -1585,6 +1604,8 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1454,6 +1473,8 @@ mm_answer_keyverify(struct ssh *ssh, int if (hostbased_cuser == NULL || hostbased_chost == NULL || !monitor_allowed_key(blob, bloblen)) fatal_f("bad key, not previously allowed"); @@ -1225,7 +1169,7 @@ index 453469665..b2f501790 100644 /* Empty signature algorithm means NULL. */ if (*sigalg == '\0') { -@@ -1600,14 +1621,19 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1469,14 +1490,19 @@ mm_answer_keyverify(struct ssh *ssh, int case MM_USERKEY: valid_data = monitor_valid_userblob(ssh, data, datalen); auth_method = "publickey"; @@ -1245,16 +1189,16 @@ index 453469665..b2f501790 100644 break; } if (!valid_data) -@@ -1619,8 +1645,6 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1488,8 +1514,6 @@ mm_answer_keyverify(struct ssh *ssh, int SSH_FP_DEFAULT)) == NULL) fatal_f("sshkey_fingerprint failed"); - ret = sshkey_verify(key, signature, signaturelen, data, datalen, - sigalg, ssh->compat, &sig_details); - debug3_f("%s %s signature using %s %s%s%s", auth_method, - sshkey_type(key), sigalg == NULL ? "default" : sigalg, - (ret == 0) ? "verified" : "unverified", -@@ -1708,13 +1732,19 @@ mm_record_login(struct ssh *ssh, Session *s, struct passwd *pw) + debug3_f("%s %s signature using %s %s%s%s", auth_method, + sshkey_type(key), sigalg == NULL ? "default" : sigalg, + (ret == 0) ? "verified" : "unverified", +@@ -1576,13 +1600,19 @@ mm_record_login(struct ssh *ssh, Session } static void @@ -1275,7 +1219,7 @@ index 453469665..b2f501790 100644 session_unused(s->self); } -@@ -1781,7 +1811,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1649,7 +1679,7 @@ mm_answer_pty(struct ssh *ssh, int sock, error: if (s != NULL) @@ -1284,7 +1228,7 @@ index 453469665..b2f501790 100644 if ((r = sshbuf_put_u32(m, 0)) != 0) fatal_fr(r, "assemble 0"); mm_request_send(sock, MONITOR_ANS_PTY, m); -@@ -1800,7 +1830,7 @@ mm_answer_pty_cleanup(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1668,7 +1698,7 @@ mm_answer_pty_cleanup(struct ssh *ssh, i if ((r = sshbuf_get_cstring(m, &tty, NULL)) != 0) fatal_fr(r, "parse tty"); if ((s = session_by_tty(tty)) != NULL) @@ -1293,24 +1237,25 @@ index 453469665..b2f501790 100644 sshbuf_reset(m); free(tty); return (0); -@@ -1822,6 +1852,8 @@ mm_answer_term(struct ssh *ssh, int sock, struct sshbuf *req) +@@ -1690,6 +1720,8 @@ mm_answer_term(struct ssh *ssh, int sock sshpam_cleanup(); #endif -+ destroy_sensitive_data(ssh); ++ destroy_sensitive_data(ssh, 0); + while (waitpid(pmonitor->m_pid, &status, 0) == -1) if (errno != EINTR) exit(1); -@@ -1868,12 +1900,46 @@ mm_answer_audit_command(struct ssh *ssh, int socket, struct sshbuf *m) +@@ -1736,12 +1768,47 @@ mm_answer_audit_command(struct ssh *ssh, { char *cmd; int r; + Session *s; - debug3_f("entering"); + debug3("%s entering", __func__); if ((r = sshbuf_get_cstring(m, &cmd, NULL)) != 0) - fatal_fr(r, "buffer error"); + fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ /* sanity check command, if so how? */ - audit_run_command(cmd); + s = session_new(); @@ -1350,7 +1295,7 @@ index 453469665..b2f501790 100644 free(cmd); return (0); } -@@ -1946,6 +2012,7 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) +@@ -1813,6 +1880,7 @@ monitor_apply_keystate(struct ssh *ssh, void mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) { @@ -1358,7 +1303,7 @@ index 453469665..b2f501790 100644 debug3_f("Waiting for new keys"); if ((child_state = sshbuf_new()) == NULL) -@@ -1953,6 +2020,19 @@ mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) +@@ -1820,6 +1888,19 @@ mm_get_keystate(struct ssh *ssh, struct mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, child_state); debug3_f("GOT new keys"); @@ -1378,7 +1323,7 @@ index 453469665..b2f501790 100644 } -@@ -2240,3 +2320,102 @@ mm_answer_gss_updatecreds(struct ssh *ssh, int socket, struct sshbuf *m) { +@@ -2111,3 +2192,102 @@ mm_answer_gss_updatecreds(struct ssh *ss #endif /* GSSAPI */ @@ -1481,11 +1426,10 @@ index 453469665..b2f501790 100644 + return 0; +} +#endif /* SSH_AUDIT_EVENTS */ -diff --git a/monitor.h b/monitor.h -index d4d631ddc..2c64f07dc 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -66,7 +66,13 @@ enum monitor_reqtype { +diff -up openssh-8.6p1/monitor.h.audit openssh-8.6p1/monitor.h +--- 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, MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, @@ -1500,11 +1444,10 @@ index d4d631ddc..2c64f07dc 100644 MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 08dc29e12..fb44ae733 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -578,7 +578,7 @@ mm_key_allowed(enum mm_keytype type, const char *user, const char *host, +diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c +--- 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 */ int @@ -1513,7 +1456,7 @@ index 08dc29e12..fb44ae733 100644 const u_char *data, size_t datalen, const char *sigalg, u_int compat, struct sshkey_sig_details **sig_detailsp) { -@@ -594,7 +594,8 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, +@@ -536,7 +536,8 @@ mm_sshkey_verify(const struct sshkey *ke *sig_detailsp = NULL; if ((m = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); @@ -1523,7 +1466,7 @@ index 08dc29e12..fb44ae733 100644 (r = sshbuf_put_string(m, sig, siglen)) != 0 || (r = sshbuf_put_string(m, data, datalen)) != 0 || (r = sshbuf_put_cstring(m, sigalg == NULL ? "" : sigalg)) != 0) -@@ -627,6 +628,22 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, +@@ -569,6 +570,22 @@ mm_sshkey_verify(const struct sshkey *ke return 0; } @@ -1546,7 +1489,7 @@ index 08dc29e12..fb44ae733 100644 void mm_send_keystate(struct ssh *ssh, struct monitor *monitor) { -@@ -1043,11 +1060,12 @@ mm_audit_event(struct ssh *ssh, ssh_audit_event_t event) +@@ -921,11 +938,12 @@ mm_audit_event(struct ssh *ssh, ssh_audi sshbuf_free(m); } @@ -1559,10 +1502,10 @@ index 08dc29e12..fb44ae733 100644 int r; + int handle; - debug3_f("entering command %s", command); + debug3("%s entering command %s", __func__, command); -@@ -1057,6 +1075,30 @@ mm_audit_run_command(const char *command) - fatal_fr(r, "buffer error"); +@@ -935,6 +953,30 @@ mm_audit_run_command(const char *command + fatal("%s: buffer error: %s", __func__, ssh_err(r)); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, m); + mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, m); @@ -1592,10 +1535,10 @@ index 08dc29e12..fb44ae733 100644 sshbuf_free(m); } #endif /* SSH_AUDIT_EVENTS */ -@@ -1305,3 +1347,83 @@ server_get_connection_info(struct ssh *ssh, int populate, int use_dns) - return &ci; +@@ -1095,3 +1137,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc } + #endif /* GSSAPI */ +#ifdef SSH_AUDIT_EVENTS +void +mm_audit_unsupported_body(struct ssh *ssh, int what) @@ -1676,11 +1619,10 @@ index 08dc29e12..fb44ae733 100644 + sshbuf_free(m); +} +#endif /* SSH_AUDIT_EVENTS */ -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 12c489c33..1bcbfd305 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -62,7 +62,9 @@ int mm_user_key_allowed(struct ssh *ssh, struct passwd *, struct sshkey *, int, +diff -up openssh-8.6p1/monitor_wrap.h.audit openssh-8.6p1/monitor_wrap.h +--- 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 *, const char *, struct sshkey *); @@ -1690,8 +1632,8 @@ index 12c489c33..1bcbfd305 100644 +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 **); - void mm_decode_activate_server_options(struct ssh *ssh, struct sshbuf *m); -@@ -89,7 +91,12 @@ void mm_sshpam_free_ctx(void *); + #ifdef GSSAPI +@@ -86,7 +88,12 @@ void mm_sshpam_free_ctx(void *); #ifdef SSH_AUDIT_EVENTS #include "audit.h" void mm_audit_event(struct ssh *, ssh_audit_event_t); @@ -1705,11 +1647,10 @@ index 12c489c33..1bcbfd305 100644 #endif struct Session; -diff --git a/packet.c b/packet.c -index 5dd8269c2..bc22b8625 100644 ---- a/packet.c -+++ b/packet.c -@@ -77,6 +77,7 @@ +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-04-19 16:48:46.885608837 +0200 +@@ -81,6 +81,7 @@ #endif #include "xmalloc.h" @@ -1717,7 +1658,7 @@ index 5dd8269c2..bc22b8625 100644 #include "compat.h" #include "ssh2.h" #include "cipher.h" -@@ -513,6 +514,13 @@ ssh_packet_get_connection_out(struct ssh *ssh) +@@ -506,6 +507,13 @@ ssh_packet_get_connection_out(struct ssh return ssh->state->connection_out; } @@ -1731,10 +1672,10 @@ index 5dd8269c2..bc22b8625 100644 /* * Returns the IP-address of the remote host as a string. The returned * string must not be freed. -@@ -683,22 +691,19 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) +@@ -583,22 +591,19 @@ ssh_packet_close_internal(struct ssh *ss + { struct session_state *state = ssh->state; u_int mode; - struct packet *p; + u_int had_keys = packet_state_has_keys(state); if (!state->initialized) @@ -1756,10 +1697,10 @@ index 5dd8269c2..bc22b8625 100644 + state->outgoing_packet = NULL; sshbuf_free(state->incoming_packet); + state->incoming_packet = NULL; - while ((p = TAILQ_FIRST(&state->outgoing))) { - sshbuf_free(p->payload); - TAILQ_REMOVE(&state->outgoing, p, next); -@@ -739,8 +744,18 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) + for (mode = 0; mode < MODE_MAX; mode++) { + kex_free_newkeys(state->newkeys[mode]); /* current keys */ + state->newkeys[mode] = NULL; +@@ -634,8 +639,18 @@ ssh_packet_close_internal(struct ssh *ss #endif /* WITH_ZLIB */ cipher_free(state->send_context); cipher_free(state->receive_context); @@ -1778,7 +1719,7 @@ index 5dd8269c2..bc22b8625 100644 free(ssh->local_ipaddr); ssh->local_ipaddr = NULL; free(ssh->remote_ipaddr); -@@ -1004,6 +1019,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode) +@@ -892,6 +907,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod (unsigned long long)state->p_send.bytes, (unsigned long long)state->p_send.blocks); kex_free_newkeys(state->newkeys[mode]); @@ -1786,7 +1727,7 @@ index 5dd8269c2..bc22b8625 100644 state->newkeys[mode] = NULL; } /* note that both bytes and the seqnr are not reset */ -@@ -2345,6 +2361,72 @@ ssh_packet_get_output(struct ssh *ssh) +@@ -2173,6 +2189,72 @@ ssh_packet_get_output(struct ssh *ssh) return (void *)ssh->state->output; } @@ -1859,29 +1800,28 @@ index 5dd8269c2..bc22b8625 100644 /* Reset after_authentication and reset compression in post-auth privsep */ static int ssh_packet_set_postauth(struct ssh *ssh) -diff --git a/packet.h b/packet.h -index 072f27425..e087d4c8a 100644 ---- a/packet.h -+++ b/packet.h -@@ -223,4 +223,5 @@ const u_char *sshpkt_ptr(struct ssh *, size_t *lenp); +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-04-19 16:47:35.758062145 +0200 +@@ -218,4 +218,5 @@ const u_char *sshpkt_ptr(struct ssh *, s # undef EC_POINT #endif +void packet_destroy_all(struct ssh *, int, int); #endif /* PACKET_H */ -diff --git a/session.c b/session.c -index d034f5c65..107edcf91 100644 ---- a/session.c -+++ b/session.c -@@ -139,6 +139,7 @@ static int session_pty_req(struct ssh *, Session *); - extern ServerOptions options; - extern char *__progname; +diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c +--- 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 void destroy_sensitive_data(struct ssh *); + extern u_int utmp_len; + extern int startup_pipe; +-extern void destroy_sensitive_data(void); ++extern void destroy_sensitive_data(struct ssh *, int); extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; extern char *tun_fwd_ifnames; /* serverloop.c */ -@@ -617,6 +618,14 @@ do_exec_pty(struct ssh *ssh, Session *s, const char *command) +@@ -644,6 +644,14 @@ do_exec_pty(struct ssh *ssh, Session *s, /* Parent. Close the slave side of the pseudo tty. */ close(ttyfd); @@ -1895,34 +1835,35 @@ index d034f5c65..107edcf91 100644 + /* Enter interactive session. */ s->ptymaster = ptymaster; - session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1); -@@ -707,15 +716,19 @@ do_exec(struct ssh *ssh, Session *s, const char *command) + ssh_packet_set_interactive(ssh, 1, +@@ -736,15 +744,19 @@ do_exec(struct ssh *ssh, Session *s, con s->self); #ifdef SSH_AUDIT_EVENTS + if (s->command != NULL || s->command_handle != -1) + fatal("do_exec: command already set"); if (command != NULL) -- mm_audit_run_command(command); +- PRIVSEP(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; -- mm_audit_run_command(shell); +- PRIVSEP(audit_run_command(shell)); + s->command = xstrdup(shell); } + if (s->command != NULL && s->ptyfd == -1) -+ s->command_handle = mm_audit_run_command(ssh, s->command); ++ s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); #endif if (s->ttyfd != -1) ret = do_exec_pty(ssh, s, command); -@@ -1495,7 +1508,11 @@ do_child(struct ssh *ssh, Session *s, const char *command) +@@ -1550,8 +1562,11 @@ do_child(struct ssh *ssh, Session *s, co sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); - /* remove keys from memory */ -+ destroy_sensitive_data(ssh); + /* remove hostkey from the child's memory */ +- destroy_sensitive_data(); ++ destroy_sensitive_data(ssh, 1); 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. */ @@ -1930,7 +1871,7 @@ index d034f5c65..107edcf91 100644 /* Force a password change */ if (s->authctxt->force_pwchange) { -@@ -1710,6 +1727,9 @@ session_unused(int id) +@@ -1763,6 +1778,9 @@ session_unused(int id) sessions[id].ttyfd = -1; sessions[id].ptymaster = -1; sessions[id].x11_chanids = NULL; @@ -1940,11 +1881,10 @@ index d034f5c65..107edcf91 100644 sessions[id].next_unused = sessions_first_unused; sessions_first_unused = id; } -@@ -1788,6 +1808,19 @@ session_open(Authctxt *authctxt, int chanid) - return 1; +@@ -1843,6 +1861,19 @@ session_open(Authctxt *authctxt, int cha } -+Session * + Session * +session_by_id(int id) +{ + if (id >= 0 && id < sessions_nalloc) { @@ -1957,10 +1897,11 @@ index d034f5c65..107edcf91 100644 + return NULL; +} + - Session * ++Session * session_by_tty(char *tty) { -@@ -2405,6 +2438,32 @@ session_exit_message(struct ssh *ssh, Session *s, int status) + int i; +@@ -2450,6 +2481,32 @@ session_exit_message(struct ssh *ssh, Se chan_write_failed(ssh, c); } @@ -1982,7 +1923,7 @@ index d034f5c65..107edcf91 100644 +{ + if (s->command != NULL) { + if (s->command_handle != -1) -+ mm_audit_end_command(ssh, s->command_handle, s->command); ++ PRIVSEP(audit_end_command(ssh, s->command_handle, s->command)); + free(s->command); + s->command = NULL; + s->command_handle = -1; @@ -1993,7 +1934,7 @@ index d034f5c65..107edcf91 100644 void session_close(struct ssh *ssh, Session *s) { -@@ -2418,6 +2477,10 @@ session_close(struct ssh *ssh, Session *s) +@@ -2463,6 +2520,10 @@ session_close(struct ssh *ssh, Session * if (s->ttyfd != -1) session_pty_cleanup(s); @@ -2004,7 +1945,7 @@ index d034f5c65..107edcf91 100644 free(s->term); free(s->display); free(s->x11_chanids); -@@ -2494,14 +2557,14 @@ session_close_by_channel(struct ssh *ssh, int id, int force, void *arg) +@@ -2537,14 +2598,14 @@ session_close_by_channel(struct ssh *ssh } void @@ -2021,7 +1962,7 @@ index d034f5c65..107edcf91 100644 else session_close(ssh, s); } -@@ -2627,6 +2690,15 @@ do_authenticated2(struct ssh *ssh, Authctxt *authctxt) +@@ -2671,6 +2732,15 @@ do_authenticated2(struct ssh *ssh, Authc server_loop2(ssh, authctxt); } @@ -2037,19 +1978,18 @@ index d034f5c65..107edcf91 100644 void do_cleanup(struct ssh *ssh, Authctxt *authctxt) { -@@ -2690,7 +2762,7 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) +@@ -2734,7 +2804,7 @@ do_cleanup(struct ssh *ssh, Authctxt *au * or if running in monitor. */ - if (mm_is_monitor()) + if (!use_privsep || mm_is_monitor()) - session_destroy_all(ssh, session_pty_cleanup2); + session_destroy_all(ssh, do_cleanup_one_session); } /* Return a name for the remote host that fits inside utmp_size */ -diff --git a/session.h b/session.h -index 344a1ddf9..a41c6efcd 100644 ---- a/session.h -+++ b/session.h +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-04-19 16:47:35.758062145 +0200 @@ -61,6 +61,12 @@ struct Session { char *name; char *val; @@ -2077,61 +2017,48 @@ index 344a1ddf9..a41c6efcd 100644 Session *session_by_tty(char *); void session_close(struct ssh *, Session *); void do_setusercontext(struct passwd *); -diff --git a/sshd-session.c b/sshd-session.c -index d6bece941..e49e4fb51 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -188,8 +188,8 @@ struct include_list includes = TAILQ_HEAD_INITIALIZER(includes); - struct sshbuf *loginmsg; +diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c +--- 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 +@@ -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 *ssh); -+void demote_sensitive_data(struct ssh *ssh); ++void destroy_sensitive_data(struct ssh *, int); ++void demote_sensitive_data(struct ssh *); + static void do_ssh2_kex(struct ssh *); - /* XXX reduce to stub once postauth split */ - int -@@ -202,6 +202,35 @@ mm_is_monitor(void) - return (pmonitor && pmonitor->m_pid > 0); + static char *listener_proctitle; +@@ -279,6 +280,15 @@ close_listen_socks(void) + num_listen_socks = 0; } -+static int -+sshkey_is_private(const struct sshkey *k) ++/* ++ * Is this process listening for clients (i.e. not specific to any specific ++ * client connection?) ++ */ ++int listening_for_clients(void) +{ -+ 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; -+ } -+#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; -+ } ++ return num_listen_socks > 0; +} + - /* - * Signal handler for the alarm after the login grace period has expired. - * As usual, this may only take signal-safe actions, even though it is -@@ -230,18 +259,40 @@ grace_alarm_handler(int sig) - _exit(EXIT_LOGIN_GRACE); + static void + close_startup_pipes(void) + { +@@ -377,18 +387,45 @@ grace_alarm_handler(int sig) + ssh_remote_port(the_active_state)); } - + -/* 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, @@ -2139,7 +2066,7 @@ index d6bece941..e49e4fb51 100644 + */ void -destroy_sensitive_data(void) -+destroy_sensitive_data(struct ssh *ssh) ++destroy_sensitive_data(struct ssh *ssh, int privsep) { u_int i; +#ifdef SSH_AUDIT_EVENTS @@ -2161,7 +2088,12 @@ index d6bece941..e49e4fb51 100644 sensitive_data.host_keys[i] = NULL; + if (fp != NULL) { +#ifdef SSH_AUDIT_EVENTS -+ audit_destroy_sensitive_data(ssh, fp, pid, uid); ++ if (privsep) ++ PRIVSEP(audit_destroy_sensitive_data(ssh, fp, ++ pid, uid)); ++ else ++ audit_destroy_sensitive_data(ssh, fp, ++ pid, uid); +#endif + free(fp); + } @@ -2172,7 +2104,7 @@ index d6bece941..e49e4fb51 100644 sshkey_free(sensitive_data.host_certificates[i]); sensitive_data.host_certificates[i] = NULL; } -@@ -250,20 +301,38 @@ destroy_sensitive_data(void) +@@ -397,20 +434,38 @@ destroy_sensitive_data(void) /* Demote private to public keys for network child */ void @@ -2212,7 +2144,43 @@ index d6bece941..e49e4fb51 100644 } /* Certs do not need demotion */ } -@@ -441,7 +510,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) +@@ -438,7 +493,7 @@ reseed_prngs(void) + } + + static void +-privsep_preauth_child(void) ++privsep_preauth_child(struct ssh *ssh) + { + gid_t gidset[1]; + +@@ -453,7 +508,7 @@ privsep_preauth_child(void) + reseed_prngs(); + + /* Demote the private keys to public keys. */ +- demote_sensitive_data(); ++ demote_sensitive_data(ssh); + + #ifdef WITH_SELINUX + sshd_selinux_change_privsep_preauth_context(); +@@ -492,7 +547,7 @@ privsep_preauth(struct ssh *ssh) + + if (use_privsep == PRIVSEP_ON) + box = ssh_sandbox_init(pmonitor); +- pid = fork(); ++ pmonitor->m_pid = pid = fork(); + if (pid == -1) { + fatal("fork of unprivileged child failed"); + } else if (pid != 0) { +@@ -537,7 +592,7 @@ privsep_preauth(struct ssh *ssh) + /* Arrange for logging to be sent to the monitor */ + set_log_handler(mm_log_handler, pmonitor); + +- privsep_preauth_child(); ++ privsep_preauth_child(ssh); + setproctitle("%s", "[net]"); + if (box != NULL) + ssh_sandbox_child(box); +@@ -589,7 +644,7 @@ privsep_postauth(struct ssh *ssh, Authct set_log_handler(mm_log_handler, pmonitor); /* Demote the private keys to public keys. */ @@ -2221,21 +2189,48 @@ index d6bece941..e49e4fb51 100644 reseed_prngs(); -@@ -1365,6 +1434,9 @@ main(int ac, char **av) +@@ -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) + { + struct pollfd *pfd = NULL; + int i, j, ret, npfd; +@@ -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); ++ destroy_sensitive_data(ssh, 1); + ssh_packet_get_bytes(ssh, &ibytes, &obytes); verbose("Transferred: sent %llu, received %llu bytes", (unsigned long long)obytes, (unsigned long long)ibytes); -@@ -1410,6 +1482,14 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey, +@@ -2513,6 +2572,15 @@ 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 @@ -2243,48 +2238,77 @@ index d6bece941..e49e4fb51 100644 + if (in_cleanup) + _exit(i); + in_cleanup = 1; - extern int auth_attempted; /* monitor.c */ - if (the_active_state != NULL && the_authctxt != NULL) { -@@ -1426,7 +1506,9 @@ cleanup_exit(int i) + do_cleanup(the_active_state, the_authctxt); + if (use_privsep && privsep_is_preauth && +@@ -2525,9 +2593,16 @@ 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 && mm_is_monitor()) +- if (the_active_state != NULL && (!use_privsep || mm_is_monitor())) + if (the_active_state != NULL && + (the_authctxt == NULL || !the_authctxt->authenticated) && -+ mm_is_monitor()) ++ (!use_privsep || mm_is_monitor())) audit_event(the_active_state, SSH_CONNECTION_ABANDON); #endif - /* Override default fatal exit value when auth was attempted */ -diff --git a/sshd.c b/sshd.c -index 3ab81e268..ed7faf96d 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -213,6 +213,15 @@ close_listen_socks(void) - num_listen_socks = 0; + _exit(i); +diff -up openssh-8.6p1/sshkey.c.audit openssh-8.6p1/sshkey.c +--- openssh-8.6p1/sshkey.c.audit 2021-04-19 16:47:35.741062014 +0200 ++++ openssh-8.6p1/sshkey.c 2021-04-19 16:47:35.759062152 +0200 +@@ -371,6 +371,38 @@ sshkey_type_is_valid_ca(int type) } -+/* -+ * Is this process listening for clients (i.e. not specific to any specific -+ * client connection?) -+ */ -+int listening_for_clients(void) + int ++sshkey_is_private(const struct sshkey *k) +{ -+ return num_listen_socks > 0; ++ 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; ++ } +} + - /* Allocate and initialise the children array */ - static void - child_alloc(void) -@@ -958,6 +967,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s, - 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); --- -2.52.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-04-19 16:47:35.741062014 +0200 ++++ openssh-8.6p1/sshkey.h 2021-04-19 16:47:35.759062152 +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); diff --git a/0023-openssh-7.6p1-cleanup-selinux.patch b/openssh-7.6p1-cleanup-selinux.patch similarity index 59% rename from 0023-openssh-7.6p1-cleanup-selinux.patch rename to openssh-7.6p1-cleanup-selinux.patch index d018772..f7cd50f 100644 --- a/0023-openssh-7.6p1-cleanup-selinux.patch +++ b/openssh-7.6p1-cleanup-selinux.patch @@ -1,58 +1,40 @@ -From 4cacb1bda51a2d91cf4cc1c8058b989dfc0c58c8 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 23/53] openssh-7.6p1-cleanup-selinux - ---- - auth2-pubkey.c | 8 ++++-- - misc.c | 5 ++-- - misc.h | 2 +- - openbsd-compat/port-linux-sshd.c | 42 +++++++++++++++++--------------- - openbsd-compat/port-linux.h | 5 ++-- - platform.c | 6 ++++- - sshconnect.c | 2 +- - sshd-auth.c | 2 +- - sshd-session.c | 6 +++-- - 9 files changed, 46 insertions(+), 32 deletions(-) - -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index c326a69ba..b7300ca9e 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -75,6 +75,8 @@ +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 @@ /* import */ extern ServerOptions options; +extern int inetd_flag; ++extern int rexeced_flag; +extern Authctxt *the_authctxt; - extern struct authmethod_cfg methodcfg_pubkey; static char * -@@ -483,7 +485,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key, + 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, the_authctxt)) == 0) ++ (inetd_flag && !rexeced_flag), the_authctxt)) == 0) goto out; uid_swapped = 1; -@@ -759,7 +762,8 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key, +@@ -981,7 +985,8 @@ user_key_command_allowed2(struct ssh *ss if ((pid = subprocess("AuthorizedKeysCommand", command, ac, av, &f, - SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD, + 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, the_authctxt)) == 0) ++ (inetd_flag && !rexeced_flag), the_authctxt)) == 0) goto out; uid_swapped = 1; -diff --git a/misc.c b/misc.c -index 7e27a38d1..2fd14159d 100644 ---- a/misc.c -+++ b/misc.c -@@ -2788,7 +2788,8 @@ stdfd_devnull(int do_stdin, int do_stdout, int do_stderr) +diff -up openssh/misc.c.refactor openssh/misc.c +--- openssh/misc.c.refactor 2019-04-04 13:19:12.235821686 +0200 ++++ openssh/misc.c 2019-04-04 13:19:12.276822078 +0200 +@@ -756,7 +756,8 @@ auth_get_canonical_hostname(struct ssh * pid_t subprocess(const char *tag, const char *command, int ac, char **av, FILE **child, u_int flags, @@ -62,7 +44,7 @@ index 7e27a38d1..2fd14159d 100644 { FILE *f = NULL; struct stat st; -@@ -2922,7 +2923,7 @@ subprocess(const char *tag, const char *command, +@@ -872,7 +873,7 @@ subprocess(const char *tag, struct passw _exit(1); } #ifdef WITH_SELINUX @@ -71,11 +53,10 @@ index 7e27a38d1..2fd14159d 100644 error ("failed to copy environment: %s", strerror(errno)); _exit(127); -diff --git a/misc.h b/misc.h -index f3c5a18c6..8cdfd7cec 100644 ---- a/misc.h -+++ b/misc.h -@@ -124,7 +124,7 @@ typedef void privrestore_fn(void); +diff -up openssh/misc.h.refactor openssh/misc.h +--- openssh/misc.h.refactor 2019-04-04 13:19:12.251821839 +0200 ++++ openssh/misc.h 2019-04-04 13:19:12.276822078 +0200 +@@ -235,7 +235,7 @@ struct passwd *fakepw(void); #define SSH_SUBPROCESS_UNSAFE_PATH (1<<3) /* Don't check for safe cmd */ #define SSH_SUBPROCESS_PRESERVE_ENV (1<<4) /* Keep parent environment */ pid_t subprocess(const char *, const char *, int, char **, FILE **, u_int, @@ -84,22 +65,36 @@ index f3c5a18c6..8cdfd7cec 100644 typedef struct arglist arglist; struct arglist { -diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -index 4d56745f7..ab083a637 100644 ---- a/openbsd-compat/port-linux-sshd.c -+++ b/openbsd-compat/port-linux-sshd.c -@@ -48,10 +48,6 @@ +diff -up openssh/openbsd-compat/port-linux.h.refactor openssh/openbsd-compat/port-linux.h +--- openssh/openbsd-compat/port-linux.h.refactor 2019-04-04 13:19:12.256821887 +0200 ++++ openssh/openbsd-compat/port-linux.h 2019-04-04 13:19:12.276822078 +0200 +@@ -26,8 +26,8 @@ void ssh_selinux_setfscreatecon(const ch + + int sshd_selinux_enabled(void); + void sshd_selinux_copy_context(void); +-void sshd_selinux_setup_exec_context(char *); +-int sshd_selinux_setup_env_variables(void); ++void sshd_selinux_setup_exec_context(char *, int, int(char *, const char *), void *, int); ++int sshd_selinux_setup_env_variables(int inetd, void *); + void sshd_selinux_change_privsep_preauth_context(void); + #endif + +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 @@ #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 sshd_selinux_enabled(void) -@@ -221,7 +217,8 @@ get_user_context(const char *sename, const char *role, const char *lvl, +@@ -223,7 +218,8 @@ get_user_context(const char *sename, con } static void @@ -109,7 +104,7 @@ index 4d56745f7..ab083a637 100644 { *role = NULL; *level = NULL; -@@ -239,8 +236,8 @@ ssh_selinux_get_role_level(char **role, const char **level) +@@ -241,8 +237,8 @@ ssh_selinux_get_role_level(char **role, /* Return the default security context for the given username */ static int @@ -120,7 +115,7 @@ index 4d56745f7..ab083a637 100644 { char *sename, *lvl; char *role; -@@ -248,7 +245,7 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -250,7 +246,7 @@ sshd_selinux_getctxbyname(char *pwname, int r = 0; context_t con = NULL; @@ -129,16 +124,16 @@ index 4d56745f7..ab083a637 100644 #ifdef HAVE_GETSEUSERBYNAME if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) { -@@ -270,7 +267,7 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -272,7 +268,7 @@ sshd_selinux_getctxbyname(char *pwname, if (r == 0) { /* If launched from xinetd, we must use current level */ -- if (inetd_flag) { +- if (inetd_flag && !rexeced_flag) { + if (inetd) { security_context_t sshdsc=NULL; if (getcon_raw(&sshdsc) < 0) -@@ -331,7 +328,8 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -333,7 +329,8 @@ sshd_selinux_getctxbyname(char *pwname, /* Setup environment variables for pam_selinux */ static int @@ -148,7 +143,7 @@ index 4d56745f7..ab083a637 100644 { const char *reqlvl; char *role; -@@ -340,11 +338,11 @@ sshd_selinux_setup_variables(int(*set_it)(char *, const char *)) +@@ -342,11 +339,11 @@ sshd_selinux_setup_variables(int(*set_it debug3_f("setting execution context"); @@ -157,12 +152,12 @@ index 4d56745f7..ab083a637 100644 rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : ""); -- if (inetd_flag) { +- if (inetd_flag && !rexeced_flag) { + if (inetd) { use_current = "1"; } else { use_current = ""; -@@ -360,9 +358,10 @@ sshd_selinux_setup_variables(int(*set_it)(char *, const char *)) +@@ -362,9 +359,10 @@ sshd_selinux_setup_variables(int(*set_it } static int @@ -175,7 +170,7 @@ index 4d56745f7..ab083a637 100644 } static int -@@ -372,25 +371,28 @@ do_setenv(char *name, const char *value) +@@ -374,25 +372,28 @@ do_setenv(char *name, const char *value) } int @@ -209,7 +204,7 @@ index 4d56745f7..ab083a637 100644 switch (security_getenforce()) { case -1: fatal_f("security_getenforce() failed"); -@@ -406,7 +408,7 @@ sshd_selinux_setup_exec_context(char *pwname) +@@ -410,7 +411,7 @@ sshd_selinux_setup_exec_context(char *pw debug3_f("setting execution context"); @@ -218,51 +213,66 @@ index 4d56745f7..ab083a637 100644 if (r >= 0) { r = setexeccon(user_ctx); if (r < 0) { -diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h -index c004071d1..26c5f773b 100644 ---- a/openbsd-compat/port-linux.h -+++ b/openbsd-compat/port-linux.h -@@ -23,8 +23,9 @@ void ssh_selinux_setup_pty(char *, const char *); - void ssh_selinux_change_context(const char *); - void ssh_selinux_setfscreatecon(const char *); - --void sshd_selinux_setup_exec_context(char *); --int sshd_selinux_setup_env_variables(void); -+int sshd_selinux_enabled(void); -+void sshd_selinux_setup_exec_context(char *, int, int(char *, const char *), void *, int); -+int sshd_selinux_setup_env_variables(int inetd, void *); - #endif - - #ifdef LINUX_OOM_ADJUST -diff --git a/platform.c b/platform.c -index c92a0cba6..66d0c2a6b 100644 ---- a/platform.c -+++ b/platform.c -@@ -33,6 +33,8 @@ - #include "openbsd-compat/openbsd-compat.h" +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 @@ + extern int use_privsep; extern ServerOptions options; +extern int inetd_flag; ++extern int rexeced_flag; +extern Authctxt *the_authctxt; - /* return 1 if we are running with privilege to swap UIDs, 0 otherwise */ - int -@@ -140,7 +142,9 @@ platform_setusercontext_post_groups(struct passwd *pw) + void + platform_pre_listen(void) +@@ -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, do_pam_putenv, the_authctxt, ++ (inetd_flag && !rexeced_flag), do_pam_putenv, the_authctxt, + options.use_pam); #endif } -diff --git a/sshconnect.c b/sshconnect.c -index 912a520c5..babe4a982 100644 ---- a/sshconnect.c -+++ b/sshconnect.c -@@ -917,7 +917,7 @@ load_hostkeys_command(struct hostkeys *hostkeys, const char *command_template, +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 +@@ -158,7 +158,7 @@ int debug_flag = 0; + static int test_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; +@@ -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, ++ options.use_pam); + #endif + #ifdef USE_PAM + if (options.use_pam) { +diff -up openssh/sshconnect.c.refactor openssh/sshconnect.c +--- openssh/sshconnect.c.refactor 2021-02-24 00:12:03.065325046 +0100 ++++ openssh/sshconnect.c 2021-02-24 00:12:12.126449544 +0100 +@@ -892,7 +892,7 @@ load_hostkeys_command(struct hostkeys *h if ((pid = subprocess(tag, command, ac, av, &f, SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_UNSAFE_PATH| @@ -271,43 +281,3 @@ index 912a520c5..babe4a982 100644 goto out; load_hostkeys_file(hostkeys, hostfile_hostname, tag, f, 1); -diff --git a/sshd-auth.c b/sshd-auth.c -index 5a4ee733c..f3c38a7d1 100644 ---- a/sshd-auth.c -+++ b/sshd-auth.c -@@ -120,7 +120,7 @@ char *config_file_name = _PATH_SERVER_CONFIG_FILE; - int debug_flag = 0; - - /* Flag indicating that the daemon is being started from inetd. */ --static int inetd_flag = 0; -+int inetd_flag = 0; - - /* Saved arguments to main(). */ - static char **saved_argv; -diff --git a/sshd-session.c b/sshd-session.c -index 4a5eaa1ff..d6bece941 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -130,7 +130,7 @@ char *config_file_name = _PATH_SERVER_CONFIG_FILE; - int debug_flag = 0; - - /* Flag indicating that the daemon is being started from inetd. */ --static int inetd_flag = 0; -+int inetd_flag = 0; - - /* debug goes to stderr unless inetd_flag is set */ - static int log_stderr = 0; -@@ -1337,7 +1337,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, do_pam_putenv, the_authctxt, -+ options.use_pam); - #endif - #ifdef USE_PAM - if (options.use_pam) { --- -2.52.0 - diff --git a/0038-openssh-7.7p1-fips.patch b/openssh-7.7p1-fips.patch similarity index 59% rename from 0038-openssh-7.7p1-fips.patch rename to openssh-7.7p1-fips.patch index 18ebed3..5351571 100644 --- a/0038-openssh-7.7p1-fips.patch +++ b/openssh-7.7p1-fips.patch @@ -1,33 +1,6 @@ -From d7dd45f9e19a71269828bc5f8567613a02f6feef Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 28 Aug 2025 14:01:38 +0200 -Subject: [PATCH 38/53] openssh-7.7p1-fips - ---- - dh.c | 41 ++++++++++++++++++++++ - dh.h | 1 + - kex-names.c | 6 +++- - kex.c | 3 +- - kexgen.c | 74 ++++++++++++++++++++++++++++++++-------- - kexgexc.c | 5 +++ - myproposal.h | 33 ++++++++++++++++++ - readconf.c | 16 ++++++--- - sandbox-seccomp-filter.c | 3 ++ - servconf.c | 18 +++++++--- - ssh-ed25519.c | 9 +++++ - ssh-gss.h | 5 +++ - ssh-keygen.c | 20 +++++++++-- - ssh-rsa.c | 3 ++ - ssh.c | 5 +++ - sshconnect2.c | 9 ++++- - sshd.c | 13 +++++++ - sshkey.c | 37 ++++++++++++++++++++ - 18 files changed, 271 insertions(+), 30 deletions(-) - -diff --git a/dh.c b/dh.c -index 168dea1dd..8c9a29fa7 100644 ---- a/dh.c -+++ b/dh.c +diff -up openssh-8.6p1/dh.c.fips openssh-8.6p1/dh.c +--- openssh-8.6p1/dh.c.fips 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/dh.c 2021-05-06 12:12:10.107634472 +0200 @@ -36,6 +36,7 @@ #include @@ -36,7 +9,7 @@ index 168dea1dd..8c9a29fa7 100644 #include "dh.h" #include "pathnames.h" -@@ -164,6 +165,12 @@ choose_dh(int min, int wantbits, int max) +@@ -164,6 +164,12 @@ choose_dh(int min, int wantbits, int max int best, bestcount, which, linenum; struct dhgroup dhg; @@ -49,7 +22,7 @@ index 168dea1dd..8c9a29fa7 100644 if ((f = fopen(get_moduli_filename(), "r")) == NULL) { logit("WARNING: could not open %s (%s), using fixed modulus", get_moduli_filename(), strerror(errno)); -@@ -502,4 +509,38 @@ dh_estimate(int bits) +@@ -502,4 +508,38 @@ dh_estimate(int bits) return 8192; } @@ -88,10 +61,9 @@ index 168dea1dd..8c9a29fa7 100644 +} + #endif /* WITH_OPENSSL */ -diff --git a/dh.h b/dh.h -index c6326a39d..e51e292b8 100644 ---- a/dh.h -+++ b/dh.h +diff -up openssh-8.6p1/dh.h.fips openssh-8.6p1/dh.h +--- openssh-8.6p1/dh.h.fips 2021-05-06 12:08:36.498926877 +0200 ++++ openssh-8.6p1/dh.h 2021-05-06 12:11:28.393298005 +0200 @@ -45,6 +45,7 @@ DH *dh_new_group_fallback(int); int dh_gen_key(DH *, int); @@ -100,19 +72,18 @@ index c6326a39d..e51e292b8 100644 u_int dh_estimate(int); void dh_set_moduli_file(const char *); -diff --git a/kex-names.c b/kex-names.c -index 31e395aa2..1360a4095 100644 ---- a/kex-names.c -+++ b/kex-names.c -@@ -33,6 +33,7 @@ +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 +@@ -39,6 +39,7 @@ #ifdef WITH_OPENSSL #include +#include - #include - #endif - -@@ -208,7 +209,10 @@ kex_names_valid(const char *names) + #include + # ifdef HAVE_EVP_KDF_CTX_NEW_ID + # include +@@ -203,7 +203,10 @@ kex_names_valid(const char *names) for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { if (kex_alg_by_name(p) == NULL) { @@ -124,149 +95,9 @@ index 31e395aa2..1360a4095 100644 free(s); return 0; } -diff --git a/kex.c b/kex.c -index 44f350ce8..da2a537ce 100644 ---- a/kex.c -+++ b/kex.c -@@ -38,6 +38,7 @@ - #ifdef WITH_OPENSSL - #include - #include -+#include - # ifdef HAVE_EVP_KDF_CTX_NEW - # include - # include -@@ -107,7 +108,7 @@ kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX], - - /* 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/kexgen.c b/kexgen.c -index 58edc79ad..9a970adf1 100644 ---- a/kexgen.c -+++ b/kexgen.c -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - - #include "sshkey.h" - #include "kex.h" -@@ -115,13 +116,28 @@ kex_gen_client(struct ssh *ssh) - break; - #endif /* WITH_OPENSSL */ - case KEX_C25519_SHA256: -- r = kex_c25519_keypair(kex); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_c25519_keypair(kex); -+ } - break; - case KEX_KEM_SNTRUP761X25519_SHA512: -- r = kex_kem_sntrup761x25519_keypair(kex); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_kem_sntrup761x25519_keypair(kex); -+ } - break; - 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; -@@ -189,15 +205,30 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) - break; - #endif /* WITH_OPENSSL */ - case KEX_C25519_SHA256: -- r = kex_c25519_dec(kex, server_blob, &shared_secret); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_c25519_dec(kex, server_blob, &shared_secret); -+ } - break; - case KEX_KEM_SNTRUP761X25519_SHA512: -- r = kex_kem_sntrup761x25519_dec(kex, server_blob, -- &shared_secret); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_kem_sntrup761x25519_dec(kex, server_blob, -+ &shared_secret); -+ } - break; - 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; -@@ -312,16 +343,31 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) - break; - #endif /* WITH_OPENSSL */ - case KEX_C25519_SHA256: -- r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, -- &shared_secret); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ } - break; - case KEX_KEM_SNTRUP761X25519_SHA512: -- r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, -- &server_pubkey, &shared_secret); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, -+ &server_pubkey, &shared_secret); -+ } - break; - 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: - r = SSH_ERR_INVALID_ARGUMENT; -diff --git a/kexgexc.c b/kexgexc.c -index 097d83f30..ccbb9b580 100644 ---- a/kexgexc.c -+++ b/kexgexc.c +diff -up openssh-8.6p1/kexgexc.c.fips openssh-8.6p1/kexgexc.c +--- openssh-8.6p1/kexgexc.c.fips 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/kexgexc.c 2021-05-06 12:08:36.498926877 +0200 @@ -28,6 +28,7 @@ #ifdef WITH_OPENSSL @@ -274,8 +105,8 @@ index 097d83f30..ccbb9b580 100644 +#include #include - #include "openbsd-compat/openssl-compat.h" -@@ -115,6 +116,10 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh) + #include +@@ -115,6 +116,10 @@ input_kex_dh_gex_group(int type, u_int32 r = SSH_ERR_ALLOC_FAIL; goto out; } @@ -286,11 +117,10 @@ index 097d83f30..ccbb9b580 100644 p = g = NULL; /* belong to kex->dh now */ /* generate and send 'e', client DH public key */ -diff --git a/myproposal.h b/myproposal.h -index 8fe9276c2..3e0ec6826 100644 ---- a/myproposal.h -+++ b/myproposal.h -@@ -58,6 +58,18 @@ +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-512," \ "rsa-sha2-256" @@ -308,8 +138,8 @@ index 8fe9276c2..3e0ec6826 100644 + #define KEX_SERVER_ENCRYPT \ "chacha20-poly1305@openssh.com," \ - "aes128-gcm@openssh.com,aes256-gcm@openssh.com," \ -@@ -79,6 +91,27 @@ + "aes128-ctr,aes192-ctr,aes256-ctr," \ +@@ -78,6 +92,27 @@ #define KEX_CLIENT_MAC KEX_SERVER_MAC @@ -337,10 +167,9 @@ index 8fe9276c2..3e0ec6826 100644 /* Not a KEX value, but here so all the algorithm defaults are together */ #define SSH_ALLOWED_CA_SIGALGS \ "ssh-ed25519," \ -diff --git a/readconf.c b/readconf.c -index 3f67f4de4..b6ad47b49 100644 ---- a/readconf.c -+++ b/readconf.c +diff -up openssh-8.6p1/readconf.c.fips openssh-8.6p1/readconf.c +--- openssh-8.6p1/readconf.c.fips 2021-05-06 12:08:36.428926336 +0200 ++++ openssh-8.6p1/readconf.c 2021-05-06 12:08:36.499926885 +0200 @@ -39,6 +39,7 @@ #include #include @@ -349,7 +178,7 @@ index 3f67f4de4..b6ad47b49 100644 #ifdef USE_SYSTEM_GLOB # include #else -@@ -3078,11 +3079,16 @@ fill_default_options(Options * options) +@@ -2538,11 +2538,16 @@ fill_default_options(Options * options) all_key = sshkey_alg_list(0, 0, 1, ','); all_sig = sshkey_alg_list(0, 1, 1, ','); /* remove unsupported algos from default lists */ @@ -371,11 +200,10 @@ index 3f67f4de4..b6ad47b49 100644 #define ASSEMBLE(what, defaults, all) \ do { \ if ((r = kex_assemble_names(&options->what, \ -diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c -index e0f2d4289..c52f64897 100644 ---- a/sandbox-seccomp-filter.c -+++ b/sandbox-seccomp-filter.c -@@ -258,6 +258,9 @@ static const struct sock_filter preauth_insns[] = { +diff -up openssh-8.6p1/sandbox-seccomp-filter.c.fips openssh-8.6p1/sandbox-seccomp-filter.c +--- openssh-8.6p1/sandbox-seccomp-filter.c.fips 2021-05-06 12:08:36.463926606 +0200 ++++ openssh-8.6p1/sandbox-seccomp-filter.c 2021-05-06 12:08:36.499926885 +0200 +@@ -160,6 +160,9 @@ static const struct sock_filter preauth_ #ifdef __NR_open SC_DENY(__NR_open, EACCES), #endif @@ -385,22 +213,18 @@ index e0f2d4289..c52f64897 100644 #ifdef __NR_openat SC_DENY(__NR_openat, EACCES), #endif -diff --git a/servconf.c b/servconf.c -index ac84b74d9..f78615c28 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -37,7 +37,10 @@ +diff -up openssh-8.6p1/servconf.c.fips openssh-8.6p1/servconf.c +--- openssh-8.6p1/servconf.c.fips 2021-05-06 12:08:36.455926545 +0200 ++++ openssh-8.6p1/servconf.c 2021-05-06 12:08:36.500926893 +0200 +@@ -38,6 +38,7 @@ #include #include #include +#include -+#ifdef HAVE_UTIL_H + #ifdef HAVE_UTIL_H #include -+#endif - #ifdef USE_SYSTEM_GLOB - # include - #else -@@ -244,11 +247,16 @@ assemble_algorithms(ServerOptions *o) + #endif +@@ -226,11 +226,16 @@ assemble_algorithms(ServerOptions *o) all_key = sshkey_alg_list(0, 0, 1, ','); all_sig = sshkey_alg_list(0, 1, 1, ','); /* remove unsupported algos from default lists */ @@ -422,150 +246,10 @@ index ac84b74d9..f78615c28 100644 #define ASSEMBLE(what, defaults, all) \ do { \ if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \ -diff --git a/ssh-ed25519.c b/ssh-ed25519.c -index c8caa2221..4bcd9ef81 100644 ---- a/ssh-ed25519.c -+++ b/ssh-ed25519.c -@@ -24,6 +24,7 @@ - - #include - #include -+#include - - #include "log.h" - #include "sshbuf.h" -@@ -163,6 +164,10 @@ ssh_ed25519_sign(struct sshkey *key, - key->ed25519_sk == NULL || - datalen >= INT_MAX - crypto_sign_ed25519_BYTES) - return SSH_ERR_INVALID_ARGUMENT; -+ if (FIPS_mode()) { -+ logit_f("Ed25519 keys are not allowed in FIPS mode"); -+ return SSH_ERR_INVALID_ARGUMENT; -+ } - smlen = slen = datalen + crypto_sign_ed25519_BYTES; - if ((sig = malloc(slen)) == NULL) - return SSH_ERR_ALLOC_FAIL; -@@ -244,6 +249,10 @@ ssh_ed25519_verify(const struct sshkey *key, - 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(sig, siglen)) == NULL) - return SSH_ERR_ALLOC_FAIL; -diff --git a/ssh-gss.h b/ssh-gss.h -index a894e23c9..329dc9da0 100644 ---- a/ssh-gss.h -+++ b/ssh-gss.h -@@ -88,6 +88,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 --git a/ssh-keygen.c b/ssh-keygen.c -index 3c582a83a..afa279097 100644 ---- a/ssh-keygen.c -+++ b/ssh-keygen.c -@@ -22,6 +22,7 @@ - #include "openbsd-compat/openssl-compat.h" - #include - #include -+#include - #include - #endif - -@@ -68,6 +69,7 @@ - #endif - - #define DEFAULT_KEY_TYPE_NAME "ed25519" -+#define FIPS_DEFAULT_KEY_TYPE_NAME "rsa" - - /* - * Default number of bits in the RSA and ECDSA keys. These value can be -@@ -195,6 +197,10 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp) - #endif - } - #ifdef WITH_OPENSSL -+ if (FIPS_mode()) { -+ if (type == KEY_ED25519 || type == KEY_ED25519_SK) -+ fatal("ED25519 keys are not allowed in FIPS mode"); -+ } - switch (type) { - case KEY_RSA: - if (*bitsp < SSH_RSA_MINIMUM_MODULUS_SIZE) -@@ -248,7 +254,7 @@ ask_filename(struct passwd *pw, const char *prompt) - 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 OPENSSL_HAS_ECC -@@ -1057,9 +1063,17 @@ do_gen_all_hostkeys(struct passwd *pw) - first = 1; - printf("%s: generating new host keys: ", __progname); - } -+ 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_ED25519) { -+ logit("Skipping %s key in FIPS mode", -+ key_types[i].key_type_display); -+ goto next; -+ } -+ - printf("%s ", key_types[i].key_type_display); - fflush(stdout); -- 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)); -@@ -3757,7 +3771,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 --git a/ssh-rsa.c b/ssh-rsa.c -index fe1518984..9428df8d1 100644 ---- a/ssh-rsa.c -+++ b/ssh-rsa.c -@@ -25,6 +25,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -142,6 +143,8 @@ ssh_rsa_generate(struct sshkey *k, int bits) - 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 --git a/ssh.c b/ssh.c -index 8d27f6379..7d6ba516e 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -74,6 +74,7 @@ +diff -up openssh-8.6p1/ssh.c.fips openssh-8.6p1/ssh.c +--- openssh-8.6p1/ssh.c.fips 2021-05-06 12:08:36.467926637 +0200 ++++ openssh-8.6p1/ssh.c 2021-05-06 12:08:36.500926893 +0200 +@@ -77,6 +77,7 @@ #include #include #endif @@ -573,7 +257,7 @@ index 8d27f6379..7d6ba516e 100644 #include "openbsd-compat/openssl-compat.h" #include "openbsd-compat/sys-queue.h" -@@ -1664,6 +1665,10 @@ main(int ac, char **av) +@@ -1516,6 +1517,10 @@ main(int ac, char **av) exit(0); } @@ -584,10 +268,9 @@ index 8d27f6379..7d6ba516e 100644 /* Expand SecurityKeyProvider if it refers to an environment variable */ if (options.sk_provider != NULL && *options.sk_provider == '$' && strlen(options.sk_provider) > 1) { -diff --git a/sshconnect2.c b/sshconnect2.c -index b253f991b..fffa66c8d 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c +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 @@ -45,6 +45,8 @@ #include #endif @@ -597,48 +280,95 @@ index b253f991b..fffa66c8d 100644 #include "openbsd-compat/sys-queue.h" #include "xmalloc.h" -@@ -262,6 +264,9 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, +@@ -269,36 +271,41 @@ ssh_kex2(struct ssh *ssh, char *host, st #if defined(GSSAPI) && defined(WITH_OPENSSL) if (options.gss_keyex) { -+ char * gss_kex_filtered = FIPS_mode() ? -+ match_filter_allowlist(options.gss_kex_algorithms, GSS_KEX_DEFAULT_KEX_FIPS) : xstrdup(options.gss_kex_algorithms); +- /* 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]; + - /* Add the GSSAPI mechanisms currently supported on this - * client to the key exchange algorithm proposal */ - orig = myproposal[PROPOSAL_KEX_ALGS]; -@@ -281,7 +286,9 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, - } ++ 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, +- 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], +- "%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 (gss) { - debug("Offering GSSAPI proposal: %s", gss); - xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -diff --git a/sshd.c b/sshd.c -index ed7faf96d..de2baa5e4 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -44,6 +44,7 @@ - #include ++ /* 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); ++ } + } + } + #endif +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 @@ + #endif #include #include +#include #include - #include #include -@@ -55,6 +56,7 @@ - #ifdef WITH_OPENSSL - #include + #include +@@ -77,6 +78,7 @@ + #include + #include #include +#include #include "openbsd-compat/openssl-compat.h" #endif -@@ -1613,6 +1615,13 @@ main(int ac, char **av) +@@ -1931,6 +1931,13 @@ main(int ac, char **av) &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) do_log2_r(r, ll, "Unable to load host key \"%s\"", options.host_key_files[i]); @@ -652,7 +382,7 @@ index ed7faf96d..de2baa5e4 100644 if (sshkey_is_sk(key) && key->sk_flags & SSH_SK_USER_PRESENCE_REQD) { debug("host key %s requires user presence, ignoring", -@@ -1836,6 +1845,10 @@ main(int ac, char **av) +@@ -2110,6 +2113,10 @@ main(int ac, char **av) /* Reinitialize the log (because of the fork above). */ log_init(__progname, options.log_level, options.log_facility, log_stderr); @@ -663,27 +393,45 @@ index ed7faf96d..de2baa5e4 100644 /* * Chdir to the root directory so that the current disk can be * unmounted if desired. -diff --git a/sshkey.c b/sshkey.c -index 148fee2b7..394d9b105 100644 ---- a/sshkey.c -+++ b/sshkey.c +@@ -2494,10 +2501,14 @@ do_ssh2_kex(struct ssh *ssh) + if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) + orig = NULL; + +- if (options.gss_keyex) +- gss = ssh_gssapi_server_mechanisms(); +- else +- gss = NULL; ++ if (options.gss_keyex) { ++ if (FIPS_mode()) { ++ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); ++ options.gss_keyex = 0; ++ } else { ++ gss = ssh_gssapi_server_mechanisms(); ++ } ++ } + + if (gss && orig) + xasprintf(&newstr, "%s,%s", gss, orig); +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 @@ -36,6 +36,7 @@ - #include - #include #include + #include + #include +#include #endif #include "crypto_api.h" -@@ -58,6 +59,7 @@ +@@ -57,6 +58,7 @@ #define SSHKEY_INTERNAL #include "sshkey.h" #include "match.h" +#include "log.h" #include "ssh-sk.h" - #include "ssh-pkcs11.h" -@@ -386,6 +388,18 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) + #ifdef WITH_XMSS +@@ -285,6 +285,18 @@ sshkey_alg_list(int certs_only, int plai impl = keyimpls[i]; if (impl->name == NULL || impl->type == KEY_NULL) continue; @@ -702,7 +450,7 @@ index 148fee2b7..394d9b105 100644 if (!include_sigonly && impl->sigonly) continue; if ((certs_only && !impl->cert) || (plain_only && impl->cert)) -@@ -1418,6 +1432,20 @@ sshkey_read(struct sshkey *ret, char **cpp) +@@ -1503,6 +1503,20 @@ sshkey_read(struct sshkey *ret, char **c return SSH_ERR_EC_CURVE_MISMATCH; } @@ -723,29 +471,208 @@ index 148fee2b7..394d9b105 100644 /* Fill in ret from parsed key */ sshkey_free_contents(ret); *ret = *k; -@@ -2251,6 +2279,11 @@ sshkey_sign(struct sshkey *key, +@@ -2916,6 +2916,11 @@ sshkey_sign(struct sshkey *key, *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 (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) -@@ -2290,6 +2323,10 @@ sshkey_verify(const struct sshkey *key, +@@ -2973,6 +2978,10 @@ sshkey_verify(const struct sshkey *key, *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))) { ++ 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 +@@ -20,6 +20,7 @@ + + #ifdef WITH_OPENSSL + #include ++#include + #include + #include "openbsd-compat/openssl-compat.h" + #endif +@@ -205,6 +205,12 @@ type_bits_valid(int type, const char *na + #endif + } + #ifdef WITH_OPENSSL ++ if (FIPS_mode()) { ++ if (type == KEY_DSA) ++ fatal("DSA keys are not allowed in FIPS mode"); ++ if (type == KEY_ED25519 || type == KEY_ED25519_SK) ++ fatal("ED25519 keys are not allowed in FIPS mode"); ++ } + switch (type) { + case KEY_DSA: + if (*bitsp != 1024) +@@ -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); ++ ++ /* Skip the keys that are not supported in FIPS mode */ ++ if (FIPS_mode() && (type == KEY_DSA || type == KEY_ED25519)) { ++ logit("Skipping %s key in FIPS mode", ++ key_types[i].key_type_display); ++ goto next; ++ } ++ + printf("%s ", key_types[i].key_type_display); + fflush(stdout); +- type = sshkey_type_from_name(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-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 + #include +@@ -1705,6 +1707,8 @@ ssh_rsa_generate(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; + } +diff -up openssh-8.7p1/kexgen.c.fips3 openssh-8.7p1/kexgen.c +--- openssh-8.7p1/kexgen.c.fips3 2022-07-11 16:11:21.973519913 +0200 ++++ openssh-8.7p1/kexgen.c 2022-07-11 16:25:31.172187365 +0200 +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include "sshkey.h" + #include "kex.h" +@@ -115,10 +116,20 @@ kex_gen_client(struct ssh *ssh) + break; + #endif + case KEX_C25519_SHA256: +- r = kex_c25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_keypair(kex); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_keypair(kex); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +@@ -186,11 +197,21 @@ input_kex_gen_reply(int type, u_int32_t + break; + #endif + case KEX_C25519_SHA256: +- r = kex_c25519_dec(kex, server_blob, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_dec(kex, server_blob, &shared_secret); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_dec(kex, server_blob, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_dec(kex, server_blob, ++ &shared_secret); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +@@ -285,12 +306,22 @@ input_kex_gen_init(int type, u_int32_t s + break; + #endif + case KEX_C25519_SHA256: +- r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, ++ &shared_secret); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, +- &server_pubkey, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +diff -up openssh-8.7p1/ssh-ed25519.c.fips3 openssh-8.7p1/ssh-ed25519.c +--- openssh-8.7p1/ssh-ed25519.c.fips3 2022-07-11 16:53:41.428343304 +0200 ++++ openssh-8.7p1/ssh-ed25519.c 2022-07-11 16:56:09.284663661 +0200 +@@ -24,6 +24,7 @@ + + #include + #include ++#include + + #include "log.h" + #include "sshbuf.h" +@@ -52,6 +53,10 @@ ssh_ed25519_sign(const struct sshkey *ke + key->ed25519_sk == NULL || + datalen >= INT_MAX - crypto_sign_ed25519_BYTES) + return SSH_ERR_INVALID_ARGUMENT; ++ if (FIPS_mode()) { + logit_f("Ed25519 keys are not allowed in FIPS mode"); + return SSH_ERR_INVALID_ARGUMENT; + } - if ((impl = sshkey_impl_from_key(key)) == NULL) - return SSH_ERR_KEY_TYPE_UNKNOWN; - return impl->funcs->verify(key, sig, siglen, data, dlen, --- -2.52.0 - + smlen = slen = datalen + crypto_sign_ed25519_BYTES; + if ((sig = malloc(slen)) == NULL) + return SSH_ERR_ALLOC_FAIL; +@@ -108,6 +113,10 @@ ssh_ed25519_verify(const struct sshkey * + 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(sig, siglen)) == NULL) + return SSH_ERR_ALLOC_FAIL; diff --git a/0013-openssh-7.7p1-gssapi-new-unique.patch b/openssh-7.7p1-gssapi-new-unique.patch similarity index 78% rename from 0013-openssh-7.7p1-gssapi-new-unique.patch rename to openssh-7.7p1-gssapi-new-unique.patch index 89fb40d..544932b 100644 --- a/0013-openssh-7.7p1-gssapi-new-unique.patch +++ b/openssh-7.7p1-gssapi-new-unique.patch @@ -1,25 +1,26 @@ -From 1a5b32dbf550467a4ae19351667bcfdf9c52e44d Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 13/53] openssh-7.7p1-gssapi-new-unique - ---- - auth-krb5.c | 262 ++++++++++++++++++++++++++++++++++++++++++------ - auth.h | 3 +- - gss-serv-krb5.c | 42 +++----- - gss-serv.c | 10 +- - servconf.c | 12 ++- - servconf.h | 2 + - session.c | 5 +- - ssh-gss.h | 4 +- - sshd-session.c | 2 +- - sshd_config.5 | 8 ++ - 10 files changed, 279 insertions(+), 71 deletions(-) - -diff --git a/auth-krb5.c b/auth-krb5.c -index 9d2f1f0ea..035032221 100644 ---- a/auth-krb5.c -+++ b/auth-krb5.c +diff -up openssh-8.6p1/auth.h.ccache_name openssh-8.6p1/auth.h +--- 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; + char *krb5_ccname; ++ int krb5_set_env; + #endif + struct sshbuf *loginmsg; + +@@ -231,7 +232,7 @@ struct passwd *fakepw(void); + int sys_auth_passwd(struct ssh *, const char *); + + #if defined(KRB5) && !defined(HEIMDAL) +-krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *); ++krb5_error_code ssh_krb5_cc_new_unique(krb5_context, krb5_ccache *, int *); + #endif + + #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-04-19 14:40:55.142832954 +0200 @@ -51,6 +51,7 @@ #include #include @@ -28,7 +29,7 @@ index 9d2f1f0ea..035032221 100644 extern ServerOptions options; -@@ -77,7 +78,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password) +@@ -77,7 +78,7 @@ auth_krb5_password(Authctxt *authctxt, c #endif krb5_error_code problem; krb5_ccache ccache = NULL; @@ -37,7 +38,7 @@ index 9d2f1f0ea..035032221 100644 char *client, *platform_client; const char *errmsg; -@@ -163,8 +164,8 @@ auth_krb5_password(Authctxt *authctxt, const char *password) +@@ -163,8 +164,8 @@ auth_krb5_password(Authctxt *authctxt, c goto out; } @@ -48,7 +49,7 @@ index 9d2f1f0ea..035032221 100644 if (problem) goto out; -@@ -179,15 +180,14 @@ auth_krb5_password(Authctxt *authctxt, const char *password) +@@ -179,15 +180,14 @@ auth_krb5_password(Authctxt *authctxt, c goto out; #endif @@ -69,7 +70,7 @@ index 9d2f1f0ea..035032221 100644 do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); #endif -@@ -223,11 +223,54 @@ auth_krb5_password(Authctxt *authctxt, const char *password) +@@ -223,11 +223,54 @@ auth_krb5_password(Authctxt *authctxt, c void krb5_cleanup_proc(Authctxt *authctxt) { @@ -125,29 +126,12 @@ index 9d2f1f0ea..035032221 100644 if (authctxt->krb5_user) { krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); authctxt->krb5_user = NULL; -@@ -238,36 +281,189 @@ krb5_cleanup_proc(Authctxt *authctxt) +@@ -238,36 +281,188 @@ krb5_cleanup_proc(Authctxt *authctxt) } } -#ifndef HEIMDAL --krb5_error_code --ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { -- int tmpfd, ret, oerrno; -- char ccname[40]; -- mode_t old_umask; - -- ret = snprintf(ccname, sizeof(ccname), -- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); -- if (ret < 0 || (size_t)ret >= sizeof(ccname)) -- return ENOMEM; -- -- old_umask = umask(0177); -- tmpfd = mkstemp(ccname + strlen("FILE:")); -- oerrno = errno; -- umask(old_umask); -- if (tmpfd == -1) { -- logit("mkstemp(): %.100s", strerror(oerrno)); -- return oerrno; ++ +#if !defined(HEIMDAL) +int +ssh_asprintf_append(char **dsc, const char *fmt, ...) { @@ -165,8 +149,7 @@ index 9d2f1f0ea..035032221 100644 + old = *dsc; + + i = asprintf(dsc, "%s%s", *dsc, src); -+ if (i == -1) { -+ *dsc = old; ++ if (i == -1 || src == NULL) { + free(src); + return -1; + } @@ -213,9 +196,8 @@ index 9d2f1f0ea..035032221 100644 + /* unknown token, fallback to the default */ + goto cleanup; + } - } - -- if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { ++ } ++ + if (ssh_asprintf_append(&r, "%s", p_o) == -1) + goto cleanup; + @@ -250,13 +232,29 @@ index 9d2f1f0ea..035032221 100644 + return ret; +} + -+krb5_error_code + krb5_error_code +-ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { +- int tmpfd, ret, oerrno; +- char ccname[40]; +ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environment) { + int tmpfd, ret, oerrno, type_len; + char *ccname = NULL; -+ mode_t old_umask; + mode_t old_umask; + char *type = NULL, *colon = NULL; -+ + +- ret = snprintf(ccname, sizeof(ccname), +- "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); +- if (ret < 0 || (size_t)ret >= sizeof(ccname)) +- return ENOMEM; +- +- old_umask = umask(0177); +- tmpfd = mkstemp(ccname + strlen("FILE:")); +- oerrno = errno; +- umask(old_umask); +- if (tmpfd == -1) { +- logit("mkstemp(): %.100s", strerror(oerrno)); +- return oerrno; +- } + debug3_f("called"); + if (need_environment) + *need_environment = 0; @@ -271,7 +269,8 @@ index 9d2f1f0ea..035032221 100644 + "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); + if (ret < 0) + return ENOMEM; -+ + +- if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { + old_umask = umask(0177); + tmpfd = mkstemp(ccname + strlen("FILE:")); oerrno = errno; @@ -338,32 +337,42 @@ index 9d2f1f0ea..035032221 100644 } #endif /* !HEIMDAL */ #endif /* KRB5 */ -diff --git a/auth.h b/auth.h -index 83d07ae8b..10e88e11f 100644 ---- a/auth.h -+++ b/auth.h -@@ -85,6 +85,7 @@ struct Authctxt { - krb5_principal krb5_user; - char *krb5_ticket_file; - char *krb5_ccname; -+ int krb5_set_env; - #endif - struct sshbuf *loginmsg; +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-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) + } -@@ -245,7 +246,7 @@ FILE *auth_openprincipals(const char *, struct passwd *, int); - int sys_auth_passwd(struct ssh *, const char *); + /* As user */ +-void ++int + ssh_gssapi_storecreds(void) + { + if (gssapi_client.mech && gssapi_client.mech->storecreds) { +- (*gssapi_client.mech->storecreds)(&gssapi_client); ++ return (*gssapi_client.mech->storecreds)(&gssapi_client); + } else + debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); ++ ++ return 0; + } - #if defined(KRB5) && !defined(HEIMDAL) --krb5_error_code ssh_krb5_cc_gen(krb5_context, krb5_ccache *); -+krb5_error_code ssh_krb5_cc_new_unique(krb5_context, krb5_ccache *, int *); + /* This allows GSSAPI methods to do things to the child's environment based +@@ -499,9 +501,7 @@ ssh_gssapi_rekey_creds(void) { + char *envstr; #endif - #endif /* AUTH_H */ -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index 14502c5a6..df55512d3 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c -@@ -267,7 +267,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, +- if (gssapi_client.store.filename == NULL && +- gssapi_client.store.envval == NULL && +- gssapi_client.store.envvar == NULL) ++ if (gssapi_client.store.envval == NULL) + return; + + ok = PRIVSEP(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-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 */ @@ -372,7 +381,7 @@ index 14502c5a6..df55512d3 100644 ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) { krb5_ccache ccache; -@@ -276,14 +276,15 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -276,14 +276,15 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl OM_uint32 maj_status, min_status; const char *new_ccname, *new_cctype; const char *errmsg; @@ -390,7 +399,7 @@ index 14502c5a6..df55512d3 100644 #ifdef HEIMDAL # ifdef HAVE_KRB5_CC_NEW_UNIQUE -@@ -297,14 +298,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -297,14 +298,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl krb5_get_err_text(krb_context, problem)); # endif krb5_free_error_message(krb_context, errmsg); @@ -409,7 +418,7 @@ index 14502c5a6..df55512d3 100644 } #endif /* #ifdef HEIMDAL */ -@@ -313,7 +314,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -313,7 +314,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl errmsg = krb5_get_error_message(krb_context, problem); logit("krb5_parse_name(): %.100s", errmsg); krb5_free_error_message(krb_context, errmsg); @@ -418,7 +427,7 @@ index 14502c5a6..df55512d3 100644 } if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) { -@@ -322,7 +323,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -322,7 +323,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl krb5_free_error_message(krb_context, errmsg); krb5_free_principal(krb_context, princ); krb5_cc_destroy(krb_context, ccache); @@ -427,7 +436,7 @@ index 14502c5a6..df55512d3 100644 } krb5_free_principal(krb_context, princ); -@@ -331,32 +332,21 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -331,32 +332,21 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl client->creds, ccache))) { logit("gss_krb5_copy_ccache() failed"); krb5_cc_destroy(krb_context, ccache); @@ -465,7 +474,7 @@ index 14502c5a6..df55512d3 100644 do_pam_putenv(client->store.envvar, client->store.envval); #endif -@@ -364,7 +354,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) +@@ -364,7 +354,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl client->store.data = krb_context; @@ -474,44 +483,10 @@ index 14502c5a6..df55512d3 100644 } int -diff --git a/gss-serv.c b/gss-serv.c -index 6bac42931..d2bc03486 100644 ---- a/gss-serv.c -+++ b/gss-serv.c -@@ -414,13 +414,15 @@ ssh_gssapi_cleanup_creds(void) - } - - /* As user */ --void -+int - ssh_gssapi_storecreds(void) - { - if (gssapi_client.mech && gssapi_client.mech->storecreds) { -- (*gssapi_client.mech->storecreds)(&gssapi_client); -+ return (*gssapi_client.mech->storecreds)(&gssapi_client); - } else - debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); -+ -+ return 0; - } - - /* This allows GSSAPI methods to do things to the child's environment based -@@ -500,9 +502,7 @@ ssh_gssapi_rekey_creds(void) { - char *envstr; - #endif - -- if (gssapi_client.store.filename == NULL && -- gssapi_client.store.envval == NULL && -- gssapi_client.store.envvar == NULL) -+ if (gssapi_client.store.envval == NULL) - return; - - ok = mm_ssh_gssapi_update_creds(&gssapi_client.store); -diff --git a/servconf.c b/servconf.c -index 3b93ca829..7bf1507df 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -136,6 +136,7 @@ initialize_server_options(ServerOptions *options) +diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c +--- 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; options->kerberos_get_afs_token = -1; @@ -519,7 +494,7 @@ index 3b93ca829..7bf1507df 100644 options->gss_authentication=-1; options->gss_keyex = -1; options->gss_cleanup_creds = -1; -@@ -376,6 +377,8 @@ fill_default_server_options(ServerOptions *options) +@@ -359,6 +360,8 @@ fill_default_server_options(ServerOption options->kerberos_ticket_cleanup = 1; if (options->kerberos_get_afs_token == -1) options->kerberos_get_afs_token = 0; @@ -528,16 +503,16 @@ index 3b93ca829..7bf1507df 100644 if (options->gss_authentication == -1) options->gss_authentication = 0; if (options->gss_keyex == -1) -@@ -558,7 +561,7 @@ typedef enum { - sPort, sHostKeyFile, sLoginGraceTime, - sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, +@@ -506,7 +509,7 @@ typedef enum { + sPort, sHostKeyFile, sLoginGraceTime, + sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, + sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, - sKerberosGetAFSToken, sPasswordAuthentication, + sKerberosGetAFSToken, sKerberosUniqueCCache, sPasswordAuthentication, - sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, - sPrintMotd, sPrintLastLog, sIgnoreRhosts, - sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, -@@ -649,11 +652,13 @@ static struct { + sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, +@@ -593,11 +597,13 @@ static struct { #else { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, #endif @@ -551,7 +526,7 @@ index 3b93ca829..7bf1507df 100644 #endif { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, -@@ -1662,6 +1667,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, +@@ -1573,6 +1579,10 @@ process_server_config_line_depth(ServerO intptr = &options->kerberos_get_afs_token; goto parse_flag; @@ -562,7 +537,7 @@ index 3b93ca829..7bf1507df 100644 case sGssAuthentication: intptr = &options->gss_authentication; goto parse_flag; -@@ -3295,6 +3304,7 @@ dump_config(ServerOptions *o) +@@ -2891,6 +2901,7 @@ dump_config(ServerOptions *o) # ifdef USE_AFS dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token); # endif @@ -570,11 +545,10 @@ index 3b93ca829..7bf1507df 100644 #endif #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); -diff --git a/servconf.h b/servconf.h -index c3f501400..a4a38d6d7 100644 ---- a/servconf.h -+++ b/servconf.h -@@ -149,6 +149,8 @@ typedef struct { +diff -up openssh-8.6p1/servconf.h.ccache_name openssh-8.6p1/servconf.h +--- 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 * authenticated with Kerberos. */ @@ -583,11 +557,10 @@ index c3f501400..a4a38d6d7 100644 int gss_authentication; /* If true, permit GSSAPI authentication */ int gss_keyex; /* If true, permit GSSAPI key exchange */ int gss_cleanup_creds; /* If true, destroy cred cache on logout */ -diff --git a/session.c b/session.c -index 3eae5bdf3..b8a2dae92 100644 ---- a/session.c -+++ b/session.c -@@ -987,7 +987,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) +diff -up openssh-8.6p1/session.c.ccache_name openssh-8.6p1/session.c +--- 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 */ @@ -597,7 +570,7 @@ index 3eae5bdf3..b8a2dae92 100644 #endif /* Set basic environment. */ -@@ -1063,7 +1064,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) +@@ -1114,7 +1115,7 @@ do_setup_env(struct ssh *ssh, Session *s } #endif #ifdef KRB5 @@ -606,33 +579,10 @@ index 3eae5bdf3..b8a2dae92 100644 child_set_env(&env, &envsize, "KRB5CCNAME", s->authctxt->krb5_ccname); #endif -diff --git a/ssh-gss.h b/ssh-gss.h -index db34d77f4..a894e23c9 100644 ---- a/ssh-gss.h -+++ b/ssh-gss.h -@@ -116,7 +116,7 @@ typedef struct ssh_gssapi_mech_struct { - int (*dochild) (ssh_gssapi_client *); - int (*userok) (ssh_gssapi_client *, char *); - int (*localname) (ssh_gssapi_client *, char **); -- void (*storecreds) (ssh_gssapi_client *); -+ int (*storecreds) (ssh_gssapi_client *); - int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); - } ssh_gssapi_mech; - -@@ -186,7 +186,7 @@ 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); -+int ssh_gssapi_storecreds(void); - const char *ssh_gssapi_displayname(void); - - char *ssh_gssapi_server_mechanisms(void); -diff --git a/sshd-session.c b/sshd-session.c -index 6e28020e9..028d5850e 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -1327,7 +1327,7 @@ main(int ac, char **av) +diff -up openssh-8.6p1/sshd.c.ccache_name openssh-8.6p1/sshd.c +--- openssh-8.6p1/sshd.c.ccache_name 2021-04-19 14:05:10.849744540 +0200 ++++ openssh-8.6p1/sshd.c 2021-04-19 14:05:10.855744584 +0200 +@@ -2284,7 +2284,7 @@ main(int ac, char **av) #ifdef GSSAPI if (options.gss_authentication) { temporarily_use_uid(authctxt->pw); @@ -641,11 +591,10 @@ index 6e28020e9..028d5850e 100644 restore_uid(); } #endif -diff --git a/sshd_config.5 b/sshd_config.5 -index b90068bf3..cae0fd0b4 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -1032,6 +1032,14 @@ Specifies whether to automatically destroy the user's ticket cache +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-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 .Cm yes . @@ -658,8 +607,26 @@ index b90068bf3..cae0fd0b4 100644 +can lead to overwriting previous tickets by subseqent connections to the same +user account. .It Cm KexAlgorithms - Specifies the permitted KEX (Key Exchange) algorithms that the server will - offer to clients. --- -2.52.0 - + Specifies the available KEX (Key Exchange) algorithms. + Multiple algorithms must be comma-separated. +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-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 *); + int (*localname) (ssh_gssapi_client *, char **); +- void (*storecreds) (ssh_gssapi_client *); ++ int (*storecreds) (ssh_gssapi_client *); + int (*updatecreds) (ssh_gssapi_ccache *, ssh_gssapi_client *); + } ssh_gssapi_mech; + +@@ -175,7 +175,7 @@ int ssh_gssapi_userok(char *name, struct + 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); ++int ssh_gssapi_storecreds(void); + const char *ssh_gssapi_displayname(void); + + char *ssh_gssapi_server_mechanisms(void); diff --git a/0009-openssh-8.7p1-redhat.patch b/openssh-7.7p1-redhat.patch similarity index 64% rename from 0009-openssh-8.7p1-redhat.patch rename to openssh-7.7p1-redhat.patch index 8e75aa5..1d77f90 100644 --- a/0009-openssh-8.7p1-redhat.patch +++ b/openssh-7.7p1-redhat.patch @@ -1,25 +1,6 @@ -From c76607384ff077ba1c45759e749562cccaeaa335 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 09/53] openssh-8.7p1-redhat - ---- - ssh_config | 7 +++++++ - ssh_config_redhat | 18 ++++++++++++++++++ - sshd_config | 8 ++++++++ - sshd_config.0 | 6 +++--- - sshd_config.5 | 2 +- - sshd_config_redhat | 18 ++++++++++++++++++ - sshd_config_redhat_cp | 7 +++++++ - 7 files changed, 62 insertions(+), 4 deletions(-) - create mode 100644 ssh_config_redhat - create mode 100644 sshd_config_redhat - create mode 100644 sshd_config_redhat_cp - -diff --git a/ssh_config b/ssh_config -index 238a0c5e3..d9324c957 100644 ---- a/ssh_config -+++ b/ssh_config +diff -up openssh/ssh_config.redhat openssh/ssh_config +--- openssh/ssh_config.redhat 2020-02-11 23:28:35.000000000 +0100 ++++ openssh/ssh_config 2020-02-13 18:13:39.180641839 +0100 @@ -43,3 +43,10 @@ # ProxyCommand ssh -q -W %h:%p gateway.example.com # RekeyLimit 1G 1h @@ -31,12 +12,10 @@ index 238a0c5e3..d9324c957 100644 +# included below. For more information, see manual page for +# update-crypto-policies(8) and ssh_config(5). +Include /etc/ssh/ssh_config.d/*.conf -diff --git a/ssh_config_redhat b/ssh_config_redhat -new file mode 100644 -index 000000000..8b1b59021 ---- /dev/null -+++ b/ssh_config_redhat -@@ -0,0 +1,18 @@ +diff -up openssh/ssh_config_redhat.redhat openssh/ssh_config_redhat +--- openssh/ssh_config_redhat.redhat 2020-02-13 18:13:39.180641839 +0100 ++++ openssh/ssh_config_redhat 2020-02-13 18:13:39.180641839 +0100 +@@ -0,0 +1,15 @@ +# The options here are in the "Match final block" to be applied as the last +# options and could be potentially overwritten by the user configuration +Match final all @@ -50,35 +29,12 @@ index 000000000..8b1b59021 +# mode correctly we set this to yes. + ForwardX11Trusted yes + -+# rhbz#2352653 - export COLORTERM -+ SendEnv COLORTERM -+ +# Uncomment this if you want to use .local domain +# Host *.local -diff --git a/sshd_config b/sshd_config -index 0f4a3a724..608203e4b 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -10,6 +10,14 @@ - # possible, but leave them commented. Uncommented options override the - # default value. - -+# To modify the system-wide sshd configuration, create a *.conf file under -+# /etc/ssh/sshd_config.d/ which will be automatically included below -+Include /etc/ssh/sshd_config.d/*.conf -+ -+# If you want to change the port on a SELinux system, you have to tell -+# SELinux about this change. -+# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER -+# - #Port 22 - #AddressFamily any - #ListenAddress 0.0.0.0 -diff --git a/sshd_config.0 b/sshd_config.0 -index c63d729a9..8c5217c0b 100644 ---- a/sshd_config.0 -+++ b/sshd_config.0 -@@ -1219,9 +1219,9 @@ DESCRIPTION +diff -up openssh/sshd_config.0.redhat openssh/sshd_config.0 +--- openssh/sshd_config.0.redhat 2020-02-12 14:30:04.000000000 +0100 ++++ openssh/sshd_config.0 2020-02-13 18:13:39.181641855 +0100 +@@ -970,9 +970,9 @@ DESCRIPTION SyslogFacility Gives the facility code that is used when logging messages from @@ -91,11 +47,10 @@ index c63d729a9..8c5217c0b 100644 TCPKeepAlive Specifies whether the system should send TCP keepalive messages -diff --git a/sshd_config.5 b/sshd_config.5 -index 6ae606f1e..aa9f0af76 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -1941,7 +1941,7 @@ By default no subsystems are defined. +diff -up openssh/sshd_config.5.redhat openssh/sshd_config.5 +--- openssh/sshd_config.5.redhat 2020-02-11 23:28:35.000000000 +0100 ++++ openssh/sshd_config.5 2020-02-13 18:13:39.181641855 +0100 +@@ -1614,7 +1614,7 @@ By default no subsystems are defined. .It Cm SyslogFacility Gives the facility code that is used when logging messages from .Xr sshd 8 . @@ -104,15 +59,31 @@ index 6ae606f1e..aa9f0af76 100644 LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The default is AUTH. .It Cm TCPKeepAlive -diff --git a/sshd_config_redhat b/sshd_config_redhat -new file mode 100644 -index 000000000..993a28d52 ---- /dev/null -+++ b/sshd_config_redhat -@@ -0,0 +1,18 @@ +diff -up openssh/sshd_config.redhat openssh/sshd_config +--- openssh/sshd_config.redhat 2020-02-11 23:28:35.000000000 +0100 ++++ openssh/sshd_config 2020-02-13 18:20:16.349913681 +0100 +@@ -10,6 +10,14 @@ + # possible, but leave them commented. Uncommented options override the + # default value. + ++# To modify the system-wide sshd configuration, create a *.conf file under ++# /etc/ssh/sshd_config.d/ which will be automatically included below ++Include /etc/ssh/sshd_config.d/*.conf ++ ++# If you want to change the port on a SELinux system, you have to tell ++# SELinux about this change. ++# semanage port -a -t ssh_port_t -p tcp #PORTNUMBER ++# + #Port 22 + #AddressFamily any + #ListenAddress 0.0.0.0 +diff -up openssh/sshd_config_redhat.redhat openssh/sshd_config_redhat +--- openssh/sshd_config_redhat.redhat 2020-02-13 18:14:02.268006439 +0100 ++++ openssh/sshd_config_redhat 2020-02-13 18:19:20.765035947 +0100 +@@ -0,0 +1,15 @@ +SyslogFacility AUTHPRIV + -+KbdInteractiveAuthentication no ++ChallengeResponseAuthentication no + +GSSAPIAuthentication yes +GSSAPICleanupCredentials no @@ -121,18 +92,13 @@ index 000000000..993a28d52 + +X11Forwarding yes + -+# rhbz#2352653 - accept COLORTERM -+ AcceptEnv COLORTERM -+ +# It is recommended to use pam_motd in /etc/pam.d/sshd instead of PrintMotd, +# as it is more configurable and versatile than the built-in version. +PrintMotd no + -diff --git a/sshd_config_redhat_cp b/sshd_config_redhat_cp -new file mode 100644 -index 000000000..1d592d13f ---- /dev/null -+++ b/sshd_config_redhat_cp +diff -up openssh/sshd_config_redhat.redhat openssh/sshd_config_redhat +--- openssh/sshd_config_redhat_cp.redhat 2020-02-13 18:14:02.268006439 +0100 ++++ openssh/sshd_config_redhat_cp 2020-02-13 18:19:20.765035947 +0100 @@ -0,0 +1,7 @@ +# This system is following system-wide crypto policy. The changes to +# crypto properties (Ciphers, MACs, ...) will not have any effect in @@ -141,6 +107,3 @@ index 000000000..1d592d13f +# Please, see manual pages for update-crypto-policies(8) and sshd_config(5). +Include /etc/crypto-policies/back-ends/opensshserver.config + --- -2.52.0 - diff --git a/openssh-7.8p1-UsePAM-warning.patch b/openssh-7.8p1-UsePAM-warning.patch new file mode 100644 index 0000000..a94419e --- /dev/null +++ b/openssh-7.8p1-UsePAM-warning.patch @@ -0,0 +1,26 @@ +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 +@@ -1749,6 +1749,10 @@ main(int ac, char **av) + parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, + cfg, &includes, NULL, rexeced_flag); + ++ /* 'UsePAM no' is not supported in Fedora */ ++ if (! options.use_pam) ++ logit("WARNING: 'UsePAM no' is not supported in Fedora and may cause several problems."); ++ + #ifdef WITH_OPENSSL + if (options.moduli_file != NULL) + dh_set_moduli_file(options.moduli_file); +diff -up openssh-8.6p1/sshd_config.log-usepam-no openssh-8.6p1/sshd_config +--- openssh-8.6p1/sshd_config.log-usepam-no 2021-04-19 14:00:45.098735121 +0200 ++++ openssh-8.6p1/sshd_config 2021-04-19 14:00:45.099735129 +0200 +@@ -87,6 +87,8 @@ AuthorizedKeysFile .ssh/authorized_keys + # 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 Fedora and may cause several ++# problems. + #UsePAM no + + #AllowAgentForwarding yes diff --git a/0001-openssh-7.8p1-role-mls.patch b/openssh-7.8p1-role-mls.patch similarity index 78% rename from 0001-openssh-7.8p1-role-mls.patch rename to openssh-7.8p1-role-mls.patch index 0377e8c..347766d 100644 --- a/0001-openssh-7.8p1-role-mls.patch +++ b/openssh-7.8p1-role-mls.patch @@ -1,83 +1,57 @@ -From b6875ceaca4be9e0de0d6d260d8fcff1772f5fb5 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 01/53] openssh-7.8p1-role-mls - ---- - auth-pam.c | 2 +- - auth-pam.h | 2 +- - auth.h | 3 + - auth2-gss.c | 11 +- - auth2-hostbased.c | 9 + - auth2-pubkey.c | 11 +- - auth2.c | 14 ++ - misc.c | 8 + - monitor.c | 37 ++- - monitor.h | 4 + - monitor_wrap.c | 21 ++ - monitor_wrap.h | 3 + - openbsd-compat/Makefile.in | 3 +- - openbsd-compat/port-linux-sshd.c | 420 +++++++++++++++++++++++++++++++ - openbsd-compat/port-linux.c | 37 +-- - openbsd-compat/port-linux.h | 3 +- - platform.c | 2 +- - sshd-session.c | 3 + - 18 files changed, 551 insertions(+), 42 deletions(-) - create mode 100644 openbsd-compat/port-linux-sshd.c - -diff --git a/auth-pam.c b/auth-pam.c -index 5591f094e..70bcae83a 100644 ---- a/auth-pam.c -+++ b/auth-pam.c -@@ -1261,7 +1261,7 @@ is_pam_session_open(void) - * during the ssh authentication process. - */ - int --do_pam_putenv(char *name, char *value) -+do_pam_putenv(char *name, const char *value) - { - int ret = 1; - char *compound; -diff --git a/auth-pam.h b/auth-pam.h -index 8d801c689..9dd7ae078 100644 ---- a/auth-pam.h -+++ b/auth-pam.h -@@ -33,7 +33,7 @@ u_int do_pam_account(void); - void do_pam_session(struct ssh *); - void do_pam_setcred(void); - void do_pam_chauthtok(void); --int do_pam_putenv(char *, char *); -+int do_pam_putenv(char *, const char *); - char ** fetch_pam_environment(void); - char ** fetch_pam_child_environment(void); - void free_pam_environment(char **); -diff --git a/auth.h b/auth.h -index 98bb23d4c..83d07ae8b 100644 ---- a/auth.h -+++ b/auth.h -@@ -65,6 +65,9 @@ struct Authctxt { - char *service; - struct passwd *pw; /* set if 'valid' */ - char *style; +diff -up openssh/auth2.c.role-mls openssh/auth2.c +--- openssh/auth2.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth2.c 2018-08-22 11:14:56.815430916 +0200 +@@ -256,6 +256,9 @@ input_userauth_request(int type, u_int32 + Authctxt *authctxt = ssh->authctxt; + Authmethod *m = NULL; + char *user = NULL, *service = NULL, *method = NULL, *style = NULL; +#ifdef WITH_SELINUX -+ char *role; ++ char *role = NULL; +#endif + int r, authenticated = 0; + double tstart = monotime_double(); - /* Method lists for multiple authentication */ - char **auth_methods; /* modified from server config */ -diff --git a/auth2-gss.c b/auth2-gss.c -index 75eb4e3a3..f7898ab3e 100644 ---- a/auth2-gss.c -+++ b/auth2-gss.c -@@ -284,6 +284,7 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) +@@ -268,6 +271,11 @@ input_userauth_request(int type, u_int32 + debug("userauth-request for user %s service %s method %s", user, service, method); + debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); + ++#ifdef WITH_SELINUX ++ if ((role = strchr(user, '/')) != NULL) ++ *role++ = 0; ++#endif ++ + if ((style = strchr(user, ':')) != NULL) + *style++ = 0; + +@@ -314,8 +314,15 @@ input_userauth_request(int type, u_int32 + use_privsep ? " [net]" : ""); + 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); ++#ifdef WITH_SELINUX ++ mm_inform_authrole(role); ++#endif ++ } + userauth_banner(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 +@@ -281,6 +281,7 @@ input_gssapi_mic(int type, u_int32_t ple Authctxt *authctxt = ssh->authctxt; Gssctxt *gssctxt; int r, authenticated = 0; + char *micuser; struct sshbuf *b; gss_buffer_desc mic, gssbuf; - u_char *p; -@@ -300,7 +301,13 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) + const char *displayname; +@@ -298,7 +299,13 @@ input_gssapi_mic(int type, u_int32_t ple fatal_f("sshbuf_new failed"); mic.value = p; mic.length = len; @@ -92,7 +66,7 @@ index 75eb4e3a3..f7898ab3e 100644 "gssapi-with-mic", ssh->kex->session_id); if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) -@@ -313,6 +320,8 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) +@@ -311,6 +318,8 @@ input_gssapi_mic(int type, u_int32_t ple logit("GSSAPI MIC check failed"); sshbuf_free(b); @@ -100,12 +74,11 @@ index 75eb4e3a3..f7898ab3e 100644 + free(micuser); free(mic.value); - authctxt->postponed = 0; -diff --git a/auth2-hostbased.c b/auth2-hostbased.c -index 9d8b860eb..976484fc5 100644 ---- a/auth2-hostbased.c -+++ b/auth2-hostbased.c -@@ -129,7 +129,16 @@ userauth_hostbased(struct ssh *ssh, const char *method) + if ((!use_privsep || mm_is_monitor()) && +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 +@@ -123,7 +123,16 @@ userauth_hostbased(struct ssh *ssh) /* reconstruct packet */ if ((r = sshbuf_put_stringb(b, ssh->kex->session_id)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || @@ -122,11 +95,10 @@ index 9d8b860eb..976484fc5 100644 (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || (r = sshbuf_put_cstring(b, method)) != 0 || (r = sshbuf_put_string(b, pkalg, alen)) != 0 || -diff --git a/auth2-pubkey.c b/auth2-pubkey.c -index 15ad3000c..c326a69ba 100644 ---- a/auth2-pubkey.c -+++ b/auth2-pubkey.c -@@ -204,9 +204,16 @@ userauth_pubkey(struct ssh *ssh, const char *method) +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 ++++ openssh/auth2-pubkey.c 2018-08-22 11:17:07.331483958 +0200 +@@ -169,9 +169,16 @@ userauth_pubkey(struct ssh *ssh) goto done; } /* reconstruct packet */ @@ -145,51 +117,47 @@ index 15ad3000c..c326a69ba 100644 if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || (r = sshbuf_put_cstring(b, userstyle)) != 0 || (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || -diff --git a/auth2.c b/auth2.c -index b9bb46f59..1345d3257 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -271,6 +271,9 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) - Authctxt *authctxt = ssh->authctxt; - Authmethod *m = NULL; - char *user = NULL, *service = NULL, *method = NULL, *style = NULL; +diff -up openssh/auth.h.role-mls openssh/auth.h +--- openssh/auth.h.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth.h 2018-08-22 11:14:56.816430924 +0200 +@@ -65,6 +65,9 @@ struct Authctxt { + char *service; + struct passwd *pw; /* set if 'valid' */ + char *style; +#ifdef WITH_SELINUX -+ char *role = NULL; ++ char *role; +#endif - int r, authenticated = 0; - double tstart = monotime_double(); -@@ -284,6 +287,11 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) - debug("userauth-request for user %s service %s method %s", user, service, method); - debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); - -+#ifdef WITH_SELINUX -+ if ((role = strchr(user, '/')) != NULL) -+ *role++ = 0; -+#endif -+ - if ((style = strchr(user, ':')) != NULL) - *style++ = 0; - -@@ -313,7 +321,13 @@ input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) - setproctitle("%s [net]", authctxt->valid ? user : "unknown"); - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; -+#ifdef WITH_SELINUX -+ authctxt->role = role ? xstrdup(role) : NULL; -+#endif - mm_inform_authserv(service, style); -+#ifdef WITH_SELINUX -+ mm_inform_authrole(role); -+#endif - userauth_banner(ssh); - if ((r = kex_server_update_ext_info(ssh)) != 0) - fatal_fr(r, "kex_server_update_ext_info failed"); -diff --git a/misc.c b/misc.c -index ce77ec943..5bed34735 100644 ---- a/misc.c -+++ b/misc.c -@@ -822,6 +822,7 @@ char * + /* Method lists for multiple authentication */ + char **auth_methods; /* modified from server config */ +diff -up openssh/auth-pam.c.role-mls openssh/auth-pam.c +--- openssh/auth-pam.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/auth-pam.c 2018-08-22 11:14:56.816430924 +0200 +@@ -1172,7 +1172,7 @@ is_pam_session_open(void) + * during the ssh authentication process. + */ + int +-do_pam_putenv(char *name, char *value) ++do_pam_putenv(char *name, const char *value) + { + int ret = 1; + char *compound; +diff -up openssh/auth-pam.h.role-mls openssh/auth-pam.h +--- openssh/auth-pam.h.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ 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_chauthtok(void); +-int do_pam_putenv(char *, char *); ++int do_pam_putenv(char *, const char *); + char ** fetch_pam_environment(void); + char ** fetch_pam_child_environment(void); + void free_pam_environment(char **); +diff -up openssh/misc.c.role-mls openssh/misc.c +--- openssh/misc.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/misc.c 2018-08-22 11:14:56.817430932 +0200 +@@ -542,6 +542,7 @@ char * colon(char *cp) { int flag = 0; @@ -197,7 +165,7 @@ index ce77ec943..5bed34735 100644 if (*cp == ':') /* Leading colon is part of file name. */ return NULL; -@@ -837,6 +838,13 @@ colon(char *cp) +@@ -557,6 +558,13 @@ colon(char *cp) return (cp); if (*cp == '/') return NULL; @@ -211,11 +179,10 @@ index ce77ec943..5bed34735 100644 } return NULL; } -diff --git a/monitor.c b/monitor.c -index a9e854bec..85dc1b1b7 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -110,6 +110,9 @@ int mm_answer_sign(struct ssh *, int, struct sshbuf *); +diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c +--- openssh-8.6p1/monitor.c.role-mls 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/monitor.c 2021-05-21 14:21:56.719414087 +0200 +@@ -117,6 +117,9 @@ int mm_answer_sign(struct ssh *, int, st int mm_answer_pwnamallow(struct ssh *, int, struct sshbuf *); int mm_answer_auth2_read_banner(struct ssh *, int, struct sshbuf *); int mm_answer_authserv(struct ssh *, int, struct sshbuf *); @@ -225,7 +192,7 @@ index a9e854bec..85dc1b1b7 100644 int mm_answer_authpassword(struct ssh *, int, struct sshbuf *); int mm_answer_bsdauthquery(struct ssh *, int, struct sshbuf *); int mm_answer_bsdauthrespond(struct ssh *, int, struct sshbuf *); -@@ -184,6 +187,9 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -195,6 +198,9 @@ struct mon_table mon_dispatch_proto20[] {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, {MONITOR_REQ_PWNAM, MON_ONCE, mm_answer_pwnamallow}, {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, @@ -235,7 +202,7 @@ index a9e854bec..85dc1b1b7 100644 {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, #ifdef USE_PAM -@@ -919,6 +925,9 @@ mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -803,6 +809,9 @@ mm_answer_pwnamallow(struct ssh *ssh, in /* Allow service/style information on the auth context */ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); @@ -245,7 +212,7 @@ index a9e854bec..85dc1b1b7 100644 monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); #ifdef USE_PAM -@@ -993,6 +1002,26 @@ key_base_type_match(const char *method, const struct sshkey *key, +@@ -877,6 +886,26 @@ key_base_type_match(const char *method, return found; } @@ -272,16 +239,16 @@ index a9e854bec..85dc1b1b7 100644 int mm_answer_authpassword(struct ssh *ssh, int sock, struct sshbuf *m) { -@@ -1364,7 +1393,7 @@ monitor_valid_userblob(struct ssh *ssh, const u_char *data, u_int datalen) +@@ -1251,7 +1280,7 @@ monitor_valid_userblob(struct ssh *ssh, struct sshbuf *b; - struct sshkey *hostkey = NULL; + struct sshkey *hostkey = NULL; const u_char *p; - char *userstyle, *cp; + char *userstyle, *s, *cp; size_t len; u_char type; int hostbound = 0, r, fail = 0; -@@ -1395,6 +1424,8 @@ monitor_valid_userblob(struct ssh *ssh, const u_char *data, u_int datalen) +@@ -1282,6 +1311,8 @@ monitor_valid_userblob(struct ssh *ssh, fail++; if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) fatal_fr(r, "parse userstyle"); @@ -290,7 +257,7 @@ index a9e854bec..85dc1b1b7 100644 xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); -@@ -1445,7 +1476,7 @@ monitor_valid_hostbasedblob(const u_char *data, u_int datalen, +@@ -1317,7 +1348,7 @@ monitor_valid_hostbasedblob(const u_char { struct sshbuf *b; const u_char *p; @@ -299,7 +266,7 @@ index a9e854bec..85dc1b1b7 100644 size_t len; int r, fail = 0; u_char type; -@@ -1466,6 +1497,8 @@ monitor_valid_hostbasedblob(const u_char *data, u_int datalen, +@@ -1338,6 +1370,8 @@ monitor_valid_hostbasedblob(const u_char fail++; if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) fatal_fr(r, "parse userstyle"); @@ -308,13 +275,12 @@ index a9e854bec..85dc1b1b7 100644 xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); -diff --git a/monitor.h b/monitor.h -index 3f8a9bea3..9dcd9c293 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -56,6 +56,10 @@ enum monitor_reqtype { +diff -up openssh/monitor.h.role-mls openssh/monitor.h +--- openssh/monitor.h.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/monitor.h 2018-08-22 11:14:56.818430941 +0200 +@@ -55,6 +55,10 @@ enum monitor_reqtype { + MONITOR_REQ_GSSCHECKMIC = 48, MONITOR_ANS_GSSCHECKMIC = 49, MONITOR_REQ_TERM = 50, - MONITOR_REQ_STATE = 51, MONITOR_ANS_STATE = 52, +#ifdef WITH_SELINUX + MONITOR_REQ_AUTHROLE = 80, @@ -323,11 +289,10 @@ index 3f8a9bea3..9dcd9c293 100644 MONITOR_REQ_PAM_START = 100, MONITOR_REQ_PAM_ACCOUNT = 102, MONITOR_ANS_PAM_ACCOUNT = 103, MONITOR_REQ_PAM_INIT_CTX = 104, MONITOR_ANS_PAM_INIT_CTX = 105, -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 33494b73f..347eb6870 100644 ---- a/monitor_wrap.c -+++ b/monitor_wrap.c -@@ -453,6 +453,27 @@ mm_inform_authserv(char *service, char *style) +diff -up openssh/monitor_wrap.c.role-mls openssh/monitor_wrap.c +--- openssh/monitor_wrap.c.role-mls 2018-08-22 11:14:56.818430941 +0200 ++++ openssh/monitor_wrap.c 2018-08-22 11:21:47.938747968 +0200 +@@ -390,6 +390,27 @@ mm_inform_authserv(char *service, char * sshbuf_free(m); } @@ -355,11 +320,10 @@ index 33494b73f..347eb6870 100644 /* Do the password authentication */ int mm_auth_password(struct ssh *ssh, char *password) -diff --git a/monitor_wrap.h b/monitor_wrap.h -index c87295388..9b42ddbcb 100644 ---- a/monitor_wrap.h -+++ b/monitor_wrap.h -@@ -50,6 +50,9 @@ int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *, +diff -up openssh/monitor_wrap.h.role-mls openssh/monitor_wrap.h +--- openssh/monitor_wrap.h.role-mls 2018-08-22 11:14:56.818430941 +0200 ++++ openssh/monitor_wrap.h 2018-08-22 11:22:10.439929513 +0200 +@@ -44,6 +44,9 @@ DH *mm_choose_dh(int, int, int); const u_char *, size_t, const char *, const char *, const char *, u_int compat); void mm_inform_authserv(char *, char *); @@ -369,11 +333,10 @@ index c87295388..9b42ddbcb 100644 struct passwd *mm_getpwnamallow(struct ssh *, const char *); char *mm_auth2_read_banner(void); int mm_auth_password(struct ssh *, char *); -diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in -index 53c87db6d..39531ae77 100644 ---- a/openbsd-compat/Makefile.in -+++ b/openbsd-compat/Makefile.in -@@ -102,7 +102,8 @@ PORTS= port-aix.o \ +diff -up openssh/openbsd-compat/Makefile.in.role-mls openssh/openbsd-compat/Makefile.in +--- openssh/openbsd-compat/Makefile.in.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/openbsd-compat/Makefile.in 2018-08-22 11:14:56.819430949 +0200 +@@ -92,7 +92,8 @@ PORTS= port-aix.o \ port-prngd.o \ port-solaris.o \ port-net.o \ @@ -383,12 +346,79 @@ index 53c87db6d..39531ae77 100644 .c.o: $(CC) $(CFLAGS_NOPIE) $(PICFLAG) $(CPPFLAGS) -c $< -diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -new file mode 100644 -index 000000000..b9fbe38b7 ---- /dev/null -+++ b/openbsd-compat/port-linux-sshd.c -@@ -0,0 +1,420 @@ +diff -up openssh/openbsd-compat/port-linux.c.role-mls openssh/openbsd-compat/port-linux.c +--- openssh/openbsd-compat/port-linux.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/openbsd-compat/port-linux.c 2018-08-22 11:14:56.819430949 +0200 +@@ -100,37 +100,6 @@ ssh_selinux_getctxbyname(char *pwname) + return sc; + } + +-/* Set the execution context to the default for the specified user */ +-void +-ssh_selinux_setup_exec_context(char *pwname) +-{ +- char *user_ctx = NULL; +- +- if (!ssh_selinux_enabled()) +- return; +- +- debug3("%s: setting execution context", __func__); +- +- user_ctx = ssh_selinux_getctxbyname(pwname); +- if (setexeccon(user_ctx) != 0) { +- switch (security_getenforce()) { +- case -1: +- fatal("%s: security_getenforce() failed", __func__); +- case 0: +- error("%s: Failed to set SELinux execution " +- "context for %s", __func__, pwname); +- break; +- default: +- fatal("%s: Failed to set SELinux execution context " +- "for %s (in enforcing mode)", __func__, pwname); +- } +- } +- if (user_ctx != NULL) +- freecon(user_ctx); +- +- debug3("%s: done", __func__); +-} +- + /* Set the TTY context for the specified user */ + void + ssh_selinux_setup_pty(char *pwname, const char *tty) +@@ -145,7 +114,11 @@ ssh_selinux_setup_pty(char *pwname, cons + + debug3("%s: setting TTY context on %s", __func__, tty); + +- user_ctx = ssh_selinux_getctxbyname(pwname); ++ if (getexeccon(&user_ctx) != 0) { ++ error_f("getexeccon: %s", strerror(errno)); ++ goto out; ++ } ++ + + /* XXX: should these calls fatal() upon failure in enforcing mode? */ + +diff -up openssh/openbsd-compat/port-linux.h.role-mls openssh/openbsd-compat/port-linux.h +--- openssh/openbsd-compat/port-linux.h.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/openbsd-compat/port-linux.h 2018-08-22 11:14:56.819430949 +0200 +@@ -20,9 +20,10 @@ + #ifdef WITH_SELINUX + int ssh_selinux_enabled(void); + void ssh_selinux_setup_pty(char *, const char *); +-void ssh_selinux_setup_exec_context(char *); + void ssh_selinux_change_context(const char *); + void ssh_selinux_setfscreatecon(const char *); ++ ++void sshd_selinux_setup_exec_context(char *); + #endif + + #ifdef LINUX_OOM_ADJUST +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 @@ +/* + * Copyright (c) 2005 Daniel Walsh + * Copyright (c) 2014 Petr Lautrbach @@ -442,6 +472,7 @@ index 000000000..b9fbe38b7 +extern ServerOptions options; +extern Authctxt *the_authctxt; +extern int inetd_flag; ++extern int rexeced_flag; + +/* Send audit message */ +static int @@ -647,7 +678,7 @@ index 000000000..b9fbe38b7 + + if (r == 0) { + /* If launched from xinetd, we must use current level */ -+ if (inetd_flag) { ++ if (inetd_flag && !rexeced_flag) { + security_context_t sshdsc=NULL; + + if (getcon_raw(&sshdsc) < 0) @@ -721,7 +752,7 @@ index 000000000..b9fbe38b7 + + rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); + -+ if (inetd_flag) { ++ if (inetd_flag && !rexeced_flag) { + use_current = "1"; + } else { + use_current = ""; @@ -809,82 +840,10 @@ index 000000000..b9fbe38b7 +#endif +#endif + -diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c -index c1d54f38d..7426f6f79 100644 ---- a/openbsd-compat/port-linux.c -+++ b/openbsd-compat/port-linux.c -@@ -109,37 +109,6 @@ ssh_selinux_getctxbyname(char *pwname) - return sc; - } - --/* Set the execution context to the default for the specified user */ --void --ssh_selinux_setup_exec_context(char *pwname) --{ -- char *user_ctx = NULL; -- -- if (!ssh_selinux_enabled()) -- return; -- -- debug3("%s: setting execution context", __func__); -- -- user_ctx = ssh_selinux_getctxbyname(pwname); -- if (setexeccon(user_ctx) != 0) { -- switch (security_getenforce()) { -- case -1: -- fatal("%s: security_getenforce() failed", __func__); -- case 0: -- error("%s: Failed to set SELinux execution " -- "context for %s", __func__, pwname); -- break; -- default: -- fatal("%s: Failed to set SELinux execution context " -- "for %s (in enforcing mode)", __func__, pwname); -- } -- } -- if (user_ctx != NULL) -- freecon(user_ctx); -- -- debug3("%s: done", __func__); --} -- - /* Set the TTY context for the specified user */ - void - ssh_selinux_setup_pty(char *pwname, const char *tty) -@@ -152,7 +121,11 @@ ssh_selinux_setup_pty(char *pwname, const char *tty) - - debug3("%s: setting TTY context on %s", __func__, tty); - -- user_ctx = ssh_selinux_getctxbyname(pwname); -+ if (getexeccon(&user_ctx) != 0) { -+ error_f("getexeccon: %s", strerror(errno)); -+ goto out; -+ } -+ - - /* XXX: should these calls fatal() upon failure in enforcing mode? */ - -diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h -index 959430de1..055c825e4 100644 ---- a/openbsd-compat/port-linux.h -+++ b/openbsd-compat/port-linux.h -@@ -20,9 +20,10 @@ - #ifdef WITH_SELINUX - int ssh_selinux_enabled(void); - void ssh_selinux_setup_pty(char *, const char *); --void ssh_selinux_setup_exec_context(char *); - void ssh_selinux_change_context(const char *); - void ssh_selinux_setfscreatecon(const char *); -+ -+void sshd_selinux_setup_exec_context(char *); - #endif - - #ifdef LINUX_OOM_ADJUST -diff --git a/platform.c b/platform.c -index fd1a7a7c2..bcf1b0491 100644 ---- a/platform.c -+++ b/platform.c -@@ -140,7 +140,7 @@ platform_setusercontext_post_groups(struct passwd *pw) +diff -up openssh/platform.c.role-mls openssh/platform.c +--- openssh/platform.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/platform.c 2018-08-22 11:14:56.819430949 +0200 +@@ -183,7 +183,7 @@ platform_setusercontext_post_groups(stru } #endif /* HAVE_SETPCRED */ #ifdef WITH_SELINUX @@ -893,11 +852,10 @@ index fd1a7a7c2..bcf1b0491 100644 #endif } -diff --git a/sshd-session.c b/sshd-session.c -index 8979f743b..cb4b0523d 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -1306,6 +1306,9 @@ main(int ac, char **av) +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 +@@ -2186,6 +2186,9 @@ main(int ac, char **av) restore_uid(); } #endif @@ -906,7 +864,4 @@ index 8979f743b..cb4b0523d 100644 +#endif #ifdef USE_PAM if (options.use_pam) { - do_pam_setcred(); --- -2.52.0 - + do_pam_setcred(1); diff --git a/0025-openssh-7.8p1-scp-ipv6.patch b/openssh-7.8p1-scp-ipv6.patch similarity index 51% rename from 0025-openssh-7.8p1-scp-ipv6.patch rename to openssh-7.8p1-scp-ipv6.patch index d1eb51a..8ae0948 100644 --- a/0025-openssh-7.8p1-scp-ipv6.patch +++ b/openssh-7.8p1-scp-ipv6.patch @@ -1,17 +1,8 @@ -From e1d86d265d9543c77fa90a33acc70246e68bf3bf Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 25/53] openssh-7.8p1-scp-ipv6 - ---- - scp.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - diff --git a/scp.c b/scp.c -index e1992622f..621131ffc 100644 +index 60682c68..9344806e 100644 --- a/scp.c +++ b/scp.c -@@ -1169,7 +1169,9 @@ toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct) +@@ -714,7 +714,9 @@ toremote(int argc, char **argv) addargs(&alist, "%s", host); addargs(&alist, "%s", cmd); addargs(&alist, "%s", src); @@ -22,6 +13,4 @@ index e1992622f..621131ffc 100644 tuser ? tuser : "", tuser ? "@" : "", thost, targ); if (do_local_cmd(&alist) != 0) --- -2.52.0 diff --git a/0026-openssh-8.0p1-crypto-policies.patch b/openssh-8.0p1-crypto-policies.patch similarity index 87% rename from 0026-openssh-8.0p1-crypto-policies.patch rename to openssh-8.0p1-crypto-policies.patch index 5162ffa..86c08db 100644 --- a/0026-openssh-8.0p1-crypto-policies.patch +++ b/openssh-8.0p1-crypto-policies.patch @@ -1,18 +1,7 @@ -From 6d9e08f061451f6cd464af5ec598fa99d15acadb Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 26/53] openssh-8.0p1-crypto-policies - ---- - ssh_config.5 | 164 ++++++++++++++++++++------------------------- - sshd_config.5 | 179 +++++++++++++++++++------------------------------- - 2 files changed, 140 insertions(+), 203 deletions(-) - -diff --git a/ssh_config.5 b/ssh_config.5 -index 8a4b469cf..8ac5e1633 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -438,17 +438,13 @@ A single argument of +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 @@ -35,7 +24,7 @@ index 8a4b469cf..8ac5e1633 100644 If the specified list begins with a .Sq + character, then the specified algorithms will be appended to the default set -@@ -587,20 +583,25 @@ If the option is set to +@@ -450,20 +446,25 @@ (the default), the check will not be executed. .It Cm Ciphers @@ -65,21 +54,21 @@ index 8a4b469cf..8ac5e1633 100644 .Pp The supported ciphers are: .Bd -literal -offset indent -@@ -616,13 +617,6 @@ aes256-gcm@openssh.com +@@ -479,13 +480,6 @@ chacha20-poly1305@openssh.com .Ed .Pp -The default is: -.Bd -literal -offset indent -chacha20-poly1305@openssh.com, --aes128-gcm@openssh.com,aes256-gcm@openssh.com, --aes128-ctr,aes192-ctr,aes256-ctr +-aes128-ctr,aes192-ctr,aes256-ctr, +-aes128-gcm@openssh.com,aes256-gcm@openssh.com -.Ed -.Pp The list of available ciphers may also be obtained using .Qq ssh -Q cipher . .It Cm ClearAllForwardings -@@ -1022,6 +1016,11 @@ command line will be passed untouched to the GSSAPI library. +@@ -885,6 +879,11 @@ The default is .Dq no . .It Cm GSSAPIKexAlgorithms @@ -91,7 +80,7 @@ index 8a4b469cf..8ac5e1633 100644 The list of key exchange algorithms that are offered for GSSAPI key exchange. Possible values are .Bd -literal -offset 3n -@@ -1034,10 +1033,8 @@ gss-nistp256-sha256-, +@@ -897,10 +896,8 @@ gss-curve25519-sha256- .Ed .Pp @@ -103,7 +92,7 @@ index 8a4b469cf..8ac5e1633 100644 .It Cm HashKnownHosts Indicates that .Xr ssh 1 -@@ -1056,36 +1053,25 @@ will not be converted automatically, +@@ -919,36 +916,25 @@ but may be manually hashed using .Xr ssh-keygen 1 . .It Cm HostbasedAcceptedAlgorithms @@ -148,7 +137,7 @@ index 8a4b469cf..8ac5e1633 100644 .Pp The .Fl Q -@@ -1138,6 +1124,17 @@ to prefer their algorithms. +@@ -1001,6 +987,17 @@ .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . @@ -166,7 +155,7 @@ index 8a4b469cf..8ac5e1633 100644 .It Cm HostKeyAlias Specifies an alias that should be used instead of the real host name when looking up or saving the host key -@@ -1360,6 +1357,11 @@ it may be zero or more of: +@@ -1232,30 +1229,25 @@ and .Cm pam . .It Cm KexAlgorithms @@ -175,11 +164,8 @@ index 8a4b469cf..8ac5e1633 100644 +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 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 -@@ -1368,29 +1370,17 @@ Multiple algorithms must be comma-separated. - .Pp + Specifies the available KEX (Key Exchange) algorithms. + Multiple algorithms must be comma-separated. If the specified list begins with a .Sq + -character, then the specified algorithms will be appended to the default set @@ -195,11 +181,9 @@ index 8a4b469cf..8ac5e1633 100644 .Sq ^ character, then the specified algorithms will be placed at the head of the -default set. --.Pp -The default is: -.Bd -literal -offset indent --mlkem768x25519-sha256, --sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com, +-sntrup761x25519-sha512@openssh.com, -curve25519-sha256,curve25519-sha256@libssh.org, -ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, -diffie-hellman-group-exchange-sha256, @@ -207,12 +191,11 @@ index 8a4b469cf..8ac5e1633 100644 -diffie-hellman-group18-sha512, -diffie-hellman-group14-sha256 -.Ed - .Pp +built-in openssh default set. - The list of supported key exchange algorithms may also be obtained using + .Pp + The list of available key exchange algorithms may also be obtained using .Qq ssh -Q kex . - .It Cm KnownHostsCommand -@@ -1506,37 +1496,33 @@ function, and all code in the +@@ -1365,37 +1357,33 @@ file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs @@ -259,7 +242,7 @@ index 8a4b469cf..8ac5e1633 100644 The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . .It Cm NoHostAuthenticationForLocalhost -@@ -1725,39 +1711,31 @@ instead of continuing to execute and pass data. +@@ -1567,39 +1555,31 @@ The default is .Cm no . .It Cm PubkeyAcceptedAlgorithms @@ -311,7 +294,7 @@ index 8a4b469cf..8ac5e1633 100644 .It Cm PubkeyAuthentication Specifies whether to try public key authentication. The argument to this keyword must be -@@ -2504,7 +2482,9 @@ for those users who do not have a configuration file. +@@ -2265,7 +2245,9 @@ This file must be world-readable. .El .Sh SEE ALSO @@ -322,11 +305,10 @@ index 8a4b469cf..8ac5e1633 100644 .Sh AUTHORS .An -nosplit OpenSSH is a derivative of the original and free -diff --git a/sshd_config.5 b/sshd_config.5 -index a0fc6064f..c172d5aab 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -379,17 +379,13 @@ If the argument is +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 @@ -349,7 +331,7 @@ index a0fc6064f..c172d5aab 100644 If the specified list begins with a .Sq + character, then the specified algorithms will be appended to the default set -@@ -533,20 +529,25 @@ The default is +@@ -525,20 +521,25 @@ indicating not to .Xr chroot 2 . .It Cm Ciphers @@ -379,21 +361,21 @@ index a0fc6064f..c172d5aab 100644 .Pp The supported ciphers are: .Pp -@@ -573,13 +574,6 @@ aes256-gcm@openssh.com +@@ -565,13 +566,6 @@ chacha20-poly1305@openssh.com .El .Pp -The default is: -.Bd -literal -offset indent -chacha20-poly1305@openssh.com, --aes128-gcm@openssh.com,aes256-gcm@openssh.com, --aes128-ctr,aes192-ctr,aes256-ctr +-aes128-ctr,aes192-ctr,aes256-ctr, +-aes128-gcm@openssh.com,aes256-gcm@openssh.com -.Ed -.Pp The list of available ciphers may also be obtained using .Qq ssh -Q cipher . .It Cm ClientAliveCountMax -@@ -774,53 +768,43 @@ For this to work +@@ -766,53 +760,43 @@ .Cm GSSAPIKeyExchange needs to be enabled in the server and also used by the client. .It Cm GSSAPIKexAlgorithms @@ -466,7 +448,7 @@ index a0fc6064f..c172d5aab 100644 .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q HostbasedAcceptedAlgorithms . -@@ -887,25 +871,14 @@ is specified, the location of the socket will be read from the +@@ -879,25 +863,14 @@ .Ev SSH_AUTH_SOCK environment variable. .It Cm HostKeyAlgorithms @@ -497,7 +479,7 @@ index a0fc6064f..c172d5aab 100644 The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . .It Cm IgnoreRhosts -@@ -1051,6 +1024,11 @@ Specifies whether to look at .k5login file for user's aliases. +@@ -1044,20 +1017,25 @@ The default is .Cm yes . .It Cm KexAlgorithms @@ -506,12 +488,9 @@ index a0fc6064f..c172d5aab 100644 +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 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 -@@ -1059,16 +1037,16 @@ Multiple algorithms must be comma-separated. - .Pp - If the specified list begins with a + Specifies the available KEX (Key Exchange) algorithms. + Multiple algorithms must be comma-separated. + Alternately if the specified list begins with a .Sq + -character, then the specified algorithms will be appended to the default set -instead of replacing them. @@ -527,25 +506,27 @@ index a0fc6064f..c172d5aab 100644 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 -@@ -1105,14 +1083,6 @@ sntrup761x25519-sha512 + .Bl -item -compact -offset indent +@@ -1089,16 +1067,6 @@ sntrup761x25519-sha512@openssh.com .El .Pp -The default is: -.Bd -literal -offset indent --mlkem768x25519-sha256, --sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com, +-sntrup761x25519-sha512@openssh.com, -curve25519-sha256,curve25519-sha256@libssh.org, --ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521 +-ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, +-diffie-hellman-group-exchange-sha256, +-diffie-hellman-group16-sha512,diffie-hellman-group18-sha512, +-diffie-hellman-group14-sha256 -.Ed -.Pp - The list of supported key exchange algorithms may also be obtained using + The list of available key exchange algorithms may also be obtained using .Qq ssh -Q KexAlgorithms . .It Cm ListenAddress -@@ -1199,21 +1169,26 @@ function, and all code in the +@@ -1184,21 +1152,26 @@ file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs @@ -576,7 +557,7 @@ index a0fc6064f..c172d5aab 100644 .Pp The algorithms that contain .Qq -etm -@@ -1256,15 +1231,6 @@ umac-64-etm@openssh.com +@@ -1241,15 +1214,6 @@ umac-128-etm@openssh.com .El .Pp @@ -592,7 +573,7 @@ index a0fc6064f..c172d5aab 100644 The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . .It Cm Match -@@ -1751,36 +1717,25 @@ or equivalent.) +@@ -1633,36 +1597,25 @@ The default is .Cm yes . .It Cm PubkeyAcceptedAlgorithms @@ -638,7 +619,7 @@ index a0fc6064f..c172d5aab 100644 .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q PubkeyAcceptedAlgorithms . -@@ -2281,7 +2236,9 @@ This file should be writable by root only, but it is recommended +@@ -2131,7 +2084,9 @@ .El .Sh SEE ALSO .Xr sftp-server 8 , @@ -649,6 +630,3 @@ index a0fc6064f..c172d5aab 100644 .Sh AUTHORS .An -nosplit OpenSSH is a derivative of the original and free --- -2.52.0 - diff --git a/0011-openssh-9.6p1-gssapi-keyex.patch b/openssh-8.0p1-gssapi-keyex.patch similarity index 67% rename from 0011-openssh-9.6p1-gssapi-keyex.patch rename to openssh-8.0p1-gssapi-keyex.patch index 2e5b723..3e5ccec 100644 --- a/0011-openssh-9.6p1-gssapi-keyex.patch +++ b/openssh-8.0p1-gssapi-keyex.patch @@ -1,98 +1,37 @@ -From c992408da3ca7aeae129c731c7753019a16ed226 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 11/53] openssh-9.6p1-gssapi-keyex - ---- - Makefile.in | 7 +- - auth.c | 3 +- - auth2-gss.c | 52 +++- - auth2-methods.c | 6 + - auth2.c | 2 + - canohost.c | 93 +++++++ - canohost.h | 3 + - clientloop.c | 12 + - configure.ac | 24 ++ - gss-genr.c | 312 ++++++++++++++++++++- - gss-serv-krb5.c | 97 ++++++- - gss-serv.c | 200 ++++++++++++-- - kex-names.c | 60 +++- - kex.c | 35 ++- - kex.h | 34 +++ - kexdh.c | 10 + - kexgen.c | 2 +- - kexgssc.c | 706 ++++++++++++++++++++++++++++++++++++++++++++++++ - kexgsss.c | 601 +++++++++++++++++++++++++++++++++++++++++ - monitor.c | 147 +++++++++- - monitor.h | 2 + - monitor_wrap.c | 57 +++- - monitor_wrap.h | 4 +- - readconf.c | 70 +++++ - readconf.h | 6 + - servconf.c | 46 ++++ - servconf.h | 3 + - session.c | 10 +- - ssh-gss.h | 64 ++++- - ssh.1 | 8 + - ssh.c | 6 +- - ssh_config | 2 + - ssh_config.5 | 58 ++++ - sshconnect2.c | 154 ++++++++++- - sshd-auth.c | 55 +++- - sshd-session.c | 9 +- - sshd.c | 3 +- - sshd_config | 2 + - sshd_config.5 | 31 +++ - sshkey.c | 72 ++++- - sshkey.h | 1 + - 41 files changed, 2993 insertions(+), 76 deletions(-) - create mode 100644 kexgssc.c - create mode 100644 kexgsss.c - diff --git a/Makefile.in b/Makefile.in -index a3a495c1b..a36eb82ed 100644 +index e7549470..b68c1710 100644 --- a/Makefile.in +++ b/Makefile.in -@@ -108,6 +108,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ +@@ -109,6 +109,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ kexgexc.o kexgexs.o \ - kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \ + kexsntrup761x25519.o sntrup761.o kexgen.o \ + kexgssc.o \ sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ - sshbuf-io.o misc-agent.o + sshbuf-io.o -@@ -131,7 +132,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.o \ - auth2-chall.o groupaccess.o \ +@@ -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 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 \ -@@ -143,7 +144,7 @@ SSHD_AUTH_OBJS=sshd-auth.o \ - serverloop.o auth.o auth2.o auth-options.o session.o 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 \ - auth2-gss.o gss-serv.o gss-serv-krb5.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ - monitor_wrap.o auth-krb5.o \ - audit.o audit-bsm.o audit-linux.o platform.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ -@@ -554,7 +555,7 @@ regress-prep: + srclimit.o sftp-server.o sftp-common.o \ + sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ +@@ -523,7 +523,7 @@ regress-prep: ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile REGRESSLIBS=libssh.a $(LIBCOMPAT) --TESTLIBS=$(LIBS) $(CHANNELLIBS) @TESTLIBS@ -+TESTLIBS=$(LIBS) $(CHANNELLIBS) $(GSSLIBS) @TESTLIBS@ +-TESTLIBS=$(LIBS) $(CHANNELLIBS) ++TESTLIBS=$(LIBS) $(CHANNELLIBS) $(GSSLIBS) regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \ -diff --git a/auth.c b/auth.c -index 8d9404743..d25653ee4 100644 ---- a/auth.c -+++ b/auth.c -@@ -354,7 +354,8 @@ auth_root_allowed(struct ssh *ssh, const char *method) +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 || @@ -102,19 +41,118 @@ index 8d9404743..d25653ee4 100644 return 1; break; case PERMIT_FORCED_ONLY: +@@ -730,97 +731,6 @@ fakepw(void) + } + + /* +- * 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 f7898ab3e..5b1b9cde3 100644 +index 9351e042..d6446c0c 100644 --- a/auth2-gss.c +++ b/auth2-gss.c -@@ -51,6 +51,7 @@ - #define SSH_GSSAPI_MAX_MECHS 2048 - - extern ServerOptions options; -+extern struct authmethod_cfg methodcfg_gsskeyex; - extern struct authmethod_cfg methodcfg_gssapi; - - static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh); -@@ -58,6 +59,48 @@ static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh); +@@ -1,7 +1,7 @@ + /* $OpenBSD: auth2-gss.c,v 1.34 2023/03/31 04:22:27 djm Exp $ */ + + /* +- * 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_errtok(int, u_int32_t, struct ssh *); @@ -149,10 +187,10 @@ index f7898ab3e..5b1b9cde3 100644 + gssbuf.length = sshbuf_len(b); + + /* gss_kex_context is NULL with privsep, so we can't check it here */ -+ if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gss_kex_context, -+ &gssbuf, &mic))) -+ authenticated = mm_ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1); ++ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, ++ &gssbuf, &mic)))) ++ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1)); + + sshbuf_free(b); + free(mic.value); @@ -163,65 +201,45 @@ index f7898ab3e..5b1b9cde3 100644 /* * We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like) -@@ -267,7 +310,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) +@@ -260,7 +302,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) if ((r = sshpkt_get_end(ssh)) != 0) fatal_fr(r, "parse packet"); -- authenticated = mm_ssh_gssapi_userok(authctxt->user); -+ authenticated = mm_ssh_gssapi_userok(authctxt->user, authctxt->pw, 1); +- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); ++ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1)); - 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 plen, struct ssh *ssh) + 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) gssbuf.length = sshbuf_len(b); - 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); + 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)); else logit("GSSAPI MIC check failed"); -@@ -333,6 +376,11 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) +@@ -326,6 +370,13 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) return 0; } +Authmethod method_gsskeyex = { -+ &methodcfg_gsskeyex, ++ "gssapi-keyex", ++ NULL, + userauth_gsskeyex, ++ &options.gss_authentication +}; + Authmethod method_gssapi = { - &methodcfg_gssapi, - userauth_gssapi, -diff --git a/auth2-methods.c b/auth2-methods.c -index 99637a89b..a05908cf3 100644 ---- a/auth2-methods.c -+++ b/auth2-methods.c -@@ -50,6 +50,11 @@ struct authmethod_cfg methodcfg_pubkey = { - &options.pubkey_authentication - }; - #ifdef GSSAPI -+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_cfgs[] = { - &methodcfg_none, - &methodcfg_pubkey, - #ifdef GSSAPI -+ &methodcfg_gsskeyex, - &methodcfg_gssapi, - #endif - &methodcfg_passwd, diff --git a/auth2.c b/auth2.c -index 1345d3257..5a4b932a9 100644 +index 0e776224..1c217268 100644 --- a/auth2.c +++ b/auth2.c -@@ -71,6 +71,7 @@ extern Authmethod method_passwd; +@@ -73,6 +73,7 @@ extern Authmethod method_passwd; extern Authmethod method_kbdint; extern Authmethod method_hostbased; #ifdef GSSAPI @@ -229,7 +247,7 @@ index 1345d3257..5a4b932a9 100644 extern Authmethod method_gssapi; #endif -@@ -78,6 +79,7 @@ Authmethod *authmethods[] = { +@@ -80,6 +81,7 @@ Authmethod *authmethods[] = { &method_none, &method_pubkey, #ifdef GSSAPI @@ -238,7 +256,7 @@ index 1345d3257..5a4b932a9 100644 #endif &method_passwd, diff --git a/canohost.c b/canohost.c -index 28f086e5a..875805c99 100644 +index abea9c6e..8e81b519 100644 --- a/canohost.c +++ b/canohost.c @@ -35,6 +35,99 @@ @@ -342,7 +360,7 @@ index 28f086e5a..875805c99 100644 ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) { diff --git a/canohost.h b/canohost.h -index 26d62855a..0cadc9f18 100644 +index 26d62855..0cadc9f1 100644 --- a/canohost.h +++ b/canohost.h @@ -15,6 +15,9 @@ @@ -356,10 +374,10 @@ index 26d62855a..0cadc9f18 100644 int get_peer_port(int); char *get_local_ipaddr(int); diff --git a/clientloop.c b/clientloop.c -index 49d048d85..33adf31dc 100644 +index ebd0dbca..1bdac6a4 100644 --- a/clientloop.c +++ b/clientloop.c -@@ -107,6 +107,10 @@ +@@ -112,6 +112,10 @@ #include "ssherr.h" #include "hostfile.h" @@ -370,7 +388,7 @@ index 49d048d85..33adf31dc 100644 /* Permitted RSA signature algorithms for UpdateHostkeys proofs */ #define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256" -@@ -1604,6 +1608,14 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, +@@ -1379,6 +1383,14 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, /* Do channel operations. */ channel_after_poll(ssh, pfd, npfd_active); @@ -386,10 +404,10 @@ index 49d048d85..33adf31dc 100644 if (conn_in_ready) client_process_net_input(ssh); diff --git a/configure.ac b/configure.ac -index fd632a5a8..adccaebd4 100644 +index b689db4b..efafb6bd 100644 --- a/configure.ac +++ b/configure.ac -@@ -813,6 +813,30 @@ int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) +@@ -674,6 +674,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) [Use tunnel device compatibility to OpenBSD]) AC_DEFINE([SSH_TUN_PREPEND_AF], [1], [Prepend the address family to IP tunnel traffic]) @@ -421,10 +439,19 @@ index fd632a5a8..adccaebd4 100644 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 8f1f54afb..f2d6f59e5 100644 +index d56257b4..763a63ff 100644 --- a/gss-genr.c +++ b/gss-genr.c -@@ -42,9 +42,33 @@ +@@ -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 @@ #include "sshbuf.h" #include "log.h" #include "ssh2.h" @@ -458,7 +485,7 @@ index 8f1f54afb..f2d6f59e5 100644 /* sshbuf_get for gss_buffer_desc */ int ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) -@@ -60,6 +84,169 @@ 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) return 0; } @@ -527,29 +554,19 @@ index 8f1f54afb..f2d6f59e5 100644 + 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 ((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); ++ ++ 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) + fatal_fr(r, "digest failed"); -+ } -+ EVP_MD_free(md5); md5 = NULL; -+ EVP_MD_CTX_free(ctx); ctx = NULL; ++ ssh_digest_free(md); ++ md = NULL; + + encoded = xmalloc(ssh_digest_bytes(SSH_DIGEST_MD5) + * 2); @@ -628,28 +645,7 @@ index 8f1f54afb..f2d6f59e5 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) -@@ -168,6 +355,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 +381,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 +410,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, +@@ -218,7 +398,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, } ctx->major = gss_init_sec_context(&ctx->minor, @@ -658,7 +654,7 @@ index 8f1f54afb..f2d6f59e5 100644 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 0, NULL, recv_tok, NULL, send_tok, flags, NULL); -@@ -245,9 +439,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) +@@ -247,9 +427,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) return (ctx->major); } @@ -702,7 +698,7 @@ index 8f1f54afb..f2d6f59e5 100644 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, GSS_C_QOP_DEFAULT, buffer, hash))) ssh_gssapi_error(ctx); -@@ -255,6 +483,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) +@@ -257,6 +471,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) return (ctx->major); } @@ -722,7 +718,7 @@ index 8f1f54afb..f2d6f59e5 100644 void ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, const char *context, const struct sshbuf *session_id) -@@ -271,11 +512,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, +@@ -273,11 +500,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, } int @@ -739,8 +735,8 @@ index 8f1f54afb..f2d6f59e5 100644 + ctx = &intctx; /* RFC 4462 says we MUST NOT do SPNEGO */ - if (oid->length == spnego_oid.length && -@@ -285,6 +531,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) + if (oid->length == spnego_oid.length && +@@ -287,6 +519,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) ssh_gssapi_build_ctx(ctx); ssh_gssapi_set_oid(*ctx, oid); major = ssh_gssapi_import_name(*ctx, host); @@ -749,13 +745,13 @@ index 8f1f54afb..f2d6f59e5 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); -@@ -294,10 +544,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) +@@ -296,10 +532,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) GSS_C_NO_BUFFER); } -- if (GSS_ERROR(major)) +- if (GSS_ERROR(major)) + if (GSS_ERROR(major) || intctx != NULL) ssh_gssapi_delete_ctx(ctx); @@ -820,7 +816,7 @@ index 8f1f54afb..f2d6f59e5 100644 + #endif /* GSSAPI */ diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index a151bc1e4..8d2b677f7 100644 +index a151bc1e..8d2b677f 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c @@ -1,7 +1,7 @@ @@ -960,11 +956,11 @@ index a151bc1e4..8d2b677f7 100644 #endif /* KRB5 */ diff --git a/gss-serv.c b/gss-serv.c -index b0e9c3b49..6bac42931 100644 +index ab3a15f0..6ce56e92 100644 --- a/gss-serv.c +++ b/gss-serv.c @@ -1,7 +1,7 @@ - /* $OpenBSD: gss-serv.c,v 1.33 2025/09/29 21:30:15 dtucker Exp $ */ + /* $OpenBSD: gss-serv.c,v 1.32 2020/03/13 03:17:07 djm Exp $ */ /* - * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. @@ -972,7 +968,7 @@ index b0e9c3b49..6bac42931 100644 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions -@@ -45,17 +45,19 @@ +@@ -44,17 +44,19 @@ #include "session.h" #include "misc.h" #include "servconf.h" @@ -995,7 +991,7 @@ index b0e9c3b49..6bac42931 100644 #ifdef KRB5 extern ssh_gssapi_mech gssapi_kerberos_mech; -@@ -141,6 +143,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) +@@ -140,6 +142,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) return (ssh_gssapi_acquire_cred(*ctx)); } @@ -1016,7 +1012,7 @@ index b0e9c3b49..6bac42931 100644 + Gssctxt *ctx = NULL; + int res; + -+ res = !GSS_ERROR(mm_ssh_gssapi_server_ctx(&ctx, oid)); ++ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); + ssh_gssapi_delete_ctx(&ctx); + + return (res); @@ -1025,7 +1021,7 @@ index b0e9c3b49..6bac42931 100644 /* Unprivileged */ void ssh_gssapi_supported_oids(gss_OID_set *oidset) -@@ -151,7 +176,9 @@ 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); @@ -1036,7 +1032,7 @@ index b0e9c3b49..6bac42931 100644 while (supported_mechs[i]->name != NULL) { if (GSS_ERROR(gss_test_oid_set_member(&min_status, -@@ -277,8 +304,48 @@ OM_uint32 +@@ -276,8 +303,48 @@ OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) { int i = 0; @@ -1051,15 +1047,15 @@ index b0e9c3b49..6bac42931 100644 + 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); + } -+ + +- gss_buffer_desc ename; + ctx->major = gss_compare_name(&ctx->minor, client->name, + new_name, &equal); + @@ -1086,7 +1082,7 @@ index b0e9c3b49..6bac42931 100644 client->mech = NULL; -@@ -293,6 +360,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) +@@ -292,6 +359,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) if (client->mech == NULL) return GSS_S_FAILURE; @@ -1100,7 +1096,7 @@ index b0e9c3b49..6bac42931 100644 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); -@@ -310,6 +384,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) +@@ -309,6 +383,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) return (ctx->major); } @@ -1109,7 +1105,7 @@ index b0e9c3b49..6bac42931 100644 /* 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; -@@ -320,11 +396,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) +@@ -319,11 +395,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) void ssh_gssapi_cleanup_creds(void) { @@ -1135,7 +1131,7 @@ index b0e9c3b49..6bac42931 100644 } } -@@ -357,19 +442,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) +@@ -356,19 +441,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) /* Privileged */ int @@ -1162,7 +1158,7 @@ index b0e9c3b49..6bac42931 100644 /* Destroy delegated credentials if userok fails */ gss_release_buffer(&lmin, &gssapi_client.displayname); gss_release_buffer(&lmin, &gssapi_client.exportedname); -@@ -383,14 +472,85 @@ ssh_gssapi_userok(char *user) +@@ -382,14 +471,90 @@ ssh_gssapi_userok(char *user) return (0); } @@ -1205,7 +1201,7 @@ index b0e9c3b49..6bac42931 100644 + gssapi_client.store.envvar == NULL) + return; + -+ ok = mm_ssh_gssapi_update_creds(&gssapi_client.store); ++ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); + + if (!ok) + return; @@ -1217,6 +1213,11 @@ index b0e9c3b49..6bac42931 100644 + * for rekeying. So, use our own :) + */ +#ifdef USE_PAM ++ if (!use_privsep) { ++ debug("Not even going to try and do PAM with privsep disabled"); ++ return; ++ } ++ + ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, + &pamconv, &pamh); + if (ret) @@ -1254,37 +1255,37 @@ index b0e9c3b49..6bac42931 100644 } /* Privileged */ -diff --git a/kex-names.c b/kex-names.c -index a20ce602a..31e395aa2 100644 ---- a/kex-names.c -+++ b/kex-names.c -@@ -45,6 +45,10 @@ - #include "ssherr.h" +diff --git a/kex.c b/kex.c +index ce85f043..574c7609 100644 +--- a/kex.c ++++ b/kex.c +@@ -57,6 +57,10 @@ + #include "digest.h" #include "xmalloc.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + - struct kexalg { - char *name; - u_int type; -@@ -90,9 +94,22 @@ static const struct kexalg kexalgs[] = { + /* prototype */ + static int kex_choose_conf(struct ssh *, uint32_t seq); + 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, 0 }, + { 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_NOT_PQ }, -+ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1, KEX_NOT_PQ }, -+ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1, KEX_NOT_PQ }, -+ { KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256, KEX_NOT_PQ }, -+ { KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512, KEX_NOT_PQ }, ++ { 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_NOT_PQ }, -+ { KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256, KEX_NOT_PQ }, ++ 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, 0}, ++ { NULL, 0, -1, -1}, +}; -char * @@ -1292,9 +1293,16 @@ index a20ce602a..31e395aa2 100644 +static char * +kex_alg_list_internal(char sep, const struct kexalg *algs) { - char *ret = NULL; + char *ret = NULL, *tmp; + size_t nlen, rlen = 0; const struct kexalg *k; -@@ -104,6 +121,18 @@ kex_alg_list(char sep) + +- 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; } @@ -1313,7 +1321,7 @@ index a20ce602a..31e395aa2 100644 static const struct kexalg * kex_alg_by_name(const char *name) { -@@ -113,6 +142,10 @@ 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; } @@ -1324,11 +1332,10 @@ index a20ce602a..31e395aa2 100644 return NULL; } -@@ -336,3 +369,26 @@ kex_assemble_names(char **listp, const char *def, const char *all) - free(ret); +@@ -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) @@ -1351,55 +1358,11 @@ index a20ce602a..31e395aa2 100644 + free(s); + return 1; +} -diff --git a/kex.c b/kex.c -index 814fad947..9a2ce6d88 100644 ---- a/kex.c -+++ b/kex.c -@@ -295,17 +295,37 @@ static int - kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m) - { - int r; -+ int have_key = 0; -+ int ext_count = 2; + -+#ifdef GSSAPI -+ /* -+ * Currently GSS KEX don't provide host keys as optional message, so -+ * no reasons to announce the publickey-hostbound extension -+ */ -+ 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; -+ } -+ 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; -+ } -+ } -+ if ((r = sshbuf_put_cstring(m, "ping@openssh.com")) != 0 || - (r = sshbuf_put_cstring(m, "0")) != 0) { - error_fr(r, "compose"); - return r; -@@ -735,6 +755,9 @@ kex_free(struct kex *kex) + /* + * Fill out a proposal array with dynamically allocated values, which may + * be modified as required for compatibility reasons. +@@ -698,6 +755,9 @@ kex_free(struct kex *kex) sshbuf_free(kex->server_version); sshbuf_free(kex->client_pub); sshbuf_free(kex->session_id); @@ -1410,24 +1373,13 @@ index 814fad947..9a2ce6d88 100644 sshkey_free(kex->initial_hostkey); free(kex->failed_choice); diff --git a/kex.h b/kex.h -index 55baa6a1e..206ce60ed 100644 +index a5ae6ac0..fe714141 100644 --- a/kex.h +++ b/kex.h -@@ -29,6 +29,10 @@ - #include "mac.h" - #include "crypto_api.h" - -+#ifdef GSSAPI -+# include "ssh-gss.h" /* Gssctxt */ -+#endif -+ - #ifdef WITH_OPENSSL - # include - # include -@@ -103,6 +107,15 @@ enum kex_exchange { +@@ -102,6 +102,15 @@ enum kex_exchange { + KEX_ECDH_SHA2, KEX_C25519_SHA256, KEX_KEM_SNTRUP761X25519_SHA512, - KEX_KEM_MLKEM768X25519_SHA256, +#ifdef GSSAPI + KEX_GSS_GRP1_SHA1, + KEX_GSS_GRP14_SHA1, @@ -1440,12 +1392,11 @@ index 55baa6a1e..206ce60ed 100644 KEX_MAX }; -@@ -169,6 +182,13 @@ struct kex { +@@ -153,6 +162,12 @@ 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; @@ -1454,18 +1405,18 @@ index 55baa6a1e..206ce60ed 100644 char *failed_choice; int (*verify_host_key)(struct sshkey *, struct ssh *); struct sshkey *(*load_host_public_key)(int, int, struct ssh *); -@@ -196,8 +216,10 @@ int kex_nid_from_name(const char *); - int kex_is_pq_from_name(const char *); +@@ -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_has_any_alg(const char *, const char *); -+int kex_gss_names_valid(const char *); int kex_assemble_names(char **, const char *, const char *); ++int kex_gss_names_valid(const char *); void kex_proposal_populate_entries(struct ssh *, char *prop[PROPOSAL_MAX], const char *, const char *, const char *, const char *, const char *); -@@ -231,6 +253,12 @@ int kexgex_client(struct ssh *); + void kex_proposal_free_entries(char *prop[PROPOSAL_MAX]); +@@ -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 *); @@ -1478,7 +1429,7 @@ index 55baa6a1e..206ce60ed 100644 int kex_dh_keypair(struct kex *); int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, -@@ -269,6 +297,12 @@ int kexgex_hash(int, const struct sshbuf *, const 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 *); @@ -1492,10 +1443,10 @@ index 55baa6a1e..206ce60ed 100644 __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); diff --git a/kexdh.c b/kexdh.c -index 191bdced0..6d5a7813d 100644 +index 67133e33..edaa4676 100644 --- a/kexdh.c +++ b/kexdh.c -@@ -50,13 +50,23 @@ kex_dh_keygen(struct kex *kex) +@@ -48,13 +48,23 @@ kex_dh_keygen(struct kex *kex) { switch (kex->kex_type) { case KEX_DH_GRP1_SHA1: @@ -1520,7 +1471,7 @@ index 191bdced0..6d5a7813d 100644 break; case KEX_DH_GRP18_SHA512: diff --git a/kexgen.c b/kexgen.c -index 494d4b233..58edc79ad 100644 +index 69348b96..c0e8c2f4 100644 --- a/kexgen.c +++ b/kexgen.c @@ -44,7 +44,7 @@ @@ -1534,10 +1485,10 @@ index 494d4b233..58edc79ad 100644 const struct sshbuf *client_version, diff --git a/kexgssc.c b/kexgssc.c new file mode 100644 -index 000000000..96f7b6f58 +index 00000000..f6e1405e --- /dev/null +++ b/kexgssc.c -@@ -0,0 +1,706 @@ +@@ -0,0 +1,612 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1587,206 +1538,38 @@ index 000000000..96f7b6f58 + +#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(&kex->gss); -+ if (ssh_gssapi_id_kex(kex->gss, kex->name, kex->kex_type) == GSS_C_NO_OID) ++ 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"); + -+ if (ssh_gssapi_import_name(kex->gss, kex->gss_host)) ++ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) + fatal("Couldn't import hostname"); + + if (kex->gss_client && -+ ssh_gssapi_client_identity(kex->gss, kex->gss_client)) ++ ssh_gssapi_client_identity(ctxt, kex->gss_client)) + fatal("Couldn't acquire client credentials"); + + /* Step 1 */ @@ -1807,449 +1590,523 @@ index 000000000..96f7b6f58 + fatal_f("Unexpected KEX type %d", kex->kex_type); + } + if (r != 0) { -+ ssh_gssapi_delete_ctx(&kex->gss); ++ ssh_gssapi_delete_ctx(&ctxt); + return r; + } -+ return kexgss_init_ctx(ssh, 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; ++ token_ptr = GSS_C_NO_BUFFER; + -+ 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; -+} ++ do { ++ debug("Calling gss_init_sec_context"); + -+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; ++ maj_status = ssh_gssapi_init_ctx(ctxt, ++ kex->gss_deleg_creds, token_ptr, &send_tok, ++ &ret_flags); + -+ 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 (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"); ++ } + -+ 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 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); + -+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 (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"); + -+ 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 integ avail flag is not true kex fails */ ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity check failed"); ++ } + -+ 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 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); + -+ /* 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 we've sent them data, they should reply */ ++ do { ++ type = ssh_packet_read(ssh); ++ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { ++ u_char *tmp = NULL; ++ size_t tmp_len = 0; + -+ if (gss->major & GSS_S_CONTINUE_NEEDED) -+ return kexgss_init_ctx(ssh, &recv_tok); ++ 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); + -+ gss_release_buffer(&gss->minor, &recv_tok); -+ return kexgss_final(ssh); -+} ++ 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)); + -+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; ++ /* 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); + + /* + * We _must_ have received a COMPLETE message in reply from the + * server, which will have set server_blob and msg_tok + */ + -+ /* 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 (type != SSH2_MSG_KEXGSS_COMPLETE) ++ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); + -+ if ((shared_secret = sshbuf_new()) == NULL) { -+ ssh_gssapi_delete_ctx(&kex->gss); -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } ++ /* 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 ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) { -+ ssh_gssapi_delete_ctx(&kex->gss); -+ goto out; ++ 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) ++ 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->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)); ++ 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); + -+ gss->buf.value = hash; -+ gss->buf.length = hashlen; ++ gssbuf.value = hash; ++ gssbuf.length = hashlen; + + /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(gss, &gss->buf, &gss->msg_tok))) ++ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) + sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); + -+ gss_release_buffer(&gss->minor, &gss->msg_tok); ++ gss_release_buffer(&min_status, &msg_tok); + + if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(gss); ++ ssh_gssapi_credentials_updated(ctxt); + + if (gss_kex_context == NULL) -+ gss_kex_context = gss; ++ gss_kex_context = ctxt; + else -+ ssh_gssapi_delete_ctx(&kex->gss); ++ 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 (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)); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ BN_clear_free(dh_server_pub); ++ explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); ++ sshbuf_free(empty); ++ sshbuf_free(server_host_key_blob); ++ sshbuf_free(server_blob); + sshbuf_free(shared_secret); ++ sshbuf_free(kex->client_pub); ++ kex->client_pub = NULL; + return r; +} + -+static int -+kexgssgex_init_ctx(struct ssh *ssh, -+ gss_buffer_desc *token_ptr) -+{ -+ struct kex *kex = ssh->kex; -+ Gssctxt *gss = kex->gss; -+ const BIGNUM *pub_key; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ OM_uint32 ret_flags; -+ int r; -+ -+ /* Step 2 - call GSS_Init_sec_context() */ -+ 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) { -+ 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) ++int ++kexgssgex_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 *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; + int r; + -+ debug("Received SSH2_MSG_KEXGSS_GROUP"); -+ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUP, NULL); ++ /* 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"); ++ ++ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) ++ fatal("Couldn't import hostname"); ++ ++ if (kex->gss_client && ++ ssh_gssapi_client_identity(ctxt, kex->gss_client)) ++ fatal("Couldn't acquire client credentials"); ++ ++ debug("Doing group exchange"); ++ nbits = dh_estimate(kex->dh_need * 8); ++ ++ 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 ((r = ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0) ++ fatal("Error: %s", ssh_err(r)); + + 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) < kex->min || BN_num_bits(p) > kex->max) ++ if (BN_num_bits(p) < min || BN_num_bits(p) > max) + fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", -+ kex->min, BN_num_bits(p), kex->max); ++ min, BN_num_bits(p), 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) { -+ ssh_gssapi_delete_ctx(&kex->gss); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ return r; -+ } ++ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) ++ goto out; ++ DH_get0_key(kex->dh, &pub_key, NULL); + -+ return kexgssgex_init_ctx(ssh, GSS_C_NO_BUFFER); -+} ++ token_ptr = 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; ++ do { ++ /* Step 2 - call GSS_Init_sec_context() */ ++ debug("Calling gss_init_sec_context"); + -+ 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); ++ maj_status = ssh_gssapi_init_ctx(ctxt, ++ kex->gss_deleg_creds, token_ptr, &send_tok, ++ &ret_flags); + -+ 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)) ++ 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) { ++ u_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"); -+ 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; ++ /* 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; + -+ 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 ((shared_secret = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; + } -+ 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); ++ 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; ++ } + -+ gss_release_buffer(&gss->minor, &recv_tok); -+ return kexgssgex_final(ssh); ++ 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; +} + +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ diff --git a/kexgsss.c b/kexgsss.c new file mode 100644 -index 000000000..8362081ea +index 00000000..60bc02de --- /dev/null +++ b/kexgsss.c -@@ -0,0 +1,601 @@ +@@ -0,0 +1,482 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -2302,18 +2159,33 @@ index 000000000..8362081ea + +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 */ + @@ -2329,94 +2201,135 @@ index 000000000..8362081ea + 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(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) ++ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) + fatal("Unable to acquire credentials for the server"); + -+ ssh_gssapi_build_ctx(&kex->gss); -+ if (kex->gss == NULL) -+ fatal("Unable to allocate memory for gss context"); ++ 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_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; -+} ++ 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; + -+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; ++ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ + -+ gss->major = mm_ssh_gssapi_accept_ctx(gss, recv_tok, send_tok, ret_flags); -+ gss_release_buffer(&gss->minor, recv_tok); ++ /* 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; + -+ if (gss->major != GSS_S_COMPLETE && send_tok->length == 0) -+ fatal("Zero length token output when incomplete"); ++ gssbuf.value = hash; ++ gssbuf.length = hashlen; + -+ if (gss->buf.value == NULL) -+ fatal("No client public key"); ++ sshbuf_free(client_pubkey); ++ client_pubkey = NULL; + -+ 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); -+ } -+} ++ 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); ++ } + -+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; ++ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, ++ &send_tok, &ret_flags)); + -+ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); -+ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ gss_release_buffer(&min_status, &recv_tok); + -+ if (GSS_ERROR(gss->major)) { -+ if (send_tok->length > 0) { ++ 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 ((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)); ++ 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 (!(*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(mm_ssh_gssapi_sign(gss, &gss->buf, &msg_tok))) ++ 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_stringb(ssh, gss->server_pubkey)) != 0 || ++ (r = sshpkt_put_stringb(ssh, 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 */ @@ -2425,19 +2338,13 @@ index 000000000..8362081ea + 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); -+ -+ hashlen = gss->hashlen; -+ memcpy(hash, gss->hash, hashlen); -+ explicit_bzero(gss->hash, sizeof(gss->hash)); -+ shared_secret = gss->shared_secret; -+ gss->shared_secret = NULL; ++ gss_release_buffer(&min_status, &send_tok); ++ gss_release_buffer(&min_status, &msg_tok); + + if (gss_kex_context == NULL) -+ gss_kex_context = gss; ++ gss_kex_context = ctxt; + else -+ ssh_gssapi_delete_ctx(&kex->gss); ++ ssh_gssapi_delete_ctx(&ctxt); + + if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); @@ -2446,126 +2353,44 @@ index 000000000..8362081ea + * just exchanged. */ + if (options.gss_store_rekey) + ssh_gssapi_rekey_creds(); -+ -+ if (kex->gss != NULL) { -+ sshbuf_free(gss->server_pubkey); -+ gss->server_pubkey = NULL; -+ } ++out: ++ sshbuf_free(empty); + 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 */ + @@ -2573,194 +2398,29 @@ index 000000000..8362081ea + * in the GSSAPI code are no longer available. This kludges them back + * into life + */ -+ if (!ssh_gssapi_oid_table_ok()) { -+ mechs = ssh_gssapi_server_mechanisms(); -+ free(mechs); -+ } ++ if (!ssh_gssapi_oid_table_ok()) ++ if ((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(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) ++ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) + fatal("Unable to acquire credentials for the server"); + -+ ssh_gssapi_build_ctx(&kex->gss); -+ if (kex->gss == NULL) -+ fatal("Unable to allocate memory for gss context"); -+ -+ debug("Doing group exchange"); -+ 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); -+ ++ debug("Doing group exchange"); ++ ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUPREQ); + /* 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; @@ -2768,11 +2428,10 @@ index 000000000..8362081ea + 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 = mm_choose_dh(min, nbits, max); ++ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", ++ min, nbits, max); ++ kex->dh = PRIVSEP(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"); @@ -2789,73 +2448,152 @@ index 000000000..8362081ea + 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) { -+ ssh_gssapi_delete_ctx(&kex->gss); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ return r; ++ 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"); + } + -+ 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; -+} ++ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual Authentication flag wasn't set"); + -+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; ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity flag wasn't set"); + -+ debug("SSH2_MSG_KEXGSS_INIT received"); -+ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ /* 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; + -+ 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) ++ 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)); + -+ /* 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) ++ 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)); + -+ kexgssgex_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); -+ if (gss->major & GSS_S_CONTINUE_NEEDED) -+ return 0; ++ gss_release_buffer(&min_status, &send_tok); ++ gss_release_buffer(&min_status, &msg_tok); + -+ return kexgssgex_final(ssh, &send_tok, &ret_flags); ++ 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; +} -+ +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ diff --git a/monitor.c b/monitor.c -index 85dc1b1b7..d463d6a9c 100644 +index 2ce89fe9..ebf76c7f 100644 --- a/monitor.c +++ b/monitor.c -@@ -137,6 +137,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); +@@ -148,6 +148,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); 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 *); @@ -2864,7 +2602,7 @@ index 85dc1b1b7..d463d6a9c 100644 #endif #ifdef SSH_AUDIT_EVENTS -@@ -214,11 +216,18 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -220,11 +222,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}, @@ -2880,11 +2618,11 @@ index 85dc1b1b7..d463d6a9c 100644 + {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, + {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, +#endif - {MONITOR_REQ_STATE, MON_ONCE, mm_answer_state}, #ifdef WITH_OPENSSL {MONITOR_REQ_MODULI, 0, mm_answer_moduli}, -@@ -289,6 +298,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) - monitor_permit(mon_dispatch, MONITOR_REQ_STATE, 1); + #endif +@@ -293,6 +302,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) + /* Permit requests for moduli and signatures */ monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); +#ifdef GSSAPI @@ -2894,7 +2632,7 @@ index 85dc1b1b7..d463d6a9c 100644 /* The first few requests do not require asynchronous access */ while (!authenticated) { -@@ -341,8 +354,15 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) +@@ -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); @@ -2911,7 +2649,7 @@ index 85dc1b1b7..d463d6a9c 100644 if (authenticated || partial) { auth2_update_session_info(authctxt, auth_method, auth_submethod); -@@ -429,6 +449,10 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) +@@ -406,6 +419,10 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); @@ -2922,7 +2660,7 @@ index 85dc1b1b7..d463d6a9c 100644 if (auth_opts->permit_pty_flag) { monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); -@@ -1896,6 +1920,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) +@@ -1713,6 +1730,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kex_gen_server; # endif @@ -2940,7 +2678,7 @@ index 85dc1b1b7..d463d6a9c 100644 #endif /* WITH_OPENSSL */ kex->kex[KEX_C25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; -@@ -1987,8 +2022,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1806,8 +1834,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m) u_char *p; int r; @@ -2951,7 +2689,7 @@ index 85dc1b1b7..d463d6a9c 100644 if ((r = sshbuf_get_string(m, &p, &len)) != 0) fatal_fr(r, "parse"); -@@ -2020,8 +2055,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1839,8 +1867,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) OM_uint32 flags = 0; /* GSI needs this */ int r; @@ -2962,7 +2700,7 @@ index 85dc1b1b7..d463d6a9c 100644 if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) fatal_fr(r, "ssh_gssapi_get_buffer_desc"); -@@ -2041,6 +2076,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1860,6 +1888,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); @@ -2970,7 +2708,7 @@ index 85dc1b1b7..d463d6a9c 100644 } return (0); } -@@ -2052,8 +2088,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1871,8 +1900,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) OM_uint32 ret; int r; @@ -2981,7 +2719,7 @@ index 85dc1b1b7..d463d6a9c 100644 if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0) -@@ -2079,13 +2115,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1898,13 +1927,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) int mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) { @@ -2993,17 +2731,17 @@ index 85dc1b1b7..d463d6a9c 100644 - fatal_f("GSSAPI authentication not enabled"); + if (!options.gss_authentication && !options.gss_keyex) + fatal_f("GSSAPI not enabled"); -+ -+ if ((r = sshbuf_get_u32(m, &kex)) != 0) -+ fatal_fr(r, "buffer error"); - authenticated = authctxt->valid && ssh_gssapi_userok(authctxt->user); ++ if ((r = sshbuf_get_u32(m, &kex)) != 0) ++ fatal_fr(r, "buffer error"); ++ + authenticated = authctxt->valid && + ssh_gssapi_userok(authctxt->user, authctxt->pw, kex); sshbuf_reset(m); if ((r = sshbuf_put_u32(m, authenticated)) != 0) -@@ -2094,7 +2134,11 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1913,7 +1946,11 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) debug3_f("sending result %d", authenticated); mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); @@ -3016,7 +2754,7 @@ index 85dc1b1b7..d463d6a9c 100644 if ((displayname = ssh_gssapi_displayname()) != NULL) auth2_record_info(authctxt, "%s", displayname); -@@ -2102,5 +2146,84 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1921,5 +1958,84 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) /* Monitor loop will terminate if authenticated */ return (authenticated); } @@ -3102,10 +2840,10 @@ index 85dc1b1b7..d463d6a9c 100644 #endif /* GSSAPI */ diff --git a/monitor.h b/monitor.h -index 9dcd9c293..dbc7e0037 100644 +index 683e5e07..2b1a2d59 100644 --- a/monitor.h +++ b/monitor.h -@@ -68,6 +68,8 @@ enum monitor_reqtype { +@@ -63,6 +63,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, @@ -3115,10 +2853,10 @@ index 9dcd9c293..dbc7e0037 100644 struct ssh; diff --git a/monitor_wrap.c b/monitor_wrap.c -index 347eb6870..08dc29e12 100644 +index 001a8fa1..6edb509a 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c -@@ -1142,13 +1142,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) +@@ -993,13 +993,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) } int @@ -3135,7 +2873,7 @@ index 347eb6870..08dc29e12 100644 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, m); mm_request_receive_expect(pmonitor->m_recvfd, -@@ -1161,6 +1163,59 @@ mm_ssh_gssapi_userok(char *user) +@@ -1012,4 +1014,57 @@ mm_ssh_gssapi_userok(char *user) debug3_f("user %sauthenticated", authenticated ? "" : "not "); return (authenticated); } @@ -3193,13 +2931,11 @@ index 347eb6870..08dc29e12 100644 +} + #endif /* GSSAPI */ - - /* diff --git a/monitor_wrap.h b/monitor_wrap.h -index 9b42ddbcb..12c489c33 100644 +index 23ab096a..485590c1 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h -@@ -71,8 +71,10 @@ void mm_decode_activate_server_options(struct ssh *ssh, struct sshbuf *m); +@@ -64,8 +64,10 @@ int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, 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 *); @@ -3211,19 +2947,18 @@ index 9b42ddbcb..12c489c33 100644 #endif #ifdef USE_PAM -diff --git a/readconf.c b/readconf.c -index d99205944..eab734aaf 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -65,6 +65,7 @@ +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 @@ + #include "uidswap.h" #include "myproposal.h" #include "digest.h" - #include "version.h" +#include "ssh-gss.h" /* Format of the configuration file: -@@ -159,6 +160,8 @@ typedef enum { +@@ -161,6 +162,8 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, @@ -3255,7 +2990,7 @@ index d99205944..eab734aaf 100644 #endif #ifdef ENABLE_PKCS11 { "pkcs11provider", oPKCS11Provider }, -@@ -1326,10 +1341,42 @@ parse_time: +@@ -1113,10 +1128,42 @@ parse_time: intptr = &options->gss_authentication; goto parse_flag; @@ -3298,7 +3033,7 @@ index d99205944..eab734aaf 100644 case oBatchMode: intptr = &options->batch_mode; goto parse_flag; -@@ -2698,7 +2745,13 @@ initialize_options(Options * options) +@@ -2306,7 +2353,13 @@ initialize_options(Options * options) options->fwd_opts.streamlocal_bind_unlink = -1; options->pubkey_authentication = -1; options->gss_authentication = -1; @@ -3312,7 +3047,7 @@ index d99205944..eab734aaf 100644 options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; -@@ -2863,8 +2916,18 @@ fill_default_options(Options * options) +@@ -2463,8 +2516,18 @@ fill_default_options(Options * options) options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3331,7 +3066,7 @@ index d99205944..eab734aaf 100644 if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -3692,7 +3755,14 @@ dump_client_config(Options *o, const char *host) +@@ -3246,7 +3309,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); @@ -3346,10 +3081,9 @@ index d99205944..eab734aaf 100644 #endif /* GSSAPI */ dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); -diff --git a/readconf.h b/readconf.h -index 942149f9a..b96e3279e 100644 ---- a/readconf.h -+++ b/readconf.h +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 { int pubkey_authentication; /* Try ssh2 pubkey authentication. */ int hostbased_authentication; /* ssh2's rhosts_rsa */ @@ -3364,19 +3098,18 @@ index 942149f9a..b96e3279e 100644 int password_authentication; /* Try password * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -diff --git a/servconf.c b/servconf.c -index 48ec8c4ec..3b93ca829 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -67,6 +67,7 @@ +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 @@ + #include "auth.h" #include "myproposal.h" #include "digest.h" - #include "version.h" +#include "ssh-gss.h" - #if !defined(SSHD_PAM_SERVICE) - # define SSHD_PAM_SERVICE "sshd" -@@ -136,8 +137,11 @@ initialize_server_options(ServerOptions *options) + static void add_listen_addr(ServerOptions *, const char *, + const char *, int); +@@ -136,8 +137,11 @@ initialize_server_options(ServerOptions options->kerberos_ticket_cleanup = -1; options->kerberos_get_afs_token = -1; options->gss_authentication=-1; @@ -3388,7 +3121,7 @@ index 48ec8c4ec..3b93ca829 100644 options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->permit_empty_passwd = -1; -@@ -374,10 +378,18 @@ fill_default_server_options(ServerOptions *options) +@@ -356,10 +360,18 @@ fill_default_server_options(ServerOption options->kerberos_get_afs_token = 0; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3407,15 +3140,15 @@ index 48ec8c4ec..3b93ca829 100644 if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -562,6 +574,7 @@ typedef enum { - sPerSourcePenalties, sPerSourcePenaltyExemptList, +@@ -506,6 +518,7 @@ typedef enum { + sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -647,12 +660,22 @@ static struct { +@@ -587,12 +600,22 @@ static struct { #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, @@ -3438,7 +3171,7 @@ index 48ec8c4ec..3b93ca829 100644 { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, { "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */ -@@ -1643,6 +1666,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, +@@ -1576,6 +1599,10 @@ process_server_config_line_depth(ServerO intptr = &options->gss_authentication; goto parse_flag; @@ -3449,7 +3182,7 @@ index 48ec8c4ec..3b93ca829 100644 case sGssCleanupCreds: intptr = &options->gss_cleanup_creds; goto parse_flag; -@@ -1651,6 +1678,22 @@ process_server_config_line_depth(ServerOptions *options, char *line, +@@ -1584,6 +1611,22 @@ process_server_config_line_depth(ServerO intptr = &options->gss_strict_acceptor; goto parse_flag; @@ -3472,22 +3205,22 @@ index 48ec8c4ec..3b93ca829 100644 case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -@@ -3256,7 +3299,10 @@ dump_config(ServerOptions *o) +@@ -2892,6 +2935,10 @@ dump_config(ServerOptions *o) #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); + dump_cfg_fmtint(sGssKeyEx, o->gss_keyex); - dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); ++ dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); + dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms); #endif dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); dump_cfg_fmtint(sKbdInteractiveAuthentication, diff --git a/servconf.h b/servconf.h -index 9beb90fae..c3f501400 100644 +index 4202a2d0..3f47ea25 100644 --- a/servconf.h +++ b/servconf.h -@@ -150,8 +150,11 @@ typedef struct { +@@ -132,8 +132,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 */ @@ -3500,10 +3233,10 @@ index 9beb90fae..c3f501400 100644 * authentication. */ int kbd_interactive_authentication; /* If true, permit */ diff --git a/session.c b/session.c -index f265fdc3e..b8f0c1a58 100644 +index 8c0e54f7..06a33442 100644 --- a/session.c +++ b/session.c -@@ -2630,13 +2630,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) +@@ -2678,13 +2678,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) #ifdef KRB5 if (options.kerberos_ticket_cleanup && @@ -3526,10 +3259,18 @@ index f265fdc3e..b8f0c1a58 100644 /* remove agent socket */ diff --git a/ssh-gss.h b/ssh-gss.h -index 7b14e74a8..8ec451926 100644 +index 36180d07..70dd3665 100644 --- a/ssh-gss.h +++ b/ssh-gss.h -@@ -61,10 +61,36 @@ +@@ -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 @@ -3555,8 +3296,6 @@ index 7b14e74a8..8ec451926 100644 + 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; @@ -3566,7 +3305,7 @@ index 7b14e74a8..8ec451926 100644 void *data; } ssh_gssapi_ccache; -@@ -72,8 +98,11 @@ typedef struct { +@@ -72,8 +92,11 @@ typedef struct { gss_buffer_desc displayname; gss_buffer_desc exportedname; gss_cred_id_t creds; @@ -3578,7 +3317,7 @@ index 7b14e74a8..8ec451926 100644 } ssh_gssapi_client; typedef struct ssh_gssapi_mech_struct { -@@ -84,6 +113,7 @@ 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 *); @@ -3586,22 +3325,12 @@ index 7b14e74a8..8ec451926 100644 } ssh_gssapi_mech; typedef struct { -@@ -94,10 +124,21 @@ 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 */ -+ 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[]; @@ -3609,7 +3338,7 @@ index 7b14e74a8..8ec451926 100644 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(OM_uint32 *, gss_OID, int *); +@@ -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 *); @@ -3617,7 +3346,7 @@ index 7b14e74a8..8ec451926 100644 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 **); +@@ -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 *); @@ -3654,26 +3383,24 @@ index 7b14e74a8..8ec451926 100644 #endif /* _SSH_GSS_H */ diff --git a/ssh.1 b/ssh.1 -index db92ac9af..6a9fbdc5b 100644 +index 60de6087..db5c65bc 100644 --- a/ssh.1 +++ b/ssh.1 -@@ -539,9 +539,15 @@ For full details of the options listed below, and their possible values, see - .It ForwardX11Timeout - .It ForwardX11Trusted +@@ -503,7 +503,13 @@ For full details of the options listed below, and their possible values, see + .It GatewayPorts + .It GlobalKnownHostsFile .It GSSAPIAuthentication +.It GSSAPIKeyExchange +.It GSSAPIClientIdentity .It GSSAPIDelegateCredentials - .It GatewayPorts - .It GlobalKnownHostsFile +.It GSSAPIKexAlgorithms +.It GSSAPIRenewalForcesRekey +.It GSSAPIServerIdentity +.It GSSAPITrustDns .It HashKnownHosts .It Host - .It HostKeyAlgorithms -@@ -636,6 +642,8 @@ flag), + .It HostbasedAcceptedAlgorithms +@@ -624,6 +624,8 @@ (supported message integrity codes), .Ar kex (key exchange algorithms), @@ -3683,10 +3410,10 @@ index db92ac9af..6a9fbdc5b 100644 (key types), .Ar key-ca-sign diff --git a/ssh.c b/ssh.c -index 3b03108db..8d27f6379 100644 +index 15aee569..110cf9c1 100644 --- a/ssh.c +++ b/ssh.c -@@ -847,6 +847,8 @@ main(int ac, char **av) +@@ -747,6 +747,8 @@ main(int ac, char **av) else if (strcmp(optarg, "kex") == 0 || strcasecmp(optarg, "KexAlgorithms") == 0) cp = kex_alg_list('\n'); @@ -3695,7 +3422,7 @@ index 3b03108db..8d27f6379 100644 else if (strcmp(optarg, "key") == 0) cp = sshkey_alg_list(0, 0, 0, '\n'); else if (strcmp(optarg, "key-cert") == 0) -@@ -877,8 +879,8 @@ main(int ac, char **av) +@@ -772,8 +774,8 @@ main(int ac, char **av) } else if (strcmp(optarg, "help") == 0) { cp = xstrdup( "cipher\ncipher-auth\ncompression\nkex\n" @@ -3707,7 +3434,7 @@ index 3b03108db..8d27f6379 100644 if (cp == NULL) fatal("Unsupported query \"%s\"", optarg); diff --git a/ssh_config b/ssh_config -index d9324c957..ca7c5853b 100644 +index 5e8ef548..1ff999b6 100644 --- a/ssh_config +++ b/ssh_config @@ -24,6 +24,8 @@ @@ -3720,10 +3447,10 @@ index d9324c957..ca7c5853b 100644 # CheckHostIP no # AddressFamily any diff --git a/ssh_config.5 b/ssh_config.5 -index f7066cbaa..8a4b469cf 100644 +index 06a32d31..3f490697 100644 --- a/ssh_config.5 +++ b/ssh_config.5 -@@ -976,10 +976,68 @@ The default is +@@ -766,10 +766,68 @@ The default is Specifies whether user authentication based on GSSAPI is allowed. The default is .Cm no . @@ -3793,11 +3520,20 @@ index f7066cbaa..8a4b469cf 100644 Indicates that .Xr ssh 1 diff --git a/sshconnect2.c b/sshconnect2.c -index b3679c9d7..b253f991b 100644 +index af00fb30..03bc87eb 100644 --- a/sshconnect2.c +++ b/sshconnect2.c -@@ -222,6 +222,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, - char *all_key, *hkalgs = NULL; +@@ -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, *hkalgs = NULL; int r, use_known_hosts_order = 0; +#if defined(GSSAPI) && defined(WITH_OPENSSL) @@ -3808,10 +3544,11 @@ index b3679c9d7..b253f991b 100644 xxx_host = host; xxx_hostaddr = hostaddr; xxx_conn_info = cinfo; -@@ -255,6 +260,42 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, - compression_alg_list(options.compression), +@@ -206,6 +209,42 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) + kex_proposal_populate_entries(ssh, myproposal, s, options.ciphers, + options.macs, compression_alg_list(options.compression), hkalgs ? hkalgs : options.hostkeyalgorithms); - ++ +#if defined(GSSAPI) && defined(WITH_OPENSSL) + if (options.gss_keyex) { + /* Add the GSSAPI mechanisms currently supported on this @@ -3847,11 +3584,10 @@ index b3679c9d7..b253f991b 100644 + } + } +#endif -+ + free(hkalgs); - /* start key exchange */ -@@ -271,15 +312,45 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, +@@ -224,17 +256,47 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) # ifdef OPENSSL_HAS_ECC ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; # endif @@ -3870,7 +3606,6 @@ index b3679c9d7..b253f991b 100644 +#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_MLKEM768X25519_SHA256] = kex_gen_client; ssh->kex->verify_host_key=&verify_host_key_callback; +#if defined(GSSAPI) && defined(WITH_OPENSSL) @@ -3883,8 +3618,11 @@ index b3679c9d7..b253f991b 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 */ + free(myproposal[PROPOSAL_KEX_ALGS]); + 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 */ @@ -3895,10 +3633,10 @@ index b3679c9d7..b253f991b 100644 + free(gss); + } +#endif - #ifdef DEBUG_KEXDH - /* send 1st encrypted/maced/compressed message */ - if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || -@@ -369,6 +440,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *); + 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 *); 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 *); @@ -3906,7 +3644,7 @@ index b3679c9d7..b253f991b 100644 #endif void userauth(struct ssh *, char *); -@@ -385,6 +457,11 @@ static char *authmethods_get(void); +@@ -346,6 +409,11 @@ static char *authmethods_get(void); Authmethod authmethods[] = { #ifdef GSSAPI @@ -3918,7 +3656,7 @@ index b3679c9d7..b253f991b 100644 {"gssapi-with-mic", userauth_gssapi, userauth_gssapi_cleanup, -@@ -759,12 +836,32 @@ userauth_gssapi(struct ssh *ssh) +@@ -716,12 +784,32 @@ userauth_gssapi(struct ssh *ssh) OM_uint32 min; int r, ok = 0; gss_OID mech = NULL; @@ -3952,7 +3690,7 @@ index b3679c9d7..b253f991b 100644 /* Check to see whether the mechanism is usable before we offer it */ while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && -@@ -773,13 +870,15 @@ userauth_gssapi(struct ssh *ssh) +@@ -730,13 +811,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, @@ -3969,7 +3707,7 @@ index b3679c9d7..b253f991b 100644 if (!ok || mech == NULL) return 0; -@@ -1013,6 +1112,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) +@@ -976,6 +1059,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) free(lang); return r; } @@ -4025,20 +3763,32 @@ index b3679c9d7..b253f991b 100644 #endif /* GSSAPI */ static int -diff --git a/sshd-auth.c b/sshd-auth.c -index 9c31515de..5a4ee733c 100644 ---- a/sshd-auth.c -+++ b/sshd-auth.c -@@ -696,7 +696,7 @@ main(int ac, char **av) - break; - } +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) } -- if (!have_key) -+ if (!have_key && !options.gss_keyex) - fatal("internal error: received no hostkeys"); - - /* Ensure that umask disallows at least group and world write */ -@@ -819,6 +819,48 @@ do_ssh2_kex(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) + free(fp); + } + accumulate_host_timing_secret(cfg, NULL); +- if (!sensitive_data.have_ssh2_key) { ++ /* The GSSAPI key exchange can run without a host key */ ++ if (!sensitive_data.have_ssh2_key && !options.gss_keyex) { + logit("sshd: no hostkeys available -- exiting."); + exit(1); + } +@@ -2347,6 +2348,48 @@ do_ssh2_kex(struct ssh *ssh) free(hkalgs); @@ -4065,7 +3815,7 @@ index 9c31515de..5a4ee733c 100644 + if (gss && orig) + xasprintf(&newstr, "%s,%s", gss, orig); + else if (gss) -+ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com"); ++ newstr = gss; + else if (orig) + newstr = orig; + @@ -4075,7 +3825,7 @@ index 9c31515de..5a4ee733c 100644 + * host key algorithm we support + */ + if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) -+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xstrdup("null"); ++ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; + + if (newstr) + myproposal[PROPOSAL_KEX_ALGS] = newstr; @@ -4087,10 +3837,11 @@ index 9c31515de..5a4ee733c 100644 /* start key exchange */ if ((r = kex_setup(ssh, myproposal)) != 0) fatal_r(r, "kex_setup"); -@@ -836,6 +878,17 @@ do_ssh2_kex(struct ssh *ssh) +@@ -2362,7 +2405,18 @@ do_ssh2_kex(struct ssh *ssh) # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kex_gen_server; - # endif /* OPENSSL_HAS_ECC */ + # endif +-#endif +# ifdef GSSAPI + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; @@ -4102,55 +3853,15 @@ index 9c31515de..5a4ee733c 100644 + kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server; + } +# endif - #endif /* WITH_OPENSSL */ ++#endif /* WITH_OPENSSL */ kex->kex[KEX_C25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; -diff --git a/sshd-session.c b/sshd-session.c -index 9804dc334..6e28020e9 100644 ---- a/sshd-session.c -+++ b/sshd-session.c -@@ -592,8 +592,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); - } -@@ -1135,8 +1135,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; -diff --git a/sshd.c b/sshd.c -index 3c76b60b0..3ab81e268 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -1676,7 +1676,8 @@ main(int ac, char **av) - free(fp); - } - accumulate_host_timing_secret(cfg, NULL); -- if (!sensitive_data.have_ssh2_key) { -+ /* The GSSAPI key exchange can run without a host key */ -+ if (!sensitive_data.have_ssh2_key && !options.gss_keyex) { - logit("sshd: no hostkeys available -- exiting."); - exit(1); - } + kex->load_host_public_key=&get_hostkey_public_by_type; diff --git a/sshd_config b/sshd_config -index 48af6321b..8db9f0fb1 100644 +index 19b7c91a..2c48105f 100644 --- a/sshd_config +++ b/sshd_config -@@ -79,6 +79,8 @@ AuthorizedKeysFile .ssh/authorized_keys +@@ -69,6 +69,8 @@ AuthorizedKeysFile .ssh/authorized_keys # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes @@ -4160,10 +3871,10 @@ index 48af6321b..8db9f0fb1 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 aa9f0af76..b90068bf3 100644 +index 70ccea44..f6b41a2f 100644 --- a/sshd_config.5 +++ b/sshd_config.5 -@@ -739,6 +739,11 @@ Specifies whether to automatically destroy the user's credentials cache +@@ -646,6 +646,11 @@ Specifies whether to automatically destroy the user's credentials cache on logout. The default is .Cm yes . @@ -4175,7 +3886,7 @@ index aa9f0af76..b90068bf3 100644 .It Cm GSSAPIStrictAcceptorCheck Determines whether to be strict about the identity of the GSSAPI acceptor a client authenticates against. -@@ -753,6 +758,32 @@ machine's default store. +@@ -660,6 +665,32 @@ machine's default store. This facility is provided to assist with operation on multi homed machines. The default is .Cm yes . @@ -4209,13 +3920,14 @@ index aa9f0af76..b90068bf3 100644 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 afd7822c4..148fee2b7 100644 +index 57995ee6..fd5b7724 100644 --- a/sshkey.c +++ b/sshkey.c -@@ -114,6 +114,75 @@ extern const struct sshkey_impl sshkey_rsa_sha512_impl; - extern const struct sshkey_impl sshkey_rsa_sha512_cert_impl; - #endif /* WITH_OPENSSL */ - +@@ -127,6 +127,75 @@ static const struct keytype keytypes[] = { + extern const struct sshkey_impl sshkey_xmss_impl; + 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; @@ -4284,19 +3996,18 @@ index afd7822c4..148fee2b7 100644 + /* .keybits = */ 0, /* FIXME */ + /* .funcs = */ &sshkey_gss_funcs, +}; -+ + const struct sshkey_impl * const keyimpls[] = { &sshkey_ed25519_impl, - &sshkey_ed25519_cert_impl, -@@ -144,6 +213,7 @@ const struct sshkey_impl * const keyimpls[] = { - &sshkey_rsa_sha512_impl, - &sshkey_rsa_sha512_cert_impl, - #endif /* WITH_OPENSSL */ +@@ -154,6 +154,7 @@ static const struct keytype keytypes[] = { + &sshkey_xmss_impl, + &sshkey_xmss_cert_impl, + #endif + &sshkey_gss_kex_impl, NULL }; -@@ -314,7 +384,7 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) +@@ -255,7 +256,7 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) for (i = 0; keyimpls[i] != NULL; i++) { impl = keyimpls[i]; @@ -4306,10 +4017,10 @@ index afd7822c4..148fee2b7 100644 if (!include_sigonly && impl->sigonly) continue; diff --git a/sshkey.h b/sshkey.h -index c3262b896..931d1f79b 100644 +index 71a3fddc..37a43a67 100644 --- a/sshkey.h +++ b/sshkey.h -@@ -67,6 +67,7 @@ enum sshkey_types { +@@ -69,6 +69,7 @@ enum sshkey_types { KEY_ECDSA_SK_CERT, KEY_ED25519_SK, KEY_ED25519_SK_CERT, @@ -4317,6 +4028,47 @@ index c3262b896..931d1f79b 100644 KEY_UNSPEC }; --- -2.52.0 +diff --git a/packet.h b/packet.h +--- a/packet.h (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/packet.h (date 1703172586447) +@@ -124,6 +124,7 @@ + int ssh_packet_send2(struct ssh *); + int ssh_packet_read(struct ssh *); ++int ssh_packet_read_expect(struct ssh *, u_int type); + int ssh_packet_read_poll(struct ssh *); + int ssh_packet_read_poll2(struct ssh *, u_char *, u_int32_t *seqnr_p); + int ssh_packet_process_incoming(struct ssh *, const char *buf, u_int len); +diff --git a/packet.c b/packet.c +--- a/packet.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/packet.c (date 1703172586447) +@@ -1425,6 +1416,29 @@ + return type; + } + ++/* ++ * Waits until a packet has been received, verifies that its type matches ++ * that given, and gives a fatal error and exits if there is a mismatch. ++ */ ++ ++int ++ssh_packet_read_expect(struct ssh *ssh, u_int expected_type) ++{ ++ int r; ++ u_char type; ++ ++ if ((r = ssh_packet_read_seqnr(ssh, &type, NULL)) != 0) ++ return r; ++ if (type != expected_type) { ++ if ((r = sshpkt_disconnect(ssh, ++ "Protocol error: expected packet type %d, got %d", ++ expected_type, type)) != 0) ++ return r; ++ return SSH_ERR_PROTOCOL_ERROR; ++ } ++ return 0; ++} ++ + static int + ssh_packet_read_poll2_mux(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) + { diff --git a/openssh-8.0p1-keygen-strip-doseol.patch b/openssh-8.0p1-keygen-strip-doseol.patch new file mode 100644 index 0000000..3117a7a --- /dev/null +++ b/openssh-8.0p1-keygen-strip-doseol.patch @@ -0,0 +1,12 @@ +diff -up openssh-8.0p1/ssh-keygen.c.strip-doseol openssh-8.0p1/ssh-keygen.c +--- openssh-8.0p1/ssh-keygen.c.strip-doseol 2021-03-18 17:41:34.472404994 +0100 ++++ openssh-8.0p1/ssh-keygen.c 2021-03-18 17:41:55.255538761 +0100 +@@ -901,7 +901,7 @@ do_fingerprint(struct passwd *pw) + while (getline(&line, &linesize, f) != -1) { + lnum++; + cp = line; +- cp[strcspn(cp, "\n")] = '\0'; ++ cp[strcspn(cp, "\r\n")] = '\0'; + /* Trim leading space and comments */ + cp = line + strspn(line, " \t"); + if (*cp == '#' || *cp == '\0') diff --git a/openssh-8.0p1-openssl-kdf.patch b/openssh-8.0p1-openssl-kdf.patch new file mode 100644 index 0000000..5d76a4f --- /dev/null +++ b/openssh-8.0p1-openssl-kdf.patch @@ -0,0 +1,137 @@ +commit 2c3ef499bfffce3cfd315edeebf202850ba4e00a +Author: Jakub Jelen +Date: Tue Apr 16 15:35:18 2019 +0200 + + Use the new OpenSSL KDF + +diff --git a/configure.ac b/configure.ac +index 2a455e4e..e01c3d43 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2712,6 +2712,7 @@ if test "x$openssl" = "xyes" ; then + HMAC_CTX_init \ + RSA_generate_key_ex \ + RSA_get_default_method \ ++ EVP_KDF_CTX_new_id \ + ]) + + # OpenSSL_add_all_algorithms may be a macro. +diff --git a/kex.c b/kex.c +index b6f041f4..1fbce2bb 100644 +--- a/kex.c ++++ b/kex.c +@@ -38,6 +38,9 @@ + #ifdef WITH_OPENSSL + #include + #include ++# ifdef HAVE_EVP_KDF_CTX_NEW_ID ++# include ++# endif + #endif + + #include "ssh.h" +@@ -942,6 +945,95 @@ kex_choose_conf(struct ssh *ssh) + return r; + } + ++#ifdef HAVE_EVP_KDF_CTX_NEW_ID ++static const EVP_MD * ++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 int ++derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, ++ const struct sshbuf *shared_secret, u_char **keyp) ++{ ++ struct kex *kex = ssh->kex; ++ EVP_KDF_CTX *ctx = NULL; ++ u_char *key = NULL; ++ int r, key_len; ++ ++ if ((key_len = ssh_digest_bytes(kex->hash_alg)) == 0) ++ return SSH_ERR_INVALID_ARGUMENT; ++ key_len = ROUNDUP(need, key_len); ++ if ((key = calloc(1, key_len)) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ ctx = EVP_KDF_CTX_new_id(EVP_KDF_SSHKDF); ++ if (!ctx) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest_to_md(kex->hash_alg)); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, ++ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, hash, hashlen); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_TYPE, id); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, ++ sshbuf_ptr(kex->session_id), sshbuf_len(kex->session_id)); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ r = EVP_KDF_derive(ctx, key, key_len); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++#ifdef DEBUG_KEX ++ fprintf(stderr, "key '%c'== ", id); ++ dump_digest("key", key, key_len); ++#endif ++ *keyp = key; ++ key = NULL; ++ r = 0; ++ ++out: ++ free (key); ++ EVP_KDF_CTX_free(ctx); ++ if (r < 0) { ++ return r; ++ } ++ return 0; ++} ++#else + static int + derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, + const struct sshbuf *shared_secret, u_char **keyp) +@@ -1004,6 +1096,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, + ssh_digest_free(hashctx); + return r; + } ++#endif /* HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID */ + + #define NKEYS 6 + int + diff --git a/0052-openssh-10.2p1-pkcs11-uri.patch b/openssh-8.0p1-pkcs11-uri.patch similarity index 83% rename from 0052-openssh-10.2p1-pkcs11-uri.patch rename to openssh-8.0p1-pkcs11-uri.patch index b486fee..1e7940d 100644 --- a/0052-openssh-10.2p1-pkcs11-uri.patch +++ b/openssh-8.0p1-pkcs11-uri.patch @@ -1,116 +1,7 @@ -From f32f2a8a37e8585c1259fea2a970319d229e2cc7 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Mon, 15 Dec 2025 14:24:07 +0100 -Subject: [PATCH 52/53] openssh-10.2p1-pkcs11-uri - ---- - Makefile.in | 24 +- - configure.ac | 37 ++ - regress/Makefile | 4 +- - regress/pkcs11.sh | 349 ++++++++++++++ - regress/unittests/Makefile | 2 +- - regress/unittests/pkcs11/tests.c | 353 ++++++++++++++ - ssh-add.c | 48 +- - ssh-agent.c | 104 ++++- - ssh-keygen.c | 7 +- - ssh-pkcs11-client.c | 17 + - ssh-pkcs11-uri.c | 437 ++++++++++++++++++ - ssh-pkcs11-uri.h | 43 ++ - ssh-pkcs11.c | 760 ++++++++++++++++++++++--------- - ssh-pkcs11.h | 4 + - ssh.c | 104 ++++- - ssh_config.5 | 15 + - 16 files changed, 2039 insertions(+), 269 deletions(-) - create mode 100644 regress/pkcs11.sh - create mode 100644 regress/unittests/pkcs11/tests.c - create mode 100644 ssh-pkcs11-uri.c - create mode 100644 ssh-pkcs11-uri.h - -diff --git a/Makefile.in b/Makefile.in -index 20d134c02..f8cbd545d 100644 ---- a/Makefile.in -+++ b/Makefile.in -@@ -112,7 +112,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ - sshbuf-io.o misc-agent.o auditstub.o - --P11OBJS= ssh-pkcs11-client.o -+P11OBJS= ssh-pkcs11-client.o ssh-pkcs11-uri.o - - SKOBJS= ssh-sk-client.o - -@@ -161,11 +161,11 @@ SSHADD_OBJS= ssh-add.o $(P11OBJS) $(SKOBJS) - - SSHAGENT_OBJS= ssh-agent.o $(P11OBJS) $(SKOBJS) - --SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o ssh-pkcs11.o $(SKOBJS) -+SSHKEYGEN_OBJS= ssh-keygen.o sshsig.o ssh-pkcs11.o ssh-pkcs11-uri.o $(SKOBJS) - - SSHKEYSIGN_OBJS=ssh-keysign.o readconf.o uidswap.o $(P11OBJS) $(SKOBJS) - --P11HELPER_OBJS= ssh-pkcs11-helper.o ssh-pkcs11.o $(SKOBJS) -+P11HELPER_OBJS= ssh-pkcs11-helper.o ssh-pkcs11.o ssh-pkcs11-uri.o $(SKOBJS) - - SKHELPER_OBJS= ssh-sk-helper.o ssh-sk.o sk-usbhid.o - -@@ -331,6 +331,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) -+ rm -f regress/unittests/pkcs11/*.o -+ rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT) - rm -f regress/misc/sk-dummy/*.o - rm -f regress/misc/sk-dummy/*.lo - rm -f regress/misc/ssh-verify-attestation/ssh-verify-attestation$(EXEEXT) -@@ -369,6 +371,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 - rm -f regress/misc/sk-dummy/*.o - rm -f regress/misc/sk-dummy/*.lo - rm -f regress/misc/sk-dummy/sk-dummy.so -@@ -549,6 +553,7 @@ regress-prep: - $(MKDIR_P) `pwd`/regress/unittests/sshkey - $(MKDIR_P) `pwd`/regress/unittests/sshsig - $(MKDIR_P) `pwd`/regress/unittests/utf8 -+ $(MKDIR_P) `pwd`/regress/unittests/pkcs11 - $(MKDIR_P) `pwd`/regress/misc/sk-dummy - $(MKDIR_P) `pwd`/regress/misc/ssh-verify-attestation - [ -f `pwd`/regress/Makefile ] || \ -@@ -724,6 +729,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT): \ - regress/unittests/test_helper/libtest_helper.a \ - -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS) - -+UNITTESTS_TEST_PKCS11_OBJS=\ -+ regress/unittests/pkcs11/tests.o -+ -+regress/unittests/pkcs11/test_pkcs11$(EXEEXT): \ -+ ${UNITTESTS_TEST_PKCS11_OBJS} ssh-pkcs11-uri.o \ -+ regress/unittests/test_helper/libtest_helper.a libssh.a -+ $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_PKCS11_OBJS) \ -+ regress/unittests/test_helper/libtest_helper.a \ -+ ssh-pkcs11-uri.o -lssh -lopenbsd-compat -lcrypto $(LIBS) -lm -+ - # These all need to be compiled -fPIC, so they are treated differently. - SK_DUMMY_OBJS=\ - regress/misc/sk-dummy/sk-dummy.lo \ -@@ -769,7 +784,8 @@ regress-unit-binaries: regress-prep $(REGRESSLIBS) \ - regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \ - regress/unittests/sshkey/test_sshkey$(EXEEXT) \ - regress/unittests/sshsig/test_sshsig$(EXEEXT) \ -- regress/unittests/utf8/test_utf8$(EXEEXT) -+ regress/unittests/utf8/test_utf8$(EXEEXT) \ -+ regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ - - tests: file-tests t-exec interop-tests extra-tests unit - echo all tests passed -diff --git a/configure.ac b/configure.ac -index 9d3b19925..e33462027 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -2246,12 +2246,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).]) ]) @@ -125,7 +16,7 @@ index 9d3b19925..e33462027 100644 fi ] ) -@@ -2281,6 +2283,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 ]) @@ -166,7 +57,7 @@ index 9d3b19925..e33462027 100644 # IRIX has a const char return value for gai_strerror() AC_CHECK_FUNCS([gai_strerror], [ AC_DEFINE([HAVE_GAI_STRERROR]) -@@ -5904,6 +5940,7 @@ echo " BSD Auth support: $BSD_AUTH_MSG" +@@ -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" @@ -174,11 +65,75 @@ index 9d3b19925..e33462027 100644 echo " U2F/FIDO support: $enable_sk" echo "" -diff --git a/regress/Makefile b/regress/Makefile -index ece093a2b..a851549f6 100644 ---- a/regress/Makefile -+++ b/regress/Makefile -@@ -139,7 +139,8 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \ +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 \ +- ssh-pkcs11.o smult_curve25519_ref.o \ ++ 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 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) ++ rm -f regress/unittests/pkcs11/*.o ++ rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT) + rm -f regress/misc/sk-dummy/*.o + rm -f regress/misc/sk-dummy/*.lo + rm -f regress/misc/sk-dummy/sk-dummy.so +@@ -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 + 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 ++ $(MKDIR_P) `pwd`/regress/unittests/pkcs11 + $(MKDIR_P) `pwd`/regress/misc/sk-dummy + [ -f `pwd`/regress/Makefile ] || \ + ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile +@@ -685,6 +690,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT + regress/unittests/test_helper/libtest_helper.a \ + -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS) + ++UNITTESTS_TEST_PKCS11_OBJS=\ ++ regress/unittests/pkcs11/tests.o ++ ++regress/unittests/pkcs11/test_pkcs11$(EXEEXT): \ ++ ${UNITTESTS_TEST_PKCS11_OBJS} \ ++ 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 -lcrypto $(LIBS) ++ + # These all need to be compiled -fPIC, so they are treated differently. + SK_DUMMY_OBJS=\ + regress/misc/sk-dummy/sk-dummy.lo \ +@@ -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) \ +- regress/unittests/utf8/test_utf8$(EXEEXT) ++ regress/unittests/utf8/test_utf8$(EXEEXT) \ ++ regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \ + + tests: file-tests t-exec interop-tests extra-tests unit + echo all tests passed +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 \ @@ -188,19 +143,21 @@ index ece093a2b..a851549f6 100644 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 \ -@@ -288,6 +289,7 @@ unit unit-bench: - test "x${UNITTEST_VERBOSE}" = "x" || ARGS="$$ARGS -v"; \ - test "x${UNITTEST_BENCH_DETAIL}" = "x" || ARGS="$$ARGS -B"; \ - test "x${UNITTEST_BENCH_ONLY}" = "x" || ARGS="$$ARGS -O ${UNITTEST_BENCH_ONLY}"; \ -+ $$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \ - $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf $${ARGS}; \ - $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \ - -d ${.CURDIR}/unittests/sshkey/testdata $${ARGS}; \ -diff --git a/regress/pkcs11.sh b/regress/pkcs11.sh -new file mode 100644 -index 000000000..a91aee94f ---- /dev/null -+++ b/regress/pkcs11.sh +@@ -273,8 +274,9 @@ unit: + V="" ; \ + test "x${USE_VALGRIND}" = "x" || \ + V=${.CURDIR}/valgrind-unit.sh ; \ +- $$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 ; \ + $$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 @@ -551,10 +508,9 @@ index 000000000..a91aee94f + trace "kill agent" + ${SSHAGENT} -k > /dev/null +fi -diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile -index e370900e4..d6c89c129 100644 ---- a/regress/unittests/Makefile -+++ b/regress/unittests/Makefile +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 $ @@ -563,12 +519,10 @@ index e370900e4..d6c89c129 100644 +SUBDIR+=authopt misc sshsig pkcs11 .include -diff --git a/regress/unittests/pkcs11/tests.c b/regress/unittests/pkcs11/tests.c -new file mode 100644 -index 000000000..89ba45c4e ---- /dev/null -+++ b/regress/unittests/pkcs11/tests.c -@@ -0,0 +1,353 @@ +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 + * @@ -915,27 +869,19 @@ index 000000000..89ba45c4e + test_parse_invalid(); + test_generate_valid(); +} -+ -+void -+benchmarks(void) -+{ -+ printf("no benchmarks\n"); -+} -+ -diff --git a/ssh-add.c b/ssh-add.c -index 2d5bec89c..aae82a794 100644 ---- a/ssh-add.c -+++ b/ssh-add.c -@@ -70,6 +70,7 @@ +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" - #define CERT_EXPIRY_GRACE (5*60) - -@@ -257,6 +258,38 @@ check_cert_lifetime(const struct sshkey *cert, int cert_lifetime) - return MINIMUM(cert_lifetime, (int)n); + /* argv0 */ + extern char *__progname; +@@ -240,6 +241,38 @@ delete_all(int agent_fd, int qflag) + return ret; } +#ifdef ENABLE_PKCS11 @@ -972,8 +918,8 @@ index 2d5bec89c..aae82a794 100644 + static int add_file(int agent_fd, const char *filename, int key_only, int cert_only, - int qflag, int Nflag, const char *skprovider, -@@ -447,15 +480,14 @@ static int + 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, @@ -991,8 +937,8 @@ index 2d5bec89c..aae82a794 100644 if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN)) == NULL) return -1; -@@ -637,6 +669,14 @@ do_file(int agent_fd, int deleting, int key_only, int cert_only, - char *file, int qflag, int Nflag, 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 @@ -1006,23 +952,22 @@ index 2d5bec89c..aae82a794 100644 if (deleting) { if (delete_file(agent_fd, file, key_only, cert_only, qflag) == -1) -@@ -1009,7 +1049,7 @@ main(int argc, char **argv) +@@ -999,7 +1035,7 @@ main(int argc, char **argv) if (update_card(agent_fd, !deleting, pkcs11provider, qflag, key_only, cert_only, dest_constraints, ndest_constraints, - certs, ncerts) == -1) + certs, ncerts, NULL) == -1) ret = 1; - for (n = 0; n < ncerts; n++) - sshkey_free(certs[n]); -diff --git a/ssh-agent.c b/ssh-agent.c -index dc246066d..c3e94e2b1 100644 ---- a/ssh-agent.c -+++ b/ssh-agent.c -@@ -1540,10 +1540,75 @@ add_p11_identity(struct sshkey *key, char *comment, const char *provider, - idtab->nentries++; + goto done; + } +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,72 @@ add_p11_identity(struct sshkey *key, cha } + #ifdef ENABLE_PKCS11 +static char * +sanitize_pkcs11_provider(const char *provider) +{ @@ -1033,8 +978,6 @@ index dc246066d..c3e94e2b1 100644 + 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) { @@ -1047,7 +990,6 @@ index dc246066d..c3e94e2b1 100644 + + if (pkcs11_uri_parse(provider, uri) != 0) { + error("Failed to parse PKCS#11 URI"); -+ pkcs11_uri_cleanup(uri); + return NULL; + } + /* validate also provider from URI */ @@ -1096,21 +1038,21 @@ index dc246066d..c3e94e2b1 100644 char **comments = NULL; int r, i, count = 0, success = 0, confirm = 0; u_int seconds = 0; -@@ -1572,25 +1637,18 @@ process_add_smartcard_key(SocketEntry *e) +@@ -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; ++ 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); -+ sane_uri = sanitize_pkcs11_provider(provider); -+ if (sane_uri == NULL) - goto send; +- goto send; - } - debug_f("add %.100s", canonical_provider); if (lifetime && !death) @@ -1127,7 +1069,7 @@ index dc246066d..c3e94e2b1 100644 } for (j = 0; j < ncerts; j++) { if (!sshkey_is_cert(certs[j])) -@@ -1600,13 +1658,13 @@ process_add_smartcard_key(SocketEntry *e) +@@ -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]), @@ -1143,7 +1085,7 @@ index dc246066d..c3e94e2b1 100644 dest_constraints, ndest_constraints); keys[i] = NULL; /* transferred */ comments[i] = NULL; /* transferred */ -@@ -1619,6 +1677,7 @@ process_add_smartcard_key(SocketEntry *e) +@@ -1628,6 +1683,7 @@ process_add_smartcard_key(SocketEntry *e send: free(pin); free(provider); @@ -1151,7 +1093,7 @@ index dc246066d..c3e94e2b1 100644 free(keys); free(comments); free_dest_constraints(dest_constraints, ndest_constraints); -@@ -1631,7 +1690,7 @@ send: +@@ -1640,7 +1696,7 @@ send: static void process_remove_smartcard_key(SocketEntry *e) { @@ -1160,7 +1102,7 @@ index dc246066d..c3e94e2b1 100644 int r, success = 0; Identity *id, *nxt; -@@ -1643,30 +1702,29 @@ process_remove_smartcard_key(SocketEntry *e) +@@ -1652,30 +1708,29 @@ process_remove_smartcard_key(SocketEntry } free(pin); @@ -1197,11 +1139,185 @@ index dc246066d..c3e94e2b1 100644 send_status(e, success); } #endif /* ENABLE_PKCS11 */ -diff --git a/ssh-keygen.c b/ssh-keygen.c -index afa279097..7af08fcdf 100644 ---- a/ssh-keygen.c -+++ b/ssh-keygen.c -@@ -831,8 +831,11 @@ do_download(struct passwd *pw) +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. ++.Pp ++The authentication identity can be also specified in a form of PKCS#11 URI ++starting with a string ++.Cm pkcs11: . ++There is supported a subset of the PKCS#11 URI as defined ++in RFC 7512 (implemented path arguments ++.Cm id , ++.Cm manufacturer , ++.Cm object , ++.Cm token ++and query arguments ++.Cm module-path ++and ++.Cm pin-value ++). The URI can not be in quotes. + .It Cm IgnoreUnknown + Specifies a pattern-list of unknown options to be ignored if they are + encountered in configuration parsing. +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': ++#ifdef ENABLE_PKCS11 ++ if (strlen(optarg) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(optarg, PKCS11_URI_SCHEME, ++ strlen(PKCS11_URI_SCHEME)) == 0) { ++ add_identity_file(&options, NULL, optarg, 1); ++ break; ++ } ++#endif + p = tilde_expand_filename(optarg, getuid()); + if (stat(p, &st) == -1) + fprintf(stderr, "Warning: Identity file %s " +@@ -1784,6 +1792,7 @@ main(int ac, char **av) + #ifdef ENABLE_PKCS11 + (void)pkcs11_del_provider(options.pkcs11_provider); + #endif ++ pkcs11_terminate(); + + skip_connect: + exit_status = ssh_session2(ssh, cinfo); +@@ -2307,6 +2316,45 @@ ssh_session2(struct ssh *ssh, const stru + options.escape_char : SSH_ESCAPECHAR_NONE, id); + } + ++#ifdef ENABLE_PKCS11 ++static void ++load_pkcs11_identity(char *pkcs11_uri, char *identity_files[], ++ struct sshkey *identity_keys[], int *n_ids) ++{ ++ int nkeys, i; ++ struct sshkey **keys; ++ struct pkcs11_uri *uri; ++ ++ debug("identity file '%s' from pkcs#11", pkcs11_uri); ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PKCS#11 URI"); ++ ++ if (pkcs11_uri_parse(pkcs11_uri, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI %s", pkcs11_uri); ++ ++ /* we need to merge URI and provider together */ ++ if (options.pkcs11_provider != NULL && uri->module_path == NULL) ++ uri->module_path = strdup(options.pkcs11_provider); ++ ++ if (options.num_identity_files < SSH_MAX_IDENTITY_FILES && ++ (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys, NULL)) > 0) { ++ for (i = 0; i < nkeys; i++) { ++ if (*n_ids >= SSH_MAX_IDENTITY_FILES) { ++ sshkey_free(keys[i]); ++ continue; ++ } ++ identity_keys[*n_ids] = keys[i]; ++ identity_files[*n_ids] = pkcs11_uri_get(uri); ++ (*n_ids)++; ++ } ++ free(keys); ++ } ++ ++ pkcs11_uri_cleanup(uri); ++} ++#endif /* ENABLE_PKCS11 */ ++ + /* Loads all IdentityFile and CertificateFile keys */ + static void + load_public_identity_files(const struct ssh_conn_info *cinfo) +@@ -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]; +-#ifdef ENABLE_PKCS11 +- struct sshkey **keys = NULL; +- char **comments = NULL; +- int nkeys; +-#endif /* PKCS11 */ + + n_ids = n_certs = 0; + memset(identity_files, 0, sizeof(identity_files)); +@@ -2338,33 +2381,46 @@ load_public_identity_files(const struct + sizeof(certificate_file_userprovided)); + + #ifdef ENABLE_PKCS11 +- if (options.pkcs11_provider != NULL && +- options.num_identity_files < SSH_MAX_IDENTITY_FILES && +- (pkcs11_init(!options.batch_mode) == 0) && +- (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, +- &keys, &comments)) > 0) { +- for (i = 0; i < nkeys; i++) { +- if (n_ids >= SSH_MAX_IDENTITY_FILES) { +- sshkey_free(keys[i]); +- free(comments[i]); +- continue; +- } +- identity_keys[n_ids] = keys[i]; +- identity_files[n_ids] = comments[i]; /* transferred */ +- n_ids++; +- } +- free(keys); +- free(comments); ++ /* handle fallback from PKCS11Provider option */ ++ pkcs11_init(!options.batch_mode); ++ ++ if (options.pkcs11_provider != NULL) { ++ struct pkcs11_uri *uri; ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PKCS#11 URI"); ++ ++ /* Construct simple PKCS#11 URI to simplify access */ ++ uri->module_path = strdup(options.pkcs11_provider); ++ ++ /* Add it as any other IdentityFile */ ++ cp = pkcs11_uri_get(uri); ++ add_identity_file(&options, NULL, cp, 1); ++ free(cp); ++ ++ pkcs11_uri_cleanup(uri); + } + #endif /* ENABLE_PKCS11 */ + for (i = 0; i < options.num_identity_files; i++) { ++ char *name = options.identity_files[i]; + if (n_ids >= SSH_MAX_IDENTITY_FILES || +- strcasecmp(options.identity_files[i], "none") == 0) { ++ strcasecmp(name, "none") == 0) { + free(options.identity_files[i]); + options.identity_files[i] = NULL; + continue; + } +- cp = tilde_expand_filename(options.identity_files[i], getuid()); ++#ifdef ENABLE_PKCS11 ++ if (strlen(name) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(name, PKCS11_URI_SCHEME, ++ strlen(PKCS11_URI_SCHEME)) == 0) { ++ load_pkcs11_identity(name, identity_files, ++ identity_keys, &n_ids); ++ free(options.identity_files[i]); ++ continue; ++ } ++#endif /* ENABLE_PKCS11 */ ++ cp = tilde_expand_filename(name, getuid()); + filename = default_client_percent_dollar_expand(cp, cinfo); + free(cp); + check_load(sshkey_load_public(filename, &public, NULL), +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 */ @@ -1215,31 +1331,10 @@ index afa279097..7af08fcdf 100644 } free(comments[i]); sshkey_free(keys[i]); -diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c -index 85afb62ac..7b7eaf533 100644 ---- a/ssh-pkcs11-client.c -+++ b/ssh-pkcs11-client.c -@@ -378,6 +378,19 @@ pkcs11_start_helper(const char *path) - return helper; - } - -+int -+pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***keyp, char ***labelsp) -+{ -+ int nkeys = 0; -+ char *provider_uri = pkcs11_uri_get(uri); -+ -+ debug_f("called, provider_uri = %s", provider_uri); -+ -+ nkeys = pkcs11_add_provider(provider_uri, pin, keyp, labelsp); -+ -+ return nkeys; -+} -+ - int - pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, - char ***labelsp) -@@ -389,6 +403,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, +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; @@ -1248,19 +1343,1292 @@ index 85afb62ac..7b7eaf533 100644 if ((helper = helper_by_provider(name)) == NULL && (helper = pkcs11_start_helper(name)) == NULL) return -1; -@@ -413,6 +429,7 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, +@@ -612,6 +614,7 @@ pkcs11_add_provider(char *name, char *pi *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); if (labelsp) *labelsp = xcalloc(nkeys, sizeof(char *)); + debug_f("nkeys = %u", nkeys); for (i = 0; i < nkeys; i++) { /* XXX clean up properly instead of fatal() */ - if ((r = sshkey_froms(msg, &k)) != 0 || -diff --git a/ssh-pkcs11-uri.c b/ssh-pkcs11-uri.c -new file mode 100644 -index 000000000..8bd97e9e2 ---- /dev/null -+++ b/ssh-pkcs11-uri.c + if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 || +diff -up openssh-9.6p1/ssh-pkcs11.c.pkcs11-uri openssh-9.6p1/ssh-pkcs11.c +--- openssh-9.6p1/ssh-pkcs11.c.pkcs11-uri 2023-12-18 15:59:50.000000000 +0100 ++++ openssh-9.6p1/ssh-pkcs11.c 2024-01-12 14:28:09.170975480 +0100 +@@ -55,8 +55,8 @@ struct pkcs11_slotinfo { + int logged_in; + }; + +-struct pkcs11_provider { +- char *name; ++struct pkcs11_module { ++ char *module_path; + void *handle; + CK_FUNCTION_LIST *function_list; + CK_INFO info; +@@ -65,6 +65,13 @@ struct pkcs11_provider { + struct pkcs11_slotinfo *slotinfo; + int valid; + int refcount; ++}; ++ ++struct pkcs11_provider { ++ char *name; ++ struct pkcs11_module *module; /* can be shared between various providers */ ++ int refcount; ++ int valid; + TAILQ_ENTRY(pkcs11_provider) next; + }; + +@@ -75,6 +82,7 @@ struct pkcs11_key { + CK_ULONG slotidx; + char *keyid; + int keyid_len; ++ char *label; + }; + + int pkcs11_interactive = 0; +@@ -106,26 +114,61 @@ pkcs11_init(int interactive) + * this is called when a provider gets unregistered. + */ + static void +-pkcs11_provider_finalize(struct pkcs11_provider *p) ++pkcs11_module_finalize(struct pkcs11_module *m) + { + CK_RV rv; + CK_ULONG i; + +- debug_f("provider \"%s\" refcount %d valid %d", +- p->name, p->refcount, p->valid); +- if (!p->valid) ++ debug_f("%p refcount %d valid %d", m, m->refcount, m->valid); ++ if (!m->valid) + return; +- for (i = 0; i < p->nslots; i++) { +- if (p->slotinfo[i].session && +- (rv = p->function_list->C_CloseSession( +- p->slotinfo[i].session)) != CKR_OK) ++ for (i = 0; i < m->nslots; i++) { ++ if (m->slotinfo[i].session && ++ (rv = m->function_list->C_CloseSession( ++ m->slotinfo[i].session)) != CKR_OK) + error("C_CloseSession failed: %lu", rv); + } +- if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK) ++ if ((rv = m->function_list->C_Finalize(NULL)) != CKR_OK) + error("C_Finalize failed: %lu", rv); ++ m->valid = 0; ++ m->function_list = NULL; ++ dlclose(m->handle); ++} ++ ++/* ++ * remove a reference to the pkcs11 module. ++ * called when a provider is unregistered. ++ */ ++static void ++pkcs11_module_unref(struct pkcs11_module *m) ++{ ++ debug_f("%p refcount %d", m, m->refcount); ++ if (--m->refcount <= 0) { ++ pkcs11_module_finalize(m); ++ if (m->valid) ++ error_f("%p still valid", m); ++ free(m->slotlist); ++ free(m->slotinfo); ++ free(m->module_path); ++ free(m); ++ } ++} ++ ++/* ++ * finalize a provider shared library, it's no longer usable. ++ * however, there might still be keys referencing this provider, ++ * so the actual freeing of memory is handled by pkcs11_provider_unref(). ++ * this is called when a provider gets unregistered. ++ */ ++static void ++pkcs11_provider_finalize(struct pkcs11_provider *p) ++{ ++ debug_f("%p refcount %d valid %d", p, p->refcount, p->valid); ++ if (!p->valid) ++ return; ++ pkcs11_module_unref(p->module); ++ p->module = NULL; + p->valid = 0; +- p->function_list = NULL; +- dlclose(p->handle); + } + + /* +@@ -137,11 +180,9 @@ pkcs11_provider_unref(struct pkcs11_prov + { + debug_f("provider \"%s\" refcount %d", p->name, p->refcount); + if (--p->refcount <= 0) { +- if (p->valid) +- error_f("provider \"%s\" still valid", p->name); + free(p->name); +- free(p->slotlist); +- free(p->slotinfo); ++ if (p->module) ++ pkcs11_module_unref(p->module); + free(p); + } + } +@@ -159,6 +200,20 @@ pkcs11_terminate(void) + } + } + ++/* lookup provider by module path */ ++static struct pkcs11_module * ++pkcs11_provider_lookup_module(char *module_path) ++{ ++ struct pkcs11_provider *p; ++ ++ TAILQ_FOREACH(p, &pkcs11_providers, next) { ++ debug("check %p %s (%s)", p, p->name, p->module->module_path); ++ if (!strcmp(module_path, p->module->module_path)) ++ return (p->module); ++ } ++ return (NULL); ++} ++ + /* lookup provider by name */ + static struct pkcs11_provider * + pkcs11_provider_lookup(char *provider_id) +@@ -173,19 +228,55 @@ pkcs11_provider_lookup(char *provider_id + return (NULL); + } + ++int pkcs11_del_provider_by_uri(struct pkcs11_uri *); ++ + /* unregister provider by name */ + int + pkcs11_del_provider(char *provider_id) + { ++ int rv; ++ struct pkcs11_uri *uri; ++ ++ debug_f("called, provider_id = %s", provider_id); ++ ++ if (provider_id == NULL) ++ return 0; ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PKCS#11 URI"); ++ ++ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { ++ if (pkcs11_uri_parse(provider_id, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI"); ++ } else { ++ uri->module_path = strdup(provider_id); ++ } ++ ++ rv = pkcs11_del_provider_by_uri(uri); ++ pkcs11_uri_cleanup(uri); ++ return rv; ++} ++ ++/* unregister provider by PKCS#11 URI */ ++int ++pkcs11_del_provider_by_uri(struct pkcs11_uri *uri) ++{ + 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) { ++ if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) { + TAILQ_REMOVE(&pkcs11_providers, p, next); + pkcs11_provider_finalize(p); + pkcs11_provider_unref(p); +- return (0); ++ rv = 0; + } +- return (-1); ++ free(provider_uri); ++ return rv; + } + + static RSA_METHOD *rsa_method; +@@ -195,6 +286,56 @@ static EC_KEY_METHOD *ec_key_method; + static int ec_key_idx = 0; + #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ + ++/* ++ * This can't be in the ssh-pkcs11-uri, becase we can not depend on ++ * PKCS#11 structures in ssh-agent (using client-helper communication) ++ */ ++int ++pkcs11_uri_write(const struct sshkey *key, FILE *f) ++{ ++ char *p = NULL; ++ struct pkcs11_uri uri; ++ struct pkcs11_key *k11; ++ ++ /* 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); ++ break; ++#ifdef HAVE_EC_KEY_METHOD_NEW ++ case KEY_ECDSA: ++ k11 = EC_KEY_get_ex_data(key->ecdsa, ec_key_idx); ++ break; ++#endif ++ default: ++ error("Unknown key type %d", key->type); ++ return -1; ++ } ++ if (k11 == NULL) { ++ error("Failed to get ex_data for key type %d", key->type); ++ return (-1); ++ } ++ ++ /* omit type -- we are looking for private-public or private-certificate pairs */ ++ uri.id = k11->keyid; ++ uri.id_len = k11->keyid_len; ++ uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label; ++ uri.object = k11->label; ++ 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 */ ++ if (p == NULL) ++ return -1; ++ ++ fprintf(f, " %s", p); ++ free(p); ++ return 0; ++} ++ + /* release a wrapped object */ + static void + pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, +@@ -208,6 +349,7 @@ pkcs11_k11_free(void *parent, void *ptr, + if (k11->provider) + pkcs11_provider_unref(k11->provider); + free(k11->keyid); ++ free(k11->label); + free(k11); + } + +@@ -222,8 +364,8 @@ pkcs11_find(struct pkcs11_provider *p, C + CK_RV rv; + int ret = -1; + +- f = p->function_list; +- session = p->slotinfo[slotidx].session; ++ f = p->module->function_list; ++ session = p->module->slotinfo[slotidx].session; + if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { + error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); + return (-1); +@@ -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 '%.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) { + debug_f("no pin specified"); + return (-1); /* bail out */ + } + } +- rv = provider->function_list->C_Login(si->session, type, (u_char *)pin, ++ rv = provider->module->function_list->C_Login(si->session, type, (u_char *)pin, + (pin != NULL) ? strlen(pin) : 0); + if (pin != NULL) + freezero(pin, strlen(pin)); +@@ -297,13 +439,14 @@ pkcs11_login_slot(struct pkcs11_provider + static int + pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type) + { +- if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) { ++ if (k11 == NULL || k11->provider == NULL || !k11->provider->valid || ++ k11->provider->module == NULL || !k11->provider->module->valid) { + error("no pkcs11 (valid) provider found"); + return (-1); + } + + return pkcs11_login_slot(k11->provider, +- &k11->provider->slotinfo[k11->slotidx], type); ++ &k11->provider->module->slotinfo[k11->slotidx], type); + } + + +@@ -319,13 +462,14 @@ pkcs11_check_obj_bool_attrib(struct pkcs + + *val = 0; + +- if (!k11->provider || !k11->provider->valid) { ++ if (!k11->provider || !k11->provider->valid || ++ !k11->provider->module || !k11->provider->module->valid) { + error("no pkcs11 (valid) provider found"); + return (-1); + } + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + + attr.type = type; + attr.pValue = &flag; +@@ -356,13 +500,14 @@ pkcs11_get_key(struct pkcs11_key *k11, C + int always_auth = 0; + int did_login = 0; + +- if (!k11->provider || !k11->provider->valid) { ++ if (!k11->provider || !k11->provider->valid || ++ !k11->provider->module || !k11->provider->module->valid) { + error("no pkcs11 (valid) provider found"); + return (-1); + } + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + + if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { + if (pkcs11_login(k11, CKU_USER) < 0) { +@@ -439,8 +584,8 @@ pkcs11_rsa_private_encrypt(int flen, con + return (-1); + } + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + tlen = RSA_size(rsa); + + /* XXX handle CKR_BUFFER_TOO_SMALL */ +@@ -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, +- CK_ATTRIBUTE *keyid_attrib, RSA *rsa) ++ CK_ATTRIBUTE *keyid_attrib, CK_ATTRIBUTE *label_attrib, RSA *rsa) + { + struct pkcs11_key *k11; + +@@ -502,6 +647,12 @@ pkcs11_rsa_wrap(struct pkcs11_provider * + 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; ++ } ++ + RSA_set_method(rsa, rsa_method); + RSA_set_ex_data(rsa, rsa_idx, k11); + return (0); +@@ -532,8 +683,8 @@ ecdsa_do_sign(const unsigned char *dgst, + return (NULL); + } + +- f = k11->provider->function_list; +- si = &k11->provider->slotinfo[k11->slotidx]; ++ f = k11->provider->module->function_list; ++ si = &k11->provider->module->slotinfo[k11->slotidx]; + + siglen = ECDSA_size(ec); + sig = xmalloc(siglen); +@@ -598,7 +749,7 @@ pkcs11_ecdsa_start_wrapper(void) + + static int + pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, +- CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec) ++ CK_ATTRIBUTE *keyid_attrib, CK_ATTRIBUTE *label_attrib, EC_KEY *ec) + { + struct pkcs11_key *k11; + +@@ -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); + +@@ -622,7 +779,8 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider + } + #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ + +-/* 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; + +- f = p->function_list; +- si = &p->slotinfo[slotidx]; ++ f = p->module->function_list; ++ si = &p->module->slotinfo[slotidx]; + + login_required = si->token.flags & CKF_LOGIN_REQUIRED; + +@@ -665,9 +823,9 @@ pkcs11_open_session(struct pkcs11_provid + error("pin required"); + return (-SSH_PKCS11_ERR_PIN_REQUIRED); + } +- if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| ++ if ((rv = f->C_OpenSession(p->module->slotlist[slotidx], CKF_RW_SESSION| + CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) { +- error("C_OpenSession failed: %lu", rv); ++ error("C_OpenSession failed for slot %lu: %lu", slotidx, rv); + return (-1); + } + if (login_required && pin != NULL && strlen(pin) != 0) { +@@ -703,7 +861,8 @@ static struct sshkey * + pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + CK_OBJECT_HANDLE *obj) + { +- CK_ATTRIBUTE key_attr[3]; ++ CK_ATTRIBUTE key_attr[4]; ++ int nattr = 4; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -717,14 +876,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ + + memset(&key_attr, 0, sizeof(key_attr)); + key_attr[0].type = CKA_ID; +- key_attr[1].type = CKA_EC_POINT; +- key_attr[2].type = CKA_EC_PARAMS; ++ key_attr[1].type = CKA_LABEL; ++ key_attr[2].type = CKA_EC_POINT; ++ key_attr[3].type = CKA_EC_PARAMS; + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; + + /* figure out size of the attributes */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return (NULL); +@@ -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. + */ +- if (key_attr[1].ulValueLen == 0 || +- key_attr[2].ulValueLen == 0) { ++ if (key_attr[2].ulValueLen == 0 || ++ key_attr[3].ulValueLen == 0) { + error("invalid attribute length"); + return (NULL); + } + + /* allocate buffers for attributes */ +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + if (key_attr[i].ulValueLen > 0) + key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); + + /* retrieve ID, public point and curve parameters of EC key */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + goto fail; +@@ -759,8 +919,8 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ + goto fail; + } + +- attrp = key_attr[2].pValue; +- group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen); ++ attrp = key_attr[3].pValue; ++ group = d2i_ECPKParameters(NULL, &attrp, key_attr[3].ulValueLen); + if (group == NULL) { + ossl_error("d2i_ECPKParameters failed"); + goto fail; +@@ -771,13 +931,13 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ + goto fail; + } + +- if (key_attr[1].ulValueLen <= 2) { ++ if (key_attr[2].ulValueLen <= 2) { + error("CKA_EC_POINT too small"); + goto fail; + } + +- attrp = key_attr[1].pValue; +- octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen); ++ attrp = key_attr[2].pValue; ++ octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[2].ulValueLen); + if (octet == NULL) { + ossl_error("d2i_ASN1_OCTET_STRING failed"); + goto fail; +@@ -794,7 +954,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ + goto fail; + } + +- if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec)) ++ if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], &key_attr[1], ec)) + goto fail; + + key = sshkey_new(KEY_UNSPEC); +@@ -810,7 +970,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ + ec = NULL; /* now owned by key */ + + fail: +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + free(key_attr[i].pValue); + if (ec) + EC_KEY_free(ec); +@@ -827,7 +987,8 @@ static struct sshkey * + pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + CK_OBJECT_HANDLE *obj) + { +- CK_ATTRIBUTE key_attr[3]; ++ CK_ATTRIBUTE key_attr[4]; ++ int nattr = 4; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -838,14 +999,15 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr + + memset(&key_attr, 0, sizeof(key_attr)); + key_attr[0].type = CKA_ID; +- key_attr[1].type = CKA_MODULUS; +- key_attr[2].type = CKA_PUBLIC_EXPONENT; ++ key_attr[1].type = CKA_LABEL; ++ key_attr[2].type = CKA_MODULUS; ++ key_attr[3].type = CKA_PUBLIC_EXPONENT; + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; + + /* figure out size of the attributes */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return (NULL); +@@ -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. + */ +- if (key_attr[1].ulValueLen == 0 || +- key_attr[2].ulValueLen == 0) { ++ if (key_attr[2].ulValueLen == 0 || ++ key_attr[3].ulValueLen == 0) { + error("invalid attribute length"); + return (NULL); + } + + /* allocate buffers for attributes */ +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + if (key_attr[i].ulValueLen > 0) + key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); + + /* retrieve ID, modulus and public exponent of RSA key */ +- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + goto fail; +@@ -880,8 +1042,8 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr + goto fail; + } + +- rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL); +- rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL); ++ rsa_n = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL); ++ rsa_e = BN_bin2bn(key_attr[3].pValue, key_attr[3].ulValueLen, NULL); + if (rsa_n == NULL || rsa_e == NULL) { + error("BN_bin2bn failed"); + goto fail; +@@ -890,7 +1052,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr + fatal_f("set key"); + rsa_n = rsa_e = NULL; /* transferred */ + +- if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa)) ++ if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], &key_attr[1], rsa)) + goto fail; + + key = sshkey_new(KEY_UNSPEC); +@@ -905,7 +1067,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr + rsa = NULL; /* now owned by key */ + + fail: +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + free(key_attr[i].pValue); + RSA_free(rsa); + +@@ -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) + { +- CK_ATTRIBUTE cert_attr[3]; ++ CK_ATTRIBUTE cert_attr[4]; ++ int nattr = 4; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -940,14 +1103,15 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p + + memset(&cert_attr, 0, sizeof(cert_attr)); + cert_attr[0].type = CKA_ID; +- cert_attr[1].type = CKA_SUBJECT; +- cert_attr[2].type = CKA_VALUE; ++ cert_attr[1].type = CKA_LABEL; ++ cert_attr[2].type = CKA_SUBJECT; ++ cert_attr[3].type = CKA_VALUE; + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ session = p->module->slotinfo[slotidx].session; ++ f = p->module->function_list; + + /* figure out size of the attributes */ +- rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, cert_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + return -1; +@@ -959,18 +1123,19 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p + * XXX assumes CKA_ID is always first. + */ + if (cert_attr[1].ulValueLen == 0 || +- cert_attr[2].ulValueLen == 0) { ++ cert_attr[2].ulValueLen == 0 || ++ cert_attr[3].ulValueLen == 0) { + error("invalid attribute length"); + return -1; + } + + /* allocate buffers for attributes */ +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + if (cert_attr[i].ulValueLen > 0) + cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen); + + /* retrieve ID, subject and value of certificate */ +- rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3); ++ rv = f->C_GetAttributeValue(session, *obj, cert_attr, nattr); + if (rv != CKR_OK) { + error("C_GetAttributeValue failed: %lu", rv); + goto out; +@@ -984,8 +1149,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p + subject = xstrdup("invalid subject"); + X509_NAME_free(x509_name); + +- cp = cert_attr[2].pValue; +- if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) { ++ cp = cert_attr[3].pValue; ++ if ((x509 = d2i_X509(NULL, &cp, cert_attr[3].ulValueLen)) == NULL) { + error("d2i_x509 failed"); + goto out; + } +@@ -1005,7 +1170,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p + goto out; + } + +- if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa)) ++ if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], &cert_attr[1], rsa)) + goto out; + + key = sshkey_new(KEY_UNSPEC); +@@ -1035,7 +1200,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p + goto out; + } + +- if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec)) ++ if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], &cert_attr[1], ec)) + goto out; + + key = sshkey_new(KEY_UNSPEC); +@@ -1055,7 +1220,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p + goto out; + } + out: +- for (i = 0; i < 3; i++) ++ for (i = 0; i < nattr; i++) + free(cert_attr[i].pValue); + X509_free(x509); + RSA_free(rsa); +@@ -1106,11 +1271,12 @@ note_key(struct pkcs11_provider *p, CK_U + */ + static int + pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, +- struct sshkey ***keysp, char ***labelsp, int *nkeys) ++ struct sshkey ***keysp, char ***labelsp, int *nkeys, struct pkcs11_uri *uri) + { + struct sshkey *key = NULL; + CK_OBJECT_CLASS key_class; +- CK_ATTRIBUTE key_attr[1]; ++ CK_ATTRIBUTE key_attr[3]; ++ int nattr = 1; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -1127,10 +1293,23 @@ pkcs11_fetch_certs(struct pkcs11_provide + key_attr[0].pValue = &key_class; + key_attr[0].ulValueLen = sizeof(key_class); + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ if (uri->id != NULL) { ++ key_attr[nattr].type = CKA_ID; ++ key_attr[nattr].pValue = uri->id; ++ key_attr[nattr].ulValueLen = uri->id_len; ++ nattr++; ++ } ++ if (uri->object != NULL) { ++ key_attr[nattr].type = CKA_LABEL; ++ key_attr[nattr].pValue = uri->object; ++ 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, nattr); + if (rv != CKR_OK) { + error("C_FindObjectsInit failed: %lu", rv); + goto fail; +@@ -1211,11 +1390,12 @@ fail: + */ + static int + pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, +- struct sshkey ***keysp, char ***labelsp, int *nkeys) ++ struct sshkey ***keysp, char ***labelsp, int *nkeys, struct pkcs11_uri *uri) + { + struct sshkey *key = NULL; + CK_OBJECT_CLASS key_class; +- CK_ATTRIBUTE key_attr[2]; ++ CK_ATTRIBUTE key_attr[3]; ++ int nattr = 1; + CK_SESSION_HANDLE session; + CK_FUNCTION_LIST *f = NULL; + CK_RV rv; +@@ -1231,10 +1411,23 @@ pkcs11_fetch_keys(struct pkcs11_provider + key_attr[0].pValue = &key_class; + key_attr[0].ulValueLen = sizeof(key_class); + +- session = p->slotinfo[slotidx].session; +- f = p->function_list; ++ if (uri->id != NULL) { ++ key_attr[nattr].type = CKA_ID; ++ key_attr[nattr].pValue = uri->id; ++ key_attr[nattr].ulValueLen = uri->id_len; ++ nattr++; ++ } ++ if (uri->object != NULL) { ++ key_attr[nattr].type = CKA_LABEL; ++ key_attr[nattr].pValue = uri->object; ++ 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); ++ rv = f->C_FindObjectsInit(session, key_attr, nattr); + if (rv != CKR_OK) { + error("C_FindObjectsInit failed: %lu", rv); + goto fail; +@@ -1503,16 +1696,10 @@ pkcs11_ecdsa_generate_private_key(struct + } + #endif /* WITH_PKCS11_KEYGEN */ + +-/* +- * register a new provider, fails if provider already exists. if +- * keyp is provided, fetch keys. +- */ + static int +-pkcs11_register_provider(char *provider_id, char *pin, +- struct sshkey ***keyp, char ***labelsp, +- struct pkcs11_provider **providerp, CK_ULONG user) ++pkcs11_initialize_provider(struct pkcs11_uri *uri, struct pkcs11_provider **providerp) + { +- int nkeys, need_finalize = 0; ++ int need_finalize = 0; + int ret = -1; + struct pkcs11_provider *p = NULL; + void *handle = NULL; +@@ -1521,162 +1708,309 @@ pkcs11_register_provider(char *provider_ + CK_FUNCTION_LIST *f = NULL; + CK_TOKEN_INFO *token; + CK_ULONG i; ++ char *provider_module = NULL; ++ 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; ++#endif ++ } else { ++ provider_module = strdup(uri->module_path); ++ } ++ 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) { ++ debug_f("provider module already initialized: %s", provider_module); ++ free(provider_module); ++ /* Skip the initialization of PKCS#11 module */ ++ m->refcount++; ++ p->module = m; ++ p->valid = 1; ++ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); ++ p->refcount++; /* add to provider list */ ++ *providerp = p; ++ return 0; ++ } else { ++ m = xcalloc(1, sizeof(*m)); ++ p->module = m; ++ m->refcount++; + } ++ + /* open shared pkcs11-library */ +- if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { +- error("dlopen %s failed: %s", provider_id, dlerror()); ++ if ((handle = dlopen(provider_module, RTLD_NOW)) == NULL) { ++ error("dlopen %s failed: %s", provider_module, 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) { + error("C_GetFunctionList for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } +- p->function_list = f; ++ m->function_list = f; + if ((rv = f->C_Initialize(NULL)) != CKR_OK) { + error("C_Initialize for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } + need_finalize = 1; +- if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) { ++ if ((rv = f->C_GetInfo(&m->info)) != CKR_OK) { + error("C_GetInfo for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + goto fail; + } +- debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d" +- " libraryDescription <%.*s> libraryVersion %d.%d", +- provider_id, +- RMSPACE(p->info.manufacturerID), +- p->info.cryptokiVersion.major, +- p->info.cryptokiVersion.minor, +- 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, ++ m->info.cryptokiVersion.minor, ++ m->info.libraryDescription, ++ m->info.libraryVersion.major, ++ m->info.libraryVersion.minor); ++ ++ if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &m->nslots)) != CKR_OK) { + error("C_GetSlotList failed: %lu", rv); + goto fail; + } +- if (p->nslots == 0) { +- debug_f("provider %s returned no slots", provider_id); ++ if (m->nslots == 0) { ++ debug_f("provider %s returned no slots", provider_module); + ret = -SSH_PKCS11_ERR_NO_SLOTS; + goto fail; + } +- p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); +- if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) ++ m->slotlist = xcalloc(m->nslots, sizeof(CK_SLOT_ID)); ++ if ((rv = f->C_GetSlotList(CK_TRUE, m->slotlist, &m->nslots)) + != CKR_OK) { + error("C_GetSlotList for provider %s failed: %lu", +- provider_id, rv); ++ provider_module, rv); + 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->valid = 1; ++ for (i = 0; i < m->nslots; i++) { ++ token = &m->slotinfo[i].token; ++ if ((rv = f->C_GetTokenInfo(m->slotlist[i], token)) + != CKR_OK) { + error("C_GetTokenInfo for provider %s slot %lu " +- "failed: %lu", provider_id, (u_long)i, rv); +- continue; +- } +- if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { +- debug2_f("ignoring uninitialised token in " +- "provider %s slot %lu", provider_id, (u_long)i); ++ "failed: %lu", provider_module, (u_long)i, rv); ++ token->flags = 0; + continue; + } + 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; ++ ++ /* now owned by caller */ ++ *providerp = p; ++ ++ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); ++ p->refcount++; /* add to provider list */ ++ ++ return 0; ++fail: ++ if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) ++ error("C_Finalize for provider %s failed: %lu", ++ provider_module, rv); ++ free(provider_module); ++ if (m) { ++ free(m->slotlist); ++ free(m); ++ } ++ if (p) { ++ free(p->name); ++ free(p); ++ } ++ if (handle) ++ dlclose(handle); ++ return (ret); ++} ++ ++/* ++ * register a new provider, fails if provider already exists. if ++ * keyp is provided, fetch keys. ++ */ ++static int ++pkcs11_register_provider_by_uri(struct pkcs11_uri *uri, char *pin, ++ struct sshkey ***keyp, char ***labelsp, struct pkcs11_provider **providerp, ++ CK_ULONG user) ++{ ++ int nkeys; ++ int ret = -1; ++ struct pkcs11_provider *p = NULL; ++ CK_ULONG i; ++ CK_TOKEN_INFO *token; ++ char *provider_uri = NULL; ++ ++ if (providerp == NULL) ++ goto fail; ++ *providerp = NULL; ++ ++ if (keyp != NULL) ++ *keyp = NULL; ++ ++ if ((ret = pkcs11_initialize_provider(uri, &p)) != 0) { ++ goto fail; ++ } ++ ++ provider_uri = pkcs11_uri_get(uri); ++ if (pin == NULL && uri->pin != NULL) { ++ pin = uri->pin; ++ } ++ nkeys = 0; ++ for (i = 0; i < p->module->nslots; i++) { ++ token = &p->module->slotinfo[i].token; ++ if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { ++ debug2_f("ignoring uninitialised token in " ++ "provider %s slot %lu", provider_uri, (u_long)i); ++ continue; ++ } ++ if (uri->token != NULL && ++ 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 && ++ strncmp(token->manufacturerID, uri->manuf, 32) != 0) { ++ debug2_f("ignoring token not matching requrested " ++ "manufacturerID (%.32s) specified by PKCS#11 URI in " ++ "slot %lu", token->manufacturerID, (unsigned long)i); ++ continue; ++ } ++ 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); + /* +- * open session, login with pin and retrieve public +- * keys (if keyp is provided) ++ * 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 || ++ if ((p->module->slotinfo[i].session != 0 || ++ (ret = pkcs11_open_session(p, i, pin, user)) != 0) && /* ??? */ + keyp == NULL) + continue; +- pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); +- pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); +- if (nkeys == 0 && !p->slotinfo[i].logged_in && ++ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); ++ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); ++ if (nkeys == 0 && !p->module->slotinfo[i].logged_in && + pkcs11_interactive) { + /* + * Some tokens require login before they will + * expose keys. + */ +- if (pkcs11_login_slot(p, &p->slotinfo[i], ++ debug3_f("Trying to login as there were no keys found"); ++ if (pkcs11_login_slot(p, &p->module->slotinfo[i], + CKU_USER) < 0) { + error("login failed"); + continue; + } +- pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); +- pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); ++ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); ++ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); ++ } ++ if (nkeys == 0 && uri->object != NULL) { ++ debug3_f("No keys found. Retrying without label (%.32s) ", ++ uri->object); ++ /* Try once more without the label filter */ ++ char *label = uri->object; ++ uri->object = NULL; /* XXX clone uri? */ ++ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); ++ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); ++ uri->object = label; + } + } ++ pin = NULL; /* Will be cleaned up with URI */ + + /* now owned by caller */ + *providerp = p; + +- TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); +- p->refcount++; /* add to provider list */ +- ++ free(provider_uri); + return (nkeys); + fail: +- if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) +- error("C_Finalize for provider %s failed: %lu", +- provider_id, rv); + if (p) { +- free(p->name); +- free(p->slotlist); +- free(p->slotinfo); +- free(p); ++ TAILQ_REMOVE(&pkcs11_providers, p, next); ++ pkcs11_provider_unref(p); + } +- if (handle) +- dlclose(handle); + if (ret > 0) + ret = -1; + return (ret); + } + +-/* +- * register a new provider and get number of keys hold by the token, +- * fails if provider already exists +- */ ++static int ++pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp, ++ char ***labelsp, struct pkcs11_provider **providerp, CK_ULONG user) ++{ ++ struct pkcs11_uri *uri = NULL; ++ int r; ++ ++ debug_f("called, provider_id = %s", provider_id); ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("failed to init PKCS#11 URI"); ++ ++ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { ++ if (pkcs11_uri_parse(provider_id, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI"); ++ } else { ++ uri->module_path = strdup(provider_id); ++ } ++ ++ r = pkcs11_register_provider_by_uri(uri, pin, keyp, labelsp, providerp, user); ++ pkcs11_uri_cleanup(uri); ++ ++ return r; ++} ++ + int +-pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp, +- char ***labelsp) ++pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, ++ struct sshkey ***keyp, char ***labelsp) + { + struct pkcs11_provider *p = NULL; + int nkeys; ++ char *provider_uri = pkcs11_uri_get(uri); ++ ++ debug_f("called, provider_uri = %s", provider_uri); + +- nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp, +- &p, CKU_USER); ++ nkeys = pkcs11_register_provider_by_uri(uri, pin, keyp, labelsp, &p, CKU_USER); + + /* no keys found or some other error, de-register provider */ + if (nkeys <= 0 && p != NULL) { +@@ -1685,7 +2019,37 @@ pkcs11_add_provider(char *provider_id, c + pkcs11_provider_unref(p); + } + if (nkeys == 0) +- debug_f("provider %s returned no keys", provider_id); ++ debug_f("provider %s returned no keys", provider_uri); ++ ++ free(provider_uri); ++ return nkeys; ++} ++ ++/* ++ * register a new provider and get number of keys hold by the token, ++ * fails if provider already exists ++ */ ++int ++pkcs11_add_provider(char *provider_id, char *pin, ++ struct sshkey ***keyp, char ***labelsp) ++{ ++ struct pkcs11_uri *uri; ++ int nkeys; ++ ++ uri = pkcs11_uri_init(); ++ if (uri == NULL) ++ fatal("Failed to init PKCS#11 URI"); ++ ++ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && ++ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { ++ if (pkcs11_uri_parse(provider_id, uri) != 0) ++ fatal("Failed to parse PKCS#11 URI"); ++ } else { ++ uri->module_path = strdup(provider_id); ++ } ++ ++ nkeys = pkcs11_add_provider_by_uri(uri, pin, keyp, labelsp); ++ pkcs11_uri_cleanup(uri); + + return (nkeys); + } +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 + ++#include "ssh-pkcs11-uri.h" ++ + int pkcs11_init(int); + void pkcs11_terminate(void); + int pkcs11_add_provider(char *, char *, struct sshkey ***, char ***); ++int pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***, char ***); + int pkcs11_del_provider(char *); ++int pkcs11_uri_write(const struct sshkey *, FILE *); + #ifdef WITH_PKCS11_KEYGEN + struct sshkey * + pkcs11_gakp(char *, char *, unsigned int, char *, unsigned int, +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 @@ -1699,11 +3067,9 @@ index 000000000..8bd97e9e2 +} + +#endif /* ENABLE_PKCS11 */ -diff --git a/ssh-pkcs11-uri.h b/ssh-pkcs11-uri.h -new file mode 100644 -index 000000000..29e9f7327 ---- /dev/null -+++ b/ssh-pkcs11-uri.h +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 @@ -1748,1506 +3114,3 @@ index 000000000..29e9f7327 +struct pkcs11_uri *pkcs11_uri_init(); +char *pkcs11_uri_get(struct pkcs11_uri *uri); + -diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c -index c88179473..1a443824d 100644 ---- a/ssh-pkcs11.c -+++ b/ssh-pkcs11.c -@@ -39,6 +39,7 @@ - #include - #include - #include -+#include - #endif - - #define CRYPTOKI_COMPAT -@@ -51,6 +52,7 @@ - #include "misc.h" - #include "sshbuf.h" - #include "ssh-pkcs11.h" -+#include "ssh-pkcs11-uri.h" - #include "digest.h" - #include "xmalloc.h" - #include "crypto_api.h" -@@ -61,8 +63,8 @@ struct pkcs11_slotinfo { - int logged_in; - }; - --struct pkcs11_provider { -- char *name; -+struct pkcs11_module { -+ char *module_path; - void *handle; - CK_FUNCTION_LIST *function_list; - CK_INFO info; -@@ -71,6 +73,13 @@ struct pkcs11_provider { - struct pkcs11_slotinfo *slotinfo; - int valid; - int refcount; -+}; -+ -+struct pkcs11_provider { -+ char *name; -+ struct pkcs11_module *module; /* can be shared between various providers */ -+ int refcount; -+ int valid; - TAILQ_ENTRY(pkcs11_provider) next; - }; - -@@ -82,6 +91,7 @@ struct pkcs11_key { - CK_ULONG slotidx; - char *keyid; - int keyid_len; -+ char *label; - TAILQ_ENTRY(pkcs11_key) next; - }; - -@@ -108,26 +118,61 @@ ossl_error(const char *msg) - * this is called when a provider gets unregistered. - */ - static void --pkcs11_provider_finalize(struct pkcs11_provider *p) -+pkcs11_module_finalize(struct pkcs11_module *m) - { - CK_RV rv; - CK_ULONG i; - -- debug_f("provider \"%s\" refcount %d valid %d", -- p->name, p->refcount, p->valid); -- if (!p->valid) -+ debug_f("%p refcount %d valid %d", m, m->refcount, m->valid); -+ if (!m->valid) - return; -- for (i = 0; i < p->nslots; i++) { -- if (p->slotinfo[i].session && -- (rv = p->function_list->C_CloseSession( -- p->slotinfo[i].session)) != CKR_OK) -+ for (i = 0; i < m->nslots; i++) { -+ if (m->slotinfo[i].session && -+ (rv = m->function_list->C_CloseSession( -+ m->slotinfo[i].session)) != CKR_OK) - error("C_CloseSession failed: %lu", rv); - } -- if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK) -+ if ((rv = m->function_list->C_Finalize(NULL)) != CKR_OK) - error("C_Finalize failed: %lu", rv); -+ m->valid = 0; -+ m->function_list = NULL; -+ dlclose(m->handle); -+} -+ -+/* -+ * remove a reference to the pkcs11 module. -+ * called when a provider is unregistered. -+ */ -+static void -+pkcs11_module_unref(struct pkcs11_module *m) -+{ -+ debug_f("%p refcount %d", m, m->refcount); -+ if (--m->refcount <= 0) { -+ pkcs11_module_finalize(m); -+ if (m->valid) -+ error_f("%p still valid", m); -+ free(m->slotlist); -+ free(m->slotinfo); -+ free(m->module_path); -+ free(m); -+ } -+} -+ -+/* -+ * finalize a provider shared library, it's no longer usable. -+ * however, there might still be keys referencing this provider, -+ * so the actual freeing of memory is handled by pkcs11_provider_unref(). -+ * this is called when a provider gets unregistered. -+ */ -+static void -+pkcs11_provider_finalize(struct pkcs11_provider *p) -+{ -+ debug_f("%p refcount %d valid %d", p, p->refcount, p->valid); -+ if (!p->valid) -+ return; -+ pkcs11_module_unref(p->module); -+ p->module = NULL; - p->valid = 0; -- p->function_list = NULL; -- dlclose(p->handle); - } - - /* -@@ -139,15 +184,27 @@ pkcs11_provider_unref(struct pkcs11_provider *p) - { - debug_f("provider \"%s\" refcount %d", p->name, p->refcount); - if (--p->refcount <= 0) { -- if (p->valid) -- error_f("provider \"%s\" still valid", p->name); - free(p->name); -- free(p->slotlist); -- free(p->slotinfo); -+ if (p->module) -+ pkcs11_module_unref(p->module); - free(p); - } - } - -+/* lookup provider by module path */ -+static struct pkcs11_module * -+pkcs11_provider_lookup_module(char *module_path) -+{ -+ struct pkcs11_provider *p; -+ -+ TAILQ_FOREACH(p, &pkcs11_providers, next) { -+ debug("check %p %s (%s)", p, p->name, p->module->module_path); -+ if (!strcmp(module_path, p->module->module_path)) -+ return (p->module); -+ } -+ return (NULL); -+} -+ - /* lookup provider by name */ - static struct pkcs11_provider * - pkcs11_provider_lookup(char *provider_id) -@@ -162,19 +219,55 @@ pkcs11_provider_lookup(char *provider_id) - return (NULL); - } - -+int pkcs11_del_provider_by_uri(struct pkcs11_uri *); -+ - /* unregister provider by name */ - int - pkcs11_del_provider(char *provider_id) -+{ -+ int rv; -+ struct pkcs11_uri *uri; -+ -+ debug_f("called, provider_id = %s", provider_id); -+ -+ if (provider_id == NULL) -+ return 0; -+ -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("Failed to init PKCS#11 URI"); -+ -+ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { -+ if (pkcs11_uri_parse(provider_id, uri) != 0) -+ fatal("Failed to parse PKCS#11 URI"); -+ } else { -+ uri->module_path = strdup(provider_id); -+ } -+ -+ rv = pkcs11_del_provider_by_uri(uri); -+ pkcs11_uri_cleanup(uri); -+ return rv; -+} -+ -+/* unregister provider by PKCS#11 URI */ -+int -+pkcs11_del_provider_by_uri(struct pkcs11_uri *uri) - { - struct pkcs11_provider *p; -+ int rv = -1; -+ char *provider_uri = pkcs11_uri_get(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); - pkcs11_provider_unref(p); -- return (0); -+ rv = 0; - } -- return (-1); -+ free(provider_uri); -+ return rv; - } - - /* release a wrapped object */ -@@ -186,6 +279,7 @@ pkcs11_k11_free(struct pkcs11_key *k11) - if (k11->provider) - pkcs11_provider_unref(k11->provider); - free(k11->keyid); -+ free(k11->label); - sshbuf_free(k11->keyblob); - free(k11); - } -@@ -201,8 +295,8 @@ pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr, - CK_RV rv; - int ret = -1; - -- f = p->function_list; -- session = p->slotinfo[slotidx].session; -+ f = p->module->function_list; -+ session = p->module->slotinfo[slotidx].session; - if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) { - error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv); - return (-1); -@@ -239,14 +333,14 @@ pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si, - 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 '%.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) { - debug_f("no pin specified"); - return (-1); /* bail out */ - } - } -- rv = provider->function_list->C_Login(si->session, type, (u_char *)pin, -+ rv = provider->module->function_list->C_Login(si->session, type, (u_char *)pin, - (pin != NULL) ? strlen(pin) : 0); - if (pin != NULL) - freezero(pin, strlen(pin)); -@@ -276,13 +370,14 @@ pkcs11_login_slot(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si, - static int - pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type) - { -- if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) { -+ if (k11 == NULL || k11->provider == NULL || !k11->provider->valid || -+ k11->provider->module == NULL || !k11->provider->module->valid) { - error("no pkcs11 (valid) provider found"); - return (-1); - } - - return pkcs11_login_slot(k11->provider, -- &k11->provider->slotinfo[k11->slotidx], type); -+ &k11->provider->module->slotinfo[k11->slotidx], type); - } - - -@@ -298,13 +393,14 @@ pkcs11_check_obj_bool_attrib(struct pkcs11_key *k11, CK_OBJECT_HANDLE obj, - - *val = 0; - -- if (!k11->provider || !k11->provider->valid) { -+ if (!k11->provider || !k11->provider->valid || -+ !k11->provider->module || !k11->provider->module->valid) { - error("no pkcs11 (valid) provider found"); - return (-1); - } - -- f = k11->provider->function_list; -- si = &k11->provider->slotinfo[k11->slotidx]; -+ f = k11->provider->module->function_list; -+ si = &k11->provider->module->slotinfo[k11->slotidx]; - - attr.type = type; - attr.pValue = &flag; -@@ -335,13 +431,14 @@ pkcs11_get_key(struct pkcs11_key *k11, CK_MECHANISM_TYPE mech_type) - int always_auth = 0; - int did_login = 0; - -- if (!k11->provider || !k11->provider->valid) { -+ if (!k11->provider || !k11->provider->valid || -+ !k11->provider->module || !k11->provider->module->valid) { - error("no pkcs11 (valid) provider found"); - return (-1); - } - -- f = k11->provider->function_list; -- si = &k11->provider->slotinfo[k11->slotidx]; -+ f = k11->provider->module->function_list; -+ si = &k11->provider->module->slotinfo[k11->slotidx]; - - if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) { - if (pkcs11_login(k11, CKU_USER) < 0) { -@@ -440,6 +537,12 @@ pkcs11_record_key(struct pkcs11_provider *provider, CK_ULONG slotidx, - k11->keyid = xmalloc(k11->keyid_len); - memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); - } -+ if (keyid_attrib->ulValueLen > 0 ) { -+ k11->label = xmalloc(keyid_attrib->ulValueLen+1); -+ memcpy(k11->label, keyid_attrib->pValue, keyid_attrib->ulValueLen); -+ k11->label[keyid_attrib->ulValueLen] = 0; -+ } -+ - TAILQ_INSERT_TAIL(&pkcs11_keys, k11, next); - - return 0; -@@ -467,6 +570,42 @@ pkcs11_lookup_key(struct sshkey *key) - return found; - } - -+/* -+ * This can't be in the ssh-pkcs11-uri, becase we can not depend on -+ * PKCS#11 structures in ssh-agent (using client-helper communication) -+ */ -+int -+pkcs11_uri_write(const struct sshkey *key, FILE *f) -+{ -+ char *p = NULL; -+ struct pkcs11_uri uri; -+ struct pkcs11_key *k11 = pkcs11_lookup_key(key); -+ -+ if (k11 == NULL) { -+ error("Failed to get ex_data for key type %d", key->type); -+ return (-1); -+ } -+ -+ /* omit type -- we are looking for private-public or private-certificate pairs */ -+ uri.id = k11->keyid; -+ uri.id_len = k11->keyid_len; -+ uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label; -+ uri.object = k11->label; -+ 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 */ -+ if (p == NULL) -+ return -1; -+ -+ fprintf(f, " %s", p); -+ free(p); -+ return 0; -+} -+ - #ifdef WITH_OPENSSL - /* - * See: -@@ -571,8 +710,8 @@ pkcs11_sign_rsa(struct sshkey *key, - return SSH_ERR_AGENT_FAILURE; - } - -- f = k11->provider->function_list; -- si = &k11->provider->slotinfo[k11->slotidx]; -+ f = k11->provider->module->function_list; -+ si = &k11->provider->module->slotinfo[k11->slotidx]; - - if ((siglen = EVP_PKEY_size(key->pkey)) <= 0) - return SSH_ERR_INVALID_ARGUMENT; -@@ -661,8 +800,8 @@ pkcs11_sign_ecdsa(struct sshkey *key, - debug3_f("sign using provider %s slotidx %lu", - k11->provider->name, (u_long)k11->slotidx); - -- f = k11->provider->function_list; -- si = &k11->provider->slotinfo[k11->slotidx]; -+ f = k11->provider->module->function_list; -+ si = &k11->provider->module->slotinfo[k11->slotidx]; - - /* Prepare digest to be signed */ - if ((hashalg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) -@@ -746,8 +885,8 @@ pkcs11_sign_ed25519(struct sshkey *key, - debug3_f("sign using provider %s slotidx %lu", - k11->provider->name, (u_long)k11->slotidx); - -- f = k11->provider->function_list; -- si = &k11->provider->slotinfo[k11->slotidx]; -+ f = k11->provider->module->function_list; -+ si = &k11->provider->module->slotinfo[k11->slotidx]; - - xdata = xmalloc(datalen); - memcpy(xdata, data, datalen); -@@ -775,7 +914,8 @@ pkcs11_sign_ed25519(struct sshkey *key, - return ret; - } - --/* 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) - { -@@ -807,8 +947,8 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin, - CK_SESSION_HANDLE session; - int login_required, ret; - -- f = p->function_list; -- si = &p->slotinfo[slotidx]; -+ f = p->module->function_list; -+ si = &p->module->slotinfo[slotidx]; - - login_required = si->token.flags & CKF_LOGIN_REQUIRED; - -@@ -818,9 +958,9 @@ pkcs11_open_session(struct pkcs11_provider *p, CK_ULONG slotidx, char *pin, - error("pin required"); - return (-SSH_PKCS11_ERR_PIN_REQUIRED); - } -- if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION| -+ if ((rv = f->C_OpenSession(p->module->slotlist[slotidx], CKF_RW_SESSION| - CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) { -- error("C_OpenSession failed: %lu", rv); -+ error("C_OpenSession failed for slot %lu: %lu", slotidx, rv); - return (-1); - } - if (login_required && pin != NULL && strlen(pin) != 0) { -@@ -857,7 +997,8 @@ static struct sshkey * - pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - CK_OBJECT_HANDLE *obj) - { -- CK_ATTRIBUTE key_attr[3]; -+ CK_ATTRIBUTE key_attr[4]; -+ int nattr = 4; - CK_SESSION_HANDLE session; - CK_FUNCTION_LIST *f = NULL; - CK_RV rv; -@@ -870,14 +1011,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - - memset(&key_attr, 0, sizeof(key_attr)); - key_attr[0].type = CKA_ID; -- key_attr[1].type = CKA_EC_POINT; -- key_attr[2].type = CKA_EC_PARAMS; -+ key_attr[1].type = CKA_LABEL; -+ key_attr[2].type = CKA_EC_POINT; -+ key_attr[3].type = CKA_EC_PARAMS; - -- session = p->slotinfo[slotidx].session; -- f = p->function_list; -+ session = p->module->slotinfo[slotidx].session; -+ f = p->module->function_list; - - /* figure out size of the attributes */ -- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); -+ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); - if (rv != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - return (NULL); -@@ -888,19 +1030,19 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - * ensure that none of the others are zero length. - * XXX assumes CKA_ID is always first. - */ -- if (key_attr[1].ulValueLen == 0 || -- key_attr[2].ulValueLen == 0) { -+ if (key_attr[2].ulValueLen == 0 || -+ key_attr[3].ulValueLen == 0) { - error("invalid attribute length"); - return (NULL); - } - - /* allocate buffers for attributes */ -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattr; i++) - if (key_attr[i].ulValueLen > 0) - key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); - - /* retrieve ID, public point and curve parameters of EC key */ -- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); -+ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); - if (rv != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - goto fail; -@@ -912,8 +1054,8 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - goto fail; - } - -- attrp = key_attr[2].pValue; -- group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen); -+ attrp = key_attr[3].pValue; -+ group = d2i_ECPKParameters(NULL, &attrp, key_attr[3].ulValueLen); - if (group == NULL) { - ossl_error("d2i_ECPKParameters failed"); - goto fail; -@@ -924,13 +1066,13 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - goto fail; - } - -- if (key_attr[1].ulValueLen <= 2) { -+ if (key_attr[2].ulValueLen <= 2) { - error("CKA_EC_POINT too small"); - goto fail; - } - -- attrp = key_attr[1].pValue; -- octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen); -+ attrp = key_attr[2].pValue; -+ octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[2].ulValueLen); - if (octet == NULL) { - ossl_error("d2i_ASN1_OCTET_STRING failed"); - goto fail; -@@ -992,7 +1134,8 @@ static struct sshkey * - pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - CK_OBJECT_HANDLE *obj) - { -- CK_ATTRIBUTE key_attr[3]; -+ CK_ATTRIBUTE key_attr[4]; -+ int nattr = 4; - CK_SESSION_HANDLE session; - CK_FUNCTION_LIST *f = NULL; - CK_RV rv; -@@ -1003,14 +1146,15 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - - memset(&key_attr, 0, sizeof(key_attr)); - key_attr[0].type = CKA_ID; -- key_attr[1].type = CKA_MODULUS; -- key_attr[2].type = CKA_PUBLIC_EXPONENT; -+ key_attr[1].type = CKA_LABEL; -+ key_attr[2].type = CKA_MODULUS; -+ key_attr[3].type = CKA_PUBLIC_EXPONENT; - -- session = p->slotinfo[slotidx].session; -- f = p->function_list; -+ session = p->module->slotinfo[slotidx].session; -+ f = p->module->function_list; - - /* figure out size of the attributes */ -- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); -+ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); - if (rv != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - return (NULL); -@@ -1021,19 +1165,19 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - * ensure that none of the others are zero length. - * XXX assumes CKA_ID is always first. - */ -- if (key_attr[1].ulValueLen == 0 || -- key_attr[2].ulValueLen == 0) { -+ if (key_attr[2].ulValueLen == 0 || -+ key_attr[3].ulValueLen == 0) { - error("invalid attribute length"); - return (NULL); - } - - /* allocate buffers for attributes */ -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattr; i++) - if (key_attr[i].ulValueLen > 0) - key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); - - /* retrieve ID, modulus and public exponent of RSA key */ -- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); -+ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); - if (rv != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - goto fail; -@@ -1045,8 +1189,8 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - goto fail; - } - -- rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL); -- rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL); -+ rsa_n = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL); -+ rsa_e = BN_bin2bn(key_attr[3].pValue, key_attr[3].ulValueLen, NULL); - if (rsa_n == NULL || rsa_e == NULL) { - error("BN_bin2bn failed"); - goto fail; -@@ -1078,7 +1222,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - /* success */ - success = 0; - fail: -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattr; i++) - free(key_attr[i].pValue); - RSA_free(rsa); - if (success != 0) { -@@ -1093,7 +1237,8 @@ static struct sshkey * - pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - CK_OBJECT_HANDLE *obj) - { -- CK_ATTRIBUTE key_attr[3]; -+ CK_ATTRIBUTE key_attr[4]; -+ int nattr = 4; - CK_SESSION_HANDLE session; - CK_FUNCTION_LIST *f = NULL; - CK_RV rv; -@@ -1113,14 +1258,15 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - - memset(&key_attr, 0, sizeof(key_attr)); - key_attr[0].type = CKA_ID; -- key_attr[1].type = CKA_EC_POINT; /* XXX or CKA_VALUE ? */ -- key_attr[2].type = CKA_EC_PARAMS; -+ key_attr[1].type = CKA_LABEL; -+ key_attr[2].type = CKA_EC_POINT; /* XXX or CKA_VALUE ? */ -+ key_attr[3].type = CKA_EC_PARAMS; - -- session = p->slotinfo[slotidx].session; -- f = p->function_list; -+ session = p->module->slotinfo[slotidx].session; -+ f = p->module->function_list; - - /* figure out size of the attributes */ -- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); -+ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); - if (rv != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - return (NULL); -@@ -1131,28 +1277,28 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - * ensure that none of the others are zero length. - * XXX assumes CKA_ID is always first. - */ -- if (key_attr[1].ulValueLen == 0 || -- key_attr[2].ulValueLen == 0) { -+ if (key_attr[2].ulValueLen == 0 || -+ key_attr[3].ulValueLen == 0) { - error("invalid attribute length"); - return (NULL); - } - - /* allocate buffers for attributes */ -- for (i = 0; i < 3; i++) { -+ for (i = 0; i < nattr; i++) { - if (key_attr[i].ulValueLen > 0) - key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen); - } - - /* retrieve ID, public point and curve parameters of EC key */ -- rv = f->C_GetAttributeValue(session, *obj, key_attr, 3); -+ rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr); - if (rv != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - goto fail; - } - - /* Expect one of the supported identifiers in CKA_EC_PARAMS */ -- d = (u_char *)key_attr[2].pValue; -- len = key_attr[2].ulValueLen; -+ d = (u_char *)key_attr[3].pValue; -+ len = key_attr[3].ulValueLen; - if ((len != sizeof(id1) || memcmp(d, id1, sizeof(id1)) != 0) && - (len != sizeof(id2) || memcmp(d, id2, sizeof(id2)) != 0)) { - hex = tohex(d, len); -@@ -1164,16 +1310,16 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - * Expect either a raw 32 byte pubkey or an OCTET STRING with - * a 32 byte pubkey in CKA_VALUE - */ -- d = (u_char *)key_attr[1].pValue; -- len = key_attr[1].ulValueLen; -+ d = (u_char *)key_attr[2].pValue; -+ len = key_attr[2].ulValueLen; - if (len == ED25519_PK_SZ + 2 && d[0] == 0x04 && d[1] == ED25519_PK_SZ) { - d += 2; - len -= 2; - } - if (len != ED25519_PK_SZ) { -- hex = tohex(key_attr[1].pValue, key_attr[1].ulValueLen); -+ hex = tohex(key_attr[2].pValue, key_attr[2].ulValueLen); - logit_f("CKA_EC_POINT invalid octet str: %s (len %lu)", -- hex, (u_long)key_attr[1].ulValueLen); -+ hex, (u_long)key_attr[2].ulValueLen); - goto fail; - } - -@@ -1193,7 +1339,7 @@ pkcs11_fetch_ed25519_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - key = NULL; - } - free(hex); -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattr; i++) - free(key_attr[i].pValue); - return key; - } -@@ -1203,7 +1349,8 @@ static int - pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp) - { -- CK_ATTRIBUTE cert_attr[3]; -+ CK_ATTRIBUTE cert_attr[4]; -+ int nattr = 4; - CK_SESSION_HANDLE session; - CK_FUNCTION_LIST *f = NULL; - CK_RV rv; -@@ -1229,14 +1376,15 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - - memset(&cert_attr, 0, sizeof(cert_attr)); - cert_attr[0].type = CKA_ID; -- cert_attr[1].type = CKA_SUBJECT; -- cert_attr[2].type = CKA_VALUE; -+ cert_attr[1].type = CKA_LABEL; -+ cert_attr[2].type = CKA_SUBJECT; -+ cert_attr[3].type = CKA_VALUE; - -- session = p->slotinfo[slotidx].session; -- f = p->function_list; -+ session = p->module->slotinfo[slotidx].session; -+ f = p->module->function_list; - - /* figure out size of the attributes */ -- rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3); -+ rv = f->C_GetAttributeValue(session, *obj, cert_attr, nattr); - if (rv != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - return -1; -@@ -1248,18 +1396,19 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - * XXX assumes CKA_ID is always first. - */ - if (cert_attr[1].ulValueLen == 0 || -- cert_attr[2].ulValueLen == 0) { -+ cert_attr[2].ulValueLen == 0 || -+ cert_attr[3].ulValueLen == 0) { - error("invalid attribute length"); - return -1; - } - - /* allocate buffers for attributes */ -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattr; i++) - if (cert_attr[i].ulValueLen > 0) - cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen); - - /* retrieve ID, subject and value of certificate */ -- rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3); -+ rv = f->C_GetAttributeValue(session, *obj, cert_attr, nattr); - if (rv != CKR_OK) { - error("C_GetAttributeValue failed: %lu", rv); - goto out; -@@ -1273,8 +1422,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - subject = xstrdup("invalid subject"); - X509_NAME_free(x509_name); - -- cp = cert_attr[2].pValue; -- if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) { -+ cp = cert_attr[3].pValue; -+ if ((x509 = d2i_X509(NULL, &cp, cert_attr[3].ulValueLen)) == NULL) { - error("d2i_x509 failed"); - goto out; - } -@@ -1384,7 +1533,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, - goto out; - } - out: -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattr; i++) - free(cert_attr[i].pValue); - X509_free(x509); - RSA_free(rsa); -@@ -1427,11 +1576,12 @@ note_key(struct pkcs11_provider *p, CK_ULONG slotidx, const char *context, - */ - static int - pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, -- struct sshkey ***keysp, char ***labelsp, int *nkeys) -+ struct sshkey ***keysp, char ***labelsp, int *nkeys, struct pkcs11_uri *uri) - { - struct sshkey *key = NULL; - CK_OBJECT_CLASS key_class; -- CK_ATTRIBUTE key_attr[1]; -+ CK_ATTRIBUTE key_attr[3]; -+ int nattr = 1; - CK_SESSION_HANDLE session; - CK_FUNCTION_LIST *f = NULL; - CK_RV rv; -@@ -1448,10 +1598,23 @@ pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx, - key_attr[0].pValue = &key_class; - key_attr[0].ulValueLen = sizeof(key_class); - -- session = p->slotinfo[slotidx].session; -- f = p->function_list; -+ if (uri->id != NULL) { -+ key_attr[nattr].type = CKA_ID; -+ key_attr[nattr].pValue = uri->id; -+ key_attr[nattr].ulValueLen = uri->id_len; -+ nattr++; -+ } -+ if (uri->object != NULL) { -+ key_attr[nattr].type = CKA_LABEL; -+ key_attr[nattr].pValue = uri->object; -+ 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, nattr); - if (rv != CKR_OK) { - error("C_FindObjectsInit failed: %lu", rv); - goto fail; -@@ -1533,11 +1696,12 @@ fail: - */ - static int - pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, -- struct sshkey ***keysp, char ***labelsp, int *nkeys) -+ struct sshkey ***keysp, char ***labelsp, int *nkeys, struct pkcs11_uri *uri) - { - struct sshkey *key = NULL; - CK_OBJECT_CLASS key_class; -- CK_ATTRIBUTE key_attr[2]; -+ CK_ATTRIBUTE key_attr[3]; -+ int nattr = 1; - CK_SESSION_HANDLE session; - CK_FUNCTION_LIST *f = NULL; - CK_RV rv; -@@ -1553,10 +1717,23 @@ pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx, - key_attr[0].pValue = &key_class; - key_attr[0].ulValueLen = sizeof(key_class); - -- session = p->slotinfo[slotidx].session; -- f = p->function_list; -+ if (uri->id != NULL) { -+ key_attr[nattr].type = CKA_ID; -+ key_attr[nattr].pValue = uri->id; -+ key_attr[nattr].ulValueLen = uri->id_len; -+ nattr++; -+ } -+ if (uri->object != NULL) { -+ key_attr[nattr].type = CKA_LABEL; -+ key_attr[nattr].pValue = uri->object; -+ 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); -+ rv = f->C_FindObjectsInit(session, key_attr, nattr); - if (rv != CKR_OK) { - error("C_FindObjectsInit failed: %lu", rv); - goto fail; -@@ -1844,16 +2021,10 @@ pkcs11_ecdsa_generate_private_key(struct pkcs11_provider *p, CK_ULONG slotidx, - } - #endif /* WITH_PKCS11_KEYGEN */ - --/* -- * register a new provider, fails if provider already exists. if -- * keyp is provided, fetch keys. -- */ - static int --pkcs11_register_provider(char *provider_id, char *pin, -- struct sshkey ***keyp, char ***labelsp, -- struct pkcs11_provider **providerp, CK_ULONG user) -+pkcs11_initialize_provider(struct pkcs11_uri *uri, struct pkcs11_provider **providerp) - { -- int nkeys, need_finalize = 0; -+ int need_finalize = 0; - int ret = -1; - struct pkcs11_provider *p = NULL; - void *handle = NULL; -@@ -1862,128 +2033,126 @@ pkcs11_register_provider(char *provider_id, char *pin, - CK_FUNCTION_LIST *f = NULL; - CK_TOKEN_INFO *token; - CK_ULONG i; -+ char *provider_module = NULL; -+ struct pkcs11_module *m = 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; -+#endif -+ } else { -+ provider_module = strdup(uri->module_path); -+ } -+ p = xcalloc(1, sizeof(*p)); -+ p->name = pkcs11_uri_get(uri); - -- if (providerp == NULL) -- goto fail; -- *providerp = NULL; -- -- if (keyp != NULL) -- *keyp = NULL; -- if (labelsp != NULL) -- *labelsp = NULL; -- -- 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) { -+ debug_f("provider module already initialized: %s", provider_module); -+ free(provider_module); -+ /* Skip the initialization of PKCS#11 module */ -+ m->refcount++; -+ p->module = m; -+ p->valid = 1; -+ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); -+ p->refcount++; /* add to provider list */ -+ *providerp = p; -+ return 0; -+ } else { -+ m = xcalloc(1, sizeof(*m)); -+ p->module = m; -+ m->refcount++; - } -+ - /* open shared pkcs11-library */ -- if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) { -- error("dlopen %s failed: %s", provider_id, dlerror()); -+ if ((handle = dlopen(provider_module, RTLD_NOW)) == NULL) { -+ error("dlopen %s failed: %s", provider_module, 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) { - error("C_GetFunctionList for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - goto fail; - } -- p->function_list = f; -+ m->function_list = f; - if ((rv = f->C_Initialize(NULL)) != CKR_OK) { - error("C_Initialize for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - goto fail; - } - need_finalize = 1; -- if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) { -+ if ((rv = f->C_GetInfo(&m->info)) != CKR_OK) { - error("C_GetInfo for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - goto fail; - } -- debug("provider %s: manufacturerID <%.*s> cryptokiVersion %d.%d" -- " libraryDescription <%.*s> libraryVersion %d.%d", -- provider_id, -- RMSPACE(p->info.manufacturerID), -- p->info.cryptokiVersion.major, -- p->info.cryptokiVersion.minor, -- 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, -+ m->info.cryptokiVersion.minor, -+ m->info.libraryDescription, -+ m->info.libraryVersion.major, -+ m->info.libraryVersion.minor); -+ -+ if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &m->nslots)) != CKR_OK) { - error("C_GetSlotList failed: %lu", rv); - goto fail; - } -- if (p->nslots == 0) { -- debug_f("provider %s returned no slots", provider_id); -+ if (m->nslots == 0) { -+ debug_f("provider %s returned no slots", provider_module); - ret = -SSH_PKCS11_ERR_NO_SLOTS; - goto fail; - } -- p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID)); -- if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots)) -+ m->slotlist = xcalloc(m->nslots, sizeof(CK_SLOT_ID)); -+ if ((rv = f->C_GetSlotList(CK_TRUE, m->slotlist, &m->nslots)) - != CKR_OK) { - error("C_GetSlotList for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); - 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->valid = 1; -+ for (i = 0; i < m->nslots; i++) { -+ token = &m->slotinfo[i].token; -+ if ((rv = f->C_GetTokenInfo(m->slotlist[i], token)) - != CKR_OK) { - error("C_GetTokenInfo for provider %s slot %lu " -- "failed: %lu", provider_id, (u_long)i, rv); -- continue; -- } -- if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { -- debug2_f("ignoring uninitialised token in " -- "provider %s slot %lu", provider_id, (u_long)i); -+ "failed: %lu", provider_module, (u_long)i, rv); - continue; - } - 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); -- /* -- * open session, login with pin and retrieve public -- * keys (if keyp is provided) -- */ -- if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 || -- keyp == NULL) -- continue; -- pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); --#ifdef WITH_OPENSSL -- pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); --#endif -- if (nkeys == 0 && !p->slotinfo[i].logged_in && -- pkcs11_interactive) { -- /* -- * Some tokens require login before they will -- * expose keys. -- */ -- if (pkcs11_login_slot(p, &p->slotinfo[i], -- CKU_USER) < 0) { -- error("login failed"); -- continue; -- } -- pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys); --#ifdef WITH_OPENSSL -- pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys); --#endif -- } - } -+ m->module_path = provider_module; -+ provider_module = NULL; - - /* now owned by caller */ - *providerp = p; -@@ -1991,21 +2160,22 @@ pkcs11_register_provider(char *provider_id, char *pin, - TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); - p->refcount++; /* add to provider list */ - -- return (nkeys); -+ return 0; - fail: - if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK) - error("C_Finalize for provider %s failed: %lu", -- provider_id, rv); -+ provider_module, rv); -+ free(provider_module); -+ if (m) { -+ free(m->slotlist); -+ free(m); -+ } - if (p) { - free(p->name); -- free(p->slotlist); -- free(p->slotinfo); - free(p); - } - if (handle) - dlclose(handle); -- if (ret > 0) -- ret = -1; - return (ret); - } - -@@ -2041,18 +2211,161 @@ pkcs11_terminate(void) - } - - /* -- * register a new provider and get number of keys hold by the token, -- * fails if provider already exists -+ * register a new provider, fails if provider already exists. if -+ * keyp is provided, fetch keys. - */ -+static int -+pkcs11_register_provider_by_uri(struct pkcs11_uri *uri, char *pin, -+ struct sshkey ***keyp, char ***labelsp, struct pkcs11_provider **providerp, -+ CK_ULONG user) -+{ -+ int nkeys; -+ int ret = -1; -+ struct pkcs11_provider *p = NULL; -+ CK_ULONG i; -+ CK_TOKEN_INFO *token; -+ char *provider_uri = NULL; -+ -+ if (providerp == NULL) -+ goto fail; -+ *providerp = NULL; -+ -+ if (keyp != NULL) -+ *keyp = NULL; -+ -+ if ((ret = pkcs11_initialize_provider(uri, &p)) != 0) { -+ goto fail; -+ } -+ -+ provider_uri = pkcs11_uri_get(uri); -+ if (pin == NULL && uri->pin != NULL) { -+ pin = uri->pin; -+ } -+ nkeys = 0; -+ for (i = 0; i < p->module->nslots; i++) { -+ token = &p->module->slotinfo[i].token; -+ if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { -+ debug2_f("ignoring uninitialised token in " -+ "provider %s slot %lu", provider_uri, (u_long)i); -+ continue; -+ } -+ if (uri->token != NULL && -+ 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 && -+ strncmp(token->manufacturerID, uri->manuf, 32) != 0) { -+ debug2_f("ignoring token not matching requrested " -+ "manufacturerID (%.32s) specified by PKCS#11 URI in " -+ "slot %lu", token->manufacturerID, (unsigned long)i); -+ continue; -+ } -+ 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); -+ /* -+ * open session if not yet opened, login with pin and -+ * retrieve public keys (if keyp is provided) -+ */ -+ if ((p->module->slotinfo[i].session != 0 || -+ (ret = pkcs11_open_session(p, i, pin, user)) != 0) && /* ??? */ -+ keyp == NULL) -+ continue; -+ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); -+ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); -+ if (nkeys == 0 && !p->module->slotinfo[i].logged_in && -+ pkcs11_interactive) { -+ /* -+ * Some tokens require login before they will -+ * expose keys. -+ */ -+ debug3_f("Trying to login as there were no keys found"); -+ if (pkcs11_login_slot(p, &p->module->slotinfo[i], -+ CKU_USER) < 0) { -+ error("login failed"); -+ continue; -+ } -+ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); -+ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); -+ } -+ if (nkeys == 0 && uri->object != NULL) { -+ debug3_f("No keys found. Retrying without label (%.32s) ", -+ uri->object); -+ /* Try once more without the label filter */ -+ char *label = uri->object; -+ uri->object = NULL; /* XXX clone uri? */ -+ pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri); -+ pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri); -+ uri->object = label; -+ } -+ } -+ pin = NULL; /* Will be cleaned up with URI */ -+ -+ /* now owned by caller */ -+ *providerp = p; -+ -+ free(provider_uri); -+ return (nkeys); -+ fail: -+ if (p) { -+ TAILQ_REMOVE(&pkcs11_providers, p, next); -+ pkcs11_provider_unref(p); -+ } -+ if (ret > 0) -+ ret = -1; -+ return (ret); -+} -+ -+static int -+pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp, -+ char ***labelsp, struct pkcs11_provider **providerp, CK_ULONG user) -+{ -+ struct pkcs11_uri *uri = NULL; -+ int r; -+ -+ debug_f("called, provider_id = %s", provider_id); -+ -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("failed to init PKCS#11 URI"); -+ -+ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { -+ if (pkcs11_uri_parse(provider_id, uri) != 0) -+ fatal("Failed to parse PKCS#11 URI"); -+ } else { -+ uri->module_path = strdup(provider_id); -+ } -+ -+ r = pkcs11_register_provider_by_uri(uri, pin, keyp, labelsp, providerp, user); -+ pkcs11_uri_cleanup(uri); -+ -+ return r; -+} -+ - int --pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp, -- char ***labelsp) -+pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, -+ struct sshkey ***keyp, char ***labelsp) - { - struct pkcs11_provider *p = NULL; - int nkeys; -+ char *provider_uri = pkcs11_uri_get(uri); -+ -+ debug_f("called, provider_uri = %s", provider_uri); - -- nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp, -- &p, CKU_USER); -+ nkeys = pkcs11_register_provider_by_uri(uri, pin, keyp, labelsp, &p, CKU_USER); - - /* no keys found or some other error, de-register provider */ - if (nkeys <= 0 && p != NULL) { -@@ -2061,11 +2374,38 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp, - pkcs11_provider_unref(p); - } - if (nkeys == 0) -- debug_f("provider %s returned no keys", provider_id); -+ debug_f("provider %s returned no keys", provider_uri); - -+ free(provider_uri); - return (nkeys); - } - -+int -+pkcs11_add_provider(char *provider_id, char *pin, -+ struct sshkey ***keyp, char ***labelsp) -+{ -+ struct pkcs11_uri *uri; -+ int nkeys; -+ -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("Failed to init PKCS#11 URI"); -+ -+ if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) { -+ if (pkcs11_uri_parse(provider_id, uri) != 0) -+ fatal("Failed to parse PKCS#11 URI"); -+ } else { -+ uri->module_path = strdup(provider_id); -+ } -+ -+ nkeys = pkcs11_add_provider_by_uri(uri, pin, keyp, labelsp); -+ pkcs11_uri_cleanup(uri); -+ -+ return (nkeys); -+} -+ -+ - int - pkcs11_sign(struct sshkey *key, - u_char **sigp, size_t *lenp, -diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h -index d86c506c1..32f2d0ccf 100644 ---- a/ssh-pkcs11.h -+++ b/ssh-pkcs11.h -@@ -22,12 +22,16 @@ - #define SSH_PKCS11_ERR_PIN_REQUIRED 4 - #define SSH_PKCS11_ERR_PIN_LOCKED 5 - -+#include "ssh-pkcs11-uri.h" -+ - struct sshkey; - - int pkcs11_init(int); - void pkcs11_terminate(void); - int pkcs11_add_provider(char *, char *, struct sshkey ***, char ***); -+int pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***, char ***); - int pkcs11_del_provider(char *); -+int pkcs11_uri_write(const struct sshkey *, FILE *); - int pkcs11_sign(struct sshkey *, u_char **, size_t *, - const u_char *, size_t, const char *, const char *, - const char *, u_int); -diff --git a/ssh.c b/ssh.c -index 320ac6834..14965a4f1 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -904,6 +904,14 @@ main(int ac, char **av) - options.gss_deleg_creds = 1; - break; - case 'i': -+#ifdef ENABLE_PKCS11 -+ if (strlen(optarg) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(optarg, PKCS11_URI_SCHEME, -+ strlen(PKCS11_URI_SCHEME)) == 0) { -+ add_identity_file(&options, NULL, optarg, 1); -+ break; -+ } -+#endif - p = tilde_expand_filename(optarg, getuid()); - if (stat(p, &st) == -1) - fprintf(stderr, "Warning: Identity file %s " -@@ -1872,6 +1880,7 @@ main(int ac, char **av) - #ifdef ENABLE_PKCS11 - (void)pkcs11_del_provider(options.pkcs11_provider); - #endif -+ pkcs11_terminate(); - - skip_connect: - if (addrs != NULL) -@@ -2387,6 +2396,45 @@ ssh_session2(struct ssh *ssh, const struct ssh_conn_info *cinfo) - options.escape_char : SSH_ESCAPECHAR_NONE, id); - } - -+#ifdef ENABLE_PKCS11 -+static void -+load_pkcs11_identity(char *pkcs11_uri, char *identity_files[], -+ struct sshkey *identity_keys[], int *n_ids) -+{ -+ int nkeys, i; -+ struct sshkey **keys; -+ struct pkcs11_uri *uri; -+ -+ debug("identity file '%s' from pkcs#11", pkcs11_uri); -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("Failed to init PKCS#11 URI"); -+ -+ if (pkcs11_uri_parse(pkcs11_uri, uri) != 0) -+ fatal("Failed to parse PKCS#11 URI %s", pkcs11_uri); -+ -+ /* we need to merge URI and provider together */ -+ if (options.pkcs11_provider != NULL && uri->module_path == NULL) -+ uri->module_path = strdup(options.pkcs11_provider); -+ -+ if (options.num_identity_files < SSH_MAX_IDENTITY_FILES && -+ (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys, NULL)) > 0) { -+ for (i = 0; i < nkeys; i++) { -+ if (*n_ids >= SSH_MAX_IDENTITY_FILES) { -+ sshkey_free(keys[i]); -+ continue; -+ } -+ identity_keys[*n_ids] = keys[i]; -+ identity_files[*n_ids] = pkcs11_uri_get(uri); -+ (*n_ids)++; -+ } -+ free(keys); -+ } -+ -+ pkcs11_uri_cleanup(uri); -+} -+#endif /* ENABLE_PKCS11 */ -+ - /* Loads all IdentityFile and CertificateFile keys */ - static void - load_public_identity_files(const struct ssh_conn_info *cinfo) -@@ -2401,11 +2449,6 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) - char *certificate_files[SSH_MAX_CERTIFICATE_FILES]; - struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES]; - int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES]; --#ifdef ENABLE_PKCS11 -- struct sshkey **keys = NULL; -- char **comments = NULL; -- int nkeys; --#endif /* PKCS11 */ - - n_ids = n_certs = 0; - memset(identity_files, 0, sizeof(identity_files)); -@@ -2418,33 +2461,46 @@ load_public_identity_files(const struct ssh_conn_info *cinfo) - sizeof(certificate_file_userprovided)); - - #ifdef ENABLE_PKCS11 -- if (options.pkcs11_provider != NULL && -- options.num_identity_files < SSH_MAX_IDENTITY_FILES && -- (pkcs11_init(!options.batch_mode) == 0) && -- (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL, -- &keys, &comments)) > 0) { -- for (i = 0; i < nkeys; i++) { -- if (n_ids >= SSH_MAX_IDENTITY_FILES) { -- sshkey_free(keys[i]); -- free(comments[i]); -- continue; -- } -- identity_keys[n_ids] = keys[i]; -- identity_files[n_ids] = comments[i]; /* transferred */ -- n_ids++; -- } -- free(keys); -- free(comments); -+ /* handle fallback from PKCS11Provider option */ -+ pkcs11_init(!options.batch_mode); -+ -+ if (options.pkcs11_provider != NULL) { -+ struct pkcs11_uri *uri; -+ -+ uri = pkcs11_uri_init(); -+ if (uri == NULL) -+ fatal("Failed to init PKCS#11 URI"); -+ -+ /* Construct simple PKCS#11 URI to simplify access */ -+ uri->module_path = strdup(options.pkcs11_provider); -+ -+ /* Add it as any other IdentityFile */ -+ cp = pkcs11_uri_get(uri); -+ add_identity_file(&options, NULL, cp, 1); -+ free(cp); -+ -+ pkcs11_uri_cleanup(uri); - } - #endif /* ENABLE_PKCS11 */ - for (i = 0; i < options.num_identity_files; i++) { -+ char *name = options.identity_files[i]; - if (n_ids >= SSH_MAX_IDENTITY_FILES || -- strcasecmp(options.identity_files[i], "none") == 0) { -+ strcasecmp(name, "none") == 0) { - free(options.identity_files[i]); - options.identity_files[i] = NULL; - continue; - } -- cp = tilde_expand_filename(options.identity_files[i], getuid()); -+#ifdef ENABLE_PKCS11 -+ if (strlen(name) >= strlen(PKCS11_URI_SCHEME) && -+ strncmp(name, PKCS11_URI_SCHEME, -+ strlen(PKCS11_URI_SCHEME)) == 0) { -+ load_pkcs11_identity(name, identity_files, -+ identity_keys, &n_ids); -+ free(options.identity_files[i]); -+ continue; -+ } -+#endif /* ENABLE_PKCS11 */ -+ cp = tilde_expand_filename(name, getuid()); - filename = default_client_percent_dollar_expand(cp, cinfo); - free(cp); - check_load(sshkey_load_public(filename, &public, NULL), -diff --git a/ssh_config.5 b/ssh_config.5 -index a06fbfa11..717b0938a 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -1260,6 +1260,21 @@ may also be used in conjunction with - .Cm CertificateFile - in order to provide any certificate also needed for authentication with - the identity. -+.Pp -+The authentication identity can be also specified in a form of PKCS#11 URI -+starting with a string -+.Cm pkcs11: . -+There is supported a subset of the PKCS#11 URI as defined -+in RFC 7512 (implemented path arguments -+.Cm id , -+.Cm manufacturer , -+.Cm object , -+.Cm token -+and query arguments -+.Cm module-path -+and -+.Cm pin-value -+). The URI can not be in quotes. - .It Cm IgnoreUnknown - Specifies a pattern-list of unknown options to be ignored if they are - encountered in configuration parsing. --- -2.52.0 - diff --git a/0030-openssh-8.0p1-preserve-pam-errors.patch b/openssh-8.0p1-preserve-pam-errors.patch similarity index 65% rename from 0030-openssh-8.0p1-preserve-pam-errors.patch rename to openssh-8.0p1-preserve-pam-errors.patch index 4aa2ffb..dbdbe93 100644 --- a/0030-openssh-8.0p1-preserve-pam-errors.patch +++ b/openssh-8.0p1-preserve-pam-errors.patch @@ -1,17 +1,7 @@ -From a3b6182e1d6b69a37a6c841baa43b818251036b1 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 30/53] openssh-8.0p1-preserve-pam-errors - ---- - auth-pam.c | 18 +++++++++++++----- - 1 file changed, 13 insertions(+), 5 deletions(-) - -diff --git a/auth-pam.c b/auth-pam.c -index 70bcae83a..70b2b8580 100644 ---- a/auth-pam.c -+++ b/auth-pam.c -@@ -551,7 +551,11 @@ sshpam_thread(void *ctxtp) +diff -up openssh-8.0p1/auth-pam.c.preserve-pam-errors openssh-8.0p1/auth-pam.c +--- openssh-8.0p1/auth-pam.c.preserve-pam-errors 2021-03-31 17:03:15.618592347 +0200 ++++ openssh-8.0p1/auth-pam.c 2021-03-31 17:06:58.115220014 +0200 +@@ -511,7 +511,11 @@ sshpam_thread(void *ctxtp) goto auth_fail; if (!do_pam_account()) { @@ -24,9 +14,9 @@ index 70bcae83a..70b2b8580 100644 goto auth_fail; } if (sshpam_authctxt->force_pwchange) { -@@ -608,8 +612,10 @@ sshpam_thread(void *ctxtp) +@@ -568,8 +572,10 @@ sshpam_thread(void *ctxtp) pam_strerror(sshpam_handle, sshpam_err))) != 0) - fatal_fr(r, "buffer error"); + fatal("%s: buffer error: %s", __func__, ssh_err(r)); /* XXX - can't do much about an error here */ - if (sshpam_err == PAM_ACCT_EXPIRED) - ssh_msg_send(ctxt->pam_csock, PAM_ACCT_EXPIRED, buffer); @@ -37,20 +27,18 @@ index 70bcae83a..70b2b8580 100644 else if (sshpam_maxtries_reached) ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer); else -@@ -913,9 +919,11 @@ sshpam_query(void *ctx, char **name, char **info, +@@ -856,10 +862,12 @@ sshpam_query(void *ctx, char **name, cha + plen++; free(msg); break; ++ case PAM_USER_UNKNOWN: ++ case PAM_PERM_DENIED: case PAM_ACCT_EXPIRED: + sshpam_account_status = 0; + /* FALLTHROUGH */ case PAM_MAXTRIES: - if (type == PAM_ACCT_EXPIRED) - sshpam_account_status = 0; -+ case PAM_USER_UNKNOWN: -+ case PAM_PERM_DENIED: if (type == PAM_MAXTRIES) sshpam_set_maxtries_reached(1); /* FALLTHROUGH */ --- -2.52.0 - diff --git a/0028-openssh-8.2p1-visibility.patch b/openssh-8.2p1-visibility.patch similarity index 62% rename from 0028-openssh-8.2p1-visibility.patch rename to openssh-8.2p1-visibility.patch index 7c5eabf..89c35ef 100644 --- a/0028-openssh-8.2p1-visibility.patch +++ b/openssh-8.2p1-visibility.patch @@ -1,17 +1,8 @@ -From ed5e5df9ec7ac96ac2a68c5711db00ed29d4d1cd Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 28/53] openssh-8.2p1-visibility - ---- - regress/misc/sk-dummy/sk-dummy.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c -index 4c96e8827..4af5209db 100644 +index dca158de..afdcb1d2 100644 --- a/regress/misc/sk-dummy/sk-dummy.c +++ b/regress/misc/sk-dummy/sk-dummy.c -@@ -80,7 +80,7 @@ skdebug(const char *func, const char *fmt, ...) +@@ -71,7 +71,7 @@ skdebug(const char *func, const char *fmt, ...) #endif } @@ -20,7 +11,7 @@ index 4c96e8827..4af5209db 100644 sk_api_version(void) { return SSH_SK_VERSION_MAJOR; -@@ -229,7 +229,7 @@ check_options(struct sk_option **options) +@@ -220,7 +220,7 @@ check_options(struct sk_option **options) return 0; } @@ -29,7 +20,7 @@ index 4c96e8827..4af5209db 100644 sk_enroll(uint32_t alg, const uint8_t *challenge, size_t challenge_len, const char *application, uint8_t flags, const char *pin, struct sk_option **options, struct sk_enroll_response **enroll_response) -@@ -477,7 +477,7 @@ sig_ed25519(const uint8_t *message, size_t message_len, +@@ -467,7 +467,7 @@ sig_ed25519(const uint8_t *message, size_t message_len, return ret; } @@ -38,7 +29,7 @@ index 4c96e8827..4af5209db 100644 sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, const char *application, const uint8_t *key_handle, size_t key_handle_len, uint8_t flags, const char *pin, struct sk_option **options, -@@ -534,7 +534,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, +@@ -518,7 +518,7 @@ sk_sign(uint32_t alg, const uint8_t *message, size_t message_len, return ret; } @@ -47,6 +38,3 @@ index 4c96e8827..4af5209db 100644 sk_load_resident_keys(const char *pin, struct sk_option **options, struct sk_resident_key ***rks, size_t *nrks) { --- -2.52.0 - diff --git a/0029-openssh-8.2p1-x11-without-ipv6.patch b/openssh-8.2p1-x11-without-ipv6.patch similarity index 55% rename from 0029-openssh-8.2p1-x11-without-ipv6.patch rename to openssh-8.2p1-x11-without-ipv6.patch index 7063d7f..8b83bc3 100644 --- a/0029-openssh-8.2p1-x11-without-ipv6.patch +++ b/openssh-8.2p1-x11-without-ipv6.patch @@ -1,17 +1,12 @@ -From c8dce0615eac6d2a724cdb3f288d7aaa1362f65b Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:28 +0200 -Subject: [PATCH 29/53] openssh-8.2p1-x11-without-ipv6 - ---- - channels.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - diff --git a/channels.c b/channels.c -index 5ce6bd400..26ed9945f 100644 --- a/channels.c +++ b/channels.c -@@ -5123,6 +5123,16 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, +@@ -3933,16 +3933,26 @@ x11_create_display_inet(int x11_display_ + if (ai->ai_family == AF_INET6) + sock_set_v6only(sock); + if (x11_use_localhost) + set_reuseaddr(sock); + if (bind(sock, ai->ai_addr, ai->ai_addrlen) == -1) { debug2_f("bind port %d: %.100s", port, strerror(errno)); close(sock); @@ -28,6 +23,8 @@ index 5ce6bd400..26ed9945f 100644 for (n = 0; n < num_socks; n++) close(socks[n]); num_socks = 0; --- -2.52.0 - + break; + } + socks[num_socks++] = sock; + if (num_socks == NUM_SOCKS) + break; diff --git a/openssh-8.7p1-ibmca.patch b/openssh-8.7p1-ibmca.patch new file mode 100644 index 0000000..88914bf --- /dev/null +++ b/openssh-8.7p1-ibmca.patch @@ -0,0 +1,11 @@ +--- openssh-8.7p1/openbsd-compat/bsd-closefrom.c.orig 2022-04-12 15:47:03.815044607 +0200 ++++ openssh-8.7p1/openbsd-compat/bsd-closefrom.c 2022-04-12 15:48:12.464963511 +0200 +@@ -16,7 +16,7 @@ + + #include "includes.h" + +-#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) ++#if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) || (defined __s390__) + + #include + #include diff --git a/0033-openssh-8.7p1-minrsabits.patch b/openssh-8.7p1-minrsabits.patch similarity index 58% rename from 0033-openssh-8.7p1-minrsabits.patch rename to openssh-8.7p1-minrsabits.patch index fcd994b..479b55d 100644 --- a/0033-openssh-8.7p1-minrsabits.patch +++ b/openssh-8.7p1-minrsabits.patch @@ -1,18 +1,7 @@ -From 14f25e21b4e2c5e625f266fcc9af42c2f89845de Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 33/53] openssh-8.7p1-minrsabits - ---- - readconf.c | 1 + - servconf.c | 1 + - 2 files changed, 2 insertions(+) - diff --git a/readconf.c b/readconf.c -index eab734aaf..3f67f4de4 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -337,6 +337,7 @@ static struct { +--- a/readconf.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/readconf.c (date 1703169891147) +@@ -326,6 +326,7 @@ { "securitykeyprovider", oSecurityKeyProvider }, { "knownhostscommand", oKnownHostsCommand }, { "requiredrsasize", oRequiredRSASize }, @@ -21,17 +10,13 @@ index eab734aaf..3f67f4de4 100644 { "obscurekeystroketiming", oObscureKeystrokeTiming }, { "channeltimeout", oChannelTimeout }, diff --git a/servconf.c b/servconf.c -index b63a7f0b0..ac84b74d9 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -778,6 +778,7 @@ static struct { +--- 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 }, + { "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */ { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, - { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL }, --- -2.52.0 - + { NULL, sBadOption, 0 } diff --git a/0040-openssh-8.7p1-negotiate-supported-algs.patch b/openssh-8.7p1-negotiate-supported-algs.patch similarity index 69% rename from 0040-openssh-8.7p1-negotiate-supported-algs.patch rename to openssh-8.7p1-negotiate-supported-algs.patch index 29f8213..ee3637f 100644 --- a/0040-openssh-8.7p1-negotiate-supported-algs.patch +++ b/openssh-8.7p1-negotiate-supported-algs.patch @@ -1,17 +1,6 @@ -From 53e44bd1f669ecd6a7429e94b55beec8e3c0c529 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 40/53] openssh-8.7p1-negotiate-supported-algs - ---- - regress/hostkey-agent.sh | 32 +++++++++++++++++++++++++------- - sshconnect2.c | 17 +++++++++++++++-- - 2 files changed, 40 insertions(+), 9 deletions(-) - -diff --git a/regress/hostkey-agent.sh b/regress/hostkey-agent.sh -index 28dcfe170..b9e716dcd 100644 ---- a/regress/hostkey-agent.sh -+++ b/regress/hostkey-agent.sh +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" @@ -35,7 +24,7 @@ index 28dcfe170..b9e716dcd 100644 ${SSHKEYGEN} -qt $k -f $OBJ/agent-key.$k -N '' || fatal "ssh-keygen $k" ${SSHKEYGEN} -s $OBJ/agent-ca -qh -n localhost-with-alias \ -I localhost-with-alias $OBJ/agent-key.$k.pub || \ -@@ -32,12 +45,16 @@ rm $OBJ/agent-ca # Don't need CA private any more either +@@ -32,12 +48,16 @@ rm $OBJ/agent-ca # Don't need CA private unset SSH_AUTH_SOCK @@ -55,10 +44,10 @@ index 28dcfe170..b9e716dcd 100644 ( 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 +67,16 @@ for k in $SSH_KEYTYPES ; do +@@ -50,15 +70,16 @@ for k in $SSH_KEYTYPES ; do done - SSH_CERTTYPES=`ssh -Q key-sig | grep 'cert-v01@openssh.com' | maybe_filter_sk` + 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. @@ -74,7 +63,7 @@ index 28dcfe170..b9e716dcd 100644 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 +88,7 @@ echo "HostKeyAlgorithms $HOSTKEYALGS" >> $OBJ/sshd_proxy +@@ -70,7 +93,7 @@ echo "HostKeyAlgorithms $HOSTKEYALGS" >> ( printf '@cert-authority localhost-with-alias ' ; cat $OBJ/agent-ca.pub) > $OBJ/known_hosts @@ -83,20 +72,19 @@ index 28dcfe170..b9e716dcd 100644 verbose "cert type $k" opts="-oHostKeyAlgorithms=$k -F $OBJ/ssh_proxy" SSH_CONNECTION=`${SSH} $opts host 'echo $SSH_CONNECTION'` -diff --git a/sshconnect2.c b/sshconnect2.c -index fffa66c8d..f43c81ad9 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -221,7 +221,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, +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]; -- char *all_key, *hkalgs = NULL; -+ char *all_key, *hkalgs = NULL, *filtered_algs = NULL; +- char *s, *all_key, *hkalgs = NULL; ++ char *s, *all_key, *hkalgs = NULL, *filtered_algs = NULL; int r, use_known_hosts_order = 0; #if defined(GSSAPI) && defined(WITH_OPENSSL) -@@ -257,10 +257,22 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, +@@ -260,9 +260,21 @@ ssh_kex2(struct ssh *ssh, char *host, st if (use_known_hosts_order) hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo); @@ -112,15 +100,14 @@ index fffa66c8d..f43c81ad9 100644 + options.hostkeyalgorithms, options.pubkey_accepted_algos); + } + - kex_proposal_populate_entries(ssh, myproposal, - options.kex_algorithms, options.ciphers, options.macs, - compression_alg_list(options.compression), + kex_proposal_populate_entries(ssh, myproposal, s, 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) { -@@ -304,6 +316,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, +@@ -303,6 +315,7 @@ ssh_kex2(struct ssh *ssh, char *host, st #endif free(hkalgs); @@ -128,6 +115,3 @@ index fffa66c8d..f43c81ad9 100644 /* start key exchange */ if ((r = kex_setup(ssh, myproposal)) != 0) --- -2.52.0 - diff --git a/openssh-8.7p1-nohostsha1proof.patch b/openssh-8.7p1-nohostsha1proof.patch new file mode 100644 index 0000000..7fea800 --- /dev/null +++ b/openssh-8.7p1-nohostsha1proof.patch @@ -0,0 +1,402 @@ +diff -up openssh-8.7p1/compat.c.sshrsacheck openssh-8.7p1/compat.c +--- openssh-8.7p1/compat.c.sshrsacheck 2023-01-12 13:29:06.338710923 +0100 ++++ openssh-8.7p1/compat.c 2023-01-12 13:29:06.357711165 +0100 +@@ -43,6 +43,7 @@ void + compat_banner(struct ssh *ssh, const char *version) + { + int i; ++ int forbid_ssh_rsa = 0; + static struct { + char *pat; + int bugs; +@@ -145,16 +146,21 @@ compat_banner(struct ssh *ssh, const cha + }; + + /* process table, return first match */ ++ forbid_ssh_rsa = (ssh->compat & SSH_RH_RSASIGSHA); + ssh->compat = 0; + for (i = 0; check[i].pat; i++) { + if (match_pattern_list(version, check[i].pat, 0) == 1) { + debug_f("match: %s pat %s compat 0x%08x", + version, check[i].pat, check[i].bugs); + ssh->compat = check[i].bugs; ++ if (forbid_ssh_rsa) ++ ssh->compat |= SSH_RH_RSASIGSHA; + return; + } + } + debug_f("no match: %s", version); ++ if (forbid_ssh_rsa) ++ ssh->compat |= SSH_RH_RSASIGSHA; + } + + /* Always returns pointer to allocated memory, caller must free. */ +diff -up openssh-8.7p1/compat.h.sshrsacheck openssh-8.7p1/compat.h +--- openssh-8.7p1/compat.h.sshrsacheck 2021-08-20 06:03:49.000000000 +0200 ++++ openssh-8.7p1/compat.h 2023-01-12 13:29:06.358711178 +0100 +@@ -30,7 +30,7 @@ + #define SSH_BUG_UTF8TTYMODE 0x00000001 + #define SSH_BUG_SIGTYPE 0x00000002 + #define SSH_BUG_SIGTYPE74 0x00000004 +-/* #define unused 0x00000008 */ ++#define SSH_RH_RSASIGSHA 0x00000008 + #define SSH_OLD_SESSIONID 0x00000010 + /* #define unused 0x00000020 */ + #define SSH_BUG_DEBUG 0x00000040 +diff -up openssh-8.7p1/monitor.c.sshrsacheck openssh-8.7p1/monitor.c +--- openssh-8.7p1/monitor.c.sshrsacheck 2023-01-20 13:07:54.279676981 +0100 ++++ openssh-8.7p1/monitor.c 2023-01-20 15:01:07.007821379 +0100 +@@ -660,11 +660,12 @@ mm_answer_sign(struct ssh *ssh, int sock + struct sshkey *key; + struct sshbuf *sigbuf = NULL; + u_char *p = NULL, *signature = NULL; +- char *alg = NULL; ++ char *alg = NULL, *effective_alg; + size_t datlen, siglen, alglen; + int r, is_proof = 0; + u_int keyid, compat; + const char proof_req[] = "hostkeys-prove-00@openssh.com"; ++ const char safe_rsa[] = "rsa-sha2-256"; + + debug3_f("entering"); + +@@ -719,18 +720,30 @@ mm_answer_sign(struct ssh *ssh, int sock + } + + if ((key = get_hostkey_by_index(keyid)) != NULL) { +- if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg, ++ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 ++ && (sshkey_type_plain(key->type) == KEY_RSA)) { ++ effective_alg = safe_rsa; ++ } else { ++ effective_alg = alg; ++ } ++ if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, effective_alg, + options.sk_provider, NULL, compat)) != 0) + fatal_fr(r, "sign"); + } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && + auth_sock > 0) { ++ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 ++ && (sshkey_type_plain(key->type) == KEY_RSA)) { ++ effective_alg = safe_rsa; ++ } else { ++ effective_alg = alg; ++ } + if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, +- p, datlen, alg, compat)) != 0) ++ p, datlen, effective_alg, compat)) != 0) + fatal_fr(r, "agent sign"); + } else + fatal_f("no hostkey from index %d", keyid); + +- debug3_f("%s %s signature len=%zu", alg, ++ debug3_f("%s (effective: %s) %s signature len=%zu", alg, effective_alg, + 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 +@@ -97,7 +97,8 @@ do_kex_with_key(char *kex, int keytype, + memcpy(kex_params.proposal, myproposal, sizeof(myproposal)); + if (kex != NULL) + kex_params.proposal[PROPOSAL_KEX_ALGS] = kex; +- keyname = strdup(sshkey_ssh_name(private)); ++ keyname = (strcmp(sshkey_ssh_name(private), "ssh-rsa")) ? ++ strdup(sshkey_ssh_name(private)) : strdup("rsa-sha2-256"); + 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 +@@ -110,6 +110,7 @@ sshkey_file_tests(void) + sshkey_free(k2); + TEST_DONE(); + ++ /* Skip this test, SHA1 signatures are not supported + TEST_START("load RSA cert with SHA1 signature"); + ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha1"), &k2), 0); + ASSERT_PTR_NE(k2, NULL); +@@ -117,7 +118,7 @@ sshkey_file_tests(void) + ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1); + ASSERT_STRING_EQ(k2->cert->signature_type, "ssh-rsa"); + sshkey_free(k2); +- TEST_DONE(); ++ TEST_DONE(); */ + + TEST_START("load RSA cert with SHA512 signature"); + ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha512"), &k2), 0); +diff -up openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c +--- openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c.sshrsacheck 2023-01-26 12:10:37.533168013 +0100 ++++ openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c 2023-01-26 12:15:35.637631860 +0100 +@@ -333,13 +333,14 @@ sshkey_fuzz_tests(void) + TEST_DONE(); + + #ifdef WITH_OPENSSL ++ /* Skip this test, SHA1 signatures are not supported + TEST_START("fuzz RSA sig"); + buf = load_file("rsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, "ssh-rsa"); + sshkey_free(k1); +- TEST_DONE(); ++ TEST_DONE();*/ + + 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 +@@ -60,6 +60,9 @@ build_cert(struct sshbuf *b, struct sshk + u_char *sigblob; + size_t siglen; + ++ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp */ ++ int expected = (sig_alg == NULL || strcmp(sig_alg, "ssh-rsa") == 0) ? SSH_ERR_LIBCRYPTO_ERROR : 0; ++ + ca_buf = sshbuf_new(); + ASSERT_PTR_NE(ca_buf, NULL); + ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0); +@@ -101,8 +104,9 @@ build_cert(struct sshbuf *b, struct sshk + ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ + ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ + ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, +- sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), 0); +- ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ ++ sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), expected); ++ if (expected == 0) ++ ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ + + free(sigblob); + sshbuf_free(ca_buf); +@@ -119,16 +123,22 @@ signature_test(struct sshkey *k, struct + { + 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; ++ if (k && (sshkey_type_plain(k->type) == KEY_DSA || sshkey_type_plain(k->type) == KEY_DSA_CERT)) ++ expected = SSH_ERR_LIBCRYPTO_ERROR; + + ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, +- NULL, NULL, 0), 0); +- ASSERT_SIZE_T_GT(len, 8); +- ASSERT_PTR_NE(sig, NULL); +- ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); +- ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); +- /* Fuzz test is more comprehensive, this is just a smoke test */ +- sig[len - 5] ^= 0x10; +- ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ NULL, NULL, 0), expected); ++ if (expected == 0) { ++ ASSERT_SIZE_T_GT(len, 8); ++ ASSERT_PTR_NE(sig, NULL); ++ ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); ++ /* Fuzz test is more comprehensive, this is just a smoke test */ ++ sig[len - 5] ^= 0x10; ++ ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ } + free(sig); + } + +@@ -514,7 +524,7 @@ sshkey_tests(void) + ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, + NULL), 0); + k3 = get_private("rsa_1"); +- build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, NULL); ++ build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, "rsa-sha2-256"); + 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"; + } ++ if (ssh->compat & SSH_RH_RSASIGSHA && sigalg == NULL) { ++ sigalg = "rsa-sha2-512"; ++ 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); + 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 ++++ openssh-8.7p1/sshconnect2.c 2023-01-25 15:59:34.225364883 +0100 +@@ -1461,6 +1464,14 @@ identity_sign(struct identity *id, u_cha + retried = 1; + goto retry_pin; + } ++ if ((r == SSH_ERR_LIBCRYPTO_ERROR) && strcmp("ssh-rsa", alg)) { ++ char rsa_safe_alg[] = "rsa-sha2-512"; ++ 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) ++ 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) + Authctxt *authctxt; + struct connection_info *connection_info = NULL; + sigset_t sigmask; ++ 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 -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 +@@ -254,7 +254,8 @@ ssh_rsa_verify(const struct sshkey *key, + ret = SSH_ERR_INVALID_ARGUMENT; + goto out; + } +- if (hash_alg != want_alg) { ++ if (hash_alg != want_alg && want_alg != SSH_DIGEST_SHA1) { ++ debug_f("Unexpected digest algorithm: got %d, wanted %d", hash_alg, want_alg); + ret = SSH_ERR_SIGNATURE_INVALID; + goto out; + } diff --git a/0032-openssh-8.7p1-recursive-scp.patch b/openssh-8.7p1-recursive-scp.patch similarity index 73% rename from 0032-openssh-8.7p1-recursive-scp.patch rename to openssh-8.7p1-recursive-scp.patch index adb5e3d..17c340e 100644 --- a/0032-openssh-8.7p1-recursive-scp.patch +++ b/openssh-8.7p1-recursive-scp.patch @@ -1,21 +1,8 @@ -From e6478b233cd2298c9e6e6128867421892ff8f0e4 Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 32/53] openssh-8.7p1-recursive-scp - ---- - scp.c | 2 +- - sftp-client.c | 60 +++++++++++++++++++++++++++++++++++++++------------ - sftp-client.h | 4 ++-- - sftp.c | 6 +++--- - 4 files changed, 52 insertions(+), 20 deletions(-) - diff --git a/scp.c b/scp.c -index 3c213f83d..78c79a755 100644 ---- a/scp.c -+++ b/scp.c -@@ -1378,7 +1378,7 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn) - +--- a/scp.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/scp.c (date 1703111453316) +@@ -1372,7 +1372,7 @@ + if (src_is_dir && iamrecursive) { if (sftp_upload_dir(conn, src, abs_dst, pflag, - SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) { @@ -24,11 +11,10 @@ index 3c213f83d..78c79a755 100644 errs = 1; } diff --git a/sftp-client.c b/sftp-client.c -index 840170ab6..9bf9cc047 100644 ---- a/sftp-client.c -+++ b/sftp-client.c -@@ -1001,7 +1001,7 @@ sftp_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, - +--- 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 * -sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand) @@ -36,7 +22,7 @@ index 840170ab6..9bf9cc047 100644 { struct sshbuf *msg; u_int expected_id, count, id; -@@ -1047,11 +1047,43 @@ sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand) +@@ -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"); @@ -85,9 +71,9 @@ index 840170ab6..9bf9cc047 100644 } else if (type != SSH2_FXP_NAME) fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", SSH2_FXP_NAME, type); -@@ -1076,9 +1108,9 @@ sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand) +@@ -1078,9 +1110,9 @@ } - + char * -sftp_realpath(struct sftp_conn *conn, const char *path) +sftp_realpath(struct sftp_conn *conn, const char *path, int create_dir) @@ -95,9 +81,9 @@ index 840170ab6..9bf9cc047 100644 - return sftp_realpath_expand(conn, path, 0); + return sftp_realpath_expand(conn, path, 0, create_dir); } - + int -@@ -1092,9 +1124,9 @@ sftp_expand_path(struct sftp_conn *conn, const char *path) +@@ -1094,9 +1126,9 @@ { if (!sftp_can_expand_path(conn)) { debug3_f("no server support, fallback to realpath"); @@ -107,18 +93,18 @@ index 840170ab6..9bf9cc047 100644 - return sftp_realpath_expand(conn, path, 1); + return sftp_realpath_expand(conn, path, 1, 0); } - + int -@@ -2014,7 +2046,7 @@ sftp_download_dir(struct sftp_conn *conn, const char *src, const char *dst, +@@ -2016,7 +2048,7 @@ char *src_canon; int ret; - + - 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; } -@@ -2366,12 +2398,12 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst, +@@ -2365,12 +2397,12 @@ int sftp_upload_dir(struct sftp_conn *conn, const char *src, const char *dst, int preserve_flag, int print_flag, int resume, int fsync_flag, @@ -127,48 +113,47 @@ index 840170ab6..9bf9cc047 100644 { char *dst_canon; int ret; - + - 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; } -@@ -2826,7 +2858,7 @@ sftp_crossload_dir(struct sftp_conn *from, struct sftp_conn *to, +@@ -2825,7 +2857,7 @@ char *from_path_canon; int ret; - + - 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 --git a/sftp-client.h b/sftp-client.h -index 873ad3849..fe58651c1 100644 ---- a/sftp-client.h -+++ b/sftp-client.h -@@ -112,7 +112,7 @@ int sftp_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *); +--- 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 *sftp_realpath(struct sftp_conn *, const char *); +char *sftp_realpath(struct sftp_conn *, const char *, int); - + /* Canonicalisation with tilde expansion (requires server extension) */ char *sftp_expand_path(struct sftp_conn *, const char *); -@@ -164,7 +164,7 @@ int sftp_upload(struct sftp_conn *, const char *, const char *, +@@ -163,7 +163,7 @@ * times if 'pflag' is set */ 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 --git a/sftp.c b/sftp.c -index 3b505eea2..2a99698a8 100644 ---- a/sftp.c -+++ b/sftp.c -@@ -801,7 +801,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, +--- 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, @@ -177,7 +162,7 @@ index 3b505eea2..2a99698a8 100644 err = -1; } else { if (sftp_upload(conn, g.gl_pathv[i], abs_dst, -@@ -1636,7 +1636,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, +@@ -1642,7 +1642,7 @@ if (path1 == NULL || *path1 == '\0') path1 = xstrdup(startdir); path1 = sftp_make_absolute(path1, *pwd); @@ -186,15 +171,12 @@ index 3b505eea2..2a99698a8 100644 err = 1; break; } -@@ -2241,7 +2241,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) +@@ -2247,7 +2247,7 @@ } #endif /* USE_LIBEDIT */ - + - if ((remote_path = sftp_realpath(conn, ".")) == NULL) + if ((remote_path = sftp_realpath(conn, ".", 0)) == NULL) fatal("Need cwd"); startdir = xstrdup(remote_path); - --- -2.52.0 diff --git a/0031-openssh-8.7p1-scp-kill-switch.patch b/openssh-8.7p1-scp-kill-switch.patch similarity index 52% rename from 0031-openssh-8.7p1-scp-kill-switch.patch rename to openssh-8.7p1-scp-kill-switch.patch index 5c3594f..161ab2d 100644 --- a/0031-openssh-8.7p1-scp-kill-switch.patch +++ b/openssh-8.7p1-scp-kill-switch.patch @@ -1,31 +1,18 @@ -From ca8b4de1019b859e2c68288a554d1905a6cf029f Mon Sep 17 00:00:00 2001 -From: Dmitry Belyavskiy -Date: Thu, 15 May 2025 13:43:29 +0200 -Subject: [PATCH 31/53] openssh-8.7p1-scp-kill-switch - ---- - pathnames.h | 1 + - scp.1 | 7 +++++++ - scp.c | 8 ++++++++ - 3 files changed, 16 insertions(+) - -diff --git a/pathnames.h b/pathnames.h -index 0dcc49552..78bba2314 100644 ---- a/pathnames.h -+++ b/pathnames.h -@@ -40,6 +40,7 @@ - #define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key" +diff -up openssh-8.7p1/pathnames.h.kill-scp openssh-8.7p1/pathnames.h +--- openssh-8.7p1/pathnames.h.kill-scp 2021-09-16 11:37:57.240171687 +0200 ++++ openssh-8.7p1/pathnames.h 2021-09-16 11:42:29.183427917 +0200 +@@ -42,6 +42,7 @@ + #define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key" #define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key" #define _PATH_DH_MODULI SSHDIR "/moduli" +#define _PATH_SCP_KILL_SWITCH SSHDIR "/disable_scp" #ifndef _PATH_SSH_PROGRAM #define _PATH_SSH_PROGRAM "/usr/bin/ssh" -diff --git a/scp.1 b/scp.1 -index 7bce0fe6f..2bb838c7d 100644 ---- a/scp.1 -+++ b/scp.1 -@@ -334,6 +334,13 @@ during download or upload. +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 By default a 32KB buffer is used. .El .El @@ -39,11 +26,10 @@ index 7bce0fe6f..2bb838c7d 100644 .Sh EXIT STATUS .Ex -std scp .Sh SEE ALSO -diff --git a/scp.c b/scp.c -index 621131ffc..3c213f83d 100644 ---- a/scp.c -+++ b/scp.c -@@ -633,6 +633,14 @@ main(int argc, char **argv) +diff -up openssh-8.7p1/scp.c.kill-scp openssh-8.7p1/scp.c +--- openssh-8.7p1/scp.c.kill-scp 2021-09-16 11:42:56.013650519 +0200 ++++ openssh-8.7p1/scp.c 2021-09-16 11:53:03.249713836 +0200 +@@ -596,6 +596,14 @@ main(int argc, char **argv) if (iamremote) mode = MODE_SCP; @@ -58,6 +44,3 @@ index 621131ffc..3c213f83d 100644 if ((pwd = getpwuid(userid = getuid())) == NULL) fatal("unknown user %u", (u_int) userid); --- -2.52.0 - diff --git a/openssh-8.7p1-ssh-manpage.patch b/openssh-8.7p1-ssh-manpage.patch new file mode 100644 index 0000000..c7f6f1e --- /dev/null +++ b/openssh-8.7p1-ssh-manpage.patch @@ -0,0 +1,53 @@ +diff --color -ru a/ssh.1 b/ssh.1 +--- a/ssh.1 2022-07-12 11:47:51.307295880 +0200 ++++ b/ssh.1 2022-07-12 11:50:28.793363263 +0200 +@@ -493,6 +493,7 @@ + .It AddressFamily + .It BatchMode + .It BindAddress ++.It BindInterface + .It CanonicalDomains + .It CanonicalizeFallbackLocal + .It CanonicalizeHostname +@@ -510,6 +511,7 @@ + .It ControlPath + .It ControlPersist + .It DynamicForward ++.It EnableSSHKeysign + .It EnableEscapeCommandline + .It EscapeChar + .It ExitOnForwardFailure +@@ -538,6 +540,8 @@ + .It IdentitiesOnly + .It IdentityAgent + .It IdentityFile ++.It IgnoreUnknown ++.It Include + .It IPQoS + .It KbdInteractiveAuthentication + .It KbdInteractiveDevices +@@ -546,6 +550,7 @@ + .It LocalCommand + .It LocalForward + .It LogLevel ++.It LogVerbose + .It MACs + .It Match + .It NoHostAuthenticationForLocalhost +@@ -566,6 +571,8 @@ + .It RemoteCommand + .It RemoteForward + .It RequestTTY ++.It RevokedHostKeys ++.It SecurityKeyProvider + .It RequiredRSASize + .It SendEnv + .It ServerAliveInterval +@@ -575,6 +582,7 @@ + .It StreamLocalBindMask + .It StreamLocalBindUnlink + .It StrictHostKeyChecking ++.It SyslogFacility + .It TCPKeepAlive + .It Tunnel + .It TunnelDevice diff --git a/openssh-9.0p1-audit-log.patch b/openssh-9.0p1-audit-log.patch new file mode 100644 index 0000000..fbf5094 --- /dev/null +++ b/openssh-9.0p1-audit-log.patch @@ -0,0 +1,119 @@ +diff -up openssh-9.0p1/audit-bsm.c.patch openssh-9.0p1/audit-bsm.c +--- openssh-9.0p1/audit-bsm.c.patch 2022-10-24 15:02:16.544858331 +0200 ++++ openssh-9.0p1/audit-bsm.c 2022-10-24 14:51:43.685766639 +0200 +@@ -405,7 +405,7 @@ audit_session_close(struct logininfo *li + } + + int +-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) + { + /* not implemented */ + } +diff -up openssh-9.0p1/audit.c.patch openssh-9.0p1/audit.c +--- openssh-9.0p1/audit.c.patch 2022-10-24 15:02:16.544858331 +0200 ++++ openssh-9.0p1/audit.c 2022-10-24 15:20:38.854548226 +0200 +@@ -116,12 +116,22 @@ audit_event_lookup(ssh_audit_event_t ev) + void + audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) + { +- char *fp; ++ char *key_fp = NULL; ++ char *issuer_fp = NULL; ++ struct sshkey_cert *cert = NULL; + +- fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); +- if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) ++ key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); ++ if (sshkey_is_cert(key) && key->cert != NULL && key->cert->signature_key != NULL) { ++ cert = key->cert; ++ issuer_fp = sshkey_fingerprint(cert->signature_key, ++ options.fingerprint_hash, SSH_FP_DEFAULT); ++ } ++ if (audit_keyusage(ssh, host_user, key_fp, cert, issuer_fp, (*rv == 0)) == 0) + *rv = -SSH_ERR_INTERNAL_ERROR; +- free(fp); ++ if (key_fp) ++ free(key_fp); ++ if (issuer_fp) ++ free(issuer_fp); + } + + void +diff -up openssh-9.0p1/audit.h.patch openssh-9.0p1/audit.h +--- openssh-9.0p1/audit.h.patch 2022-10-24 15:02:16.544858331 +0200 ++++ openssh-9.0p1/audit.h 2022-10-24 14:58:20.887565518 +0200 +@@ -64,7 +64,7 @@ void audit_session_close(struct logininf + int audit_run_command(struct ssh *, const char *); + void audit_end_command(struct ssh *, int, const char *); + ssh_audit_event_t audit_classify_auth(const char *); +-int audit_keyusage(struct ssh *, int, char *, int); ++int audit_keyusage(struct ssh *, int, const char *, const struct sshkey_cert *, const char *, int); + void audit_key(struct ssh *, int, int *, const struct sshkey *); + void audit_unsupported(struct ssh *, int); + void audit_kex(struct ssh *, int, char *, char *, char *, char *); +diff -up openssh-9.0p1/audit-linux.c.patch openssh-9.0p1/audit-linux.c +--- openssh-9.0p1/audit-linux.c.patch 2022-10-24 15:02:16.544858331 +0200 ++++ openssh-9.0p1/audit-linux.c 2022-10-24 15:21:58.165303951 +0200 +@@ -137,10 +137,12 @@ fatal_report: + } + + int +-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, const char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) + { + char buf[AUDIT_LOG_SIZE]; + int audit_fd, rc, saved_errno; ++ const char *rip; ++ u_int i; + + audit_fd = audit_open(); + if (audit_fd < 0) { +@@ -150,14 +152,44 @@ audit_keyusage(struct ssh *ssh, int host + else + return 0; /* Must prevent login */ + } ++ rip = ssh_remote_ipaddr(ssh); + snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased"); + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, +- buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv); ++ buf, audit_username(), -1, NULL, rip, NULL, rv); + if ((rc < 0) && ((rc != -1) || (getuid() == 0))) + goto out; +- snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp); ++ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", key_fp); + rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, +- ssh_remote_ipaddr(ssh), NULL, rv); ++ rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ ++ if (cert) { ++ char *pbuf; ++ ++ pbuf = audit_encode_nv_string("key_id", cert->key_id, 0); ++ if (pbuf == NULL) ++ goto out; ++ snprintf(buf, sizeof(buf), "cert %s cert_serial=%llu cert_issuer_alg=\"%s\" cert_issuer_fp=\"%s\"", ++ pbuf, (unsigned long long)cert->serial, sshkey_type(cert->signature_key), issuer_fp); ++ free(pbuf); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ ++ for (i = 0; cert->principals != NULL && i < cert->nprincipals; i++) { ++ pbuf = audit_encode_nv_string("cert_principal", cert->principals[i], 0); ++ if (pbuf == NULL) ++ goto out; ++ snprintf(buf, sizeof(buf), "principal %s", pbuf); ++ free(pbuf); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ } ++ } + out: + saved_errno = errno; + audit_close(audit_fd); diff --git a/openssh-9.0p1-evp-fips-dh.patch b/openssh-9.0p1-evp-fips-dh.patch new file mode 100644 index 0000000..d0470d9 --- /dev/null +++ b/openssh-9.0p1-evp-fips-dh.patch @@ -0,0 +1,292 @@ +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,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-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 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-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,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/openssh-9.0p1-evp-fips-ecdh.patch b/openssh-9.0p1-evp-fips-ecdh.patch new file mode 100644 index 0000000..0313c6f --- /dev/null +++ b/openssh-9.0p1-evp-fips-ecdh.patch @@ -0,0 +1,207 @@ +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/openssh-9.3p1-merged-openssl-evp.patch b/openssh-9.3p1-merged-openssl-evp.patch new file mode 100644 index 0000000..6a30485 --- /dev/null +++ b/openssh-9.3p1-merged-openssl-evp.patch @@ -0,0 +1,1237 @@ +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/digest.h openssh-9.3p1-patched/digest.h +--- openssh-9.3p1/digest.h 2023-03-15 22:28:19.000000000 +0100 ++++ openssh-9.3p1-patched/digest.h 2023-06-06 15:52:25.602551466 +0200 +@@ -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 --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/digest-openssl.c openssh-9.3p1-patched/digest-openssl.c +--- openssh-9.3p1/digest-openssl.c 2023-03-15 22:28:19.000000000 +0100 ++++ openssh-9.3p1-patched/digest-openssl.c 2023-06-06 15:52:25.601551454 +0200 +@@ -64,6 +64,22 @@ + { -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 --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-dss.c openssh-9.3p1-patched/ssh-dss.c +--- openssh-9.3p1/ssh-dss.c 2023-03-15 22:28:19.000000000 +0100 ++++ openssh-9.3p1-patched/ssh-dss.c 2023-06-06 15:52:25.624551743 +0200 +@@ -32,6 +32,8 @@ + #include + #include + #include ++#include ++#include + + #include + #include +@@ -261,11 +263,15 @@ + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, const char *sk_pin, 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) +@@ -276,17 +282,23 @@ + 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 ((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); ++ 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); +@@ -319,7 +331,7 @@ + *lenp = len; + ret = 0; + out: +- explicit_bzero(digest, sizeof(digest)); ++ free(sigb); + DSA_SIG_free(sig); + sshbuf_free(b); + return ret; +@@ -331,20 +343,20 @@ + const u_char *data, size_t dlen, const char *alg, u_int compat, + struct sshkey_sig_details **detailsp) + { ++ EVP_PKEY *pkey = NULL; + DSA_SIG *dsig = NULL; + BIGNUM *sig_r = NULL, *sig_s = NULL; +- u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; +- size_t len, hlen = 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 || + sig == NULL || siglen == 0) + return SSH_ERR_INVALID_ARGUMENT; +- if (hlen == 0) +- return SSH_ERR_INTERNAL_ERROR; + + /* fetch signature */ + if ((b = sshbuf_from(sig, siglen)) == NULL) +@@ -386,25 +398,28 @@ + } + sig_r = sig_s = NULL; /* transferred */ + +- /* sha1 the data */ +- if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, +- digest, sizeof(digest))) != 0) ++ if ((slen = i2d_DSA_SIG(dsig, NULL)) == 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; +- +- switch (DSA_do_verify(digest, hlen, dsig, 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(dsig, &psig)) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + ++ if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) ++ goto out; ++ ret = sshkey_verify_signature(pkey, SSH_DIGEST_SHA1, data, dlen, ++ sigb, slen); ++ EVP_PKEY_free(pkey); ++ + out: +- explicit_bzero(digest, sizeof(digest)); ++ free(sigb); + DSA_SIG_free(dsig); + BN_clear_free(sig_r); + BN_clear_free(sig_s); +@@ -415,6 +430,65 @@ + 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; ++} ++ + static const struct sshkey_impl_funcs sshkey_dss_funcs = { + /* .size = */ ssh_dss_size, + /* .alloc = */ ssh_dss_alloc, +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-ecdsa.c openssh-9.3p1-patched/ssh-ecdsa.c +--- openssh-9.3p1/ssh-ecdsa.c 2023-03-15 22:28:19.000000000 +0100 ++++ openssh-9.3p1-patched/ssh-ecdsa.c 2023-06-06 15:52:25.626551768 +0200 +@@ -34,6 +34,8 @@ + #include + #include + #include ++#include ++#include + + #include + +@@ -44,6 +44,9 @@ + #include "digest.h" + #define SSHKEY_INTERNAL + #include "sshkey.h" ++#ifdef ENABLE_PKCS11 ++#include "ssh-pkcs11.h" ++#endif + + #include "openbsd-compat/openssl-compat.h" + +@@ -126,19 +128,29 @@ + static int + ssh_ecdsa_generate(struct sshkey *k, int bits) + { +- EC_KEY *private; ++ EVP_PKEY_CTX *ctx = NULL; ++ EVP_PKEY *res = NULL; + + if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) + return SSH_ERR_KEY_LENGTH; +- if ((private = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL) ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) + return SSH_ERR_ALLOC_FAIL; +- if (EC_KEY_generate_key(private) != 1) { +- EC_KEY_free(private); ++ ++ if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_CTX_set_group_name(ctx, OBJ_nid2sn(k->ecdsa_nid)) <= 0 ++ || EVP_PKEY_keygen(ctx, &res) <= 0) { ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(res); + return SSH_ERR_LIBCRYPTO_ERROR; + } +- EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); +- k->ecdsa = private; +- return 0; ++ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ ++ k->ecdsa = EVP_PKEY_get1_EC_KEY(res); ++ if (k->ecdsa) ++ EC_KEY_set_asn1_flag(k->ecdsa, OPENSSL_EC_NAMED_CURVE); ++ ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(res); ++ return (k->ecdsa) ? 0 : SSH_ERR_LIBCRYPTO_ERROR; + } + + static int +@@ -228,11 +240,13 @@ + const u_char *data, size_t dlen, + const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) + { ++ EVP_PKEY *pkey = NULL; + ECDSA_SIG *esig = 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, hlen; ++ int len; + struct sshbuf *b = NULL, *bb = NULL; + int ret = SSH_ERR_INTERNAL_ERROR; + +@@ -245,18 +259,33 @@ + 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 || +- (hlen = 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, dlen, +- digest, sizeof(digest))) != 0) ++ ++#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, ++ dlen); ++ EVP_PKEY_free(pkey); ++ if (ret < 0) { + goto out; ++ } + +- if ((esig = ECDSA_do_sign(digest, hlen, key->ecdsa)) == NULL) { ++ psig = sigb; ++ if (d2i_ECDSA_SIG(&esig, &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; +@@ -280,7 +309,7 @@ + *lenp = len; + ret = 0; + out: +- explicit_bzero(digest, sizeof(digest)); ++ free(sigb); + sshbuf_free(b); + sshbuf_free(bb); + ECDSA_SIG_free(esig); +@@ -293,22 +322,21 @@ + const u_char *data, size_t dlen, const char *alg, u_int compat, + struct sshkey_sig_details **detailsp) + { ++ EVP_PKEY *pkey = NULL; + ECDSA_SIG *esig = NULL; + BIGNUM *sig_r = NULL, *sig_s = NULL; +- int hash_alg; +- u_char digest[SSH_DIGEST_MAX_LENGTH]; +- size_t hlen; ++ 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 || + sig == NULL || siglen == 0) + return SSH_ERR_INVALID_ARGUMENT; + +- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || +- (hlen = 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 */ +@@ -344,28 +372,33 @@ + } + 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(esig, NULL)) == 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- if ((ret = ssh_digest_memory(hash_alg, data, dlen, +- digest, sizeof(digest))) != 0) +- goto out; +- +- switch (ECDSA_do_verify(digest, hlen, esig, key->ecdsa)) { +- case 1: +- ret = 0; +- break; +- case 0: +- ret = SSH_ERR_SIGNATURE_INVALID; ++ if ((sigb = malloc(len)) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; + goto out; +- default: ++ } ++ psig = sigb; ++ if ((len = i2d_ECDSA_SIG(esig, &psig)) == 0) { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + ++ if (sshbuf_len(sigbuf) != 0) { ++ ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; ++ goto out; ++ } ++ ++ if (ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey) != 0) ++ goto out; ++ ret = sshkey_verify_signature(pkey, hash_alg, data, dlen, sigb, len); ++ EVP_PKEY_free(pkey); ++ + out: +- explicit_bzero(digest, sizeof(digest)); ++ free(sigb); + sshbuf_free(sigbuf); + sshbuf_free(b); + ECDSA_SIG_free(esig); +@@ -375,6 +408,79 @@ + 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; ++} ++ + /* NB. not static; used by ECDSA-SK */ + const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { + /* .size = */ ssh_ecdsa_size, +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/sshkey.c openssh-9.3p1-patched/sshkey.c +--- openssh-9.3p1/sshkey.c 2023-06-06 15:53:36.608444190 +0200 ++++ openssh-9.3p1-patched/sshkey.c 2023-06-06 15:52:25.625551756 +0200 +@@ -34,6 +34,8 @@ + #include + #include + #include ++#include ++#include + #endif + + #include "crypto_api.h" +@@ -575,6 +577,86 @@ + } + + #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; ++ size_t len; ++ ++ if (sigp == NULL || lenp == NULL) { ++ return SSH_ERR_INVALID_ARGUMENT; ++ } ++ ++ slen = EVP_PKEY_get_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_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; ++ } ++ ++ *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_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_DigestVerifyFinal(ctx, sigbuf, siglen); ++ 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) +@@ -3763,3 +3845,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-9.3p1/sshkey.h openssh-9.3p1-patched/sshkey.h +--- openssh-9.3p1/sshkey.h 2023-06-06 15:53:36.608444190 +0200 ++++ openssh-9.3p1-patched/sshkey.h 2023-06-06 15:52:25.626551768 +0200 +@@ -31,6 +31,9 @@ + #ifdef WITH_OPENSSL + #include + #include ++#include ++#include ++#include + # ifdef OPENSSL_HAS_ECC + # include + # include +@@ -266,6 +266,10 @@ + const char *sshkey_ssh_name_plain(const struct sshkey *); + int sshkey_names_valid2(const char *, int, 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 **); +@@ -324,6 +331,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 sshkey_sk_fields_equal(const struct sshkey *a, const struct sshkey *b); + void sshkey_sk_cleanup(struct sshkey *k); +@@ -338,6 +352,10 @@ + #endif + #endif + ++#ifdef ENABLE_PKCS11 ++int pkcs11_get_ecdsa_idx(void); ++#endif ++ + #if !defined(WITH_OPENSSL) + # undef RSA + # undef DSA +diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c +--- a/ssh-pkcs11.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/ssh-pkcs11.c (date 1703110934679) +@@ -620,8 +620,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 /* OPENSSL_HAS_ECC && 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. Note, that this does NOT guarantee the buffer + * will be null terminated if there are no trailing spaces! */ + static char * +diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c +--- a/ssh-pkcs11-client.c (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/ssh-pkcs11-client.c (date 1703110830967) +@@ -402,8 +402,36 @@ + if (helper->nrsa == 0 && helper->nec == 0) + helper_terminate(helper); + } ++ ++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 /* defined(OPENSSL_HAS_ECC) && defined(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 helper *helper, struct sshkey *k) +diff --git a/ssh-pkcs11.h b/ssh-pkcs11.h +--- a/ssh-pkcs11.h (revision 8241b9c0529228b4b86d88b1a6076fb9f97e4a99) ++++ b/ssh-pkcs11.h (date 1703111023334) +@@ -38,6 +38,12 @@ + /* Only available in ssh-pkcs11-client.c so far */ + int pkcs11_make_cert(const struct sshkey *, + const struct sshkey *, struct sshkey **); ++ ++#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-9.3p1/ssh-rsa.c openssh-9.3p1-patched/ssh-rsa.c +--- openssh-9.3p1/ssh-rsa.c 2023-03-15 22:28:19.000000000 +0100 ++++ openssh-9.3p1-patched/ssh-rsa.c 2023-06-06 15:52:25.627551781 +0200 +@@ -23,6 +23,8 @@ + + #include + #include ++#include ++#include + + #include + #include +@@ -36,10 +36,13 @@ + #include "sshkey.h" + #include "digest.h" + #include "log.h" ++#ifdef ENABLE_PKCS11 ++#include "ssh-pkcs11.h" ++#endif + + #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 u_int + ssh_rsa_size(const struct sshkey *key) +@@ -131,27 +133,50 @@ + static int + ssh_rsa_generate(struct sshkey *k, int bits) + { +- RSA *private = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ EVP_PKEY *res = NULL; + BIGNUM *f4 = NULL; + int ret = SSH_ERR_INTERNAL_ERROR; + + if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE || + bits > SSHBUF_MAX_BIGNUM * 8) + return SSH_ERR_KEY_LENGTH; +- 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*/ ++ k->rsa = EVP_PKEY_get1_RSA(res); ++ if (k->rsa) { ++ ret = 0; ++ } else { + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- k->rsa = private; +- private = NULL; +- ret = 0; + out: +- RSA_free(private); ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(res); + BN_free(f4); + return ret; + } +@@ -317,21 +342,6 @@ + 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) + { +@@ -393,11 +403,10 @@ + const u_char *data, size_t datalen, + const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) + { +- const BIGNUM *rsa_n; +- u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; +- size_t slen = 0; +- u_int hlen, 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) +@@ -409,33 +418,33 @@ + hash_alg = SSH_DIGEST_SHA1; + else + hash_alg = rsa_hash_id_from_keyname(alg); ++ + 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 ((hlen = 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; +- goto out; ++#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 + } +- +- if (RSA_sign(nid, digest, hlen, sig, &len, key->rsa) != 1) { +- ret = SSH_ERR_LIBCRYPTO_ERROR; ++#endif ++ ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, ++ datalen); ++ EVP_PKEY_free(pkey); ++ if (ret < 0) { + goto out; + } ++ + if (len < slen) { + size_t diff = slen - len; + memmove(sig + diff, sig, len); +@@ -444,6 +453,7 @@ + ret = SSH_ERR_INTERNAL_ERROR; + goto out; + } ++ + /* encode signature */ + if ((b = sshbuf_new()) == NULL) { + ret = SSH_ERR_ALLOC_FAIL; +@@ -464,7 +474,6 @@ + *lenp = len; + ret = 0; + out: +- explicit_bzero(digest, sizeof(digest)); + freezero(sig, slen); + sshbuf_free(b); + return ret; +@@ -476,10 +485,10 @@ + const u_char *data, size_t dlen, const char *alg, u_int compat, + struct sshkey_sig_details **detailsp) + { +- 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, hlen; ++ size_t len = 0, diff, modlen; + struct sshbuf *b = NULL; + u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; + +@@ -487,8 +496,7 @@ + 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) +@@ -540,16 +548,13 @@ + explicit_bzero(sigblob, diff); + len = modlen; + } +- if ((hlen = ssh_digest_bytes(hash_alg)) == 0) { +- ret = SSH_ERR_INTERNAL_ERROR; +- goto out; +- } +- if ((ret = ssh_digest_memory(hash_alg, data, dlen, +- digest, sizeof(digest))) != 0) ++ ++ if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) + goto out; + +- ret = openssh_RSA_verify(hash_alg, digest, hlen, sigblob, len, +- key->rsa); ++ ret = openssh_RSA_verify(hash_alg, data, dlen, sigblob, len, pkey); ++ EVP_PKEY_free(pkey); ++ + out: + freezero(sigblob, len); + free(sigtype); +@@ -558,125 +563,110 @@ + 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; ++ 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; +- } +- 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; + 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; + } + ++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; ++} ++ + static const struct sshkey_impl_funcs sshkey_rsa_funcs = { + /* .size = */ ssh_rsa_size, + /* .alloc = */ ssh_rsa_alloc, diff --git a/openssh-9.3p1-openssl-compat.patch b/openssh-9.3p1-openssl-compat.patch new file mode 100644 index 0000000..cf512ef --- /dev/null +++ b/openssh-9.3p1-openssl-compat.patch @@ -0,0 +1,40 @@ +--- 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 --git a/openssh-9.3p1-upstream-cve-2023-38408.patch b/openssh-9.3p1-upstream-cve-2023-38408.patch new file mode 100644 index 0000000..e9ac2ae --- /dev/null +++ b/openssh-9.3p1-upstream-cve-2023-38408.patch @@ -0,0 +1,130 @@ +diff --git a/ssh-agent.c b/ssh-agent.c +index 618bb198..8ea831f4 100644 +diff -up openssh-9.3p1/ssh-agent.c.cve openssh-9.3p1/ssh-agent.c +--- openssh-9.3p1/ssh-agent.c.cve 2023-07-21 15:38:13.237276580 +0200 ++++ openssh-9.3p1/ssh-agent.c 2023-07-21 15:41:30.269943569 +0200 +@@ -169,6 +169,12 @@ char socket_dir[PATH_MAX]; + /* Pattern-list of allowed PKCS#11/Security key paths */ + static char *allowed_providers; + ++/* ++ * Allows PKCS11 providers or SK keys that use non-internal providers to ++ * be added over a remote connection (identified by session-bind@openssh.com). ++ */ ++static int remote_add_provider; ++ + /* locking */ + #define LOCK_SIZE 32 + #define LOCK_SALT_SIZE 16 +@@ -1228,6 +1234,12 @@ process_add_identity(SocketEntry *e) + if (strcasecmp(sk_provider, "internal") == 0) { + debug_f("internal provider"); + } else { ++ if (e->nsession_ids != 0 && !remote_add_provider) { ++ verbose("failed add of SK provider \"%.100s\": " ++ "remote addition of providers is disabled", ++ sk_provider); ++ goto out; ++ } + if (realpath(sk_provider, canonical_provider) == NULL) { + verbose("failed provider \"%.100s\": " + "realpath: %s", sk_provider, +@@ -1368,7 +1380,7 @@ no_identities(SocketEntry *e) + + #ifdef ENABLE_PKCS11 + static char * +-sanitize_pkcs11_provider(const char *provider) ++sanitize_pkcs11_provider(SocketEntry *e, const char *provider) + { + struct pkcs11_uri *uri = NULL; + char *sane_uri, *module_path = NULL; /* default path */ +@@ -1399,6 +1411,11 @@ sanitize_pkcs11_provider(const char *pro + module_path = strdup(provider); /* simple path */ + + if (module_path != NULL) { /* do not validate default NULL path in URI */ ++ if (e->nsession_ids != 0 && !remote_add_provider) { ++ verbose("failed PKCS#11 add of \"%.100s\": remote addition of " ++ "providers is disabled", provider); ++ return NULL; ++ } + if (realpath(module_path, canonical_provider) == NULL) { + verbose("failed PKCS#11 provider \"%.100s\": realpath: %s", + module_path, strerror(errno)); +@@ -1455,7 +1472,7 @@ process_add_smartcard_key(SocketEntry *e + goto send; + } + +- sane_uri = sanitize_pkcs11_provider(provider); ++ sane_uri = sanitize_pkcs11_provider(e, provider); + if (sane_uri == NULL) + goto send; + +@@ -1516,7 +1533,7 @@ process_remove_smartcard_key(SocketEntry + } + free(pin); + +- sane_uri = sanitize_pkcs11_provider(provider); ++ sane_uri = sanitize_pkcs11_provider(e, provider); + if (sane_uri == NULL) + goto send; + +@@ -2108,7 +2125,9 @@ main(int ac, char **av) + break; + case 'O': + if (strcmp(optarg, "no-restrict-websafe") == 0) +- restrict_websafe = 0; ++ restrict_websafe = 0; ++ else if (strcmp(optarg, "allow-remote-pkcs11") == 0) ++ remote_add_provider = 1; + else + fatal("Unknown -O option"); + break; +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 */ +--- a/ssh-agent.1 2023-03-15 22:28:19.000000000 +0100 ++++ b/ssh-agent.1 2023-07-19 21:39:17.981406432 +0200 +@@ -107,9 +107,27 @@ + .It Fl O Ar option + Specify an option when starting + .Nm . +-Currently only one option is supported: ++Currently two options are supported: ++.Cm allow-remote-pkcs11 ++and + .Cm no-restrict-websafe . +-This instructs ++.Pp ++The ++.Cm allow-remote-pkcs11 ++option allows clients of a forwarded ++.Nm ++to load PKCS#11 or FIDO provider libraries. ++By default only local clients may perform this operation. ++Note that signalling that a ++.Nm ++client remote is performed by ++.Xr ssh 1 , ++and use of other tools to forward access to the agent socket may circumvent ++this restriction. ++.Pp ++The ++.Cm no-restrict-websafe , ++instructs + .Nm + to permit signatures using FIDO keys that might be web authentication + requests. diff --git a/openssh.rpmlintrc b/openssh.rpmlintrc index 7031b2b..2404235 100644 --- a/openssh.rpmlintrc +++ b/openssh.rpmlintrc @@ -2,7 +2,9 @@ addFilter(r'openssh-askpass.x86_64: W: non-conffile-in-etc /etc/profile.d/gnome-ssh-askpass.c?sh') # The ssh-keysign is not supposed to have standard permissions -addFilter(r'openssh.x86_64: E: non-standard-executable-perm /usr/libexec/openssh/ssh-keysign 4555') +addFilter(r'openssh.x86_64: E: non-standard-executable-perm /usr/libexec/openssh/ssh-keysign 2555') +addFilter(r'openssh.x86_64: E: setgid-binary /usr/libexec/openssh/ssh-keysign ssh_keys 2555') +addFilter(r'openssh.x86_64: W: non-standard-gid /usr/libexec/openssh/ssh-keysign ssh_keys') # The -cavs subpackage is internal without documentation # The -askpass is not intended to be used directly so it is missing documentation diff --git a/openssh.spec b/openssh.spec index ff38f4b..6ba18b8 100644 --- a/openssh.spec +++ b/openssh.spec @@ -25,6 +25,13 @@ # Do we want libedit support %global libedit 1 +# Whether to build pam_ssh_agent_auth +%if 0%{?!nopam:1} +%global pam_ssh_agent 1 +%else +%global pam_ssh_agent 0 +%endif + # Reserve options to override askpass settings with: # rpm -ba|--rebuild --define 'skip_xxx 1' %{?skip_gnome_askpass:%global no_gnome_askpass 1} @@ -38,17 +45,24 @@ # rpm -ba|--rebuild --define "static_openssl 1" %{?static_openssl:%global static_libcrypto 1} -%global openssh_ver 10.2p1 +# Do not forget to bump pam_ssh_agent_auth release if you rewind the main package release to 1 +%global openssh_ver 9.6p1 +%global openssh_rel 1 +%global pam_ssh_agent_ver 0.10.4 +%global pam_ssh_agent_rel 9 Summary: An open source implementation of SSH protocol version 2 Name: openssh Version: %{openssh_ver} -Release: 1%{?dist} +Release: %{openssh_rel}%{?dist} URL: http://www.openssh.com/portable.html +#URL1: https://github.com/jbeverly/pam_ssh_agent_auth/ Source0: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz Source1: ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-%{version}.tar.gz.asc Source2: sshd.pam Source3: gpgkey-736060BA.gpg +Source4: https://github.com/jbeverly/pam_ssh_agent_auth/archive/pam_ssh_agent_auth-%{pam_ssh_agent_ver}.tar.gz +Source5: pam_ssh_agent-rmheaders Source6: ssh-keycat.pam Source7: sshd.sysconfig Source9: sshd@.service @@ -62,123 +76,161 @@ Source17: ssh-agent.socket Source19: openssh-server-systemd-sysusers.conf Source20: ssh-host-keys-migration.sh Source21: ssh-host-keys-migration.service -Source22: parallel_test.sh -Source23: parallel_test.Makefile + +#https://bugzilla.mindrot.org/show_bug.cgi?id=2581 +Patch100: openssh-6.7p1-coverity.patch + +#https://bugzilla.mindrot.org/show_bug.cgi?id=1402 +# https://bugzilla.redhat.com/show_bug.cgi?id=1171248 +# record pfs= field in CRYPTO_SESSION audit event +Patch200: openssh-7.6p1-audit.patch +# Audit race condition in forked child (#1310684) +Patch201: openssh-7.1p2-audit-race-condition.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2049947 +Patch202: openssh-9.0p1-audit-log.patch + +# --- pam_ssh-agent --- +# make it build reusing the openssh sources +Patch300: pam_ssh_agent_auth-0.9.3-build.patch +# check return value of seteuid() +# https://sourceforge.net/p/pamsshagentauth/bugs/23/ +Patch301: pam_ssh_agent_auth-0.10.3-seteuid.patch +# explicitly make pam callbacks visible +Patch302: pam_ssh_agent_auth-0.9.2-visibility.patch +# update to current version of agent structure +Patch305: pam_ssh_agent_auth-0.9.3-agent_structure.patch +# remove prefixes to be able to build against current openssh library +Patch306: pam_ssh_agent_auth-0.10.2-compat.patch +# Fix NULL dereference from getpwuid() return value +# https://sourceforge.net/p/pamsshagentauth/bugs/22/ +Patch307: pam_ssh_agent_auth-0.10.2-dereference.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2070113 +Patch308: pam_ssh_agent_auth-0.10.4-rsasha2.patch +Patch309: pam_ssh_agent-configure-c99.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1641 (WONTFIX) -Patch0001: 0001-openssh-7.8p1-role-mls.patch -Patch0002: 0002-openssh-6.6p1-keycat.patch +Patch400: openssh-7.8p1-role-mls.patch +#https://bugzilla.redhat.com/show_bug.cgi?id=781634 +Patch404: openssh-6.6p1-privsep-selinux.patch +#? +Patch502: openssh-6.6p1-keycat.patch + #https://bugzilla.mindrot.org/show_bug.cgi?id=1644 -Patch0003: 0003-openssh-6.6p1-allow-ip-opts.patch +Patch601: openssh-6.6p1-allow-ip-opts.patch #(drop?) https://bugzilla.mindrot.org/show_bug.cgi?id=1925 -Patch0004: 0004-openssh-5.9p1-ipv6man.patch -Patch0005: 0005-openssh-5.8p2-sigpipe.patch -Patch0006: 0006-openssh-7.2p2-x11.patch -Patch0007: 0007-openssh-5.1p1-askpass-progress.patch +Patch606: openssh-5.9p1-ipv6man.patch +#? +Patch607: openssh-5.8p2-sigpipe.patch +#https://bugzilla.mindrot.org/show_bug.cgi?id=1789 +Patch609: openssh-7.2p2-x11.patch + +#? +Patch700: openssh-7.7p1-fips.patch +#? +Patch702: openssh-5.1p1-askpass-progress.patch #https://bugzilla.redhat.com/show_bug.cgi?id=198332 -Patch0008: 0008-openssh-4.3p2-askpass-grab-info.patch +Patch703: openssh-4.3p2-askpass-grab-info.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1635 (WONTFIX) -Patch0009: 0009-openssh-8.7p1-redhat.patch +Patch707: openssh-7.7p1-redhat.patch # warn users for unsupported UsePAM=no (#757545) -Patch0010: 0010-openssh-7.8p1-UsePAM-warning.patch +Patch711: openssh-7.8p1-UsePAM-warning.patch + # GSSAPI Key Exchange (RFC 4462 + RFC 8732) -Patch0011: 0011-openssh-9.6p1-gssapi-keyex.patch +# from https://github.com/openssh-gsskex/openssh-gsskex/tree/fedora/master +# and +# Reenable MONITOR_REQ_GSSCHECKMIC after gssapi-with-mic failures +# upstream MR: +# https://github.com/openssh-gsskex/openssh-gsskex/pull/21 +Patch800: openssh-8.0p1-gssapi-keyex.patch #http://www.mail-archive.com/kerberos@mit.edu/msg17591.html -Patch0012: 0012-openssh-6.6p1-force_krb.patch -# Improve ccache handling in openssh (#991186, #1199363, #1566494) -# https://bugzilla.mindrot.org/show_bug.cgi?id=2775 -Patch0013: 0013-openssh-7.7p1-gssapi-new-unique.patch -# Respect k5login_directory option in krk5.conf (#1328243) -Patch0014: 0014-openssh-7.2p2-k5login_directory.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=1780 -Patch0015: 0015-openssh-6.6p1-kuserok.patch -# Use tty allocation for a remote scp (#985650) -Patch0016: 0016-openssh-6.4p1-fromto-remote.patch -# log via monitor in chroots without /dev/log (#2681) -Patch0017: 0017-openssh-6.6.1p1-log-in-chroot.patch -# scp file into non-existing directory (#1142223) -Patch0018: 0018-openssh-6.6.1p1-scp-non-existing-directory.patch +Patch801: openssh-6.6p1-force_krb.patch # add new option GSSAPIEnablek5users and disable using ~/.k5users by default (#1169843) # CVE-2014-9278 -Patch0019: 0019-openssh-6.6p1-GSSAPIEnablek5users.patch +Patch802: openssh-6.6p1-GSSAPIEnablek5users.patch +# Improve ccache handling in openssh (#991186, #1199363, #1566494) +# https://bugzilla.mindrot.org/show_bug.cgi?id=2775 +Patch804: openssh-7.7p1-gssapi-new-unique.patch +# Respect k5login_directory option in krk5.conf (#1328243) +Patch805: openssh-7.2p2-k5login_directory.patch + + +#https://bugzilla.mindrot.org/show_bug.cgi?id=1780 +Patch901: openssh-6.6p1-kuserok.patch +# Use tty allocation for a remote scp (#985650) +Patch906: openssh-6.4p1-fromto-remote.patch +# privsep_preauth: use SELinux context from selinux-policy (#1008580) +Patch916: openssh-6.6.1p1-selinux-contexts.patch +# log via monitor in chroots without /dev/log (#2681) +Patch918: openssh-6.6.1p1-log-in-chroot.patch +# scp file into non-existing directory (#1142223) +Patch919: openssh-6.6.1p1-scp-non-existing-directory.patch # apply upstream patch and make sshd -T more consistent (#1187521) -Patch0020: 0020-openssh-6.8p1-sshdT-output.patch +Patch922: openssh-6.8p1-sshdT-output.patch # Add sftp option to force mode of created files (#1191055) -Patch0021: 0021-openssh-6.7p1-sftp-force-permission.patch +Patch926: openssh-6.7p1-sftp-force-permission.patch # make s390 use /dev/ crypto devices -- ignore closefrom -Patch0022: 0022-openssh-7.2p2-s390-closefrom.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 -Patch0023: 0023-openssh-7.6p1-cleanup-selinux.patch +Patch949: openssh-7.6p1-cleanup-selinux.patch # Sandbox adjustments for s390 and audit -Patch0024: 0024-openssh-7.5p1-sandbox.patch +Patch950: openssh-7.5p1-sandbox.patch +# PKCS#11 URIs (upstream #2817, 2nd iteration) +# https://github.com/Jakuje/openssh-portable/commits/jjelen-pkcs11 +# git show > ~/devel/fedora/openssh/openssh-8.0p1-pkcs11-uri.patch +Patch951: openssh-8.0p1-pkcs11-uri.patch # Unbreak scp between two IPv6 hosts (#1620333) -Patch0025: 0025-openssh-7.8p1-scp-ipv6.patch +Patch953: openssh-7.8p1-scp-ipv6.patch # Mention crypto-policies in manual pages (#1668325) # clarify rhbz#2068423 on the man page of ssh_config -Patch0026: 0026-openssh-8.0p1-crypto-policies.patch +Patch962: openssh-8.0p1-crypto-policies.patch +# Use OpenSSL high-level API to produce and verify signatures (#1707485) +# TODO fix the comment above ^ +Patch963: openssh-9.3p1-merged-openssl-evp.patch # Use OpenSSL KDF (#1631761) -Patch0027: 0027-openssh-8.0p1-openssl-kdf.patch +Patch964: openssh-8.0p1-openssl-kdf.patch # sk-dummy.so built with -fvisibility=hidden does not work -Patch0028: 0028-openssh-8.2p1-visibility.patch +Patch965: openssh-8.2p1-visibility.patch # Do not break X11 without IPv6 -Patch0029: 0029-openssh-8.2p1-x11-without-ipv6.patch +Patch966: openssh-8.2p1-x11-without-ipv6.patch +# ssh-keygen printing fingerprint issue with Windows keys (#1901518) +Patch974: openssh-8.0p1-keygen-strip-doseol.patch # sshd provides PAM an incorrect error code (#1879503) -Patch0030: 0030-openssh-8.0p1-preserve-pam-errors.patch +Patch975: openssh-8.0p1-preserve-pam-errors.patch + # Implement kill switch for SCP protocol -Patch0031: 0031-openssh-8.7p1-scp-kill-switch.patch +Patch977: openssh-8.7p1-scp-kill-switch.patch + # Workaround for lack of sftp_realpath in older versions of RHEL # https://bugzilla.redhat.com/show_bug.cgi?id=2038854 # https://github.com/openssh/openssh-portable/pull/299 # downstream only -Patch0032: 0032-openssh-8.7p1-recursive-scp.patch -# Downstream alias for MinRSABits -Patch0033: 0033-openssh-8.7p1-minrsabits.patch +Patch981: openssh-8.7p1-recursive-scp.patch +# https://github.com/djmdjm/openssh-wip/pull/13 +Patch982: openssh-8.7p1-minrsabits.patch # downstream only, IBMCA tentative fix # From https://bugzilla.redhat.com/show_bug.cgi?id=1976202#c14 -Patch0034: 0034-openssh-8.7p1-ibmca.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=1402 -# https://bugzilla.redhat.com/show_bug.cgi?id=1171248 -# record pfs= field in CRYPTO_SESSION audit event -Patch0035: 0035-openssh-7.6p1-audit.patch -# Audit race condition in forked child (#1310684) -Patch0036: 0036-openssh-7.1p2-audit-race-condition.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=2049947 -Patch0037: 0037-openssh-9.0p1-audit-log.patch -Patch0038: 0038-openssh-7.7p1-fips.patch +Patch984: openssh-8.7p1-ibmca.patch + # Add missing options from ssh_config into ssh manpage # upstream bug: # https://bugzilla.mindrot.org/show_bug.cgi?id=3455 -Patch0039: 0039-openssh-8.7p1-ssh-manpage.patch +Patch1002: openssh-8.7p1-ssh-manpage.patch + # Don't propose disallowed algorithms during hostkey negotiation # upstream MR: # https://github.com/openssh/openssh-portable/pull/323 -Patch0040: 0040-openssh-8.7p1-negotiate-supported-algs.patch -Patch0041: 0041-openssh-9.0p1-evp-fips-kex.patch -Patch0042: 0042-openssh-8.7p1-nohostsha1proof.patch -Patch0043: 0043-openssh-9.9p1-separate-keysign.patch -Patch0044: 0044-openssh-9.9p1-openssl-mlkem.patch -# https://www.openwall.com/lists/oss-security/2025/02/22/1 -Patch0045: 0045-openssh-9.9p2-error_processing.patch -# https://github.com/openssh/openssh-portable/pull/564 -Patch0046: 0046-Provide-better-error-for-non-supported-private-keys.patch -# https://github.com/openssh/openssh-portable/pull/567 -Patch0047: 0047-Ignore-bad-hostkeys-in-known_hosts-file.patch -# https://github.com/openssh/openssh-portable/pull/500 -Patch0048: 0048-support-authentication-indicators-in-GSSAPI.patch -Patch0049: 0049-NIST-curves-hybrid-KEX-implementation.patch -# landed upstream, to be removed after 10.3 -Patch0050: 0050-Provide-a-way-to-disable-GSSAPIDelegateCredentials-s.patch -# Move MAX_DISPLAYS to a configuration option (#1341302) -Patch0051: 0051-openssh-7.3p1-x11-max-displays.patch -# PKCS#11 URIs (upstream #2817, seriously reworked on rebasing to 10.2) -# https://github.com/Jakuje/openssh-portable/commits/jjelen-pkcs11 -Patch0052: 0052-openssh-10.2p1-pkcs11-uri.patch -#https://bugzilla.mindrot.org/show_bug.cgi?id=2581 -Patch1000: 1000-openssh-6.7p1-coverity.patch +Patch1006: openssh-8.7p1-negotiate-supported-algs.patch + +Patch1012: openssh-9.0p1-evp-fips-dh.patch +Patch1013: openssh-9.0p1-evp-fips-ecdh.patch +Patch1014: openssh-8.7p1-nohostsha1proof.patch License: BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND sprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant Requires: /sbin/nologin -Requires: openssl-libs >= 3.5.0 %if ! %{no_gnome_askpass} BuildRequires: libX11-devel @@ -193,14 +245,13 @@ BuildRequires: autoconf, automake, perl-interpreter, perl-generators, zlib-devel BuildRequires: audit-libs-devel >= 2.0.5 BuildRequires: util-linux, groff BuildRequires: pam-devel -BuildRequires: openssl-devel >= 3.5.0 +BuildRequires: openssl-devel >= 0.9.8j BuildRequires: perl-podlators BuildRequires: systemd-devel BuildRequires: systemd-rpm-macros BuildRequires: gcc make BuildRequires: p11-kit-devel BuildRequires: libfido2-devel -BuildRequires: libxcrypt-devel Recommends: p11-kit Obsoletes: openssh-ldap < 8.3p1-4 Obsoletes: openssh-cavs < 8.4p1-5 @@ -229,10 +280,6 @@ Summary: An open source SSH client applications Requires: openssh = %{version}-%{release} Requires: crypto-policies >= 20220824-1 -%package keysign -Summary: A helper program used for host-based authentication -Requires: openssh = %{version}-%{release} - %package server Summary: An open source SSH server daemon Requires: openssh = %{version}-%{release} @@ -253,6 +300,12 @@ Requires: openssh = %{version}-%{release} Summary: OpenSSH SK driver for test purposes Requires: openssh = %{version}-%{release} +%package -n pam_ssh_agent_auth +Summary: PAM module for authentication with ssh-agent +Version: %{pam_ssh_agent_ver} +Release: %{pam_ssh_agent_rel}.%{openssh_rel}%{?dist} +License: BSD-3-Clause AND BSD-2-Clause AND ISC AND SSH-OpenSSH AND ssh-keyscan AND sprintf AND LicenseRef-Fedora-Public-Domain AND X11-distribute-modifications-variant AND OpenSSL + %description SSH (Secure SHell) is a program for logging into and executing commands on a remote machine. SSH is intended to replace rlogin and @@ -272,11 +325,6 @@ OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package includes the clients necessary to make encrypted connections to SSH servers. -%description keysign -OpenSSH is a free version of SSH (Secure SHell), a program for logging -into and executing commands on a remote machine. ssh-keysign is a -helper program used for host-based authentication disabled by default. - %description server OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package contains @@ -295,14 +343,106 @@ an X11 passphrase dialog for OpenSSH. %description sk-dummy This package contains a test SK driver used for OpenSSH test purposes +%description -n pam_ssh_agent_auth +This package contains a PAM module which can be used to authenticate +users using ssh keys stored in a ssh-agent. Through the use of the +forwarding of ssh-agent connection it also allows to authenticate with +remote ssh-agent instance. + +The module is most useful for su and sudo service stacks. + %prep gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0} -%autosetup -T -b 0 -p1 +%setup -q -a 4 + +%if %{pam_ssh_agent} +pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} +%patch -P 300 -p2 -b .psaa-build +%patch -P 301 -p2 -b .psaa-seteuid +%patch -P 302 -p2 -b .psaa-visibility +%patch -P 306 -p2 -b .psaa-compat +%patch -P 305 -p2 -b .psaa-agent +%patch -P 307 -p2 -b .psaa-deref +%patch -P 308 -p2 -b .rsasha2 +%patch -P 309 -p1 -b .psaa-configure-c99 +# Remove duplicate headers and library files +rm -f $(cat %{SOURCE5}) +popd +%endif + +%patch -P 400 -p1 -b .role-mls +%patch -P 404 -p1 -b .privsep-selinux + +%patch -P 502 -p1 -b .keycat + +%patch -P 601 -p1 -b .ip-opts +%patch -P 606 -p1 -b .ipv6man +%patch -P 607 -p1 -b .sigpipe +%patch -P 609 -p1 -b .x11 +%patch -P 702 -p1 -b .progress +%patch -P 703 -p1 -b .grab-info +%patch -P 707 -p1 -b .redhat +%patch -P 711 -p1 -b .log-usepam-no +# +%patch -P 800 -p1 -b .gsskex +%patch -P 801 -p1 -b .force_krb +%patch -P 804 -p1 -b .ccache_name +%patch -P 805 -p1 -b .k5login +# +%patch -P 901 -p1 -b .kuserok +%patch -P 906 -p1 -b .fromto-remote +%patch -P 916 -p1 -b .contexts +%patch -P 918 -p1 -b .log-in-chroot +%patch -P 919 -p1 -b .scp +%patch -P 802 -p1 -b .GSSAPIEnablek5users +%patch -P 922 -p1 -b .sshdt +%patch -P 926 -p1 -b .sftp-force-mode +%patch -P 939 -p1 -b .s390-dev +%patch -P 944 -p1 -b .x11max +%patch -P 948 -p1 -b .systemd +%patch -P 949 -p1 -b .refactor +%patch -P 950 -p1 -b .sandbox +%patch -P 951 -p1 -b .pkcs11-uri +%patch -P 953 -p1 -b .scp-ipv6 +%patch -P 962 -p1 -b .crypto-policies +%patch -P 963 -p1 -b .openssl-evp +%patch -P 964 -p1 -b .openssl-kdf +%patch -P 965 -p1 -b .visibility +%patch -P 966 -p1 -b .x11-ipv6 +%patch -P 974 -p1 -b .keygen-strip-doseol +%patch -P 975 -p1 -b .preserve-pam-errors + +%patch -P 977 -p1 -b .kill-scp + +%patch -P 981 -p1 -b .scp-sftpdirs +%patch -P 982 -p1 -b .minrsabits +%patch -P 984 -p1 -b .ibmca + +%patch -P 200 -p1 -b .audit +%patch -P 201 -p1 -b .audit-race +%patch -P 202 -p1 -b .audit-log +%patch -P 700 -p1 -b .fips + +%patch -P 1002 -p1 -b .ssh-manpage + +%patch -P 1006 -p1 -b .negotiate-supported-algs + +%patch -P 1012 -p1 -b .evp-fips-dh +%patch -P 1013 -p1 -b .evp-fips-ecdh +%patch -P 1014 -p1 -b .nosha1hostproof + +%patch -P 100 -p1 -b .coverity autoreconf +pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} +autoreconf +popd %build %set_build_flags +# the -fvisibility=hidden is needed for clean build of the pam_ssh_agent_auth +# it is needed for lib(open)ssh build too since it is linked to the pam module too +CFLAGS="$CFLAGS -fvisibility=hidden"; export CFLAGS %if %{pie} %ifarch s390 s390x sparc sparcv9 sparc64 CFLAGS="$CFLAGS -fPIC" @@ -336,14 +476,16 @@ fi --sysconfdir=%{_sysconfdir}/ssh \ --libexecdir=%{_libexecdir}/openssh \ --datadir=%{_datadir}/openssh \ - --with-default-path=/usr/local/bin:/usr/bin \ - --with-superuser-path=/usr/local/bin:/usr/bin \ + --with-default-path=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin \ + --with-superuser-path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin \ --with-privsep-path=%{_datadir}/empty.sshd \ --disable-strip \ --without-zlib-version-check \ + --with-ssl-engine \ --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 \ @@ -391,9 +533,22 @@ fi popd %endif +%if %{pam_ssh_agent} +pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} +LDFLAGS="$SAVE_LDFLAGS" +%configure --with-selinux \ + --libexecdir=/%{_libdir}/security \ + --with-mantype=man \ + --without-openssl-header-check `# The check is broken` +%make_build +popd +%endif + %check -OPENSSL_CONF=/dev/null %{SOURCE22} %{SOURCE23} # ./parallel_tests.sh parallel_tests.Makefile -#make tests +#to run tests use "--with check" +%if %{?_with_check:1}%{!?_with_check:0} +make tests +%endif %install rm -rf $RPM_BUILD_ROOT @@ -451,6 +606,12 @@ rm -f $RPM_BUILD_ROOT/etc/profile.d/gnome-ssh-askpass.* perl -pi -e "s|$RPM_BUILD_ROOT||g" $RPM_BUILD_ROOT%{_mandir}/man*/* +%if %{pam_ssh_agent} +pushd pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver} +%make_install +popd +%endif + install -m 755 -d $RPM_BUILD_ROOT%{_libdir}/sshtest/ install -m 755 regress/misc/sk-dummy/sk-dummy.so $RPM_BUILD_ROOT%{_libdir}/sshtest @@ -501,6 +662,8 @@ test -f %{sysconfig_anaconda} && \ %attr(0755,root,root) %{_bindir}/ssh-keygen %attr(0644,root,root) %{_mandir}/man1/ssh-keygen.1* %attr(0755,root,root) %dir %{_libexecdir}/openssh +%attr(4555,root,root) %{_libexecdir}/openssh/ssh-keysign +%attr(0644,root,root) %{_mandir}/man8/ssh-keysign.8* %files clients %attr(0755,root,root) %{_bindir}/ssh @@ -528,15 +691,9 @@ test -f %{sysconfig_anaconda} && \ %attr(0644,root,root) %{_userunitdir}/ssh-agent.service %attr(0644,root,root) %{_userunitdir}/ssh-agent.socket -%files keysign -%attr(4555,root,root) %{_libexecdir}/openssh/ssh-keysign -%attr(0644,root,root) %{_mandir}/man8/ssh-keysign.8* - %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/sshd-auth %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* @@ -568,183 +725,22 @@ test -f %{sysconfig_anaconda} && \ %files askpass %attr(0644,root,root) %{_sysconfdir}/profile.d/gnome-ssh-askpass.* %attr(0755,root,root) %{_libexecdir}/openssh/gnome-ssh-askpass -%{_libexecdir}/openssh/ssh-askpass +%attr(0755,root,root) %{_libexecdir}/openssh/ssh-askpass %endif %files sk-dummy %attr(0755,root,root) %{_libdir}/sshtest/sk-dummy.so +%if %{pam_ssh_agent} +%files -n pam_ssh_agent_auth +%license pam_ssh_agent_auth-pam_ssh_agent_auth-%{pam_ssh_agent_ver}/OPENSSH_LICENSE +%attr(0755,root,root) %{_libdir}/security/pam_ssh_agent_auth.so +%attr(0644,root,root) %{_mandir}/man8/pam_ssh_agent_auth.8* +%endif + %changelog -* Wed Dec 17 2025 Dmitry Belyavskiy - 10.2p1-1 -- Rebase to OpenSSH 10.2p1 - -* Wed Dec 10 2025 Pavol Žáčik - 10.0p1-10 -- Update gssapi-keyex patch to not abort KEX without hostkey - -* Mon Dec 01 2025 Dmitry Belyavskiy - 10.0p1-9 -- rebuilt - -* Mon Nov 03 2025 Dmitry Belyavskiy - 10.0p1-8 -- Implement mlkem768nistp256-sha256 and mlkem1024nistp384-sha384 KEX methods - -* Mon Sep 15 2025 Dmitry Belyavskiy - 10.0p1-7 -- rebuilt - -* Thu Aug 28 2025 Dmitry Belyavskiy - 10.0p1-6 -- Enable GSS KEX in FIPS mode - -* Thu Jul 24 2025 Fedora Release Engineering - 10.0p1-5 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild - -* Fri Jun 27 2025 Dmitry Belyavskiy - 10.0p1-4 -- Update sshd@.service to follow upstream, mostly support ephemeral sshd keys - Submitted by Allison Karlitskaya (https://src.fedoraproject.org/rpms/openssh/pull-request/101) - Needs a SELinux counterpart. - Related: rhbz#2374928 - -* Mon Jun 09 2025 Dmitry Belyavskiy - 10.0p1-3 -- Apply patches forgot in previous respin - -* Mon May 19 2025 Dmitry Belyavskiy - 10.0p1-2 -- Provide better diagnostics for non-supported private keys - (https://github.com/openssh/openssh-portable/pull/564) -- Ignore too short hostkeys in known_hosts file - (https://github.com/openssh/openssh-portable/pull/567) -- Switch to systemd-socket activation for ssh-agent - Resolves: rhbz#2181353 - -* Fri May 16 2025 Dmitry Belyavskiy - 10.0p1-1 -- Rebase to OpenSSH 10.0p1 - -* Thu Apr 17 2025 Dmitry Belyavskiy - 9.9p1-15 -- Require OpenSSL 3.5 to support PQ crypto -- Suppress systemd warning on restart sshd - -* Tue Mar 18 2025 Zbigniew Jędrzejewski-Szmek - 9.9p1-14 -- Remove /usr/local/sbin from the default path too - -* Tue Mar 18 2025 Dmitry Belyavskiy - 9.9p1-13 -- Remove /usr/sbin from the default path - Resolves: rhbz#2352387 -- Export and accept COLORTERM - Resolves: rhbz#2352653 - -* Thu Mar 06 2025 Dmitry Belyavskiy - 9.9p1-12 -- Update ssh-keysign permission for RPM linter - -* Wed Mar 05 2025 Dmitry Belyavskiy - 9.9p1-11 -- Use OpenSSL ML-KEM implementation instead of the native one - -* Tue Feb 25 2025 Dmitry Belyavskiy - 9.9p1-10 -- Some minor fixes from Rocky Linux - https://www.openwall.com/lists/oss-security/2025/02/22/1 - -* Tue Feb 18 2025 Dmitry Belyavskiy - 9.9p1-9 -- Fix regression of Match directive processing -- Fix missing error codes set and invalid error code checks in OpenSSH. It - prevents memory exhaustion attack and a MITM attack when VerifyHostKeyDNS - is on (CVE-2025-26465, CVE-2025-26466). - -* Sat Feb 01 2025 Björn Esser - 9.9p1-8.1 -- Add explicit BR: libxcrypt-devel - -* Wed Jan 29 2025 FeRD (Frank Dana) - 9.9p1-8 -- Replace deprecated (since 8.7) ChallengeResponseAuthentication - with KbdInteractiveAuthentication, in redhat sshd config - -* Mon Jan 27 2025 Dmitry Belyavskiy - 9.9p1-7 -- Fix regression of Match directive processing - Resolves: rhbz#2341769 - -* Mon Jan 27 2025 Dmitry Belyavskiy - 9.9p1-6 -- Remove pam-ssh-agent subcomponent - Resolves: rhbz#2338440 - -* Fri Jan 17 2025 Fedora Release Engineering - 9.9p1-5.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild - -* Mon Oct 28 2024 Dmitry Belyavskiy - 9.9p1-5 -- Fix MLKEM for BE platforms - -* Wed Oct 16 2024 Dmitry Belyavskiy - 9.9p1-4 -- Resolve memory management issues after rebase -- Define OPTIONS env in systemd modules (https://src.fedoraproject.org/rpms/openssh/pull-request/92) - -* Fri Oct 11 2024 Dmitry Belyavskiy - 9.9p1-3 -- Separate ssh-keysign to a dedicated package -- Use FIPS KEX defaults in FIPS mode - -* Thu Oct 10 2024 Dmitry Belyavskiy - 9.9p1-2 -- Update version of pam_ssh_agent_auth - -* Tue Oct 08 2024 Dmitry Belyavskiy - 9.9p1-1 -- Update to OpenSSH 9.9p1 - -* Tue Sep 03 2024 Dmitry Belyavskiy - 9.8p1-4 -- Synchronize patches from Red Hat - -* Mon Aug 05 2024 Dmitry Belyavskiy - 9.8p1-3 -- Sshd now proposes to enter password again when a non-existing user is specified - -* Fri Jul 26 2024 Dmitry Belyavskiy - 9.8p1-2 -- Change default key type in FIPS mode - -* Mon Jul 22 2024 Dmitry Belyavskiy - 9.8p1-1 -- Update to OpenSSH 9.8p1 - -* Thu Jul 18 2024 Fedora Release Engineering - 9.6p1-1.14 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild - -* Tue Jul 02 2024 Dmitry Belyavskiy - 9.6p1-1.13 -- rebuilt - -* Mon Jul 01 2024 Gordon Messmer - 9.6p1-12 -- Patch 9.6p1 for CVE-2024-6387 - -* Mon Jul 01 2024 Gordon Messmer - 9.6p1-11 -- Shorten paths used for parallel tests to fix BZ#2295117 - -* Thu May 09 2024 Zoltan Fridrich - 9.6p1-10 -- Correctly audit hostname and IP address -- Make default key sizes configurable in sshd-keygen - -* Wed Apr 24 2024 Dmitry Belyavskiy - 9.6p1-1.9 -- Use OpenSSL SSH KDF implementation - s390x fixup - -* Wed Apr 24 2024 Dmitry Belyavskiy - 9.6p1-1.8 -- Use OpenSSL SSH KDF implementation - -* Wed Apr 17 2024 Dmitry Belyavskiy - 9.6p1-1.7 -- Only set PAM_RHOST if the remote host is not "UNKNOWN" - https://src.fedoraproject.org/rpms/openssh/pull-request/71 - Patch by Daan De Meyer -- Some spec cleanup - https://src.fedoraproject.org/rpms/openssh/pull-request/74 - by Zbigniew Jędrzejewski-Szmek - -* Thu Apr 04 2024 Dmitry Belyavskiy - 9.6p1-1.6 -- rebuilt - -* Thu Apr 04 2024 Dmitry Belyavskiy - 9.6p1-1.5 -- rebuilt - -* Tue Apr 02 2024 Gordon Messmer - 9.6p1-1.4 -- Build OpenSSH without libsystemd dependency, using reference implementation - -* Wed Mar 13 2024 Dmitry Belyavskiy - 9.6p1-1.3 -- Build OpenSSH without engine support -- Make tests run at build phase (using parallel run mechanism by Alexander Sosedkin) - -* Thu Jan 25 2024 Fedora Release Engineering - 9.6p1-1.2 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - -* Sun Jan 21 2024 Fedora Release Engineering - 9.6p1-1.1 -- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild - * Tue Dec 26 2023 Daniel Milnes - 9.6p1-1 - Update to OpenSSH 9.6 - Original patches from https://src.fedoraproject.org/rpms/openssh/pull-request/63 - Tuned by Dmitry Belyavskiy for GSS and PKCS#11 URI processing * Fri Dec 22 2023 Florian Weimer - 9.3p1-13.1 - Fix type errors in downstream gssapi-keyex patch diff --git a/pam_ssh_agent-configure-c99.patch b/pam_ssh_agent-configure-c99.patch new file mode 100644 index 0000000..bc40434 --- /dev/null +++ b/pam_ssh_agent-configure-c99.patch @@ -0,0 +1,249 @@ +configure.ac: Improve C99 compatibility + +Future compilers will not support implicit declarations and implicit +ints by default. This means that configure probes which rely on them +will fail unconditionally, without actually testing anything. + +The changes mostly mirror what has been implemented in the openssh +repository, but had to be adapted somewhat because of drift between +the two versions of configure.ac. + +Sam James has submitted similar fixes upstream: + + + +diff --git a/configure.ac b/configure.ac +index 6496679..d927b62 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -500,10 +500,10 @@ int main(void) { exit(0); } + AC_DEFINE(HAVE_BUNDLE, 1, [Define if your system uses bundles instead of ELF shared objects]) + AC_MSG_CHECKING(if we have working getaddrinfo) + AC_TRY_RUN([#include +-main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) +- exit(0); ++int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) ++ return 0; + else +- exit(1); ++ return 1; + }], [AC_MSG_RESULT(working)], + [AC_MSG_RESULT(buggy) + AC_DEFINE(BROKEN_GETADDRINFO, 1, [getaddrinfo is broken (if present)])], +@@ -917,8 +917,8 @@ AC_SUBST(LDFLAGS_SHARED) + AC_MSG_CHECKING(compiler and flags for sanity) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([ +-#include +-int main(){exit(0);} ++#include ++int main(void){exit(0);} + ])], + [ AC_MSG_RESULT(yes) ], + [ +@@ -951,9 +951,9 @@ int main(int argc, char **argv) { + strncpy(buf,"/etc", 32); + s = dirname(buf); + if (!s || strncmp(s, "/", 32) != 0) { +- exit(1); ++ return 1; + } else { +- exit(0); ++ return 0; + } + } + ]])], +@@ -1102,7 +1102,7 @@ AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include + #include +-int main(void){struct dirent d;exit(sizeof(d.d_name)<=sizeof(char));} ++int main(void){struct dirent d;return sizeof(d.d_name)<=sizeof(char);} + ]])], + [AC_MSG_RESULT(yes)], + [ +@@ -1327,8 +1327,10 @@ AC_CHECK_FUNCS(setresuid, [ + AC_MSG_CHECKING(if setresuid seems to work) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ ++#define _GNU_SOURCE + #include + #include ++#include + int main(){errno=0; setresuid(0,0,0); if (errno==ENOSYS) exit(1); else exit(0);} + ]])], + [AC_MSG_RESULT(yes)], +@@ -1344,8 +1346,10 @@ AC_CHECK_FUNCS(setresgid, [ + AC_MSG_CHECKING(if setresgid seems to work) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ ++#define _GNU_SOURCE + #include + #include ++#include + int main(){errno=0; setresgid(0,0,0); if (errno==ENOSYS) exit(1); else exit(0);} + ]])], + [AC_MSG_RESULT(yes)], +@@ -1384,7 +1388,7 @@ if test "x$ac_cv_func_snprintf" = "xyes" ; then + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include +-int main(void){char b[5];snprintf(b,5,"123456789");exit(b[4]!='\0');} ++int main(void){char b[5];snprintf(b,5,"123456789");return b[4]!='\0';} + ]])], + [AC_MSG_RESULT(yes)], + [ +@@ -1418,7 +1422,7 @@ int x_snprintf(char *str,size_t count,const char *fmt,...) + int main(void) + { + char x[1]; +- exit(x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1); ++ return x_snprintf(x, 1, "%s %d", "hello", 12345) == 11 ? 0 : 1; + } ]])], + [AC_MSG_RESULT(yes)], + [ +@@ -1467,7 +1471,8 @@ AC_MSG_CHECKING([for (overly) strict mkstemp]) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include +-main() { char template[]="conftest.mkstemp-test"; ++#include ++int main(void) { char template[]="conftest.mkstemp-test"; + if (mkstemp(template) == -1) + exit(1); + unlink(template); exit(0); +@@ -1492,10 +1497,14 @@ if test ! -z "$check_for_openpty_ctty_bug"; then + AC_MSG_CHECKING(if openpty correctly handles controlling tty) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ ++#include + #include + #include + #include + #include ++#ifdef HAVE_PTY_H ++#include ++#endif + + int + main() +@@ -1543,6 +1552,7 @@ if test "x$ac_cv_func_getaddrinfo" = "xyes" && \ + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include ++#include + #include + #include + #include +@@ -1748,6 +1758,7 @@ AC_TRY_LINK_FUNC(RAND_add, AC_DEFINE(HAVE_OPENSSL, 1, + AC_MSG_CHECKING([OpenSSL header version]) + AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ ++#include + #include + #include + #include +@@ -1794,12 +1805,12 @@ int main(void) { + + fd = fopen(DATA,"w"); + if(fd == NULL) +- exit(1); ++ return 1; + + if ((rc = fprintf(fd ,"%x (%s)\n", SSLeay(), SSLeay_version(SSLEAY_VERSION))) <0) +- exit(1); ++ return 1; + +- exit(0); ++ return 0; + } + ]])], + [ +@@ -1829,7 +1840,7 @@ AC_RUN_IFELSE( + [AC_LANG_SOURCE([[ + #include + #include +-int main(void) { exit(SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1); } ++int main(void) { return SSLeay() == OPENSSL_VERSION_NUMBER ? 0 : 1; } + ]])], + [ + AC_MSG_RESULT(yes) +@@ -2598,7 +2609,7 @@ dnl test snprintf (broken on SCO w/gcc) + #include + #include + #ifdef HAVE_SNPRINTF +-main() ++int main(void) + { + char buf[50]; + char expected_out[50]; +@@ -2611,11 +2622,11 @@ main() + strcpy(expected_out, "9223372036854775807"); + snprintf(buf, mazsize, "%lld", num); + if(strcmp(buf, expected_out) != 0) +- exit(1); +- exit(0); ++ return 1; ++ return 0; + } + #else +-main() { exit(0); } ++int main(void) { return 0; } + #endif + ]])], [ true ], [ AC_DEFINE(BROKEN_SNPRINTF) ], + AC_MSG_WARN([cross compiling: Assuming working snprintf()]) +@@ -2746,11 +2757,11 @@ AC_CACHE_CHECK([for msg_accrights field in struct msghdr], + int main() { + #ifdef msg_accrights + #error "msg_accrights is a macro" +-exit(1); ++return 1; + #endif + struct msghdr m; + m.msg_accrights = 0; +-exit(0); ++return 0; + } + ])], + [ ac_cv_have_accrights_in_msghdr="yes" ], +@@ -2773,11 +2784,11 @@ AC_CACHE_CHECK([for msg_control field in struct msghdr], + int main() { + #ifdef msg_control + #error "msg_control is a macro" +-exit(1); ++return 1; + #endif + struct msghdr m; + m.msg_control = 0; +-exit(0); ++return 0; + } + ])], + [ ac_cv_have_control_in_msghdr="yes" ], +@@ -2791,7 +2802,7 @@ if test "x$ac_cv_have_control_in_msghdr" = "xyes" ; then + fi + + AC_CACHE_CHECK([if libc defines __progname], ac_cv_libc_defines___progname, [ +- AC_TRY_LINK([], ++ AC_TRY_LINK([#include ], + [ extern char *__progname; printf("%s", __progname); ], + [ ac_cv_libc_defines___progname="yes" ], + [ ac_cv_libc_defines___progname="no" ] +@@ -2871,7 +2882,7 @@ if test "x$ac_cv_have_getopt_optreset" = "xyes" ; then + fi + + AC_CACHE_CHECK([if libc defines sys_errlist], ac_cv_libc_defines_sys_errlist, [ +- AC_TRY_LINK([], ++ AC_TRY_LINK([#include ], + [ extern const char *const sys_errlist[]; printf("%s", sys_errlist[0]);], + [ ac_cv_libc_defines_sys_errlist="yes" ], + [ ac_cv_libc_defines_sys_errlist="no" ] +@@ -2884,7 +2895,7 @@ fi + + + AC_CACHE_CHECK([if libc defines sys_nerr], ac_cv_libc_defines_sys_nerr, [ +- AC_TRY_LINK([], ++ AC_TRY_LINK([#include ], + [ extern int sys_nerr; printf("%i", sys_nerr);], + [ ac_cv_libc_defines_sys_nerr="yes" ], + [ ac_cv_libc_defines_sys_nerr="no" ] diff --git a/pam_ssh_agent-rmheaders b/pam_ssh_agent-rmheaders new file mode 100644 index 0000000..ab5899f --- /dev/null +++ b/pam_ssh_agent-rmheaders @@ -0,0 +1,36 @@ +authfd.c +authfd.h +atomicio.c +atomicio.h +bufaux.c +bufbn.c +buffer.h +buffer.c +cleanup.c +cipher.h +compat.h +entropy.c +entropy.h +fatal.c +includes.h +kex.h +key.c +key.h +log.c +log.h +match.h +misc.c +misc.h +pathnames.h +platform.h +rsa.h +ssh-dss.c +ssh-rsa.c +ssh.h +ssh2.h +uidswap.c +uidswap.h +uuencode.c +uuencode.h +xmalloc.c +xmalloc.h diff --git a/pam_ssh_agent_auth-0.10.2-compat.patch b/pam_ssh_agent_auth-0.10.2-compat.patch new file mode 100644 index 0000000..0822b61 --- /dev/null +++ b/pam_ssh_agent_auth-0.10.2-compat.patch @@ -0,0 +1,992 @@ +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/get_command_line.c 2020-09-23 10:52:16.424001475 +0200 +@@ -27,6 +27,7 @@ + * or implied, of Jamie Beverly. + */ + ++#include + #include + #include + #include +@@ -66,8 +67,8 @@ proc_pid_cmdline(char *** inargv) + case EOF: + case '\0': + if (len > 0) { +- argv = pamsshagentauth_xrealloc(argv, count + 1, sizeof(*argv)); +- argv[count] = pamsshagentauth_xcalloc(len + 1, sizeof(*argv[count])); ++ argv = xreallocarray(argv, count + 1, sizeof(*argv)); ++ argv[count] = xcalloc(len + 1, sizeof(*argv[count])); + strncpy(argv[count++], argbuf, len); + memset(argbuf, '\0', MAX_LEN_PER_CMDLINE_ARG + 1); + len = 0; +@@ -106,9 +107,9 @@ pamsshagentauth_free_command_line(char * + { + size_t i; + for (i = 0; i < n_args; i++) +- pamsshagentauth_xfree(argv[i]); ++ free(argv[i]); + +- pamsshagentauth_xfree(argv); ++ free(argv); + return; + } + +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/identity.h 2020-09-23 10:52:16.424001475 +0200 +@@ -30,8 +30,8 @@ + #include "openbsd-compat/sys-queue.h" + #include "xmalloc.h" + #include "log.h" +-#include "buffer.h" +-#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" + #include "authfd.h" + #include + +@@ -41,7 +41,7 @@ typedef struct idlist Idlist; + struct identity { + TAILQ_ENTRY(identity) next; + AuthenticationConnection *ac; /* set if agent supports key */ +- Key *key; /* public/private key */ ++ struct sshkey *key; /* public/private key */ + char *filename; /* comment for agent-only keys */ + int tried; + int isprivate; /* key points to the private key */ +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c.psaa-compat 2020-09-23 10:52:16.421001434 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/iterate_ssh_agent_keys.c 2020-09-23 10:52:16.424001475 +0200 +@@ -36,8 +36,8 @@ + #include "openbsd-compat/sys-queue.h" + #include "xmalloc.h" + #include "log.h" +-#include "buffer.h" +-#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" + #include "authfd.h" + #include + #include +@@ -58,6 +58,8 @@ + #include "get_command_line.h" + extern char **environ; + ++#define PAM_SSH_AGENT_AUTH_REQUESTv1 101 ++ + /* + * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user + * A cursory check is done, but to avoid race conditions, it is necessary +@@ -77,7 +79,7 @@ log_action(char ** action, size_t count) + if (count == 0) + return NULL; + +- buf = pamsshagentauth_xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); ++ buf = xcalloc((count * MAX_LEN_PER_CMDLINE_ARG) + (count * 3), sizeof(*buf)); + for (i = 0; i < count; i++) { + strcat(buf, (i > 0) ? " '" : "'"); + strncat(buf, action[i], MAX_LEN_PER_CMDLINE_ARG); +@@ -87,21 +89,25 @@ log_action(char ** action, size_t count) + } + + void +-agent_action(Buffer *buf, char ** action, size_t count) ++agent_action(struct sshbuf **buf, char ** action, size_t count) + { + size_t i; +- pamsshagentauth_buffer_init(buf); ++ int r; + +- pamsshagentauth_buffer_put_int(buf, count); ++ if ((*buf = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); ++ if ((r = sshbuf_put_u32(*buf, count)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + for (i = 0; i < count; i++) { +- pamsshagentauth_buffer_put_cstring(buf, action[i]); ++ if ((r = sshbuf_put_cstring(*buf, action[i])) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + } + } + + +-void +-pamsshagentauth_session_id2_gen(Buffer * session_id2, const char * user, ++static void ++pamsshagentauth_session_id2_gen(struct sshbuf ** session_id2, const char * user, + const char * ruser, const char * servicename) + { + u_char *cookie = NULL; +@@ -114,22 +120,23 @@ pamsshagentauth_session_id2_gen(Buffer * + char ** reported_argv = NULL; + size_t count = 0; + char * action_logbuf = NULL; +- Buffer action_agentbuf; ++ struct sshbuf *action_agentbuf = NULL; + uint8_t free_logbuf = 0; + char * retc; + int32_t reti; ++ int r; + +- rnd = pamsshagentauth_arc4random(); ++ rnd = arc4random(); + cookie_len = ((uint8_t) rnd); + while (cookie_len < 16) { + cookie_len += 16; /* Add 16 bytes to the size to ensure that while the length is random, the length is always reasonable; ticket #18 */ + } + +- cookie = pamsshagentauth_xcalloc(1,cookie_len); ++ cookie = xcalloc(1, cookie_len); + + for (i = 0; i < cookie_len; i++) { + if (i % 4 == 0) { +- rnd = pamsshagentauth_arc4random(); ++ rnd = arc4random(); + } + cookie[i] = (u_char) rnd; + rnd >>= 8; +@@ -144,7 +151,8 @@ pamsshagentauth_session_id2_gen(Buffer * + } + else { + action_logbuf = "unknown on this platform"; +- pamsshagentauth_buffer_init(&action_agentbuf); /* stays empty, means unavailable */ ++ if ((action_agentbuf = sshbuf_new()) == NULL) /* stays empty, means unavailable */ ++ fatal("%s: sshbuf_new failed", __func__); + } + + /* +@@ -161,35 +169,39 @@ pamsshagentauth_session_id2_gen(Buffer * + retc = getcwd(pwd, sizeof(pwd) - 1); + time(&ts); + +- pamsshagentauth_buffer_init(session_id2); ++ if ((*session_id2 = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); + +- pamsshagentauth_buffer_put_int(session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1); +- /* pamsshagentauth_debug3("cookie: %s", pamsshagentauth_tohex(cookie, cookie_len)); */ +- pamsshagentauth_buffer_put_string(session_id2, cookie, cookie_len); +- /* pamsshagentauth_debug3("user: %s", user); */ +- pamsshagentauth_buffer_put_cstring(session_id2, user); +- /* pamsshagentauth_debug3("ruser: %s", ruser); */ +- pamsshagentauth_buffer_put_cstring(session_id2, ruser); +- /* pamsshagentauth_debug3("servicename: %s", servicename); */ +- pamsshagentauth_buffer_put_cstring(session_id2, servicename); +- /* pamsshagentauth_debug3("pwd: %s", pwd); */ +- if(retc) +- pamsshagentauth_buffer_put_cstring(session_id2, pwd); +- else +- pamsshagentauth_buffer_put_cstring(session_id2, ""); +- /* pamsshagentauth_debug3("action: %s", action_logbuf); */ +- pamsshagentauth_buffer_put_string(session_id2, action_agentbuf.buf + action_agentbuf.offset, action_agentbuf.end - action_agentbuf.offset); ++ if ((r = sshbuf_put_u32(*session_id2, PAM_SSH_AGENT_AUTH_REQUESTv1)) != 0 || ++ (r = sshbuf_put_string(*session_id2, cookie, cookie_len)) != 0 || ++ (r = sshbuf_put_cstring(*session_id2, user)) != 0 || ++ (r = sshbuf_put_cstring(*session_id2, ruser)) != 0 || ++ (r = sshbuf_put_cstring(*session_id2, servicename)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ if (retc) { ++ if ((r = sshbuf_put_cstring(*session_id2, pwd)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ } else { ++ if ((r = sshbuf_put_cstring(*session_id2, "")) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ } ++ if ((r = sshbuf_put_stringb(*session_id2, action_agentbuf)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + if (free_logbuf) { +- pamsshagentauth_xfree(action_logbuf); +- pamsshagentauth_buffer_free(&action_agentbuf); ++ free(action_logbuf); ++ sshbuf_free(action_agentbuf); ++ } ++ /* debug3("hostname: %s", hostname); */ ++ if (reti >= 0) { ++ if ((r = sshbuf_put_cstring(*session_id2, hostname)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); ++ } else { ++ if ((r = sshbuf_put_cstring(*session_id2, "")) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + } +- /* pamsshagentauth_debug3("hostname: %s", hostname); */ +- if(reti >= 0) +- pamsshagentauth_buffer_put_cstring(session_id2, hostname); +- else +- pamsshagentauth_buffer_put_cstring(session_id2, ""); +- /* pamsshagentauth_debug3("ts: %ld", ts); */ +- pamsshagentauth_buffer_put_int64(session_id2, (uint64_t) ts); ++ /* debug3("ts: %ld", ts); */ ++ if ((r = sshbuf_put_u64(*session_id2, (uint64_t) ts)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + + free(cookie); + return; +@@ -278,7 +290,8 @@ ssh_get_authentication_connection_for_ui + + auth = xmalloc(sizeof(*auth)); + auth->fd = sock; +- buffer_init(&auth->identities); ++ if ((auth->identities = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); + auth->howmany = 0; + + return auth; +@@ -287,9 +300,9 @@ ssh_get_authentication_connection_for_ui + int + pamsshagentauth_find_authorized_keys(const char * user, const char * ruser, const char * servicename) + { +- Buffer session_id2 = { 0 }; ++ struct sshbuf *session_id2 = NULL; + Identity *id; +- Key *key; ++ struct sshkey *key; + AuthenticationConnection *ac; + char *comment; + uint8_t retval = 0; +@@ -299,31 +312,30 @@ pamsshagentauth_find_authorized_keys(con + pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); + + if ((ac = ssh_get_authentication_connection_for_uid(uid))) { +- pamsshagentauth_verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); ++ verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); + for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) + { + if(key != NULL) { +- id = pamsshagentauth_xcalloc(1, sizeof(*id)); ++ id = xcalloc(1, sizeof(*id)); + id->key = key; + id->filename = comment; + id->ac = ac; +- if(userauth_pubkey_from_id(ruser, id, &session_id2)) { ++ if(userauth_pubkey_from_id(ruser, id, session_id2)) { + retval = 1; + } +- pamsshagentauth_xfree(id->filename); +- pamsshagentauth_key_free(id->key); +- pamsshagentauth_xfree(id); ++ free(id->filename); ++ key_free(id->key); ++ free(id); + if(retval == 1) + break; + } + } +- pamsshagentauth_buffer_free(&session_id2); ++ sshbuf_free(session_id2); + ssh_close_authentication_connection(ac); + } + else { +- pamsshagentauth_verbose("No ssh-agent could be contacted"); ++ verbose("No ssh-agent could be contacted"); + } +- /* pamsshagentauth_xfree(session_id2); */ + EVP_cleanup(); + return retval; + } +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c.psaa-compat 2020-09-23 10:52:16.423001461 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_ssh_agent_auth.c 2020-09-23 10:53:10.631727657 +0200 +@@ -106,7 +106,7 @@ pam_sm_authenticate(pam_handle_t * pamh, + * a patch 8-) + */ + #if ! HAVE___PROGNAME || HAVE_BUNDLE +- __progname = pamsshagentauth_xstrdup(servicename); ++ __progname = xstrdup(servicename); + #endif + + for(i = argc, argv_ptr = (char **) argv; i > 0; ++argv_ptr, i--) { +@@ -132,11 +132,11 @@ pam_sm_authenticate(pam_handle_t * pamh, + #endif + } + +- pamsshagentauth_log_init(__progname, log_lvl, facility, getenv("PAM_SSH_AGENT_AUTH_DEBUG") ? 1 : 0); ++ log_init(__progname, log_lvl, facility, getenv("PAM_SSH_AGENT_AUTH_DEBUG") ? 1 : 0); + pam_get_item(pamh, PAM_USER, (void *) &user); + pam_get_item(pamh, PAM_RUSER, (void *) &ruser_ptr); + +- pamsshagentauth_verbose("Beginning pam_ssh_agent_auth for user %s", user); ++ verbose("Beginning pam_ssh_agent_auth for user %s", user); + + if(ruser_ptr) { + strncpy(ruser, ruser_ptr, sizeof(ruser) - 1); +@@ -151,12 +151,12 @@ pam_sm_authenticate(pam_handle_t * pamh, + #ifdef ENABLE_SUDO_HACK + if( (strlen(sudo_service_name) > 0) && strncasecmp(servicename, sudo_service_name, sizeof(sudo_service_name) - 1) == 0 && getenv("SUDO_USER") ) { + strncpy(ruser, getenv("SUDO_USER"), sizeof(ruser) - 1 ); +- pamsshagentauth_verbose( "Using environment variable SUDO_USER (%s)", ruser ); ++ verbose( "Using environment variable SUDO_USER (%s)", ruser ); + } else + #endif + { + if( ! getpwuid(getuid()) ) { +- pamsshagentauth_verbose("Unable to getpwuid(getuid())"); ++ verbose("Unable to getpwuid(getuid())"); + goto cleanexit; + } + strncpy(ruser, getpwuid(getuid())->pw_name, sizeof(ruser) - 1); +@@ -165,11 +165,11 @@ pam_sm_authenticate(pam_handle_t * pamh, + + /* Might as well explicitely confirm the user exists here */ + if(! getpwnam(ruser) ) { +- pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", ruser); ++ verbose("getpwnam(%s) failed, bailing out", ruser); + goto cleanexit; + } + if( ! getpwnam(user) ) { +- pamsshagentauth_verbose("getpwnam(%s) failed, bailing out", user); ++ verbose("getpwnam(%s) failed, bailing out", user); + goto cleanexit; + } + +@@ -179,8 +179,8 @@ pam_sm_authenticate(pam_handle_t * pamh, + */ + parse_authorized_key_file(user, authorized_keys_file_input); + } else { +- pamsshagentauth_verbose("Using default file=/etc/security/authorized_keys"); +- authorized_keys_file = pamsshagentauth_xstrdup("/etc/security/authorized_keys"); ++ verbose("Using default file=/etc/security/authorized_keys"); ++ authorized_keys_file = xstrdup("/etc/security/authorized_keys"); + } + + /* +@@ -189,7 +189,7 @@ pam_sm_authenticate(pam_handle_t * pamh, + */ + + if(user && strlen(ruser) > 0) { +- pamsshagentauth_verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ verbose("Attempting authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); + + /* + * Attempt to read data from the sshd if we're being called as an auth agent. +@@ -197,10 +197,10 @@ pam_sm_authenticate(pam_handle_t * pamh, + const char* ssh_user_auth = pam_getenv(pamh, "SSH_AUTH_INFO_0"); + int sshd_service = strncasecmp(servicename, sshd_service_name, sizeof(sshd_service_name) - 1); + if (sshd_service == 0 && ssh_user_auth != NULL) { +- pamsshagentauth_verbose("Got SSH_AUTH_INFO_0: `%.20s...'", ssh_user_auth); ++ verbose("Got SSH_AUTH_INFO_0: `%.20s...'", ssh_user_auth); + if (userauth_pubkey_from_pam(ruser, ssh_user_auth) > 0) { + retval = PAM_SUCCESS; +- pamsshagentauth_logit("Authenticated (sshd): `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ logit("Authenticated (sshd): `%s' as `%s' using %s", ruser, user, authorized_keys_file); + goto cleanexit; + } + } +@@ -208,13 +208,13 @@ pam_sm_authenticate(pam_handle_t * pamh, + * this pw_uid is used to validate the SSH_AUTH_SOCK, and so must be the uid of the ruser invoking the program, not the target-user + */ + if(pamsshagentauth_find_authorized_keys(user, ruser, servicename)) { /* getpwnam(ruser)->pw_uid)) { */ +- pamsshagentauth_logit("Authenticated (agent): `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ logit("Authenticated (agent): `%s' as `%s' using %s", ruser, user, authorized_keys_file); + retval = PAM_SUCCESS; + } else { +- pamsshagentauth_logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); ++ logit("Failed Authentication: `%s' as `%s' using %s", ruser, user, authorized_keys_file); + } + } else { +- pamsshagentauth_logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); ++ logit("No %s specified, cannot continue with this form of authentication", (user) ? "ruser" : "user" ); + } + + cleanexit: +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.c 2020-09-23 10:52:16.424001475 +0200 +@@ -66,8 +66,8 @@ + #include "xmalloc.h" + #include "match.h" + #include "log.h" +-#include "buffer.h" +-#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" + #include "misc.h" + + #include "xmalloc.h" +@@ -77,7 +77,6 @@ + #include "pathnames.h" + #include "secure_filename.h" + +-#include "identity.h" + #include "pam_user_key_allowed2.h" + + extern char *authorized_keys_file; +@@ -117,12 +116,12 @@ parse_authorized_key_file(const char *us + } else { + slash_ptr = strchr(auth_keys_file_buf, '/'); + if(!slash_ptr) +- pamsshagentauth_fatal ++ fatal + ("cannot expand tilde in path without a `/'"); + + owner_uname_len = slash_ptr - auth_keys_file_buf - 1; + if(owner_uname_len > (sizeof(owner_uname) - 1)) +- pamsshagentauth_fatal("Username too long"); ++ fatal("Username too long"); + + strncat(owner_uname, auth_keys_file_buf + 1, owner_uname_len); + if(!authorized_keys_file_allowed_owner_uid) +@@ -130,11 +129,11 @@ parse_authorized_key_file(const char *us + getpwnam(owner_uname)->pw_uid; + } + authorized_keys_file = +- pamsshagentauth_tilde_expand_filename(auth_keys_file_buf, ++ tilde_expand_filename(auth_keys_file_buf, + authorized_keys_file_allowed_owner_uid); + strncpy(auth_keys_file_buf, authorized_keys_file, + sizeof(auth_keys_file_buf) - 1); +- pamsshagentauth_xfree(authorized_keys_file) /* when we ++ free(authorized_keys_file) /* when we + percent_expand + later, we'd step + on this, so free +@@ -150,13 +149,13 @@ parse_authorized_key_file(const char *us + strncat(hostname, fqdn, strcspn(fqdn, ".")); + #endif + authorized_keys_file = +- pamsshagentauth_percent_expand(auth_keys_file_buf, "h", ++ percent_expand(auth_keys_file_buf, "h", + getpwnam(user)->pw_dir, "H", hostname, + "f", fqdn, "u", user, NULL); + } + + int +-pam_user_key_allowed(const char *ruser, Key * key) ++pam_user_key_allowed(const char *ruser, struct sshkey * key) + { + return + pamsshagentauth_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_authorized_keys.h 2020-09-23 10:52:16.424001475 +0200 +@@ -32,7 +32,7 @@ + #define _PAM_USER_KEY_ALLOWED_H + + #include "identity.h" +-int pam_user_key_allowed(const char *, Key *); ++int pam_user_key_allowed(const char *, struct sshkey *); + void parse_authorized_key_file(const char *, const char *); + + #endif +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.c 2020-09-23 10:52:16.424001475 +0200 +@@ -45,44 +45,46 @@ + #include "xmalloc.h" + #include "ssh.h" + #include "ssh2.h" +-#include "buffer.h" ++#include "sshbuf.h" + #include "log.h" + #include "compat.h" +-#include "key.h" ++#include "digest.h" ++#include "sshkey.h" + #include "pathnames.h" + #include "misc.h" + #include "secure_filename.h" + #include "uidswap.h" +- +-#include "identity.h" ++#include + + /* return 1 if user allows given key */ + /* Modified slightly from original found in auth2-pubkey.c */ + static int +-pamsshagentauth_check_authkeys_file(FILE * f, char *file, Key * key) ++pamsshagentauth_check_authkeys_file(FILE * f, char *file, struct sshkey * key) + { +- char line[SSH_MAX_PUBKEY_BYTES]; ++ char *line = NULL; + int found_key = 0; + u_long linenum = 0; +- Key *found; ++ struct sshkey *found; + char *fp; ++ size_t linesize = 0; + + found_key = 0; +- found = pamsshagentauth_key_new(key->type); ++ found = sshkey_new(key->type); + +- while(read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { ++ while ((getline(&line, &linesize, f)) != -1) { + char *cp = NULL; /* *key_options = NULL; */ + ++ linenum++; + /* Skip leading whitespace, empty and comment lines. */ + for(cp = line; *cp == ' ' || *cp == '\t'; cp++); + if(!*cp || *cp == '\n' || *cp == '#') + continue; + +- if(pamsshagentauth_key_read(found, &cp) != 1) { ++ if (sshkey_read(found, &cp) != 0) { + /* no key? check if there are options for this key */ + int quoted = 0; + +- pamsshagentauth_verbose("user_key_allowed: check options: '%s'", cp); ++ verbose("user_key_allowed: check options: '%s'", cp); + /* key_options = cp; */ + for(; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { + if(*cp == '\\' && cp[1] == '"') +@@ -92,26 +94,27 @@ pamsshagentauth_check_authkeys_file(FILE + } + /* Skip remaining whitespace. */ + for(; *cp == ' ' || *cp == '\t'; cp++); +- if(pamsshagentauth_key_read(found, &cp) != 1) { +- pamsshagentauth_verbose("user_key_allowed: advance: '%s'", cp); ++ if(sshkey_read(found, &cp) != 0) { ++ verbose("user_key_allowed: advance: '%s'", cp); + /* still no key? advance to next line */ + continue; + } + } +- if(pamsshagentauth_key_equal(found, key)) { ++ if(sshkey_equal(found, key)) { + found_key = 1; +- pamsshagentauth_logit("matching key found: file/command %s, line %lu", file, ++ logit("matching key found: file/command %s, line %lu", file, + linenum); +- fp = pamsshagentauth_key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX); +- pamsshagentauth_logit("Found matching %s key: %s", +- pamsshagentauth_key_type(found), fp); +- pamsshagentauth_xfree(fp); ++ fp = sshkey_fingerprint(found, SSH_DIGEST_SHA256, SSH_FP_BASE64); ++ logit("Found matching %s key: %s", ++ sshkey_type(found), fp); ++ free(fp); + break; + } + } +- pamsshagentauth_key_free(found); ++ free(line); ++ sshkey_free(found); + if(!found_key) +- pamsshagentauth_verbose("key not found"); ++ verbose("key not found"); + return found_key; + } + +@@ -120,19 +123,19 @@ pamsshagentauth_check_authkeys_file(FILE + * returns 1 if the key is allowed or 0 otherwise. + */ + int +-pamsshagentauth_user_key_allowed2(struct passwd *pw, Key * key, char *file) ++pamsshagentauth_user_key_allowed2(struct passwd *pw, struct sshkey * key, char *file) + { + FILE *f; + int found_key = 0; + struct stat st; +- char buf[SSH_MAX_PUBKEY_BYTES]; ++ char buf[256]; + + /* Temporarily use the user's uid. */ +- pamsshagentauth_verbose("trying public key file %s", file); ++ verbose("trying public key file %s", file); + + /* Fail not so quietly if file does not exist */ + if(stat(file, &st) < 0) { +- pamsshagentauth_verbose("File not found: %s", file); ++ verbose("File not found: %s", file); + return 0; + } + +@@ -144,7 +147,7 @@ pamsshagentauth_user_key_allowed2(struct + + if(pamsshagentauth_secure_filename(f, file, pw, buf, sizeof(buf)) != 0) { + fclose(f); +- pamsshagentauth_logit("Authentication refused: %s", buf); ++ logit("Authentication refused: %s", buf); + return 0; + } + +@@ -160,7 +163,7 @@ pamsshagentauth_user_key_allowed2(struct + int + pamsshagentauth_user_key_command_allowed2(char *authorized_keys_command, + char *authorized_keys_command_user, +- struct passwd *user_pw, Key * key) ++ struct passwd *user_pw, struct sshkey * key) + { + FILE *f; + int ok, found_key = 0; +@@ -187,44 +190,44 @@ pamsshagentauth_user_key_command_allowed + else { + pw = getpwnam(authorized_keys_command_user); + if(pw == NULL) { +- pamsshagentauth_logerror("authorized_keys_command_user \"%s\" not found: %s", ++ error("authorized_keys_command_user \"%s\" not found: %s", + authorized_keys_command_user, strerror(errno)); + return 0; + } + } + +- pamsshagentauth_temporarily_use_uid(pw); ++ temporarily_use_uid(pw); + + if(stat(authorized_keys_command, &st) < 0) { +- pamsshagentauth_logerror ++ error + ("Could not stat AuthorizedKeysCommand \"%s\": %s", + authorized_keys_command, strerror(errno)); + goto out; + } + if(pamsshagentauth_auth_secure_path + (authorized_keys_command, &st, NULL, 0, errmsg, sizeof(errmsg)) != 0) { +- pamsshagentauth_logerror("Unsafe AuthorizedKeysCommand: %s", errmsg); ++ error("Unsafe AuthorizedKeysCommand: %s", errmsg); + goto out; + } + + /* open the pipe and read the keys */ + if(pipe(p) != 0) { +- pamsshagentauth_logerror("%s: pipe: %s", __func__, strerror(errno)); ++ error("%s: pipe: %s", __func__, strerror(errno)); + goto out; + } + +- pamsshagentauth_debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", ++ debug("Running AuthorizedKeysCommand: \"%s\" as \"%s\" with argument: \"%s\"", + authorized_keys_command, pw->pw_name, username); + + /* + * Don't want to call this in the child, where it can fatal() and + * run cleanup_exit() code. + */ +- pamsshagentauth_restore_uid(); ++ restore_uid(); + + switch ((pid = fork())) { + case -1: /* error */ +- pamsshagentauth_logerror("%s: fork: %s", __func__, strerror(errno)); ++ error("%s: fork: %s", __func__, strerror(errno)); + close(p[0]); + close(p[1]); + return 0; +@@ -234,13 +237,13 @@ pamsshagentauth_user_key_command_allowed + + /* do this before the setresuid so thta they can be logged */ + if((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { +- pamsshagentauth_logerror("%s: open %s: %s", __func__, _PATH_DEVNULL, ++ error("%s: open %s: %s", __func__, _PATH_DEVNULL, + strerror(errno)); + _exit(1); + } + if(dup2(devnull, STDIN_FILENO) == -1 || dup2(p[1], STDOUT_FILENO) == -1 + || dup2(devnull, STDERR_FILENO) == -1) { +- pamsshagentauth_logerror("%s: dup2: %s", __func__, strerror(errno)); ++ error("%s: dup2: %s", __func__, strerror(errno)); + _exit(1); + } + #if defined(HAVE_SETRESGID) && !defined(BROKEN_SETRESGID) +@@ -248,7 +251,7 @@ pamsshagentauth_user_key_command_allowed + #else + if (setgid(pw->pw_gid) != 0 || setegid(pw->pw_gid) != 0) { + #endif +- pamsshagentauth_logerror("setresgid %u: %s", (u_int) pw->pw_gid, ++ error("setresgid %u: %s", (u_int) pw->pw_gid, + strerror(errno)); + _exit(1); + } +@@ -258,7 +261,7 @@ pamsshagentauth_user_key_command_allowed + #else + if (setuid(pw->pw_uid) != 0 || seteuid(pw->pw_uid) != 0) { + #endif +- pamsshagentauth_logerror("setresuid %u: %s", (u_int) pw->pw_uid, ++ error("setresuid %u: %s", (u_int) pw->pw_uid, + strerror(errno)); + _exit(1); + } +@@ -270,18 +273,18 @@ pamsshagentauth_user_key_command_allowed + + /* pretty sure this will barf because we are now suid, but since we + should't reach this anyway, I'll leave it here */ +- pamsshagentauth_logerror("AuthorizedKeysCommand %s exec failed: %s", ++ error("AuthorizedKeysCommand %s exec failed: %s", + authorized_keys_command, strerror(errno)); + _exit(127); + default: /* parent */ + break; + } + +- pamsshagentauth_temporarily_use_uid(pw); ++ temporarily_use_uid(pw); + + close(p[1]); + if((f = fdopen(p[0], "r")) == NULL) { +- pamsshagentauth_logerror("%s: fdopen: %s", __func__, strerror(errno)); ++ error("%s: fdopen: %s", __func__, strerror(errno)); + close(p[0]); + /* Don't leave zombie child */ + while(waitpid(pid, NULL, 0) == -1 && errno == EINTR); +@@ -292,22 +295,22 @@ pamsshagentauth_user_key_command_allowed + + while(waitpid(pid, &status, 0) == -1) { + if(errno != EINTR) { +- pamsshagentauth_logerror("%s: waitpid: %s", __func__, ++ error("%s: waitpid: %s", __func__, + strerror(errno)); + goto out; + } + } + if(WIFSIGNALED(status)) { +- pamsshagentauth_logerror("AuthorizedKeysCommand %s exited on signal %d", ++ error("AuthorizedKeysCommand %s exited on signal %d", + authorized_keys_command, WTERMSIG(status)); + goto out; + } else if(WEXITSTATUS(status) != 0) { +- pamsshagentauth_logerror("AuthorizedKeysCommand %s returned status %d", ++ error("AuthorizedKeysCommand %s returned status %d", + authorized_keys_command, WEXITSTATUS(status)); + goto out; + } + found_key = ok; + out: +- pamsshagentauth_restore_uid(); ++ restore_uid(); + return found_key; + } +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/pam_user_key_allowed2.h 2020-09-23 10:52:16.424001475 +0200 +@@ -32,7 +32,7 @@ + #define _PAM_USER_KEY_ALLOWED_H + + #include "identity.h" +-int pamsshagentauth_user_key_allowed2(struct passwd *, Key *, char *); +-int pamsshagentauth_user_key_command_allowed2(char *, char *, struct passwd *, Key *); ++int pamsshagentauth_user_key_allowed2(struct passwd *, struct sshkey *, char *); ++int pamsshagentauth_user_key_command_allowed2(char *, char *, struct passwd *, struct sshkey *); + + #endif +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/secure_filename.c 2020-09-23 10:52:16.424001475 +0200 +@@ -53,8 +53,8 @@ + #include "xmalloc.h" + #include "match.h" + #include "log.h" +-#include "buffer.h" +-#include "key.h" ++#include "sshbuf.h" ++#include "sshkey.h" + #include "misc.h" + + +@@ -80,7 +80,7 @@ pamsshagentauth_auth_secure_path(const c + int comparehome = 0; + struct stat st; + +- pamsshagentauth_verbose("auth_secure_filename: checking for uid: %u", uid); ++ verbose("auth_secure_filename: checking for uid: %u", uid); + + if (realpath(name, buf) == NULL) { + snprintf(err, errlen, "realpath %s failed: %s", name, +@@ -115,9 +115,9 @@ pamsshagentauth_auth_secure_path(const c + snprintf(err, errlen, "dirname() failed"); + return -1; + } +- pamsshagentauth_strlcpy(buf, cp, sizeof(buf)); ++ strlcpy(buf, cp, sizeof(buf)); + +- pamsshagentauth_verbose("secure_filename: checking '%s'", buf); ++ verbose("secure_filename: checking '%s'", buf); + if (stat(buf, &st) < 0 || + (st.st_uid != 0 && st.st_uid != uid) || + (st.st_mode & 022) != 0) { +@@ -128,7 +128,7 @@ pamsshagentauth_auth_secure_path(const c + + /* If are passed the homedir then we can stop */ + if (comparehome && strcmp(homedir, buf) == 0) { +- pamsshagentauth_verbose("secure_filename: terminating check at '%s'", ++ verbose("secure_filename: terminating check at '%s'", + buf); + break; + } +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c 2020-09-23 10:52:16.424001475 +0200 +@@ -37,10 +37,11 @@ + #include "xmalloc.h" + #include "ssh.h" + #include "ssh2.h" +-#include "buffer.h" ++#include "sshbuf.h" + #include "log.h" + #include "compat.h" +-#include "key.h" ++#include "sshkey.h" ++#include "ssherr.h" + #include "pathnames.h" + #include "misc.h" + #include "secure_filename.h" +@@ -48,54 +49,59 @@ + #include "identity.h" + #include "pam_user_authorized_keys.h" + ++#define SSH2_MSG_USERAUTH_TRUST_REQUEST 54 ++ + /* extern u_char *session_id2; + extern uint8_t session_id_len; + */ + + int +-userauth_pubkey_from_id(const char *ruser, Identity * id, Buffer * session_id2) ++userauth_pubkey_from_id(const char *ruser, Identity * id, struct sshbuf * session_id2) + { +- Buffer b = { 0 }; ++ struct sshbuf *b = NULL; + char *pkalg = NULL; + u_char *pkblob = NULL, *sig = NULL; +- u_int blen = 0, slen = 0; +- int authenticated = 0; ++ size_t blen = 0, slen = 0; ++ int r, authenticated = 0; + +- pkalg = (char *) key_ssh_name(id->key); ++ pkalg = (char *) sshkey_ssh_name(id->key); + + /* first test if this key is even allowed */ + if(! pam_user_key_allowed(ruser, id->key)) +- goto user_auth_clean_exit; ++ goto user_auth_clean_exit_without_buffer; + +- if(pamsshagentauth_key_to_blob(id->key, &pkblob, &blen) == 0) +- goto user_auth_clean_exit; ++ if(sshkey_to_blob(id->key, &pkblob, &blen) != 0) ++ goto user_auth_clean_exit_without_buffer; + + /* construct packet to sign and test */ +- pamsshagentauth_buffer_init(&b); ++ if ((b = sshbuf_new()) == NULL) ++ fatal("%s: sshbuf_new failed", __func__); + +- pamsshagentauth_buffer_put_string(&b, session_id2->buf + session_id2->offset, session_id2->end - session_id2->offset); +- pamsshagentauth_buffer_put_char(&b, SSH2_MSG_USERAUTH_TRUST_REQUEST); +- pamsshagentauth_buffer_put_cstring(&b, ruser); +- pamsshagentauth_buffer_put_cstring(&b, "pam_ssh_agent_auth"); +- pamsshagentauth_buffer_put_cstring(&b, "publickey"); +- pamsshagentauth_buffer_put_char(&b, 1); +- pamsshagentauth_buffer_put_cstring(&b, pkalg); +- pamsshagentauth_buffer_put_string(&b, pkblob, blen); ++ if ((r = sshbuf_put_string(b, sshbuf_ptr(session_id2), sshbuf_len(session_id2))) != 0 || ++ (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_TRUST_REQUEST)) != 0 || ++ (r = sshbuf_put_cstring(b, ruser)) != 0 || ++ (r = sshbuf_put_cstring(b, "pam_ssh_agent_auth")) != 0 || ++ (r = sshbuf_put_cstring(b, "publickey")) != 0 || ++ (r = sshbuf_put_u8(b, 1)) != 0 || ++ (r = sshbuf_put_cstring(b, pkalg)) != 0 || ++ (r = sshbuf_put_string(b, pkblob, blen)) != 0) ++ fatal("%s: buffer error: %s", __func__, ssh_err(r)); + +- if(ssh_agent_sign(id->ac, id->key, &sig, &slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) != 0) ++ if (ssh_agent_sign(id->ac, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b)) != 0) + goto user_auth_clean_exit; + + /* test for correct signature */ +- if(pamsshagentauth_key_verify(id->key, sig, slen, pamsshagentauth_buffer_ptr(&b), pamsshagentauth_buffer_len(&b)) == 1) ++ if (sshkey_verify(id->key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0, NULL) == 0) + authenticated = 1; + + user_auth_clean_exit: + /* if(&b != NULL) */ +- pamsshagentauth_buffer_free(&b); ++ sshbuf_free(b); ++ user_auth_clean_exit_without_buffer: + if(sig != NULL) +- pamsshagentauth_xfree(sig); ++ free(sig); + if(pkblob != NULL) +- pamsshagentauth_xfree(pkblob); ++ free(pkblob); + CRYPTO_cleanup_all_ex_data(); + return authenticated; + } +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.h 2020-09-23 10:52:16.424001475 +0200 +@@ -31,7 +31,7 @@ + #ifndef _USERAUTH_PUBKEY_FROM_ID_H + #define _USERAUTH_PUBKEY_FROM_ID_H + +-#include +-int userauth_pubkey_from_id(const char *, Identity *, Buffer *); ++#include "identity.h" ++int userauth_pubkey_from_id(const char *, Identity *, struct sshbuf *); + + #endif +diff -up openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c.psaa-compat openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c.psaa-compat 2019-07-08 18:36:13.000000000 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/uuencode.c 2020-09-23 10:52:16.424001475 +0200 +@@ -56,7 +56,7 @@ pamsshagentauth_uudecode(const char *src + /* and remove trailing whitespace because __b64_pton needs this */ + *p = '\0'; + len = pamsshagentauth___b64_pton(encoded, target, targsize); +- pamsshagentauth_xfree(encoded); ++ xfree(encoded); + return len; + } + +@@ -70,7 +70,7 @@ pamsshagentauth_dump_base64(FILE *fp, co + fprintf(fp, "dump_base64: len > 65536\n"); + return; + } +- buf = pamsshagentauth_xmalloc(2*len); ++ buf = malloc(2*len); + n = pamsshagentauth_uuencode(data, len, buf, 2*len); + for (i = 0; i < n; i++) { + fprintf(fp, "%c", buf[i]); +@@ -79,5 +79,5 @@ pamsshagentauth_dump_base64(FILE *fp, co + } + if (i % 70 != 69) + fprintf(fp, "\n"); +- pamsshagentauth_xfree(buf); ++ free(buf); + } +--- openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_pam.c.compat 2020-09-23 11:32:30.783695267 +0200 ++++ openssh/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_pam.c 2020-09-23 11:33:21.383389036 +0200 +@@ -33,7 +33,8 @@ + #include + + #include "defines.h" +-#include "key.h" ++#include ++#include "sshkey.h" + #include "log.h" + + #include "pam_user_authorized_keys.h" +@@ -42,28 +42,28 @@ + int authenticated = 0; + const char method[] = "publickey "; + +- char* ai = pamsshagentauth_xstrdup(ssh_auth_info); ++ char* ai = xstrdup(ssh_auth_info); + char* saveptr; + + char* auth_line = strtok_r(ai, "\n", &saveptr); + while (auth_line != NULL) { + if (strncmp(auth_line, method, sizeof(method) - 1) == 0) { + char* key_str = auth_line + sizeof(method) - 1; +- Key* key = pamsshagentauth_key_new(KEY_UNSPEC); ++ struct sshkey* key = sshkey_new(KEY_UNSPEC); + if (key == NULL) { + continue; + } +- int r = pamsshagentauth_key_read(key, &key_str); ++ int r = sshkey_read(key, &key_str); + if (r == 1) { + if (pam_user_key_allowed(ruser, key)) { + authenticated = 1; +- pamsshagentauth_key_free(key); ++ sshkey_free(key); + break; + } + } else { +- pamsshagentauth_verbose("Failed to create key for %s: %d", auth_line, r); ++ verbose("Failed to create key for %s: %d", auth_line, r); + } +- pamsshagentauth_key_free(key); ++ sshkey_free(key); + } + auth_line = strtok_r(NULL, "\n", &saveptr); + } diff --git a/pam_ssh_agent_auth-0.10.2-dereference.patch b/pam_ssh_agent_auth-0.10.2-dereference.patch new file mode 100644 index 0000000..bf49c37 --- /dev/null +++ b/pam_ssh_agent_auth-0.10.2-dereference.patch @@ -0,0 +1,20 @@ +diff --git a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c b/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c +--- a/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c ++++ b/pam_ssh_agent_auth-0.10.2/pam_user_authorized_keys.c +@@ -158,11 +158,12 @@ parse_authorized_key_file(const char *user, + int + pam_user_key_allowed(const char *ruser, struct sshkey * key) + { ++ struct passwd *pw; + return +- pamsshagentauth_user_key_allowed2(getpwuid(authorized_keys_file_allowed_owner_uid), +- key, authorized_keys_file) +- || pamsshagentauth_user_key_allowed2(getpwuid(0), key, +- authorized_keys_file) ++ ( (pw = getpwuid(authorized_keys_file_allowed_owner_uid)) && ++ pamsshagentauth_user_key_allowed2(pw, key, authorized_keys_file)) ++ || ((pw = getpwuid(0)) && ++ pamsshagentauth_user_key_allowed2(pw, key, authorized_keys_file)) + || pamsshagentauth_user_key_command_allowed2(authorized_keys_command, + authorized_keys_command_user, + getpwnam(ruser), key); diff --git a/pam_ssh_agent_auth-0.10.3-seteuid.patch b/pam_ssh_agent_auth-0.10.3-seteuid.patch new file mode 100644 index 0000000..be1f8e5 --- /dev/null +++ b/pam_ssh_agent_auth-0.10.3-seteuid.patch @@ -0,0 +1,37 @@ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-seteuid openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c +--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-seteuid 2017-02-07 15:41:53.172334151 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-07 15:41:53.174334149 +0100 +@@ -238,17 +238,26 @@ ssh_get_authentication_socket_for_uid(ui + } + + errno = 0; +- seteuid(uid); /* To ensure a race condition is not used to circumvent the stat +- above, we will temporarily drop UID to the caller */ +- if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { ++ /* To ensure a race condition is not used to circumvent the stat ++ above, we will temporarily drop UID to the caller */ ++ if (seteuid(uid) == -1) { + close(sock); +- if(errno == EACCES) +- fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); ++ error("seteuid(%lu) failed with error: %s", ++ (unsigned long) uid, strerror(errno)); + return -1; + } ++ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { ++ close(sock); ++ sock = -1; ++ if(errno == EACCES) ++ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); ++ } + +- seteuid(0); /* we now continue the regularly scheduled programming */ +- ++ /* we now continue the regularly scheduled programming */ ++ if (0 != seteuid(0)) { ++ fatal("setuid(0) failed with error: %s", strerror(errno)); ++ return -1; ++ } + return sock; + } + diff --git a/pam_ssh_agent_auth-0.10.4-rsasha2.patch b/pam_ssh_agent_auth-0.10.4-rsasha2.patch new file mode 100644 index 0000000..c8815bb --- /dev/null +++ b/pam_ssh_agent_auth-0.10.4-rsasha2.patch @@ -0,0 +1,19 @@ +diff -up openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.rsasha2 openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c +--- openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c.rsasha2 2022-07-15 15:08:12.865585410 +0200 ++++ openssh-8.7p1/pam_ssh_agent_auth-pam_ssh_agent_auth-0.10.4/userauth_pubkey_from_id.c 2022-07-15 15:16:25.164282372 +0200 +@@ -87,8 +87,13 @@ userauth_pubkey_from_id(const char *ruse + (r = sshbuf_put_string(b, pkblob, blen)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + +- if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) +- goto user_auth_clean_exit; ++ if (sshkey_type_plain(id->key->type) == KEY_RSA ++ && ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), "rsa-sha2-256", 0) == 0) { ++ /* Do nothing */ ++ } else { ++ if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) ++ goto user_auth_clean_exit; ++ } + + /* test for correct signature */ + if (sshkey_verify(id->key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0, NULL) == 0) diff --git a/pam_ssh_agent_auth-0.9.2-visibility.patch b/pam_ssh_agent_auth-0.9.2-visibility.patch new file mode 100644 index 0000000..aea068d --- /dev/null +++ b/pam_ssh_agent_auth-0.9.2-visibility.patch @@ -0,0 +1,21 @@ +diff -up openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c.psaa-visibility openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c +--- openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c.psaa-visibility 2014-03-31 19:35:17.000000000 +0200 ++++ openssh-7.1p2/pam_ssh_agent_auth-0.10.2/pam_ssh_agent_auth.c 2016-01-22 15:22:40.984469774 +0100 +@@ -72,7 +72,7 @@ char *__progname; + extern char *__progname; + #endif + +-PAM_EXTERN int ++PAM_EXTERN int __attribute__ ((visibility ("default"))) + pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, const char **argv) + { + char **argv_ptr; +@@ -214,7 +214,7 @@ cleanexit: + } + + +-PAM_EXTERN int ++PAM_EXTERN int __attribute__ ((visibility ("default"))) + pam_sm_setcred(pam_handle_t * pamh, int flags, int argc, const char **argv) + { + UNUSED(pamh); diff --git a/pam_ssh_agent_auth-0.9.3-agent_structure.patch b/pam_ssh_agent_auth-0.9.3-agent_structure.patch new file mode 100644 index 0000000..1f2c02c --- /dev/null +++ b/pam_ssh_agent_auth-0.9.3-agent_structure.patch @@ -0,0 +1,96 @@ +diff -up openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/identity.h +--- openssh/pam_ssh_agent_auth-0.10.3/identity.h.psaa-agent 2016-11-13 04:24:32.000000000 +0100 ++++ openssh/pam_ssh_agent_auth-0.10.3/identity.h 2017-09-27 14:25:49.421739027 +0200 +@@ -38,6 +38,12 @@ + typedef struct identity Identity; + typedef struct idlist Idlist; + ++typedef struct { ++ int fd; ++ struct sshbuf *identities; ++ int howmany; ++} AuthenticationConnection; ++ + struct identity { + TAILQ_ENTRY(identity) next; + AuthenticationConnection *ac; /* set if agent supports key */ +diff -up openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c +--- openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-agent 2017-09-27 14:25:49.420739021 +0200 ++++ openssh/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-09-27 14:25:49.421739027 +0200 +@@ -39,6 +39,7 @@ + #include "sshbuf.h" + #include "sshkey.h" + #include "authfd.h" ++#include "ssherr.h" + #include + #include + #include "ssh2.h" +@@ -291,36 +292,43 @@ pamsshagentauth_find_authorized_keys(con + { + struct sshbuf *session_id2 = NULL; + Identity *id; +- struct sshkey *key; + AuthenticationConnection *ac; +- char *comment; + uint8_t retval = 0; + uid_t uid = getpwnam(ruser)->pw_uid; ++ struct ssh_identitylist *idlist; ++ int r; ++ unsigned int i; + + OpenSSL_add_all_digests(); + pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); + + if ((ac = ssh_get_authentication_connection_for_uid(uid))) { + verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); +- for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) +- { +- if(key != NULL) { ++ if ((r = ssh_fetch_identitylist(ac->fd, &idlist)) != 0) { ++ if (r != SSH_ERR_AGENT_NO_IDENTITIES) ++ fprintf(stderr, "error fetching identities for " ++ "protocol %d: %s\n", 2, ssh_err(r)); ++ } else { ++ for (i = 0; i < idlist->nkeys; i++) ++ { ++ if (idlist->keys[i] != NULL) { + id = xcalloc(1, sizeof(*id)); +- id->key = key; +- id->filename = comment; ++ id->key = idlist->keys[i]; ++ id->filename = idlist->comments[i]; + id->ac = ac; + if(userauth_pubkey_from_id(ruser, id, session_id2)) { + retval = 1; + } +- free(id->filename); +- key_free(id->key); + free(id); + if(retval == 1) + break; +- } +- } ++ } ++ } +- sshbuf_free(session_id2); +- ssh_close_authentication_connection(ac); ++ sshbuf_free(session_id2); ++ ssh_free_identitylist(idlist); ++ } ++ ssh_close_authentication_socket(ac->fd); ++ free(ac); + } + else { + verbose("No ssh-agent could be contacted"); +diff -up openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c +--- openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c.psaa-agent 2017-09-27 14:25:49.420739021 +0200 ++++ openssh/pam_ssh_agent_auth-0.10.3/userauth_pubkey_from_id.c 2017-09-27 14:25:49.422739032 +0200 +@@ -84,7 +85,7 @@ userauth_pubkey_from_id(const char *ruse + (r = sshbuf_put_string(b, pkblob, blen)) != 0) + fatal("%s: buffer error: %s", __func__, ssh_err(r)); + +- if (ssh_agent_sign(id->ac, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b)) != 0) ++ if (ssh_agent_sign(id->ac->fd, id->key, &sig, &slen, sshbuf_ptr(b), sshbuf_len(b), NULL, 0) != 0) + goto user_auth_clean_exit; + + /* test for correct signature */ diff --git a/pam_ssh_agent_auth-0.9.3-build.patch b/pam_ssh_agent_auth-0.9.3-build.patch new file mode 100644 index 0000000..4018c4d --- /dev/null +++ b/pam_ssh_agent_auth-0.9.3-build.patch @@ -0,0 +1,198 @@ +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-build openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c +--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c.psaa-build 2016-11-13 04:24:32.000000000 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/iterate_ssh_agent_keys.c 2017-02-07 14:29:41.626116675 +0100 +@@ -43,12 +43,31 @@ + #include + #include "ssh2.h" + #include "misc.h" ++#include "ssh.h" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include + + #include "userauth_pubkey_from_id.h" + #include "identity.h" + #include "get_command_line.h" + extern char **environ; + ++/* ++ * Added by Jamie Beverly, ensure socket fd points to a socket owned by the user ++ * A cursory check is done, but to avoid race conditions, it is necessary ++ * to drop effective UID when connecting to the socket. ++ * ++ * If the cause of error is EACCES, because we verified we would not have that ++ * problem initially, we can safely assume that somebody is attempting to find a ++ * race condition; so a more "direct" log message is generated. ++ */ ++ + static char * + log_action(char ** action, size_t count) + { +@@ -85,7 +104,7 @@ void + pamsshagentauth_session_id2_gen(Buffer * session_id2, const char * user, + const char * ruser, const char * servicename) + { +- char *cookie = NULL; ++ u_char *cookie = NULL; + uint8_t i = 0; + uint32_t rnd = 0; + uint8_t cookie_len; +@@ -112,7 +131,7 @@ pamsshagentauth_session_id2_gen(Buffer * + if (i % 4 == 0) { + rnd = pamsshagentauth_arc4random(); + } +- cookie[i] = (char) rnd; ++ cookie[i] = (u_char) rnd; + rnd >>= 8; + } + +@@ -177,6 +196,86 @@ pamsshagentauth_session_id2_gen(Buffer * + } + + int ++ssh_get_authentication_socket_for_uid(uid_t uid) ++{ ++ const char *authsocket; ++ int sock; ++ struct sockaddr_un sunaddr; ++ struct stat sock_st; ++ ++ authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME); ++ if (!authsocket) ++ return -1; ++ ++ /* Advisory only; seteuid ensures no race condition; but will only log if we see EACCES */ ++ if( stat(authsocket,&sock_st) == 0) { ++ if(uid != 0 && sock_st.st_uid != uid) { ++ fatal("uid %lu attempted to open an agent socket owned by uid %lu", (unsigned long) uid, (unsigned long) sock_st.st_uid); ++ return -1; ++ } ++ } ++ ++ /* ++ * Ensures that the EACCES tested for below can _only_ happen if somebody ++ * is attempting to race the stat above to bypass authentication. ++ */ ++ if( (sock_st.st_mode & S_IWUSR) != S_IWUSR || (sock_st.st_mode & S_IRUSR) != S_IRUSR) { ++ error("ssh-agent socket has incorrect permissions for owner"); ++ return -1; ++ } ++ ++ sunaddr.sun_family = AF_UNIX; ++ strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path)); ++ ++ sock = socket(AF_UNIX, SOCK_STREAM, 0); ++ if (sock < 0) ++ return -1; ++ ++ /* close on exec */ ++ if (fcntl(sock, F_SETFD, 1) == -1) { ++ close(sock); ++ return -1; ++ } ++ ++ errno = 0; ++ seteuid(uid); /* To ensure a race condition is not used to circumvent the stat ++ above, we will temporarily drop UID to the caller */ ++ if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { ++ close(sock); ++ if(errno == EACCES) ++ fatal("MAJOR SECURITY WARNING: uid %lu made a deliberate and malicious attempt to open an agent socket owned by another user", (unsigned long) uid); ++ return -1; ++ } ++ ++ seteuid(0); /* we now continue the regularly scheduled programming */ ++ ++ return sock; ++} ++ ++AuthenticationConnection * ++ssh_get_authentication_connection_for_uid(uid_t uid) ++{ ++ AuthenticationConnection *auth; ++ int sock; ++ ++ sock = ssh_get_authentication_socket_for_uid(uid); ++ ++ /* ++ * Fail if we couldn't obtain a connection. This happens if we ++ * exited due to a timeout. ++ */ ++ if (sock < 0) ++ return NULL; ++ ++ auth = xmalloc(sizeof(*auth)); ++ auth->fd = sock; ++ buffer_init(&auth->identities); ++ auth->howmany = 0; ++ ++ return auth; ++} ++ ++int + pamsshagentauth_find_authorized_keys(const char * user, const char * ruser, const char * servicename) + { + Buffer session_id2 = { 0 }; +@@ -190,7 +289,7 @@ pamsshagentauth_find_authorized_keys(con + OpenSSL_add_all_digests(); + pamsshagentauth_session_id2_gen(&session_id2, user, ruser, servicename); + +- if ((ac = ssh_get_authentication_connection(uid))) { ++ if ((ac = ssh_get_authentication_connection_for_uid(uid))) { + pamsshagentauth_verbose("Contacted ssh-agent of user %s (%u)", ruser, uid); + for (key = ssh_get_first_identity(ac, &comment, 2); key != NULL; key = ssh_get_next_identity(ac, &comment, 2)) + { +diff -up openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in +--- openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in.psaa-build 2016-11-13 04:24:32.000000000 +0100 ++++ openssh-7.4p1/pam_ssh_agent_auth-0.10.3/Makefile.in 2017-02-07 14:40:14.407566921 +0100 +@@ -52,7 +52,7 @@ PATHS= + CC=@CC@ + LD=@LD@ + CFLAGS=@CFLAGS@ +-CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ ++CPPFLAGS=-I.. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ + LIBS=@LIBS@ + AR=@AR@ + AWK=@AWK@ +@@ -61,8 +61,8 @@ INSTALL=@INSTALL@ + PERL=@PERL@ + SED=@SED@ + ENT=@ENT@ +-LDFLAGS=-L. -Lopenbsd-compat/ @LDFLAGS@ +-LDFLAGS_SHARED = @LDFLAGS_SHARED@ ++LDFLAGS=-L.. -L../openbsd-compat/ @LDFLAGS@ ++LDFLAGS_SHARED =-Wl,-z,defs @LDFLAGS_SHARED@ + EXEEXT=@EXEEXT@ + + INSTALL_SSH_PRNG_CMDS=@INSTALL_SSH_PRNG_CMDS@ +@@ -74,7 +74,7 @@ SSHOBJS=xmalloc.o atomicio.o authfd.o bu + + ED25519OBJS=ed25519-donna/ed25519.o + +-PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o get_command_line.o userauth_pubkey_from_pam.o ++PAM_SSH_AGENT_AUTH_OBJS=pam_user_key_allowed2.o iterate_ssh_agent_keys.o userauth_pubkey_from_id.o pam_user_authorized_keys.o get_command_line.o userauth_pubkey_from_pam.o secure_filename.o + + + MANPAGES_IN = pam_ssh_agent_auth.pod +@@ -94,13 +94,13 @@ $(PAM_MODULES): Makefile.in config.h + .c.o: + $(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ + +-LIBCOMPAT=openbsd-compat/libopenbsd-compat.a ++LIBCOMPAT=../openbsd-compat/libopenbsd-compat.a + $(LIBCOMPAT): always + (cd openbsd-compat && $(MAKE)) + always: + +-pam_ssh_agent_auth.so: $(LIBCOMPAT) $(SSHOBJS) $(ED25519OBJS) $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o +- $(LD) $(LDFLAGS_SHARED) -o $@ $(SSHOBJS) $(ED25519OBJS) $(PAM_SSH_AGENT_AUTH_OBJS) $(LDFLAGS) -lopenbsd-compat pam_ssh_agent_auth.o $(LIBS) -lpam ++pam_ssh_agent_auth.so: $(PAM_SSH_AGENT_AUTH_OBJS) pam_ssh_agent_auth.o ../uidswap.o ../ssh-sk-client.o ++ $(LD) $(LDFLAGS_SHARED) -o $@ $(PAM_SSH_AGENT_AUTH_OBJS) ../ssh-sk-client.o $(LDFLAGS) -lssh -lopenbsd-compat pam_ssh_agent_auth.o ../uidswap.o $(LIBS) -lpam + + $(MANPAGES): $(MANPAGES_IN) + pod2man --section=8 --release=v0.10.3 --name=pam_ssh_agent_auth --official --center "PAM" pam_ssh_agent_auth.pod > pam_ssh_agent_auth.8 diff --git a/parallel_test.Makefile b/parallel_test.Makefile deleted file mode 100644 index f49df30..0000000 --- a/parallel_test.Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# just a Makefile parallel_test.sh uses to run stuff in parallel with make -%: - $(MAKE) -j1 -C .t/$* $* - -t-exec-%: - $(MAKE) -j1 -C ".t/t-exec-$*" \ - TEST_SSH_PORT=10$*0 \ - SKIP_LTESTS="$(shell cat .ltests/not-in/$*)" \ - BUILDDIR="$(shell pwd)/.t/t-exec-$*" \ - TEST_SHELL=sh \ - MAKE=make \ - TEST_SSH_TRACE=yes \ - TEST_SSH_FAIL_FATAL=yes \ - t-exec \ diff --git a/parallel_test.sh b/parallel_test.sh deleted file mode 100755 index 682c7e8..0000000 --- a/parallel_test.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/bash -set -uexo pipefail - -# The custom %check script to run the OpenSSH upstream testsuite in parallel. -# -# The upstream testsuite is serial, -# so the idea here is to split the testsuite into several $PARTS: -# * file-tests -# * interop-tests -# * unit -# * ltests-00 -# * ltests-01 -# * ... -# * ltests-23 -# and run them in parallel, using make, each in its own build subtree. - -PARALLEL_MAKEFILE=$1 - -SPLIT=24 -PARTS='file-tests interop-tests unit ' -for ((i = 1; i < SPLIT; i++)); do ii=$(printf %02d $i); - PARTS+="t-exec-$ii " -done - -# work around a selinux restriction: -chcon -t unconfined_exec_t ssh-sk-helper || : - -# work around something else that only crops up in brew -export TEST_SSH_UNSAFE_PERMISSIONS=1 - -# create a .test directory to store all our files in: -mkdir -p .t .ltests/{in,not-in} - -# patch testsuite: use different ports to avoid port collisions -grep -REi 'port=[2-9][0-9]*' regress -sed -i 's|PORT=4242|PORT=$(expr $TEST_SSH_PORT + 1)|' \ - regress/test-exec.sh* -sed -i 's|^P=3301 # test port|P=$(expr $TEST_SSH_PORT + 1)|' \ - regress/multiplex.sh* -sed -i 's|^fwdport=3301|fwdport=$(expr $TEST_SSH_PORT + 1)|' \ - regress/cfgmatch.sh* regress/cfgmatchlisten.sh* -sed -i 's|^LFWD_PORT=.*|LFWD_PORT=$(expr $TEST_SSH_PORT + 1)|' \ - regress/forward-control.sh* -sed -i 's|^RFWD_PORT=.*|RFWD_PORT=$(expr $TEST_SSH_PORT + 2)|' \ - regress/forward-control.sh* -( ! grep -REi 'port=[2-9][0-9]*' regress) # try to find more of those - -# patch testsuite: speed up -sed -i 's|sleep 1$|sleep .25|' regress/forward-control.sh - -# extract LTESTS list to .tests/ltests/all: -grep -Ex 'tests:[[:space:]]*file-tests t-exec interop-tests extra-tests unit' Makefile -echo -ne '\necho-ltests:\n\techo ${LTESTS}' >> regress/Makefile -make -s -C regress echo-ltests | tr ' ' '\n' > .ltests/all - -# separate ltests into $SPLIT roughly equal .tests/ltests/in/$ii parts: -grep -qFx connect .ltests/all -( ! grep -qFx nonex .ltests/all ) -split -d -a2 --number=l/$SPLIT .ltests/all .ltests/in/ -wc -l .ltests/in/* -grep -qFx connect .ltests/in/* - -# generate the inverses of them --- .ltests/not-in/$ii: -( ! grep -qFx nonex .ltests/in/* ) -for ((i = 0; i < SPLIT; i++)); do ii=$(printf %02d $i); - while read -r tname; do - if ! grep -qFx "$tname" ".ltests/in/$ii"; then - echo -n "$tname " >> ".ltests/not-in/$ii" - fi - done < .ltests/all -done -grep . .ltests/not-in/* -( ! grep -q ^connect .ltests/not-in/0 ) -for ((i = 1; i < SPLIT; i++)); do ii=$(printf %02d $i); - grep -q ^connect .ltests/not-in/$ii -done - -# prepare several test directories: -for PART in $PARTS; do - mkdir .t/${PART} - cp -ra * .t/${PART}/ - sed -i "s|abs_top_srcdir=.*|abs_top_srcdir=$(pwd)/.t/${PART}|" \ - .t/${PART}/Makefile - sed -i "s|abs_top_builddir=.*|abs_top_builddir=$(pwd)/.t/${PART}|" \ - .t/${PART}/Makefile - sed -i "s|^BUILDDIR=.*|BUILDDIR=$(pwd)/.t/${PART}|" \ - .t/${PART}/Makefile -done - -# finally, run tests $PARTS in parallel in their own subtrees: -time make -f "$PARALLEL_MAKEFILE" -j$(nproc) $PARTS diff --git a/plans/main.fmf b/plans/main.fmf deleted file mode 100644 index ae0c305..0000000 --- a/plans/main.fmf +++ /dev/null @@ -1,6 +0,0 @@ -summary: Run all tests -execute: - how: tmt -discover: - how: fmf - diff --git a/sources b/sources index 318e485..62f22c0 100644 --- a/sources +++ b/sources @@ -1,3 +1,4 @@ -SHA512 (openssh-10.2p1.tar.gz) = 66f3dd646179e71aaf41c33b6f14a207dc873d71d24f11c130a89dee317ee45398b818e5b94887b5913240964a38630d7bca3e481e0f1eff2e41d9e1cfdbdfc5 -SHA512 (openssh-10.2p1.tar.gz.asc) = f1f71700b1b0b2117aed505488b98b7ebb51ce26e53184b08df0b07aa2c5a1e54dc4d3cbcbe871b5ad849a2a0e22b02af318ff22a68c980ab53b04be03c9bf3c +SHA512 (openssh-9.6p1.tar.gz) = 0ebf81e39914c3a90d7777a001ec7376a94b37e6024baf3e972c58f0982b7ddef942315f5e01d56c00ff95603b4a20ee561ab918ecc55511df007ac138160509 +SHA512 (openssh-9.6p1.tar.gz.asc) = aec5a5bd6ce480a8e5b5879dc55f8186aec90fe61f085aa92ad7d07f324574aa781be09c83b7443a32848d091fd44fb12c1842d49cee77afc351e550ffcc096d +SHA512 (pam_ssh_agent_auth-0.10.4.tar.gz) = caccf72174d15e43f4c86a459ac6448682e62116557cf1e1e828955f3d1731595b238df42adec57860e7f341e92daf5d8285020bcb5018f3b8a5145aa32ee1c2 SHA512 (gpgkey-736060BA.gpg) = df44f3fdbcd1d596705348c7f5aed3f738c5f626a55955e0642f7c6c082995cf36a1b1891bb41b8715cb2aff34fef1c877e0eff0d3507dd00a055ba695757a21 diff --git a/ssh-agent.service b/ssh-agent.service index d0c38dd..812303c 100644 --- a/ssh-agent.service +++ b/ssh-agent.service @@ -8,7 +8,9 @@ Documentation=man:ssh-agent(1) man:ssh-add(1) man:ssh(1) Requires=ssh-agent.socket [Service] -ExecStart=/usr/bin/ssh-agent -D +Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket +ExecStartPre=/usr/bin/rm -f $SSH_AUTH_SOCK +ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK PassEnvironment=SSH_AGENT_PID SuccessExitStatus=2 Type=simple diff --git a/sshd-keygen b/sshd-keygen index b15fc8c..170ada0 100644 --- a/sshd-keygen +++ b/sshd-keygen @@ -9,14 +9,8 @@ case $KEYTYPE in if [[ -r "$FIPS" && $(cat $FIPS) == "1" ]]; then exit 0 fi ;; - "rsa") - if [[ ! -z $SSH_RSA_BITS ]]; then - SSH_KEYGEN_OPTIONS="-b $SSH_RSA_BITS" - fi ;; # always ok - "ecdsa") - if [[ ! -z $SSH_ECDSA_BITS ]]; then - SSH_KEYGEN_OPTIONS="-b $SSH_ECDSA_BITS" - fi ;; + "rsa") ;; # always ok + "ecdsa") ;; *) # wrong argument exit 12 ;; esac @@ -31,7 +25,7 @@ fi rm -f $KEY{,.pub} # create new keys -if ! $KEYGEN -q -t $KEYTYPE $SSH_KEYGEN_OPTIONS -f $KEY -C '' -N '' >&/dev/null; then +if ! $KEYGEN -q -t $KEYTYPE -f $KEY -C '' -N '' >&/dev/null; then exit 1 fi diff --git a/sshd-keygen@.service b/sshd-keygen@.service index aee1303..f27f729 100644 --- a/sshd-keygen@.service +++ b/sshd-keygen@.service @@ -4,9 +4,6 @@ ConditionFileNotEmpty=|!/etc/ssh/ssh_host_%i_key [Service] Type=oneshot -# Set option as empty variable to suppress warnings upon expanding the command line -# when the config file under /etc does not exist or is empty. -Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/sshd ExecStart=/usr/libexec/openssh/sshd-keygen %i diff --git a/sshd.service b/sshd.service index 350624d..0cb2a26 100644 --- a/sshd.service +++ b/sshd.service @@ -9,9 +9,6 @@ Wants=ssh-host-keys-migration.service [Service] Type=notify -# Set option as empty variable to suppress warnings upon expanding the command line -# when the config file under /etc does not exist or is empty. -Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/sshd ExecStart=/usr/sbin/sshd -D $OPTIONS ExecReload=/bin/kill -HUP $MAINPID diff --git a/sshd.sysconfig b/sshd.sysconfig index be40d08..a217ce7 100644 --- a/sshd.sysconfig +++ b/sshd.sysconfig @@ -5,7 +5,3 @@ # example using systemctl enable sshd-keygen@dsa.service to allow creation # of DSA key or systemctl mask sshd-keygen@rsa.service to disable RSA key # creation. - -#SSH_RSA_BITS=3072 -#SSH_ECDSA_BITS=256 -OPTIONS="" diff --git a/sshd@.service b/sshd@.service index 4f12190..be6d3b9 100644 --- a/sshd@.service +++ b/sshd@.service @@ -8,10 +8,6 @@ After=sshd-keygen.target Wants=ssh-host-keys-migration.service [Service] -# Set option as empty variable to avoid warnings upon expanding the command line -# when the config file under /etc does not exist or is empty. -Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/sshd -ExecStart=-/usr/sbin/sshd -i $OPTIONS -o "AuthorizedKeysFile ${CREDENTIALS_DIRECTORY}/ssh.ephemeral-authorized_keys-all .ssh/authorized_keys" +ExecStart=-/usr/sbin/sshd -i $OPTIONS StandardInput=socket -ImportCredential=ssh.ephemeral-authorized_keys-all diff --git a/tests/main.fmf b/tests/main.fmf deleted file mode 100644 index 339889b..0000000 --- a/tests/main.fmf +++ /dev/null @@ -1,11 +0,0 @@ -test: ./runtest.sh -framework: beakerlib -require: - - iproute # needs ip command - - procps-ng # needs ps and pgrep commands - - initscripts # needs service command - - openssh-clients # needs ssh command - - findutils # needs find command - - net-tools # needs netstat command - - libselinux-utils # needs selinuxenabled command - - nmap-ncat # needs nc command diff --git a/tests/pam_ssh_agent_auth/Makefile b/tests/pam_ssh_agent_auth/Makefile index 7b75039..f77eb4d 100644 --- a/tests/pam_ssh_agent_auth/Makefile +++ b/tests/pam_ssh_agent_auth/Makefile @@ -28,7 +28,7 @@ export TESTVERSION=1.0 BUILT_FILES= -FILES=$(METADATA) runtest.sh Makefile pam_save_ssh_var.c +FILES=$(METADATA) runtest.sh Makefile PURPOSE pam_save_ssh_var.c .PHONY: all install download clean diff --git a/tests/pam_ssh_agent_auth/PURPOSE b/tests/pam_ssh_agent_auth/PURPOSE new file mode 100644 index 0000000..59557de --- /dev/null +++ b/tests/pam_ssh_agent_auth/PURPOSE @@ -0,0 +1,7 @@ +PURPOSE of /CoreOS/openssh/Sanity/pam_ssh_agent_auth +Description: This is basic sanity test for pam_ssh_agent_auth +Author: Jakub Jelen + +Created as a response to rhbz#1251777 and previous one rhbz#1225106. +The code of pam module is outdated and compiled with current openssh +version which went through quite enough refactoring. diff --git a/tests/pam_ssh_agent_auth/main.fmf b/tests/pam_ssh_agent_auth/main.fmf deleted file mode 100644 index 5820055..0000000 --- a/tests/pam_ssh_agent_auth/main.fmf +++ /dev/null @@ -1,11 +0,0 @@ -summary: Basic sanity test for pam_ssh_agent_auth -description: | - Created as a response to rhbz#1251777 and previous one rhbz#1225106. - The code of pam module is outdated and compiled with current openssh - version which went through quite enough refactoring. -contact: Jakub Jelen -require+: - - pam_ssh_agent_auth - - gcc # needs to test pam_ssh_agent_auth - - pam-devel # needs to test pam_ssh_agent_auth - - expect # needs to test pam_ssh_agent_auth diff --git a/tests/pam_ssh_agent_auth/runtest.sh b/tests/pam_ssh_agent_auth/runtest.sh index 7587269..297be39 100755 --- a/tests/pam_ssh_agent_auth/runtest.sh +++ b/tests/pam_ssh_agent_auth/runtest.sh @@ -26,6 +26,7 @@ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Include Beaker environment +. /usr/bin/rhts-environment.sh || exit 1 . /usr/share/beakerlib/beakerlib.sh || exit 1 PACKAGE="openssh" @@ -47,8 +48,6 @@ rlJournalStart rlAssertRpm pam_ssh_agent_auth rlImport distribution/fips rlServiceStart sshd - # The following line is a temporary fix for https://pagure.io/releng/issue/12187 - rlRun "rpm --restore filesystem" rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" rlRun "cp ${PAM_MODULE}.c $TmpDir/" rlRun "pushd $TmpDir" @@ -63,6 +62,10 @@ auth sufficient pam_ssh_agent_auth.so file=$AUTH_KEYS' $PAM_SUDO" rlRun "echo $PASS |passwd --stdin $USER" rlPhaseEnd + if ! fipsIsEnabled; then + KEYS+=("dsa") + fi + for KEY in "${KEYS[@]}"; do rlPhaseStartTest "Test with key type $KEY" rlRun "su $USER -c 'ssh-keygen -t $KEY -f ~/.ssh/my_id_$KEY -N \"\"'" 0 @@ -176,9 +179,6 @@ _EOF rlRun "userdel -fr $USER" rlFileRestore rlServiceRestore sshd - # Collect journal data. If the test fails, the log probably - # explains why, which may be difficult to determine without logs. - rlRun "journalctl -b 0 > '$TMT_TEST_DATA'/journalctl.txt" rlPhaseEnd rlJournalPrintText rlJournalEnd diff --git a/tests/port-forwarding/Makefile b/tests/port-forwarding/Makefile index d92f24d..d325bdd 100644 --- a/tests/port-forwarding/Makefile +++ b/tests/port-forwarding/Makefile @@ -28,7 +28,7 @@ export TESTVERSION=1.0 BUILT_FILES= -FILES=$(METADATA) runtest.sh Makefile +FILES=$(METADATA) runtest.sh Makefile PURPOSE .PHONY: all install download clean diff --git a/tests/port-forwarding/PURPOSE b/tests/port-forwarding/PURPOSE new file mode 100644 index 0000000..5a8bc87 --- /dev/null +++ b/tests/port-forwarding/PURPOSE @@ -0,0 +1,3 @@ +PURPOSE of /CoreOS/openssh/Sanity/port-forwarding +Description: Testing port forwarding (ideally all possibilities: -L, -R, -D) +Author: Stanislav Zidek diff --git a/tests/port-forwarding/main.fmf b/tests/port-forwarding/main.fmf deleted file mode 100644 index 8f29286..0000000 --- a/tests/port-forwarding/main.fmf +++ /dev/null @@ -1,4 +0,0 @@ -summary: Testing port forwarding -description: | - Testing port forwarding (ideally all possibilities: -L, -R, -D) -contact: Stanislav Zidek diff --git a/tests/port-forwarding/runtest.sh b/tests/port-forwarding/runtest.sh index d690270..f18f2ae 100755 --- a/tests/port-forwarding/runtest.sh +++ b/tests/port-forwarding/runtest.sh @@ -44,8 +44,6 @@ rlJournalStart rlRun "su - $USER -c \"mkdir .ssh; chmod 700 .ssh; cd .ssh; ssh-keygen -N '' -f id_rsa; cat id_rsa.pub >authorized_keys; chmod 600 authorized_keys\"" rlRun "echo 'LogLevel DEBUG' >>/etc/ssh/sshd_config" rlServiceStart sshd - # Rate limit service restarts by sleeping - rlRun "sleep 3s" rlRun "IP=\$( ip a |grep 'scope global' |grep -w inet |cut -d'/' -f1 |awk '{ print \$2 }' |tail -1 )" rlRun "echo 'IP=$IP'" rlRun "TmpDir=\$(mktemp -d)" 0 "Creating tmp directory" @@ -100,8 +98,6 @@ forwarding_test() { rlRun "echo 'PermitOpen any' >>/etc/ssh/sshd_config" rlRun "echo '$IP anyhost1 anyhost2' >>/etc/hosts" rlRun "service sshd restart" - # Rate limit service restarts by sleeping - rlRun "sleep 3s" for i in `seq 3`; do forwarding_test "success" $FORWARDED anyhost1 $LISTEN forwarding_test "success" $FORWARDED anyhost2 $LISTEN @@ -118,8 +114,6 @@ forwarding_test() { rlRun "echo 'PermitOpen wildportallow:*' >>/etc/ssh/sshd_config" rlRun "echo '$IP wildportallow wildportdeny' >>/etc/hosts" rlRun "service sshd restart" - # Rate limit service restarts by sleeping - rlRun "sleep 3s" forwarding_test "success" $FORWARDED wildportallow $LISTEN ((FORWARDED+=1)) ((LISTEN+=1)) @@ -128,8 +122,6 @@ forwarding_test() { ((LISTEN+=1)) rlFileRestore --namespace port_wildcard rlRun "service sshd restart" - # Rate limit service restarts by sleeping - rlRun "sleep 3s" rlPhaseEnd fi @@ -139,8 +131,6 @@ forwarding_test() { rlRun "echo 'PermitOpen *:$LISTEN' >>/etc/ssh/sshd_config" rlRun "echo '$IP wildhost1 wildhost2' >>/etc/hosts" rlRun "service sshd restart" - # Rate limit service restarts by sleeping - rlRun "sleep 3s" forwarding_test "success" $FORWARDED wildhost1 $LISTEN ((FORWARDED+=1)) forwarding_test "success" $FORWARDED wildhost2 $LISTEN @@ -157,9 +147,6 @@ forwarding_test() { rlFileRestore rlServiceRestore sshd rlRun "rm -r $TmpDir" 0 "Removing tmp directory" - # Collect journal data. If the test fails, the log probably - # explains why, which may be difficult to determine without logs. - rlRun "journalctl -b 0 > '$TMT_TEST_DATA'/journalctl.txt" rlPhaseEnd rlJournalPrintText rlJournalEnd diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100644 index 0000000..8086af2 --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,31 @@ +--- +# Tests for docker container +- hosts: localhost + tags: + - container + # no compatible tests + +# Tests for classic environment and Atomic Host +- hosts: localhost + tags: + - all + - classic + - atomic + roles: + - role: standard-test-beakerlib + tests: + - port-forwarding + - pam_ssh_agent_auth + required_packages: + - iproute # needs ip command + - procps-ng # needs ps and pgrep commands + - initscripts # needs service command + - openssh-clients # needs ssh command + - findutils # needs find command + - net-tools # needs netstat command + - libselinux-utils # needs selinuxenabled command + - nmap-ncat # needs nc command + - pam_ssh_agent_auth + - gcc # needs to test pam_ssh_agent_auth + - pam-devel # needs to test pam_ssh_agent_auth + - expect # needs to test pam_ssh_agent_auth