diff --git a/.gitignore b/.gitignore index 98996cc..7004cb5 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,3 @@ pam_ssh_agent_auth-0.9.2.tar.bz2 /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/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/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/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/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..0f65279 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,22 +227,20 @@ 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) +- return (sftp_server_main(argc, argv, user_pw)); ++ return (sftp_server_main(argc, argv, user_pw, 0)); + } +diff -up openssh-8.6p1/sshd-session.c.log-in-chroot openssh-8.6p1/sshd-session.c +--- openssh-8.6p1/sshd-session.c.log-in-chroot 2021-04-19 14:43:08.543843426 +0200 ++++ openssh-8.6p1/sshd-session.c 2021-04-19 14:43:08.545843441 +0200 +@@ -559,7 +559,7 @@ privsep_postauth(struct ssh *ssh, Authct #endif /* New socket pair */ @@ -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..96161cb --- /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-session.c b/sshd-session.c +index 2871fe9..39b9c08 100644 +--- a/sshd-session.c ++++ b/sshd-session.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 61% rename from 0019-openssh-6.6p1-GSSAPIEnablek5users.patch rename to openssh-6.6p1-GSSAPIEnablek5users.patch index 4c0a60b..7fef831 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,7 +38,7 @@ 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 { +@@ -578,7 +578,7 @@ typedef enum { sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, @@ -62,7 +47,7 @@ index 8f4b2b43e..5e40f1b00 100644 sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, -@@ -675,6 +678,7 @@ static struct { +@@ -600,14 +600,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,17 @@ 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 -up openssh-9.8p1/servconf.c.xxx openssh-9.8p1/servconf.c +--- openssh-9.8p1/servconf.c.xxx 2024-07-11 13:51:19.969960781 +0200 ++++ openssh-9.8p1/servconf.c 2024-07-11 13:51:30.938231250 +0200 diff --git a/0003-openssh-6.6p1-allow-ip-opts.patch b/openssh-6.6p1-allow-ip-opts.patch similarity index 68% rename from 0003-openssh-6.6p1-allow-ip-opts.patch rename to openssh-6.6p1-allow-ip-opts.patch index ea11b6c..995e04e 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-session.c.ip-opts 2016-07-25 13:58:48.998507834 +0200 ++++ openssh/sshd-session.c 2016-07-25 14:01:28.346469878 +0200 +@@ -1507,12 +1507,32 @@ check_ip_options(struct ssh *ssh) if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts, &option_size) >= 0 && option_size != 0) { @@ -50,6 +40,3 @@ index cb4b0523d..1c72e664a 100644 } #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..4eb0998 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,11 +15,86 @@ 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; +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 + SSHD_SESSION=$(libexecdir)/sshd-session + SSH_PKCS11_HELPER=$(libexecdir)/ssh-pkcs11-helper + SSH_SK_HELPER=$(libexecdir)/ssh-sk-helper +@@ -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) sshd-session$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) ++TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) ssh-keycat$(EXEEXT) + + XMSS_OBJS=\ + ssh-xmss.o \ +@@ -190,6 +191,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) + ssh-sk-helper$(EXEEXT): $(LIBCOMPAT) libssh.a $(SKHELPER_OBJS) + $(LD) -o $@ $(SKHELPER_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS) $(LIBFIDO2) $(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 Authctxt *the_authctxt; extern int inetd_flag; @@ -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,7 +124,7 @@ 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); @@ -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 80% rename from 0015-openssh-6.6p1-kuserok.patch rename to openssh-6.6p1-kuserok.patch index a403c7c..e43128b 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. @@ -299,7 +268,7 @@ index cae0fd0b4..c360fcfff 100644 .It Cm KexAlgorithms Specifies the permitted KEX (Key Exchange) algorithms that the server will offer to clients. -@@ -1354,6 +1358,7 @@ Available keywords are +@@ -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..16d98cd --- /dev/null +++ b/openssh-6.6p1-privsep-selinux.patch @@ -0,0 +1,120 @@ +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) { + #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-session.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100 ++++ openssh-7.4p1/sshd-session.c 2016-12-23 18:59:13.808124269 +0100 +@@ -540,6 +540,10 @@ privsep_preauth_child(void) + /* Demote the private keys to public keys. */ + demote_sensitive_data(); + ++#ifdef WITH_SELINUX ++ ssh_selinux_change_context("sshd_net_t"); ++#endif ++ + /* Demote the child */ + if (privsep_chroot) { + /* Change our root directory */ +@@ -403,7 +403,7 @@ privsep_postauth(struct ssh *ssh, Authct + * fd passing, as AFAIK PTY allocation on this platform doesn't require + * special privileges to begin with. + */ +-#if defined(DISABLE_FD_PASSING) && !defined(HAVE_CYGWIN) ++#if defined(DISABLE_FD_PASSING) && !defined(HAVE_CYGWIN) && !defined(WITH_SELINUX) + skip_privdrop = 1; + #endif + diff --git a/openssh-6.7p1-coverity.patch b/openssh-6.7p1-coverity.patch new file mode 100644 index 0000000..ffe0c69 --- /dev/null +++ b/openssh-6.7p1-coverity.patch @@ -0,0 +1,248 @@ +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 GCC diagnostic pop + for ((p = strsep(&cp, ",")); p && *p != '\0'; + (p = strsep(&cp, ","))) { + if (sshbuf_len(buf) != 0 && +diff -up openssh-8.5p1/krl.c.coverity openssh-8.5p1/krl.c +--- openssh-8.5p1/krl.c.coverity 2021-03-02 11:31:47.000000000 +0100 ++++ openssh-8.5p1/krl.c 2021-03-24 12:03:33.783968166 +0100 +@@ -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 +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-session.c.coverity openssh-7.4p1/sshd-session.c +--- openssh-7.4p1/sshd-session.c.coverity 2016-12-23 16:40:26.897788690 +0100 ++++ openssh-7.4p1/sshd-session.c 2016-12-23 16:40:26.904788692 +0100 +@@ -691,8 +691,10 @@ privsep_preauth(Authctxt *authctxt) + + privsep_preauth_child(ssh); + 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 73% rename from 0036-openssh-7.1p2-audit-race-condition.patch rename to openssh-7.1p2-audit-race-condition.patch index 863f700..57ad148 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,7 +106,7 @@ 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); @@ -129,7 +115,7 @@ index 107edcf91..80282dfd8 100644 #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); @@ -150,7 +136,7 @@ index 107edcf91..80282dfd8 100644 return ret; } -@@ -1490,6 +1517,33 @@ child_close_fds(struct ssh *ssh) +@@ -1538,6 +1565,33 @@ child_close_fds(void) log_redirect_stderr_to(NULL); } @@ -165,7 +151,7 @@ index 107edcf91..80282dfd8 100644 +#endif + + /* remove hostkey from the child's memory */ -+ /* FIXME beldmit destroy_sensitive_data(ssh); */ ++ destroy_sensitive_data(ssh); + /* + * We can audit this, because we hacked the pipe to direct the + * messages over postauth child. But this message requires answer @@ -184,11 +170,11 @@ 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 */ +- /* remove hostkey from the child's memory */ - destroy_sensitive_data(ssh); - ssh_packet_clear_keys(ssh); - /* Don't audit this - both us and the parent would be talking to the @@ -198,6 +184,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 70% rename from 0006-openssh-7.2p2-x11.patch rename to openssh-7.2p2-x11.patch index dceef7b..6db16be 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; 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..e28c62e 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 NUM_SOCKS 10 + + /* -- 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.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 82% rename from 0035-openssh-7.6p1-audit.patch rename to openssh-7.6p1-audit.patch index 1635f9f..2c7ddc5 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) ++{ ++ 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. +@@ -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,211 @@ audit_connection_from(const char *host, /* not implemented */ } @@ -381,7 +555,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; } } @@ -496,238 +670,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,47 +726,23 @@ 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) +- mm_audit_event(ssh, SSH_INVALID_USER); +-#endif + } + #ifdef USE_PAM + if (options.use_pam) +diff -up openssh-8.6p1/auth2-hostbased.c.audit openssh-8.6p1/auth2-hostbased.c +--- openssh-8.6p1/auth2-hostbased.c.audit 2021-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) && @@ -830,7 +751,7 @@ index 976484fc5..e9421a868 100644 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,11 +772,10 @@ 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) && @@ -864,7 +784,7 @@ index b7300ca9e..9f3371c07 100644 sshbuf_ptr(b), sshbuf_len(b), (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, ssh->compat, &sig_details) == 0) { -@@ -326,6 +326,20 @@ done: +@@ -305,6 +305,20 @@ done: return authenticated; } @@ -885,24 +805,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 */ + int auth_activate_options(struct ssh *, struct sshauthopt *); +@@ -239,6 +241,8 @@ struct passwd * getpwnamallow(struct ssh + char *, const char *, const char *, const char *, struct sshauthopt **); + int auth_check_authkeys_file(struct passwd *, FILE *, char *, + struct sshkey *, const char *, const char *, struct sshauthopt **); ++int user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, ++ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); + FILE *auth_openkeyfile(const char *, struct passwd *, int); + FILE *auth_openprincipals(const char *, struct passwd *, int); + +diff -up openssh-8.6p1/cipher.c.audit openssh-8.6p1/cipher.c +--- openssh-8.6p1/cipher.c.audit 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/cipher.c 2021-04-19 16:47:35.755062122 +0200 @@ -64,25 +64,6 @@ struct sshcipher_ctx { const struct sshcipher *cipher; }; @@ -929,7 +868,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 +877,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,11 +907,10 @@ 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" @@ -981,7 +918,7 @@ index 5f9530908..44f350ce8 100644 /* prototype */ static int kex_choose_conf(struct ssh *, uint32_t seq); -@@ -820,12 +821,16 @@ kex_start_rekex(struct ssh *ssh) +@@ -816,12 +817,16 @@ kex_start_rekex(struct ssh *ssh) } static int @@ -1000,7 +937,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 +951,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 +970,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 +979,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 +988,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 +999,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 +1036,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 +1048,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 +1072,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 kexmlkem768x25519.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,8 +1105,8 @@ 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 *); @@ -1169,7 +1114,7 @@ index 453469665..b2f501790 100644 /* 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 +1126,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 +1137,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 +1149,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 +1161,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 +1170,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 +1190,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 +1220,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 +1229,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,7 +1238,7 @@ 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 @@ -1302,15 +1247,16 @@ index 453469665..b2f501790 100644 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 +1296,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 +1304,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 +1324,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 +1427,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 +1445,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 +1457,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 +1467,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 +1490,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 +1503,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,7 +1536,7 @@ 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) +@@ -1095,3 +1137,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc return &ci; } @@ -1676,11 +1620,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 *); @@ -1691,7 +1634,7 @@ index 12c489c33..1bcbfd305 100644 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 *); +@@ -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 +1648,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 +1659,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 +1673,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 +1698,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 +1720,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 +1728,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 +1801,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 u_int utmp_len; + extern int startup_pipe; +-extern void destroy_sensitive_data(void); +extern void destroy_sensitive_data(struct ssh *); 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,8 +1836,8 @@ 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 @@ -1918,10 +1859,11 @@ index d034f5c65..107edcf91 100644 #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 */ + /* remove hostkey from the child's memory */ +- destroy_sensitive_data(); + destroy_sensitive_data(ssh); ssh_packet_clear_keys(ssh); + /* Don't audit this - both us and the parent would be talking to the @@ -1930,7 +1872,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 +1882,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 +1898,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); } @@ -1993,7 +1935,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 +1946,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 +1963,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,7 +1979,7 @@ 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()) @@ -2046,10 +1988,9 @@ index d034f5c65..107edcf91 100644 } /* 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,25 +2018,53 @@ 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); +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 +@@ -279,6 +280,15 @@ close_listen_socks(void) + num_listen_socks = 0; + } + ++/* ++ * Is this process listening for clients (i.e. not specific to any specific ++ * client connection?) ++ */ ++int listening_for_clients(void) ++{ ++ return num_listen_socks > 0; ++} ++ + /* Allocate and initialise the children array */ + static void + child_alloc(void) +@@ -1204,6 +1259,7 @@ server_accept_loop(int *sock_in, int *so + if (received_sigterm) { + logit("Received signal %d; terminating.", + (int) received_sigterm); ++ /* destroy_sensitive_data(ssh, 0); FIXME */ + close_listen_socks(); + if (options.pid_file != NULL) + unlink(options.pid_file); +diff -up openssh-8.6p1/sshd-session.c.audit openssh-8.6p1/sshd-session.c +--- openssh-8.6p1/sshd-session.c.audit 2021-04-19 16:47:35.727061907 +0200 ++++ openssh-8.6p1/sshd-session.c 2021-04-19 16:47:35.759062152 +0200 +@@ -122,6 +122,7 @@ + #include "ssh-gss.h" + #endif + #include "monitor_wrap.h" ++#include "audit.h" + #include "ssh-sandbox.h" + #include "auth-options.h" + #include "version.h" +@@ -260,8 +261,44 @@ struct sshbuf *loginmsg; struct sshbuf *loginmsg; /* Prototypes for various functions defined later in this file. */ -void destroy_sensitive_data(void); -void demote_sensitive_data(void); -+void destroy_sensitive_data(struct ssh *ssh); -+void demote_sensitive_data(struct ssh *ssh); - - /* XXX reduce to stub once postauth split */ - int -@@ -202,6 +202,35 @@ mm_is_monitor(void) - return (pmonitor && pmonitor->m_pid > 0); - } - ++void destroy_sensitive_data(struct ssh *); ++void demote_sensitive_data(struct ssh *); ++ +static int +sshkey_is_private(const struct sshkey *k) +{ @@ -2108,6 +2077,12 @@ index d6bece941..e49e4fb51 100644 + RSA_get0_key(rsa, NULL, NULL, &d); + return d != NULL; + } ++ case KEY_DSA_CERT: ++ case KEY_DSA: { ++ const BIGNUM *priv_key; ++ DSA_get0_key(k->dsa, NULL, &priv_key); ++ return priv_key != NULL; ++ } +#ifdef OPENSSL_HAS_ECC + case KEY_ECDSA_CERT: + case KEY_ECDSA: { @@ -2125,13 +2100,13 @@ index d6bece941..e49e4fb51 100644 + } +} + + static void do_ssh2_kex(struct ssh *); + /* - * 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) +@@ -377,18 +387,40 @@ grace_alarm_handler(int sig) _exit(EXIT_LOGIN_GRACE); } - + -/* Destroy the host and server keys. They will no longer be needed. */ +/* + * Destroy the host and server keys. They will no longer be needed. Careful, @@ -2172,7 +2147,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 +2187,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) + pmonitor->m_pkex = &ssh->kex; + + 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,7 +2232,7 @@ index d6bece941..e49e4fb51 100644 reseed_prngs(); -@@ -1365,6 +1434,9 @@ main(int ac, char **av) +@@ -2333,6 +2389,9 @@ main(int ac, char **av) do_authenticated(ssh, authctxt); /* The connection has been terminated. */ @@ -2231,7 +2242,7 @@ index d6bece941..e49e4fb51 100644 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,14 @@ do_ssh2_kex(struct ssh *ssh) void cleanup_exit(int i) { @@ -2246,7 +2257,7 @@ index d6bece941..e49e4fb51 100644 extern int auth_attempted; /* monitor.c */ if (the_active_state != NULL && the_authctxt != NULL) { -@@ -1426,7 +1506,9 @@ cleanup_exit(int i) +@@ -2525,7 +2593,9 @@ cleanup_exit(int i) } #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ @@ -2257,34 +2268,3 @@ index d6bece941..e49e4fb51 100644 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; - } - -+/* -+ * Is this process listening for clients (i.e. not specific to any specific -+ * client connection?) -+ */ -+int listening_for_clients(void) -+{ -+ return num_listen_socks > 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 - diff --git a/0023-openssh-7.6p1-cleanup-selinux.patch b/openssh-7.6p1-cleanup-selinux.patch similarity index 63% rename from 0023-openssh-7.6p1-cleanup-selinux.patch rename to openssh-7.6p1-cleanup-selinux.patch index d018772..cfe11ad 100644 --- a/0023-openssh-7.6p1-cleanup-selinux.patch +++ b/openssh-7.6p1-cleanup-selinux.patch @@ -1,25 +1,7 @@ -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,8 @@ /* import */ extern ServerOptions options; @@ -28,7 +10,7 @@ index c326a69ba..b7300ca9e 100644 extern struct authmethod_cfg methodcfg_pubkey; static char * -@@ -483,7 +485,8 @@ match_principals_command(struct passwd *user_pw, 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, @@ -38,21 +20,20 @@ index c326a69ba..b7300ca9e 100644 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) 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 +43,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 +52,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,11 +64,24 @@ 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,10 +49,6 @@ #include #endif @@ -99,7 +92,7 @@ index 4d56745f7..ab083a637 100644 /* 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 +102,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 +113,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,7 +122,7 @@ 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 */ @@ -138,7 +131,7 @@ index 4d56745f7..ab083a637 100644 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 +141,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"); @@ -162,7 +155,7 @@ index 4d56745f7..ab083a637 100644 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 +168,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 +202,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,27 +211,10 @@ 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 @@ +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,8 @@ #include "openbsd-compat/openbsd-compat.h" extern ServerOptions options; @@ -247,7 +223,7 @@ index c92a0cba6..66d0c2a6b 100644 /* 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) +@@ -183,7 +186,9 @@ platform_setusercontext_post_groups(stru } #endif /* HAVE_SETPCRED */ #ifdef WITH_SELINUX @@ -258,37 +234,10 @@ index c92a0cba6..66d0c2a6b 100644 #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, - - if ((pid = subprocess(tag, command, ac, av, &f, - SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_UNSAFE_PATH| -- SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL)) == 0) -+ SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL, 0, NULL)) == 0) - 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; +diff -up openssh/sshd-session.c.refactor openssh/sshd-session.c +--- openssh/sshd-session.c.refactor 2019-04-04 13:19:12.275822068 +0200 ++++ openssh/sshd-session.c 2019-04-04 13:19:51.270195262 +0200 +@@ -158,7 +158,7 @@ int debug_flag = 0; int debug_flag = 0; /* Flag indicating that the daemon is being started from inetd. */ @@ -297,7 +246,7 @@ index 4a5eaa1ff..d6bece941 100644 /* debug goes to stderr unless inetd_flag is set */ static int log_stderr = 0; -@@ -1337,7 +1337,9 @@ main(int ac, char **av) +@@ -2192,7 +2192,9 @@ main(int ac, char **av) } #endif #ifdef WITH_SELINUX @@ -308,6 +257,15 @@ index 4a5eaa1ff..d6bece941 100644 #endif #ifdef USE_PAM if (options.use_pam) { --- -2.52.0 - +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| +- SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL)) == 0) ++ SSH_SUBPROCESS_PRESERVE_ENV, NULL, NULL, NULL, 0, NULL)) == 0) + goto out; + + load_hostkeys_file(hostkeys, hostfile_hostname, tag, f, 1); diff --git a/0038-openssh-7.7p1-fips.patch b/openssh-7.7p1-fips.patch similarity index 65% rename from 0038-openssh-7.7p1-fips.patch rename to openssh-7.7p1-fips.patch index 18ebed3..5d8da08 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,11 +72,10 @@ 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-names.c.fips openssh-8.6p1/kex-names.c +--- openssh-8.6p1/kex-names.c.fips 2021-05-06 12:08:36.489926807 +0200 ++++ openssh-8.6p1/kex-names.c 2021-05-06 12:08:36.498926877 +0200 +@@ -39,6 +39,7 @@ #ifdef WITH_OPENSSL #include @@ -112,7 +83,7 @@ index 31e395aa2..1360a4095 100644 #include #endif -@@ -208,7 +209,10 @@ kex_names_valid(const char *names) +@@ -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,31 +95,508 @@ 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], +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 @@ - /* 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 + #ifdef WITH_OPENSSL + ++#include + #include + + #include +@@ -115,6 +116,10 @@ input_kex_dh_gex_group(int type, u_int32 + r = SSH_ERR_ALLOC_FAIL; + goto out; + } ++ if (FIPS_mode() && dh_is_known_group(kex->dh) == 0) { ++ r = SSH_ERR_INVALID_ARGUMENT; ++ goto out; ++ } + p = g = NULL; /* belong to kex->dh now */ + + /* generate and send 'e', client DH public key */ +diff -up openssh-8.6p1/myproposal.h.fips openssh-8.6p1/myproposal.h +--- openssh-8.6p1/myproposal.h.fips 2021-04-16 05:55:25.000000000 +0200 ++++ openssh-8.6p1/myproposal.h 2021-05-06 12:08:36.498926877 +0200 +@@ -57,6 +57,18 @@ + "rsa-sha2-512," \ + "rsa-sha2-256" + ++#define KEX_FIPS_PK_ALG \ ++ "ecdsa-sha2-nistp256-cert-v01@openssh.com," \ ++ "ecdsa-sha2-nistp384-cert-v01@openssh.com," \ ++ "ecdsa-sha2-nistp521-cert-v01@openssh.com," \ ++ "rsa-sha2-512-cert-v01@openssh.com," \ ++ "rsa-sha2-256-cert-v01@openssh.com," \ ++ "ecdsa-sha2-nistp256," \ ++ "ecdsa-sha2-nistp384," \ ++ "ecdsa-sha2-nistp521," \ ++ "rsa-sha2-512," \ ++ "rsa-sha2-256" ++ + #define KEX_SERVER_ENCRYPT \ + "chacha20-poly1305@openssh.com," \ + "aes128-ctr,aes192-ctr,aes256-ctr," \ +@@ -78,6 +92,27 @@ + + #define KEX_CLIENT_MAC KEX_SERVER_MAC + ++#define KEX_FIPS_ENCRYPT \ ++ "aes128-ctr,aes192-ctr,aes256-ctr," \ ++ "aes128-cbc,3des-cbc," \ ++ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \ ++ "aes128-gcm@openssh.com,aes256-gcm@openssh.com" ++#define KEX_DEFAULT_KEX_FIPS \ ++ "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" ++#define KEX_FIPS_MAC \ ++ "hmac-sha1," \ ++ "hmac-sha2-256," \ ++ "hmac-sha2-512," \ ++ "hmac-sha1-etm@openssh.com," \ ++ "hmac-sha2-256-etm@openssh.com," \ ++ "hmac-sha2-512-etm@openssh.com" ++ + /* Not a KEX value, but here so all the algorithm defaults are together */ + #define SSH_ALLOWED_CA_SIGALGS \ + "ssh-ed25519," \ +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 + #include ++#include + #ifdef USE_SYSTEM_GLOB + # include + #else +@@ -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 */ +- def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher); +- def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac); +- def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex); +- def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); +- def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); ++ def_cipher = match_filter_allowlist((FIPS_mode() ? ++ KEX_FIPS_ENCRYPT : KEX_CLIENT_ENCRYPT), all_cipher); ++ def_mac = match_filter_allowlist((FIPS_mode() ? ++ KEX_FIPS_MAC : KEX_CLIENT_MAC), all_mac); ++ def_kex = match_filter_allowlist((FIPS_mode() ? ++ KEX_DEFAULT_KEX_FIPS : KEX_CLIENT_KEX), all_kex); ++ def_key = match_filter_allowlist((FIPS_mode() ? ++ KEX_FIPS_PK_ALG : KEX_DEFAULT_PK_ALG), all_key); ++ def_sig = match_filter_allowlist((FIPS_mode() ? ++ KEX_FIPS_PK_ALG : SSH_ALLOWED_CA_SIGALGS), all_sig); + #define ASSEMBLE(what, defaults, all) \ + do { \ + if ((r = kex_assemble_names(&options->what, \ +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 ++#ifdef __NR_socket ++ SC_DENY(__NR_socket, EACCES), ++#endif + #ifdef __NR_openat + SC_DENY(__NR_openat, EACCES), + #endif +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 + #include + #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 */ +- def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher); +- def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac); +- def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex); +- def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); +- def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); ++ def_cipher = match_filter_allowlist((FIPS_mode() ? ++ KEX_FIPS_ENCRYPT : KEX_SERVER_ENCRYPT), all_cipher); ++ def_mac = match_filter_allowlist((FIPS_mode() ? ++ KEX_FIPS_MAC : KEX_SERVER_MAC), all_mac); ++ def_kex = match_filter_allowlist((FIPS_mode() ? ++ KEX_DEFAULT_KEX_FIPS : KEX_SERVER_KEX), all_kex); ++ def_key = match_filter_allowlist((FIPS_mode() ? ++ KEX_FIPS_PK_ALG : KEX_DEFAULT_PK_ALG), all_key); ++ def_sig = match_filter_allowlist((FIPS_mode() ? ++ KEX_FIPS_PK_ALG : SSH_ALLOWED_CA_SIGALGS), all_sig); + #define ASSEMBLE(what, defaults, all) \ + do { \ + if ((r = kex_assemble_names(&o->what, defaults, all)) != 0) \ +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 ++#include + #include "openbsd-compat/openssl-compat.h" + #include "openbsd-compat/sys-queue.h" + +@@ -1516,6 +1517,10 @@ main(int ac, char **av) + exit(0); + } + ++ if (FIPS_mode()) { ++ debug("FIPS mode initialized"); ++ } ++ + /* Expand SecurityKeyProvider if it refers to an environment variable */ + if (options.sk_provider != NULL && *options.sk_provider == '$' && + strlen(options.sk_provider) > 1) { +diff -up openssh-8.6p1/sshconnect2.c.fips openssh-8.6p1/sshconnect2.c +--- openssh-8.6p1/sshconnect2.c.fips 2021-05-06 12:08:36.485926777 +0200 ++++ openssh-8.6p1/sshconnect2.c 2021-05-06 12:08:36.501926900 +0200 +@@ -45,6 +45,8 @@ + #include + #endif + ++#include ++ + #include "openbsd-compat/sys-queue.h" + + #include "xmalloc.h" +@@ -269,36 +271,41 @@ ssh_kex2(struct ssh *ssh, char *host, st + + #if defined(GSSAPI) && defined(WITH_OPENSSL) + if (options.gss_keyex) { +- /* Add the GSSAPI mechanisms currently supported on this +- * client to the key exchange algorithm proposal */ +- orig = myproposal[PROPOSAL_KEX_ALGS]; +- +- if (options.gss_server_identity) { +- gss_host = xstrdup(options.gss_server_identity); +- } else if (options.gss_trust_dns) { +- gss_host = remote_hostname(ssh); +- /* Fall back to specified host if we are using proxy command +- * and can not use DNS on that socket */ +- if (strcmp(gss_host, "UNKNOWN") == 0) { +- free(gss_host); ++ if (FIPS_mode()) { ++ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); ++ options.gss_keyex = 0; ++ } else { ++ /* Add the GSSAPI mechanisms currently supported on this ++ * client to the key exchange algorithm proposal */ ++ orig = myproposal[PROPOSAL_KEX_ALGS]; ++ ++ if (options.gss_server_identity) { ++ gss_host = xstrdup(options.gss_server_identity); ++ } else if (options.gss_trust_dns) { ++ gss_host = remote_hostname(ssh); ++ /* Fall back to specified host if we are using proxy command ++ * and can not use DNS on that socket */ ++ if (strcmp(gss_host, "UNKNOWN") == 0) { ++ free(gss_host); ++ gss_host = xstrdup(host); ++ } ++ } else { + gss_host = xstrdup(host); + } +- } else { +- gss_host = xstrdup(host); +- } + +- gss = ssh_gssapi_client_mechanisms(gss_host, +- options.gss_client_identity, options.gss_kex_algorithms); +- if (gss) { +- debug("Offering GSSAPI proposal: %s", gss); +- xasprintf(&myproposal[PROPOSAL_KEX_ALGS], +- "%s,%s", gss, orig); +- +- /* If we've got GSSAPI algorithms, then we also support the +- * 'null' hostkey, as a last resort */ +- orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; +- xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], +- "%s,null", orig); ++ gss = ssh_gssapi_client_mechanisms(gss_host, ++ options.gss_client_identity, options.gss_kex_algorithms); ++ if (gss) { ++ debug("Offering GSSAPI proposal: %s", gss); ++ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], ++ "%s,%s", gss, orig); ++ ++ /* If we've got GSSAPI algorithms, then we also support the ++ * 'null' hostkey, as a last resort */ ++ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; ++ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], ++ "%s,null", orig); ++ } + } + } + #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 +@@ -77,6 +78,7 @@ + #ifdef WITH_OPENSSL + #include + #include ++#include + #include "openbsd-compat/openssl-compat.h" + #endif + +@@ -1931,6 +1931,13 @@ main(int ac, char **av) + &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) + do_log2_r(r, ll, "Unable to load host key \"%s\"", + options.host_key_files[i]); ++ if (FIPS_mode() && key != NULL && (sshkey_type_plain(key->type) == KEY_ED25519_SK ++ || sshkey_type_plain(key->type) == KEY_ED25519)) { ++ logit_f("sshd: Ed25519 keys are not allowed in FIPS mode, skipping %s", options.host_key_files[i]); ++ sshkey_free(key); ++ key = NULL; ++ continue; ++ } + if (sshkey_is_sk(key) && + key->sk_flags & SSH_SK_USER_PRESENCE_REQD) { + debug("host key %s requires user presence, ignoring", +@@ -2110,6 +2113,10 @@ main(int ac, char **av) + /* Reinitialize the log (because of the fork above). */ + log_init(__progname, options.log_level, options.log_facility, log_stderr); + ++ if (FIPS_mode()) { ++ debug("FIPS mode initialized"); ++ } ++ + /* + * Chdir to the root directory so that the current disk can be + * unmounted if desired. +diff -up openssh-8.6p1/sshd-session.c.fips openssh-8.6p1/sshd-session.c +--- a/sshd-session.c.fips 2021-05-06 12:08:36.493926838 +0200 ++++ b/sshd-session.c 2021-05-06 12:13:56.501492639 +0200 +@@ -78,6 +79,7 @@ + #include + #include + #include ++#include + #include "openbsd-compat/openssl-compat.h" + #endif + +@@ -2506,10 +2513,14 @@ do_ssh2_kex(struct ssh *ssh) + if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) + orig = NULL; + +- 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 + #endif + + #include "crypto_api.h" +@@ -57,6 +58,7 @@ + #define SSHKEY_INTERNAL + #include "sshkey.h" + #include "match.h" ++#include "log.h" + #include "ssh-sk.h" + + #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; ++ if (FIPS_mode()) { ++ switch (impl->type) { ++ case KEY_ED25519: ++ case KEY_ED25519_SK: ++ case KEY_ED25519_CERT: ++ case KEY_ED25519_SK_CERT: ++ continue; ++ break; ++ default: ++ break; ++ } ++ } + if (!include_sigonly && impl->sigonly) + continue; + if ((certs_only && !impl->cert) || (plain_only && impl->cert)) +@@ -1503,6 +1503,20 @@ sshkey_read(struct sshkey *ret, char **c + return SSH_ERR_EC_CURVE_MISMATCH; + } + ++ switch (type) { ++ case KEY_ED25519: ++ case KEY_ED25519_SK: ++ case KEY_ED25519_CERT: ++ case KEY_ED25519_SK_CERT: ++ if (FIPS_mode()) { ++ sshkey_free(k); ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } ++ break; ++ default: ++ break; ++ } + /* Fill in ret from parsed key */ + sshkey_free_contents(ret); + *ret = *k; +@@ -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 ((impl = sshkey_impl_from_key(key)) == NULL) + return SSH_ERR_KEY_TYPE_UNKNOWN; + if ((r = sshkey_unshield_private(key)) != 0) +@@ -2973,6 +2978,10 @@ sshkey_verify(const struct sshkey *key, + *detailsp = NULL; + if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE) + return SSH_ERR_INVALID_ARGUMENT; ++ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) { ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } + if ((impl = sshkey_impl_from_key(key)) == NULL) + return SSH_ERR_KEY_TYPE_UNKNOWN; + return impl->funcs->verify(key, sig, siglen, data, dlen, +diff -up openssh-8.6p1/ssh-keygen.c.fips openssh-8.6p1/ssh-keygen.c +--- openssh-8.6p1/ssh-keygen.c.fips 2021-05-06 12:08:36.467926637 +0200 ++++ openssh-8.6p1/ssh-keygen.c 2021-05-06 12:08:36.503926916 +0200 +@@ -20,6 +20,7 @@ + + #ifdef WITH_OPENSSL + #include ++#include + #include + #include "openbsd-compat/openssl-compat.h" + #endif +@@ -69,6 +69,7 @@ + #include "cipher.h" + + #define DEFAULT_KEY_TYPE_NAME "ed25519" ++#define FIPS_DEFAULT_KEY_TYPE_NAME "rsa" + + /* + * Default number of bits in the RSA, DSA and ECDSA keys. These value can be +@@ -205,6 +205,12 @@ type_bits_valid(int type, const char *na + #endif + } + #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) +@@ -266,7 +267,7 @@ ask_filename(struct passwd *pw, const ch + char *name = NULL; + + if (key_type_name == NULL) +- name = _PATH_SSH_CLIENT_ID_ED25519; ++ name = FIPS_mode() ? _PATH_SSH_CLIENT_ID_RSA : _PATH_SSH_CLIENT_ID_ED25519; + else { + switch (sshkey_type_from_shortname(key_type_name)) { + #ifdef WITH_DSA +@@ -1098,9 +1104,17 @@ do_gen_all_hostkeys(struct passwd *pw) + first = 1; + printf("%s: generating new host keys: ", __progname); + } ++ type = sshkey_type_from_shortname(key_types[i].key_type); ++ ++ /* Skip the keys that are not supported in FIPS mode */ ++ if (FIPS_mode() && (type == KEY_DSA || type == KEY_ED25519)) { ++ 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)); +@@ -3830,7 +3831,7 @@ main(int argc, char **argv) + } + + if (key_type_name == NULL) +- key_type_name = DEFAULT_KEY_TYPE_NAME; ++ key_type_name = FIPS_mode() ? FIPS_DEFAULT_KEY_TYPE_NAME : DEFAULT_KEY_TYPE_NAME; + + type = sshkey_type_from_shortname(key_type_name); + type_bits_valid(type, key_type_name, &bits); +diff -up openssh-9.3p1/ssh-rsa.c.evpgenrsa openssh-9.3p1/ssh-rsa.c +--- openssh-9.3p1/ssh-rsa.c.evpgenrsa 2022-06-30 15:14:58.200518353 +0200 ++++ openssh-9.3p1/ssh-rsa.c 2022-06-30 15:24:31.499641196 +0200 +@@ -33,6 +33,7 @@ + + #include + #include ++#include + + #include + #include +@@ -1705,6 +1707,8 @@ ssh_rsa_generate(u_int bits, RSA + goto out; + } + if (EVP_PKEY_keygen(ctx, &res) <= 0 || res == NULL) { ++ if (FIPS_mode()) ++ logit_f("the key length might be unsupported by FIPS mode approved key generation method"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +diff -up openssh-9.9p1/kexgen.c.xxx openssh-9.9p1/kexgen.c +--- openssh-9.9p1/kexgen.c.xxx 2024-10-09 10:35:56.285946080 +0200 ++++ openssh-9.9p1/kexgen.c 2024-10-09 10:41:52.792597194 +0200 @@ -31,6 +31,7 @@ #include #include @@ -159,7 +607,7 @@ index 58edc79ad..9a970adf1 100644 #include "kex.h" @@ -115,13 +116,28 @@ kex_gen_client(struct ssh *ssh) break; - #endif /* WITH_OPENSSL */ + #endif case KEX_C25519_SHA256: - r = kex_c25519_keypair(kex); + if (FIPS_mode()) { @@ -189,9 +637,9 @@ index 58edc79ad..9a970adf1 100644 break; default: r = SSH_ERR_INVALID_ARGUMENT; -@@ -189,15 +205,30 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) +@@ -189,15 +205,30 @@ input_kex_gen_reply(int type, u_int32_t break; - #endif /* WITH_OPENSSL */ + #endif case KEX_C25519_SHA256: - r = kex_c25519_dec(kex, server_blob, &shared_secret); + if (FIPS_mode()) { @@ -225,9 +673,9 @@ index 58edc79ad..9a970adf1 100644 break; default: r = SSH_ERR_INVALID_ARGUMENT; -@@ -312,16 +343,31 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) +@@ -312,16 +343,31 @@ input_kex_gen_init(int type, u_int32_t s break; - #endif /* WITH_OPENSSL */ + #endif case KEX_C25519_SHA256: - r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, - &shared_secret); @@ -263,169 +711,9 @@ index 58edc79ad..9a970adf1 100644 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 -@@ -28,6 +28,7 @@ - - #ifdef WITH_OPENSSL - -+#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) - r = SSH_ERR_ALLOC_FAIL; - goto out; - } -+ if (FIPS_mode() && dh_is_known_group(kex->dh) == 0) { -+ r = SSH_ERR_INVALID_ARGUMENT; -+ goto out; -+ } - 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 @@ - "rsa-sha2-512," \ - "rsa-sha2-256" - -+#define KEX_FIPS_PK_ALG \ -+ "ecdsa-sha2-nistp256-cert-v01@openssh.com," \ -+ "ecdsa-sha2-nistp384-cert-v01@openssh.com," \ -+ "ecdsa-sha2-nistp521-cert-v01@openssh.com," \ -+ "rsa-sha2-512-cert-v01@openssh.com," \ -+ "rsa-sha2-256-cert-v01@openssh.com," \ -+ "ecdsa-sha2-nistp256," \ -+ "ecdsa-sha2-nistp384," \ -+ "ecdsa-sha2-nistp521," \ -+ "rsa-sha2-512," \ -+ "rsa-sha2-256" -+ - #define KEX_SERVER_ENCRYPT \ - "chacha20-poly1305@openssh.com," \ - "aes128-gcm@openssh.com,aes256-gcm@openssh.com," \ -@@ -79,6 +91,27 @@ - - #define KEX_CLIENT_MAC KEX_SERVER_MAC - -+#define KEX_FIPS_ENCRYPT \ -+ "aes128-ctr,aes192-ctr,aes256-ctr," \ -+ "aes128-cbc,3des-cbc," \ -+ "aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se," \ -+ "aes128-gcm@openssh.com,aes256-gcm@openssh.com" -+#define KEX_DEFAULT_KEX_FIPS \ -+ "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" -+#define KEX_FIPS_MAC \ -+ "hmac-sha1," \ -+ "hmac-sha2-256," \ -+ "hmac-sha2-512," \ -+ "hmac-sha1-etm@openssh.com," \ -+ "hmac-sha2-256-etm@openssh.com," \ -+ "hmac-sha2-512-etm@openssh.com" -+ - /* 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 -@@ -39,6 +39,7 @@ - #include - #include - #include -+#include - #ifdef USE_SYSTEM_GLOB - # include - #else -@@ -3078,11 +3079,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 */ -- def_cipher = match_filter_allowlist(KEX_CLIENT_ENCRYPT, all_cipher); -- def_mac = match_filter_allowlist(KEX_CLIENT_MAC, all_mac); -- def_kex = match_filter_allowlist(KEX_CLIENT_KEX, all_kex); -- def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); -- def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); -+ def_cipher = match_filter_allowlist((FIPS_mode() ? -+ KEX_FIPS_ENCRYPT : KEX_CLIENT_ENCRYPT), all_cipher); -+ def_mac = match_filter_allowlist((FIPS_mode() ? -+ KEX_FIPS_MAC : KEX_CLIENT_MAC), all_mac); -+ def_kex = match_filter_allowlist((FIPS_mode() ? -+ KEX_DEFAULT_KEX_FIPS : KEX_CLIENT_KEX), all_kex); -+ def_key = match_filter_allowlist((FIPS_mode() ? -+ KEX_FIPS_PK_ALG : KEX_DEFAULT_PK_ALG), all_key); -+ def_sig = match_filter_allowlist((FIPS_mode() ? -+ KEX_FIPS_PK_ALG : SSH_ALLOWED_CA_SIGALGS), all_sig); - #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[] = { - #ifdef __NR_open - SC_DENY(__NR_open, EACCES), - #endif -+#ifdef __NR_socket -+ SC_DENY(__NR_socket, EACCES), -+#endif - #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 @@ - #include - #include - #include -+#include -+#ifdef HAVE_UTIL_H - #include -+#endif - #ifdef USE_SYSTEM_GLOB - # include - #else -@@ -244,11 +247,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 */ -- def_cipher = match_filter_allowlist(KEX_SERVER_ENCRYPT, all_cipher); -- def_mac = match_filter_allowlist(KEX_SERVER_MAC, all_mac); -- def_kex = match_filter_allowlist(KEX_SERVER_KEX, all_kex); -- def_key = match_filter_allowlist(KEX_DEFAULT_PK_ALG, all_key); -- def_sig = match_filter_allowlist(SSH_ALLOWED_CA_SIGALGS, all_sig); -+ def_cipher = match_filter_allowlist((FIPS_mode() ? -+ KEX_FIPS_ENCRYPT : KEX_SERVER_ENCRYPT), all_cipher); -+ def_mac = match_filter_allowlist((FIPS_mode() ? -+ KEX_FIPS_MAC : KEX_SERVER_MAC), all_mac); -+ def_kex = match_filter_allowlist((FIPS_mode() ? -+ KEX_DEFAULT_KEX_FIPS : KEX_SERVER_KEX), all_kex); -+ def_key = match_filter_allowlist((FIPS_mode() ? -+ KEX_FIPS_PK_ALG : KEX_DEFAULT_PK_ALG), all_key); -+ def_sig = match_filter_allowlist((FIPS_mode() ? -+ KEX_FIPS_PK_ALG : SSH_ALLOWED_CA_SIGALGS), all_sig); - #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 +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 @@ -434,7 +722,7 @@ index c8caa2221..4bcd9ef81 100644 #include "log.h" #include "sshbuf.h" -@@ -163,6 +164,10 @@ ssh_ed25519_sign(struct sshkey *key, +@@ -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; @@ -445,7 +733,7 @@ index c8caa2221..4bcd9ef81 100644 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, +@@ -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; @@ -456,296 +744,23 @@ index c8caa2221..4bcd9ef81 100644 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 - } +diff -up openssh-9.9p1/kex.c.xxx openssh-9.9p1/kex.c +--- openssh-9.9p1/kex.c.xxx 2024-10-11 12:44:08.087426597 +0200 ++++ openssh-9.9p1/kex.c 2024-10-11 14:00:10.404714521 +0200 +@@ -40,6 +40,7 @@ #ifdef WITH_OPENSSL -+ 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 + # ifdef HAVE_EVP_KDF_CTX_NEW + # include + # include +@@ -109,7 +110,7 @@ kex_proposal_populate_entries(struct ssh - #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 @@ - #include - #include - #endif -+#include - #include "openbsd-compat/openssl-compat.h" - #include "openbsd-compat/sys-queue.h" - -@@ -1664,6 +1665,10 @@ main(int ac, char **av) - exit(0); - } - -+ if (FIPS_mode()) { -+ debug("FIPS mode initialized"); -+ } -+ - /* 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 -@@ -45,6 +45,8 @@ - #include - #endif - -+#include -+ - #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, - - #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]; -@@ -281,7 +286,9 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, - } - - gss = ssh_gssapi_client_mechanisms(gss_host, -- options.gss_client_identity, options.gss_kex_algorithms); -+ options.gss_client_identity, gss_kex_filtered); -+ free(gss_kex_filtered); -+ - if (gss) { - debug("Offering GSSAPI proposal: %s", gss); - xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -diff --git a/sshd.c b/sshd.c -index ed7faf96d..de2baa5e4 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -44,6 +44,7 @@ - #include - #include - #include -+#include - #include - #include - #include -@@ -55,6 +56,7 @@ - #ifdef WITH_OPENSSL - #include - #include -+#include - #include "openbsd-compat/openssl-compat.h" - #endif - -@@ -1613,6 +1615,13 @@ main(int ac, char **av) - &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) - do_log2_r(r, ll, "Unable to load host key \"%s\"", - options.host_key_files[i]); -+ if (FIPS_mode() && key != NULL && (sshkey_type_plain(key->type) == KEY_ED25519_SK -+ || sshkey_type_plain(key->type) == KEY_ED25519)) { -+ logit_f("sshd: Ed25519 keys are not allowed in FIPS mode, skipping %s", options.host_key_files[i]); -+ sshkey_free(key); -+ key = NULL; -+ continue; -+ } - if (sshkey_is_sk(key) && - key->sk_flags & SSH_SK_USER_PRESENCE_REQD) { - debug("host key %s requires user presence, ignoring", -@@ -1836,6 +1845,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); - -+ if (FIPS_mode()) { -+ debug("FIPS mode initialized"); -+ } -+ - /* - * 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 -@@ -36,6 +36,7 @@ - #include - #include - #include -+#include - #endif - - #include "crypto_api.h" -@@ -58,6 +59,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) - impl = keyimpls[i]; - if (impl->name == NULL || impl->type == KEY_NULL) - continue; -+ if (FIPS_mode()) { -+ switch (impl->type) { -+ case KEY_ED25519: -+ case KEY_ED25519_SK: -+ case KEY_ED25519_CERT: -+ case KEY_ED25519_SK_CERT: -+ continue; -+ break; -+ default: -+ break; -+ } -+ } - 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) - return SSH_ERR_EC_CURVE_MISMATCH; - } - -+ switch (type) { -+ case KEY_ED25519: -+ case KEY_ED25519_SK: -+ case KEY_ED25519_CERT: -+ case KEY_ED25519_SK_CERT: -+ if (FIPS_mode()) { -+ sshkey_free(k); -+ logit_f("Ed25519 keys are not allowed in FIPS mode"); -+ return SSH_ERR_INVALID_ARGUMENT; -+ } -+ break; -+ default: -+ break; -+ } - /* Fill in ret from parsed key */ - sshkey_free_contents(ret); - *ret = *k; -@@ -2251,6 +2279,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 ((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, - *detailsp = NULL; - if (siglen == 0 || dlen > SSH_KEY_MAX_SIGN_DATA_SIZE) - return SSH_ERR_INVALID_ARGUMENT; -+ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) { -+ logit_f("Ed25519 keys are not allowed in FIPS mode"); -+ return SSH_ERR_INVALID_ARGUMENT; -+ } - if ((impl = sshkey_impl_from_key(key)) == NULL) - return SSH_ERR_KEY_TYPE_UNKNOWN; - return impl->funcs->verify(key, sig, siglen, data, dlen, --- -2.52.0 - + /* 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/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..0b8ab02 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 = mm_ssh_gssapi_update_creds(&gssapi_client.store); +diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c +--- openssh-8.6p1/gss-serv-krb5.c.ccache_name 2021-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-session.c.ccache_name openssh-8.6p1/sshd-session.c +--- openssh-8.6p1/sshd-session.c.ccache_name 2021-04-19 14:05:10.849744540 +0200 ++++ openssh-8.6p1/sshd-session.c 2021-04-19 14:05:10.855744584 +0200 +@@ -2284,7 +2284,7 @@ main(int ac, char **av) #ifdef GSSAPI if (options.gss_authentication) { 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 . @@ -660,6 +609,24 @@ index b90068bf3..cae0fd0b4 100644 .It Cm KexAlgorithms Specifies the permitted KEX (Key Exchange) algorithms that the server will offer to clients. --- -2.52.0 - +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/0010-openssh-7.8p1-UsePAM-warning.patch b/openssh-7.8p1-UsePAM-warning.patch similarity index 50% rename from 0010-openssh-7.8p1-UsePAM-warning.patch rename to openssh-7.8p1-UsePAM-warning.patch index 521abe4..f8d7042 100644 --- a/0010-openssh-7.8p1-UsePAM-warning.patch +++ b/openssh-7.8p1-UsePAM-warning.patch @@ -1,18 +1,7 @@ -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) +diff -up openssh-8.6p1/sshd.c.log-usepam-no openssh-8.6p1/sshd.c +--- openssh-8.6p1/sshd-session.c.log-usepam-no 2021-04-19 14:00:45.099735129 +0200 ++++ openssh-8.6p1/sshd-session.c 2021-04-19 14:03:21.140920974 +0200 +@@ -1749,6 +1749,10 @@ main(int ac, char **av) "enabled authentication methods"); } @@ -23,11 +12,10 @@ index 1c72e664a..9804dc334 100644 #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 +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'. @@ -36,6 +24,3 @@ index 608203e4b..48af6321b 100644 #UsePAM no #AllowAgentForwarding yes --- -2.52.0 - diff --git a/0001-openssh-7.8p1-role-mls.patch b/openssh-7.8p1-role-mls.patch similarity index 79% rename from 0001-openssh-7.8p1-role-mls.patch rename to openssh-7.8p1-role-mls.patch index 0377e8c..7c6d0ca 100644 --- a/0001-openssh-7.8p1-role-mls.patch +++ b/openssh-7.8p1-role-mls.patch @@ -1,75 +1,46 @@ -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,7 +314,13 @@ input_userauth_request(int type, u_int32 + setproctitle("%s [net]", authctxt->valid ? user : "unknown"); + authctxt->service = xstrdup(service); + authctxt->style = style ? xstrdup(style) : NULL; ++#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 -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; @@ -77,7 +48,7 @@ index 75eb4e3a3..f7898ab3e 100644 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) +@@ -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 +63,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); @@ -101,11 +72,10 @@ index 75eb4e3a3..f7898ab3e 100644 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) +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 +92,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 +114,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(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 -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 +162,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 +176,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 +189,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 +199,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 +209,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 +236,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 +254,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 +263,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 +272,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 +286,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 +317,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 +330,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,11 +343,78 @@ 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 +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,420 @@ +/* + * Copyright (c) 2005 Daniel Walsh @@ -809,82 +836,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 +848,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-session.c.role-mls 2018-08-20 07:57:29.000000000 +0200 ++++ openssh/sshd-session.c 2018-08-22 11:14:56.820430957 +0200 +@@ -2186,6 +2186,9 @@ main(int ac, char **av) restore_uid(); } #endif @@ -907,6 +861,3 @@ index 8979f743b..cb4b0523d 100644 #ifdef USE_PAM if (options.use_pam) { do_pam_setcred(); --- -2.52.0 - 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 90% rename from 0026-openssh-8.0p1-crypto-policies.patch rename to openssh-8.0p1-crypto-policies.patch index 5162ffa..a666c5c 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: +@@ -1330,6 +1330,11 @@ it may be zero or more of: and .Cm pam . .It Cm KexAlgorithms @@ -178,7 +167,7 @@ index 8a4b469cf..8ac5e1633 100644 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. +@@ -1338,29 +1343,17 @@ Multiple algorithms must be comma-separa .Pp If the specified list begins with a .Sq + @@ -198,8 +187,8 @@ index 8a4b469cf..8ac5e1633 100644 -.Pp -The default is: -.Bd -literal -offset indent --mlkem768x25519-sha256, -sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com, +-mlkem768x25519-sha256, -curve25519-sha256,curve25519-sha256@libssh.org, -ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, -diffie-hellman-group-exchange-sha256, @@ -212,7 +201,7 @@ index 8a4b469cf..8ac5e1633 100644 The list of supported 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 +248,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 +300,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 +311,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 +337,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 +367,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 +454,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 +485,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. +@@ -1025,6 +1025,11 @@ Specifies whether to look at .k5login fi The default is .Cm yes . .It Cm KexAlgorithms @@ -509,7 +497,7 @@ index a0fc6064f..c172d5aab 100644 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. +@@ -1033,16 +1038,16 @@ Multiple algorithms must be comma-separa .Pp If the specified list begins with a .Sq + @@ -530,22 +518,25 @@ index a0fc6064f..c172d5aab 100644 .Pp The supported algorithms are: .Pp -@@ -1105,14 +1083,6 @@ sntrup761x25519-sha512 +@@ -1075,17 +1080,6 @@ ecdh-sha2-nistp521 sntrup761x25519-sha512@openssh.com .El .Pp -The default is: -.Bd -literal -offset indent --mlkem768x25519-sha256, -sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com, +-mlkem768x25519-sha256, -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 .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 +567,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 +583,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 +629,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 +640,3 @@ index a0fc6064f..c172d5aab 100644 .Sh AUTHORS .An -nosplit OpenSSH is a derivative of the original and free --- -2.52.0 - 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/0027-openssh-8.0p1-openssl-kdf.patch b/openssh-8.0p1-openssl-kdf.patch similarity index 84% rename from 0027-openssh-8.0p1-openssl-kdf.patch rename to openssh-8.0p1-openssl-kdf.patch index 6f7f49b..c22b210 100644 --- a/0027-openssh-8.0p1-openssl-kdf.patch +++ b/openssh-8.0p1-openssl-kdf.patch @@ -1,18 +1,14 @@ -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 +commit 2c3ef499bfffce3cfd315edeebf202850ba4e00a +Author: Jakub Jelen +Date: Tue Apr 16 15:35:18 2019 +0200 ---- - configure.ac | 1 + - kex.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 108 insertions(+) + Use the new OpenSSL KDF diff --git a/configure.ac b/configure.ac -index adccaebd4..805be4b5e 100644 +index 2a455e4e..e01c3d43 100644 --- a/configure.ac +++ b/configure.ac -@@ -3182,6 +3182,7 @@ if test "x$openssl" = "xyes" ; then +@@ -2712,6 +2712,7 @@ if test "x$openssl" = "xyes" ; then HMAC_CTX_init \ RSA_generate_key_ex \ RSA_get_default_method \ @@ -21,7 +17,7 @@ index adccaebd4..805be4b5e 100644 # OpenSSL_add_all_algorithms may be a macro. diff --git a/kex.c b/kex.c -index 9a2ce6d88..5f9530908 100644 +index b6f041f4..1fbce2bb 100644 --- a/kex.c +++ b/kex.c @@ -38,6 +38,11 @@ @@ -36,7 +32,7 @@ index 9a2ce6d88..5f9530908 100644 #endif #include "ssh.h" -@@ -1077,6 +1082,107 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) +@@ -942,6 +945,107 @@ kex_choose_conf(struct ssh *ssh) return r; } @@ -144,7 +140,7 @@ index 9a2ce6d88..5f9530908 100644 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, +@@ -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; } @@ -152,6 +148,4 @@ index 9a2ce6d88..5f9530908 100644 #define NKEYS 6 int --- -2.52.0 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..bdc4722 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,20 +952,19 @@ 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, + 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,74 @@ add_p11_identity(struct sshkey *key, cha idtab->nentries++; } @@ -1047,7 +992,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 +1040,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 +1071,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 +1087,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 +1095,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 +1104,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 +1141,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 +1333,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 +1345,1304 @@ 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.9p1/ssh-pkcs11.c.xxx openssh-9.9p1/ssh-pkcs11.c +--- openssh-9.9p1/ssh-pkcs11.c.xxx 2024-10-09 11:56:35.890126144 +0200 ++++ openssh-9.9p1/ssh-pkcs11.c 2024-10-09 11:56:48.528459585 +0200 +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #define CRYPTOKI_COMPAT + #include "pkcs11.h" +@@ -55,8 +55,8 @@ struct pkcs11_slotinfo { + int logged_in; + }; + +-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,60 @@ 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: { ++ const RSA *rsa = EVP_PKEY_get0_RSA(key->pkey); ++ k11 = RSA_get_ex_data(rsa, rsa_idx); ++ break; ++ } ++#ifdef HAVE_EC_KEY_METHOD_NEW ++ case KEY_ECDSA: { ++ const EC_KEY * ecdsa = EVP_PKEY_get0_EC_KEY(key->pkey); ++ k11 = EC_KEY_get_ex_data(ecdsa, ec_key_idx); ++ break; ++ } ++#endif ++ default: ++ error("Unknown key type %d", key->type); ++ 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; ++ } ++ + if (RSA_set_method(rsa, rsa_method) != 1) + fatal_f("RSA_set_method failed"); + if (RSA_set_ex_data(rsa, rsa_idx, k11) != 1) +@@ -532,8 +683,8 @@ ecdsa_do_sign(const unsigned char *dgst, + return (NULL); + } + +- 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; ++ } ++ + if (EC_KEY_set_method(ec, ec_key_method) != 1) + fatal_f("EC_KEY_set_method failed"); + if (EC_KEY_set_ex_data(ec, ec_key_idx, k11) != 1) +@@ -622,7 +779,8 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider + } + #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ + +-/* 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_ + key->flags |= SSHKEY_FLAG_EXT; + + 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 + key->flags |= SSHKEY_FLAG_EXT; + + 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 +3081,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 +3128,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..b7ab965 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,17 @@ 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,9 +862,11 @@ sshpam_query(void *ctx, char **name, cha free(msg); break; 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_ACCT_EXPIRED) +- sshpam_account_status = 0; 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 63% rename from 0033-openssh-8.7p1-minrsabits.patch rename to openssh-8.7p1-minrsabits.patch index fcd994b..d8577d2 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,10 +10,9 @@ 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 }, @@ -32,6 +20,3 @@ index b63a7f0b0..ac84b74d9 100644 { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL }, --- -2.52.0 - diff --git a/0040-openssh-8.7p1-negotiate-supported-algs.patch b/openssh-8.7p1-negotiate-supported-algs.patch similarity index 74% rename from 0040-openssh-8.7p1-negotiate-supported-algs.patch rename to openssh-8.7p1-negotiate-supported-algs.patch index 29f8213..c4d86e7 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,11 +72,10 @@ 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]; @@ -96,7 +84,7 @@ index fffa66c8d..f43c81ad9 100644 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,10 +260,22 @@ ssh_kex2(struct ssh *ssh, char *host, st if (use_known_hosts_order) hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo); @@ -120,7 +108,7 @@ index fffa66c8d..f43c81ad9 100644 #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 +116,3 @@ index fffa66c8d..f43c81ad9 100644 /* start key exchange */ if ((r = kex_setup(ssh, myproposal)) != 0) --- -2.52.0 - diff --git a/0042-openssh-8.7p1-nohostsha1proof.patch b/openssh-8.7p1-nohostsha1proof.patch similarity index 66% rename from 0042-openssh-8.7p1-nohostsha1proof.patch rename to openssh-8.7p1-nohostsha1proof.patch index 681d051..dae0932 100644 --- a/0042-openssh-8.7p1-nohostsha1proof.patch +++ b/openssh-8.7p1-nohostsha1proof.patch @@ -1,27 +1,7 @@ -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 +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; @@ -29,7 +9,7 @@ index b59f0bfc0..4e611dc39 100644 static struct { char *pat; int bugs; -@@ -125,16 +126,21 @@ compat_banner(struct ssh *ssh, const char *version) +@@ -145,16 +146,21 @@ compat_banner(struct ssh *ssh, const cha }; /* process table, return first match */ @@ -51,10 +31,9 @@ index b59f0bfc0..4e611dc39 100644 } /* 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 +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 @@ -64,28 +43,24 @@ index 1a19060fc..2e6db5bf9 100644 #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; +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; -- 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; + 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) +@@ -719,18 +720,30 @@ mm_answer_sign(struct ssh *ssh, int sock } if ((key = get_hostkey_by_index(keyid)) != NULL) { @@ -119,25 +94,23 @@ index b2f501790..6c83739ee 100644 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; - } +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); -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) +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(); @@ -145,7 +118,7 @@ index e412b75d8..5b06bc905 100644 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) +@@ -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); @@ -154,11 +127,10 @@ index e412b75d8..5b06bc905 100644 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) +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 @@ -174,11 +146,10 @@ index d0f47d7cf..ba4d506d5 100644 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, +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; @@ -188,7 +159,7 @@ index d0c46a90b..7b5e51b83 100644 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, +@@ -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, @@ -200,12 +171,14 @@ index d0c46a90b..7b5e51b83 100644 free(sigblob); sshbuf_free(ca_buf); -@@ -118,16 +122,20 @@ signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg, +@@ -119,16 +123,22 @@ signature_test(struct sshkey *k, struct { size_t len; u_char *sig; -+ /* ssh-rsa implies SHA1, forbidden in DEFAULT crypto policies */ ++ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp in RHEL, permitted in Fedora */ + int expected = (sig_alg && strcmp(sig_alg, "ssh-rsa") == 0) ? sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, NULL, 0) : 0; ++ if (k && (sshkey_type_plain(k->type) == KEY_DSA || sshkey_type_plain(k->type) == KEY_DSA_CERT)) ++ expected = sshkey_sign(k, &sig, &len, d, l, sig_alg, NULL, NULL, 0); ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, - NULL, NULL, 0), 0); @@ -229,7 +202,7 @@ index d0c46a90b..7b5e51b83 100644 free(sig); } -@@ -552,7 +560,7 @@ sshkey_tests(void) +@@ -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"); @@ -238,11 +211,10 @@ index d0c46a90b..7b5e51b83 100644 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 @@ +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" @@ -250,11 +222,10 @@ index 5d3b194d1..55411a6b4 100644 extern ServerOptions options; -@@ -721,7 +722,10 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp) +@@ -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); @@ -262,25 +233,10 @@ index 5d3b194d1..55411a6b4 100644 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, +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; } @@ -295,11 +251,23 @@ index f43c81ad9..2d98fc3da 100644 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) +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 -up openssh-9.8p1/sshd-session.c.xxx openssh-9.8p1/sshd-session.c +--- openssh-9.8p1/sshd-session.c.xxx 2024-07-23 15:08:14.794350818 +0200 ++++ openssh-9.8p1/sshd-session.c 2024-07-23 15:40:21.658456636 +0200 +@@ -1305,6 +1305,27 @@ main(int ac, char **av) check_ip_options(ssh); @@ -327,6 +295,3 @@ index e49e4fb51..a558bbc33 100644 /* Prepare the channels layer */ channel_init_channels(ssh); channel_set_af(ssh, options.address_family); --- -2.52.0 - 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/0009-openssh-8.7p1-redhat.patch b/openssh-8.7p1-redhat.patch similarity index 64% rename from 0009-openssh-8.7p1-redhat.patch rename to openssh-8.7p1-redhat.patch index 8e75aa5..4e9d108 100644 --- a/0009-openssh-8.7p1-redhat.patch +++ b/openssh-8.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,12 +59,28 @@ 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 @@ -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/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/0037-openssh-9.0p1-audit-log.patch b/openssh-9.0p1-audit-log.patch similarity index 83% rename from 0037-openssh-9.0p1-audit-log.patch rename to openssh-9.0p1-audit-log.patch index c58a5fe..ae9550f 100644 --- a/0037-openssh-9.0p1-audit-log.patch +++ b/openssh-9.0p1-audit-log.patch @@ -1,20 +1,7 @@ -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) +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 @@ -23,10 +10,51 @@ index a6292cb8f..0f2ef8235 100644 { /* not implemented */ } -diff --git a/audit-linux.c b/audit-linux.c -index 4d3e9d41e..d2bc0b526 100644 ---- a/audit-linux.c -+++ b/audit-linux.c +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.9p1/audit-linux.c.xxx openssh-9.9p1/audit-linux.c +--- openssh-9.9p1/audit-linux.c.xxx 2024-10-15 11:49:48.092151974 +0200 ++++ openssh-9.9p1/audit-linux.c 2024-10-15 12:08:17.179158343 +0200 @@ -52,7 +52,7 @@ extern u_int utmp_len; const char *audit_username(void); @@ -36,8 +64,8 @@ index 4d3e9d41e..d2bc0b526 100644 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; +@@ -66,7 +66,7 @@ linux_audit_user_logxxx(int uid, const c + } rc = audit_log_acct_message(audit_fd, event, NULL, "login", username ? username : "(unknown)", - username == NULL ? uid : -1, NULL, ip, ttyn, success); @@ -45,7 +73,7 @@ index 4d3e9d41e..d2bc0b526 100644 saved_errno = errno; close(audit_fd); -@@ -139,10 +139,12 @@ fatal_report: +@@ -137,10 +137,12 @@ fatal_report: } int @@ -59,7 +87,7 @@ index 4d3e9d41e..d2bc0b526 100644 audit_fd = audit_open(); if (audit_fd < 0) { -@@ -152,14 +154,44 @@ audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) +@@ -150,14 +152,44 @@ audit_keyusage(struct ssh *ssh, int host else return 0; /* Must prevent login */ } @@ -107,7 +135,7 @@ index 4d3e9d41e..d2bc0b526 100644 out: saved_errno = errno; audit_close(audit_fd); -@@ -181,26 +213,34 @@ audit_connection_from(const char *host, int port) +@@ -179,26 +211,34 @@ audit_connection_from(const char *host, int audit_run_command(struct ssh *ssh, const char *command) { @@ -142,7 +170,7 @@ index 4d3e9d41e..d2bc0b526 100644 } void -@@ -213,31 +253,41 @@ void +@@ -211,31 +251,41 @@ void audit_session_open(struct logininfo *li) { if (!user_login_count++) @@ -189,7 +217,7 @@ index 4d3e9d41e..d2bc0b526 100644 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) +@@ -255,9 +305,11 @@ audit_event(struct ssh *ssh, ssh_audit_e if (user_login_count) { while (user_login_count--) linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, @@ -201,7 +229,7 @@ index 4d3e9d41e..d2bc0b526 100644 ssh_remote_ipaddr(ssh), "ssh", 1, AUDIT_USER_LOGOUT); } -@@ -268,12 +320,14 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) +@@ -266,12 +318,14 @@ audit_event(struct ssh *ssh, ssh_audit_e case SSH_CONNECTION_ABANDON: case SSH_INVALID_USER: linux_audit_user_logxxx(-1, audit_username(), @@ -209,57 +237,10 @@ index 4d3e9d41e..d2bc0b526 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; } + 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/0041-openssh-9.0p1-evp-fips-kex.patch b/openssh-9.0p1-evp-fips-kex.patch similarity index 90% rename from 0041-openssh-9.0p1-evp-fips-kex.patch rename to openssh-9.0p1-evp-fips-kex.patch index 24ef8e8..36fd1cf 100644 --- a/0041-openssh-9.0p1-evp-fips-kex.patch +++ b/openssh-9.0p1-evp-fips-kex.patch @@ -1,20 +1,6 @@ -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 +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 @@ -25,7 +11,7 @@ index 8c9a29fa7..ea0a0b093 100644 #include "dh.h" #include "pathnames.h" -@@ -290,10 +293,15 @@ dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub) +@@ -290,10 +293,15 @@ int dh_gen_key(DH *dh, int need) { @@ -44,7 +30,7 @@ index 8c9a29fa7..ea0a0b093 100644 if (need < 0 || dh_p == NULL || (pbits = BN_num_bits(dh_p)) <= 0 || -@@ -301,19 +309,85 @@ dh_gen_key(DH *dh, int need) +@@ -301,19 +309,85 @@ return SSH_ERR_INVALID_ARGUMENT; if (need < 256) need = 256; @@ -139,11 +125,10 @@ index 8c9a29fa7..ea0a0b093 100644 } 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, +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kex.c openssh-9.0p1-patched/kex.c +--- openssh-9.0p1/kex.c 2023-05-25 09:24:28.731868327 +0200 ++++ openssh-9.0p1-patched/kex.c 2023-05-25 09:23:44.841379532 +0200 +@@ -1623,3 +1623,142 @@ return r; } @@ -286,37 +271,12 @@ index da2a537ce..56c80395c 100644 + 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); +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 @@ - #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 @@ -325,7 +285,7 @@ index 6d5a7813d..b05277aa1 100644 #include "sshkey.h" #include "kex.h" -@@ -84,9 +88,12 @@ int +@@ -83,9 +87,12 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) { BIGNUM *shared_secret = NULL; @@ -339,7 +299,7 @@ index 6d5a7813d..b05277aa1 100644 #ifdef DEBUG_KEXDH fprintf(stderr, "dh_pub= "); -@@ -101,24 +108,59 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) +@@ -100,24 +107,59 @@ r = SSH_ERR_MESSAGE_INCOMPLETE; goto out; } @@ -403,13 +363,35 @@ index 6d5a7813d..b05277aa1 100644 return r; } -diff --git a/kexecdh.c b/kexecdh.c -index 500ec5725..1a1bae35e 100644 ---- a/kexecdh.c -+++ b/kexecdh.c -@@ -36,17 +36,57 @@ +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kex.h openssh-9.0p1-patched/kex.h +--- openssh-9.0p1/kex.h 2023-05-25 09:24:28.725868260 +0200 ++++ openssh-9.0p1-patched/kex.h 2023-05-25 09:23:44.841379532 +0200 +@@ -33,6 +33,9 @@ + # include + # include + # include ++# include ++# include ++# include + # ifdef OPENSSL_HAS_ECC + # include + # else /* OPENSSL_HAS_ECC */ +@@ -283,6 +286,9@@ + const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); ++int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, ++ const BIGNUM *, const BIGNUM *, const BIGNUM *); ++int kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey); + + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) + void dump_digest(const char *, const u_char *, int); +diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../openssh-8.7p1/kexecdh.c ./kexecdh.c +--- ../openssh-8.7p1/kexecdh.c 2021-08-20 06:03:49.000000000 +0200 ++++ ./kexecdh.c 2023-04-13 14:30:14.882449593 +0200 +@@ -35,17 +35,57 @@ + #include - #include #include +#include +#include @@ -465,7 +447,7 @@ index 500ec5725..1a1bae35e 100644 int kex_ecdh_keypair(struct kex *kex) { -@@ -56,11 +96,7 @@ kex_ecdh_keypair(struct kex *kex) +@@ -55,11 +95,7 @@ struct sshbuf *buf = NULL; int r; @@ -478,7 +460,7 @@ index 500ec5725..1a1bae35e 100644 r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } -@@ -102,11 +138,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, +@@ -101,11 +137,7 @@ *server_blobp = NULL; *shared_secretp = NULL; @@ -491,7 +473,7 @@ index 500ec5725..1a1bae35e 100644 r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } -@@ -141,11 +173,21 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, +@@ -140,11 +172,21 @@ { struct sshbuf *buf = NULL; BIGNUM *shared_secret = NULL; @@ -516,7 +498,7 @@ index 500ec5725..1a1bae35e 100644 *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, +@@ -153,45 +195,82 @@ } if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) goto out; @@ -611,6 +593,3 @@ index 500ec5725..1a1bae35e 100644 sshbuf_free(buf); return r; } --- -2.52.0 - diff --git a/0011-openssh-9.6p1-gssapi-keyex.patch b/openssh-9.6p1-gssapi-keyex.patch similarity index 88% rename from 0011-openssh-9.6p1-gssapi-keyex.patch rename to openssh-9.6p1-gssapi-keyex.patch index 2e5b723..ef1f97e 100644 --- a/0011-openssh-9.6p1-gssapi-keyex.patch +++ b/openssh-9.6p1-gssapi-keyex.patch @@ -1,111 +1,25 @@ -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 ---- 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 \ - kexgexc.o kexgexs.o \ - kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \ -+ kexgssc.o \ - sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ - sshbuf-io.o misc-agent.o +diff --color -ruNp a/auth2.c b/auth2.c +--- a/auth2.c 2024-09-16 11:45:56.858133241 +0200 ++++ b/auth2.c 2024-09-16 11:46:34.688939755 +0200 +@@ -71,6 +71,7 @@ extern Authmethod method_passwd; + extern Authmethod method_kbdint; + extern Authmethod method_hostbased; + #ifdef GSSAPI ++extern Authmethod method_gsskeyex; + extern Authmethod method_gssapi; + #endif -@@ -131,7 +132,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rhosts.o auth-passwd.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 \ -+ 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 \ -- 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: - ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile - - REGRESSLIBS=libssh.a $(LIBCOMPAT) --TESTLIBS=$(LIBS) $(CHANNELLIBS) @TESTLIBS@ -+TESTLIBS=$(LIBS) $(CHANNELLIBS) $(GSSLIBS) @TESTLIBS@ - - 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) - case PERMIT_NO_PASSWD: - if (strcmp(method, "publickey") == 0 || - strcmp(method, "hostbased") == 0 || -- strcmp(method, "gssapi-with-mic") == 0) -+ strcmp(method, "gssapi-with-mic") == 0 || -+ strcmp(method, "gssapi-keyex") == 0) - return 1; - break; - case PERMIT_FORCED_ONLY: -diff --git a/auth2-gss.c b/auth2-gss.c -index f7898ab3e..5b1b9cde3 100644 ---- a/auth2-gss.c -+++ b/auth2-gss.c +@@ -78,6 +79,7 @@ Authmethod *authmethods[] = { + &method_none, + &method_pubkey, + #ifdef GSSAPI ++ &method_gsskeyex, + &method_gssapi, + #endif + &method_passwd, +diff --color -ruNp a/auth2-gss.c b/auth2-gss.c +--- a/auth2-gss.c 2024-09-16 11:45:56.858133241 +0200 ++++ b/auth2-gss.c 2024-09-16 11:46:34.689939776 +0200 @@ -51,6 +51,7 @@ #define SSH_GSSAPI_MAX_MECHS 2048 @@ -114,11 +28,10 @@ index f7898ab3e..5b1b9cde3 100644 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); - static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh); +@@ -59,6 +60,48 @@ static int input_gssapi_exchange_complet static int input_gssapi_errtok(int, u_int32_t, struct ssh *); -+/* + /* + * The 'gssapi_keyex' userauth mechanism. + */ +static int @@ -160,10 +73,11 @@ index f7898ab3e..5b1b9cde3 100644 + return (authenticated); +} + - /* ++/* * We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like) -@@ -267,7 +310,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) + */ +@@ -267,7 +310,7 @@ input_gssapi_exchange_complete(int type, if ((r = sshpkt_get_end(ssh)) != 0) fatal_fr(r, "parse packet"); @@ -172,7 +86,7 @@ index f7898ab3e..5b1b9cde3 100644 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) +@@ -315,7 +358,7 @@ input_gssapi_mic(int type, u_int32_t ple gssbuf.length = sshbuf_len(b); if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))) @@ -181,7 +95,7 @@ index f7898ab3e..5b1b9cde3 100644 else logit("GSSAPI MIC check failed"); -@@ -333,6 +376,11 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) +@@ -333,6 +376,11 @@ input_gssapi_mic(int type, u_int32_t ple return 0; } @@ -193,11 +107,10 @@ index f7898ab3e..5b1b9cde3 100644 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 = { +diff --color -ruNp a/auth2-methods.c b/auth2-methods.c +--- a/auth2-methods.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/auth2-methods.c 2024-09-16 11:46:34.689939776 +0200 +@@ -50,6 +50,11 @@ struct authmethod_cfg methodcfg_pubkey = &options.pubkey_authentication }; #ifdef GSSAPI @@ -209,7 +122,7 @@ index 99637a89b..a05908cf3 100644 struct authmethod_cfg methodcfg_gssapi = { "gssapi-with-mic", NULL, -@@ -76,6 +81,7 @@ static struct authmethod_cfg *authmethod_cfgs[] = { +@@ -76,6 +81,7 @@ static struct authmethod_cfg *authmethod &methodcfg_none, &methodcfg_pubkey, #ifdef GSSAPI @@ -217,30 +130,22 @@ index 99637a89b..a05908cf3 100644 &methodcfg_gssapi, #endif &methodcfg_passwd, -diff --git a/auth2.c b/auth2.c -index 1345d3257..5a4b932a9 100644 ---- a/auth2.c -+++ b/auth2.c -@@ -71,6 +71,7 @@ extern Authmethod method_passwd; - extern Authmethod method_kbdint; - extern Authmethod method_hostbased; - #ifdef GSSAPI -+extern Authmethod method_gsskeyex; - extern Authmethod method_gssapi; - #endif - -@@ -78,6 +79,7 @@ Authmethod *authmethods[] = { - &method_none, - &method_pubkey, - #ifdef GSSAPI -+ &method_gsskeyex, - &method_gssapi, - #endif - &method_passwd, -diff --git a/canohost.c b/canohost.c -index 28f086e5a..875805c99 100644 ---- a/canohost.c -+++ b/canohost.c +diff --color -ruNp a/auth.c b/auth.c +--- a/auth.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/auth.c 2024-09-16 11:46:34.690939798 +0200 +@@ -356,7 +356,8 @@ auth_root_allowed(struct ssh *ssh, const + case PERMIT_NO_PASSWD: + if (strcmp(method, "publickey") == 0 || + strcmp(method, "hostbased") == 0 || +- strcmp(method, "gssapi-with-mic") == 0) ++ strcmp(method, "gssapi-with-mic") == 0 || ++ strcmp(method, "gssapi-keyex") == 0) + return 1; + break; + case PERMIT_FORCED_ONLY: +diff --color -ruNp a/canohost.c b/canohost.c +--- a/canohost.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/canohost.c 2024-09-16 11:46:34.690939798 +0200 @@ -35,6 +35,99 @@ #include "canohost.h" #include "misc.h" @@ -341,10 +246,9 @@ index 28f086e5a..875805c99 100644 void ipv64_normalise_mapped(struct sockaddr_storage *addr, socklen_t *len) { -diff --git a/canohost.h b/canohost.h -index 26d62855a..0cadc9f18 100644 ---- a/canohost.h -+++ b/canohost.h +diff --color -ruNp a/canohost.h b/canohost.h +--- a/canohost.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/canohost.h 2024-09-16 11:46:34.690939798 +0200 @@ -15,6 +15,9 @@ #ifndef _CANOHOST_H #define _CANOHOST_H @@ -355,11 +259,10 @@ index 26d62855a..0cadc9f18 100644 char *get_peer_ipaddr(int); int get_peer_port(int); char *get_local_ipaddr(int); -diff --git a/clientloop.c b/clientloop.c -index 49d048d85..33adf31dc 100644 ---- a/clientloop.c -+++ b/clientloop.c -@@ -107,6 +107,10 @@ +diff --color -ruNp a/clientloop.c b/clientloop.c +--- a/clientloop.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/clientloop.c 2024-09-16 11:46:34.690939798 +0200 +@@ -115,6 +115,10 @@ #include "ssherr.h" #include "hostfile.h" @@ -370,7 +273,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, +@@ -1590,6 +1594,14 @@ client_loop(struct ssh *ssh, int have_pt /* Do channel operations. */ channel_after_poll(ssh, pfd, npfd_active); @@ -385,11 +288,10 @@ index 49d048d85..33adf31dc 100644 /* Buffer input from the connection. */ if (conn_in_ready) client_process_net_input(ssh); -diff --git a/configure.ac b/configure.ac -index fd632a5a8..adccaebd4 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -813,6 +813,30 @@ int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) +diff --color -ruNp a/configure.ac b/configure.ac +--- a/configure.ac 2024-09-16 11:45:56.870133497 +0200 ++++ b/configure.ac 2024-09-16 11:46:34.691939819 +0200 +@@ -774,6 +774,30 @@ int main(void) { if (NSVersionOfRunTimeL [Use tunnel device compatibility to OpenBSD]) AC_DEFINE([SSH_TUN_PREPEND_AF], [1], [Prepend the address family to IP tunnel traffic]) @@ -420,10 +322,9 @@ index fd632a5a8..adccaebd4 100644 m4_pattern_allow([AU_IPv]) AC_CHECK_DECL([AU_IPv4], [], AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) -diff --git a/gss-genr.c b/gss-genr.c -index 8f1f54afb..f2d6f59e5 100644 ---- a/gss-genr.c -+++ b/gss-genr.c +diff --color -ruNp a/gss-genr.c b/gss-genr.c +--- a/gss-genr.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/gss-genr.c 2024-09-16 11:46:34.708940181 +0200 @@ -42,9 +42,33 @@ #include "sshbuf.h" #include "log.h" @@ -458,7 +359,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) +@@ -60,6 +84,159 @@ ssh_gssapi_get_buffer_desc(struct sshbuf return 0; } @@ -527,29 +428,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,7 +519,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) +@@ -168,6 +345,7 @@ ssh_gssapi_build_ctx(Gssctxt **ctx) (*ctx)->creds = GSS_C_NO_CREDENTIAL; (*ctx)->client = GSS_C_NO_NAME; (*ctx)->client_creds = GSS_C_NO_CREDENTIAL; @@ -636,7 +527,7 @@ index 8f1f54afb..f2d6f59e5 100644 } /* Delete our context, providing it has been built correctly */ -@@ -193,6 +381,12 @@ ssh_gssapi_delete_ctx(Gssctxt **ctx) +@@ -193,6 +371,12 @@ ssh_gssapi_delete_ctx(Gssctxt **ctx) gss_release_name(&ms, &(*ctx)->client); if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) gss_release_cred(&ms, &(*ctx)->client_creds); @@ -649,7 +540,7 @@ index 8f1f54afb..f2d6f59e5 100644 free(*ctx); *ctx = NULL; -@@ -216,7 +410,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, +@@ -216,7 +400,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int de } ctx->major = gss_init_sec_context(&ctx->minor, @@ -658,11 +549,10 @@ 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) - return (ctx->major); +@@ -246,8 +430,42 @@ ssh_gssapi_import_name(Gssctxt *ctx, con } -+OM_uint32 + OM_uint32 +ssh_gssapi_client_identity(Gssctxt *ctx, const char *name) +{ + gss_buffer_desc gssbuf; @@ -693,7 +583,7 @@ index 8f1f54afb..f2d6f59e5 100644 + return(ctx->major); +} + - OM_uint32 ++OM_uint32 ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) { + if (ctx == NULL) @@ -702,7 +592,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) +@@ -255,6 +473,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer return (ctx->major); } @@ -722,7 +612,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, +@@ -271,11 +502,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, co } int @@ -740,7 +630,7 @@ index 8f1f54afb..f2d6f59e5 100644 /* 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) +@@ -285,6 +521,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx ssh_gssapi_build_ctx(ctx); ssh_gssapi_set_oid(*ctx, oid); major = ssh_gssapi_import_name(*ctx, host); @@ -751,7 +641,7 @@ index 8f1f54afb..f2d6f59e5 100644 if (!GSS_ERROR(major)) { 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) +@@ -294,10 +534,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx GSS_C_NO_BUFFER); } @@ -819,152 +709,11 @@ index 8f1f54afb..f2d6f59e5 100644 +} + #endif /* GSSAPI */ -diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index a151bc1e4..8d2b677f7 100644 ---- a/gss-serv-krb5.c -+++ b/gss-serv-krb5.c +diff --color -ruNp a/gss-serv.c b/gss-serv.c +--- a/gss-serv.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/gss-serv.c 2024-09-16 11:46:34.692939840 +0200 @@ -1,7 +1,7 @@ - /* $OpenBSD: gss-serv-krb5.c,v 1.9 2018/07/09 21:37:55 markus 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 -@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - krb5_error_code problem; - krb5_principal princ; - OM_uint32 maj_status, min_status; -- int len; -+ const char *new_ccname, *new_cctype; - const char *errmsg; - - if (client->creds == NULL) { -@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - return; - } - -- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); -+ new_cctype = krb5_cc_get_type(krb_context, ccache); -+ new_ccname = krb5_cc_get_name(krb_context, ccache); -+ - client->store.envvar = "KRB5CCNAME"; -- len = strlen(client->store.filename) + 6; -- client->store.envval = xmalloc(len); -- snprintf(client->store.envval, len, "FILE:%s", client->store.filename); -+#ifdef USE_CCAPI -+ xasprintf(&client->store.envval, "API:%s", new_ccname); -+ client->store.filename = NULL; -+#else -+ if (new_ccname[0] == ':') -+ new_ccname++; -+ xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname); -+ if (strcmp(new_cctype, "DIR") == 0) { -+ char *p; -+ p = strrchr(client->store.envval, '/'); -+ if (p) -+ *p = '\0'; -+ } -+ if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0)) -+ client->store.filename = xstrdup(new_ccname); -+#endif - - #ifdef USE_PAM - if (options.use_pam) -@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) - - krb5_cc_close(krb_context, ccache); - -+ client->store.data = krb_context; -+ - return; - } - -+int -+ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, -+ ssh_gssapi_client *client) -+{ -+ krb5_ccache ccache = NULL; -+ krb5_principal principal = NULL; -+ char *name = NULL; -+ krb5_error_code problem; -+ OM_uint32 maj_status, min_status; -+ -+ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { -+ logit("krb5_cc_resolve(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ return 0; -+ } -+ -+ /* Find out who the principal in this cache is */ -+ if ((problem = krb5_cc_get_principal(krb_context, ccache, -+ &principal))) { -+ logit("krb5_cc_get_principal(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ if ((problem = krb5_unparse_name(krb_context, principal, &name))) { -+ logit("krb5_unparse_name(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ -+ if (strcmp(name,client->exportedname.value)!=0) { -+ debug("Name in local credentials cache differs. Not storing"); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ krb5_free_unparsed_name(krb_context, name); -+ return 0; -+ } -+ krb5_free_unparsed_name(krb_context, name); -+ -+ /* Name matches, so lets get on with it! */ -+ -+ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { -+ logit("krb5_cc_initialize(): %.100s", -+ krb5_get_err_text(krb_context, problem)); -+ krb5_free_principal(krb_context, principal); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ krb5_free_principal(krb_context, principal); -+ -+ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, -+ ccache))) { -+ logit("gss_krb5_copy_ccache() failed. Sorry!"); -+ krb5_cc_close(krb_context, ccache); -+ return 0; -+ } -+ -+ return 1; -+} -+ - ssh_gssapi_mech gssapi_kerberos_mech = { - "toWM5Slw5Ew8Mqkay+al2g==", - "Kerberos", -@@ -203,7 +285,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { - NULL, - &ssh_gssapi_krb5_userok, - NULL, -- &ssh_gssapi_krb5_storecreds -+ &ssh_gssapi_krb5_storecreds, -+ &ssh_gssapi_krb5_updatecreds - }; - - #endif /* KRB5 */ -diff --git a/gss-serv.c b/gss-serv.c -index b0e9c3b49..6bac42931 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 +721,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,11 +744,10 @@ 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) - return (ssh_gssapi_acquire_cred(*ctx)); +@@ -141,6 +143,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss } -+/* Unprivileged */ + /* Unprivileged */ +char * +ssh_gssapi_server_mechanisms(void) { + if (supported_oids == NULL) @@ -1022,10 +770,11 @@ index b0e9c3b49..6bac42931 100644 + return (res); +} + - /* Unprivileged */ ++/* 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 *o gss_OID_set supported; gss_create_empty_oid_set(&min_status, oidset); @@ -1036,7 +785,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; @@ -1086,7 +835,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_g if (client->mech == NULL) return GSS_S_FAILURE; @@ -1100,7 +849,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_g return (ctx->major); } @@ -1109,7 +858,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_g void ssh_gssapi_cleanup_creds(void) { @@ -1135,7 +884,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 /* Privileged */ int @@ -1162,7 +911,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,85 @@ ssh_gssapi_userok(char *user) return (0); } @@ -1254,108 +1003,149 @@ 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" - #include "xmalloc.h" +diff --color -ruNp a/gss-serv-krb5.c b/gss-serv-krb5.c +--- a/gss-serv-krb5.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/gss-serv-krb5.c 2024-09-16 11:46:34.692939840 +0200 +@@ -1,7 +1,7 @@ + /* $OpenBSD: gss-serv-krb5.c,v 1.9 2018/07/09 21:37:55 markus Exp $ */ -+#ifdef GSSAPI -+#include "ssh-gss.h" -+#endif -+ - struct kexalg { - char *name; - u_int type; -@@ -90,9 +94,22 @@ static const struct kexalg kexalgs[] = { - #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ - { NULL, 0, -1, -1, 0 }, - }; -+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_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 }, -+#endif -+ { NULL, 0, -1, -1, 0}, -+}; + /* +- * 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 +@@ -120,7 +120,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + krb5_error_code problem; + krb5_principal princ; + OM_uint32 maj_status, min_status; +- int len; ++ const char *new_ccname, *new_cctype; + const char *errmsg; --char * --kex_alg_list(char sep) -+static char * -+kex_alg_list_internal(char sep, const struct kexalg *algs) - { - char *ret = NULL; - const struct kexalg *k; -@@ -104,6 +121,18 @@ kex_alg_list(char sep) - return ret; - } - -+char * -+kex_alg_list(char sep) -+{ -+ return kex_alg_list_internal(sep, kexalgs); -+} -+ -+char * -+kex_gss_alg_list(char sep) -+{ -+ return kex_alg_list_internal(sep, gss_kexalgs); -+} -+ - static const struct kexalg * - kex_alg_by_name(const char *name) - { -@@ -113,6 +142,10 @@ kex_alg_by_name(const char *name) - if (strcmp(k->name, name) == 0) - return k; + if (client->creds == NULL) { +@@ -180,11 +180,26 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + return; } -+ for (k = gss_kexalgs; k->name != NULL; k++) { -+ if (strncmp(k->name, name, strlen(k->name)) == 0) -+ return k; + +- client->store.filename = xstrdup(krb5_cc_get_name(krb_context, ccache)); ++ new_cctype = krb5_cc_get_type(krb_context, ccache); ++ new_ccname = krb5_cc_get_name(krb_context, ccache); ++ + client->store.envvar = "KRB5CCNAME"; +- len = strlen(client->store.filename) + 6; +- client->store.envval = xmalloc(len); +- snprintf(client->store.envval, len, "FILE:%s", client->store.filename); ++#ifdef USE_CCAPI ++ xasprintf(&client->store.envval, "API:%s", new_ccname); ++ client->store.filename = NULL; ++#else ++ if (new_ccname[0] == ':') ++ new_ccname++; ++ xasprintf(&client->store.envval, "%s:%s", new_cctype, new_ccname); ++ if (strcmp(new_cctype, "DIR") == 0) { ++ char *p; ++ p = strrchr(client->store.envval, '/'); ++ if (p) ++ *p = '\0'; + } - return NULL; ++ if ((strcmp(new_cctype, "FILE") == 0) || (strcmp(new_cctype, "DIR") == 0)) ++ client->store.filename = xstrdup(new_ccname); ++#endif + + #ifdef USE_PAM + if (options.use_pam) +@@ -193,9 +208,76 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl + + krb5_cc_close(krb_context, ccache); + ++ client->store.data = krb_context; ++ + return; } -@@ -336,3 +369,26 @@ kex_assemble_names(char **listp, const char *def, const char *all) - free(ret); - return r; - } -+ -+/* Validate GSS KEX method name list */ +int -+kex_gss_names_valid(const char *names) ++ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, ++ ssh_gssapi_client *client) +{ -+ char *s, *cp, *p; ++ krb5_ccache ccache = NULL; ++ krb5_principal principal = NULL; ++ char *name = NULL; ++ krb5_error_code problem; ++ OM_uint32 maj_status, min_status; + -+ if (names == NULL || *names == '\0') -+ return 0; -+ s = cp = xstrdup(names); -+ for ((p = strsep(&cp, ",")); p && *p != '\0'; -+ (p = strsep(&cp, ","))) { -+ if (strncmp(p, "gss-", 4) != 0 -+ || kex_alg_by_name(p) == NULL) { -+ error("Unsupported KEX algorithm \"%.100s\"", p); -+ free(s); -+ return 0; -+ } ++ if ((problem = krb5_cc_resolve(krb_context, store->envval, &ccache))) { ++ logit("krb5_cc_resolve(): %.100s", ++ krb5_get_err_text(krb_context, problem)); ++ return 0; + } -+ debug3("gss kex names ok: [%s]", names); -+ free(s); ++ ++ /* Find out who the principal in this cache is */ ++ if ((problem = krb5_cc_get_principal(krb_context, ccache, ++ &principal))) { ++ logit("krb5_cc_get_principal(): %.100s", ++ krb5_get_err_text(krb_context, problem)); ++ krb5_cc_close(krb_context, ccache); ++ return 0; ++ } ++ ++ if ((problem = krb5_unparse_name(krb_context, principal, &name))) { ++ logit("krb5_unparse_name(): %.100s", ++ krb5_get_err_text(krb_context, problem)); ++ krb5_free_principal(krb_context, principal); ++ krb5_cc_close(krb_context, ccache); ++ return 0; ++ } ++ ++ ++ if (strcmp(name,client->exportedname.value)!=0) { ++ debug("Name in local credentials cache differs. Not storing"); ++ krb5_free_principal(krb_context, principal); ++ krb5_cc_close(krb_context, ccache); ++ krb5_free_unparsed_name(krb_context, name); ++ return 0; ++ } ++ krb5_free_unparsed_name(krb_context, name); ++ ++ /* Name matches, so lets get on with it! */ ++ ++ if ((problem = krb5_cc_initialize(krb_context, ccache, principal))) { ++ logit("krb5_cc_initialize(): %.100s", ++ krb5_get_err_text(krb_context, problem)); ++ krb5_free_principal(krb_context, principal); ++ krb5_cc_close(krb_context, ccache); ++ return 0; ++ } ++ ++ krb5_free_principal(krb_context, principal); ++ ++ if ((maj_status = gss_krb5_copy_ccache(&min_status, client->creds, ++ ccache))) { ++ logit("gss_krb5_copy_ccache() failed. Sorry!"); ++ krb5_cc_close(krb_context, ccache); ++ return 0; ++ } ++ + 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 ++ + ssh_gssapi_mech gssapi_kerberos_mech = { + "toWM5Slw5Ew8Mqkay+al2g==", + "Kerberos", +@@ -203,7 +285,8 @@ ssh_gssapi_mech gssapi_kerberos_mech = { + NULL, + &ssh_gssapi_krb5_userok, + NULL, +- &ssh_gssapi_krb5_storecreds ++ &ssh_gssapi_krb5_storecreds, ++ &ssh_gssapi_krb5_updatecreds + }; + + #endif /* KRB5 */ +diff --color -ruNp a/kex.c b/kex.c +--- a/kex.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/kex.c 2024-09-16 11:46:34.692939840 +0200 +@@ -297,17 +297,37 @@ static int kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m) { int r; @@ -1399,7 +1189,7 @@ index 814fad947..9a2ce6d88 100644 (r = sshbuf_put_cstring(m, "0")) != 0) { error_fr(r, "compose"); return r; -@@ -735,6 +755,9 @@ kex_free(struct kex *kex) +@@ -737,6 +757,9 @@ kex_free(struct kex *kex) sshbuf_free(kex->server_version); sshbuf_free(kex->client_pub); sshbuf_free(kex->session_id); @@ -1409,93 +1199,10 @@ index 814fad947..9a2ce6d88 100644 sshbuf_free(kex->initial_sig); sshkey_free(kex->initial_hostkey); free(kex->failed_choice); -diff --git a/kex.h b/kex.h -index 55baa6a1e..206ce60ed 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 { - KEX_C25519_SHA256, - KEX_KEM_SNTRUP761X25519_SHA512, - KEX_KEM_MLKEM768X25519_SHA256, -+#ifdef GSSAPI -+ KEX_GSS_GRP1_SHA1, -+ KEX_GSS_GRP14_SHA1, -+ KEX_GSS_GRP14_SHA256, -+ KEX_GSS_GRP16_SHA512, -+ KEX_GSS_GEX_SHA1, -+ KEX_GSS_NISTP256_SHA256, -+ KEX_GSS_C25519_SHA256, -+#endif - KEX_MAX - }; - -@@ -169,6 +182,13 @@ struct kex { - u_int flags; - int hash_alg; - int ec_nid; -+#ifdef GSSAPI -+ Gssctxt *gss; -+ int gss_deleg_creds; -+ int gss_trust_dns; -+ char *gss_host; -+ char *gss_client; -+#endif - char *failed_choice; - int (*verify_host_key)(struct sshkey *, struct ssh *); - struct sshkey *(*load_host_public_key)(int, int, struct ssh *); -@@ -196,8 +216,10 @@ int kex_nid_from_name(const char *); - int kex_is_pq_from_name(const char *); - int kex_names_valid(const char *); - char *kex_alg_list(char); -+char *kex_gss_alg_list(char); - char *kex_names_cat(const char *, const char *); - int kex_has_any_alg(const char *, const char *); -+int kex_gss_names_valid(const char *); - int kex_assemble_names(char **, const char *, const char *); - void kex_proposal_populate_entries(struct ssh *, char *prop[PROPOSAL_MAX], - const char *, const char *, const char *, const char *, const char *); -@@ -231,6 +253,12 @@ int kexgex_client(struct ssh *); - int kexgex_server(struct ssh *); - int kex_gen_client(struct ssh *); - int kex_gen_server(struct ssh *); -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+int kexgssgex_client(struct ssh *); -+int kexgssgex_server(struct ssh *); -+int kexgss_client(struct ssh *); -+int kexgss_server(struct ssh *); -+#endif - - int kex_dh_keypair(struct kex *); - int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, -@@ -269,6 +297,12 @@ int kexgex_hash(int, const struct sshbuf *, const struct sshbuf *, - const BIGNUM *, const u_char *, size_t, - u_char *, size_t *); - -+int kex_gen_hash(int hash_alg, const struct sshbuf *client_version, -+ const struct sshbuf *server_version, const struct sshbuf *client_kexinit, -+ const struct sshbuf *server_kexinit, const struct sshbuf *server_host_key_blob, -+ const struct sshbuf *client_pub, const struct sshbuf *server_pub, -+ const struct sshbuf *shared_secret, u_char *hash, size_t *hashlen); -+ - void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) - __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) - __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); -diff --git a/kexdh.c b/kexdh.c -index 191bdced0..6d5a7813d 100644 ---- a/kexdh.c -+++ b/kexdh.c -@@ -50,13 +50,23 @@ kex_dh_keygen(struct kex *kex) +diff --color -ruNp a/kexdh.c b/kexdh.c +--- a/kexdh.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/kexdh.c 2024-09-16 11:46:34.693939862 +0200 +@@ -49,13 +49,23 @@ kex_dh_keygen(struct kex *kex) { switch (kex->kex_type) { case KEX_DH_GRP1_SHA1: @@ -1519,10 +1226,9 @@ index 191bdced0..6d5a7813d 100644 kex->dh = dh_new_group16(); break; case KEX_DH_GRP18_SHA512: -diff --git a/kexgen.c b/kexgen.c -index 494d4b233..58edc79ad 100644 ---- a/kexgen.c -+++ b/kexgen.c +diff --color -ruNp a/kexgen.c b/kexgen.c +--- a/kexgen.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/kexgen.c 2024-09-16 11:46:34.693939862 +0200 @@ -44,7 +44,7 @@ static int input_kex_gen_init(int, u_int32_t, struct ssh *); static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh); @@ -1532,11 +1238,9 @@ index 494d4b233..58edc79ad 100644 kex_gen_hash( int hash_alg, const struct sshbuf *client_version, -diff --git a/kexgssc.c b/kexgssc.c -new file mode 100644 -index 000000000..96f7b6f58 ---- /dev/null -+++ b/kexgssc.c +diff --color -ruNp a/kexgssc.c b/kexgssc.c +--- a/kexgssc.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/kexgssc.c 2024-10-14 15:18:02.491798105 +0200 @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. @@ -2244,11 +1948,9 @@ index 000000000..96f7b6f58 +} + +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ -diff --git a/kexgsss.c b/kexgsss.c -new file mode 100644 -index 000000000..8362081ea ---- /dev/null -+++ b/kexgsss.c +diff --color -ruNp a/kexgsss.c b/kexgsss.c +--- a/kexgsss.c 1970-01-01 01:00:00.000000000 +0100 ++++ b/kexgsss.c 2024-10-14 15:18:02.491798105 +0200 @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. @@ -2851,11 +2553,223 @@ index 000000000..8362081ea +} + +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ -diff --git a/monitor.c b/monitor.c -index 85dc1b1b7..d463d6a9c 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -137,6 +137,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); +diff --color -ruNp a/kex.h b/kex.h +--- a/kex.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/kex.h 2024-09-16 11:46:34.710940224 +0200 +@@ -29,6 +29,10 @@ + #include "mac.h" + #include "crypto_api.h" + ++#ifdef GSSAPI ++# include "ssh-gss.h" /* Gssctxt */ ++#endif ++ + #ifdef WITH_OPENSSL + # include + # include +@@ -102,6 +106,15 @@ enum kex_exchange { + KEX_C25519_SHA256, + KEX_KEM_SNTRUP761X25519_SHA512, + KEX_KEM_MLKEM768X25519_SHA256, ++#ifdef GSSAPI ++ KEX_GSS_GRP1_SHA1, ++ KEX_GSS_GRP14_SHA1, ++ KEX_GSS_GRP14_SHA256, ++ KEX_GSS_GRP16_SHA512, ++ KEX_GSS_GEX_SHA1, ++ KEX_GSS_NISTP256_SHA256, ++ KEX_GSS_C25519_SHA256, ++#endif + KEX_MAX + }; + +@@ -164,6 +177,13 @@ struct kex { + u_int flags; + int hash_alg; + int ec_nid; ++#ifdef GSSAPI ++ Gssctxt *gss; ++ int gss_deleg_creds; ++ int gss_trust_dns; ++ char *gss_host; ++ char *gss_client; ++#endif + char *failed_choice; + int (*verify_host_key)(struct sshkey *, struct ssh *); + struct sshkey *(*load_host_public_key)(int, int, struct ssh *); +@@ -189,8 +209,10 @@ int kex_hash_from_name(const char *); + int kex_nid_from_name(const char *); + int kex_names_valid(const char *); + char *kex_alg_list(char); ++char *kex_gss_alg_list(char); + char *kex_names_cat(const char *, const char *); + int kex_has_any_alg(const char *, const char *); ++int kex_gss_names_valid(const char *); + int kex_assemble_names(char **, const char *, const char *); + void kex_proposal_populate_entries(struct ssh *, char *prop[PROPOSAL_MAX], + const char *, const char *, const char *, const char *, const char *); +@@ -224,6 +246,12 @@ int kexgex_client(struct ssh *); + int kexgex_server(struct ssh *); + int kex_gen_client(struct ssh *); + int kex_gen_server(struct ssh *); ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++int kexgssgex_client(struct ssh *); ++int kexgssgex_server(struct ssh *); ++int kexgss_client(struct ssh *); ++int kexgss_server(struct ssh *); ++#endif + + int kex_dh_keypair(struct kex *); + int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, +@@ -256,6 +284,12 @@ int kexgex_hash(int, const struct sshbu + const BIGNUM *, const u_char *, size_t, + u_char *, size_t *); + ++int kex_gen_hash(int hash_alg, const struct sshbuf *client_version, ++ const struct sshbuf *server_version, const struct sshbuf *client_kexinit, ++ const struct sshbuf *server_kexinit, const struct sshbuf *server_host_key_blob, ++ const struct sshbuf *client_pub, const struct sshbuf *server_pub, ++ const struct sshbuf *shared_secret, u_char *hash, size_t *hashlen); ++ + void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); +diff --color -ruNp a/kex-names.c b/kex-names.c +--- a/kex-names.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/kex-names.c 2024-09-16 11:46:34.694939883 +0200 +@@ -45,6 +45,10 @@ + #include "ssherr.h" + #include "xmalloc.h" + ++#ifdef GSSAPI ++#include "ssh-gss.h" ++#endif ++ + struct kexalg { + char *name; + u_int type; +@@ -83,15 +87,28 @@ static const struct kexalg kexalgs[] = { + #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ + { NULL, 0, -1, -1}, + }; ++static const struct kexalg gss_kexalgs[] = { ++#ifdef GSSAPI ++ { KEX_GSS_GEX_SHA1_ID, KEX_GSS_GEX_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP1_SHA1_ID, KEX_GSS_GRP1_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP14_SHA1_ID, KEX_GSS_GRP14_SHA1, 0, SSH_DIGEST_SHA1 }, ++ { KEX_GSS_GRP14_SHA256_ID, KEX_GSS_GRP14_SHA256, 0, SSH_DIGEST_SHA256 }, ++ { KEX_GSS_GRP16_SHA512_ID, KEX_GSS_GRP16_SHA512, 0, SSH_DIGEST_SHA512 }, ++ { KEX_GSS_NISTP256_SHA256_ID, KEX_GSS_NISTP256_SHA256, ++ NID_X9_62_prime256v1, SSH_DIGEST_SHA256 }, ++ { KEX_GSS_C25519_SHA256_ID, KEX_GSS_C25519_SHA256, 0, SSH_DIGEST_SHA256 }, ++#endif ++ { NULL, 0, -1, -1}, ++}; + +-char * +-kex_alg_list(char sep) ++static char * ++kex_alg_list_internal(char sep, const struct kexalg *algs) + { + char *ret = NULL, *tmp; + size_t nlen, rlen = 0; + const struct kexalg *k; + +- for (k = kexalgs; k->name != NULL; k++) { ++ for (k = algs; k->name != NULL; k++) { + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(k->name); +@@ -106,6 +123,18 @@ kex_alg_list(char sep) + return ret; + } + ++char * ++kex_alg_list(char sep) ++{ ++ return kex_alg_list_internal(sep, kexalgs); ++} ++ ++char * ++kex_gss_alg_list(char sep) ++{ ++ return kex_alg_list_internal(sep, gss_kexalgs); ++} ++ + static const struct kexalg * + kex_alg_by_name(const char *name) + { +@@ -115,6 +144,10 @@ kex_alg_by_name(const char *name) + if (strcmp(k->name, name) == 0) + return k; + } ++ for (k = gss_kexalgs; k->name != NULL; k++) { ++ if (strncmp(k->name, name, strlen(k->name)) == 0) ++ return k; ++ } + return NULL; + } + +@@ -328,3 +361,26 @@ kex_assemble_names(char **listp, const c + free(ret); + return r; + } ++ ++/* Validate GSS KEX method name list */ ++int ++kex_gss_names_valid(const char *names) ++{ ++ char *s, *cp, *p; ++ ++ if (names == NULL || *names == '\0') ++ return 0; ++ s = cp = xstrdup(names); ++ for ((p = strsep(&cp, ",")); p && *p != '\0'; ++ (p = strsep(&cp, ","))) { ++ if (strncmp(p, "gss-", 4) != 0 ++ || kex_alg_by_name(p) == NULL) { ++ error("Unsupported KEX algorithm \"%.100s\"", p); ++ free(s); ++ return 0; ++ } ++ } ++ debug3("gss kex names ok: [%s]", names); ++ free(s); ++ return 1; ++} +diff --color -ruNp a/Makefile.in b/Makefile.in +--- a/Makefile.in 2024-09-16 11:45:56.868133454 +0200 ++++ b/Makefile.in 2024-09-16 11:46:34.695939904 +0200 +@@ -114,6 +114,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ + kexgexc.o kexgexs.o \ + kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \ ++ kexgssc.o \ + sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ + sshbuf-io.o + +@@ -135,7 +136,7 @@ SSHD_SESSION_OBJS=sshd-session.o auth-rh + auth2-chall.o groupaccess.o \ + auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ + auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-pubkeyfile.o \ +- monitor.o monitor_wrap.o auth-krb5.o \ ++ monitor.o monitor_wrap.o auth-krb5.o kexgsss.o \ + auth2-gss.o gss-serv.o gss-serv-krb5.o \ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ + sftp-server.o sftp-common.o \ +@@ -529,7 +530,7 @@ regress-prep: + ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile + + REGRESSLIBS=libssh.a $(LIBCOMPAT) +-TESTLIBS=$(LIBS) $(CHANNELLIBS) ++TESTLIBS=$(LIBS) $(CHANNELLIBS) $(GSSLIBS) + + regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS) + $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \ +diff --color -ruNp a/monitor.c b/monitor.c +--- a/monitor.c 2024-09-16 11:45:56.861133305 +0200 ++++ b/monitor.c 2024-09-16 11:46:34.696939926 +0200 +@@ -143,6 +143,8 @@ int mm_answer_gss_setup_ctx(struct ssh * int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *); int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *); int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *); @@ -2864,7 +2778,7 @@ index 85dc1b1b7..d463d6a9c 100644 #endif #ifdef SSH_AUDIT_EVENTS -@@ -214,11 +216,18 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -219,11 +221,18 @@ struct mon_table mon_dispatch_proto20[] {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, {MONITOR_REQ_GSSCHECKMIC, MON_ONCE, mm_answer_gss_checkmic}, @@ -2880,11 +2794,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 +@@ -292,6 +301,10 @@ monitor_child_preauth(struct ssh *ssh, s + /* Permit requests for moduli and signatures */ monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); +#ifdef GSSAPI @@ -2894,7 +2808,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) +@@ -344,8 +357,15 @@ monitor_child_preauth(struct ssh *ssh, s if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) { auth_log(ssh, authenticated, partial, auth_method, auth_submethod); @@ -2911,7 +2825,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) +@@ -413,6 +433,10 @@ monitor_child_postauth(struct ssh *ssh, monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); @@ -2922,7 +2836,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) +@@ -1793,6 +1817,17 @@ monitor_apply_keystate(struct ssh *ssh, # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kex_gen_server; # endif @@ -2940,7 +2854,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) +@@ -1885,8 +1920,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, u_char *p; int r; @@ -2951,7 +2865,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) +@@ -1918,8 +1953,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh OM_uint32 flags = 0; /* GSI needs this */ int r; @@ -2962,7 +2876,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) +@@ -1939,6 +1974,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); @@ -2970,7 +2884,7 @@ index 85dc1b1b7..d463d6a9c 100644 } return (0); } -@@ -2052,8 +2088,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1950,8 +1986,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, OM_uint32 ret; int r; @@ -2981,7 +2895,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) +@@ -1977,13 +2013,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) { @@ -2993,17 +2907,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) +@@ -1992,7 +2032,11 @@ mm_answer_gss_userok(struct ssh *ssh, in debug3_f("sending result %d", authenticated); mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); @@ -3016,7 +2930,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) +@@ -2000,5 +2044,84 @@ mm_answer_gss_userok(struct ssh *ssh, in /* Monitor loop will terminate if authenticated */ return (authenticated); } @@ -3101,11 +3015,10 @@ index 85dc1b1b7..d463d6a9c 100644 + #endif /* GSSAPI */ -diff --git a/monitor.h b/monitor.h -index 9dcd9c293..dbc7e0037 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -68,6 +68,8 @@ enum monitor_reqtype { +diff --color -ruNp a/monitor.h b/monitor.h +--- a/monitor.h 2024-09-16 11:45:56.861133305 +0200 ++++ b/monitor.h 2024-09-16 11:46:34.696939926 +0200 +@@ -67,6 +67,8 @@ enum monitor_reqtype { MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111, MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113, @@ -3114,11 +3027,10 @@ index 9dcd9c293..dbc7e0037 100644 }; struct ssh; -diff --git a/monitor_wrap.c b/monitor_wrap.c -index 347eb6870..08dc29e12 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) +diff --color -ruNp a/monitor_wrap.c b/monitor_wrap.c +--- a/monitor_wrap.c 2024-09-16 11:45:56.862133326 +0200 ++++ b/monitor_wrap.c 2024-09-16 11:46:34.697939947 +0200 +@@ -1075,13 +1075,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss } int @@ -3135,7 +3047,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) +@@ -1094,6 +1096,59 @@ mm_ssh_gssapi_userok(char *user) debug3_f("user %sauthenticated", authenticated ? "" : "not "); return (authenticated); } @@ -3195,11 +3107,10 @@ index 347eb6870..08dc29e12 100644 #endif /* GSSAPI */ /* -diff --git a/monitor_wrap.h b/monitor_wrap.h -index 9b42ddbcb..12c489c33 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); +diff --color -ruNp a/monitor_wrap.h b/monitor_wrap.h +--- a/monitor_wrap.h 2024-09-16 11:45:56.862133326 +0200 ++++ b/monitor_wrap.h 2024-09-16 11:46:34.697939947 +0200 +@@ -67,8 +67,10 @@ void mm_decode_activate_server_options(s OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); OM_uint32 mm_ssh_gssapi_accept_ctx(Gssctxt *, gss_buffer_desc *, gss_buffer_desc *, OM_uint32 *); @@ -3211,19 +3122,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 --color -ruNp a/readconf.c b/readconf.c +--- a/readconf.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/readconf.c 2024-09-16 11:46:34.699939990 +0200 +@@ -70,6 +70,7 @@ + #include "uidswap.h" #include "myproposal.h" #include "digest.h" - #include "version.h" +#include "ssh-gss.h" /* Format of the configuration file: -@@ -159,6 +160,8 @@ typedef enum { +@@ -164,6 +165,8 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, @@ -3232,7 +3142,7 @@ index d99205944..eab734aaf 100644 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, -@@ -206,10 +209,22 @@ static struct { +@@ -210,10 +213,22 @@ static struct { /* Sometimes-unsupported options */ #if defined(GSSAPI) { "gssapiauthentication", oGssAuthentication }, @@ -3255,7 +3165,7 @@ index d99205944..eab734aaf 100644 #endif #ifdef ENABLE_PKCS11 { "pkcs11provider", oPKCS11Provider }, -@@ -1326,10 +1341,42 @@ parse_time: +@@ -1227,10 +1242,42 @@ parse_time: intptr = &options->gss_authentication; goto parse_flag; @@ -3298,7 +3208,7 @@ index d99205944..eab734aaf 100644 case oBatchMode: intptr = &options->batch_mode; goto parse_flag; -@@ -2698,7 +2745,13 @@ initialize_options(Options * options) +@@ -2542,7 +2589,13 @@ initialize_options(Options * options) options->fwd_opts.streamlocal_bind_unlink = -1; options->pubkey_authentication = -1; options->gss_authentication = -1; @@ -3312,7 +3222,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) +@@ -2705,8 +2758,18 @@ fill_default_options(Options * options) options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3331,7 +3241,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) +@@ -3533,7 +3596,14 @@ dump_client_config(Options *o, const cha dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); #ifdef GSSAPI dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); @@ -3346,11 +3256,10 @@ 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 -@@ -39,7 +39,13 @@ typedef struct { +diff --color -ruNp a/readconf.h b/readconf.h +--- a/readconf.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/readconf.h 2024-09-16 11:46:34.699939990 +0200 +@@ -40,7 +40,13 @@ typedef struct { int pubkey_authentication; /* Try ssh2 pubkey authentication. */ int hostbased_authentication; /* ssh2's rhosts_rsa */ int gss_authentication; /* Try GSS authentication */ @@ -3364,19 +3273,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 --color -ruNp a/servconf.c b/servconf.c +--- a/servconf.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/servconf.c 2024-09-16 11:46:34.700940011 +0200 +@@ -68,6 +68,7 @@ + #include "auth.h" #include "myproposal.h" #include "digest.h" - #include "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) +@@ -137,8 +138,11 @@ initialize_server_options(ServerOptions options->kerberos_ticket_cleanup = -1; options->kerberos_get_afs_token = -1; options->gss_authentication=-1; @@ -3388,7 +3296,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) +@@ -376,10 +380,18 @@ fill_default_server_options(ServerOption options->kerberos_get_afs_token = 0; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3407,7 +3315,7 @@ 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 { +@@ -558,6 +570,7 @@ typedef enum { sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, @@ -3415,7 +3323,7 @@ index 48ec8c4ec..3b93ca829 100644 sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -647,12 +660,22 @@ static struct { +@@ -643,12 +656,22 @@ static struct { #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, @@ -3438,7 +3346,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, +@@ -1585,6 +1608,10 @@ process_server_config_line_depth(ServerO intptr = &options->gss_authentication; goto parse_flag; @@ -3449,7 +3357,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, +@@ -1593,6 +1620,22 @@ process_server_config_line_depth(ServerO intptr = &options->gss_strict_acceptor; goto parse_flag; @@ -3472,22 +3380,21 @@ index 48ec8c4ec..3b93ca829 100644 case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -@@ -3256,7 +3299,10 @@ dump_config(ServerOptions *o) +@@ -3178,6 +3221,10 @@ dump_config(ServerOptions *o) #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); + 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 ---- a/servconf.h -+++ b/servconf.h -@@ -150,8 +150,11 @@ typedef struct { +diff --color -ruNp a/servconf.h b/servconf.h +--- a/servconf.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/servconf.h 2024-09-16 11:46:34.700940011 +0200 +@@ -149,8 +149,11 @@ typedef struct { int kerberos_get_afs_token; /* If true, try to get AFS token if * authenticated with Kerberos. */ int gss_authentication; /* If true, permit GSSAPI authentication */ @@ -3499,11 +3406,10 @@ index 9beb90fae..c3f501400 100644 int password_authentication; /* If true, permit password * authentication. */ int kbd_interactive_authentication; /* If true, permit */ -diff --git a/session.c b/session.c -index f265fdc3e..b8f0c1a58 100644 ---- a/session.c -+++ b/session.c -@@ -2630,13 +2630,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) +diff --color -ruNp a/session.c b/session.c +--- a/session.c 2024-09-16 11:45:56.866133411 +0200 ++++ b/session.c 2024-09-16 11:46:34.701940032 +0200 +@@ -2674,13 +2674,19 @@ do_cleanup(struct ssh *ssh, Authctxt *au #ifdef KRB5 if (options.kerberos_ticket_cleanup && @@ -3525,10 +3431,542 @@ index f265fdc3e..b8f0c1a58 100644 #endif /* remove agent socket */ -diff --git a/ssh-gss.h b/ssh-gss.h -index 7b14e74a8..8ec451926 100644 ---- a/ssh-gss.h -+++ b/ssh-gss.h +diff --color -ruNp a/ssh.1 b/ssh.1 +--- a/ssh.1 2024-09-16 11:45:56.875133603 +0200 ++++ b/ssh.1 2024-09-16 11:46:34.701940032 +0200 +@@ -536,7 +536,13 @@ For full details of the options listed b + .It GatewayPorts + .It GlobalKnownHostsFile + .It GSSAPIAuthentication ++.It GSSAPIKeyExchange ++.It GSSAPIClientIdentity + .It GSSAPIDelegateCredentials ++.It GSSAPIKexAlgorithms ++.It GSSAPIRenewalForcesRekey ++.It GSSAPIServerIdentity ++.It GSSAPITrustDns + .It HashKnownHosts + .It Host + .It HostbasedAcceptedAlgorithms +@@ -624,6 +630,8 @@ flag), + (supported message integrity codes), + .Ar kex + (key exchange algorithms), ++.Ar kex-gss ++(GSSAPI key exchange algorithms), + .Ar key + (key types), + .Ar key-ca-sign +diff --color -ruNp a/ssh.c b/ssh.c +--- a/ssh.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/ssh.c 2024-09-16 11:46:34.702940054 +0200 +@@ -827,6 +827,8 @@ main(int ac, char **av) + else if (strcmp(optarg, "kex") == 0 || + strcasecmp(optarg, "KexAlgorithms") == 0) + cp = kex_alg_list('\n'); ++ else if (strcmp(optarg, "kex-gss") == 0) ++ cp = kex_gss_alg_list('\n'); + else if (strcmp(optarg, "key") == 0) + cp = sshkey_alg_list(0, 0, 0, '\n'); + else if (strcmp(optarg, "key-cert") == 0) +@@ -857,8 +859,8 @@ main(int ac, char **av) + } else if (strcmp(optarg, "help") == 0) { + cp = xstrdup( + "cipher\ncipher-auth\ncompression\nkex\n" +- "key\nkey-cert\nkey-plain\nkey-sig\nmac\n" +- "protocol-version\nsig"); ++ "kex-gss\nkey\nkey-cert\nkey-plain\n" ++ "key-sig\nmac\nprotocol-version\nsig"); + } + if (cp == NULL) + fatal("Unsupported query \"%s\"", optarg); +diff --color -ruNp a/ssh_config b/ssh_config +--- a/ssh_config 2024-09-16 11:45:56.884133795 +0200 ++++ b/ssh_config 2024-09-16 11:46:34.702940054 +0200 +@@ -24,6 +24,8 @@ + # HostbasedAuthentication no + # GSSAPIAuthentication no + # GSSAPIDelegateCredentials no ++# GSSAPIKeyExchange no ++# GSSAPITrustDNS no + # BatchMode no + # CheckHostIP no + # AddressFamily any +diff --color -ruNp a/ssh_config.5 b/ssh_config.5 +--- a/ssh_config.5 2024-07-01 06:36:28.000000000 +0200 ++++ b/ssh_config.5 2024-09-16 11:46:34.703940075 +0200 +@@ -938,10 +938,68 @@ The default is + Specifies whether user authentication based on GSSAPI is allowed. + The default is + .Cm no . ++.It Cm GSSAPIClientIdentity ++If set, specifies the GSSAPI client identity that ssh should use when ++connecting to the server. The default is unset, which means that the default ++identity will be used. + .It Cm GSSAPIDelegateCredentials + Forward (delegate) credentials to the server. + The default is + .Cm no . ++.It Cm GSSAPIKeyExchange ++Specifies whether key exchange based on GSSAPI may be used. When using ++GSSAPI key exchange the server need not have a host key. ++The default is ++.Dq no . ++.It Cm GSSAPIRenewalForcesRekey ++If set to ++.Dq yes ++then renewal of the client's GSSAPI credentials will force the rekeying of the ++ssh connection. With a compatible server, this will delegate the renewed ++credentials to a session on the server. ++.Pp ++Checks are made to ensure that credentials are only propagated when the new ++credentials match the old ones on the originating client and where the ++receiving server still has the old set in its cache. ++.Pp ++The default is ++.Dq no . ++.Pp ++For this to work ++.Cm GSSAPIKeyExchange ++needs to be enabled in the server and also used by the client. ++.It Cm GSSAPIServerIdentity ++If set, specifies the GSSAPI server identity that ssh should expect when ++connecting to the server. The default is unset, which means that the ++expected GSSAPI server identity will be determined from the target ++hostname. ++.It Cm GSSAPITrustDns ++Set to ++.Dq yes ++to indicate that the DNS is trusted to securely canonicalize ++the name of the host being connected to. If ++.Dq no , ++the hostname entered on the ++command line will be passed untouched to the GSSAPI library. ++The default is ++.Dq no . ++.It Cm GSSAPIKexAlgorithms ++The list of key exchange algorithms that are offered for GSSAPI ++key exchange. Possible values are ++.Bd -literal -offset 3n ++gss-gex-sha1-, ++gss-group1-sha1-, ++gss-group14-sha1-, ++gss-group14-sha256-, ++gss-group16-sha512-, ++gss-nistp256-sha256-, ++gss-curve25519-sha256- ++.Ed ++.Pp ++The default is ++.Dq gss-group14-sha256-,gss-group16-sha512-,gss-nistp256-sha256-, ++gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- . ++This option only applies to connections using GSSAPI. + .It Cm HashKnownHosts + Indicates that + .Xr ssh 1 +diff --color -ruNp a/sshconnect2.c b/sshconnect2.c +--- a/sshconnect2.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/sshconnect2.c 2024-09-16 11:46:34.703940075 +0200 +@@ -222,6 +222,11 @@ ssh_kex2(struct ssh *ssh, char *host, st + char *all_key, *hkalgs = NULL; + int r, use_known_hosts_order = 0; + ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++ char *orig = NULL, *gss = NULL; ++ char *gss_host = NULL; ++#endif ++ + xxx_host = host; + xxx_hostaddr = hostaddr; + xxx_conn_info = cinfo; +@@ -255,6 +260,42 @@ ssh_kex2(struct ssh *ssh, char *host, st + compression_alg_list(options.compression), + hkalgs ? hkalgs : options.hostkeyalgorithms); + ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++ if (options.gss_keyex) { ++ /* 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); ++ gss_host = xstrdup(host); ++ } ++ } else { ++ gss_host = xstrdup(host); ++ } ++ ++ gss = ssh_gssapi_client_mechanisms(gss_host, ++ options.gss_client_identity, options.gss_kex_algorithms); ++ if (gss) { ++ debug("Offering GSSAPI proposal: %s", gss); ++ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], ++ "%s,%s", gss, orig); ++ ++ /* If we've got GSSAPI algorithms, then we also support the ++ * 'null' hostkey, as a last resort */ ++ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; ++ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], ++ "%s,null", orig); ++ } ++ } ++#endif ++ + free(hkalgs); + + /* start key exchange */ +@@ -271,15 +312,45 @@ ssh_kex2(struct ssh *ssh, char *host, st + # ifdef OPENSSL_HAS_ECC + ssh->kex->kex[KEX_ECDH_SHA2] = kex_gen_client; + # endif +-#endif ++# ifdef GSSAPI ++ if (options.gss_keyex) { ++ ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; ++ ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; ++ ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client; ++ ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client; ++ ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client; ++ ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client; ++ ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client; ++ } ++# endif ++#endif /* WITH_OPENSSL */ + ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; + ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; + ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client; + ssh->kex->verify_host_key=&verify_host_key_callback; + ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++ if (options.gss_keyex) { ++ ssh->kex->gss_deleg_creds = options.gss_deleg_creds; ++ ssh->kex->gss_trust_dns = options.gss_trust_dns; ++ ssh->kex->gss_client = options.gss_client_identity; ++ ssh->kex->gss_host = gss_host; ++ } ++#endif ++ + ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); + kex_proposal_free_entries(myproposal); + ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++ /* repair myproposal after it was crumpled by the */ ++ /* ext-info removal above */ ++ if (gss) { ++ orig = myproposal[PROPOSAL_KEX_ALGS]; ++ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], ++ "%s,%s", gss, orig); ++ free(gss); ++ } ++#endif + #ifdef DEBUG_KEXDH + /* send 1st encrypted/maced/compressed message */ + if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || +@@ -368,6 +439,7 @@ static int input_gssapi_response(int typ + static int input_gssapi_token(int type, u_int32_t, struct ssh *); + static int input_gssapi_error(int, u_int32_t, struct ssh *); + static int input_gssapi_errtok(int, u_int32_t, struct ssh *); ++static int userauth_gsskeyex(struct ssh *); + #endif + + void userauth(struct ssh *, char *); +@@ -384,6 +456,11 @@ static char *authmethods_get(void); + + Authmethod authmethods[] = { + #ifdef GSSAPI ++ {"gssapi-keyex", ++ userauth_gsskeyex, ++ NULL, ++ &options.gss_keyex, ++ NULL}, + {"gssapi-with-mic", + userauth_gssapi, + userauth_gssapi_cleanup, +@@ -755,12 +832,32 @@ userauth_gssapi(struct ssh *ssh) + OM_uint32 min; + int r, ok = 0; + gss_OID mech = NULL; ++ char *gss_host = NULL; ++ ++ 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(authctxt->host); ++ } ++ } else { ++ gss_host = xstrdup(authctxt->host); ++ } + + /* Try one GSSAPI method at a time, rather than sending them all at + * once. */ + + if (authctxt->gss_supported_mechs == NULL) +- gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); ++ if (GSS_ERROR(gss_indicate_mechs(&min, ++ &authctxt->gss_supported_mechs))) { ++ authctxt->gss_supported_mechs = NULL; ++ free(gss_host); ++ return 0; ++ } + + /* Check to see whether the mechanism is usable before we offer it */ + while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && +@@ -769,13 +866,15 @@ userauth_gssapi(struct ssh *ssh) + elements[authctxt->mech_tried]; + /* My DER encoding requires length<128 */ + if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, +- mech, authctxt->host)) { ++ mech, gss_host, options.gss_client_identity)) { + ok = 1; /* Mechanism works */ + } else { + authctxt->mech_tried++; + } + } + ++ free(gss_host); ++ + if (!ok || mech == NULL) + return 0; + +@@ -1009,6 +1108,55 @@ input_gssapi_error(int type, u_int32_t p + free(lang); + return r; + } ++ ++int ++userauth_gsskeyex(struct ssh *ssh) ++{ ++ struct sshbuf *b = NULL; ++ Authctxt *authctxt = ssh->authctxt; ++ gss_buffer_desc gssbuf; ++ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ms; ++ int r; ++ ++ static int attempt = 0; ++ if (attempt++ >= 1) ++ return (0); ++ ++ if (gss_kex_context == NULL) { ++ debug("No valid Key exchange context"); ++ return (0); ++ } ++ ++ if ((b = sshbuf_new()) == NULL) ++ fatal_f("sshbuf_new failed"); ++ ++ ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service, ++ "gssapi-keyex", ssh->kex->session_id); ++ ++ if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) ++ fatal_f("sshbuf_mutable_ptr failed"); ++ gssbuf.length = sshbuf_len(b); ++ ++ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { ++ sshbuf_free(b); ++ return (0); ++ } ++ ++ if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || ++ (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || ++ (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || ++ (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || ++ (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal_fr(r, "parsing"); ++ ++ sshbuf_free(b); ++ gss_release_buffer(&ms, &mic); ++ ++ return (1); ++} ++ + #endif /* GSSAPI */ + + static int +diff --color -ruNp a/sshd.c b/sshd.c +--- a/sshd.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/sshd.c 2024-09-16 11:46:34.704940096 +0200 +@@ -1551,7 +1551,8 @@ main(int ac, char **av) + free(fp); + } + accumulate_host_timing_secret(cfg, NULL); +- 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); + } +diff --color -ruNp a/sshd_config b/sshd_config +--- a/sshd_config 2024-09-16 11:45:56.888133880 +0200 ++++ b/sshd_config 2024-09-16 11:46:34.704940096 +0200 +@@ -77,6 +77,8 @@ AuthorizedKeysFile .ssh/authorized_keys + # GSSAPI options + #GSSAPIAuthentication no + #GSSAPICleanupCredentials yes ++#GSSAPIStrictAcceptorCheck yes ++#GSSAPIKeyExchange no + + # Set this to 'yes' to enable PAM authentication, account processing, + # and session processing. If this is enabled, PAM authentication will +diff --color -ruNp a/sshd_config.5 b/sshd_config.5 +--- a/sshd_config.5 2024-09-16 11:45:56.885133816 +0200 ++++ b/sshd_config.5 2024-09-16 11:46:34.704940096 +0200 +@@ -739,6 +739,11 @@ Specifies whether to automatically destr + on logout. + The default is + .Cm yes . ++.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. ++The default is ++.Cm no . + .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. + This facility is provided to assist with operation on multi homed machines. + The default is + .Cm yes . ++.It Cm GSSAPIStoreCredentialsOnRekey ++Controls whether the user's GSSAPI credentials should be updated following a ++successful connection rekeying. This option can be used to accepted renewed ++or updated credentials from a compatible client. The default is ++.Dq no . ++.Pp ++For this to work ++.Cm GSSAPIKeyExchange ++needs to be enabled in the server and also used by the client. ++.It Cm GSSAPIKexAlgorithms ++The list of key exchange algorithms that are accepted by GSSAPI ++key exchange. Possible values are ++.Bd -literal -offset 3n ++gss-gex-sha1-, ++gss-group1-sha1-, ++gss-group14-sha1-, ++gss-group14-sha256-, ++gss-group16-sha512-, ++gss-nistp256-sha256-, ++gss-curve25519-sha256- ++.Ed ++.Pp ++The default is ++.Dq gss-group14-sha256-,gss-group16-sha512-,gss-nistp256-sha256-, ++gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- . ++This option only applies to connections using GSSAPI. + .It Cm HostbasedAcceptedAlgorithms + Specifies the signature algorithms that will be accepted for hostbased + authentication as a list of comma-separated patterns. +diff --color -ruNp a/sshd-session.c b/sshd-session.c +--- a/sshd-session.c 2024-09-16 11:45:56.888133880 +0200 ++++ b/sshd-session.c 2024-09-16 11:46:34.705940118 +0200 +@@ -660,8 +660,8 @@ notify_hostkeys(struct ssh *ssh) + } + debug3_f("sent %u hostkeys", nkeys); + if (nkeys == 0) +- fatal_f("no hostkeys"); +- if ((r = sshpkt_send(ssh)) != 0) ++ debug3_f("no hostkeys"); ++ else if ((r = sshpkt_send(ssh)) != 0) + sshpkt_fatal(ssh, r, "%s: send", __func__); + sshbuf_free(buf); + } +@@ -1180,8 +1180,9 @@ main(int ac, char **av) + break; + } + } +- if (!have_key) +- fatal("internal error: monitor received no hostkeys"); ++ /* The GSSAPI key exchange can run without a host key */ ++ if (!have_key && !options.gss_keyex) ++ fatal("internal error: monitor received no hostkeys and GSS KEX is not configured"); + + /* Ensure that umask disallows at least group and world write */ + new_umask = umask(0077) | 0022; +@@ -1462,6 +1463,48 @@ do_ssh2_kex(struct ssh *ssh) + + free(hkalgs); + ++#if defined(GSSAPI) && defined(WITH_OPENSSL) ++ { ++ char *orig; ++ char *gss = NULL; ++ char *newstr = NULL; ++ orig = myproposal[PROPOSAL_KEX_ALGS]; ++ ++ /* ++ * If we don't have a host key, then there's no point advertising ++ * the other key exchange algorithms ++ */ ++ ++ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) ++ orig = NULL; ++ ++ if (options.gss_keyex) ++ gss = ssh_gssapi_server_mechanisms(); ++ else ++ gss = NULL; ++ ++ if (gss && orig) ++ xasprintf(&newstr, "%s,%s", gss, orig); ++ else if (gss) ++ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com"); ++ else if (orig) ++ newstr = orig; ++ ++ /* ++ * If we've got GSSAPI mechanisms, then we've got the 'null' host ++ * key alg, but we can't tell people about it unless its the only ++ * host key algorithm we support ++ */ ++ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) ++ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xstrdup("null"); ++ ++ if (newstr) ++ myproposal[PROPOSAL_KEX_ALGS] = newstr; ++ else ++ fatal("No supported key exchange algorithms"); ++ } ++#endif ++ + /* start key exchange */ + if ((r = kex_setup(ssh, myproposal)) != 0) + fatal_r(r, "kex_setup"); +@@ -1479,7 +1522,18 @@ do_ssh2_kex(struct ssh *ssh) + #ifdef OPENSSL_HAS_ECC + kex->kex[KEX_ECDH_SHA2] = kex_gen_server; + #endif +-#endif ++# ifdef GSSAPI ++ if (options.gss_keyex) { ++ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; ++ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; ++ kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server; ++ kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server; ++ kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server; ++ kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server; ++ kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server; ++ } ++# endif ++#endif /* WITH_OPENSSL */ + kex->kex[KEX_C25519_SHA256] = kex_gen_server; + kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; + kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_server; +diff --color -ruNp a/ssh-gss.h b/ssh-gss.h +--- a/ssh-gss.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/ssh-gss.h 2024-09-16 11:46:34.710940224 +0200 @@ -61,10 +61,36 @@ #define SSH_GSS_OIDTYPE 0x06 @@ -3609,7 +4047,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 *); +@@ -108,6 +149,7 @@ OM_uint32 ssh_gssapi_test_oid_supported( struct sshbuf; int ssh_gssapi_get_buffer_desc(struct sshbuf *, gss_buffer_desc *); @@ -3653,569 +4091,13 @@ index 7b14e74a8..8ec451926 100644 #endif /* GSSAPI */ #endif /* _SSH_GSS_H */ -diff --git a/ssh.1 b/ssh.1 -index db92ac9af..6a9fbdc5b 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 - .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), - (supported message integrity codes), - .Ar kex - (key exchange algorithms), -+.Ar kex-gss -+(GSSAPI key exchange algorithms), - .Ar key - (key types), - .Ar key-ca-sign -diff --git a/ssh.c b/ssh.c -index 3b03108db..8d27f6379 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -847,6 +847,8 @@ main(int ac, char **av) - else if (strcmp(optarg, "kex") == 0 || - strcasecmp(optarg, "KexAlgorithms") == 0) - cp = kex_alg_list('\n'); -+ else if (strcmp(optarg, "kex-gss") == 0) -+ cp = kex_gss_alg_list('\n'); - 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) - } else if (strcmp(optarg, "help") == 0) { - cp = xstrdup( - "cipher\ncipher-auth\ncompression\nkex\n" -- "key\nkey-cert\nkey-plain\nkey-sig\nmac\n" -- "protocol-version\nsig"); -+ "kex-gss\nkey\nkey-cert\nkey-plain\n" -+ "key-sig\nmac\nprotocol-version\nsig"); - } - if (cp == NULL) - fatal("Unsupported query \"%s\"", optarg); -diff --git a/ssh_config b/ssh_config -index d9324c957..ca7c5853b 100644 ---- a/ssh_config -+++ b/ssh_config -@@ -24,6 +24,8 @@ - # HostbasedAuthentication no - # GSSAPIAuthentication no - # GSSAPIDelegateCredentials no -+# GSSAPIKeyExchange no -+# GSSAPITrustDNS no - # BatchMode no - # CheckHostIP no - # AddressFamily any -diff --git a/ssh_config.5 b/ssh_config.5 -index f7066cbaa..8a4b469cf 100644 ---- a/ssh_config.5 -+++ b/ssh_config.5 -@@ -976,10 +976,68 @@ The default is - Specifies whether user authentication based on GSSAPI is allowed. - The default is - .Cm no . -+.It Cm GSSAPIClientIdentity -+If set, specifies the GSSAPI client identity that ssh should use when -+connecting to the server. The default is unset, which means that the default -+identity will be used. - .It Cm GSSAPIDelegateCredentials - Forward (delegate) credentials to the server. - The default is - .Cm no . -+.It Cm GSSAPIKeyExchange -+Specifies whether key exchange based on GSSAPI may be used. When using -+GSSAPI key exchange the server need not have a host key. -+The default is -+.Dq no . -+.It Cm GSSAPIRenewalForcesRekey -+If set to -+.Dq yes -+then renewal of the client's GSSAPI credentials will force the rekeying of the -+ssh connection. With a compatible server, this will delegate the renewed -+credentials to a session on the server. -+.Pp -+Checks are made to ensure that credentials are only propagated when the new -+credentials match the old ones on the originating client and where the -+receiving server still has the old set in its cache. -+.Pp -+The default is -+.Dq no . -+.Pp -+For this to work -+.Cm GSSAPIKeyExchange -+needs to be enabled in the server and also used by the client. -+.It Cm GSSAPIServerIdentity -+If set, specifies the GSSAPI server identity that ssh should expect when -+connecting to the server. The default is unset, which means that the -+expected GSSAPI server identity will be determined from the target -+hostname. -+.It Cm GSSAPITrustDns -+Set to -+.Dq yes -+to indicate that the DNS is trusted to securely canonicalize -+the name of the host being connected to. If -+.Dq no , -+the hostname entered on the -+command line will be passed untouched to the GSSAPI library. -+The default is -+.Dq no . -+.It Cm GSSAPIKexAlgorithms -+The list of key exchange algorithms that are offered for GSSAPI -+key exchange. Possible values are -+.Bd -literal -offset 3n -+gss-gex-sha1-, -+gss-group1-sha1-, -+gss-group14-sha1-, -+gss-group14-sha256-, -+gss-group16-sha512-, -+gss-nistp256-sha256-, -+gss-curve25519-sha256- -+.Ed -+.Pp -+The default is -+.Dq gss-group14-sha256-,gss-group16-sha512-,gss-nistp256-sha256-, -+gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- . -+This option only applies to connections using GSSAPI. - .It Cm HashKnownHosts - Indicates that - .Xr ssh 1 -diff --git a/sshconnect2.c b/sshconnect2.c -index b3679c9d7..b253f991b 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; - int r, use_known_hosts_order = 0; - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ char *orig = NULL, *gss = NULL; -+ char *gss_host = NULL; -+#endif -+ - 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), - hkalgs ? hkalgs : options.hostkeyalgorithms); - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ if (options.gss_keyex) { -+ /* Add the GSSAPI mechanisms currently supported on this -+ * client to the key exchange algorithm proposal */ -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ if (options.gss_server_identity) { -+ gss_host = xstrdup(options.gss_server_identity); -+ } else if (options.gss_trust_dns) { -+ gss_host = remote_hostname(ssh); -+ /* Fall back to specified host if we are using proxy command -+ * and can not use DNS on that socket */ -+ if (strcmp(gss_host, "UNKNOWN") == 0) { -+ free(gss_host); -+ gss_host = xstrdup(host); -+ } -+ } else { -+ gss_host = xstrdup(host); -+ } -+ -+ gss = ssh_gssapi_client_mechanisms(gss_host, -+ options.gss_client_identity, options.gss_kex_algorithms); -+ if (gss) { -+ debug("Offering GSSAPI proposal: %s", gss); -+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ -+ /* If we've got GSSAPI algorithms, then we also support the -+ * 'null' hostkey, as a last resort */ -+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; -+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], -+ "%s,null", orig); -+ } -+ } -+#endif -+ - free(hkalgs); - - /* start key exchange */ -@@ -271,15 +312,45 @@ 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 --#endif -+# ifdef GSSAPI -+ if (options.gss_keyex) { -+ ssh->kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_client; -+ ssh->kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_client; -+ ssh->kex->kex[KEX_GSS_C25519_SHA256] = kexgss_client; -+ } -+# endif -+#endif /* WITH_OPENSSL */ - ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; - ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; - ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client; - ssh->kex->verify_host_key=&verify_host_key_callback; - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ if (options.gss_keyex) { -+ ssh->kex->gss_deleg_creds = options.gss_deleg_creds; -+ ssh->kex->gss_trust_dns = options.gss_trust_dns; -+ ssh->kex->gss_client = options.gss_client_identity; -+ ssh->kex->gss_host = gss_host; -+ } -+#endif -+ - ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); - kex_proposal_free_entries(myproposal); - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ /* repair myproposal after it was crumpled by the */ -+ /* ext-info removal above */ -+ if (gss) { -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ 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 *); - 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 *); -+static int userauth_gsskeyex(struct ssh *); +diff --color -ruNp a/sshkey.c b/sshkey.c +--- a/sshkey.c 2024-07-01 06:36:28.000000000 +0200 ++++ b/sshkey.c 2024-09-16 11:46:34.706940139 +0200 +@@ -131,6 +131,75 @@ extern const struct sshkey_impl sshkey_x + extern const struct sshkey_impl sshkey_xmss_cert_impl; #endif - void userauth(struct ssh *, char *); -@@ -385,6 +457,11 @@ static char *authmethods_get(void); - - Authmethod authmethods[] = { - #ifdef GSSAPI -+ {"gssapi-keyex", -+ userauth_gsskeyex, -+ NULL, -+ &options.gss_keyex, -+ NULL}, - {"gssapi-with-mic", - userauth_gssapi, - userauth_gssapi_cleanup, -@@ -759,12 +836,32 @@ userauth_gssapi(struct ssh *ssh) - OM_uint32 min; - int r, ok = 0; - gss_OID mech = NULL; -+ char *gss_host = NULL; -+ -+ 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(authctxt->host); -+ } -+ } else { -+ gss_host = xstrdup(authctxt->host); -+ } - - /* Try one GSSAPI method at a time, rather than sending them all at - * once. */ - - if (authctxt->gss_supported_mechs == NULL) -- gss_indicate_mechs(&min, &authctxt->gss_supported_mechs); -+ if (GSS_ERROR(gss_indicate_mechs(&min, -+ &authctxt->gss_supported_mechs))) { -+ authctxt->gss_supported_mechs = NULL; -+ free(gss_host); -+ return 0; -+ } - - /* 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) - elements[authctxt->mech_tried]; - /* My DER encoding requires length<128 */ - if (mech->length < 128 && ssh_gssapi_check_mechanism(&gssctxt, -- mech, authctxt->host)) { -+ mech, gss_host, options.gss_client_identity)) { - ok = 1; /* Mechanism works */ - } else { - authctxt->mech_tried++; - } - } - -+ free(gss_host); -+ - if (!ok || mech == NULL) - return 0; - -@@ -1013,6 +1112,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) - free(lang); - return r; - } -+ -+int -+userauth_gsskeyex(struct ssh *ssh) -+{ -+ struct sshbuf *b = NULL; -+ Authctxt *authctxt = ssh->authctxt; -+ gss_buffer_desc gssbuf; -+ gss_buffer_desc mic = GSS_C_EMPTY_BUFFER; -+ OM_uint32 ms; -+ int r; -+ -+ static int attempt = 0; -+ if (attempt++ >= 1) -+ return (0); -+ -+ if (gss_kex_context == NULL) { -+ debug("No valid Key exchange context"); -+ return (0); -+ } -+ -+ if ((b = sshbuf_new()) == NULL) -+ fatal_f("sshbuf_new failed"); -+ -+ ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service, -+ "gssapi-keyex", ssh->kex->session_id); -+ -+ if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) -+ fatal_f("sshbuf_mutable_ptr failed"); -+ gssbuf.length = sshbuf_len(b); -+ -+ if (GSS_ERROR(ssh_gssapi_sign(gss_kex_context, &gssbuf, &mic))) { -+ sshbuf_free(b); -+ return (0); -+ } -+ -+ if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || -+ (r = sshpkt_put_cstring(ssh, authctxt->server_user)) != 0 || -+ (r = sshpkt_put_cstring(ssh, authctxt->service)) != 0 || -+ (r = sshpkt_put_cstring(ssh, authctxt->method->name)) != 0 || -+ (r = sshpkt_put_string(ssh, mic.value, mic.length)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal_fr(r, "parsing"); -+ -+ sshbuf_free(b); -+ gss_release_buffer(&ms, &mic); -+ -+ return (1); -+} -+ - #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; - } - } -- 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) - - free(hkalgs); - -+#if defined(GSSAPI) && defined(WITH_OPENSSL) -+ { -+ char *orig; -+ char *gss = NULL; -+ char *newstr = NULL; -+ orig = myproposal[PROPOSAL_KEX_ALGS]; -+ -+ /* -+ * If we don't have a host key, then there's no point advertising -+ * the other key exchange algorithms -+ */ -+ -+ if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) -+ orig = NULL; -+ -+ if (options.gss_keyex) -+ gss = ssh_gssapi_server_mechanisms(); -+ else -+ gss = NULL; -+ -+ if (gss && orig) -+ xasprintf(&newstr, "%s,%s", gss, orig); -+ else if (gss) -+ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com"); -+ else if (orig) -+ newstr = orig; -+ -+ /* -+ * If we've got GSSAPI mechanisms, then we've got the 'null' host -+ * key alg, but we can't tell people about it unless its the only -+ * host key algorithm we support -+ */ -+ if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) -+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xstrdup("null"); -+ -+ if (newstr) -+ myproposal[PROPOSAL_KEX_ALGS] = newstr; -+ else -+ fatal("No supported key exchange algorithms"); -+ } -+#endif -+ - /* start key exchange */ - if ((r = kex_setup(ssh, myproposal)) != 0) - fatal_r(r, "kex_setup"); -@@ -836,6 +878,17 @@ do_ssh2_kex(struct ssh *ssh) - # ifdef OPENSSL_HAS_ECC - kex->kex[KEX_ECDH_SHA2] = kex_gen_server; - # endif /* OPENSSL_HAS_ECC */ -+# ifdef GSSAPI -+ if (options.gss_keyex) { -+ kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; -+ kex->kex[KEX_GSS_GRP14_SHA256] = kexgss_server; -+ kex->kex[KEX_GSS_GRP16_SHA512] = kexgss_server; -+ kex->kex[KEX_GSS_GEX_SHA1] = kexgssgex_server; -+ kex->kex[KEX_GSS_NISTP256_SHA256] = kexgss_server; -+ kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server; -+ } -+# endif - #endif /* WITH_OPENSSL */ - kex->kex[KEX_C25519_SHA256] = kex_gen_server; - kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; -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); - } -diff --git a/sshd_config b/sshd_config -index 48af6321b..8db9f0fb1 100644 ---- a/sshd_config -+++ b/sshd_config -@@ -79,6 +79,8 @@ AuthorizedKeysFile .ssh/authorized_keys - # GSSAPI options - #GSSAPIAuthentication no - #GSSAPICleanupCredentials yes -+#GSSAPIStrictAcceptorCheck yes -+#GSSAPIKeyExchange 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 aa9f0af76..b90068bf3 100644 ---- a/sshd_config.5 -+++ b/sshd_config.5 -@@ -739,6 +739,11 @@ Specifies whether to automatically destroy the user's credentials cache - on logout. - The default is - .Cm yes . -+.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. -+The default is -+.Cm no . - .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. - This facility is provided to assist with operation on multi homed machines. - The default is - .Cm yes . -+.It Cm GSSAPIStoreCredentialsOnRekey -+Controls whether the user's GSSAPI credentials should be updated following a -+successful connection rekeying. This option can be used to accepted renewed -+or updated credentials from a compatible client. The default is -+.Dq no . -+.Pp -+For this to work -+.Cm GSSAPIKeyExchange -+needs to be enabled in the server and also used by the client. -+.It Cm GSSAPIKexAlgorithms -+The list of key exchange algorithms that are accepted by GSSAPI -+key exchange. Possible values are -+.Bd -literal -offset 3n -+gss-gex-sha1-, -+gss-group1-sha1-, -+gss-group14-sha1-, -+gss-group14-sha256-, -+gss-group16-sha512-, -+gss-nistp256-sha256-, -+gss-curve25519-sha256- -+.Ed -+.Pp -+The default is -+.Dq gss-group14-sha256-,gss-group16-sha512-,gss-nistp256-sha256-, -+gss-curve25519-sha256-,gss-group14-sha1-,gss-gex-sha1- . -+This option only applies to connections using GSSAPI. - .It Cm HostbasedAcceptedAlgorithms - Specifies the signature algorithms that will be accepted for hostbased - authentication as a list of comma-separated patterns. -diff --git a/sshkey.c b/sshkey.c -index afd7822c4..148fee2b7 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 */ - +static int ssh_gss_equal(const struct sshkey *, const struct sshkey *) +{ + return SSH_ERR_FEATURE_UNSUPPORTED; @@ -4288,15 +4170,15 @@ index afd7822c4..148fee2b7 100644 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 */ +@@ -169,6 +238,7 @@ const struct sshkey_impl * const keyimpl + &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) +@@ -324,7 +394,7 @@ sshkey_alg_list(int certs_only, int plai for (i = 0; keyimpls[i] != NULL; i++) { impl = keyimpls[i]; @@ -4305,11 +4187,10 @@ index afd7822c4..148fee2b7 100644 continue; if (!include_sigonly && impl->sigonly) continue; -diff --git a/sshkey.h b/sshkey.h -index c3262b896..931d1f79b 100644 ---- a/sshkey.h -+++ b/sshkey.h -@@ -67,6 +67,7 @@ enum sshkey_types { +diff --color -ruNp a/sshkey.h b/sshkey.h +--- a/sshkey.h 2024-07-01 06:36:28.000000000 +0200 ++++ b/sshkey.h 2024-09-16 11:46:34.706940139 +0200 +@@ -71,6 +71,7 @@ enum sshkey_types { KEY_ECDSA_SK_CERT, KEY_ED25519_SK, KEY_ED25519_SK_CERT, @@ -4317,6 +4198,3 @@ index c3262b896..931d1f79b 100644 KEY_UNSPEC }; --- -2.52.0 - diff --git a/openssh-9.6p1-pam-rhost.patch b/openssh-9.6p1-pam-rhost.patch new file mode 100644 index 0000000..b1b0d04 --- /dev/null +++ b/openssh-9.6p1-pam-rhost.patch @@ -0,0 +1,32 @@ +From 26f366e263e575c4e1a18e2e64ba418f58878b37 Mon Sep 17 00:00:00 2001 +From: Daan De Meyer +Date: Mon, 20 Mar 2023 20:22:14 +0100 +Subject: [PATCH] Only set PAM_RHOST if the remote host is not "UNKNOWN" + +When using sshd's -i option with stdio that is not a AF_INET/AF_INET6 +socket, auth_get_canonical_hostname() returns "UNKNOWN" which is then +set as the value of PAM_RHOST, causing pam to try to do a reverse DNS +query of "UNKNOWN", which times out multiple times, causing a +substantial slowdown when logging in. + +To fix this, let's only set PAM_RHOST if the hostname is not "UNKNOWN". +--- + auth-pam.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/auth-pam.c b/auth-pam.c +index e143304e3..39b4e4563 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -735,7 +735,7 @@ sshpam_init(struct ssh *ssh, Authctxt *authctxt) + sshpam_laddr = get_local_ipaddr( + ssh_packet_get_connection_in(ssh)); + } +- if (sshpam_rhost != NULL) { ++ if (sshpam_rhost != NULL && strcmp(sshpam_rhost, "UNKNOWN") != 0) { + debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost); + sshpam_err = pam_set_item(sshpam_handle, PAM_RHOST, + sshpam_rhost); +-- +2.44.0 + diff --git a/openssh-9.9p1-disable-forwarding.patch b/openssh-9.9p1-disable-forwarding.patch new file mode 100644 index 0000000..45a021e --- /dev/null +++ b/openssh-9.9p1-disable-forwarding.patch @@ -0,0 +1,22 @@ +diff --color -ruNp a/session.c b/session.c +--- a/session.c 2025-04-29 11:20:59.475107377 +0200 ++++ b/session.c 2025-04-29 11:23:16.638538968 +0200 +@@ -2284,7 +2284,8 @@ session_auth_agent_req(struct ssh *ssh, + if ((r = sshpkt_get_end(ssh)) != 0) + sshpkt_fatal(ssh, r, "%s: parse packet", __func__); + if (!auth_opts->permit_agent_forwarding_flag || +- !options.allow_agent_forwarding) { ++ !options.allow_agent_forwarding || ++ options.disable_forwarding) { + debug_f("agent forwarding disabled"); + return 0; + } +@@ -2709,7 +2710,7 @@ session_setup_x11fwd(struct ssh *ssh, Se + ssh_packet_send_debug(ssh, "X11 forwarding disabled by key options."); + return 0; + } +- if (!options.x11_forwarding) { ++ if (!options.x11_forwarding || options.disable_forwarding) { + debug("X11 forwarding disabled in server configuration file."); + return 0; + } diff --git a/openssh-9.9p1-match-regression.patch b/openssh-9.9p1-match-regression.patch new file mode 100644 index 0000000..73ea964 --- /dev/null +++ b/openssh-9.9p1-match-regression.patch @@ -0,0 +1,471 @@ +diff --git a/misc.c b/misc.c +index afdf5142..1b4b55c5 100644 +--- a/misc.c ++++ b/misc.c +@@ -107,6 +107,27 @@ rtrim(char *s) + } + } + ++/* ++ * returns pointer to character after 'prefix' in 's' or otherwise NULL ++ * if the prefix is not present. ++ */ ++const char * ++strprefix(const char *s, const char *prefix, int ignorecase) ++{ ++ size_t prefixlen; ++ ++ if ((prefixlen = strlen(prefix)) == 0) ++ return s; ++ if (ignorecase) { ++ if (strncasecmp(s, prefix, prefixlen) != 0) ++ return NULL; ++ } else { ++ if (strncmp(s, prefix, prefixlen) != 0) ++ return NULL; ++ } ++ return s + prefixlen; ++} ++ + /* set/unset filedescriptor to non-blocking */ + int + set_nonblock(int fd) +diff --git a/misc.h b/misc.h +index 11340389..efecdf1a 100644 +--- a/misc.h ++++ b/misc.h +@@ -56,6 +56,7 @@ struct ForwardOptions { + char *chop(char *); + void rtrim(char *); + void skip_space(char **); ++const char *strprefix(const char *, const char *, int); + char *strdelim(char **); + char *strdelimw(char **); + int set_nonblock(int); +diff --git a/readconf.c b/readconf.c +index 3d9cc6db..9f559269 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -710,7 +710,7 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + struct passwd *pw, const char *host_arg, const char *original_host, + int final_pass, int *want_final_pass, const char *filename, int linenum) + { +- char *arg, *oattrib, *attrib, *cmd, *host, *criteria; ++ char *arg, *oattrib = NULL, *attrib = NULL, *cmd, *host, *criteria; + const char *ruser; + int r, this_result, result = 1, attributes = 0, negate; + +@@ -731,7 +731,8 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + + debug2("checking match for '%s' host %s originally %s", + full_line, host, original_host); +- while ((oattrib = attrib = argv_next(acp, avp)) != NULL) { ++ while ((attrib = argv_next(acp, avp)) != NULL) { ++ attrib = oattrib = xstrdup(attrib); + /* Terminate on comment */ + if (*attrib == '#') { + argv_consume(acp); +@@ -777,9 +778,23 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + this_result ? "" : "not ", oattrib); + continue; + } ++ ++ /* Keep this list in sync with below */ ++ if (strprefix(attrib, "host=", 1) != NULL || ++ strprefix(attrib, "originalhost=", 1) != NULL || ++ strprefix(attrib, "user=", 1) != NULL || ++ strprefix(attrib, "localuser=", 1) != NULL || ++ strprefix(attrib, "localnetwork=", 1) != NULL || ++ strprefix(attrib, "tagged=", 1) != NULL || ++ strprefix(attrib, "exec=", 1) != NULL) { ++ arg = strchr(attrib, '='); ++ *(arg++) = '\0'; ++ } else { ++ arg = argv_next(acp, avp); ++ } ++ + /* All other criteria require an argument */ +- if ((arg = argv_next(acp, avp)) == NULL || +- *arg == '\0' || *arg == '#') { ++ if (arg == NULL || *arg == '\0' || *arg == '#') { + error("Missing Match criteria for %s", attrib); + result = -1; + goto out; +@@ -856,6 +871,8 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + criteria == NULL ? "" : criteria, + criteria == NULL ? "" : "\""); + free(criteria); ++ free(oattrib); ++ oattrib = attrib = NULL; + } + if (attributes == 0) { + error("One or more attributes required for Match"); +@@ -865,6 +882,7 @@ match_cfg_line(Options *options, const char *full_line, int *acp, char ***avp, + out: + if (result != -1) + debug2("match %sfound", result ? "" : "not "); ++ free(oattrib); + free(host); + return result; + } +diff --git a/servconf.c b/servconf.c +index 89b8413e..dd774f46 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -1,4 +1,4 @@ +-/* $OpenBSD: servconf.c,v 1.418 2024/09/15 03:09:44 djm Exp $ */ ++/* $OpenBSD: servconf.c,v 1.419 2024/09/25 01:24:04 djm Exp $ */ + /* + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved +@@ -1033,7 +1033,7 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + int line, struct connection_info *ci) + { + int result = 1, attributes = 0, port; +- char *arg, *attrib; ++ char *arg, *attrib = NULL, *oattrib; + + if (ci == NULL) + debug3("checking syntax for 'Match %s'", full_line); +@@ -1047,7 +1047,8 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + ci->laddress ? ci->laddress : "(null)", ci->lport); + } + +- while ((attrib = argv_next(acp, avp)) != NULL) { ++ while ((oattrib = argv_next(acp, avp)) != NULL) { ++ attrib = xstrdup(oattrib); + /* Terminate on comment */ + if (*attrib == '#') { + argv_consume(acp); /* mark all arguments consumed */ +@@ -1062,16 +1063,20 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + *arg != '\0' && *arg != '#')) { + error("'all' cannot be combined with other " + "Match attributes"); +- return -1; ++ result = -1; ++ goto out; + } + if (arg != NULL && *arg == '#') + argv_consume(acp); /* consume remaining args */ +- return 1; ++ result = 1; ++ goto out; + } + /* Criterion "invalid-user" also has no argument */ + if (strcasecmp(attrib, "invalid-user") == 0) { +- if (ci == NULL) ++ if (ci == NULL) { ++ result = 0; + continue; ++ } + if (ci->user_invalid == 0) + result = 0; + else +@@ -1078,11 +1081,26 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + debug("matched invalid-user at line %d", line); + continue; + } ++ ++ /* Keep this list in sync with below */ ++ if (strprefix(attrib, "user=", 1) != NULL || ++ strprefix(attrib, "group=", 1) != NULL || ++ strprefix(attrib, "host=", 1) != NULL || ++ strprefix(attrib, "address=", 1) != NULL || ++ strprefix(attrib, "localaddress=", 1) != NULL || ++ strprefix(attrib, "localport=", 1) != NULL || ++ strprefix(attrib, "rdomain=", 1) != NULL) { ++ arg = strchr(attrib, '='); ++ *(arg++) = '\0'; ++ } else { ++ arg = argv_next(acp, avp); ++ } ++ + /* All other criteria require an argument */ +- if ((arg = argv_next(acp, avp)) == NULL || +- *arg == '\0' || *arg == '#') { ++ if (arg == NULL || *arg == '\0' || *arg == '#') { + error("Missing Match criteria for %s", attrib); +- return -1; ++ result = -1; ++ goto out; + } + if (strcasecmp(attrib, "user") == 0) { + if (ci == NULL || (ci->test && ci->user == NULL)) { +@@ -1105,7 +1123,8 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + match_test_missing_fatal("Group", "user"); + switch (match_cfg_line_group(arg, line, ci->user)) { + case -1: +- return -1; ++ result = -1; ++ goto out; + case 0: + result = 0; + } +@@ -1141,7 +1160,8 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + result = 0; + break; + case -2: +- return -1; ++ result = -1; ++ goto out; + } + } else if (strcasecmp(attrib, "localaddress") == 0){ + if (ci == NULL || (ci->test && ci->laddress == NULL)) { +@@ -1166,13 +1186,15 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + result = 0; + break; + case -2: +- return -1; ++ result = -1; ++ goto out; + } + } else if (strcasecmp(attrib, "localport") == 0) { + if ((port = a2port(arg)) == -1) { + error("Invalid LocalPort '%s' on Match line", + arg); +- return -1; ++ result = -1; ++ goto out; + } + if (ci == NULL || (ci->test && ci->lport == -1)) { + result = 0; +@@ -1200,16 +1222,21 @@ match_cfg_line(const char *full_line, int *acp, char ***avp, + debug("user %.100s matched 'RDomain %.100s' at " + "line %d", ci->rdomain, arg, line); + } else { +- error("Unsupported Match attribute %s", attrib); +- return -1; ++ error("Unsupported Match attribute %s", oattrib); ++ result = -1; ++ goto out; + } ++ free(attrib); ++ attrib = NULL; + } + if (attributes == 0) { + error("One or more attributes required for Match"); + return -1; + } +- if (ci != NULL) ++ out: ++ if (ci != NULL && result != -1) + debug3("match %sfound", result ? "" : "not "); ++ free(attrib); + return result; + } + +diff --git a/regress/cfginclude.sh b/regress/cfginclude.sh +index d442cdd6..97fd816f 100644 +--- a/regress/cfginclude.sh ++++ b/regress/cfginclude.sh +@@ -1,4 +1,4 @@ +-# $OpenBSD: cfginclude.sh,v 1.4 2024/09/03 05:58:56 djm Exp $ ++# $OpenBSD: cfginclude.sh,v 1.5 2024/09/27 01:05:54 djm Exp $ + # Placed in the Public Domain. + + tid="config include" +@@ -10,7 +10,7 @@ cat > $OBJ/ssh_config.i << _EOF + Match host a + Hostname aa + +-Match host b # comment ++Match host=b # comment + Hostname bb + Include $OBJ/ssh_config.i.* + +@@ -18,7 +18,7 @@ Match host c + Include $OBJ/ssh_config.i.* + Hostname cc + +-Match host m ++Match host=m !user xxxyfake + Include $OBJ/ssh_config.i.* # comment + + Host d +@@ -41,7 +41,7 @@ Match host xxxxxx + _EOF + + cat > $OBJ/ssh_config.i.1 << _EOF +-Match host a ++Match host=a + Hostname aaa + + Match host b +@@ -64,10 +64,10 @@ cat > $OBJ/ssh_config.i.2 << _EOF + Match host a + Hostname aaaa + +-Match host b ++Match host=b !user blahblahfake + Hostname bbbb + +-Match host c ++Match host=c + Hostname cccc + + Host d +@@ -142,7 +142,7 @@ trial a aa + + # cleanup + rm -f $OBJ/ssh_config.i $OBJ/ssh_config.i.* $OBJ/ssh_config.out +-# $OpenBSD: cfginclude.sh,v 1.4 2024/09/03 05:58:56 djm Exp $ ++# $OpenBSD: cfginclude.sh,v 1.5 2024/09/27 01:05:54 djm Exp $ + # Placed in the Public Domain. + + tid="config include" +diff --git a/regress/cfgmatch.sh b/regress/cfgmatch.sh +index 05a66685..2737a5f9 100644 +--- a/regress/cfgmatch.sh ++++ b/regress/cfgmatch.sh +@@ -1,4 +1,4 @@ +-# $OpenBSD: cfgmatch.sh,v 1.13 2021/06/08 06:52:43 djm Exp $ ++# $OpenBSD: cfgmatch.sh,v 1.14 2024/09/27 01:05:54 djm Exp $ + # Placed in the Public Domain. + + tid="sshd_config match" +@@ -26,7 +26,7 @@ start_client() + kill $client_pid + fatal "timeout waiting for background ssh" + fi +- done ++ done + } + + stop_client() +@@ -119,40 +119,42 @@ stop_client + # requires knowledge of actual group memberships user running the test). + params="user:user:u1 host:host:h1 address:addr:1.2.3.4 \ + localaddress:laddr:5.6.7.8 rdomain:rdomain:rdom1" +-cp $OBJ/sshd_proxy_bak $OBJ/sshd_config +-echo 'Banner /nomatch' >>$OBJ/sshd_config +-for i in $params; do +- config=`echo $i | cut -f1 -d:` +- criteria=`echo $i | cut -f2 -d:` +- value=`echo $i | cut -f3 -d:` +- cat >>$OBJ/sshd_config </dev/null || \ ++ fail "validate config for w/out spec" ++ ++ # Test matching each criteria. ++ for i in $params; do ++ testcriteria=`echo $i | cut -f2 -d:` ++ expected=/`echo $i | cut -f3 -d:` ++ spec="" ++ for j in $params; do ++ config=`echo $j | cut -f1 -d:` ++ criteria=`echo $j | cut -f2 -d:` ++ value=`echo $j | cut -f3 -d:` ++ if [ "$criteria" = "$testcriteria" ]; then ++ spec="$criteria=$value,$spec" ++ else ++ spec="$criteria=1$value,$spec" ++ fi ++ done ++ trace "test spec $spec" ++ result=`${SUDO} ${SSHD} -f $OBJ/sshd_config -T -C "$spec" | \ ++ awk '$1=="banner"{print $2}'` ++ if [ "$result" != "$expected" ]; then ++ fail "match $config expected $expected got $result" + fi + done +- trace "test spec $spec" +- result=`${SUDO} ${SSHD} -f $OBJ/sshd_config -T -C "$spec" | \ +- awk '$1=="banner"{print $2}'` +- if [ "$result" != "$expected" ]; then +- fail "match $config expected $expected got $result" +- fi + done +diff --git a/regress/servcfginclude.sh b/regress/servcfginclude.sh +index 518a703d..f67c3caa 100644 +--- a/regress/servcfginclude.sh ++++ b/regress/servcfginclude.sh +@@ -4,14 +4,14 @@ tid="server config include" + + cat > $OBJ/sshd_config.i << _EOF + HostKey $OBJ/host.ssh-ed25519 +-Match host a ++Match host=a + Banner /aa + + Match host b + Banner /bb + Include $OBJ/sshd_config.i.* # comment + +-Match host c ++Match host=c + Include $OBJ/sshd_config.i.* # comment + Banner /cc + +@@ -25,7 +25,7 @@ Match Host e + Banner /ee + Include $OBJ/sshd_config.i.* + +-Match Host f ++Match Host=f + Include $OBJ/sshd_config.i.* + Banner /ff + +@@ -47,13 +47,13 @@ Match host b + Match host c + Banner /ccc + +-Match Host d ++Match Host=d + Banner /ddd + + Match Host e + Banner /eee + +-Match Host f ++Match Host=f + Banner /fff + _EOF + +@@ -61,13 +61,13 @@ cat > $OBJ/sshd_config.i.2 << _EOF + Match host a + Banner /aaaa + +-Match host b ++Match host=b + Banner /bbbb + + Match host c # comment + Banner /cccc + +-Match Host d ++Match Host=d + Banner /dddd + + Match Host e diff --git a/openssh-9.9p1-mlkembe.patch b/openssh-9.9p1-mlkembe.patch new file mode 100644 index 0000000..aa0c26c --- /dev/null +++ b/openssh-9.9p1-mlkembe.patch @@ -0,0 +1,98 @@ +diff --git a/kexmlkem768x25519.c b/kexmlkem768x25519.c +index 679446e9..2b5d3960 100644 +--- a/kexmlkem768x25519.c ++++ b/kexmlkem768x25519.c +@@ -1,4 +1,4 @@ +-/* $OpenBSD: kexmlkem768x25519.c,v 1.1 2024/09/02 12:13:56 djm Exp $ */ ++/* $OpenBSD: kexmlkem768x25519.c,v 1.2 2024/10/27 02:06:59 djm Exp $ */ + /* + * Copyright (c) 2023 Markus Friedl. All rights reserved. + * +@@ -34,6 +34,9 @@ + #include + #include + #include ++#ifdef HAVE_ENDIAN_H ++# include ++#endif + + #include "sshkey.h" + #include "kex.h" +diff --git a/libcrux_mlkem768_sha3.h b/libcrux_mlkem768_sha3.h +index a82d60e8..b8ac1436 100644 +--- a/libcrux_mlkem768_sha3.h ++++ b/libcrux_mlkem768_sha3.h +@@ -1,4 +1,5 @@ +-/* $OpenBSD: libcrux_mlkem768_sha3.h,v 1.1 2024/09/02 12:13:56 djm Exp $ */ ++/* $OpenBSD: libcrux_mlkem768_sha3.h,v 1.2 2024/10/27 02:06:01 djm Exp $ */ ++ + /* Extracted from libcrux revision 84c5d87b3092c59294345aa269ceefe0eb97cc35 */ + + /* +@@ -160,18 +161,19 @@ static inline void Eurydice_slice_to_array3(uint8_t *dst_tag, char *dst_ok, + // CORE STUFF (conversions, endianness, ...) + + static inline void core_num__u64_9__to_le_bytes(uint64_t v, uint8_t buf[8]) { ++ v = htole64(v); + memcpy(buf, &v, sizeof(v)); + } + static inline uint64_t core_num__u64_9__from_le_bytes(uint8_t buf[8]) { + uint64_t v; + memcpy(&v, buf, sizeof(v)); +- return v; ++ return le64toh(v); + } + + static inline uint32_t core_num__u32_8__from_le_bytes(uint8_t buf[4]) { + uint32_t v; + memcpy(&v, buf, sizeof(v)); +- return v; ++ return le32toh(v); + } + + static inline uint32_t core_num__u8_6__count_ones(uint8_t x0) { +diff --git a/mlkem768.sh b/mlkem768.sh +index 2fdc2831..3d12b2ed 100644 +--- a/mlkem768.sh ++++ b/mlkem768.sh +@@ -1,9 +1,10 @@ + #!/bin/sh +-# $OpenBSD: mlkem768.sh,v 1.2 2024/09/04 05:11:33 djm Exp $ ++# $OpenBSD: mlkem768.sh,v 1.3 2024/10/27 02:06:01 djm Exp $ + # Placed in the Public Domain. + # + +-WANT_LIBCRUX_REVISION="origin/main" ++#WANT_LIBCRUX_REVISION="origin/main" ++WANT_LIBCRUX_REVISION="84c5d87b3092c59294345aa269ceefe0eb97cc35" + + FILES=" + libcrux/libcrux-ml-kem/cg/eurydice_glue.h +@@ -47,6 +48,7 @@ echo '#define KRML_NOINLINE __attribute__((noinline, unused))' + echo '#define KRML_HOST_EPRINTF(...)' + echo '#define KRML_HOST_EXIT(x) fatal_f("internal error")' + echo ++ + for i in $FILES; do + echo "/* from $i */" + # Changes to all files: +@@ -56,11 +58,16 @@ for i in $FILES; do + -e 's/[ ]*$//' \ + $i | \ + case "$i" in +- # XXX per-file handling goes here. ++ */libcrux-ml-kem/cg/eurydice_glue.h) ++ # Replace endian functions with versions that work. ++ perl -0777 -pe 's/(static inline void core_num__u64_9__to_le_bytes.*\n)([^}]*\n)/\1 v = htole64(v);\n\2/' | ++ perl -0777 -pe 's/(static inline uint64_t core_num__u64_9__from_le_bytes.*?)return v;/\1return le64toh(v);/s' | ++ perl -0777 -pe 's/(static inline uint32_t core_num__u32_8__from_le_bytes.*?)return v;/\1return le32toh(v);/s' ++ ;; + # Default: pass through. + *) +- cat +- ;; ++ cat ++ ;; + esac + echo + done diff --git a/openssh-9.9p1-reject-cntrl-chars-in-username.patch b/openssh-9.9p1-reject-cntrl-chars-in-username.patch new file mode 100644 index 0000000..05bbe4d --- /dev/null +++ b/openssh-9.9p1-reject-cntrl-chars-in-username.patch @@ -0,0 +1,59 @@ +diff --color -ruNp a/ssh.c b/ssh.c +--- a/ssh.c 2025-12-03 15:22:36.754555231 +0100 ++++ b/ssh.c 2025-12-03 16:12:16.715320349 +0100 +@@ -662,6 +662,8 @@ valid_ruser(const char *s) + if (*s == '-') + return 0; + for (i = 0; s[i] != 0; i++) { ++ if (iscntrl((u_char)s[i])) ++ return 0; + if (strchr("'`\";&<>|(){}", s[i]) != NULL) + return 0; + /* Disallow '-' after whitespace */ +@@ -683,6 +685,7 @@ main(int ac, char **av) + struct ssh *ssh = NULL; + int i, r, opt, exit_status, use_syslog, direct, timeout_ms; + int was_addr, config_test = 0, opt_terminated = 0, want_final_pass = 0; ++ int user_on_commandline = 0; + char *p, *cp, *line, *argv0, *logfile; + char cname[NI_MAXHOST], thishost[NI_MAXHOST]; + struct stat st; +@@ -1039,8 +1042,10 @@ main(int ac, char **av) + } + break; + case 'l': +- if (options.user == NULL) ++ if (options.user == NULL) { + options.user = optarg; ++ user_on_commandline = 1; ++ } + break; + + case 'L': +@@ -1143,6 +1148,7 @@ main(int ac, char **av) + if (options.user == NULL) { + options.user = tuser; + tuser = NULL; ++ user_on_commandline = 1; + } + free(tuser); + if (options.port == -1 && tport != -1) +@@ -1157,6 +1163,7 @@ main(int ac, char **av) + if (options.user == NULL) { + options.user = p; + p = NULL; ++ user_on_commandline = 1; + } + *cp++ = '\0'; + host = xstrdup(cp); +@@ -1459,6 +1466,10 @@ main(int ac, char **av) + cinfo->locuser = xstrdup(pw->pw_name); + cinfo->jmphost = xstrdup(options.jump_host == NULL ? + "" : options.jump_host); ++ ++ if (user_on_commandline && !valid_ruser(options.user)) ++ fatal("remote username contains invalid characters"); ++ + cinfo->conn_hash_hex = ssh_connection_hash(cinfo->thishost, + cinfo->remhost, cinfo->portstr, cinfo->remuser, cinfo->jmphost); + diff --git a/openssh-9.9p1-reject-null-char-in-url-string.patch b/openssh-9.9p1-reject-null-char-in-url-string.patch new file mode 100644 index 0000000..9b2d378 --- /dev/null +++ b/openssh-9.9p1-reject-null-char-in-url-string.patch @@ -0,0 +1,24 @@ +diff --color -ruNp a/misc.c b/misc.c +--- a/misc.c 2025-12-03 16:19:11.255135131 +0100 ++++ b/misc.c 2025-12-03 16:21:53.769590836 +0100 +@@ -998,7 +998,7 @@ urldecode(const char *src) + size_t srclen; + + if ((srclen = strlen(src)) >= SIZE_MAX) +- fatal_f("input too large"); ++ return NULL; + ret = xmalloc(srclen + 1); + for (dst = ret; *src != '\0'; src++) { + switch (*src) { +@@ -1006,9 +1006,10 @@ urldecode(const char *src) + *dst++ = ' '; + break; + case '%': ++ /* note: don't allow \0 characters */ + if (!isxdigit((unsigned char)src[1]) || + !isxdigit((unsigned char)src[2]) || +- (ch = hexchar(src + 1)) == -1) { ++ (ch = hexchar(src + 1)) == -1 || ch == 0) { + free(ret); + return NULL; + } diff --git a/openssh-9.9p1-separate-keysign.patch b/openssh-9.9p1-separate-keysign.patch new file mode 100644 index 0000000..ff0e35f --- /dev/null +++ b/openssh-9.9p1-separate-keysign.patch @@ -0,0 +1,12 @@ +diff -up openssh-9.9p1/ssh_config.5.xxx openssh-9.9p1/ssh_config.5 +--- openssh-9.9p1/ssh_config.5.xxx 2024-10-11 12:01:14.260566303 +0200 ++++ openssh-9.9p1/ssh_config.5 2024-10-11 12:01:59.725654775 +0200 +@@ -759,7 +759,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 ~ ) . diff --git a/openssh-9.9p2-error_processing.patch b/openssh-9.9p2-error_processing.patch new file mode 100644 index 0000000..692c6ac --- /dev/null +++ b/openssh-9.9p2-error_processing.patch @@ -0,0 +1,152 @@ +diff --git a/krl.c b/krl.c +index e2efdf06..0d0f6953 100644 +--- a/krl.c ++++ b/krl.c +@@ -674,6 +674,7 @@ revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf) + break; + case KRL_SECTION_CERT_SERIAL_BITMAP: + if (rs->lo - bitmap_start > INT_MAX) { ++ r = SSH_ERR_INVALID_FORMAT; + error_f("insane bitmap gap"); + goto out; + } +@@ -1059,6 +1060,7 @@ ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp) + } + + if ((krl = ssh_krl_init()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; + error_f("alloc failed"); + goto out; + } +diff --git a/packet.c b/packet.c +index 486f8515..9dea2cfc 100644 +--- a/packet.c ++++ b/packet.c +@@ -1864,6 +1864,14 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) + if ((r = sshpkt_get_string_direct(ssh, &d, &len)) != 0) + return r; + DBG(debug("Received SSH2_MSG_PING len %zu", len)); ++ if (!ssh->state->after_authentication) { ++ DBG(debug("Won't reply to PING in preauth")); ++ break; ++ } ++ if (ssh_packet_is_rekeying(ssh)) { ++ DBG(debug("Won't reply to PING during KEX")); ++ break; ++ } + if ((r = sshpkt_start(ssh, SSH2_MSG_PONG)) != 0 || + (r = sshpkt_put_string(ssh, d, len)) != 0 || + (r = sshpkt_send(ssh)) != 0) +diff --git a/ssh-agent.c b/ssh-agent.c +index 48973b2c..c27c5a95 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c +@@ -1220,6 +1220,7 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp, + "restrict-destination-v00@openssh.com") == 0) { + if (*dcsp != NULL) { + error_f("%s already set", ext_name); ++ r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if ((r = sshbuf_froms(m, &b)) != 0) { +@@ -1229,6 +1230,7 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp, + while (sshbuf_len(b) != 0) { + if (*ndcsp >= AGENT_MAX_DEST_CONSTRAINTS) { + error_f("too many %s constraints", ext_name); ++ r = SSH_ERR_INVALID_FORMAT; + goto out; + } + *dcsp = xrecallocarray(*dcsp, *ndcsp, *ndcsp + 1, +@@ -1246,6 +1248,7 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp, + } + if (*certs != NULL) { + error_f("%s already set", ext_name); ++ r = SSH_ERR_INVALID_FORMAT; + goto out; + } + if ((r = sshbuf_get_u8(m, &v)) != 0 || +@@ -1257,6 +1260,7 @@ parse_key_constraint_extension(struct sshbuf *m, char **sk_providerp, + while (sshbuf_len(b) != 0) { + if (*ncerts >= AGENT_MAX_EXT_CERTS) { + error_f("too many %s constraints", ext_name); ++ r = SSH_ERR_INVALID_FORMAT; + goto out; + } + *certs = xrecallocarray(*certs, *ncerts, *ncerts + 1, +@@ -1757,6 +1761,7 @@ process_ext_session_bind(SocketEntry *e) + /* record new key/sid */ + if (e->nsession_ids >= AGENT_MAX_SESSION_IDS) { + error_f("too many session IDs recorded"); ++ r = -1; + goto out; + } + e->session_ids = xrecallocarray(e->session_ids, e->nsession_ids, +diff --git a/ssh-sk-client.c b/ssh-sk-client.c +index 321fe53a..06fad221 100644 +--- a/ssh-sk-client.c ++++ b/ssh-sk-client.c +@@ -439,6 +439,7 @@ sshsk_load_resident(const char *provider_path, const char *device, + } + if ((srk = calloc(1, sizeof(*srk))) == NULL) { + error_f("calloc failed"); ++ r = SSH_ERR_ALLOC_FAIL; + goto out; + } + srk->key = key; +@@ -450,6 +451,7 @@ sshsk_load_resident(const char *provider_path, const char *device, + if ((tmp = recallocarray(srks, nsrks, nsrks + 1, + sizeof(*srks))) == NULL) { + error_f("recallocarray keys failed"); ++ r = SSH_ERR_ALLOC_FAIL; + goto out; + } + debug_f("srks[%zu]: %s %s uidlen %zu", nsrks, +diff --git a/sshconnect2.c b/sshconnect2.c +index a69c4da1..1ee6000a 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -99,7 +99,7 @@ verify_host_key_callback(struct sshkey *hostkey, struct ssh *ssh) + options.required_rsa_size)) != 0) + fatal_r(r, "Bad server host key"); + if (verify_host_key(xxx_host, xxx_hostaddr, hostkey, +- xxx_conn_info) == -1) ++ xxx_conn_info) != 0) + fatal("Host key verification failed."); + return 0; + } +@@ -699,6 +699,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh) + + if ((pktype = sshkey_type_from_name(pkalg)) == KEY_UNSPEC) { + debug_f("server sent unknown pkalg %s", pkalg); ++ r = SSH_ERR_INVALID_FORMAT; + goto done; + } + if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { +@@ -709,6 +710,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh) + error("input_userauth_pk_ok: type mismatch " + "for decoded key (received %d, expected %d)", + key->type, pktype); ++ r = SSH_ERR_INVALID_FORMAT; + goto done; + } + +@@ -728,6 +730,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, struct ssh *ssh) + SSH_FP_DEFAULT); + error_f("server replied with unknown key: %s %s", + sshkey_type(key), fp == NULL ? "" : fp); ++ r = SSH_ERR_INVALID_FORMAT; + goto done; + } + ident = format_identity(id); +diff --git a/sshsig.c b/sshsig.c +index 6e03c0b0..3da005d6 100644 +--- a/sshsig.c ++++ b/sshsig.c +@@ -879,6 +879,7 @@ cert_filter_principals(const char *path, u_long linenum, + } + if ((principals = sshbuf_dup_string(nprincipals)) == NULL) { + error_f("buffer error"); ++ r = SSH_ERR_ALLOC_FAIL; + goto out; + } + /* success */ 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..956e169 100644 --- a/openssh.spec +++ b/openssh.spec @@ -38,12 +38,12 @@ # rpm -ba|--rebuild --define "static_openssl 1" %{?static_openssl:%global static_libcrypto 1} -%global openssh_ver 10.2p1 +%global openssh_ver 9.9p1 Summary: An open source implementation of SSH protocol version 2 Name: openssh Version: %{openssh_ver} -Release: 1%{?dist} +Release: 12%{?dist} URL: http://www.openssh.com/portable.html 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 @@ -65,120 +65,152 @@ 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 + #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-8.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-9.6p1-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 # 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 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-kex.patch +Patch1014: openssh-8.7p1-nohostsha1proof.patch + +Patch1015: openssh-9.6p1-pam-rhost.patch +Patch1016: openssh-9.9p1-separate-keysign.patch +# upstream cf3e48ee8ba1beeccddd2f203b558fa102be67a2 +# upstream 0c3927c45f8a57b511c874c4d51a8c89414f74ef +Patch1017: openssh-9.9p1-mlkembe.patch +# upstream 3f02368e8e9121847727c46b280efc280e5eb615 +# upstream 67a115e7a56dbdc3f5a58c64b29231151f3670f5 +Patch1020: openssh-9.9p1-match-regression.patch +# upstream 6ce00f0c2ecbb9f75023dbe627ee6460bcec78c2 +# upstream 0832aac79517611dd4de93ad0a83577994d9c907 +Patch1021: openssh-9.9p2-error_processing.patch +# upstream fc86875e6acb36401dfc1dfb6b628a9d1460f367 +Patch1022: openssh-9.9p1-disable-forwarding.patch +# upstream 35d5917652106aede47621bb3f64044604164043 +Patch1023: openssh-9.9p1-reject-cntrl-chars-in-username.patch +# upstream 43b3bff47bb029f2299bacb6a36057981b39fdb0 +Patch1024: openssh-9.9p1-reject-null-char-in-url-string.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,7 +225,7 @@ 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 @@ -297,7 +329,75 @@ This package contains a test SK driver used for OpenSSH test purposes %prep gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0} -%autosetup -T -b 0 -p1 +%setup -q + +%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 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 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 1014 -p1 -b .nosha1hostproof +%patch -P 1015 -p1 -b .pam-rhost +%patch -P 1016 -p1 -b .sep-keysign +%patch -P 1017 -p1 -b .mlkembe +%patch -P 1020 -p1 -b .match +%patch -P 1021 -p1 -b .errcode_set +%patch -P 1022 -p1 -b .disable-forwarding +%patch -P 1023 -p1 -b .reject-cntrl-chars-in-username +%patch -P 1024 -p1 -b .reject-null-char-in-url-string + +%patch -P 100 -p1 -b .coverity autoreconf @@ -344,6 +444,7 @@ fi --with-ipaddr-display \ --with-pie=no \ --without-hardening `# The hardening flags are configured by system` \ + --with-systemd \ --with-default-pkcs11-provider=yes \ --with-security-key-builtin=yes \ --with-pam \ @@ -393,7 +494,6 @@ popd %check OPENSSL_CONF=/dev/null %{SOURCE22} %{SOURCE23} # ./parallel_tests.sh parallel_tests.Makefile -#make tests %install rm -rf $RPM_BUILD_ROOT @@ -536,7 +636,6 @@ test -f %{sysconfig_anaconda} && \ %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* @@ -575,69 +674,19 @@ test -f %{sysconfig_anaconda} && \ %attr(0755,root,root) %{_libdir}/sshtest/sk-dummy.so %changelog -* Wed Dec 17 2025 Dmitry Belyavskiy - 10.2p1-1 -- Rebase to OpenSSH 10.2p1 +* Thu Jan 08 2026 Zoltan Fridrich - 9.9p1-12 +- CVE-2025-61984: Reject usernames with control characters + Resolves: rhbz#2402667 +- CVE-2025-61985: Reject URL-strings with NULL characters + Resolves: rhbz#2402670 -* Wed Dec 10 2025 Pavol Žáčik - 10.0p1-10 -- Update gssapi-keyex patch to not abort KEX without hostkey +* Mon May 19 2025 Zoltan Fridrich - 9.9p1-11 +- CVE-2025-32728: Fix logic error in DisableForwarding option + Resolves: rhbz#2358778 -* 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 +* Wed Mar 26 2025 Dmitry Belyavskiy - 9.9p1-10 +- Remove /usr/sbin and /usr/local/sbin from the default PATH + Resolves: rhbz#2354820 * Tue Feb 18 2025 Dmitry Belyavskiy - 9.9p1-9 - Fix regression of Match directive processing diff --git a/sources b/sources index 318e485..e88b6d9 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ -SHA512 (openssh-10.2p1.tar.gz) = 66f3dd646179e71aaf41c33b6f14a207dc873d71d24f11c130a89dee317ee45398b818e5b94887b5913240964a38630d7bca3e481e0f1eff2e41d9e1cfdbdfc5 -SHA512 (openssh-10.2p1.tar.gz.asc) = f1f71700b1b0b2117aed505488b98b7ebb51ce26e53184b08df0b07aa2c5a1e54dc4d3cbcbe871b5ad849a2a0e22b02af318ff22a68c980ab53b04be03c9bf3c +SHA512 (openssh-9.9p1.tar.gz) = 3cc0ed97f3e29ecbd882eca79239f02eb5a1606fce4f3119ddc3c5e86128aa3ff12dc85000879fccc87b60e7d651cfe37376607ac66075fede2118deaa685d6d +SHA512 (openssh-9.9p1.tar.gz.asc) = 916e975c54eb68c0b2f0b0006522b241cbe54c4caa88d31537a6278490c93d9d732c2ab3a080ac084bf75cbdd5402901ec68583cbe7c7cde4a8e40e7a8b78c28 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.sysconfig b/sshd.sysconfig index be40d08..ee44ae6 100644 --- a/sshd.sysconfig +++ b/sshd.sysconfig @@ -8,4 +8,3 @@ #SSH_RSA_BITS=3072 #SSH_ECDSA_BITS=256 -OPTIONS="" diff --git a/sshd@.service b/sshd@.service index 4f12190..c077be2 100644 --- a/sshd@.service +++ b/sshd@.service @@ -12,6 +12,5 @@ Wants=ssh-host-keys-migration.service # 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