diff --git a/openssh-7.8p1-role-mls.patch b/0001-openssh-7.8p1-role-mls.patch similarity index 78% rename from openssh-7.8p1-role-mls.patch rename to 0001-openssh-7.8p1-role-mls.patch index 4dc460a..c08e414 100644 --- a/openssh-7.8p1-role-mls.patch +++ b/0001-openssh-7.8p1-role-mls.patch @@ -1,57 +1,83 @@ -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; +From 95f4e30195382c3df7104c2ad3e5e9953f8ad554 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 01/50] 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 13c0a792..b4100ea1 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -1238,7 +1238,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 8d801c68..9dd7ae07 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 98bb23d4..83d07ae8 100644 +--- a/auth.h ++++ b/auth.h +@@ -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(); -@@ -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; - -@@ -296,8 +304,15 @@ input_userauth_request(int type, u_int32 - use_privsep ? " [net]" : ""); - authctxt->service = xstrdup(service); - authctxt->style = style ? xstrdup(style) : NULL; -- if (use_privsep) -+#ifdef WITH_SELINUX -+ authctxt->role = role ? xstrdup(role) : NULL; -+#endif -+ if (use_privsep) { - mm_inform_authserv(service, style); -+#ifdef WITH_SELINUX -+ mm_inform_authrole(role); -+#endif -+ } - userauth_banner(ssh); - if (auth2_setup_methods_lists(authctxt) != 0) - ssh_packet_disconnect(ssh, -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 + /* Method lists for multiple authentication */ + char **auth_methods; /* modified from server config */ +diff --git a/auth2-gss.c b/auth2-gss.c +index 75eb4e3a..f7898ab3 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) Authctxt *authctxt = ssh->authctxt; Gssctxt *gssctxt; int r, authenticated = 0; + char *micuser; struct sshbuf *b; gss_buffer_desc mic, gssbuf; - const char *displayname; -@@ -298,7 +299,13 @@ input_gssapi_mic(int type, u_int32_t ple + u_char *p; +@@ -300,7 +301,13 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) fatal_f("sshbuf_new failed"); mic.value = p; mic.length = len; @@ -66,7 +92,7 @@ diff -up openssh/auth2-gss.c.role-mls openssh/auth2-gss.c "gssapi-with-mic", ssh->kex->session_id); if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) -@@ -311,6 +318,8 @@ input_gssapi_mic(int type, u_int32_t ple +@@ -313,6 +320,8 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) logit("GSSAPI MIC check failed"); sshbuf_free(b); @@ -74,11 +100,12 @@ diff -up openssh/auth2-gss.c.role-mls openssh/auth2-gss.c + free(micuser); free(mic.value); - if ((!use_privsep || mm_is_monitor()) && -diff -up openssh/auth2-hostbased.c.role-mls openssh/auth2-hostbased.c ---- openssh/auth2-hostbased.c.role-mls 2018-08-20 07:57:29.000000000 +0200 -+++ openssh/auth2-hostbased.c 2018-08-22 11:14:56.816430924 +0200 -@@ -123,7 +123,16 @@ userauth_hostbased(struct ssh *ssh) + authctxt->postponed = 0; +diff --git a/auth2-hostbased.c b/auth2-hostbased.c +index eb21479a..a3be6e49 100644 +--- a/auth2-hostbased.c ++++ b/auth2-hostbased.c +@@ -129,7 +129,16 @@ userauth_hostbased(struct ssh *ssh, const char *method) /* reconstruct packet */ if ((r = sshbuf_put_stringb(b, ssh->kex->session_id)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || @@ -95,10 +122,11 @@ diff -up openssh/auth2-hostbased.c.role-mls openssh/auth2-hostbased.c (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || (r = sshbuf_put_cstring(b, method)) != 0 || (r = sshbuf_put_string(b, pkalg, alen)) != 0 || -diff -up openssh/auth2-pubkey.c.role-mls openssh/auth2-pubkey.c ---- openssh/auth2-pubkey.c.role-mls 2018-08-22 11:14:56.816430924 +0200 -+++ openssh/auth2-pubkey.c 2018-08-22 11:17:07.331483958 +0200 -@@ -169,9 +169,16 @@ userauth_pubkey(struct ssh *ssh) +diff --git a/auth2-pubkey.c b/auth2-pubkey.c +index aa24fda0..267a27d2 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -206,9 +206,16 @@ userauth_pubkey(struct ssh *ssh, const char *method) goto done; } /* reconstruct packet */ @@ -117,47 +145,51 @@ diff -up openssh/auth2-pubkey.c.role-mls openssh/auth2-pubkey.c 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 -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; +diff --git a/auth2.c b/auth2.c +index 82f6e621..5ba45c12 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; +#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 -up openssh/auth-pam.c.role-mls openssh/auth-pam.c ---- openssh/auth-pam.c.role-mls 2018-08-20 07:57:29.000000000 +0200 -+++ openssh/auth-pam.c 2018-08-22 11:14:56.816430924 +0200 -@@ -1172,7 +1172,7 @@ is_pam_session_open(void) - * during the ssh authentication process. - */ - int --do_pam_putenv(char *name, char *value) -+do_pam_putenv(char *name, const char *value) - { - int ret = 1; - char *compound; -diff -up openssh/auth-pam.h.role-mls openssh/auth-pam.h ---- openssh/auth-pam.h.role-mls 2018-08-20 07:57:29.000000000 +0200 -+++ openssh/auth-pam.h 2018-08-22 11:14:56.817430932 +0200 -@@ -33,7 +33,7 @@ u_int do_pam_account(void); - void do_pam_session(struct ssh *); - void do_pam_setcred(int ); - void do_pam_chauthtok(void); --int do_pam_putenv(char *, char *); -+int do_pam_putenv(char *, const char *); - char ** fetch_pam_environment(void); - char ** fetch_pam_child_environment(void); - void free_pam_environment(char **); -diff -up openssh/misc.c.role-mls openssh/misc.c ---- openssh/misc.c.role-mls 2018-08-20 07:57:29.000000000 +0200 -+++ openssh/misc.c 2018-08-22 11:14:56.817430932 +0200 -@@ -542,6 +542,7 @@ char * +@@ -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 dd0bd032..c932f9bb 100644 +--- a/misc.c ++++ b/misc.c +@@ -806,6 +806,7 @@ char * colon(char *cp) { int flag = 0; @@ -165,7 +197,7 @@ diff -up openssh/misc.c.role-mls openssh/misc.c if (*cp == ':') /* Leading colon is part of file name. */ return NULL; -@@ -557,6 +558,13 @@ colon(char *cp) +@@ -821,6 +822,13 @@ colon(char *cp) return (cp); if (*cp == '/') return NULL; @@ -179,10 +211,11 @@ diff -up openssh/misc.c.role-mls openssh/misc.c } return NULL; } -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 +diff --git a/monitor.c b/monitor.c +index 2179553d..02b3eaaa 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -120,6 +120,9 @@ int mm_answer_sign(struct ssh *, int, struct sshbuf *); 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 *); @@ -192,7 +225,7 @@ diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c 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 *); -@@ -195,6 +198,9 @@ struct mon_table mon_dispatch_proto20[] +@@ -194,6 +197,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}, @@ -202,7 +235,7 @@ diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, #ifdef USE_PAM -@@ -803,6 +809,9 @@ mm_answer_pwnamallow(struct ssh *ssh, in +@@ -912,6 +918,9 @@ mm_answer_pwnamallow(struct ssh *ssh, int sock, struct sshbuf *m) /* Allow service/style information on the auth context */ monitor_permit(mon_dispatch, MONITOR_REQ_AUTHSERV, 1); @@ -212,7 +245,7 @@ diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c monitor_permit(mon_dispatch, MONITOR_REQ_AUTH2_READ_BANNER, 1); #ifdef USE_PAM -@@ -877,6 +886,26 @@ key_base_type_match(const char *method, +@@ -986,6 +995,26 @@ key_base_type_match(const char *method, const struct sshkey *key, return found; } @@ -239,16 +272,16 @@ diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c int mm_answer_authpassword(struct ssh *ssh, int sock, struct sshbuf *m) { -@@ -1251,7 +1280,7 @@ monitor_valid_userblob(struct ssh *ssh, +@@ -1358,7 +1387,7 @@ monitor_valid_userblob(struct ssh *ssh, const u_char *data, u_int datalen) 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; -@@ -1282,6 +1311,8 @@ monitor_valid_userblob(struct ssh *ssh, +@@ -1389,6 +1418,8 @@ monitor_valid_userblob(struct ssh *ssh, const u_char *data, u_int datalen) fail++; if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) fatal_fr(r, "parse userstyle"); @@ -257,7 +290,7 @@ diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); -@@ -1317,7 +1348,7 @@ monitor_valid_hostbasedblob(const u_char +@@ -1439,7 +1470,7 @@ monitor_valid_hostbasedblob(const u_char *data, u_int datalen, { struct sshbuf *b; const u_char *p; @@ -266,7 +299,7 @@ diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c size_t len; int r, fail = 0; u_char type; -@@ -1338,6 +1370,8 @@ monitor_valid_hostbasedblob(const u_char +@@ -1460,6 +1491,8 @@ monitor_valid_hostbasedblob(const u_char *data, u_int datalen, fail++; if ((r = sshbuf_get_cstring(b, &cp, NULL)) != 0) fatal_fr(r, "parse userstyle"); @@ -275,12 +308,13 @@ diff -up openssh-8.6p1/monitor.c.role-mls openssh-8.6p1/monitor.c xasprintf(&userstyle, "%s%s%s", authctxt->user, authctxt->style ? ":" : "", authctxt->style ? authctxt->style : ""); -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, +diff --git a/monitor.h b/monitor.h +index 3f8a9bea..9dcd9c29 100644 +--- a/monitor.h ++++ b/monitor.h +@@ -56,6 +56,10 @@ enum monitor_reqtype { MONITOR_REQ_TERM = 50, + MONITOR_REQ_STATE = 51, MONITOR_ANS_STATE = 52, +#ifdef WITH_SELINUX + MONITOR_REQ_AUTHROLE = 80, @@ -289,10 +323,11 @@ diff -up openssh/monitor.h.role-mls openssh/monitor.h 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 -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 * +diff --git a/monitor_wrap.c b/monitor_wrap.c +index bd900b2f..ef3ab1b1 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -442,6 +442,27 @@ mm_inform_authserv(char *service, char *style) sshbuf_free(m); } @@ -320,10 +355,11 @@ diff -up openssh/monitor_wrap.c.role-mls openssh/monitor_wrap.c /* Do the password authentication */ int mm_auth_password(struct ssh *ssh, char *password) -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); +diff --git a/monitor_wrap.h b/monitor_wrap.h +index 7134afee..38a280c8 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -46,6 +46,9 @@ int mm_sshkey_sign(struct ssh *, struct sshkey *, u_char **, size_t *, const u_char *, size_t, const char *, const char *, const char *, u_int compat); void mm_inform_authserv(char *, char *); @@ -333,10 +369,11 @@ diff -up openssh/monitor_wrap.h.role-mls openssh/monitor_wrap.h struct passwd *mm_getpwnamallow(struct ssh *, const char *); char *mm_auth2_read_banner(void); int mm_auth_password(struct ssh *, char *); -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 \ +diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in +index 1d549954..78e6fa5b 100644 +--- a/openbsd-compat/Makefile.in ++++ b/openbsd-compat/Makefile.in +@@ -100,7 +100,8 @@ PORTS= port-aix.o \ port-prngd.o \ port-solaris.o \ port-net.o \ @@ -346,79 +383,12 @@ diff -up openssh/openbsd-compat/Makefile.in.role-mls openssh/openbsd-compat/Make .c.o: $(CC) $(CFLAGS_NOPIE) $(PICFLAG) $(CPPFLAGS) -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,421 @@ +diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c +new file mode 100644 +index 00000000..b9fbe38b +--- /dev/null ++++ b/openbsd-compat/port-linux-sshd.c +@@ -0,0 +1,420 @@ +/* + * Copyright (c) 2005 Daniel Walsh + * Copyright (c) 2014 Petr Lautrbach @@ -472,7 +442,6 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compa +extern ServerOptions options; +extern Authctxt *the_authctxt; +extern int inetd_flag; -+extern int rexeced_flag; + +/* Send audit message */ +static int @@ -678,7 +647,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compa + + if (r == 0) { + /* If launched from xinetd, we must use current level */ -+ if (inetd_flag && !rexeced_flag) { ++ if (inetd_flag) { + security_context_t sshdsc=NULL; + + if (getcon_raw(&sshdsc) < 0) @@ -752,7 +721,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compa + + rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); + -+ if (inetd_flag && !rexeced_flag) { ++ if (inetd_flag) { + use_current = "1"; + } else { + use_current = ""; @@ -840,10 +809,82 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.role-mls openssh/openbsd-compa +#endif +#endif + -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 +diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c +index c1d54f38..7426f6f7 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 959430de..055c825e 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 4c4fe57e..1bfb4bea 100644 +--- a/platform.c ++++ b/platform.c +@@ -140,7 +140,7 @@ platform_setusercontext_post_groups(struct passwd *pw) } #endif /* HAVE_SETPCRED */ #ifdef WITH_SELINUX @@ -852,10 +893,11 @@ diff -up openssh/platform.c.role-mls openssh/platform.c #endif } -diff -up openssh/sshd.c.role-mls openssh/sshd.c ---- openssh/sshd.c.role-mls 2018-08-20 07:57:29.000000000 +0200 -+++ openssh/sshd.c 2018-08-22 11:14:56.820430957 +0200 -@@ -2186,6 +2186,9 @@ main(int ac, char **av) +diff --git a/sshd-session.c b/sshd-session.c +index c64eb29f..74d2cbc7 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -1328,6 +1328,9 @@ main(int ac, char **av) restore_uid(); } #endif @@ -864,4 +906,7 @@ diff -up openssh/sshd.c.role-mls openssh/sshd.c +#endif #ifdef USE_PAM if (options.use_pam) { - do_pam_setcred(1); + do_pam_setcred(); +-- +2.49.0 + diff --git a/0002-openssh-6.6p1-privsep-selinux.patch b/0002-openssh-6.6p1-privsep-selinux.patch new file mode 100644 index 0000000..32d3c64 --- /dev/null +++ b/0002-openssh-6.6p1-privsep-selinux.patch @@ -0,0 +1,144 @@ +From 99d8e250514023d3b88a1c9eb724c4898aba9827 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 02/50] openssh-6.6p1-privsep-selinux + +--- + openbsd-compat/port-linux-sshd.c | 22 ++++++++++++++++++++++ + openbsd-compat/port-linux.h | 1 + + session.c | 16 +++++++++------- + sshd-auth.c | 4 ++++ + sshd-session.c | 2 +- + 5 files changed, 37 insertions(+), 8 deletions(-) + +diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c +index b9fbe38b..dfafc622 100644 +--- a/openbsd-compat/port-linux-sshd.c ++++ b/openbsd-compat/port-linux-sshd.c +@@ -415,6 +415,28 @@ sshd_selinux_setup_exec_context(char *pwname) + 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 --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h +index 055c825e..498d242a 100644 +--- a/openbsd-compat/port-linux.h ++++ b/openbsd-compat/port-linux.h +@@ -23,6 +23,7 @@ void ssh_selinux_setup_pty(char *, const char *); + 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 --git a/session.c b/session.c +index 6444c77f..e4657cef 100644 +--- a/session.c ++++ b/session.c +@@ -1350,7 +1350,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) { +@@ -1382,6 +1382,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); +@@ -1417,6 +1420,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"); +@@ -1434,9 +1442,6 @@ do_pwchange(Session *s) + if (s->ttyfd != -1) { + fprintf(stderr, + "You must change your password now and log in again!\n"); +-#ifdef WITH_SELINUX +- setexeccon(NULL); +-#endif + #ifdef PASSWD_NEEDS_USERNAME + execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name, + (char *)NULL); +@@ -1649,9 +1654,6 @@ do_child(struct ssh *ssh, 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 --git a/sshd-auth.c b/sshd-auth.c +index 30eecd8a..f957dc22 100644 +--- a/sshd-auth.c ++++ b/sshd-auth.c +@@ -187,6 +187,10 @@ privsep_child_demote(void) + if ((box = ssh_sandbox_init(pmonitor)) == NULL) + fatal_f("ssh_sandbox_init failed"); + #endif ++#ifdef WITH_SELINUX ++ ssh_selinux_change_context("sshd_net_t"); ++#endif ++ + /* Demote the child */ + if (privsep_chroot) { + /* Change our root directory */ +diff --git a/sshd-session.c b/sshd-session.c +index 74d2cbc7..4a148db4 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -432,7 +432,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) + * 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 + +-- +2.49.0 + diff --git a/openssh-6.6p1-keycat.patch b/0003-openssh-6.6p1-keycat.patch similarity index 76% rename from openssh-6.6p1-keycat.patch rename to 0003-openssh-6.6p1-keycat.patch index 529b508..b46b378 100644 --- a/openssh-6.6p1-keycat.patch +++ b/0003-openssh-6.6p1-keycat.patch @@ -1,23 +1,26 @@ -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); - } -+#ifdef WITH_SELINUX -+ if (sshd_selinux_setup_env_variables() < 0) { -+ error ("failed to copy environment: %s", -+ strerror(errno)); -+ _exit(127); -+ } -+#endif - if (env != NULL) - execve(av[0], av, env); - else -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 +From 5e35e18a419a5a66b6e1cb2b98beaaf4d9db0dc6 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 03/50] openssh-6.6p1-keycat + +--- + HOWTO.ssh-keycat | 12 ++ + Makefile.in | 8 +- + configure.ac | 6 + + misc.c | 7 + + openbsd-compat/port-linux-sshd.c | 44 +++++- + openbsd-compat/port-linux.h | 2 + + platform.c | 2 +- + ssh-keycat.c | 241 +++++++++++++++++++++++++++++++ + 8 files changed, 314 insertions(+), 8 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 00000000..630ec628 +--- /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 @@ -31,35 +34,36 @@ diff -up openssh/HOWTO.ssh-keycat.keycat openssh/HOWTO.ssh-keycat + 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 +diff --git a/Makefile.in b/Makefile.in +index 4617cebc..438efc51 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 - SSH_SK_HELPER=$(libexecdir)/ssh-sk-helper - PRIVSEP_PATH=@PRIVSEP_PATH@ -@@ -52,6 +52,7 @@ K5LIBS=@K5LIBS@ +@@ -57,6 +58,7 @@ CHANNELLIBS=@CHANNELLIBS@ K5LIBS=@K5LIBS@ GSSLIBS=@GSSLIBS@ SSHDLIBS=@SSHDLIBS@ +KEYCATLIBS=@KEYCATLIBS@ LIBEDIT=@LIBEDIT@ LIBFIDO2=@LIBFIDO2@ - AR=@AR@ -@@ -65,7 +66,7 @@ EXEEXT=@EXEEXT@ + LIBWTMPDB=@LIBWTMPDB@ +@@ -74,7 +76,7 @@ MKDIR_P=@MKDIR_P@ .SUFFIXES: .lo --TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) -+TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT) ssh-sk-helper$(EXEEXT) ssh-keycat$(EXEEXT) +-TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) sshd-session$(EXEEXT) 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) XMSS_OBJS=\ ssh-xmss.o \ -@@ -190,6 +191,9 @@ ssh-pkcs11-helper$(EXEEXT): $(LIBCOMPAT) +@@ -260,6 +262,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) @@ -69,7 +73,7 @@ diff -up openssh/Makefile.in.keycat openssh/Makefile.in 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: +@@ -447,6 +452,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) @@ -77,26 +81,69 @@ diff -up openssh/Makefile.in.keycat openssh/Makefile.in $(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 *); +diff --git a/configure.ac b/configure.ac +index ee77a048..d546788c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3566,6 +3566,7 @@ AC_ARG_WITH([pam], + PAM_MSG="yes" -+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 + SSHDLIBS="$SSHDLIBS -lpam" ++ KEYCATLIBS="$KEYCATLIBS -lpam" + AC_DEFINE([USE_PAM], [1], + [Define if you want to enable PAM support]) - #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; +@@ -3576,6 +3577,7 @@ AC_ARG_WITH([pam], + ;; + *) + SSHDLIBS="$SSHDLIBS -ldl" ++ KEYCATLIBS="$KEYCATLIBS -ldl" + ;; + esac + fi +@@ -4801,6 +4803,7 @@ AC_ARG_WITH([selinux], + fi ] + ) + AC_SUBST([SSHDLIBS]) ++AC_SUBST([KEYCATLIBS]) + + # Check whether user wants Kerberos 5 support + KRB5_MSG="no" +@@ -5812,6 +5815,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 c932f9bb..1e31acc9 100644 +--- a/misc.c ++++ b/misc.c +@@ -2897,6 +2897,13 @@ subprocess(const char *tag, const char *command, + error("%s: dup2: %s", tag, strerror(errno)); + _exit(1); + } ++#ifdef WITH_SELINUX ++ if (sshd_selinux_setup_env_variables() < 0) { ++ error ("failed to copy environment: %s", ++ strerror(errno)); ++ _exit(127); ++ } ++#endif + 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 dfafc622..8c5fc1fe 100644 +--- a/openbsd-compat/port-linux-sshd.c ++++ b/openbsd-compat/port-linux-sshd.c +@@ -52,6 +52,20 @@ extern ServerOptions options; + extern Authctxt *the_authctxt; extern int inetd_flag; - extern int rexeced_flag; +/* Wrapper around is_selinux_enabled() to log its return value once only */ +int @@ -115,7 +162,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/ /* Send audit message */ static int sshd_selinux_send_audit_message(int success, security_context_t default_context, -@@ -308,7 +322,7 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -317,7 +331,7 @@ sshd_selinux_getctxbyname(char *pwname, /* Setup environment variables for pam_selinux */ static int @@ -124,14 +171,14 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/ { const char *reqlvl; char *role; -@@ -319,16 +333,16 @@ sshd_selinux_setup_pam_variables(void) +@@ -328,16 +342,16 @@ sshd_selinux_setup_pam_variables(void) ssh_selinux_get_role_level(&role, &reqlvl); - rv = do_pam_putenv("SELINUX_ROLE_REQUESTED", role ? role : ""); + rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : ""); - if (inetd_flag && !rexeced_flag) { + if (inetd_flag) { use_current = "1"; } else { use_current = ""; @@ -144,7 +191,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/ if (role != NULL) free(role); -@@ -336,6 +350,24 @@ sshd_selinux_setup_pam_variables(void) +@@ -345,6 +359,24 @@ sshd_selinux_setup_pam_variables(void) return rv; } @@ -169,7 +216,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/ /* Set the execution context to the default for the specified user */ void sshd_selinux_setup_exec_context(char *pwname) -@@ -344,7 +376,7 @@ sshd_selinux_setup_exec_context(char *pw +@@ -353,7 +385,7 @@ sshd_selinux_setup_exec_context(char *pwname) int r = 0; security_context_t default_ctx = NULL; @@ -178,7 +225,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/ return; if (options.use_pam) { -@@ -415,7 +447,7 @@ sshd_selinux_copy_context(void) +@@ -420,7 +452,7 @@ sshd_selinux_copy_context(void) { security_context_t *ctx; @@ -187,10 +234,26 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.keycat openssh/openbsd-compat/ return; 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 +diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h +index 498d242a..1b745a76 100644 +--- a/openbsd-compat/port-linux.h ++++ b/openbsd-compat/port-linux.h +@@ -23,8 +23,10 @@ void ssh_selinux_setup_pty(char *, const char *); + 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 --git a/platform.c b/platform.c +index 1bfb4bea..0d12f311 100644 +--- a/platform.c ++++ b/platform.c +@@ -55,7 +55,7 @@ platform_setusercontext(struct passwd *pw) { #ifdef WITH_SELINUX /* Cache selinux status for later use */ @@ -199,9 +262,11 @@ diff -up openssh/platform.c.keycat openssh/platform.c #endif #ifdef USE_SOLARIS_PROJECTS -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 +diff --git a/ssh-keycat.c b/ssh-keycat.c +new file mode 100644 +index 00000000..5678be07 +--- /dev/null ++++ b/ssh-keycat.c @@ -0,0 +1,241 @@ +/* + * Redistribution and use in source and binary forms, with or without @@ -444,41 +509,6 @@ diff -up openssh/ssh-keycat.c.keycat openssh/ssh-keycat.c + } + return ev; +} -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 "" - +-- +2.49.0 + diff --git a/openssh-6.6p1-allow-ip-opts.patch b/0004-openssh-6.6p1-allow-ip-opts.patch similarity index 68% rename from openssh-6.6p1-allow-ip-opts.patch rename to 0004-openssh-6.6p1-allow-ip-opts.patch index be8d340..ef15fbf 100644 --- a/openssh-6.6p1-allow-ip-opts.patch +++ b/0004-openssh-6.6p1-allow-ip-opts.patch @@ -1,7 +1,17 @@ -diff -up openssh/sshd.c.ip-opts openssh/sshd.c ---- openssh/sshd.c.ip-opts 2016-07-25 13:58:48.998507834 +0200 -+++ openssh/sshd.c 2016-07-25 14:01:28.346469878 +0200 -@@ -1507,12 +1507,32 @@ check_ip_options(struct ssh *ssh) +From 28333f1dfe68b0ffc80c2a4799759587b4c32d3e Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 04/50] 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 4a148db4..a365f26f 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -778,12 +778,32 @@ check_ip_options(struct ssh *ssh) if (getsockopt(sock_in, IPPROTO_IP, IP_OPTIONS, opts, &option_size) >= 0 && option_size != 0) { @@ -38,5 +48,8 @@ diff -up openssh/sshd.c.ip-opts openssh/sshd.c + } + } while (i < option_size); } - return; #endif /* IP_OPTIONS */ + } +-- +2.49.0 + diff --git a/openssh-5.9p1-ipv6man.patch b/0005-openssh-5.9p1-ipv6man.patch similarity index 54% rename from openssh-5.9p1-ipv6man.patch rename to 0005-openssh-5.9p1-ipv6man.patch index ece1a73..909b988 100644 --- a/openssh-5.9p1-ipv6man.patch +++ b/0005-openssh-5.9p1-ipv6man.patch @@ -1,7 +1,18 @@ -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. +From 388be633842a9f3e4b0a76fe40cf7035912a913a Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 05/50] openssh-5.9p1-ipv6man + +--- + ssh.1 | 2 ++ + sshd.8 | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/ssh.1 b/ssh.1 +index 697f4e42..db92ac9a 100644 +--- a/ssh.1 ++++ b/ssh.1 +@@ -1663,6 +1663,8 @@ manual page for more information. .Nm exits with the exit status of the remote command or with 255 if an error occurred. @@ -10,10 +21,11 @@ diff -up openssh-5.9p0/ssh.1.ipv6man openssh-5.9p0/ssh.1 .Sh SEE ALSO .Xr scp 1 , .Xr sftp 1 , -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 +diff --git a/sshd.8 b/sshd.8 +index 08ebf53a..2aa73271 100644 +--- a/sshd.8 ++++ b/sshd.8 +@@ -1018,6 +1018,8 @@ concurrently for different ports, this contains the process ID of the one started last). The content of this file is not sensitive; it can be world-readable. .El @@ -22,3 +34,6 @@ diff -up openssh-5.9p0/sshd.8.ipv6man openssh-5.9p0/sshd.8 .Sh SEE ALSO .Xr scp 1 , .Xr sftp 1 , +-- +2.49.0 + diff --git a/0006-openssh-5.8p2-sigpipe.patch b/0006-openssh-5.8p2-sigpipe.patch new file mode 100644 index 0000000..5bf31bc --- /dev/null +++ b/0006-openssh-5.8p2-sigpipe.patch @@ -0,0 +1,26 @@ +From 80359feb76fd8061b5ce18f73451d7b9db0c2477 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 06/50] openssh-5.8p2-sigpipe + +--- + ssh-keyscan.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/ssh-keyscan.c b/ssh-keyscan.c +index 3436c0b5..9f76ad22 100644 +--- a/ssh-keyscan.c ++++ b/ssh-keyscan.c +@@ -798,6 +798,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.49.0 + diff --git a/openssh-7.2p2-x11.patch b/0007-openssh-7.2p2-x11.patch similarity index 68% rename from openssh-7.2p2-x11.patch rename to 0007-openssh-7.2p2-x11.patch index 0a19ecb..2f72f9a 100644 --- a/openssh-7.2p2-x11.patch +++ b/0007-openssh-7.2p2-x11.patch @@ -1,7 +1,17 @@ -diff -up openssh-7.2p2/channels.c.x11 openssh-7.2p2/channels.c ---- openssh-7.2p2/channels.c.x11 2016-03-09 19:04:48.000000000 +0100 -+++ openssh-7.2p2/channels.c 2016-06-03 10:42:04.775164520 +0200 -@@ -3990,21 +3990,24 @@ x11_create_display_inet(int x11_display_ +From cf6d48305cf6601448ea7a0d96ae825cbbbf0a2c Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 07/50] openssh-7.2p2-x11 + +--- + channels.c | 25 +++++++++++++++++++------ + 1 file changed, 19 insertions(+), 6 deletions(-) + +diff --git a/channels.c b/channels.c +index bfe2e3b2..d46531ce 100644 +--- a/channels.c ++++ b/channels.c +@@ -5098,11 +5098,13 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, } static int @@ -14,8 +24,10 @@ diff -up openssh-7.2p2/channels.c.x11 openssh-7.2p2/channels.c + if (len <= 0) + return -1; sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock == -1) + if (sock == -1) { error("socket: %.100s", strerror(errno)); +@@ -5110,11 +5112,12 @@ connect_local_xsocket_path(const char *pathname) + } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strlcpy(addr.sun_path, pathname, sizeof addr.sun_path); @@ -30,7 +42,7 @@ diff -up openssh-7.2p2/channels.c.x11 openssh-7.2p2/channels.c return -1; } -@@ -4012,8 +4015,18 @@ static int +@@ -5122,8 +5125,18 @@ static int connect_local_xsocket(u_int dnr) { char buf[1024]; @@ -51,3 +63,6 @@ diff -up openssh-7.2p2/channels.c.x11 openssh-7.2p2/channels.c } #ifdef __APPLE__ +-- +2.49.0 + diff --git a/openssh-5.1p1-askpass-progress.patch b/0008-openssh-5.1p1-askpass-progress.patch similarity index 66% rename from openssh-5.1p1-askpass-progress.patch rename to 0008-openssh-5.1p1-askpass-progress.patch index ff609da..f7ca382 100644 --- a/openssh-5.1p1-askpass-progress.patch +++ b/0008-openssh-5.1p1-askpass-progress.patch @@ -1,7 +1,17 @@ -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 @@ +From 6b2a33044583e892badb9ac86cd2c6252b1a532f Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 08/50] 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 a62f9815..cb7152dc 100644 +--- a/contrib/gnome-ssh-askpass2.c ++++ b/contrib/gnome-ssh-askpass2.c +@@ -58,6 +58,7 @@ #include #include @@ -9,7 +19,7 @@ diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contr #include #include #include -@@ -81,14 +82,25 @@ ok_dialog(GtkWidget *entry, gpointer dia +@@ -146,6 +147,17 @@ parse_env_hex_color(const char *env, GdkColor *c) return 1; } @@ -27,7 +37,7 @@ diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contr static int passphrase_dialog(char *message, int prompt_type) { - const char *failed; +@@ -153,7 +165,7 @@ passphrase_dialog(char *message, int prompt_type) char *passphrase, *local; int result, grab_tries, grab_server, grab_pointer; int buttons, default_response; @@ -36,7 +46,7 @@ diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contr GdkGrabStatus status; GdkColor fg, bg; int fg_set = 0, bg_set = 0; -@@ -104,14 +116,19 @@ passphrase_dialog(char *message) +@@ -199,14 +211,19 @@ passphrase_dialog(char *message, int prompt_type) gtk_widget_modify_bg(dialog, GTK_STATE_NORMAL, &bg); if (prompt_type == PROMPT_ENTRY || prompt_type == PROMPT_NONE) { @@ -45,12 +55,12 @@ diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contr + 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); @@ -58,7 +68,7 @@ diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contr gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); gtk_widget_grab_focus(entry); if (prompt_type == PROMPT_ENTRY) { -@@ -130,6 +145,22 @@ passphrase_dialog(char *message) +@@ -225,6 +242,22 @@ passphrase_dialog(char *message, int prompt_type) g_signal_connect(G_OBJECT(entry), "key_press_event", G_CALLBACK(check_none), dialog); } @@ -81,3 +91,6 @@ diff -up openssh-7.4p1/contrib/gnome-ssh-askpass2.c.progress openssh-7.4p1/contr } /* Grab focus */ +-- +2.49.0 + diff --git a/openssh-4.3p2-askpass-grab-info.patch b/0009-openssh-4.3p2-askpass-grab-info.patch similarity index 53% rename from openssh-4.3p2-askpass-grab-info.patch rename to 0009-openssh-4.3p2-askpass-grab-info.patch index 120ed1b..8a7cf9e 100644 --- a/openssh-4.3p2-askpass-grab-info.patch +++ b/0009-openssh-4.3p2-askpass-grab-info.patch @@ -1,7 +1,17 @@ -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 +From 710ce53fdf1d32a0629fce2e42fb49d407e2b06c Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 09/50] 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 cb7152dc..bbe93d83 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) err = gtk_message_dialog_new(GTK_WINDOW(parent_window), 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, @@ -16,3 +26,6 @@ diff -up openssh-8.6p1/contrib/gnome-ssh-askpass2.c.grab-info openssh-8.6p1/cont gtk_window_set_position(GTK_WINDOW(err), GTK_WIN_POS_CENTER); gtk_dialog_run(GTK_DIALOG(err)); +-- +2.49.0 + diff --git a/openssh-7.7p1-redhat.patch b/0010-openssh-8.7p1-redhat.patch similarity index 63% rename from openssh-7.7p1-redhat.patch rename to 0010-openssh-8.7p1-redhat.patch index 1d77f90..cb3d140 100644 --- a/openssh-7.7p1-redhat.patch +++ b/0010-openssh-8.7p1-redhat.patch @@ -1,7 +1,26 @@ -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 @@ +From 5f21983f6472b26693babea4d6ca6b95a7dc7b05 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 10/50] 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 cc566356..18169187 100644 +--- a/ssh_config ++++ b/ssh_config +@@ -44,3 +44,10 @@ # ProxyCommand ssh -q -W %h:%p gateway.example.com # RekeyLimit 1G 1h # UserKnownHostsFile ~/.ssh/known_hosts.d/%k @@ -12,10 +31,12 @@ diff -up openssh/ssh_config.redhat openssh/ssh_config +# 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 -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 @@ +diff --git a/ssh_config_redhat b/ssh_config_redhat +new file mode 100644 +index 00000000..8b1b5902 +--- /dev/null ++++ b/ssh_config_redhat +@@ -0,0 +1,18 @@ +# 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 @@ -29,12 +50,35 @@ diff -up openssh/ssh_config_redhat.redhat openssh/ssh_config_redhat +# 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 -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 +diff --git a/sshd_config b/sshd_config +index 0f4a3a72..608203e4 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 2f77b4f4..49349bb3 100644 +--- a/sshd_config.0 ++++ b/sshd_config.0 +@@ -1219,9 +1219,9 @@ DESCRIPTION SyslogFacility Gives the facility code that is used when logging messages from @@ -47,10 +91,11 @@ diff -up openssh/sshd_config.0.redhat openssh/sshd_config.0 TCPKeepAlive Specifies whether the system should send TCP keepalive messages -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. +diff --git a/sshd_config.5 b/sshd_config.5 +index c0771737..035a50c8 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1942,7 +1942,7 @@ By default no subsystems are defined. .It Cm SyslogFacility Gives the facility code that is used when logging messages from .Xr sshd 8 . @@ -59,31 +104,15 @@ diff -up openssh/sshd_config.5.redhat openssh/sshd_config.5 LOCAL3, LOCAL4, LOCAL5, LOCAL6, LOCAL7. The default is AUTH. .It Cm TCPKeepAlive -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 @@ +diff --git a/sshd_config_redhat b/sshd_config_redhat +new file mode 100644 +index 00000000..993a28d5 +--- /dev/null ++++ b/sshd_config_redhat +@@ -0,0 +1,18 @@ +SyslogFacility AUTHPRIV + -+ChallengeResponseAuthentication no ++KbdInteractiveAuthentication no + +GSSAPIAuthentication yes +GSSAPICleanupCredentials no @@ -92,13 +121,18 @@ diff -up openssh/sshd_config_redhat.redhat openssh/sshd_config_redhat + +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 -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 +diff --git a/sshd_config_redhat_cp b/sshd_config_redhat_cp +new file mode 100644 +index 00000000..1d592d13 +--- /dev/null ++++ b/sshd_config_redhat_cp @@ -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 @@ -107,3 +141,6 @@ diff -up openssh/sshd_config_redhat.redhat openssh/sshd_config_redhat +# Please, see manual pages for update-crypto-policies(8) and sshd_config(5). +Include /etc/crypto-policies/back-ends/opensshserver.config + +-- +2.49.0 + diff --git a/0011-openssh-7.8p1-UsePAM-warning.patch b/0011-openssh-7.8p1-UsePAM-warning.patch new file mode 100644 index 0000000..76ee115 --- /dev/null +++ b/0011-openssh-7.8p1-UsePAM-warning.patch @@ -0,0 +1,41 @@ +From 56b8d082bc9e25a77b5227d576f27088446c6fb9 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 11/50] 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 a365f26f..a70b36c9 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -1127,6 +1127,10 @@ main(int ac, char **av) + "enabled authentication methods"); + } + ++ /* 'UsePAM no' is not supported in our builds */ ++ if (! options.use_pam) ++ logit("WARNING: 'UsePAM no' is not supported in this build and may cause several problems."); ++ + #ifdef WITH_OPENSSL + if (options.moduli_file != NULL) + dh_set_moduli_file(options.moduli_file); +diff --git a/sshd_config b/sshd_config +index 608203e4..48af6321 100644 +--- a/sshd_config ++++ b/sshd_config +@@ -89,6 +89,8 @@ AuthorizedKeysFile .ssh/authorized_keys + # If you just want the PAM account and session checks to run without + # PAM authentication, then enable this but set PasswordAuthentication + # and KbdInteractiveAuthentication to 'no'. ++# WARNING: 'UsePAM no' is not supported in this build and may cause several ++# problems. + #UsePAM no + + #AllowAgentForwarding yes +-- +2.49.0 + diff --git a/openssh-8.0p1-gssapi-keyex.patch b/0012-openssh-9.6p1-gssapi-keyex.patch similarity index 69% rename from openssh-8.0p1-gssapi-keyex.patch rename to 0012-openssh-9.6p1-gssapi-keyex.patch index d1d914d..f5f54f7 100644 --- a/openssh-8.0p1-gssapi-keyex.patch +++ b/0012-openssh-9.6p1-gssapi-keyex.patch @@ -1,25 +1,85 @@ +From 754b023b92aa68742258c55243a6ae8f30ed5a17 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 12/50] 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 | 302 ++++++++++++++++++++- + gss-serv-krb5.c | 97 ++++++- + gss-serv.c | 200 ++++++++++++-- + kex-names.c | 62 ++++- + 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 | 47 ++++ + 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 | 53 ++++ + sshd-session.c | 9 +- + sshd.c | 3 +- + sshd_config | 2 + + sshd_config.5 | 31 +++ + sshkey.c | 72 ++++- + sshkey.h | 1 + + 41 files changed, 2984 insertions(+), 76 deletions(-) + create mode 100644 kexgssc.c + create mode 100644 kexgsss.c + diff --git a/Makefile.in b/Makefile.in -index e7549470..b68c1710 100644 +index 438efc51..78f65948 100644 --- a/Makefile.in +++ b/Makefile.in -@@ -109,6 +109,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kex.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ +@@ -117,6 +117,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ + kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ kexgexc.o kexgexs.o \ - kexsntrup761x25519.o sntrup761.o kexgen.o \ + kexsntrup761x25519.o kexmlkem768x25519.o sntrup761.o kexgen.o \ + kexgssc.o \ sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ sshbuf-io.o -@@ -125,7 +126,7 @@ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o \ +@@ -138,7 +139,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 \ ++ 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 \ +@@ -150,7 +151,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 \ - srclimit.o sftp-server.o sftp-common.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ -@@ -523,7 +523,7 @@ regress-prep: +@@ -563,7 +564,7 @@ regress-prep: ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile REGRESSLIBS=libssh.a $(LIBCOMPAT) @@ -28,10 +88,11 @@ index e7549470..b68c1710 100644 regress/modpipe$(EXEEXT): $(srcdir)/regress/modpipe.c $(REGRESSLIBS) $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/modpipe.c \ -diff -up a/auth.c.gsskex b/auth.c ---- a/auth.c.gsskex 2021-08-20 06:03:49.000000000 +0200 -+++ b/auth.c 2021-08-27 12:41:51.262788953 +0200 -@@ -402,7 +402,8 @@ auth_root_allowed(struct ssh *ssh, const +diff --git a/auth.c b/auth.c +index 9a6e5a31..e4578169 100644 +--- a/auth.c ++++ b/auth.c +@@ -356,7 +356,8 @@ auth_root_allowed(struct ssh *ssh, const char *method) case PERMIT_NO_PASSWD: if (strcmp(method, "publickey") == 0 || strcmp(method, "hostbased") == 0 || @@ -41,118 +102,19 @@ diff -up a/auth.c.gsskex b/auth.c return 1; break; case PERMIT_FORCED_ONLY: -@@ -730,97 +731,6 @@ fakepw(void) - } - - /* -- * Returns the remote DNS hostname as a string. The returned string must not -- * be freed. NB. this will usually trigger a DNS query the first time it is -- * called. -- * This function does additional checks on the hostname to mitigate some -- * attacks on based on conflation of hostnames and IP addresses. -- */ -- --static char * --remote_hostname(struct ssh *ssh) --{ -- struct sockaddr_storage from; -- socklen_t fromlen; -- struct addrinfo hints, *ai, *aitop; -- char name[NI_MAXHOST], ntop2[NI_MAXHOST]; -- const char *ntop = ssh_remote_ipaddr(ssh); -- -- /* Get IP address of client. */ -- fromlen = sizeof(from); -- memset(&from, 0, sizeof(from)); -- if (getpeername(ssh_packet_get_connection_in(ssh), -- (struct sockaddr *)&from, &fromlen) == -1) { -- debug("getpeername failed: %.100s", strerror(errno)); -- return xstrdup(ntop); -- } -- -- ipv64_normalise_mapped(&from, &fromlen); -- if (from.ss_family == AF_INET6) -- fromlen = sizeof(struct sockaddr_in6); -- -- debug3("Trying to reverse map address %.100s.", ntop); -- /* Map the IP address to a host name. */ -- if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name), -- NULL, 0, NI_NAMEREQD) != 0) { -- /* Host name not found. Use ip address. */ -- return xstrdup(ntop); -- } -- -- /* -- * if reverse lookup result looks like a numeric hostname, -- * someone is trying to trick us by PTR record like following: -- * 1.1.1.10.in-addr.arpa. IN PTR 2.3.4.5 -- */ -- memset(&hints, 0, sizeof(hints)); -- hints.ai_socktype = SOCK_DGRAM; /*dummy*/ -- hints.ai_flags = AI_NUMERICHOST; -- if (getaddrinfo(name, NULL, &hints, &ai) == 0) { -- logit("Nasty PTR record \"%s\" is set up for %s, ignoring", -- name, ntop); -- freeaddrinfo(ai); -- return xstrdup(ntop); -- } -- -- /* Names are stored in lowercase. */ -- lowercase(name); -- -- /* -- * Map it back to an IP address and check that the given -- * address actually is an address of this host. This is -- * necessary because anyone with access to a name server can -- * define arbitrary names for an IP address. Mapping from -- * name to IP address can be trusted better (but can still be -- * fooled if the intruder has access to the name server of -- * the domain). -- */ -- memset(&hints, 0, sizeof(hints)); -- hints.ai_family = from.ss_family; -- hints.ai_socktype = SOCK_STREAM; -- if (getaddrinfo(name, NULL, &hints, &aitop) != 0) { -- logit("reverse mapping checking getaddrinfo for %.700s " -- "[%s] failed.", name, ntop); -- return xstrdup(ntop); -- } -- /* Look for the address from the list of addresses. */ -- for (ai = aitop; ai; ai = ai->ai_next) { -- if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2, -- sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 && -- (strcmp(ntop, ntop2) == 0)) -- break; -- } -- freeaddrinfo(aitop); -- /* If we reached the end of the list, the address was not there. */ -- if (ai == NULL) { -- /* Address not found for the host name. */ -- logit("Address %.100s maps to %.600s, but this does not " -- "map back to the address.", ntop, name); -- return xstrdup(ntop); -- } -- return xstrdup(name); --} -- --/* - * Return the canonical name of the host in the other side of the current - * connection. The host name is cached, so it is efficient to call this - * several times. diff --git a/auth2-gss.c b/auth2-gss.c -index 9351e042..d6446c0c 100644 +index f7898ab3..5b1b9cde 100644 --- a/auth2-gss.c +++ b/auth2-gss.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: auth2-gss.c,v 1.33 2021/12/19 22:12:07 djm Exp $ */ +@@ -51,6 +51,7 @@ + #define SSH_GSSAPI_MAX_MECHS 2048 - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -54,6 +54,48 @@ static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh); + extern ServerOptions options; ++extern struct authmethod_cfg methodcfg_gsskeyex; + extern struct authmethod_cfg methodcfg_gssapi; + + static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh); +@@ -58,6 +59,48 @@ static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh); static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh); static int input_gssapi_errtok(int, u_int32_t, struct ssh *); @@ -187,10 +149,10 @@ index 9351e042..d6446c0c 100644 + gssbuf.length = sshbuf_len(b); + + /* gss_kex_context is NULL with privsep, so we can't check it here */ -+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -+ &gssbuf, &mic)))) -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); ++ if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gss_kex_context, ++ &gssbuf, &mic))) ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1); + + sshbuf_free(b); + free(mic.value); @@ -201,45 +163,65 @@ index 9351e042..d6446c0c 100644 /* * We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like) -@@ -260,7 +302,8 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) +@@ -267,7 +310,7 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) if ((r = sshpkt_get_end(ssh)) != 0) fatal_fr(r, "parse packet"); -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); +- authenticated = mm_ssh_gssapi_userok(authctxt->user); ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, authctxt->pw, 1); - if ((!use_privsep || mm_is_monitor()) && - (displayname = ssh_gssapi_displayname()) != NULL) -@@ -306,7 +349,8 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) + authctxt->postponed = 0; + ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); +@@ -315,7 +358,7 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) gssbuf.length = sshbuf_len(b); - if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 0)); + if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))) +- authenticated = mm_ssh_gssapi_userok(authctxt->user); ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, authctxt->pw, 0); else logit("GSSAPI MIC check failed"); -@@ -326,6 +370,13 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) +@@ -333,6 +376,11 @@ input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) return 0; } +Authmethod method_gsskeyex = { -+ "gssapi-keyex", -+ NULL, ++ &methodcfg_gsskeyex, + userauth_gsskeyex, -+ &options.gss_authentication +}; + Authmethod method_gssapi = { + &methodcfg_gssapi, + userauth_gssapi, +diff --git a/auth2-methods.c b/auth2-methods.c +index 99637a89..a05908cf 100644 +--- a/auth2-methods.c ++++ b/auth2-methods.c +@@ -50,6 +50,11 @@ struct authmethod_cfg methodcfg_pubkey = { + &options.pubkey_authentication + }; + #ifdef GSSAPI ++struct authmethod_cfg methodcfg_gsskeyex = { ++ "gssapi-keyex", ++ NULL, ++ &options.gss_authentication ++}; + struct authmethod_cfg methodcfg_gssapi = { "gssapi-with-mic", NULL, +@@ -76,6 +81,7 @@ static struct authmethod_cfg *authmethod_cfgs[] = { + &methodcfg_none, + &methodcfg_pubkey, + #ifdef GSSAPI ++ &methodcfg_gsskeyex, + &methodcfg_gssapi, + #endif + &methodcfg_passwd, diff --git a/auth2.c b/auth2.c -index 0e776224..1c217268 100644 +index 5ba45c12..8ec41de2 100644 --- a/auth2.c +++ b/auth2.c -@@ -73,6 +73,7 @@ extern Authmethod method_passwd; +@@ -71,6 +71,7 @@ extern Authmethod method_passwd; extern Authmethod method_kbdint; extern Authmethod method_hostbased; #ifdef GSSAPI @@ -247,7 +229,7 @@ index 0e776224..1c217268 100644 extern Authmethod method_gssapi; #endif -@@ -80,6 +81,7 @@ Authmethod *authmethods[] = { +@@ -78,6 +79,7 @@ Authmethod *authmethods[] = { &method_none, &method_pubkey, #ifdef GSSAPI @@ -256,7 +238,7 @@ index 0e776224..1c217268 100644 #endif &method_passwd, diff --git a/canohost.c b/canohost.c -index abea9c6e..8e81b519 100644 +index 28f086e5..875805c9 100644 --- a/canohost.c +++ b/canohost.c @@ -35,6 +35,99 @@ @@ -374,10 +356,10 @@ index 26d62855..0cadc9f1 100644 int get_peer_port(int); char *get_local_ipaddr(int); diff --git a/clientloop.c b/clientloop.c -index ebd0dbca..1bdac6a4 100644 +index 916fc077..4655f91f 100644 --- a/clientloop.c +++ b/clientloop.c -@@ -112,6 +112,10 @@ +@@ -115,6 +115,10 @@ #include "ssherr.h" #include "hostfile.h" @@ -388,7 +370,7 @@ index ebd0dbca..1bdac6a4 100644 /* Permitted RSA signature algorithms for UpdateHostkeys proofs */ #define HOSTKEY_PROOF_RSA_ALGS "rsa-sha2-512,rsa-sha2-256" -@@ -1379,6 +1383,14 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, +@@ -1591,6 +1595,14 @@ client_loop(struct ssh *ssh, int have_pty, int escape_char_arg, /* Do channel operations. */ channel_after_poll(ssh, pfd, npfd_active); @@ -404,10 +386,10 @@ index ebd0dbca..1bdac6a4 100644 if (conn_in_ready) client_process_net_input(ssh); diff --git a/configure.ac b/configure.ac -index b689db4b..efafb6bd 100644 +index d546788c..13c70a98 100644 --- a/configure.ac +++ b/configure.ac -@@ -674,6 +674,30 @@ main() { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) +@@ -786,6 +786,30 @@ int main(void) { if (NSVersionOfRunTimeLibrary("System") >= (60 << 16)) [Use tunnel device compatibility to OpenBSD]) AC_DEFINE([SSH_TUN_PREPEND_AF], [1], [Prepend the address family to IP tunnel traffic]) @@ -439,19 +421,10 @@ index b689db4b..efafb6bd 100644 AC_CHECK_DECL([AU_IPv4], [], AC_DEFINE([AU_IPv4], [0], [System only supports IPv4 audit records]) diff --git a/gss-genr.c b/gss-genr.c -index d56257b4..763a63ff 100644 +index aa34b71c..3034370c 100644 --- a/gss-genr.c +++ b/gss-genr.c -@@ -1,7 +1,7 @@ - /* $OpenBSD: gss-genr.c,v 1.28 2021/01/27 10:05:28 djm Exp $ */ - - /* -- * Copyright (c) 2001-2007 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -41,9 +41,33 @@ +@@ -42,9 +42,33 @@ #include "sshbuf.h" #include "log.h" #include "ssh2.h" @@ -485,7 +458,7 @@ index d56257b4..763a63ff 100644 /* sshbuf_get for gss_buffer_desc */ int ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) -@@ -62,6 +86,159 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) +@@ -60,6 +84,159 @@ ssh_gssapi_get_buffer_desc(struct sshbuf *b, gss_buffer_desc *g) return 0; } @@ -645,7 +618,28 @@ index d56257b4..763a63ff 100644 /* Check that the OID in a data stream matches that in the context */ int ssh_gssapi_check_oid(Gssctxt *ctx, void *data, size_t len) -@@ -218,7 +398,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, +@@ -168,6 +345,7 @@ ssh_gssapi_build_ctx(Gssctxt **ctx) + (*ctx)->creds = GSS_C_NO_CREDENTIAL; + (*ctx)->client = GSS_C_NO_NAME; + (*ctx)->client_creds = GSS_C_NO_CREDENTIAL; ++ (*ctx)->first = 1; + } + + /* Delete our context, providing it has been built correctly */ +@@ -193,6 +371,12 @@ ssh_gssapi_delete_ctx(Gssctxt **ctx) + gss_release_name(&ms, &(*ctx)->client); + if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) + gss_release_cred(&ms, &(*ctx)->client_creds); ++ sshbuf_free((*ctx)->shared_secret); ++ sshbuf_free((*ctx)->server_pubkey); ++ sshbuf_free((*ctx)->server_host_key_blob); ++ sshbuf_free((*ctx)->server_blob); ++ explicit_bzero((*ctx)->hash, sizeof((*ctx)->hash)); ++ BN_clear_free((*ctx)->dh_client_pub); + + free(*ctx); + *ctx = NULL; +@@ -216,7 +400,7 @@ ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, } ctx->major = gss_init_sec_context(&ctx->minor, @@ -654,7 +648,7 @@ index d56257b4..763a63ff 100644 GSS_C_MUTUAL_FLAG | GSS_C_INTEG_FLAG | deleg_flag, 0, NULL, recv_tok, NULL, send_tok, flags, NULL); -@@ -247,9 +427,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) +@@ -245,9 +429,43 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) return (ctx->major); } @@ -698,7 +692,7 @@ index d56257b4..763a63ff 100644 if ((ctx->major = gss_get_mic(&ctx->minor, ctx->context, GSS_C_QOP_DEFAULT, buffer, hash))) ssh_gssapi_error(ctx); -@@ -257,6 +471,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) +@@ -255,6 +473,19 @@ ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_t buffer, gss_buffer_t hash) return (ctx->major); } @@ -718,7 +712,7 @@ index d56257b4..763a63ff 100644 void ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, const char *context, const struct sshbuf *session_id) -@@ -273,11 +500,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, +@@ -271,11 +502,16 @@ ssh_gssapi_buildmic(struct sshbuf *b, const char *user, const char *service, } int @@ -735,8 +729,8 @@ index d56257b4..763a63ff 100644 + ctx = &intctx; /* RFC 4462 says we MUST NOT do SPNEGO */ - if (oid->length == spnego_oid.length && -@@ -287,6 +519,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) + if (oid->length == spnego_oid.length && +@@ -285,6 +521,10 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) ssh_gssapi_build_ctx(ctx); ssh_gssapi_set_oid(*ctx, oid); major = ssh_gssapi_import_name(*ctx, host); @@ -745,13 +739,13 @@ index d56257b4..763a63ff 100644 + major = ssh_gssapi_client_identity(*ctx, client); + if (!GSS_ERROR(major)) { - major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, + major = ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL); -@@ -296,10 +532,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) +@@ -294,10 +534,66 @@ ssh_gssapi_check_mechanism(Gssctxt **ctx, gss_OID oid, const char *host) GSS_C_NO_BUFFER); } -- if (GSS_ERROR(major)) +- if (GSS_ERROR(major)) + if (GSS_ERROR(major) || intctx != NULL) ssh_gssapi_delete_ctx(ctx); @@ -956,7 +950,7 @@ index a151bc1e..8d2b677f 100644 #endif /* KRB5 */ diff --git a/gss-serv.c b/gss-serv.c -index ab3a15f0..6ce56e92 100644 +index 025a118f..a5cca797 100644 --- a/gss-serv.c +++ b/gss-serv.c @@ -1,7 +1,7 @@ @@ -968,7 +962,7 @@ index ab3a15f0..6ce56e92 100644 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions -@@ -44,17 +44,19 @@ +@@ -45,17 +45,19 @@ #include "session.h" #include "misc.h" #include "servconf.h" @@ -991,7 +985,7 @@ index ab3a15f0..6ce56e92 100644 #ifdef KRB5 extern ssh_gssapi_mech gssapi_kerberos_mech; -@@ -140,6 +142,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) +@@ -141,6 +143,29 @@ ssh_gssapi_server_ctx(Gssctxt **ctx, gss_OID oid) return (ssh_gssapi_acquire_cred(*ctx)); } @@ -1012,7 +1006,7 @@ index ab3a15f0..6ce56e92 100644 + Gssctxt *ctx = NULL; + int res; + -+ res = !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, oid))); ++ res = !GSS_ERROR(mm_ssh_gssapi_server_ctx(&ctx, oid)); + ssh_gssapi_delete_ctx(&ctx); + + return (res); @@ -1021,7 +1015,7 @@ index ab3a15f0..6ce56e92 100644 /* Unprivileged */ void ssh_gssapi_supported_oids(gss_OID_set *oidset) -@@ -150,7 +175,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) +@@ -151,7 +176,9 @@ ssh_gssapi_supported_oids(gss_OID_set *oidset) gss_OID_set supported; gss_create_empty_oid_set(&min_status, oidset); @@ -1032,7 +1026,7 @@ index ab3a15f0..6ce56e92 100644 while (supported_mechs[i]->name != NULL) { if (GSS_ERROR(gss_test_oid_set_member(&min_status, -@@ -276,8 +303,48 @@ OM_uint32 +@@ -277,8 +304,48 @@ OM_uint32 ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) { int i = 0; @@ -1047,15 +1041,15 @@ index ab3a15f0..6ce56e92 100644 + debug("Rekeyed credentials have different mechanism"); + return GSS_S_COMPLETE; + } -+ + +- gss_buffer_desc ename; + if ((ctx->major = gss_inquire_cred_by_mech(&ctx->minor, + ctx->client_creds, ctx->oid, &new_name, + NULL, NULL, NULL))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } - -- gss_buffer_desc ename; ++ + ctx->major = gss_compare_name(&ctx->minor, client->name, + new_name, &equal); + @@ -1082,7 +1076,7 @@ index ab3a15f0..6ce56e92 100644 client->mech = NULL; -@@ -292,6 +359,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) +@@ -293,6 +360,13 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) if (client->mech == NULL) return GSS_S_FAILURE; @@ -1096,7 +1090,7 @@ index ab3a15f0..6ce56e92 100644 if ((ctx->major = gss_display_name(&ctx->minor, ctx->client, &client->displayname, NULL))) { ssh_gssapi_error(ctx); -@@ -309,6 +383,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) +@@ -310,6 +384,8 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) return (ctx->major); } @@ -1105,7 +1099,7 @@ index ab3a15f0..6ce56e92 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; -@@ -319,11 +395,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) +@@ -320,11 +396,20 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) void ssh_gssapi_cleanup_creds(void) { @@ -1131,7 +1125,7 @@ index ab3a15f0..6ce56e92 100644 } } -@@ -356,19 +441,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) +@@ -357,19 +442,23 @@ ssh_gssapi_do_child(char ***envp, u_int *envsizep) /* Privileged */ int @@ -1158,7 +1152,7 @@ index ab3a15f0..6ce56e92 100644 /* Destroy delegated credentials if userok fails */ gss_release_buffer(&lmin, &gssapi_client.displayname); gss_release_buffer(&lmin, &gssapi_client.exportedname); -@@ -382,14 +471,90 @@ ssh_gssapi_userok(char *user) +@@ -383,14 +472,85 @@ ssh_gssapi_userok(char *user) return (0); } @@ -1201,7 +1195,7 @@ index ab3a15f0..6ce56e92 100644 + gssapi_client.store.envvar == NULL) + return; + -+ ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); ++ ok = mm_ssh_gssapi_update_creds(&gssapi_client.store); + + if (!ok) + return; @@ -1213,11 +1207,6 @@ index ab3a15f0..6ce56e92 100644 + * for rekeying. So, use our own :) + */ +#ifdef USE_PAM -+ if (!use_privsep) { -+ debug("Not even going to try and do PAM with privsep disabled"); -+ return; -+ } -+ + ret = pam_start("sshd-rekey", gssapi_client.store.owner->pw_name, + &pamconv, &pamh); + if (ret) @@ -1255,22 +1244,22 @@ index ab3a15f0..6ce56e92 100644 } /* Privileged */ -diff --git a/kex.c b/kex.c -index ce85f043..574c7609 100644 ---- a/kex.c -+++ b/kex.c -@@ -57,6 +57,10 @@ - #include "digest.h" +diff --git a/kex-names.c b/kex-names.c +index ec840c1f..6c0b7c2b 100644 +--- a/kex-names.c ++++ b/kex-names.c +@@ -45,6 +45,10 @@ + #include "ssherr.h" #include "xmalloc.h" +#ifdef GSSAPI +#include "ssh-gss.h" +#endif + - /* prototype */ - static int kex_choose_conf(struct ssh *); - static int kex_input_newkeys(int, u_int32_t, struct ssh *); -@@ -115,15 +120,28 @@ static const struct kexalg kexalgs[] = { + struct kexalg { + char *name; + u_int type; +@@ -89,15 +93,28 @@ static const struct kexalg kexalgs[] = { #endif /* HAVE_EVP_SHA256 || !WITH_OPENSSL */ { NULL, 0, -1, -1}, }; @@ -1302,7 +1291,7 @@ index ce85f043..574c7609 100644 if (ret != NULL) ret[rlen++] = sep; nlen = strlen(k->name); -@@ -138,6 +156,18 @@ kex_alg_list(char sep) +@@ -112,6 +129,18 @@ kex_alg_list(char sep) return ret; } @@ -1321,7 +1310,7 @@ index ce85f043..574c7609 100644 static const struct kexalg * kex_alg_by_name(const char *name) { -@@ -147,6 +177,10 @@ kex_alg_by_name(const char *name) +@@ -121,6 +150,10 @@ kex_alg_by_name(const char *name) if (strcmp(k->name, name) == 0) return k; } @@ -1332,10 +1321,11 @@ index ce85f043..574c7609 100644 return NULL; } -@@ -315,6 +349,29 @@ kex_assemble_names(char **listp, const char *def, const char *all) +@@ -334,3 +367,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) @@ -1358,11 +1348,55 @@ index ce85f043..574c7609 100644 + free(s); + return 1; +} +diff --git a/kex.c b/kex.c +index 6b957e5e..19a56e8e 100644 +--- a/kex.c ++++ b/kex.c +@@ -297,17 +297,37 @@ static int + kex_compose_ext_info_server(struct ssh *ssh, struct sshbuf *m) + { + int r; ++ int have_key = 0; ++ int ext_count = 2; + - /* - * Fill out a proposal array with dynamically allocated values, which may - * be modified as required for compatibility reasons. -@@ -698,6 +755,9 @@ kex_free(struct kex *kex) ++#ifdef GSSAPI ++ /* ++ * Currently GSS KEX don't provide host keys as optional message, so ++ * no reasons to announce the publickey-hostbound extension ++ */ ++ if (ssh->kex->gss == NULL) ++ have_key = 1; ++#endif ++ ext_count += have_key; ++ + + if (ssh->kex->server_sig_algs == NULL && + (ssh->kex->server_sig_algs = sshkey_alg_list(0, 1, 1, ',')) == NULL) + return SSH_ERR_ALLOC_FAIL; +- if ((r = sshbuf_put_u32(m, 3)) != 0 || ++ if ((r = sshbuf_put_u32(m, ext_count)) != 0 || + (r = sshbuf_put_cstring(m, "server-sig-algs")) != 0 || +- (r = sshbuf_put_cstring(m, ssh->kex->server_sig_algs)) != 0 || +- (r = sshbuf_put_cstring(m, +- "publickey-hostbound@openssh.com")) != 0 || +- (r = sshbuf_put_cstring(m, "0")) != 0 || +- (r = sshbuf_put_cstring(m, "ping@openssh.com")) != 0 || ++ (r = sshbuf_put_cstring(m, ssh->kex->server_sig_algs)) != 0) { ++ error_fr(r, "compose"); ++ return r; ++ } ++ if (have_key) { ++ if ((r = sshbuf_put_cstring(m, "publickey-hostbound@openssh.com")) != 0 || ++ (r = sshbuf_put_cstring(m, "0")) != 0) { ++ error_fr(r, "compose"); ++ return r; ++ } ++ } ++ if ((r = sshbuf_put_cstring(m, "ping@openssh.com")) != 0 || + (r = sshbuf_put_cstring(m, "0")) != 0) { + error_fr(r, "compose"); + return r; +@@ -737,6 +757,9 @@ kex_free(struct kex *kex) sshbuf_free(kex->server_version); sshbuf_free(kex->client_pub); sshbuf_free(kex->session_id); @@ -1373,13 +1407,24 @@ index ce85f043..574c7609 100644 sshkey_free(kex->initial_hostkey); free(kex->failed_choice); diff --git a/kex.h b/kex.h -index a5ae6ac0..fe714141 100644 +index d08988b3..0e080ea3 100644 --- a/kex.h +++ b/kex.h -@@ -102,6 +102,15 @@ enum kex_exchange { - KEX_ECDH_SHA2, +@@ -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, @@ -1392,11 +1437,12 @@ index a5ae6ac0..fe714141 100644 KEX_MAX }; -@@ -153,6 +162,12 @@ struct kex { +@@ -165,6 +178,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; @@ -1405,18 +1451,18 @@ index a5ae6ac0..fe714141 100644 char *failed_choice; int (*verify_host_key)(struct sshkey *, struct ssh *); struct sshkey *(*load_host_public_key)(int, int, struct ssh *); -@@ -174,8 +189,10 @@ struct kex { - +@@ -191,8 +211,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_assemble_names(char **, 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 *); - void kex_proposal_free_entries(char *prop[PROPOSAL_MAX]); -@@ -202,6 +219,12 @@ int kexgex_client(struct ssh *); +@@ -226,6 +248,12 @@ int kexgex_client(struct ssh *); int kexgex_server(struct ssh *); int kex_gen_client(struct ssh *); int kex_gen_server(struct ssh *); @@ -1429,7 +1475,7 @@ index a5ae6ac0..fe714141 100644 int kex_dh_keypair(struct kex *); int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, -@@ -234,6 +257,12 @@ int kexgex_hash(int, const struct sshbuf *, const struct sshbuf *, +@@ -264,6 +292,12 @@ int kexgex_hash(int, const struct sshbuf *, const struct sshbuf *, const BIGNUM *, const u_char *, size_t, u_char *, size_t *); @@ -1443,10 +1489,10 @@ index a5ae6ac0..fe714141 100644 __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); diff --git a/kexdh.c b/kexdh.c -index 67133e33..edaa4676 100644 +index c1084f21..0faab21b 100644 --- a/kexdh.c +++ b/kexdh.c -@@ -48,13 +48,23 @@ kex_dh_keygen(struct kex *kex) +@@ -49,13 +49,23 @@ kex_dh_keygen(struct kex *kex) { switch (kex->kex_type) { case KEX_DH_GRP1_SHA1: @@ -1471,7 +1517,7 @@ index 67133e33..edaa4676 100644 break; case KEX_DH_GRP18_SHA512: diff --git a/kexgen.c b/kexgen.c -index 69348b96..c0e8c2f4 100644 +index 40d688d6..15df591c 100644 --- a/kexgen.c +++ b/kexgen.c @@ -44,7 +44,7 @@ @@ -1485,10 +1531,10 @@ index 69348b96..c0e8c2f4 100644 const struct sshbuf *client_version, diff --git a/kexgssc.c b/kexgssc.c new file mode 100644 -index 00000000..f6e1405e +index 00000000..96f7b6f5 --- /dev/null +++ b/kexgssc.c -@@ -0,0 +1,600 @@ +@@ -0,0 +1,706 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -1538,38 +1584,206 @@ index 00000000..f6e1405e + +#include "ssh-gss.h" + ++static int input_kexgss_hostkey(int, u_int32_t, struct ssh *); ++static int input_kexgss_continue(int, u_int32_t, struct ssh *); ++static int input_kexgss_complete(int, u_int32_t, struct ssh *); ++static int input_kexgss_error(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_group(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_continue(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_complete(int, u_int32_t, struct ssh *); ++ ++static int ++kexgss_final(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ struct sshbuf *empty = NULL; ++ struct sshbuf *shared_secret = NULL; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ int r; ++ ++ /* ++ * We _must_ have received a COMPLETE message in reply from the ++ * server, which will have set server_blob and msg_tok ++ */ ++ ++ /* compute shared secret */ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ case KEX_GSS_GRP14_SHA1: ++ case KEX_GSS_GRP14_SHA256: ++ case KEX_GSS_GRP16_SHA512: ++ r = kex_dh_dec(kex, gss->server_blob, &shared_secret); ++ break; ++ case KEX_GSS_C25519_SHA256: ++ if (sshbuf_ptr(gss->server_blob)[sshbuf_len(gss->server_blob)] & 0x80) ++ fatal("The received key has MSB of last octet set!"); ++ r = kex_c25519_dec(kex, gss->server_blob, &shared_secret); ++ break; ++ case KEX_GSS_NISTP256_SHA256: ++ if (sshbuf_len(gss->server_blob) != 65) ++ fatal("The received NIST-P256 key did not match " ++ "expected length (expected 65, got %zu)", ++ sshbuf_len(gss->server_blob)); ++ ++ if (sshbuf_ptr(gss->server_blob)[0] != POINT_CONVERSION_UNCOMPRESSED) ++ fatal("The received NIST-P256 key does not have first octet 0x04"); ++ ++ r = kex_ecdh_dec(kex, gss->server_blob, &shared_secret); ++ break; ++ default: ++ r = SSH_ERR_INVALID_ARGUMENT; ++ break; ++ } ++ if (r != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ goto out; ++ } ++ ++ if ((empty = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ hashlen = sizeof(hash); ++ r = kex_gen_hash(kex->hash_alg, kex->client_version, ++ kex->server_version, kex->my, kex->peer, ++ (gss->server_host_key_blob ? gss->server_host_key_blob : empty), ++ kex->client_pub, gss->server_blob, shared_secret, ++ hash, &hashlen); ++ sshbuf_free(empty); ++ if (r != 0) ++ fatal_f("Unexpected KEX type %d", kex->kex_type); ++ ++ gss->buf.value = hash; ++ gss->buf.length = hashlen; ++ ++ /* Verify that the hash matches the MIC we just got. */ ++ if (GSS_ERROR(ssh_gssapi_checkmic(gss, &gss->buf, &gss->msg_tok))) ++ sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); ++ ++ gss_release_buffer(&gss->minor, &gss->msg_tok); ++ ++ if (kex->gss_deleg_creds) ++ ssh_gssapi_credentials_updated(gss); ++ ++ if (gss_kex_context == NULL) ++ gss_kex_context = gss; ++ else ++ ssh_gssapi_delete_ctx(&kex->gss); ++ ++ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) ++ r = kex_send_newkeys(ssh); ++ ++ if (kex->gss != NULL) { ++ sshbuf_free(gss->server_host_key_blob); ++ gss->server_host_key_blob = NULL; ++ sshbuf_free(gss->server_blob); ++ gss->server_blob = NULL; ++ } ++out: ++ explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); ++ explicit_bzero(hash, sizeof(hash)); ++ sshbuf_free(shared_secret); ++ sshbuf_free(kex->client_pub); ++ kex->client_pub = NULL; ++ return r; ++} ++ ++static int ++kexgss_init_ctx(struct ssh *ssh, ++ gss_buffer_desc *token_ptr) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags; ++ int r; ++ ++ debug("Calling gss_init_sec_context"); ++ ++ gss->major = ssh_gssapi_init_ctx(gss, kex->gss_deleg_creds, ++ token_ptr, &send_tok, &ret_flags); ++ ++ if (GSS_ERROR(gss->major)) { ++ /* XXX Useless code: Missing send? */ ++ if (send_tok.length != 0) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ fatal("gss_init_context failed"); ++ } ++ ++ /* If we've got an old receive buffer get rid of it */ ++ if (token_ptr != GSS_C_NO_BUFFER) ++ gss_release_buffer(&gss->minor, token_ptr); ++ ++ if (gss->major == GSS_S_COMPLETE) { ++ /* If mutual state flag is not true, kex fails */ ++ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual authentication failed"); ++ ++ /* If integ avail flag is not true kex fails */ ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity check failed"); ++ } ++ ++ /* ++ * If we have data to send, then the last message that we ++ * received cannot have been a 'complete'. ++ */ ++ if (send_tok.length != 0) { ++ if (gss->first) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || ++ (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ gss->first = 0; ++ } else { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ } ++ if ((r = sshpkt_send(ssh)) != 0) ++ fatal("failed to send packet: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, &send_tok); ++ ++ /* If we've sent them data, they should reply */ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, &input_kexgss_hostkey); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgss_continue); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, &input_kexgss_complete); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, &input_kexgss_error); ++ return 0; ++ } ++ /* No data, and not complete */ ++ if (gss->major != GSS_S_COMPLETE) ++ fatal("Not complete, and no token output"); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgss_init_ctx(ssh, token_ptr); ++ ++ return kexgss_final(ssh); ++} ++ +int +kexgss_client(struct ssh *ssh) +{ + struct kex *kex = ssh->kex; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER, -+ recv_tok = GSS_C_EMPTY_BUFFER, -+ gssbuf, msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ struct sshbuf *server_blob = NULL; -+ struct sshbuf *shared_secret = NULL; -+ struct sshbuf *server_host_key_blob = NULL; -+ struct sshbuf *empty = NULL; -+ u_char *msg; -+ int type = 0; -+ int first = 1; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ u_char c; + int r; + + /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (ssh_gssapi_id_kex(kex->gss, kex->name, kex->kex_type) == GSS_C_NO_OID) + fatal("Couldn't identify host exchange"); + -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) ++ if (ssh_gssapi_import_name(kex->gss, kex->gss_host)) + fatal("Couldn't import hostname"); + + if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) ++ ssh_gssapi_client_identity(kex->gss, kex->gss_client)) + fatal("Couldn't acquire client credentials"); + + /* Step 1 */ @@ -1589,512 +1803,450 @@ index 00000000..f6e1405e + default: + fatal_f("Unexpected KEX type %d", kex->kex_type); + } -+ if (r != 0) ++ if (r != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); + return r; ++ } ++ return kexgss_init_ctx(ssh, GSS_C_NO_BUFFER); ++} + -+ token_ptr = GSS_C_NO_BUFFER; ++static int ++input_kexgss_hostkey(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ u_char *tmp = NULL; ++ size_t tmp_len = 0; ++ int r; + -+ do { -+ debug("Calling gss_init_sec_context"); ++ debug("Received KEXGSS_HOSTKEY"); ++ if (gss->server_host_key_blob) ++ fatal("Server host key received more than once"); ++ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) ++ fatal("Failed to read server host key: %s", ssh_err(r)); ++ if ((gss->server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) ++ fatal("sshbuf_from failed"); ++ return 0; ++} + -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); ++static int ++input_kexgss_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ int r; + -+ if (GSS_ERROR(maj_status)) { -+ /* XXX Useles code: Missing send? */ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_start(ssh, -+ SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("gss_init_context failed"); -+ } ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); + -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ gss_release_buffer(&min_status, &recv_tok); ++ debug("Received GSSAPI_CONTINUE"); ++ if (gss->major == GSS_S_COMPLETE) ++ fatal("GSSAPI Continue received from server when complete"); ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ if (!(gss->major & GSS_S_CONTINUE_NEEDED)) ++ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); ++ return kexgss_init_ctx(ssh, &recv_tok); ++} + -+ if (maj_status == GSS_S_COMPLETE) { -+ /* If mutual state flag is not true, kex fails */ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual authentication failed"); ++static int ++input_kexgss_complete(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ u_char c; ++ int r; + -+ /* If integ avail flag is not true kex fails */ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity check failed"); -+ } ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); + -+ /* -+ * If we have data to send, then the last message that we -+ * received cannot have been a 'complete'. -+ */ -+ if (send_tok.length != 0) { -+ if (first) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0 || -+ (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0) -+ fatal("failed to construct packet: %s", ssh_err(r)); -+ first = 0; -+ } else { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("failed to construct packet: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("failed to send packet: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); ++ debug("Received GSSAPI_COMPLETE"); ++ if (gss->msg_tok.value != NULL) ++ fatal("Received GSSAPI_COMPLETE twice?"); ++ if ((r = sshpkt_getb_froms(ssh, &gss->server_blob)) != 0 || ++ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &gss->msg_tok)) != 0) ++ fatal("Failed to read message: %s", ssh_err(r)); + -+ /* If we've sent them data, they should reply */ -+ do { -+ type = ssh_packet_read(ssh); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ debug("Received KEXGSS_HOSTKEY"); -+ if (server_host_key_blob) -+ fatal("Server host key received more than once"); -+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) -+ fatal("Failed to read server host key: %s", ssh_err(r)); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); ++ /* Is there a token included? */ ++ if ((r = sshpkt_get_u8(ssh, &c)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ if (c) { ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ /* If we're already complete - protocol error */ ++ if (gss->major == GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); ++ } else { ++ if (gss->major != GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); ++ } ++ if ((r = sshpkt_get_end(ssh)) != 0) ++ fatal("Expecting end of packet."); + -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("Failed to read token: %s", ssh_err(r)); -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ if (msg_tok.value != NULL) -+ fatal("Received GSSAPI_COMPLETE twice?"); -+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || -+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &msg_tok)) != 0) -+ fatal("Failed to read message: %s", ssh_err(r)); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgss_init_ctx(ssh, &recv_tok); + -+ /* Is there a token included? */ -+ if ((r = sshpkt_get_u8(ssh, &c)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if (c) { -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc( -+ ssh, &recv_tok)) != 0) -+ fatal("Failed to read token: %s", ssh_err(r)); -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); -+ } -+ if ((r = sshpkt_get_end(ssh)) != 0) { -+ fatal("Expecting end of packet."); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 || -+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || -+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt_get failed: %s", ssh_err(r)); -+ fatal("GSSAPI Error: \n%.400s", msg); -+ default: -+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ return kexgss_final(ssh); ++} ++ ++static int ++input_kexgss_error(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ u_char *msg; ++ int r; ++ ++ debug("Received Error"); ++ if ((r = sshpkt_get_u32(ssh, &gss->major)) != 0 || ++ (r = sshpkt_get_u32(ssh, &gss->minor)) != 0 || ++ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || ++ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt_get failed: %s", ssh_err(r)); ++ fatal("GSSAPI Error: \n%.400s", msg); ++ return 0; ++} ++ ++/*******************************************************/ ++/******************** KEXGSSGEX ************************/ ++/*******************************************************/ ++ ++int ++kexgssgex_client(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ int r; ++ ++ /* Initialise our GSSAPI world */ ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (ssh_gssapi_id_kex(kex->gss, kex->name, kex->kex_type) == GSS_C_NO_OID) ++ fatal("Couldn't identify host exchange"); ++ ++ if (ssh_gssapi_import_name(kex->gss, kex->gss_host)) ++ fatal("Couldn't import hostname"); ++ ++ if (kex->gss_client && ++ ssh_gssapi_client_identity(kex->gss, kex->gss_client)) ++ fatal("Couldn't acquire client credentials"); ++ ++ debug("Doing group exchange"); ++ kex->min = DH_GRP_MIN; ++ kex->max = DH_GRP_MAX; ++ kex->nbits = dh_estimate(kex->dh_need * 8); ++ ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->min)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || ++ (r = sshpkt_put_u32(ssh, kex->max)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("Failed to construct a packet: %s", ssh_err(r)); ++ ++ debug("Wait SSH2_MSG_KEXGSS_GROUP"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUP, &input_kexgssgex_group); ++ return 0; ++} ++ ++static int ++kexgssgex_final(struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ struct sshbuf *buf = NULL; ++ struct sshbuf *empty = NULL; ++ struct sshbuf *shared_secret = NULL; ++ BIGNUM *dh_server_pub = NULL; ++ const BIGNUM *pub_key, *dh_p, *dh_g; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ int r = SSH_ERR_INTERNAL_ERROR; + + /* + * We _must_ have received a COMPLETE message in reply from the + * server, which will have set server_blob and msg_tok + */ + -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) -+ fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); -+ -+ /* compute shared secret */ -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_dec(kex, server_blob, &shared_secret); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ if (sshbuf_ptr(server_blob)[sshbuf_len(server_blob)] & 0x80) -+ fatal("The received key has MSB of last octet set!"); -+ r = kex_c25519_dec(kex, server_blob, &shared_secret); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ if (sshbuf_len(server_blob) != 65) -+ fatal("The received NIST-P256 key did not match" -+ "expected length (expected 65, got %zu)", sshbuf_len(server_blob)); -+ -+ if (sshbuf_ptr(server_blob)[0] != POINT_CONVERSION_UNCOMPRESSED) -+ fatal("The received NIST-P256 key does not have first octet 0x04"); -+ -+ r = kex_ecdh_dec(kex, server_blob, &shared_secret); -+ break; -+ default: -+ r = SSH_ERR_INVALID_ARGUMENT; -+ break; -+ } -+ if (r != 0) ++ /* 7. C verifies that the key Q_S is valid */ ++ /* 8. C computes shared secret */ ++ if ((buf = sshbuf_new()) == NULL || ++ (r = sshbuf_put_stringb(buf, gss->server_blob)) != 0 || ++ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); + goto out; ++ } ++ sshbuf_free(buf); ++ buf = NULL; + -+ if ((empty = sshbuf_new()) == NULL) { ++ if ((shared_secret = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->my, -+ kex->peer, -+ (server_host_key_blob ? server_host_key_blob : empty), -+ kex->client_pub, -+ server_blob, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ fatal_f("Unexpected KEX type %d", kex->kex_type); ++ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ goto out; ++ } + -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; ++ if ((empty = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); ++ hashlen = sizeof(hash); ++ r = kexgex_hash(kex->hash_alg, kex->client_version, ++ kex->server_version, kex->my, kex->peer, ++ (gss->server_host_key_blob ? gss->server_host_key_blob : empty), ++ kex->min, kex->nbits, kex->max, dh_p, dh_g, pub_key, ++ dh_server_pub, sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), ++ hash, &hashlen); ++ sshbuf_free(empty); ++ if (r != 0) ++ fatal("Failed to calculate hash: %s", ssh_err(r)); ++ ++ gss->buf.value = hash; ++ gss->buf.length = hashlen; + + /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) ++ if (GSS_ERROR(ssh_gssapi_checkmic(gss, &gss->buf, &gss->msg_tok))) + sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); + -+ gss_release_buffer(&min_status, &msg_tok); ++ gss_release_buffer(&gss->minor, &gss->msg_tok); + + if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); ++ ssh_gssapi_credentials_updated(gss); + + if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; ++ gss_kex_context = gss; + else -+ ssh_gssapi_delete_ctx(&ctxt); ++ ssh_gssapi_delete_ctx(&kex->gss); + ++ /* Finally derive the keys and send them */ + if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); + ++ if (kex->gss != NULL) { ++ sshbuf_free(gss->server_host_key_blob); ++ gss->server_host_key_blob = NULL; ++ sshbuf_free(gss->server_blob); ++ gss->server_blob = NULL; ++ } +out: + explicit_bzero(hash, sizeof(hash)); -+ explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); -+ sshbuf_free(empty); -+ sshbuf_free(server_host_key_blob); -+ sshbuf_free(server_blob); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ BN_clear_free(dh_server_pub); + sshbuf_free(shared_secret); -+ sshbuf_free(kex->client_pub); -+ kex->client_pub = NULL; + return r; +} + -+int -+kexgssgex_client(struct ssh *ssh) ++static int ++kexgssgex_init_ctx(struct ssh *ssh, ++ gss_buffer_desc *token_ptr) +{ + struct kex *kex = ssh->kex; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER, -+ recv_tok = GSS_C_EMPTY_BUFFER, gssbuf, -+ msg_tok = GSS_C_EMPTY_BUFFER, *token_ptr; -+ Gssctxt *ctxt; -+ OM_uint32 maj_status, min_status, ret_flags; -+ struct sshbuf *shared_secret = NULL; -+ BIGNUM *p = NULL; -+ BIGNUM *g = NULL; -+ struct sshbuf *buf = NULL; -+ struct sshbuf *server_host_key_blob = NULL; -+ struct sshbuf *server_blob = NULL; -+ BIGNUM *dh_server_pub = NULL; -+ u_char *msg; -+ int type = 0; -+ int first = 1; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ const BIGNUM *pub_key, *dh_p, *dh_g; -+ int nbits = 0, min = DH_GRP_MIN, max = DH_GRP_MAX; -+ struct sshbuf *empty = NULL; -+ u_char c; ++ Gssctxt *gss = kex->gss; ++ const BIGNUM *pub_key; ++ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags; + int r; + -+ /* Initialise our GSSAPI world */ -+ ssh_gssapi_build_ctx(&ctxt); -+ if (ssh_gssapi_id_kex(ctxt, kex->name, kex->kex_type) -+ == GSS_C_NO_OID) -+ fatal("Couldn't identify host exchange"); ++ /* Step 2 - call GSS_Init_sec_context() */ ++ debug("Calling gss_init_sec_context"); + -+ if (ssh_gssapi_import_name(ctxt, kex->gss_host)) -+ fatal("Couldn't import hostname"); ++ gss->major = ssh_gssapi_init_ctx(gss, kex->gss_deleg_creds, ++ token_ptr, &send_tok, &ret_flags); + -+ if (kex->gss_client && -+ ssh_gssapi_client_identity(ctxt, kex->gss_client)) -+ fatal("Couldn't acquire client credentials"); ++ if (GSS_ERROR(gss->major)) { ++ /* XXX Useless code: Missing send? */ ++ if (send_tok.length != 0) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ fatal("gss_init_context failed"); ++ } + -+ debug("Doing group exchange"); -+ nbits = dh_estimate(kex->dh_need * 8); ++ /* If we've got an old receive buffer get rid of it */ ++ if (token_ptr != GSS_C_NO_BUFFER) ++ gss_release_buffer(&gss->minor, token_ptr); + -+ kex->min = DH_GRP_MIN; -+ kex->max = DH_GRP_MAX; -+ kex->nbits = nbits; -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_GROUPREQ)) != 0 || -+ (r = sshpkt_put_u32(ssh, min)) != 0 || -+ (r = sshpkt_put_u32(ssh, nbits)) != 0 || -+ (r = sshpkt_put_u32(ssh, max)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("Failed to construct a packet: %s", ssh_err(r)); ++ if (gss->major == GSS_S_COMPLETE) { ++ /* If mutual state flag is not true, kex fails */ ++ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual authentication failed"); + -+ if ((r = ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUP)) != 0) -+ fatal("Error: %s", ssh_err(r)); ++ /* If integ avail flag is not true kex fails */ ++ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity check failed"); ++ } ++ ++ /* ++ * If we have data to send, then the last message that we ++ * received cannot have been a 'complete'. ++ */ ++ if (send_tok.length != 0) { ++ if (gss->first) { ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ gss->first = 0; ++ } else { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ fatal("failed to construct packet: %s", ssh_err(r)); ++ } ++ if ((r = sshpkt_send(ssh)) != 0) ++ fatal("failed to send packet: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, &send_tok); ++ ++ /* If we've sent them data, they should reply */ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, &input_kexgss_hostkey); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgssgex_continue); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, &input_kexgssgex_complete); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, &input_kexgss_error); ++ return 0; ++ } ++ /* No data, and not complete */ ++ if (gss->major != GSS_S_COMPLETE) ++ fatal("Not complete, and no token output"); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgssgex_init_ctx(ssh, token_ptr); ++ ++ return kexgssgex_final(ssh); ++} ++ ++static int ++input_kexgssgex_group(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ BIGNUM *p = NULL; ++ BIGNUM *g = NULL; ++ int r; ++ ++ debug("Received SSH2_MSG_KEXGSS_GROUP"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUP, NULL); + + if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 || + (r = sshpkt_get_bignum2(ssh, &g)) != 0 || + (r = sshpkt_get_end(ssh)) != 0) + fatal("shpkt_get_bignum2 failed: %s", ssh_err(r)); + -+ if (BN_num_bits(p) < min || BN_num_bits(p) > max) ++ if (BN_num_bits(p) < kex->min || BN_num_bits(p) > kex->max) + fatal("GSSGRP_GEX group out of range: %d !< %d !< %d", -+ min, BN_num_bits(p), max); ++ kex->min, BN_num_bits(p), kex->max); + + if ((kex->dh = dh_new_group(g, p)) == NULL) + fatal("dn_new_group() failed"); + p = g = NULL; /* belong to kex->dh now */ + -+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) -+ goto out; -+ DH_get0_key(kex->dh, &pub_key, NULL); ++ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ return r; ++ } + -+ token_ptr = GSS_C_NO_BUFFER; ++ return kexgssgex_init_ctx(ssh, GSS_C_NO_BUFFER); ++} + -+ do { -+ /* Step 2 - call GSS_Init_sec_context() */ -+ debug("Calling gss_init_sec_context"); ++static int ++input_kexgssgex_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ int r; + -+ maj_status = ssh_gssapi_init_ctx(ctxt, -+ kex->gss_deleg_creds, token_ptr, &send_tok, -+ &ret_flags); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); + -+ if (GSS_ERROR(maj_status)) { -+ /* XXX Useles code: Missing send? */ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_start(ssh, -+ SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("gss_init_context failed"); -+ } -+ -+ /* If we've got an old receive buffer get rid of it */ -+ if (token_ptr != GSS_C_NO_BUFFER) -+ gss_release_buffer(&min_status, &recv_tok); -+ -+ if (maj_status == GSS_S_COMPLETE) { -+ /* If mutual state flag is not true, kex fails */ -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual authentication failed"); -+ -+ /* If integ avail flag is not true kex fails */ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity check failed"); -+ } -+ -+ /* -+ * If we have data to send, then the last message that we -+ * received cannot have been a 'complete'. -+ */ -+ if (send_tok.length != 0) { -+ if (first) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_INIT)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, -+ send_tok.length)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ first = 0; -+ } else { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh,send_tok.value, -+ send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt_send failed: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ -+ /* If we've sent them data, they should reply */ -+ do { -+ type = ssh_packet_read(ssh); -+ if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ debug("Received KEXGSS_HOSTKEY"); -+ if (server_host_key_blob) -+ fatal("Server host key received more than once"); -+ if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ } while (type == SSH2_MSG_KEXGSS_HOSTKEY); -+ -+ switch (type) { -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ debug("Received GSSAPI_CONTINUE"); -+ if (maj_status == GSS_S_COMPLETE) -+ fatal("GSSAPI Continue received from server when complete"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ case SSH2_MSG_KEXGSS_COMPLETE: -+ debug("Received GSSAPI_COMPLETE"); -+ if (msg_tok.value != NULL) -+ fatal("Received GSSAPI_COMPLETE twice?"); -+ if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 || -+ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &msg_tok)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ /* Is there a token included? */ -+ if ((r = sshpkt_get_u8(ssh, &c)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ if (c) { -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc( -+ ssh, &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ /* If we're already complete - protocol error */ -+ if (maj_status == GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); -+ } else { -+ /* No token included */ -+ if (maj_status != GSS_S_COMPLETE) -+ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); -+ } -+ break; -+ case SSH2_MSG_KEXGSS_ERROR: -+ debug("Received Error"); -+ if ((r = sshpkt_get_u32(ssh, &maj_status)) != 0 || -+ (r = sshpkt_get_u32(ssh, &min_status)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0 || -+ (r = sshpkt_get_string(ssh, NULL, NULL)) != 0 || /* lang tag */ -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ fatal("GSSAPI Error: \n%.400s", msg); -+ default: -+ sshpkt_disconnect(ssh, "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ token_ptr = &recv_tok; -+ } else { -+ /* No data, and not complete */ -+ if (maj_status != GSS_S_COMPLETE) -+ fatal("Not complete, and no token output"); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ /* -+ * We _must_ have received a COMPLETE message in reply from the -+ * server, which will have set dh_server_pub and msg_tok -+ */ -+ -+ if (type != SSH2_MSG_KEXGSS_COMPLETE) ++ debug("Received GSSAPI_CONTINUE"); ++ if (gss->major == GSS_S_COMPLETE) ++ fatal("GSSAPI Continue received from server when complete"); ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ if (!(gss->major & GSS_S_CONTINUE_NEEDED)) + fatal("Didn't receive a SSH2_MSG_KEXGSS_COMPLETE when I expected it"); ++ return kexgssgex_init_ctx(ssh, &recv_tok); ++} + -+ /* 7. C verifies that the key Q_S is valid */ -+ /* 8. C computes shared secret */ -+ if ((buf = sshbuf_new()) == NULL || -+ (r = sshbuf_put_stringb(buf, server_blob)) != 0 || -+ (r = sshbuf_get_bignum2(buf, &dh_server_pub)) != 0) -+ goto out; -+ sshbuf_free(buf); -+ buf = NULL; ++static int ++input_kexgssgex_complete(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER; ++ u_char c; ++ int r; + -+ if ((shared_secret = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_HOSTKEY, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_COMPLETE, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_ERROR, NULL); ++ ++ debug("Received GSSAPI_COMPLETE"); ++ if (gss->msg_tok.value != NULL) ++ fatal("Received GSSAPI_COMPLETE twice?"); ++ if ((r = sshpkt_getb_froms(ssh, &gss->server_blob)) != 0 || ++ (r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &gss->msg_tok)) != 0) ++ fatal("Failed to read message: %s", ssh_err(r)); ++ ++ /* Is there a token included? */ ++ if ((r = sshpkt_get_u8(ssh, &c)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ if (c) { ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0) ++ fatal("Failed to read token: %s", ssh_err(r)); ++ /* If we're already complete - protocol error */ ++ if (gss->major == GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: received token when complete"); ++ } else { ++ if (gss->major != GSS_S_COMPLETE) ++ sshpkt_disconnect(ssh, "Protocol error: did not receive final token"); + } ++ if ((r = sshpkt_get_end(ssh)) != 0) ++ fatal("Expecting end of packet."); + -+ if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) -+ goto out; -+ if ((empty = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return kexgssgex_init_ctx(ssh, &recv_tok); + -+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); -+ hashlen = sizeof(hash); -+ if ((r = kexgex_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->my, -+ kex->peer, -+ (server_host_key_blob ? server_host_key_blob : empty), -+ kex->min, kex->nbits, kex->max, -+ dh_p, dh_g, -+ pub_key, -+ dh_server_pub, -+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), -+ hash, &hashlen)) != 0) -+ fatal("Failed to calculate hash: %s", ssh_err(r)); -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ /* Verify that the hash matches the MIC we just got. */ -+ if (GSS_ERROR(ssh_gssapi_checkmic(ctxt, &gssbuf, &msg_tok))) -+ sshpkt_disconnect(ssh, "Hash's MIC didn't verify"); -+ -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ if (kex->gss_deleg_creds) -+ ssh_gssapi_credentials_updated(ctxt); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ /* Finally derive the keys and send them */ -+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) -+ r = kex_send_newkeys(ssh); -+out: -+ sshbuf_free(buf); -+ sshbuf_free(server_blob); -+ sshbuf_free(empty); -+ explicit_bzero(hash, sizeof(hash)); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ BN_clear_free(dh_server_pub); -+ sshbuf_free(shared_secret); -+ sshbuf_free(server_host_key_blob); -+ return r; ++ gss_release_buffer(&gss->minor, &recv_tok); ++ return kexgssgex_final(ssh); +} + +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ diff --git a/kexgsss.c b/kexgsss.c new file mode 100644 -index 00000000..60bc02de +index 00000000..8362081e --- /dev/null +++ b/kexgsss.c -@@ -0,0 +1,474 @@ +@@ -0,0 +1,601 @@ +/* + * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. + * @@ -2147,33 +2299,18 @@ index 00000000..60bc02de + +extern ServerOptions options; + ++static int input_kexgss_init(int, u_int32_t, struct ssh *); ++static int input_kexgss_continue(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_groupreq(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_init(int, u_int32_t, struct ssh *); ++static int input_kexgssgex_continue(int, u_int32_t, struct ssh *); ++ +int +kexgss_server(struct ssh *ssh) +{ + struct kex *kex = ssh->kex; -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ struct sshbuf *shared_secret = NULL; -+ struct sshbuf *client_pubkey = NULL; -+ struct sshbuf *server_pubkey = NULL; -+ struct sshbuf *empty = sshbuf_new(); -+ int type = 0; + gss_OID oid; + char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ int r; + + /* Initialise GSSAPI */ + @@ -2189,127 +2326,94 @@ index 00000000..60bc02de + debug2_f("Identifying %s", kex->name); + oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); + if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); ++ fatal("Unknown gssapi mechanism"); + + debug2_f("Acquiring credentials"); + -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ if (GSS_ERROR(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) + fatal("Unable to acquire credentials for the server"); + -+ do { -+ debug("Wait SSH2_MSG_KEXGSS_INIT"); -+ type = ssh_packet_read(ssh); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (client_pubkey != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (kex->gss == NULL) ++ fatal("Unable to allocate memory for gss context"); + -+ switch (kex->kex_type) { -+ case KEX_GSS_GRP1_SHA1: -+ case KEX_GSS_GRP14_SHA1: -+ case KEX_GSS_GRP14_SHA256: -+ case KEX_GSS_GRP16_SHA512: -+ r = kex_dh_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ case KEX_GSS_NISTP256_SHA256: -+ r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ case KEX_GSS_C25519_SHA256: -+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ break; -+ default: -+ fatal_f("Unexpected KEX type %d", kex->kex_type); -+ } -+ if (r != 0) -+ goto out; ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, &input_kexgss_init); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgss_continue); ++ debug("Wait SSH2_MSG_KEXGSS_INIT"); ++ return 0; ++} + -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ default: -+ sshpkt_disconnect(ssh, -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } ++static inline void ++kexgss_accept_ctx(struct ssh *ssh, ++ gss_buffer_desc *recv_tok, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ int r; + -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); ++ gss->major = mm_ssh_gssapi_accept_ctx(gss, recv_tok, send_tok, ret_flags); ++ gss_release_buffer(&gss->minor, recv_tok); + -+ gss_release_buffer(&min_status, &recv_tok); ++ if (gss->major != GSS_S_COMPLETE && send_tok->length == 0) ++ fatal("Zero length token output when incomplete"); + -+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) -+ fatal("Zero length token output when incomplete"); ++ if (gss->buf.value == NULL) ++ fatal("No client public key"); + -+ if (client_pubkey == NULL) -+ fatal("No client public key"); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) { ++ debug("Sending GSSAPI_CONTINUE"); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, send_tok); ++ } ++} + -+ if (maj_status & GSS_S_CONTINUE_NEEDED) { -+ debug("Sending GSSAPI_CONTINUE"); ++static inline int ++kexgss_final(struct ssh *ssh, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ gss_buffer_desc msg_tok; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ struct sshbuf *shared_secret = NULL; ++ int r; ++ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ++ if (GSS_ERROR(gss->major)) { ++ if (send_tok->length > 0) { + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length > 0) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || + (r = sshpkt_send(ssh)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + } + fatal("accept_ctx died"); + } + -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) ++ if (!(*ret_flags & GSS_C_MUTUAL_FLAG)) + fatal("Mutual Authentication flag wasn't set"); + -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) ++ if (!(*ret_flags & GSS_C_INTEG_FLAG)) + fatal("Integrity flag wasn't set"); + -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->peer, -+ kex->my, -+ empty, -+ client_pubkey, -+ server_pubkey, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ goto out; -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) ++ if (GSS_ERROR(mm_ssh_gssapi_sign(gss, &gss->buf, &msg_tok))) + fatal("Couldn't get MIC"); + + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || -+ (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 || ++ (r = sshpkt_put_stringb(ssh, gss->server_pubkey)) != 0 || + (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + -+ if (send_tok.length != 0) { ++ if (send_tok->length != 0) { + if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); + } else { + if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ @@ -2318,13 +2422,19 @@ index 00000000..60bc02de + if ((r = sshpkt_send(ssh)) != 0) + fatal("sshpkt_send failed: %s", ssh_err(r)); + -+ gss_release_buffer(&min_status, &send_tok); -+ gss_release_buffer(&min_status, &msg_tok); ++ gss_release_buffer(&gss->minor, send_tok); ++ gss_release_buffer(&gss->minor, &msg_tok); ++ ++ hashlen = gss->hashlen; ++ memcpy(hash, gss->hash, hashlen); ++ explicit_bzero(gss->hash, sizeof(gss->hash)); ++ shared_secret = gss->shared_secret; ++ gss->shared_secret = NULL; + + if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; ++ gss_kex_context = gss; + else -+ ssh_gssapi_delete_ctx(&ctxt); ++ ssh_gssapi_delete_ctx(&kex->gss); + + if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) + r = kex_send_newkeys(ssh); @@ -2333,44 +2443,126 @@ index 00000000..60bc02de + * just exchanged. */ + if (options.gss_store_rekey) + ssh_gssapi_rekey_creds(); -+out: -+ sshbuf_free(empty); ++ ++ if (kex->gss != NULL) { ++ sshbuf_free(gss->server_pubkey); ++ gss->server_pubkey = NULL; ++ } + explicit_bzero(hash, sizeof(hash)); + sshbuf_free(shared_secret); -+ sshbuf_free(client_pubkey); -+ sshbuf_free(server_pubkey); + return r; +} + ++static int ++input_kexgss_init(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ struct sshbuf *empty; ++ struct sshbuf *client_pubkey = NULL; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ debug("SSH2_MSG_KEXGSS_INIT received"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ switch (kex->kex_type) { ++ case KEX_GSS_GRP1_SHA1: ++ case KEX_GSS_GRP14_SHA1: ++ case KEX_GSS_GRP14_SHA256: ++ case KEX_GSS_GRP16_SHA512: ++ r = kex_dh_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ case KEX_GSS_NISTP256_SHA256: ++ r = kex_ecdh_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ case KEX_GSS_C25519_SHA256: ++ r = kex_c25519_enc(kex, client_pubkey, &gss->server_pubkey, &gss->shared_secret); ++ break; ++ default: ++ fatal_f("Unexpected KEX type %d", kex->kex_type); ++ } ++ if (r != 0) { ++ sshbuf_free(client_pubkey); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return r; ++ } ++ ++ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ ++ ++ if ((empty = sshbuf_new()) == NULL) { ++ sshbuf_free(client_pubkey); ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return SSH_ERR_ALLOC_FAIL; ++ } ++ ++ /* Calculate the hash early so we can free the ++ * client_pubkey, which has reference to the parent ++ * buffer state->incoming_packet ++ */ ++ gss->hashlen = sizeof(gss->hash); ++ r = kex_gen_hash(kex->hash_alg, kex->client_version, kex->server_version, ++ kex->peer, kex->my, empty, client_pubkey, gss->server_pubkey, ++ gss->shared_secret, gss->hash, &gss->hashlen); ++ sshbuf_free(empty); ++ sshbuf_free(client_pubkey); ++ if (r != 0) { ++ gss_release_buffer(&gss->minor, &recv_tok); ++ ssh_gssapi_delete_ctx(&kex->gss); ++ return r; ++ } ++ ++ gss->buf.value = gss->hash; ++ gss->buf.length = gss->hashlen; ++ ++ kexgss_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgss_final(ssh, &send_tok, &ret_flags); ++} ++ ++static int ++input_kexgss_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ kexgss_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgss_final(ssh, &send_tok, &ret_flags); ++} ++ ++/*******************************************************/ ++/******************** KEXGSSGEX ************************/ ++/*******************************************************/ ++ +int +kexgssgex_server(struct ssh *ssh) +{ + struct kex *kex = ssh->kex; -+ OM_uint32 maj_status, min_status; -+ -+ /* -+ * Some GSSAPI implementations use the input value of ret_flags (an -+ * output variable) as a means of triggering mechanism specific -+ * features. Initializing it to zero avoids inadvertently -+ * activating this non-standard behaviour. -+ */ -+ -+ OM_uint32 ret_flags = 0; -+ gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; -+ Gssctxt *ctxt = NULL; -+ struct sshbuf *shared_secret = NULL; -+ int type = 0; + gss_OID oid; + char *mechs; -+ u_char hash[SSH_DIGEST_MAX_LENGTH]; -+ size_t hashlen; -+ BIGNUM *dh_client_pub = NULL; -+ const BIGNUM *pub_key, *dh_p, *dh_g; -+ int min = -1, max = -1, nbits = -1; -+ int cmin = -1, cmax = -1; /* client proposal */ -+ struct sshbuf *empty = sshbuf_new(); -+ int r; + + /* Initialise GSSAPI */ + @@ -2378,29 +2570,194 @@ index 00000000..60bc02de + * in the GSSAPI code are no longer available. This kludges them back + * into life + */ -+ if (!ssh_gssapi_oid_table_ok()) -+ if ((mechs = ssh_gssapi_server_mechanisms())) -+ free(mechs); ++ if (!ssh_gssapi_oid_table_ok()) { ++ mechs = ssh_gssapi_server_mechanisms(); ++ free(mechs); ++ } + + debug2_f("Identifying %s", kex->name); + oid = ssh_gssapi_id_kex(NULL, kex->name, kex->kex_type); + if (oid == GSS_C_NO_OID) -+ fatal("Unknown gssapi mechanism"); ++ fatal("Unknown gssapi mechanism"); + + debug2_f("Acquiring credentials"); + -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) ++ if (GSS_ERROR(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) + fatal("Unable to acquire credentials for the server"); + -+ /* 5. S generates an ephemeral key pair (do the allocations early) */ ++ ssh_gssapi_build_ctx(&kex->gss); ++ if (kex->gss == NULL) ++ fatal("Unable to allocate memory for gss context"); ++ + debug("Doing group exchange"); -+ ssh_packet_read_expect(ssh, SSH2_MSG_KEXGSS_GROUPREQ); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUPREQ, &input_kexgssgex_groupreq); ++ return 0; ++} ++ ++static inline void ++kexgssgex_accept_ctx(struct ssh *ssh, ++ gss_buffer_desc *recv_tok, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ int r; ++ ++ gss->major = mm_ssh_gssapi_accept_ctx(gss, recv_tok, send_tok, ret_flags); ++ gss_release_buffer(&gss->minor, recv_tok); ++ ++ if (gss->major != GSS_S_COMPLETE && send_tok->length == 0) ++ fatal("Zero length token output when incomplete"); ++ ++ if (gss->dh_client_pub == NULL) ++ fatal("No client public key"); ++ ++ if (gss->major & GSS_S_CONTINUE_NEEDED) { ++ debug("Sending GSSAPI_CONTINUE"); ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ gss_release_buffer(&gss->minor, send_tok); ++ } ++} ++ ++static inline int ++kexgssgex_final(struct ssh *ssh, ++ gss_buffer_desc *send_tok, ++ OM_uint32 *ret_flags) ++{ ++ struct kex *kex = ssh->kex; ++ Gssctxt *gss = kex->gss; ++ gss_buffer_desc msg_tok; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t hashlen; ++ const BIGNUM *pub_key, *dh_p, *dh_g; ++ struct sshbuf *shared_secret = NULL; ++ struct sshbuf *empty = NULL; ++ int r; ++ ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); ++ ++ if (GSS_ERROR(gss->major)) { ++ if (send_tok->length > 0) { ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || ++ (r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ fatal("accept_ctx died"); ++ } ++ ++ if (!(*ret_flags & GSS_C_MUTUAL_FLAG)) ++ fatal("Mutual Authentication flag wasn't set"); ++ ++ if (!(*ret_flags & GSS_C_INTEG_FLAG)) ++ fatal("Integrity flag wasn't set"); ++ ++ /* calculate shared secret */ ++ shared_secret = sshbuf_new(); ++ if (shared_secret == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if ((r = kex_dh_compute_key(kex, gss->dh_client_pub, shared_secret)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ goto out; ++ } ++ ++ if ((empty = sshbuf_new()) == NULL) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ DH_get0_key(kex->dh, &pub_key, NULL); ++ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); ++ hashlen = sizeof(hash); ++ r = kexgex_hash(kex->hash_alg, kex->client_version, kex->server_version, ++ kex->peer, kex->my, empty, kex->min, kex->nbits, kex->max, dh_p, dh_g, ++ gss->dh_client_pub, pub_key, sshbuf_ptr(shared_secret), ++ sshbuf_len(shared_secret), hash, &hashlen); ++ sshbuf_free(empty); ++ if (r != 0) ++ fatal("kexgex_hash failed: %s", ssh_err(r)); ++ ++ gss->buf.value = hash; ++ gss->buf.length = hashlen; ++ ++ if (GSS_ERROR(mm_ssh_gssapi_sign(gss, &gss->buf, &msg_tok))) ++ fatal("Couldn't get MIC"); ++ ++ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || ++ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || ++ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ if (send_tok->length != 0) { ++ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ ++ (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } else { ++ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ } ++ if ((r = sshpkt_send(ssh)) != 0) ++ fatal("sshpkt_send failed: %s", ssh_err(r)); ++ ++ gss_release_buffer(&gss->minor, send_tok); ++ gss_release_buffer(&gss->minor, &msg_tok); ++ ++ if (gss_kex_context == NULL) ++ gss_kex_context = gss; ++ else ++ ssh_gssapi_delete_ctx(&kex->gss); ++ ++ /* Finally derive the keys and send them */ ++ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) ++ r = kex_send_newkeys(ssh); ++ ++ /* If this was a rekey, then save out any delegated credentials we ++ * just exchanged. */ ++ if (options.gss_store_rekey) ++ ssh_gssapi_rekey_creds(); ++ ++ if (kex->gss != NULL) ++ BN_clear_free(gss->dh_client_pub); ++ ++out: ++ explicit_bzero(hash, sizeof(hash)); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ sshbuf_free(shared_secret); ++ return r; ++} ++ ++static int ++input_kexgssgex_groupreq(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ struct kex *kex = ssh->kex; ++ const BIGNUM *dh_p, *dh_g; ++ int min = -1, max = -1, nbits = -1; ++ int cmin = -1, cmax = -1; /* client proposal */ ++ int r; ++ ++ /* 5. S generates an ephemeral key pair (do the allocations early) */ ++ ++ debug("SSH2_MSG_KEXGSS_GROUPREQ received"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_GROUPREQ, NULL); ++ + /* store client proposal to provide valid signature */ + if ((r = sshpkt_get_u32(ssh, &cmin)) != 0 || + (r = sshpkt_get_u32(ssh, &nbits)) != 0 || + (r = sshpkt_get_u32(ssh, &cmax)) != 0 || + (r = sshpkt_get_end(ssh)) != 0) + fatal("sshpkt failed: %s", ssh_err(r)); ++ + kex->nbits = nbits; + kex->min = cmin; + kex->max = cmax; @@ -2408,10 +2765,11 @@ index 00000000..60bc02de + max = MIN(DH_GRP_MAX, cmax); + nbits = MAXIMUM(DH_GRP_MIN, nbits); + nbits = MINIMUM(DH_GRP_MAX, nbits); ++ + if (max < min || nbits < min || max < nbits) -+ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", -+ min, nbits, max); -+ kex->dh = PRIVSEP(choose_dh(min, nbits, max)); ++ fatal("GSS_GEX, bad parameters: %d !< %d !< %d", min, nbits, max); ++ ++ kex->dh = mm_choose_dh(min, nbits, max); + if (kex->dh == NULL) { + sshpkt_disconnect(ssh, "Protocol error: no matching group found"); + fatal("Protocol error: no matching group found"); @@ -2428,152 +2786,73 @@ index 00000000..60bc02de + fatal("ssh_packet_write_wait: %s", ssh_err(r)); + + /* Compute our exchange value in parallel with the client */ -+ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) -+ goto out; -+ -+ do { -+ debug("Wait SSH2_MSG_GSSAPI_INIT"); -+ type = ssh_packet_read(ssh); -+ switch(type) { -+ case SSH2_MSG_KEXGSS_INIT: -+ if (dh_client_pub != NULL) -+ fatal("Received KEXGSS_INIT after initialising"); -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ -+ break; -+ case SSH2_MSG_KEXGSS_CONTINUE: -+ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -+ &recv_tok)) != 0 || -+ (r = sshpkt_get_end(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ break; -+ default: -+ sshpkt_disconnect(ssh, -+ "Protocol error: didn't expect packet type %d", -+ type); -+ } -+ -+ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(ctxt, &recv_tok, -+ &send_tok, &ret_flags)); -+ -+ gss_release_buffer(&min_status, &recv_tok); -+ -+ if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) -+ fatal("Zero length token output when incomplete"); -+ -+ if (dh_client_pub == NULL) -+ fatal("No client public key"); -+ -+ if (maj_status & GSS_S_CONTINUE_NEEDED) { -+ debug("Sending GSSAPI_CONTINUE"); -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ gss_release_buffer(&min_status, &send_tok); -+ } -+ } while (maj_status & GSS_S_CONTINUE_NEEDED); -+ -+ if (GSS_ERROR(maj_status)) { -+ if (send_tok.length > 0) { -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || -+ (r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ fatal("accept_ctx died"); ++ if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) { ++ ssh_gssapi_delete_ctx(&kex->gss); ++ DH_free(kex->dh); ++ kex->dh = NULL; ++ return r; + } + -+ if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -+ fatal("Mutual Authentication flag wasn't set"); -+ -+ if (!(ret_flags & GSS_C_INTEG_FLAG)) -+ fatal("Integrity flag wasn't set"); -+ -+ /* calculate shared secret */ -+ if ((shared_secret = sshbuf_new()) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0) -+ goto out; -+ -+ DH_get0_key(kex->dh, &pub_key, NULL); -+ DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); -+ hashlen = sizeof(hash); -+ if ((r = kexgex_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->peer, -+ kex->my, -+ empty, -+ cmin, nbits, cmax, -+ dh_p, dh_g, -+ dh_client_pub, -+ pub_key, -+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), -+ hash, &hashlen)) != 0) -+ fatal("kexgex_hash failed: %s", ssh_err(r)); -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) -+ fatal("Couldn't get MIC"); -+ -+ if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_COMPLETE)) != 0 || -+ (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || -+ (r = sshpkt_put_string(ssh, msg_tok.value, msg_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ if (send_tok.length != 0) { -+ if ((r = sshpkt_put_u8(ssh, 1)) != 0 || /* true */ -+ (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } else { -+ if ((r = sshpkt_put_u8(ssh, 0)) != 0) /* false */ -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ } -+ if ((r = sshpkt_send(ssh)) != 0) -+ fatal("sshpkt failed: %s", ssh_err(r)); -+ -+ gss_release_buffer(&min_status, &send_tok); -+ gss_release_buffer(&min_status, &msg_tok); -+ -+ if (gss_kex_context == NULL) -+ gss_kex_context = ctxt; -+ else -+ ssh_gssapi_delete_ctx(&ctxt); -+ -+ /* Finally derive the keys and send them */ -+ if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) -+ r = kex_send_newkeys(ssh); -+ -+ /* If this was a rekey, then save out any delegated credentials we -+ * just exchanged. */ -+ if (options.gss_store_rekey) -+ ssh_gssapi_rekey_creds(); -+out: -+ sshbuf_free(empty); -+ explicit_bzero(hash, sizeof(hash)); -+ DH_free(kex->dh); -+ kex->dh = NULL; -+ BN_clear_free(dh_client_pub); -+ sshbuf_free(shared_secret); -+ return r; ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, &input_kexgssgex_init); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, &input_kexgssgex_continue); ++ debug("Wait SSH2_MSG_KEXGSS_INIT"); ++ return 0; +} ++ ++static int ++input_kexgssgex_init(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ debug("SSH2_MSG_KEXGSS_INIT received"); ++ ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_INIT, NULL); ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_bignum2(ssh, &gss->dh_client_pub)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ ++ ++ kexgssgex_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgssgex_final(ssh, &send_tok, &ret_flags); ++} ++ ++static int ++input_kexgssgex_continue(int type, ++ u_int32_t seq, ++ struct ssh *ssh) ++{ ++ Gssctxt *gss = ssh->kex->gss; ++ gss_buffer_desc recv_tok, send_tok = GSS_C_EMPTY_BUFFER; ++ OM_uint32 ret_flags = 0; ++ int r; ++ ++ if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, &recv_tok)) != 0 || ++ (r = sshpkt_get_end(ssh)) != 0) ++ fatal("sshpkt failed: %s", ssh_err(r)); ++ ++ kexgssgex_accept_ctx(ssh, &recv_tok, &send_tok, &ret_flags); ++ if (gss->major & GSS_S_CONTINUE_NEEDED) ++ return 0; ++ ++ return kexgssgex_final(ssh, &send_tok, &ret_flags); ++} ++ +#endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ diff --git a/monitor.c b/monitor.c -index 2ce89fe9..ebf76c7f 100644 +index 02b3eaaa..2ef16cc8 100644 --- a/monitor.c +++ b/monitor.c -@@ -148,6 +148,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); +@@ -147,6 +147,8 @@ int mm_answer_gss_setup_ctx(struct ssh *, int, struct sshbuf *); int mm_answer_gss_accept_ctx(struct ssh *, int, struct sshbuf *); int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *); int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *); @@ -2582,7 +2861,7 @@ index 2ce89fe9..ebf76c7f 100644 #endif #ifdef SSH_AUDIT_EVENTS -@@ -220,11 +222,18 @@ struct mon_table mon_dispatch_proto20[] = { +@@ -224,11 +226,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}, @@ -2598,11 +2877,11 @@ index 2ce89fe9..ebf76c7f 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}, - #endif -@@ -293,6 +302,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) - /* Permit requests for moduli and signatures */ +@@ -299,6 +308,10 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) + monitor_permit(mon_dispatch, MONITOR_REQ_STATE, 1); monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); +#ifdef GSSAPI @@ -2612,7 +2891,7 @@ index 2ce89fe9..ebf76c7f 100644 /* The first few requests do not require asynchronous access */ while (!authenticated) { -@@ -376,8 +376,15 @@ monitor_child_preauth(struct ssh *ssh, s +@@ -351,8 +364,15 @@ monitor_child_preauth(struct ssh *ssh, struct monitor *pmonitor) if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) { auth_log(ssh, authenticated, partial, auth_method, auth_submethod); @@ -2629,7 +2908,7 @@ index 2ce89fe9..ebf76c7f 100644 if (authenticated || partial) { auth2_update_session_info(authctxt, auth_method, auth_submethod); -@@ -406,6 +419,10 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) +@@ -421,6 +441,10 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1); monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1); monitor_permit(mon_dispatch, MONITOR_REQ_TERM, 1); @@ -2640,7 +2919,7 @@ index 2ce89fe9..ebf76c7f 100644 if (auth_opts->permit_pty_flag) { monitor_permit(mon_dispatch, MONITOR_REQ_PTY, 1); -@@ -1713,6 +1730,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) +@@ -1890,6 +1914,17 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kex_gen_server; # endif @@ -2658,7 +2937,7 @@ index 2ce89fe9..ebf76c7f 100644 #endif /* WITH_OPENSSL */ kex->kex[KEX_C25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; -@@ -1806,8 +1834,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -1981,8 +2016,8 @@ mm_answer_gss_setup_ctx(struct ssh *ssh, int sock, struct sshbuf *m) u_char *p; int r; @@ -2669,7 +2948,7 @@ index 2ce89fe9..ebf76c7f 100644 if ((r = sshbuf_get_string(m, &p, &len)) != 0) fatal_fr(r, "parse"); -@@ -1839,8 +1867,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -2014,8 +2049,8 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) OM_uint32 flags = 0; /* GSI needs this */ int r; @@ -2680,7 +2959,7 @@ index 2ce89fe9..ebf76c7f 100644 if ((r = ssh_gssapi_get_buffer_desc(m, &in)) != 0) fatal_fr(r, "ssh_gssapi_get_buffer_desc"); -@@ -1860,6 +1888,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -2035,6 +2070,7 @@ mm_answer_gss_accept_ctx(struct ssh *ssh, int sock, struct sshbuf *m) monitor_permit(mon_dispatch, MONITOR_REQ_GSSSTEP, 0); monitor_permit(mon_dispatch, MONITOR_REQ_GSSUSEROK, 1); monitor_permit(mon_dispatch, MONITOR_REQ_GSSCHECKMIC, 1); @@ -2688,7 +2967,7 @@ index 2ce89fe9..ebf76c7f 100644 } return (0); } -@@ -1871,8 +1900,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -2046,8 +2082,8 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) OM_uint32 ret; int r; @@ -2699,7 +2978,7 @@ index 2ce89fe9..ebf76c7f 100644 if ((r = ssh_gssapi_get_buffer_desc(m, &gssbuf)) != 0 || (r = ssh_gssapi_get_buffer_desc(m, &mic)) != 0) -@@ -1898,13 +1927,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -2073,13 +2109,17 @@ mm_answer_gss_checkmic(struct ssh *ssh, int sock, struct sshbuf *m) int mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) { @@ -2711,17 +2990,17 @@ index 2ce89fe9..ebf76c7f 100644 - fatal_f("GSSAPI authentication not enabled"); + if (!options.gss_authentication && !options.gss_keyex) + fatal_f("GSSAPI not enabled"); - -- 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); + authenticated = authctxt->valid && + ssh_gssapi_userok(authctxt->user, authctxt->pw, kex); sshbuf_reset(m); if ((r = sshbuf_put_u32(m, authenticated)) != 0) -@@ -1913,7 +1946,11 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -2088,7 +2128,11 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) debug3_f("sending result %d", authenticated); mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m); @@ -2734,7 +3013,7 @@ index 2ce89fe9..ebf76c7f 100644 if ((displayname = ssh_gssapi_displayname()) != NULL) auth2_record_info(authctxt, "%s", displayname); -@@ -1921,5 +1958,84 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) +@@ -2096,5 +2140,84 @@ mm_answer_gss_userok(struct ssh *ssh, int sock, struct sshbuf *m) /* Monitor loop will terminate if authenticated */ return (authenticated); } @@ -2820,10 +3099,10 @@ index 2ce89fe9..ebf76c7f 100644 #endif /* GSSAPI */ diff --git a/monitor.h b/monitor.h -index 683e5e07..2b1a2d59 100644 +index 9dcd9c29..dbc7e003 100644 --- a/monitor.h +++ b/monitor.h -@@ -63,6 +63,8 @@ enum monitor_reqtype { +@@ -68,6 +68,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, @@ -2833,10 +3112,10 @@ index 683e5e07..2b1a2d59 100644 struct ssh; diff --git a/monitor_wrap.c b/monitor_wrap.c -index 001a8fa1..6edb509a 100644 +index ef3ab1b1..b6e3b3f3 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c -@@ -993,13 +993,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) +@@ -1131,13 +1131,15 @@ mm_ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic) } int @@ -2853,7 +3132,7 @@ index 001a8fa1..6edb509a 100644 mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_GSSUSEROK, m); mm_request_receive_expect(pmonitor->m_recvfd, -@@ -1012,4 +1014,57 @@ mm_ssh_gssapi_userok(char *user) +@@ -1150,6 +1152,59 @@ mm_ssh_gssapi_userok(char *user) debug3_f("user %sauthenticated", authenticated ? "" : "not "); return (authenticated); } @@ -2911,11 +3190,13 @@ index 001a8fa1..6edb509a 100644 +} + #endif /* GSSAPI */ + + /* diff --git a/monitor_wrap.h b/monitor_wrap.h -index 23ab096a..485590c1 100644 +index 38a280c8..672dce52 100644 --- a/monitor_wrap.h +++ b/monitor_wrap.h -@@ -64,8 +64,10 @@ int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t, +@@ -67,8 +67,10 @@ void mm_decode_activate_server_options(struct ssh *ssh, struct sshbuf *m); 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 *); @@ -2927,18 +3208,19 @@ index 23ab096a..485590c1 100644 #endif #ifdef USE_PAM -diff -up a/readconf.c.gsskex b/readconf.c ---- a/readconf.c.gsskex 2021-08-20 06:03:49.000000000 +0200 -+++ b/readconf.c 2021-08-27 12:25:42.556421509 +0200 -@@ -67,6 +67,7 @@ - #include "uidswap.h" +diff --git a/readconf.c b/readconf.c +index 7cbe7d2c..6c04ed43 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -71,6 +71,7 @@ #include "myproposal.h" #include "digest.h" + #include "version.h" +#include "ssh-gss.h" /* Format of the configuration file: -@@ -161,6 +162,8 @@ typedef enum { +@@ -165,6 +166,8 @@ typedef enum { oClearAllForwardings, oNoHostAuthenticationForLocalhost, oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, oAddressFamily, oGssAuthentication, oGssDelegateCreds, @@ -2947,7 +3229,7 @@ diff -up a/readconf.c.gsskex b/readconf.c oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, oSendEnv, oSetEnv, oControlPath, oControlMaster, oControlPersist, oHashKnownHosts, -@@ -206,10 +209,22 @@ static struct { +@@ -212,10 +215,22 @@ static struct { /* Sometimes-unsupported options */ #if defined(GSSAPI) { "gssapiauthentication", oGssAuthentication }, @@ -2970,7 +3252,7 @@ diff -up a/readconf.c.gsskex b/readconf.c #endif #ifdef ENABLE_PKCS11 { "pkcs11provider", oPKCS11Provider }, -@@ -1113,10 +1128,42 @@ parse_time: +@@ -1320,10 +1335,42 @@ parse_time: intptr = &options->gss_authentication; goto parse_flag; @@ -3013,7 +3295,7 @@ diff -up a/readconf.c.gsskex b/readconf.c case oBatchMode: intptr = &options->batch_mode; goto parse_flag; -@@ -2306,7 +2353,13 @@ initialize_options(Options * options) +@@ -2662,7 +2709,13 @@ initialize_options(Options * options) options->fwd_opts.streamlocal_bind_unlink = -1; options->pubkey_authentication = -1; options->gss_authentication = -1; @@ -3027,7 +3309,7 @@ diff -up a/readconf.c.gsskex b/readconf.c options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->kbd_interactive_devices = NULL; -@@ -2463,8 +2516,18 @@ fill_default_options(Options * options) +@@ -2826,8 +2879,18 @@ fill_default_options(Options * options) options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3046,7 +3328,7 @@ diff -up a/readconf.c.gsskex b/readconf.c if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -3246,7 +3309,14 @@ dump_client_config(Options *o, const cha +@@ -3656,7 +3719,14 @@ dump_client_config(Options *o, const char *host) dump_cfg_fmtint(oGatewayPorts, o->fwd_opts.gateway_ports); #ifdef GSSAPI dump_cfg_fmtint(oGssAuthentication, o->gss_authentication); @@ -3061,9 +3343,10 @@ diff -up a/readconf.c.gsskex b/readconf.c #endif /* GSSAPI */ dump_cfg_fmtint(oHashKnownHosts, o->hash_known_hosts); dump_cfg_fmtint(oHostbasedAuthentication, o->hostbased_authentication); -diff -up a/readconf.h.gsskex b/readconf.h ---- a/readconf.h.gsskex 2021-08-27 12:05:29.248142431 +0200 -+++ b/readconf.h 2021-08-27 12:22:19.270679852 +0200 +diff --git a/readconf.h b/readconf.h +index cd49139b..368523dd 100644 +--- a/readconf.h ++++ b/readconf.h @@ -39,7 +39,13 @@ typedef struct { int pubkey_authentication; /* Try ssh2 pubkey authentication. */ int hostbased_authentication; /* ssh2's rhosts_rsa */ @@ -3078,18 +3361,19 @@ diff -up a/readconf.h.gsskex b/readconf.h int password_authentication; /* Try password * authentication. */ int kbd_interactive_authentication; /* Try keyboard-interactive auth. */ -diff -up a/servconf.c.gsskex b/servconf.c ---- a/servconf.c.gsskex 2021-08-20 06:03:49.000000000 +0200 -+++ b/servconf.c 2021-08-27 12:28:15.887735189 +0200 -@@ -70,6 +70,7 @@ - #include "auth.h" +diff --git a/servconf.c b/servconf.c +index f7bc9237..d4f7fd66 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -69,6 +69,7 @@ #include "myproposal.h" #include "digest.h" + #include "version.h" +#include "ssh-gss.h" - static void add_listen_addr(ServerOptions *, const char *, - const char *, int); -@@ -136,8 +137,11 @@ initialize_server_options(ServerOptions + #if !defined(SSHD_PAM_SERVICE) + # define SSHD_PAM_SERVICE "sshd" +@@ -138,8 +139,11 @@ initialize_server_options(ServerOptions *options) options->kerberos_ticket_cleanup = -1; options->kerberos_get_afs_token = -1; options->gss_authentication=-1; @@ -3101,7 +3385,7 @@ diff -up a/servconf.c.gsskex b/servconf.c options->password_authentication = -1; options->kbd_interactive_authentication = -1; options->permit_empty_passwd = -1; -@@ -356,10 +360,18 @@ fill_default_server_options(ServerOption +@@ -380,10 +384,18 @@ fill_default_server_options(ServerOptions *options) options->kerberos_get_afs_token = 0; if (options->gss_authentication == -1) options->gss_authentication = 0; @@ -3120,15 +3404,15 @@ diff -up a/servconf.c.gsskex b/servconf.c if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -506,6 +518,7 @@ typedef enum { - sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, +@@ -568,6 +580,7 @@ typedef enum { + sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, -@@ -587,12 +600,22 @@ static struct { +@@ -653,12 +666,22 @@ static struct { #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, { "gssapicleanupcredentials", sGssCleanupCreds, SSHCFG_GLOBAL }, @@ -3151,7 +3435,7 @@ diff -up a/servconf.c.gsskex b/servconf.c { "passwordauthentication", sPasswordAuthentication, SSHCFG_ALL }, { "kbdinteractiveauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, { "challengeresponseauthentication", sKbdInteractiveAuthentication, SSHCFG_ALL }, /* alias */ -@@ -1576,6 +1599,10 @@ process_server_config_line_depth(ServerO +@@ -1649,6 +1672,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->gss_authentication; goto parse_flag; @@ -3162,7 +3446,7 @@ diff -up a/servconf.c.gsskex b/servconf.c case sGssCleanupCreds: intptr = &options->gss_cleanup_creds; goto parse_flag; -@@ -1584,6 +1611,22 @@ process_server_config_line_depth(ServerO +@@ -1657,6 +1684,22 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->gss_strict_acceptor; goto parse_flag; @@ -3185,7 +3469,7 @@ diff -up a/servconf.c.gsskex b/servconf.c case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -@@ -2892,6 +2935,10 @@ dump_config(ServerOptions *o) +@@ -3254,6 +3297,10 @@ dump_config(ServerOptions *o) #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); @@ -3197,10 +3481,10 @@ diff -up a/servconf.c.gsskex b/servconf.c dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); dump_cfg_fmtint(sKbdInteractiveAuthentication, diff --git a/servconf.h b/servconf.h -index 4202a2d0..3f47ea25 100644 +index 9beb90fa..c3f50140 100644 --- a/servconf.h +++ b/servconf.h -@@ -132,8 +132,11 @@ typedef struct { +@@ -150,8 +150,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 */ @@ -3213,10 +3497,10 @@ index 4202a2d0..3f47ea25 100644 * authentication. */ int kbd_interactive_authentication; /* If true, permit */ diff --git a/session.c b/session.c -index 8c0e54f7..06a33442 100644 +index e4657cef..cbfbcee8 100644 --- a/session.c +++ b/session.c -@@ -2678,13 +2678,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) +@@ -2670,13 +2670,19 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) #ifdef KRB5 if (options.kerberos_ticket_cleanup && @@ -3239,18 +3523,10 @@ index 8c0e54f7..06a33442 100644 /* remove agent socket */ diff --git a/ssh-gss.h b/ssh-gss.h -index 36180d07..70dd3665 100644 +index 7b14e74a..8ec45192 100644 --- a/ssh-gss.h +++ b/ssh-gss.h -@@ -1,6 +1,6 @@ - /* $OpenBSD: ssh-gss.h,v 1.15 2021/01/27 10:05:28 djm Exp $ */ - /* -- * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. -+ * Copyright (c) 2001-2009 Simon Wilkinson. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions -@@ -61,10 +61,34 @@ +@@ -61,10 +61,36 @@ #define SSH_GSS_OIDTYPE 0x06 @@ -3276,6 +3552,8 @@ index 36180d07..70dd3665 100644 + KEX_GSS_C25519_SHA256_ID "," \ + KEX_GSS_GRP14_SHA1_ID "," \ + KEX_GSS_GEX_SHA1_ID ++ ++#include "digest.h" /* SSH_DIGEST_MAX_LENGTH */ + typedef struct { char *filename; @@ -3285,7 +3563,7 @@ index 36180d07..70dd3665 100644 void *data; } ssh_gssapi_ccache; -@@ -72,8 +92,11 @@ typedef struct { +@@ -72,8 +98,11 @@ typedef struct { gss_buffer_desc displayname; gss_buffer_desc exportedname; gss_cred_id_t creds; @@ -3297,7 +3575,7 @@ index 36180d07..70dd3665 100644 } ssh_gssapi_client; typedef struct ssh_gssapi_mech_struct { -@@ -84,6 +107,7 @@ typedef struct ssh_gssapi_mech_struct { +@@ -84,6 +113,7 @@ typedef struct ssh_gssapi_mech_struct { int (*userok) (ssh_gssapi_client *, char *); int (*localname) (ssh_gssapi_client *, char **); void (*storecreds) (ssh_gssapi_client *); @@ -3305,12 +3583,22 @@ index 36180d07..70dd3665 100644 } ssh_gssapi_mech; typedef struct { -@@ -94,10 +118,11 @@ typedef struct { +@@ -94,10 +124,21 @@ typedef struct { gss_OID oid; /* client */ gss_cred_id_t creds; /* server */ gss_name_t client; /* server */ - gss_cred_id_t client_creds; /* server */ + gss_cred_id_t client_creds; /* both */ ++ struct sshbuf *shared_secret; /* both */ ++ struct sshbuf *server_pubkey; /* server */ ++ struct sshbuf *server_blob; /* client */ ++ struct sshbuf *server_host_key_blob; /* client */ ++ gss_buffer_desc msg_tok; /* client */ ++ gss_buffer_desc buf; /* both */ ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; /* both */ ++ size_t hashlen; /* both */ ++ int first; /* client */ ++ BIGNUM *dh_client_pub; /* server (gex) */ } Gssctxt; extern ssh_gssapi_mech *supported_mechs[]; @@ -3318,7 +3606,7 @@ index 36180d07..70dd3665 100644 int ssh_gssapi_check_oid(Gssctxt *, void *, size_t); void ssh_gssapi_set_oid_data(Gssctxt *, void *, size_t); -@@ -109,6 +134,7 @@ OM_uint32 ssh_gssapi_test_oid_supported(OM_uint32 *, gss_OID, int *); +@@ -108,6 +149,7 @@ OM_uint32 ssh_gssapi_test_oid_supported(OM_uint32 *, gss_OID, int *); struct sshbuf; int ssh_gssapi_get_buffer_desc(struct sshbuf *, gss_buffer_desc *); @@ -3326,7 +3614,7 @@ index 36180d07..70dd3665 100644 OM_uint32 ssh_gssapi_import_name(Gssctxt *, const char *); OM_uint32 ssh_gssapi_init_ctx(Gssctxt *, int, -@@ -123,17 +149,33 @@ void ssh_gssapi_delete_ctx(Gssctxt **); +@@ -122,17 +164,33 @@ void ssh_gssapi_delete_ctx(Gssctxt **); OM_uint32 ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); void ssh_gssapi_buildmic(struct sshbuf *, const char *, const char *, const char *, const struct sshbuf *); @@ -3363,24 +3651,26 @@ index 36180d07..70dd3665 100644 #endif /* _SSH_GSS_H */ diff --git a/ssh.1 b/ssh.1 -index 60de6087..db5c65bc 100644 +index db92ac9a..6a9fbdc5 100644 --- a/ssh.1 +++ b/ssh.1 -@@ -503,7 +503,13 @@ For full details of the options listed below, and their possible values, see - .It GatewayPorts - .It GlobalKnownHostsFile +@@ -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 HostbasedAcceptedAlgorithms -@@ -579,6 +585,8 @@ flag), + .It HostKeyAlgorithms +@@ -636,6 +642,8 @@ flag), (supported message integrity codes), .Ar kex (key exchange algorithms), @@ -3388,12 +3678,12 @@ index 60de6087..db5c65bc 100644 +(GSSAPI key exchange algorithms), .Ar key (key types), - .Ar key-cert + .Ar key-ca-sign diff --git a/ssh.c b/ssh.c -index 15aee569..110cf9c1 100644 +index dc4886d0..c23d3b9e 100644 --- a/ssh.c +++ b/ssh.c -@@ -747,6 +747,8 @@ main(int ac, char **av) +@@ -835,6 +835,8 @@ main(int ac, char **av) else if (strcmp(optarg, "kex") == 0 || strcasecmp(optarg, "KexAlgorithms") == 0) cp = kex_alg_list('\n'); @@ -3402,7 +3692,7 @@ index 15aee569..110cf9c1 100644 else if (strcmp(optarg, "key") == 0) cp = sshkey_alg_list(0, 0, 0, '\n'); else if (strcmp(optarg, "key-cert") == 0) -@@ -772,8 +774,8 @@ main(int ac, char **av) +@@ -865,8 +867,8 @@ main(int ac, char **av) } else if (strcmp(optarg, "help") == 0) { cp = xstrdup( "cipher\ncipher-auth\ncompression\nkex\n" @@ -3414,7 +3704,7 @@ index 15aee569..110cf9c1 100644 if (cp == NULL) fatal("Unsupported query \"%s\"", optarg); diff --git a/ssh_config b/ssh_config -index 5e8ef548..1ff999b6 100644 +index 18169187..209248d6 100644 --- a/ssh_config +++ b/ssh_config @@ -24,6 +24,8 @@ @@ -3424,13 +3714,13 @@ index 5e8ef548..1ff999b6 100644 +# GSSAPIKeyExchange no +# GSSAPITrustDNS no # BatchMode no - # CheckHostIP yes + # CheckHostIP no # AddressFamily any diff --git a/ssh_config.5 b/ssh_config.5 -index 06a32d31..3f490697 100644 +index 894d7383..3a8e246c 100644 --- a/ssh_config.5 +++ b/ssh_config.5 -@@ -766,10 +766,68 @@ The default is +@@ -976,10 +976,68 @@ The default is Specifies whether user authentication based on GSSAPI is allowed. The default is .Cm no . @@ -3500,20 +3790,11 @@ index 06a32d31..3f490697 100644 Indicates that .Xr ssh 1 diff --git a/sshconnect2.c b/sshconnect2.c -index af00fb30..03bc87eb 100644 +index 1ee6000a..0af15bcc 100644 --- a/sshconnect2.c +++ b/sshconnect2.c -@@ -80,8 +80,6 @@ - #endif - - /* import */ --extern char *client_version_string; --extern char *server_version_string; - extern Options options; - - /* -@@ -163,6 +161,11 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) - char *s, *all_key, *hkalgs = NULL; +@@ -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) @@ -3524,11 +3805,10 @@ index af00fb30..03bc87eb 100644 xxx_host = host; xxx_hostaddr = hostaddr; xxx_conn_info = cinfo; -@@ -206,6 +209,42 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) - kex_proposal_populate_entries(ssh, myproposal, s, options.ciphers, - options.macs, compression_alg_list(options.compression), +@@ -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 @@ -3564,10 +3844,11 @@ index af00fb30..03bc87eb 100644 + } + } +#endif - ++ free(hkalgs); -@@ -224,17 +256,47 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port) + /* 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 @@ -3586,6 +3867,7 @@ index af00fb30..03bc87eb 100644 +#endif /* WITH_OPENSSL */ ssh->kex->kex[KEX_C25519_SHA256] = kex_gen_client; ssh->kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_client; + ssh->kex->kex[KEX_KEM_MLKEM768X25519_SHA256] = kex_gen_client; ssh->kex->verify_host_key=&verify_host_key_callback; +#if defined(GSSAPI) && defined(WITH_OPENSSL) @@ -3598,11 +3880,8 @@ index af00fb30..03bc87eb 100644 +#endif + ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &ssh->kex->done); + kex_proposal_free_entries(myproposal); - /* remove ext-info from the KEX proposals for rekeying */ - free(myproposal[PROPOSAL_KEX_ALGS]); - myproposal[PROPOSAL_KEX_ALGS] = - compat_kex_proposal(ssh, options.kex_algorithms); +#if defined(GSSAPI) && defined(WITH_OPENSSL) + /* repair myproposal after it was crumpled by the */ + /* ext-info removal above */ @@ -3613,10 +3892,10 @@ index af00fb30..03bc87eb 100644 + free(gss); + } +#endif - if ((r = kex_prop2buf(ssh->kex->my, myproposal)) != 0) - fatal_r(r, "kex_prop2buf"); - -@@ -330,6 +392,7 @@ static int input_gssapi_response(int type, u_int32_t, struct ssh *); + #ifdef DEBUG_KEXDH + /* send 1st encrypted/maced/compressed message */ + if ((r = sshpkt_start(ssh, SSH2_MSG_IGNORE)) != 0 || +@@ -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 *); @@ -3624,7 +3903,7 @@ index af00fb30..03bc87eb 100644 #endif void userauth(struct ssh *, char *); -@@ -346,6 +409,11 @@ static char *authmethods_get(void); +@@ -385,6 +457,11 @@ static char *authmethods_get(void); Authmethod authmethods[] = { #ifdef GSSAPI @@ -3636,7 +3915,7 @@ index af00fb30..03bc87eb 100644 {"gssapi-with-mic", userauth_gssapi, userauth_gssapi_cleanup, -@@ -716,12 +784,32 @@ userauth_gssapi(struct ssh *ssh) +@@ -759,12 +836,32 @@ userauth_gssapi(struct ssh *ssh) OM_uint32 min; int r, ok = 0; gss_OID mech = NULL; @@ -3670,7 +3949,7 @@ index af00fb30..03bc87eb 100644 /* Check to see whether the mechanism is usable before we offer it */ while (authctxt->mech_tried < authctxt->gss_supported_mechs->count && -@@ -730,13 +811,15 @@ userauth_gssapi(struct ssh *ssh) +@@ -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, @@ -3687,7 +3966,7 @@ index af00fb30..03bc87eb 100644 if (!ok || mech == NULL) return 0; -@@ -976,6 +1059,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) +@@ -1013,6 +1112,55 @@ input_gssapi_error(int type, u_int32_t plen, struct ssh *ssh) free(lang); return r; } @@ -3743,32 +4022,11 @@ index af00fb30..03bc87eb 100644 #endif /* GSSAPI */ static int -diff --git a/sshd.c b/sshd.c -index 60b2aaf7..d92f03aa 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -817,8 +817,8 @@ notify_hostkeys(struct ssh *ssh) - } - debug3_f("sent %u hostkeys", nkeys); - if (nkeys == 0) -- fatal_f("no hostkeys"); -- if ((r = sshpkt_send(ssh)) != 0) -+ debug3_f("no hostkeys"); -+ else if ((r = sshpkt_send(ssh)) != 0) - sshpkt_fatal(ssh, r, "%s: send", __func__); - sshbuf_free(buf); - } -@@ -1852,7 +1852,8 @@ main(int ac, char **av) - free(fp); - } - accumulate_host_timing_secret(cfg, NULL); -- if (!sensitive_data.have_ssh2_key) { -+ /* The GSSAPI key exchange can run without a host key */ -+ if (!sensitive_data.have_ssh2_key && !options.gss_keyex) { - logit("sshd: no hostkeys available -- exiting."); - exit(1); - } -@@ -2347,6 +2348,48 @@ do_ssh2_kex(struct ssh *ssh) +diff --git a/sshd-auth.c b/sshd-auth.c +index f957dc22..d51e4636 100644 +--- a/sshd-auth.c ++++ b/sshd-auth.c +@@ -844,6 +844,48 @@ do_ssh2_kex(struct ssh *ssh) free(hkalgs); @@ -3795,7 +4053,7 @@ index 60b2aaf7..d92f03aa 100644 + if (gss && orig) + xasprintf(&newstr, "%s,%s", gss, orig); + else if (gss) -+ newstr = gss; ++ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com"); + else if (orig) + newstr = orig; + @@ -3805,7 +4063,7 @@ index 60b2aaf7..d92f03aa 100644 + * host key algorithm we support + */ + if (gss && (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS])) == 0) -+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = "null"; ++ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = xstrdup("null"); + + if (newstr) + myproposal[PROPOSAL_KEX_ALGS] = newstr; @@ -3817,11 +4075,10 @@ index 60b2aaf7..d92f03aa 100644 /* start key exchange */ if ((r = kex_setup(ssh, myproposal)) != 0) fatal_r(r, "kex_setup"); -@@ -2362,7 +2405,18 @@ do_ssh2_kex(struct ssh *ssh) +@@ -861,6 +903,17 @@ do_ssh2_kex(struct ssh *ssh) # ifdef OPENSSL_HAS_ECC kex->kex[KEX_ECDH_SHA2] = kex_gen_server; - # endif --#endif + # endif /* OPENSSL_HAS_ECC */ +# ifdef GSSAPI + if (options.gss_keyex) { + kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; @@ -3833,15 +4090,55 @@ index 60b2aaf7..d92f03aa 100644 + kex->kex[KEX_GSS_C25519_SHA256] = kexgss_server; + } +# endif -+#endif /* WITH_OPENSSL */ + #endif /* WITH_OPENSSL */ kex->kex[KEX_C25519_SHA256] = kex_gen_server; kex->kex[KEX_KEM_SNTRUP761X25519_SHA512] = kex_gen_server; - kex->load_host_public_key=&get_hostkey_public_by_type; +diff --git a/sshd-session.c b/sshd-session.c +index a70b36c9..f8c8a797 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -616,8 +616,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); + } +@@ -1159,8 +1159,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 4a93e29e..c9ea8e38 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 19b7c91a..2c48105f 100644 +index 48af6321..8db9f0fb 100644 --- a/sshd_config +++ b/sshd_config -@@ -69,6 +69,8 @@ AuthorizedKeysFile .ssh/authorized_keys +@@ -79,6 +79,8 @@ AuthorizedKeysFile .ssh/authorized_keys # GSSAPI options #GSSAPIAuthentication no #GSSAPICleanupCredentials yes @@ -3851,10 +4148,10 @@ index 19b7c91a..2c48105f 100644 # Set this to 'yes' to enable PAM authentication, account processing, # and session processing. If this is enabled, PAM authentication will diff --git a/sshd_config.5 b/sshd_config.5 -index 70ccea44..f6b41a2f 100644 +index 035a50c8..8bc6586e 100644 --- a/sshd_config.5 +++ b/sshd_config.5 -@@ -646,6 +646,11 @@ Specifies whether to automatically destroy the user's credentials cache +@@ -739,6 +739,11 @@ Specifies whether to automatically destroy the user's credentials cache on logout. The default is .Cm yes . @@ -3866,7 +4163,7 @@ index 70ccea44..f6b41a2f 100644 .It Cm GSSAPIStrictAcceptorCheck Determines whether to be strict about the identity of the GSSAPI acceptor a client authenticates against. -@@ -660,6 +665,32 @@ machine's default store. +@@ -753,6 +758,32 @@ machine's default store. This facility is provided to assist with operation on multi homed machines. The default is .Cm yes . @@ -3900,14 +4197,13 @@ index 70ccea44..f6b41a2f 100644 Specifies the signature algorithms that will be accepted for hostbased authentication as a list of comma-separated patterns. diff --git a/sshkey.c b/sshkey.c -index 57995ee6..fd5b7724 100644 +index ab80752b..4e41a78c 100644 --- a/sshkey.c +++ b/sshkey.c -@@ -127,6 +127,75 @@ static const struct keytype keytypes[] = { - extern const struct sshkey_impl sshkey_xmss_impl; +@@ -129,6 +129,75 @@ extern const struct sshkey_impl sshkey_xmss_impl; extern const struct sshkey_impl sshkey_xmss_cert_impl; #endif -+ + +static int ssh_gss_equal(const struct sshkey *, const struct sshkey *) +{ + return SSH_ERR_FEATURE_UNSUPPORTED; @@ -3976,10 +4272,11 @@ index 57995ee6..fd5b7724 100644 + /* .keybits = */ 0, /* FIXME */ + /* .funcs = */ &sshkey_gss_funcs, +}; - ++ const struct sshkey_impl * const keyimpls[] = { &sshkey_ed25519_impl, -@@ -154,6 +154,7 @@ static const struct keytype keytypes[] = { + &sshkey_ed25519_cert_impl, +@@ -167,6 +236,7 @@ const struct sshkey_impl * const keyimpls[] = { &sshkey_xmss_impl, &sshkey_xmss_cert_impl, #endif @@ -3987,7 +4284,7 @@ index 57995ee6..fd5b7724 100644 NULL }; -@@ -255,7 +256,7 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) +@@ -336,7 +406,7 @@ sshkey_alg_list(int certs_only, int plain_only, int include_sigonly, char sep) for (i = 0; keyimpls[i] != NULL; i++) { impl = keyimpls[i]; @@ -3997,10 +4294,10 @@ index 57995ee6..fd5b7724 100644 if (!include_sigonly && impl->sigonly) continue; diff --git a/sshkey.h b/sshkey.h -index 71a3fddc..37a43a67 100644 +index 19bbbac7..4a318d05 100644 --- a/sshkey.h +++ b/sshkey.h -@@ -69,6 +69,7 @@ enum sshkey_types { +@@ -75,6 +75,7 @@ enum sshkey_types { KEY_ECDSA_SK_CERT, KEY_ED25519_SK, KEY_ED25519_SK_CERT, @@ -4008,3 +4305,6 @@ index 71a3fddc..37a43a67 100644 KEY_UNSPEC }; +-- +2.49.0 + diff --git a/openssh-6.6p1-force_krb.patch b/0013-openssh-6.6p1-force_krb.patch similarity index 88% rename from openssh-6.6p1-force_krb.patch rename to 0013-openssh-6.6p1-force_krb.patch index 90f8322..74643b5 100644 --- a/openssh-6.6p1-force_krb.patch +++ b/0013-openssh-6.6p1-force_krb.patch @@ -1,5 +1,17 @@ +From f5e5ee321def2a3674600714ad98fd1ca9b2cff1 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 13/50] 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 413b845..54dd383 100644 +index 8d2b677f..14502c5a 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c @@ -32,7 +32,9 @@ @@ -12,7 +24,7 @@ index 413b845..54dd383 100644 #include "xmalloc.h" #include "sshkey.h" -@@ -45,6 +47,7 @@ +@@ -44,6 +46,7 @@ #include "ssh-gss.h" @@ -20,7 +32,7 @@ index 413b845..54dd383 100644 extern ServerOptions options; #ifdef HEIMDAL -@@ -56,6 +59,13 @@ extern ServerOptions options; +@@ -55,6 +58,13 @@ extern ServerOptions options; # include #endif @@ -34,7 +46,7 @@ index 413b845..54dd383 100644 static krb5_context krb_context = NULL; /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ -@@ -88,6 +98,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -87,6 +97,7 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) krb5_principal princ; int retval; const char *errmsg; @@ -42,7 +54,7 @@ index 413b845..54dd383 100644 if (ssh_gssapi_krb5_init() == 0) return 0; -@@ -99,10 +110,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -98,10 +109,22 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) krb5_free_error_message(krb_context, errmsg); return 0; } @@ -66,7 +78,7 @@ index 413b845..54dd383 100644 } else retval = 0; -@@ -110,6 +133,137 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) +@@ -109,6 +132,137 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) return retval; } @@ -205,10 +217,10 @@ index 413b845..54dd383 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 28659ec..9c94d8e 100644 +index cbfbcee8..89b3a9cf 100644 --- a/session.c +++ b/session.c -@@ -789,6 +789,29 @@ do_exec(Session *s, const char *command) +@@ -680,6 +680,29 @@ do_exec(struct ssh *ssh, Session *s, const char *command) command = auth_opts->force_command; forced = "(key-option)"; } @@ -239,7 +251,7 @@ index 28659ec..9c94d8e 100644 if (forced != NULL) { s->forced = 1; diff --git a/ssh-gss.h b/ssh-gss.h -index 0374c88..509109a 100644 +index 8ec45192..db34d77f 100644 --- a/ssh-gss.h +++ b/ssh-gss.h @@ -49,6 +49,10 @@ @@ -254,10 +266,10 @@ index 0374c88..509109a 100644 /* draft-ietf-secsh-gsskeyex-06 */ diff --git a/sshd.8 b/sshd.8 -index adcaaf9..824163b 100644 +index 2aa73271..049d0a94 100644 --- a/sshd.8 +++ b/sshd.8 -@@ -324,6 +324,7 @@ Finally, the server and the client enter an authentication dialog. +@@ -286,6 +286,7 @@ Finally, the server and the client enter an authentication dialog. The client tries to authenticate itself using host-based authentication, public key authentication, @@ -265,7 +277,7 @@ index adcaaf9..824163b 100644 challenge-response authentication, or password authentication. .Pp -@@ -800,6 +801,12 @@ This file is used in exactly the same way as +@@ -874,6 +875,12 @@ This file is used in exactly the same way as but allows host-based authentication without permitting login with rlogin/rsh. .Pp @@ -278,3 +290,6 @@ index adcaaf9..824163b 100644 .It Pa ~/.ssh/ This directory is the default location for all user-specific configuration and authentication information. +-- +2.49.0 + diff --git a/openssh-7.7p1-gssapi-new-unique.patch b/0014-openssh-7.7p1-gssapi-new-unique.patch similarity index 78% rename from openssh-7.7p1-gssapi-new-unique.patch rename to 0014-openssh-7.7p1-gssapi-new-unique.patch index 544932b..1d21839 100644 --- a/openssh-7.7p1-gssapi-new-unique.patch +++ b/0014-openssh-7.7p1-gssapi-new-unique.patch @@ -1,26 +1,25 @@ -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 +From 5fca5946aa97dce23c6824c52b070a92532752a9 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 14/50] 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 c99e4e43..77714e3d 100644 +--- a/auth-krb5.c ++++ b/auth-krb5.c @@ -51,6 +51,7 @@ #include #include @@ -29,7 +28,7 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c extern ServerOptions options; -@@ -77,7 +78,7 @@ auth_krb5_password(Authctxt *authctxt, c +@@ -77,7 +78,7 @@ auth_krb5_password(Authctxt *authctxt, const char *password) #endif krb5_error_code problem; krb5_ccache ccache = NULL; @@ -38,7 +37,7 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c char *client, *platform_client; const char *errmsg; -@@ -163,8 +164,8 @@ auth_krb5_password(Authctxt *authctxt, c +@@ -163,8 +164,8 @@ auth_krb5_password(Authctxt *authctxt, const char *password) goto out; } @@ -49,7 +48,7 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c if (problem) goto out; -@@ -179,15 +180,14 @@ auth_krb5_password(Authctxt *authctxt, c +@@ -179,15 +180,14 @@ auth_krb5_password(Authctxt *authctxt, const char *password) goto out; #endif @@ -70,7 +69,7 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); #endif -@@ -223,11 +223,54 @@ auth_krb5_password(Authctxt *authctxt, c +@@ -223,11 +223,54 @@ auth_krb5_password(Authctxt *authctxt, const char *password) void krb5_cleanup_proc(Authctxt *authctxt) { @@ -126,12 +125,29 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c if (authctxt->krb5_user) { krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); authctxt->krb5_user = NULL; -@@ -238,36 +281,188 @@ krb5_cleanup_proc(Authctxt *authctxt) +@@ -238,36 +281,189 @@ 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, ...) { @@ -149,7 +165,8 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c + old = *dsc; + + i = asprintf(dsc, "%s%s", *dsc, src); -+ if (i == -1 || src == NULL) { ++ if (i == -1) { ++ *dsc = old; + free(src); + return -1; + } @@ -196,8 +213,9 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c + /* 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; + @@ -232,29 +250,13 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c + return ret; +} + - krb5_error_code --ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { -- int tmpfd, ret, oerrno; -- char ccname[40]; ++krb5_error_code +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; @@ -269,8 +271,7 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c + "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; @@ -337,42 +338,32 @@ diff -up openssh-8.6p1/auth-krb5.c.ccache_name openssh-8.6p1/auth-krb5.c } #endif /* !HEIMDAL */ #endif /* KRB5 */ -diff -up openssh-8.6p1/gss-serv.c.ccache_name openssh-8.6p1/gss-serv.c ---- openssh-8.6p1/gss-serv.c.ccache_name 2021-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) - } +diff --git a/auth.h b/auth.h +index 83d07ae8..10e88e11 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; - /* 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; - } +@@ -245,7 +246,7 @@ FILE *auth_openprincipals(const char *, struct passwd *, int); + int sys_auth_passwd(struct ssh *, const char *); - /* This allows GSSAPI methods to do things to the child's environment based -@@ -499,9 +501,7 @@ ssh_gssapi_rekey_creds(void) { - char *envstr; + #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 -- if (gssapi_client.store.filename == NULL && -- gssapi_client.store.envval == NULL && -- gssapi_client.store.envvar == NULL) -+ if (gssapi_client.store.envval == NULL) - return; - - ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); -diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c ---- openssh-8.6p1/gss-serv-krb5.c.ccache_name 2021-04-19 14:05:10.852744562 +0200 -+++ openssh-8.6p1/gss-serv-krb5.c 2021-04-19 14:05:10.854744577 +0200 -@@ -267,7 +267,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri + #endif /* AUTH_H */ +diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c +index 14502c5a..df55512d 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, /* This writes out any forwarded credentials from the structure populated * during userauth. Called after we have setuid to the user */ @@ -381,7 +372,7 @@ diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) { krb5_ccache ccache; -@@ -276,14 +276,15 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl +@@ -276,14 +276,15 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) OM_uint32 maj_status, min_status; const char *new_ccname, *new_cctype; const char *errmsg; @@ -399,7 +390,7 @@ diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c #ifdef HEIMDAL # ifdef HAVE_KRB5_CC_NEW_UNIQUE -@@ -297,14 +298,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl +@@ -297,14 +298,14 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) krb5_get_err_text(krb_context, problem)); # endif krb5_free_error_message(krb_context, errmsg); @@ -418,7 +409,7 @@ diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c } #endif /* #ifdef HEIMDAL */ -@@ -313,7 +314,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl +@@ -313,7 +314,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) errmsg = krb5_get_error_message(krb_context, problem); logit("krb5_parse_name(): %.100s", errmsg); krb5_free_error_message(krb_context, errmsg); @@ -427,7 +418,7 @@ diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c } if ((problem = krb5_cc_initialize(krb_context, ccache, princ))) { -@@ -322,7 +323,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl +@@ -322,7 +323,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) krb5_free_error_message(krb_context, errmsg); krb5_free_principal(krb_context, princ); krb5_cc_destroy(krb_context, ccache); @@ -436,7 +427,7 @@ diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c } krb5_free_principal(krb_context, princ); -@@ -331,32 +332,21 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl +@@ -331,32 +332,21 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) client->creds, ccache))) { logit("gss_krb5_copy_ccache() failed"); krb5_cc_destroy(krb_context, ccache); @@ -474,7 +465,7 @@ diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c do_pam_putenv(client->store.envvar, client->store.envval); #endif -@@ -364,7 +354,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_cl +@@ -364,7 +354,7 @@ ssh_gssapi_krb5_storecreds(ssh_gssapi_client *client) client->store.data = krb_context; @@ -483,10 +474,44 @@ diff -up openssh-8.6p1/gss-serv-krb5.c.ccache_name openssh-8.6p1/gss-serv-krb5.c } int -diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c ---- openssh-8.6p1/servconf.c.ccache_name 2021-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 +diff --git a/gss-serv.c b/gss-serv.c +index a5cca797..9d5435ed 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 d4f7fd66..55aa5bf0 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -138,6 +138,7 @@ initialize_server_options(ServerOptions *options) options->kerberos_or_local_passwd = -1; options->kerberos_ticket_cleanup = -1; options->kerberos_get_afs_token = -1; @@ -494,7 +519,7 @@ diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c options->gss_authentication=-1; options->gss_keyex = -1; options->gss_cleanup_creds = -1; -@@ -359,6 +360,8 @@ fill_default_server_options(ServerOption +@@ -382,6 +383,8 @@ fill_default_server_options(ServerOptions *options) options->kerberos_ticket_cleanup = 1; if (options->kerberos_get_afs_token == -1) options->kerberos_get_afs_token = 0; @@ -503,16 +528,16 @@ diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c if (options->gss_authentication == -1) options->gss_authentication = 0; if (options->gss_keyex == -1) -@@ -506,7 +509,7 @@ typedef enum { - sPort, sHostKeyFile, sLoginGraceTime, - sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, +@@ -564,7 +567,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, -@@ -593,11 +597,13 @@ static struct { + sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, +@@ -655,11 +658,13 @@ static struct { #else { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, #endif @@ -526,7 +551,7 @@ diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c #endif { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, -@@ -1573,6 +1579,10 @@ process_server_config_line_depth(ServerO +@@ -1668,6 +1673,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->kerberos_get_afs_token; goto parse_flag; @@ -537,7 +562,7 @@ diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c case sGssAuthentication: intptr = &options->gss_authentication; goto parse_flag; -@@ -2891,6 +2901,7 @@ dump_config(ServerOptions *o) +@@ -3293,6 +3302,7 @@ dump_config(ServerOptions *o) # ifdef USE_AFS dump_cfg_fmtint(sKerberosGetAFSToken, o->kerberos_get_afs_token); # endif @@ -545,10 +570,11 @@ diff -up openssh-8.6p1/servconf.c.ccache_name openssh-8.6p1/servconf.c #endif #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); -diff -up openssh-8.6p1/servconf.h.ccache_name openssh-8.6p1/servconf.h ---- openssh-8.6p1/servconf.h.ccache_name 2021-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 { +diff --git a/servconf.h b/servconf.h +index c3f50140..a4a38d6d 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -149,6 +149,8 @@ typedef struct { * file on logout. */ int kerberos_get_afs_token; /* If true, try to get AFS token if * authenticated with Kerberos. */ @@ -557,10 +583,11 @@ diff -up openssh-8.6p1/servconf.h.ccache_name openssh-8.6p1/servconf.h 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 -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 +diff --git a/session.c b/session.c +index 89b3a9cf..2620dd11 100644 +--- a/session.c ++++ b/session.c +@@ -1025,7 +1025,8 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) /* Allow any GSSAPI methods that we've used to alter * the child's environment as they see fit */ @@ -570,7 +597,7 @@ diff -up openssh-8.6p1/session.c.ccache_name openssh-8.6p1/session.c #endif /* Set basic environment. */ -@@ -1114,7 +1115,7 @@ do_setup_env(struct ssh *ssh, Session *s +@@ -1101,7 +1102,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) } #endif #ifdef KRB5 @@ -579,10 +606,33 @@ diff -up openssh-8.6p1/session.c.ccache_name openssh-8.6p1/session.c child_set_env(&env, &envsize, "KRB5CCNAME", s->authctxt->krb5_ccname); #endif -diff -up openssh-8.6p1/sshd.c.ccache_name openssh-8.6p1/sshd.c ---- openssh-8.6p1/sshd.c.ccache_name 2021-04-19 14:05:10.849744540 +0200 -+++ openssh-8.6p1/sshd.c 2021-04-19 14:05:10.855744584 +0200 -@@ -2284,7 +2284,7 @@ main(int ac, char **av) +diff --git a/ssh-gss.h b/ssh-gss.h +index db34d77f..a894e23c 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 f8c8a797..478381db 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -1349,7 +1349,7 @@ main(int ac, char **av) #ifdef GSSAPI if (options.gss_authentication) { temporarily_use_uid(authctxt->pw); @@ -591,10 +641,11 @@ diff -up openssh-8.6p1/sshd.c.ccache_name openssh-8.6p1/sshd.c restore_uid(); } #endif -diff -up openssh-8.6p1/sshd_config.5.ccache_name openssh-8.6p1/sshd_config.5 ---- openssh-8.6p1/sshd_config.5.ccache_name 2021-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 +diff --git a/sshd_config.5 b/sshd_config.5 +index 8bc6586e..1251d4d5 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1033,6 +1033,14 @@ Specifies whether to automatically destroy the user's ticket cache file on logout. The default is .Cm yes . @@ -607,26 +658,8 @@ diff -up openssh-8.6p1/sshd_config.5.ccache_name openssh-8.6p1/sshd_config.5 +can lead to overwriting previous tickets by subseqent connections to the same +user account. .It Cm KexAlgorithms - Specifies the available KEX (Key Exchange) algorithms. - Multiple algorithms must be comma-separated. -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); + Specifies the permitted KEX (Key Exchange) algorithms that the server will + offer to clients. +-- +2.49.0 + diff --git a/openssh-7.2p2-k5login_directory.patch b/0015-openssh-7.2p2-k5login_directory.patch similarity index 74% rename from openssh-7.2p2-k5login_directory.patch rename to 0015-openssh-7.2p2-k5login_directory.patch index 80e7678..5e980c8 100644 --- a/openssh-7.2p2-k5login_directory.patch +++ b/0015-openssh-7.2p2-k5login_directory.patch @@ -1,8 +1,20 @@ +From 25540939422660b024b8832f67eab82267aa8df6 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 15/50] 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 2b02a04..19b9364 100644 +index 77714e3d..74f56d47 100644 --- a/auth-krb5.c +++ b/auth-krb5.c -@@ -375,5 +375,21 @@ cleanup: +@@ -465,5 +465,21 @@ ssh_krb5_cc_new_unique(krb5_context ctx, krb5_ccache *ccache, int *need_environm return (krb5_cc_resolve(ctx, ccname, ccache)); } } @@ -25,10 +37,10 @@ index 2b02a04..19b9364 100644 #endif /* !HEIMDAL */ #endif /* KRB5 */ diff --git a/auth.h b/auth.h -index f9d191c..c432d2f 100644 +index 10e88e11..39163035 100644 --- a/auth.h +++ b/auth.h -@@ -222,6 +222,8 @@ int sys_auth_passwd(Authctxt *, const char *); +@@ -247,6 +247,8 @@ int sys_auth_passwd(struct ssh *, const char *); #if defined(KRB5) && !defined(HEIMDAL) krb5_error_code ssh_krb5_cc_new_unique(krb5_context, krb5_ccache *, int *); @@ -38,10 +50,10 @@ index f9d191c..c432d2f 100644 #endif /* AUTH_H */ diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c -index a7c0c5f..df8cc9a 100644 +index df55512d..820f794c 100644 --- a/gss-serv-krb5.c +++ b/gss-serv-krb5.c -@@ -244,8 +244,27 @@ ssh_gssapi_k5login_exists() +@@ -144,8 +144,27 @@ ssh_gssapi_k5login_exists() { char file[MAXPATHLEN]; struct passwd *pw = the_authctxt->pw; @@ -71,10 +83,10 @@ index a7c0c5f..df8cc9a 100644 } diff --git a/sshd.8 b/sshd.8 -index 5c4f15b..135e290 100644 +index 049d0a94..6784286d 100644 --- a/sshd.8 +++ b/sshd.8 -@@ -806,6 +806,10 @@ rlogin/rsh. +@@ -880,6 +880,10 @@ rlogin/rsh. These files enforce GSSAPI/Kerberos authentication access control. Further details are described in .Xr ksu 1 . @@ -85,3 +97,6 @@ index 5c4f15b..135e290 100644 .Pp .It Pa ~/.ssh/ This directory is the default location for all user-specific configuration +-- +2.49.0 + diff --git a/openssh-6.6p1-kuserok.patch b/0016-openssh-6.6p1-kuserok.patch similarity index 79% rename from openssh-6.6p1-kuserok.patch rename to 0016-openssh-6.6p1-kuserok.patch index eaf4453..3724b8d 100644 --- a/openssh-6.6p1-kuserok.patch +++ b/0016-openssh-6.6p1-kuserok.patch @@ -1,7 +1,22 @@ -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 @@ +From bac7a9d1a654c8c2e0c71f979195e300b25d6232 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 16/50] 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 74f56d47..bae153c9 100644 +--- a/auth-krb5.c ++++ b/auth-krb5.c +@@ -55,6 +55,21 @@ extern ServerOptions options; @@ -23,7 +38,7 @@ diff -up openssh-7.4p1/auth-krb5.c.kuserok openssh-7.4p1/auth-krb5.c static int krb5_init(void *context) { -@@ -160,8 +175,9 @@ auth_krb5_password(Authctxt *authctxt, c +@@ -158,8 +173,9 @@ auth_krb5_password(Authctxt *authctxt, const char *password) if (problem) goto out; @@ -35,10 +50,11 @@ diff -up openssh-7.4p1/auth-krb5.c.kuserok openssh-7.4p1/auth-krb5.c problem = -1; goto out; } -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 +diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c +index 820f794c..187faf92 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 *, int); static krb5_context krb_context = NULL; @@ -46,7 +62,7 @@ diff -up openssh-7.4p1/gss-serv-krb5.c.kuserok openssh-7.4p1/gss-serv-krb5.c /* Initialise the krb5 library, for the stuff that GSSAPI won't do */ -@@ -92,6 +93,103 @@ ssh_gssapi_krb5_init(void) +@@ -91,6 +92,103 @@ ssh_gssapi_krb5_init(void) * Returns true if the user is OK to log in, otherwise returns 0 */ @@ -150,7 +166,7 @@ diff -up openssh-7.4p1/gss-serv-krb5.c.kuserok openssh-7.4p1/gss-serv-krb5.c static int ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) { -@@ -116,7 +214,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client +@@ -115,7 +213,8 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) /* 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. */ @@ -160,7 +176,7 @@ diff -up openssh-7.4p1/gss-serv-krb5.c.kuserok openssh-7.4p1/gss-serv-krb5.c 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 pri +@@ -190,9 +289,8 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, 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)) { @@ -172,18 +188,19 @@ diff -up openssh-7.4p1/gss-serv-krb5.c.kuserok openssh-7.4p1/gss-serv-krb5.c } if ((fp = fopen(file, "r")) == NULL) { int saved_errno = errno; -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 +diff --git a/servconf.c b/servconf.c +index 55aa5bf0..5dd5ca21 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -145,6 +145,7 @@ initialize_server_options(ServerOptions *options) 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; -@@ -278,6 +279,8 @@ fill_default_server_options(ServerOption + options->permit_empty_passwd = -1; +@@ -399,6 +400,8 @@ fill_default_server_options(ServerOptions *options) if (options->gss_kex_algorithms == NULL) options->gss_kex_algorithms = strdup(GSS_KEX_DEFAULT_KEX); #endif @@ -192,16 +209,16 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -399,7 +402,7 @@ typedef enum { - sPort, sHostKeyFile, sLoginGraceTime, - sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, - sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup, +@@ -567,7 +570,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, -@@ -478,12 +481,14 @@ static struct { + sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, + sPrintMotd, sPrintLastLog, sIgnoreRhosts, + sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost, +@@ -659,12 +662,14 @@ static struct { { "kerberosgetafstoken", sUnsupported, SSHCFG_GLOBAL }, #endif { "kerberosuniqueccache", sKerberosUniqueCCache, SSHCFG_GLOBAL }, @@ -216,18 +233,18 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c #endif { "kerberostgtpassing", sUnsupported, SSHCFG_GLOBAL }, { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, -@@ -1644,6 +1649,10 @@ process_server_config_line(ServerOptions - } - break; - +@@ -2441,6 +2446,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, + } + break; + + case sKerberosUseKuserok: + intptr = &options->use_kuserok; + goto parse_flag; + - case sMatch: - if (cmdline) - fatal("Match directive not supported as a command-line " -@@ -2016,6 +2025,7 @@ copy_set_server_options(ServerOptions *d + case sMatch: + if (cmdline) + fatal("Match directive not supported as a command-line " +@@ -2995,6 +3004,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(client_alive_interval); M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); @@ -235,18 +252,19 @@ diff -up openssh-7.4p1/servconf.c.kuserok openssh-7.4p1/servconf.c M_CP_INTOPT(rekey_limit); M_CP_INTOPT(rekey_interval); M_CP_INTOPT(log_level); -@@ -2309,6 +2319,7 @@ dump_config(ServerOptions *o) +@@ -3303,6 +3313,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 -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 { + dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); +diff --git a/servconf.h b/servconf.h +index a4a38d6d..11de36a2 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -151,6 +151,7 @@ typedef struct { * authenticated with Kerberos. */ int kerberos_unique_ccache; /* If true, the acquired ticket will * be stored in per-session ccache */ @@ -254,10 +272,23 @@ diff -up openssh-7.4p1/servconf.h.kuserok openssh-7.4p1/servconf.h 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 -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 +diff --git a/sshd_config b/sshd_config +index 8db9f0fb..ea5a878e 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 1251d4d5..0fcb409a 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1041,6 +1041,10 @@ The default value .Cm no can lead to overwriting previous tickets by subseqent connections to the same user account. @@ -266,9 +297,9 @@ diff -up openssh-7.4p1/sshd_config.5.kuserok openssh-7.4p1/sshd_config.5 +The default is +.Cm yes . .It Cm KexAlgorithms - Specifies the available KEX (Key Exchange) algorithms. - Multiple algorithms must be comma-separated. -@@ -1078,6 +1082,7 @@ Available keywords are + Specifies the permitted KEX (Key Exchange) algorithms that the server will + offer to clients. +@@ -1355,6 +1359,7 @@ Available keywords are .Cm IPQoS , .Cm KbdInteractiveAuthentication , .Cm KerberosAuthentication , @@ -276,14 +307,6 @@ diff -up openssh-7.4p1/sshd_config.5.kuserok openssh-7.4p1/sshd_config.5 .Cm LogLevel , .Cm MaxAuthTries , .Cm MaxSessions , -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 +-- +2.49.0 + diff --git a/0017-openssh-6.4p1-fromto-remote.patch b/0017-openssh-6.4p1-fromto-remote.patch new file mode 100644 index 0000000..5e8309d --- /dev/null +++ b/0017-openssh-6.4p1-fromto-remote.patch @@ -0,0 +1,28 @@ +From 20aabb2c445e29d211266ce7434bb0273edf88b9 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 17/50] openssh-6.4p1-fromto-remote + +--- + scp.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/scp.c b/scp.c +index 57c242ff..716ae386 100644 +--- a/scp.c ++++ b/scp.c +@@ -1162,7 +1162,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.49.0 + diff --git a/openssh-6.6.1p1-selinux-contexts.patch b/0018-openssh-6.6.1p1-selinux-contexts.patch similarity index 67% rename from openssh-6.6.1p1-selinux-contexts.patch rename to 0018-openssh-6.6.1p1-selinux-contexts.patch index fa9d591..49f2119 100644 --- a/openssh-6.6.1p1-selinux-contexts.patch +++ b/0018-openssh-6.6.1p1-selinux-contexts.patch @@ -1,8 +1,20 @@ +From 6481ac7fbd0027a7038560e0f51dd0af056cc229 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 18/50] openssh-6.6.1p1-selinux-contexts + +--- + openbsd-compat/port-linux-sshd.c | 69 +++++++++++++++++++++++++++++++- + openbsd-compat/port-linux.c | 2 +- + openbsd-compat/port-linux.h | 1 + + sshd-auth.c | 2 +- + 4 files changed, 71 insertions(+), 3 deletions(-) + diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c -index 8f32464..18a2ca4 100644 +index 8c5fc1fe..646f0887 100644 --- a/openbsd-compat/port-linux-sshd.c +++ b/openbsd-compat/port-linux-sshd.c -@@ -32,6 +32,7 @@ +@@ -33,6 +33,7 @@ #include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */ #include "servconf.h" #include "port-linux.h" @@ -10,7 +22,7 @@ index 8f32464..18a2ca4 100644 #include "sshkey.h" #include "hostfile.h" #include "auth.h" -@@ -445,7 +446,7 @@ sshd_selinux_setup_exec_context(char *pwname) +@@ -450,7 +451,7 @@ sshd_selinux_setup_exec_context(char *pwname) void sshd_selinux_copy_context(void) { @@ -19,7 +31,7 @@ index 8f32464..18a2ca4 100644 if (!sshd_selinux_enabled()) return; -@@ -461,6 +462,72 @@ sshd_selinux_copy_context(void) +@@ -469,6 +470,72 @@ sshd_selinux_copy_context(void) } } @@ -93,24 +105,23 @@ index 8f32464..18a2ca4 100644 #endif diff --git a/openbsd-compat/port-linux.c b/openbsd-compat/port-linux.c -index 22ea8ef..1fc963d 100644 +index 7426f6f7..9a6b1d6e 100644 --- a/openbsd-compat/port-linux.c +++ b/openbsd-compat/port-linux.c -@@ -179,7 +179,7 @@ ssh_selinux_change_context(const char *newname) - strlcpy(newctx + len, newname, newlen - len); - if ((cx = index(cx + 1, ':'))) - strlcat(newctx, cx, newlen); -- debug3("%s: setting context from '%s' to '%s'", __func__, -+ debug_f("setting context from '%s' to '%s'", - oldctx, newctx); +@@ -188,7 +188,7 @@ ssh_selinux_change_context(const char *newname) + xasprintf(&newctx, "%.*s%s%s", (int)(cx - oldctx + 1), oldctx, + newname, cx2 == NULL ? "" : cx2); + +- debug3_f("setting context from '%s' to '%s'", oldctx, newctx); ++ debug_f("setting context from '%s' to '%s'", oldctx, newctx); if (setcon(newctx) < 0) - do_log2(log_level, "%s: setcon %s from %s failed with %s", - __func__, newctx, oldctx, strerror(errno)); + do_log2_f(log_level, "setcon %s from %s failed with %s", + newctx, oldctx, strerror(errno)); diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h -index cb51f99..8b7cda2 100644 +index 1b745a76..7f8ba200 100644 --- a/openbsd-compat/port-linux.h +++ b/openbsd-compat/port-linux.h -@@ -29,6 +29,7 @@ int sshd_selinux_enabled(void); +@@ -27,6 +27,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); @@ -118,16 +129,19 @@ index cb51f99..8b7cda2 100644 #endif #ifdef LINUX_OOM_ADJUST -diff --git a/sshd.c b/sshd.c -index 2871fe9..39b9c08 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -629,7 +629,7 @@ privsep_preauth_child(void) - demote_sensitive_data(); - +diff --git a/sshd-auth.c b/sshd-auth.c +index d51e4636..e4a8edfd 100644 +--- a/sshd-auth.c ++++ b/sshd-auth.c +@@ -188,7 +188,7 @@ privsep_child_demote(void) + fatal_f("ssh_sandbox_init failed"); + #endif #ifdef WITH_SELINUX - ssh_selinux_change_context("sshd_net_t"); + sshd_selinux_change_privsep_preauth_context(); #endif /* Demote the child */ +-- +2.49.0 + diff --git a/openssh-6.6.1p1-log-in-chroot.patch b/0019-openssh-6.6.1p1-log-in-chroot.patch similarity index 54% rename from openssh-6.6.1p1-log-in-chroot.patch rename to 0019-openssh-6.6.1p1-log-in-chroot.patch index 941c694..3b30f98 100644 --- a/openssh-6.6.1p1-log-in-chroot.patch +++ b/0019-openssh-6.6.1p1-log-in-chroot.patch @@ -1,7 +1,25 @@ -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 +From 825018f5f2d892655f3d63167a0d1f3391cec678 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 19/50] 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 6617f267..9782cfb0 100644 +--- a/log.c ++++ b/log.c +@@ -196,6 +196,11 @@ void log_init(const char *av0, LogLevel level, SyslogFacility facility, int on_stderr) { @@ -13,7 +31,7 @@ diff -up openssh-8.6p1/log.c.log-in-chroot openssh-8.6p1/log.c #if defined(HAVE_OPENLOG_R) && defined(SYSLOG_DATA_INIT) struct syslog_data sdata = SYSLOG_DATA_INIT; #endif -@@ -206,8 +211,10 @@ log_init(const char *av0, LogLevel level +@@ -208,8 +213,10 @@ log_init(const char *av0, LogLevel level, SyslogFacility facility, exit(1); } @@ -26,9 +44,10 @@ diff -up openssh-8.6p1/log.c.log-in-chroot openssh-8.6p1/log.c log_on_stderr = on_stderr; if (on_stderr) -diff -up openssh-8.6p1/log.h.log-in-chroot openssh-8.6p1/log.h ---- openssh-8.6p1/log.h.log-in-chroot 2021-04-19 14:43:08.544843434 +0200 -+++ openssh-8.6p1/log.h 2021-04-19 14:56:46.931042176 +0200 +diff --git a/log.h b/log.h +index 8e8dfc23..70048a8a 100644 +--- a/log.h ++++ b/log.h @@ -52,6 +52,7 @@ typedef enum { typedef void (log_handler_fn)(LogLevel, int, const char *, void *); @@ -37,43 +56,11 @@ diff -up openssh-8.6p1/log.h.log-in-chroot openssh-8.6p1/log.h LogLevel log_level_get(void); int log_change_level(LogLevel); int log_is_on_stderr(void); -diff -up openssh-8.6p1/monitor.c.log-in-chroot openssh-8.6p1/monitor.c ---- openssh-8.6p1/monitor.c.log-in-chroot 2021-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; +diff --git a/monitor.c b/monitor.c +index 2ef16cc8..43c10a4e 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -2001,9 +2001,22 @@ monitor_init(void) } void @@ -98,14 +85,11 @@ diff -up openssh-8.6p1/monitor.c.log-in-chroot openssh-8.6p1/monitor.c } #ifdef GSSAPI -diff -up openssh-8.6p1/monitor.h.log-in-chroot openssh-8.6p1/monitor.h ---- openssh-8.6p1/monitor.h.log-in-chroot 2021-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; +diff --git a/monitor.h b/monitor.h +index dbc7e003..d4d631dd 100644 +--- a/monitor.h ++++ b/monitor.h +@@ -85,7 +85,7 @@ struct monitor { }; struct monitor *monitor_init(void); @@ -114,10 +98,11 @@ diff -up openssh-8.6p1/monitor.h.log-in-chroot openssh-8.6p1/monitor.h struct Authctxt; void monitor_child_preauth(struct ssh *, struct monitor *); -diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c ---- openssh-8.6p1/session.c.log-in-chroot 2021-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; +diff --git a/session.c b/session.c +index 2620dd11..54da09d5 100644 +--- a/session.c ++++ b/session.c +@@ -169,6 +169,7 @@ login_cap_t *lc; static int is_child = 0; static int in_chroot = 0; @@ -125,7 +110,7 @@ diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c /* File containing userauth info, if ExposeAuthInfo set */ static char *auth_info_file = NULL; -@@ -661,6 +662,7 @@ do_exec(struct ssh *ssh, Session *s, con +@@ -670,6 +671,7 @@ do_exec(struct ssh *ssh, Session *s, const char *command) int ret; const char *forced = NULL, *tty = NULL; char session_type[1024]; @@ -133,7 +118,7 @@ diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c if (options.adm_forced_command) { original_command = command; -@@ -720,6 +722,10 @@ do_exec(struct ssh *ssh, Session *s, con +@@ -729,6 +731,10 @@ do_exec(struct ssh *ssh, Session *s, const char *command) tty += 5; } @@ -144,7 +129,7 @@ diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c verbose("Starting session: %s%s%s for %s from %.200s port %d id %d", session_type, tty == NULL ? "" : " on ", -@@ -1524,14 +1530,6 @@ child_close_fds(struct ssh *ssh) +@@ -1512,14 +1518,6 @@ child_close_fds(struct ssh *ssh) /* Stop directing logs to a high-numbered fd before we close it */ log_redirect_stderr_to(NULL); @@ -159,7 +144,7 @@ diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c } /* -@@ -1665,8 +1663,6 @@ do_child(struct ssh *ssh, Session *s, co +@@ -1652,8 +1650,6 @@ do_child(struct ssh *ssh, Session *s, const char *command) exit(1); } @@ -168,7 +153,7 @@ diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c do_rc_files(ssh, s, shell); /* restore SIGPIPE for child */ -@@ -1691,9 +1687,17 @@ do_child(struct ssh *ssh, Session *s, co +@@ -1678,9 +1674,17 @@ do_child(struct ssh *ssh, Session *s, const char *command) argv[i] = NULL; optind = optreset = 1; __progname = argv[0]; @@ -187,29 +172,31 @@ diff -up openssh-8.6p1/session.c.log-in-chroot openssh-8.6p1/session.c fflush(NULL); /* Get the last component of the shell name. */ -diff -up openssh-8.6p1/sftp.h.log-in-chroot openssh-8.6p1/sftp.h ---- openssh-8.6p1/sftp.h.log-in-chroot 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/sftp.h 2021-04-19 14:43:08.545843441 +0200 -@@ -97,5 +97,5 @@ +diff --git a/sftp-server-main.c b/sftp-server-main.c +index 2c70f89b..bbb79f27 100644 +--- a/sftp-server-main.c ++++ b/sftp-server-main.c +@@ -48,5 +48,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 -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) +- 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 a4abb9f7..4985da38 100644 +--- a/sftp-server.c ++++ b/sftp-server.c +@@ -1901,7 +1901,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; -@@ -1657,7 +1657,7 @@ sftp_server_main(int argc, char **argv, + int i, r, in, out, ch, skipargs = 0, log_stderr = 0; + ssize_t len, olen; +@@ -1913,7 +1913,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) extern char *__progname; __progname = ssh_get_progname(argv[0]); @@ -218,7 +205,7 @@ diff -up openssh-8.6p1/sftp-server.c.log-in-chroot openssh-8.6p1/sftp-server.c pw = pwcopy(user_pw); -@@ -1730,7 +1730,7 @@ sftp_server_main(int argc, char **argv, +@@ -1986,7 +1986,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw) } } @@ -227,21 +214,23 @@ diff -up openssh-8.6p1/sftp-server.c.log-in-chroot openssh-8.6p1/sftp-server.c /* * On platforms where we can, avoid making /proc/self/{mem,maps} -diff -up openssh-8.6p1/sftp-server-main.c.log-in-chroot openssh-8.6p1/sftp-server-main.c ---- openssh-8.6p1/sftp-server-main.c.log-in-chroot 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/sftp-server-main.c 2021-04-19 14:43:08.545843441 +0200 -@@ -50,5 +50,5 @@ main(int argc, char **argv) - return 1; - } +diff --git a/sftp.h b/sftp.h +index 2bde8bb7..ddf1a396 100644 +--- a/sftp.h ++++ b/sftp.h +@@ -97,5 +97,5 @@ -- return (sftp_server_main(argc, argv, user_pw)); -+ return (sftp_server_main(argc, argv, user_pw, 0)); - } -diff -up openssh-8.6p1/sshd.c.log-in-chroot openssh-8.6p1/sshd.c ---- openssh-8.6p1/sshd.c.log-in-chroot 2021-04-19 14:43:08.543843426 +0200 -+++ openssh-8.6p1/sshd.c 2021-04-19 14:43:08.545843441 +0200 -@@ -559,7 +559,7 @@ privsep_postauth(struct ssh *ssh, Authct - } + 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 478381db..9342e416 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -437,7 +437,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) + #endif /* New socket pair */ - monitor_reinit(pmonitor); @@ -249,7 +238,7 @@ diff -up openssh-8.6p1/sshd.c.log-in-chroot openssh-8.6p1/sshd.c pmonitor->m_pid = fork(); if (pmonitor->m_pid == -1) -@@ -578,6 +578,11 @@ privsep_postauth(struct ssh *ssh, Authct +@@ -456,6 +456,11 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) close(pmonitor->m_sendfd); pmonitor->m_sendfd = -1; @@ -261,3 +250,6 @@ diff -up openssh-8.6p1/sshd.c.log-in-chroot openssh-8.6p1/sshd.c /* Demote the private keys to public keys. */ demote_sensitive_data(); +-- +2.49.0 + diff --git a/0020-openssh-6.6.1p1-scp-non-existing-directory.patch b/0020-openssh-6.6.1p1-scp-non-existing-directory.patch new file mode 100644 index 0000000..94c43ef --- /dev/null +++ b/0020-openssh-6.6.1p1-scp-non-existing-directory.patch @@ -0,0 +1,27 @@ +From 007ee98fa9100f7241985ac2a7eed71e17d89a9f Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 20/50] 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 716ae386..9554b188 100644 +--- a/scp.c ++++ b/scp.c +@@ -1876,6 +1876,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.49.0 + diff --git a/openssh-6.6p1-GSSAPIEnablek5users.patch b/0021-openssh-6.6p1-GSSAPIEnablek5users.patch similarity index 62% rename from openssh-6.6p1-GSSAPIEnablek5users.patch rename to 0021-openssh-6.6p1-GSSAPIEnablek5users.patch index cccb3e0..eeff02a 100644 --- a/openssh-6.6p1-GSSAPIEnablek5users.patch +++ b/0021-openssh-6.6p1-GSSAPIEnablek5users.patch @@ -1,7 +1,21 @@ -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 +From 9c75c175e3555377328fc5fc9b06e94f129b7cd7 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 21/50] 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 187faf92..03188d9b 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, FILE *fp; char file[MAXPATHLEN]; char *line = NULL; @@ -9,7 +23,7 @@ diff -up openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users openssh-7.4p1/gss-ser struct stat st; struct passwd *pw = the_authctxt->pw; int found_principal = 0; -@@ -288,7 +287,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal pri +@@ -288,7 +287,7 @@ ssh_gssapi_krb5_cmdok(krb5_principal principal, const char *name, snprintf(file, sizeof(file), "%s/.k5users", pw->pw_dir); /* If both .k5login and .k5users DNE, self-login is ok. */ @@ -18,18 +32,19 @@ diff -up openssh-7.4p1/gss-serv-krb5.c.GSSAPIEnablek5users openssh-7.4p1/gss-ser return ssh_krb5_kuserok(krb_context, principal, luser, k5login_exists); } -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 +diff --git a/servconf.c b/servconf.c +index 5dd5ca21..c0de7110 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -146,6 +146,7 @@ initialize_server_options(ServerOptions *options) 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; -@@ -345,6 +346,8 @@ fill_default_server_options(ServerOption + options->permit_empty_passwd = -1; +@@ -402,6 +403,8 @@ fill_default_server_options(ServerOptions *options) #endif if (options->use_kuserok == -1) options->use_kuserok = 1; @@ -38,16 +53,16 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c if (options->password_authentication == -1) options->password_authentication = 1; if (options->kbd_interactive_authentication == -1) -@@ -418,7 +421,7 @@ typedef enum { - sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, +@@ -585,7 +588,7 @@ typedef enum { sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, + sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, - sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, -@@ -497,14 +500,16 @@ static struct { +@@ -681,6 +684,7 @@ static struct { { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, @@ -55,8 +70,7 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, - { "gssapicleanupcreds", sUnsupported, SSHCFG_GLOBAL }, - { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, +@@ -689,6 +693,7 @@ static struct { { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL }, @@ -64,7 +78,7 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c #endif { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, -@@ -1653,6 +1658,10 @@ process_server_config_line(ServerOptions +@@ -2450,6 +2455,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, intptr = &options->use_kuserok; goto parse_flag; @@ -72,10 +86,10 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c + intptr = &options->enable_k5users; + goto parse_flag; + - case sMatch: - if (cmdline) - fatal("Match directive not supported as a command-line " -@@ -2026,6 +2035,7 @@ copy_set_server_options(ServerOptions *d + case sMatch: + if (cmdline) + fatal("Match directive not supported as a command-line " +@@ -3005,6 +3014,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(ip_qos_interactive); M_CP_INTOPT(ip_qos_bulk); M_CP_INTOPT(use_kuserok); @@ -83,7 +97,7 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c M_CP_INTOPT(rekey_limit); M_CP_INTOPT(rekey_interval); M_CP_INTOPT(log_level); -@@ -2320,6 +2330,7 @@ dump_config(ServerOptions *o) +@@ -3314,6 +3324,7 @@ dump_config(ServerOptions *o) # endif dump_cfg_fmtint(sKerberosUniqueCCache, o->kerberos_unique_ccache); dump_cfg_fmtint(sKerberosUseKuserok, o->use_kuserok); @@ -91,21 +105,35 @@ diff -up openssh-7.4p1/servconf.c.GSSAPIEnablek5users openssh-7.4p1/servconf.c #endif #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); -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 */ +diff --git a/servconf.h b/servconf.h +index 11de36a2..c08cf6a7 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 */ 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 -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 +diff --git a/sshd_config b/sshd_config +index ea5a878e..33713c88 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 0fcb409a..fe246fc2 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -739,6 +739,12 @@ Specifies whether to automatically destroy the user's credentials cache on logout. The default is .Cm yes . @@ -118,14 +146,6 @@ diff -up openssh-7.4p1/sshd_config.5.GSSAPIEnablek5users openssh-7.4p1/sshd_conf .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. -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 +-- +2.49.0 + diff --git a/0022-openssh-6.8p1-sshdT-output.patch b/0022-openssh-6.8p1-sshdT-output.patch new file mode 100644 index 0000000..4e4766e --- /dev/null +++ b/0022-openssh-6.8p1-sshdT-output.patch @@ -0,0 +1,25 @@ +From 05b09904f431333e19cd24528ef66d1fd15e9efe Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 22/50] openssh-6.8p1-sshdT-output + +--- + servconf.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/servconf.c b/servconf.c +index c0de7110..105e301d 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -3366,7 +3366,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.49.0 + diff --git a/openssh-6.7p1-sftp-force-permission.patch b/0023-openssh-6.7p1-sftp-force-permission.patch similarity index 72% rename from openssh-6.7p1-sftp-force-permission.patch rename to 0023-openssh-6.7p1-sftp-force-permission.patch index 1cfa309..1cdc0df 100644 --- a/openssh-6.7p1-sftp-force-permission.patch +++ b/0023-openssh-6.7p1-sftp-force-permission.patch @@ -1,6 +1,17 @@ -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 +From 34b196198018059bed294fa7a08e70606b4cbc36 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 23/50] 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 5311bf92..5e6e3aa4 100644 +--- a/sftp-server.8 ++++ b/sftp-server.8 @@ -38,6 +38,7 @@ .Op Fl P Ar denied_requests .Op Fl p Ar allowed_requests @@ -22,10 +33,11 @@ diff -up openssh-7.2p2/sftp-server.8.sftp-force-mode openssh-7.2p2/sftp-server.8 .El .Pp On some systems, -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; +diff --git a/sftp-server.c b/sftp-server.c +index 4985da38..6ed1c27f 100644 +--- a/sftp-server.c ++++ b/sftp-server.c +@@ -76,6 +76,10 @@ struct sshbuf *oqueue; /* Version of client */ static u_int version; @@ -36,7 +48,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c /* SSH2_FXP_INIT received */ static int init_done; -@@ -683,6 +687,7 @@ process_open(u_int32_t id) +@@ -745,6 +749,7 @@ process_open(u_int32_t id) Attrib a; char *name; int r, handle, fd, flags, mode, status = SSH2_FX_FAILURE; @@ -44,7 +56,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c if ((r = sshbuf_get_cstring(iqueue, &name, NULL)) != 0 || (r = sshbuf_get_u32(iqueue, &pflags)) != 0 || /* portable flags */ -@@ -692,6 +697,10 @@ process_open(u_int32_t id) +@@ -754,6 +759,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; @@ -55,7 +67,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c logit("open \"%s\" flags %s mode 0%o", name, string_from_portable(pflags), mode); if (readonly && -@@ -713,6 +722,8 @@ process_open(u_int32_t id) +@@ -775,6 +784,8 @@ process_open(u_int32_t id) } } } @@ -64,7 +76,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c if (status != SSH2_FX_OK) send_status(id, status); free(name); -@@ -1494,7 +1505,7 @@ sftp_server_usage(void) +@@ -1894,7 +1905,7 @@ sftp_server_usage(void) fprintf(stderr, "usage: %s [-ehR] [-d start_directory] [-f log_facility] " "[-l log_level]\n\t[-P denied_requests] " @@ -73,7 +85,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c " %s -Q protocol_feature\n", __progname, __progname); exit(1); -@@ -1520,7 +1531,7 @@ sftp_server_main(int argc, char **argv, +@@ -1918,7 +1929,7 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handle pw = pwcopy(user_pw); while (!skipargs && (ch = getopt(argc, argv, @@ -82,7 +94,7 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c switch (ch) { case 'Q': if (strcasecmp(optarg, "requests") != 0) { -@@ -1580,6 +1591,15 @@ sftp_server_main(int argc, char **argv, +@@ -1980,6 +1991,15 @@ sftp_server_main(int argc, char **argv, struct passwd *user_pw, int reset_handle fatal("Invalid umask \"%s\"", optarg); (void)umask((mode_t)mask); break; @@ -98,3 +110,6 @@ diff -up openssh-7.2p2/sftp-server.c.sftp-force-mode openssh-7.2p2/sftp-server.c case 'h': default: sftp_server_usage(); +-- +2.49.0 + diff --git a/openssh-7.2p2-s390-closefrom.patch b/0024-openssh-7.2p2-s390-closefrom.patch similarity index 66% rename from openssh-7.2p2-s390-closefrom.patch rename to 0024-openssh-7.2p2-s390-closefrom.patch index 363538c..0214781 100644 --- a/openssh-7.2p2-s390-closefrom.patch +++ b/0024-openssh-7.2p2-s390-closefrom.patch @@ -1,21 +1,17 @@ -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 +From 9bb31b63142adaaf949e20c2d86c97f9b787217b Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 24/50] openssh-7.2p2-s390-closefrom --- - 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 49a4f35f..f6112458 100644 --- a/openbsd-compat/bsd-closefrom.c +++ b/openbsd-compat/bsd-closefrom.c -@@ -82,7 +82,33 @@ closefrom(int lowfd) +@@ -140,7 +140,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)) @@ -49,4 +45,6 @@ Author: Harald Freudenberger } (void) closedir(dirp); return; +-- +2.49.0 diff --git a/openssh-7.3p1-x11-max-displays.patch b/0025-openssh-7.3p1-x11-max-displays.patch similarity index 53% rename from openssh-7.3p1-x11-max-displays.patch rename to 0025-openssh-7.3p1-x11-max-displays.patch index 2b702d4..68d679c 100644 --- a/openssh-7.3p1-x11-max-displays.patch +++ b/0025-openssh-7.3p1-x11-max-displays.patch @@ -1,18 +1,22 @@ -diff -up openssh-7.4p1/channels.c.x11max openssh-7.4p1/channels.c ---- openssh-7.4p1/channels.c.x11max 2016-12-23 15:46:32.071506625 +0100 -+++ openssh-7.4p1/channels.c 2016-12-23 15:46:32.139506636 +0100 -@@ -152,8 +152,8 @@ static int all_opens_permitted = 0; - #define FWD_PERMIT_ANY_HOST "*" - - /* -- X11 forwarding */ --/* Maximum number of fake X11 displays to try. */ --#define MAX_DISPLAYS 1000 -+/* Minimum port number for X11 forwarding */ -+#define X11_PORT_MIN 6000 - - /* Per-channel callback for pre/post IO actions */ - typedef void chan_fn(struct ssh *, Channel *c); -@@ -4228,7 +4228,7 @@ channel_send_window_changes(void) +From 36e3430d1f81397d5f40600e075272a81f7effce Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 25/50] 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 d46531ce..7438c1a5 100644 +--- a/channels.c ++++ b/channels.c +@@ -4996,7 +4996,7 @@ rdynamic_connect_finish(struct ssh *ssh, Channel *c) */ int x11_create_display_inet(struct ssh *ssh, int x11_display_offset, @@ -21,8 +25,8 @@ diff -up openssh-7.4p1/channels.c.x11max openssh-7.4p1/channels.c u_int *display_numberp, int **chanids) { Channel *nc = NULL; -@@ -4240,10 +4241,15 @@ x11_create_display_inet(int x11_display_ - if (chanids == NULL) +@@ -5009,8 +5009,11 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, + x11_display_offset > UINT16_MAX - X11_BASE_PORT - MAX_DISPLAYS) return -1; + /* Try to bind ports starting at 6000+X11DisplayOffset */ @@ -32,55 +36,22 @@ diff -up openssh-7.4p1/channels.c.x11max openssh-7.4p1/channels.c - display_number < MAX_DISPLAYS; + display_number < x11_max_displays; display_number++) { -- port = 6000 + display_number; -+ port = X11_PORT_MIN + display_number; -+ if (port < X11_PORT_MIN) /* overflow */ -+ break; + port = X11_BASE_PORT + display_number; memset(&hints, 0, sizeof(hints)); - 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_ +@@ -5065,7 +5068,7 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, if (num_socks > 0) break; } - if (display_number >= MAX_DISPLAYS) { -+ if (display_number >= x11_max_displays || port < X11_PORT_MIN ) { ++ if (display_number >= x11_max_displays || port < X11_BASE_PORT ) { error("Failed to allocate internet-domain X11 display socket."); return -1; } -@@ -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 *); +diff --git a/channels.h b/channels.h +index 134528d5..8a09a820 100644 +--- a/channels.h ++++ b/channels.h +@@ -379,7 +379,7 @@ int permitopen_port(const char *); void channel_set_x11_refuse_time(struct ssh *, time_t); int x11_connect_display(struct ssh *); @@ -88,11 +59,12 @@ diff -up openssh-7.4p1/channels.h.x11max openssh-7.4p1/channels.h +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); - -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 + int x11_channel_used_recently(struct ssh *ssh); +diff --git a/servconf.c b/servconf.c +index 105e301d..15c99b30 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -117,6 +117,7 @@ initialize_server_options(ServerOptions *options) options->print_lastlog = -1; options->x11_forwarding = -1; options->x11_display_offset = -1; @@ -100,7 +72,7 @@ diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c options->x11_use_localhost = -1; options->permit_tty = -1; options->permit_user_rc = -1; -@@ -243,6 +244,8 @@ fill_default_server_options(ServerOption +@@ -353,6 +354,8 @@ fill_default_server_options(ServerOptions *options) options->x11_forwarding = 0; if (options->x11_display_offset == -1) options->x11_display_offset = 10; @@ -109,16 +81,16 @@ diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c if (options->x11_use_localhost == -1) options->x11_use_localhost = 1; if (options->xauth_location == NULL) -@@ -419,7 +422,7 @@ typedef enum { - sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication, - sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, - sPrintMotd, sPrintLastLog, sIgnoreRhosts, +@@ -576,7 +579,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, -@@ -540,6 +543,7 @@ static struct { +@@ -714,6 +717,7 @@ static struct { { "ignoreuserknownhosts", sIgnoreUserKnownHosts, SSHCFG_GLOBAL }, { "x11forwarding", sX11Forwarding, SSHCFG_ALL }, { "x11displayoffset", sX11DisplayOffset, SSHCFG_ALL }, @@ -126,7 +98,7 @@ diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c { "x11uselocalhost", sX11UseLocalhost, SSHCFG_ALL }, { "xauthlocation", sXAuthLocation, SSHCFG_GLOBAL }, { "strictmodes", sStrictModes, SSHCFG_GLOBAL }, -@@ -1316,6 +1320,10 @@ process_server_config_line(ServerOptions +@@ -1750,6 +1754,10 @@ process_server_config_line_depth(ServerOptions *options, char *line, *intptr = value; break; @@ -137,7 +109,7 @@ diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c case sX11UseLocalhost: intptr = &options->x11_use_localhost; goto parse_flag; -@@ -2063,6 +2071,7 @@ copy_set_server_options(ServerOptions *d +@@ -3004,6 +3012,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) M_CP_INTOPT(fwd_opts.streamlocal_bind_unlink); M_CP_INTOPT(x11_display_offset); M_CP_INTOPT(x11_forwarding); @@ -145,7 +117,7 @@ diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c M_CP_INTOPT(x11_use_localhost); M_CP_INTOPT(permit_tty); M_CP_INTOPT(permit_user_rc); -@@ -2315,6 +2324,7 @@ dump_config(ServerOptions *o) +@@ -3299,6 +3308,7 @@ dump_config(ServerOptions *o) #endif dump_cfg_int(sLoginGraceTime, o->login_grace_time); dump_cfg_int(sX11DisplayOffset, o->x11_display_offset); @@ -153,10 +125,11 @@ diff -up openssh-7.4p1/servconf.c.x11max openssh-7.4p1/servconf.c dump_cfg_int(sMaxAuthTries, o->max_authtries); dump_cfg_int(sMaxSessions, o->max_sessions); dump_cfg_int(sClientAliveInterval, o->client_alive_interval); -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 @@ +diff --git a/servconf.h b/servconf.h +index c08cf6a7..7c7e5d43 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -38,6 +38,7 @@ #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ #define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ @@ -164,7 +137,7 @@ diff -up openssh-7.4p1/servconf.h.x11max openssh-7.4p1/servconf.h /* Magic name for internal sftp-server */ #define INTERNAL_SFTP_NAME "internal-sftp" -@@ -85,6 +86,7 @@ typedef struct { +@@ -114,6 +115,7 @@ typedef struct { int x11_forwarding; /* If true, permit inet (spoofing) X11 fwd. */ int x11_display_offset; /* What DISPLAY number to start * searching at */ @@ -172,13 +145,14 @@ diff -up openssh-7.4p1/servconf.h.x11max openssh-7.4p1/servconf.h 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 -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) +diff --git a/session.c b/session.c +index 54da09d5..28bbb8a7 100644 +--- a/session.c ++++ b/session.c +@@ -2611,8 +2611,9 @@ session_setup_x11fwd(struct ssh *ssh, 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, @@ -187,10 +161,11 @@ diff -up openssh-7.4p1/session.c.x11max openssh-7.4p1/session.c debug("x11_create_display_inet failed."); return 0; } -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 +diff --git a/sshd_config.5 b/sshd_config.5 +index fe246fc2..26fcdc84 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -1391,6 +1391,7 @@ Available keywords are .Cm TrustedUserCAKeys , .Cm UnusedConnectionTimeout , .Cm X11DisplayOffset , @@ -198,7 +173,7 @@ diff -up openssh-7.4p1/sshd_config.5.x11max openssh-7.4p1/sshd_config.5 .Cm X11Forwarding and .Cm X11UseLocalhost . -@@ -1566,6 +1567,12 @@ Specifies the first display number avail +@@ -2111,6 +2112,12 @@ Specifies the first display number available for X11 forwarding. This prevents sshd from interfering with real X11 servers. The default is 10. @@ -211,3 +186,6 @@ diff -up openssh-7.4p1/sshd_config.5.x11max openssh-7.4p1/sshd_config.5 .It Cm X11Forwarding Specifies whether X11 forwarding is permitted. The argument must be +-- +2.49.0 + diff --git a/openssh-7.6p1-cleanup-selinux.patch b/0026-openssh-7.6p1-cleanup-selinux.patch similarity index 60% rename from openssh-7.6p1-cleanup-selinux.patch rename to 0026-openssh-7.6p1-cleanup-selinux.patch index f7cd50f..c4f2d15 100644 --- a/openssh-7.6p1-cleanup-selinux.patch +++ b/0026-openssh-7.6p1-cleanup-selinux.patch @@ -1,40 +1,58 @@ -diff -up openssh/auth2-pubkey.c.refactor openssh/auth2-pubkey.c ---- openssh/auth2-pubkey.c.refactor 2019-04-04 13:19:12.188821236 +0200 -+++ openssh/auth2-pubkey.c 2019-04-04 13:19:12.276822078 +0200 -@@ -72,6 +72,9 @@ +From 43320351b6f150167190aacc84f2f87030fef3d2 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 26/50] 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 | 4 +-- + platform.c | 6 ++++- + sshconnect.c | 2 +- + sshd-auth.c | 2 +- + sshd-session.c | 6 +++-- + 9 files changed, 45 insertions(+), 32 deletions(-) + +diff --git a/auth2-pubkey.c b/auth2-pubkey.c +index 267a27d2..0d5ae0df 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -77,6 +77,8 @@ /* import */ extern ServerOptions options; +extern int inetd_flag; -+extern int rexeced_flag; +extern Authctxt *the_authctxt; + extern struct authmethod_cfg methodcfg_pubkey; static char * - format_key(const struct sshkey *key) -@@ -511,7 +514,8 @@ match_principals_command(struct ssh *ssh +@@ -485,7 +487,8 @@ match_principals_command(struct passwd *user_pw, const struct sshkey *key, if ((pid = subprocess("AuthorizedPrincipalsCommand", command, ac, av, &f, SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD, - runas_pw, temporarily_use_uid, restore_uid)) == 0) + runas_pw, temporarily_use_uid, restore_uid, -+ (inetd_flag && !rexeced_flag), the_authctxt)) == 0) ++ inetd_flag, the_authctxt)) == 0) goto out; uid_swapped = 1; -@@ -981,7 +985,8 @@ user_key_command_allowed2(struct ssh *ss +@@ -755,7 +758,8 @@ user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key, 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 && !rexeced_flag), the_authctxt)) == 0) ++ inetd_flag, the_authctxt)) == 0) goto out; uid_swapped = 1; -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 * +diff --git a/misc.c b/misc.c +index 1e31acc9..09722962 100644 +--- a/misc.c ++++ b/misc.c +@@ -2764,7 +2764,8 @@ stdfd_devnull(int do_stdin, int do_stdout, int do_stderr) pid_t subprocess(const char *tag, const char *command, int ac, char **av, FILE **child, u_int flags, @@ -44,7 +62,7 @@ diff -up openssh/misc.c.refactor openssh/misc.c { FILE *f = NULL; struct stat st; -@@ -872,7 +873,7 @@ subprocess(const char *tag, struct passw +@@ -2898,7 +2899,7 @@ subprocess(const char *tag, const char *command, _exit(1); } #ifdef WITH_SELINUX @@ -53,10 +71,11 @@ diff -up openssh/misc.c.refactor openssh/misc.c error ("failed to copy environment: %s", strerror(errno)); _exit(127); -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); +diff --git a/misc.h b/misc.h +index efecdf1a..9efa9cf4 100644 +--- a/misc.h ++++ b/misc.h +@@ -122,7 +122,7 @@ typedef void privrestore_fn(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, @@ -65,36 +84,22 @@ diff -up openssh/misc.h.refactor openssh/misc.h typedef struct arglist arglist; struct arglist { -diff -up openssh/openbsd-compat/port-linux.h.refactor openssh/openbsd-compat/port-linux.h ---- openssh/openbsd-compat/port-linux.h.refactor 2019-04-04 13:19:12.256821887 +0200 -+++ openssh/openbsd-compat/port-linux.h 2019-04-04 13:19:12.276822078 +0200 -@@ -26,8 +26,8 @@ void ssh_selinux_setfscreatecon(const ch - - int sshd_selinux_enabled(void); - void sshd_selinux_copy_context(void); --void sshd_selinux_setup_exec_context(char *); --int sshd_selinux_setup_env_variables(void); -+void sshd_selinux_setup_exec_context(char *, int, int(char *, const char *), void *, int); -+int sshd_selinux_setup_env_variables(int inetd, void *); - void sshd_selinux_change_privsep_preauth_context(void); - #endif - -diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compat/port-linux-sshd.c ---- openssh/openbsd-compat/port-linux-sshd.c.refactor 2019-04-04 13:19:12.256821887 +0200 -+++ openssh/openbsd-compat/port-linux-sshd.c 2019-04-04 13:19:12.276822078 +0200 -@@ -49,11 +49,6 @@ +diff --git a/openbsd-compat/port-linux-sshd.c b/openbsd-compat/port-linux-sshd.c +index 646f0887..291b569a 100644 +--- a/openbsd-compat/port-linux-sshd.c ++++ b/openbsd-compat/port-linux-sshd.c +@@ -49,10 +49,6 @@ #include #endif -extern ServerOptions options; -extern Authctxt *the_authctxt; -extern int inetd_flag; --extern int rexeced_flag; - /* Wrapper around is_selinux_enabled() to log its return value once only */ int sshd_selinux_enabled(void) -@@ -223,7 +218,8 @@ get_user_context(const char *sename, con +@@ -222,7 +218,8 @@ get_user_context(const char *sename, const char *role, const char *lvl, } static void @@ -104,7 +109,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa { *role = NULL; *level = NULL; -@@ -241,8 +237,8 @@ ssh_selinux_get_role_level(char **role, +@@ -240,8 +237,8 @@ ssh_selinux_get_role_level(char **role, const char **level) /* Return the default security context for the given username */ static int @@ -115,7 +120,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa { char *sename, *lvl; char *role; -@@ -250,7 +246,7 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -249,7 +246,7 @@ sshd_selinux_getctxbyname(char *pwname, int r = 0; context_t con = NULL; @@ -124,16 +129,16 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa #ifdef HAVE_GETSEUSERBYNAME if ((r=getseuserbyname(pwname, &sename, &lvl)) != 0) { -@@ -272,7 +268,7 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -271,7 +268,7 @@ sshd_selinux_getctxbyname(char *pwname, if (r == 0) { /* If launched from xinetd, we must use current level */ -- if (inetd_flag && !rexeced_flag) { +- if (inetd_flag) { + if (inetd) { security_context_t sshdsc=NULL; if (getcon_raw(&sshdsc) < 0) -@@ -333,7 +329,8 @@ sshd_selinux_getctxbyname(char *pwname, +@@ -332,7 +329,8 @@ sshd_selinux_getctxbyname(char *pwname, /* Setup environment variables for pam_selinux */ static int @@ -143,7 +148,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa { const char *reqlvl; char *role; -@@ -342,11 +339,11 @@ sshd_selinux_setup_variables(int(*set_it +@@ -341,11 +339,11 @@ sshd_selinux_setup_variables(int(*set_it)(char *, const char *)) debug3_f("setting execution context"); @@ -152,12 +157,12 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa rv = set_it("SELINUX_ROLE_REQUESTED", role ? role : ""); -- if (inetd_flag && !rexeced_flag) { +- if (inetd_flag) { + if (inetd) { use_current = "1"; } else { use_current = ""; -@@ -362,9 +359,10 @@ sshd_selinux_setup_variables(int(*set_it +@@ -361,9 +359,10 @@ sshd_selinux_setup_variables(int(*set_it)(char *, const char *)) } static int @@ -170,7 +175,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa } static int -@@ -374,25 +372,28 @@ do_setenv(char *name, const char *value) +@@ -373,25 +372,28 @@ do_setenv(char *name, const char *value) } int @@ -204,7 +209,7 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa switch (security_getenforce()) { case -1: fatal_f("security_getenforce() failed"); -@@ -410,7 +411,7 @@ sshd_selinux_setup_exec_context(char *pw +@@ -407,7 +409,7 @@ sshd_selinux_setup_exec_context(char *pwname) debug3_f("setting execution context"); @@ -213,66 +218,50 @@ diff -up openssh/openbsd-compat/port-linux-sshd.c.refactor openssh/openbsd-compa if (r >= 0) { r = setexeccon(user_ctx); if (r < 0) { -diff -up openssh/platform.c.refactor openssh/platform.c ---- openssh/platform.c.refactor 2019-04-04 13:19:12.204821389 +0200 -+++ openssh/platform.c 2019-04-04 13:19:12.277822088 +0200 -@@ -32,6 +32,9 @@ +diff --git a/openbsd-compat/port-linux.h b/openbsd-compat/port-linux.h +index 7f8ba200..3cd7da6a 100644 +--- a/openbsd-compat/port-linux.h ++++ b/openbsd-compat/port-linux.h +@@ -25,8 +25,8 @@ 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); ++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 --git a/platform.c b/platform.c +index 0d12f311..f0800b1f 100644 +--- a/platform.c ++++ b/platform.c +@@ -33,6 +33,8 @@ + #include "openbsd-compat/openbsd-compat.h" - extern int use_privsep; extern ServerOptions options; +extern int inetd_flag; -+extern int rexeced_flag; +extern Authctxt *the_authctxt; - void - platform_pre_listen(void) -@@ -183,7 +186,9 @@ platform_setusercontext_post_groups(stru + /* 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) } #endif /* HAVE_SETPCRED */ #ifdef WITH_SELINUX - sshd_selinux_setup_exec_context(pw->pw_name); + sshd_selinux_setup_exec_context(pw->pw_name, -+ (inetd_flag && !rexeced_flag), do_pam_putenv, the_authctxt, ++ inetd_flag, do_pam_putenv, the_authctxt, + options.use_pam); #endif } -diff -up openssh/sshd.c.refactor openssh/sshd.c ---- openssh/sshd.c.refactor 2019-04-04 13:19:12.275822068 +0200 -+++ openssh/sshd.c 2019-04-04 13:19:51.270195262 +0200 -@@ -158,7 +158,7 @@ int debug_flag = 0; - static int test_flag = 0; - - /* Flag indicating that the daemon is being started from inetd. */ --static int inetd_flag = 0; -+int inetd_flag = 0; - - /* Flag indicating that sshd should not detach and become a daemon. */ - static int no_daemon_flag = 0; -@@ -171,7 +171,7 @@ static char **saved_argv; - static int saved_argc; - - /* re-exec */ --static int rexeced_flag = 0; -+int rexeced_flag = 0; - static int rexec_flag = 1; - static int rexec_argc = 0; - static char **rexec_argv; -@@ -2192,7 +2192,9 @@ main(int ac, char **av) - } - #endif - #ifdef WITH_SELINUX -- sshd_selinux_setup_exec_context(authctxt->pw->pw_name); -+ sshd_selinux_setup_exec_context(authctxt->pw->pw_name, -+ (inetd_flag && !rexeced_flag), do_pam_putenv, the_authctxt, -+ options.use_pam); - #endif - #ifdef USE_PAM - if (options.use_pam) { -diff -up openssh/sshconnect.c.refactor openssh/sshconnect.c ---- openssh/sshconnect.c.refactor 2021-02-24 00:12:03.065325046 +0100 -+++ openssh/sshconnect.c 2021-02-24 00:12:12.126449544 +0100 -@@ -892,7 +892,7 @@ load_hostkeys_command(struct hostkeys *h +diff --git a/sshconnect.c b/sshconnect.c +index c86182d1..04084810 100644 +--- a/sshconnect.c ++++ b/sshconnect.c +@@ -925,7 +925,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| @@ -281,3 +270,43 @@ diff -up openssh/sshconnect.c.refactor openssh/sshconnect.c goto out; load_hostkeys_file(hostkeys, hostfile_hostname, tag, f, 1); +diff --git a/sshd-auth.c b/sshd-auth.c +index e4a8edfd..897db9b4 100644 +--- a/sshd-auth.c ++++ b/sshd-auth.c +@@ -122,7 +122,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 9342e416..81d30152 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -136,7 +136,7 @@ char *config_file_name = _PATH_SERVER_CONFIG_FILE; + int debug_flag = 0; + + /* Flag indicating that the daemon is being started from inetd. */ +-static int inetd_flag = 0; ++int inetd_flag = 0; + + /* debug goes to stderr unless inetd_flag is set */ + static int log_stderr = 0; +@@ -1359,7 +1359,9 @@ main(int ac, char **av) + } + #endif + #ifdef WITH_SELINUX +- sshd_selinux_setup_exec_context(authctxt->pw->pw_name); ++ sshd_selinux_setup_exec_context(authctxt->pw->pw_name, ++ inetd_flag, do_pam_putenv, the_authctxt, ++ options.use_pam); + #endif + #ifdef USE_PAM + if (options.use_pam) { +-- +2.49.0 + diff --git a/0027-openssh-7.5p1-sandbox.patch b/0027-openssh-7.5p1-sandbox.patch new file mode 100644 index 0000000..435d029 --- /dev/null +++ b/0027-openssh-7.5p1-sandbox.patch @@ -0,0 +1,58 @@ +From 35205319dd71d8e61c1596b8f9479df91aff7756 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 27/50] 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 b31062c2..1fabf99d 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -277,6 +277,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 +@@ -295,6 +298,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 +@@ -304,6 +322,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.49.0 + diff --git a/openssh-8.0p1-pkcs11-uri.patch b/0028-openssh-8.0p1-pkcs11-uri.patch similarity index 82% rename from openssh-8.0p1-pkcs11-uri.patch rename to 0028-openssh-8.0p1-pkcs11-uri.patch index affdd72..73e890b 100644 --- a/openssh-8.0p1-pkcs11-uri.patch +++ b/0028-openssh-8.0p1-pkcs11-uri.patch @@ -1,7 +1,102 @@ -diff -up openssh-8.7p1/configure.ac.pkcs11-uri openssh-8.7p1/configure.ac ---- openssh-8.7p1/configure.ac.pkcs11-uri 2021-08-30 13:07:43.646699953 +0200 -+++ openssh-8.7p1/configure.ac 2021-08-30 13:07:43.662700088 +0200 -@@ -1985,12 +1985,14 @@ AC_LINK_IFELSE( +From 5d6ec35c1a0e06452a2c087decb0baf6e8063e21 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 28/50] openssh-8.0p1-pkcs11-uri + +--- + Makefile.in | 20 +- + configure.ac | 37 ++ + regress/Makefile | 8 +- + regress/pkcs11.sh | 349 +++++++++++++++ + regress/unittests/Makefile | 2 +- + regress/unittests/pkcs11/tests.c | 346 ++++++++++++++ + ssh-add.c | 48 +- + ssh-agent.c | 103 ++++- + ssh-keygen.c | 7 +- + ssh-pkcs11-client.c | 3 + + ssh-pkcs11-uri.c | 437 ++++++++++++++++++ + ssh-pkcs11-uri.h | 43 ++ + ssh-pkcs11.c | 745 +++++++++++++++++++++++-------- + ssh-pkcs11.h | 4 + + ssh.c | 104 ++++- + ssh_config.5 | 15 + + 16 files changed, 2024 insertions(+), 247 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 78f65948..6c417ef7 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -110,7 +110,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 \ +@@ -339,6 +339,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) +@@ -377,6 +379,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 +@@ -558,6 +562,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 ] || \ +@@ -731,6 +736,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 \ +@@ -776,7 +791,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 13c70a98..d9bd2f51 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2172,12 +2172,14 @@ AC_LINK_IFELSE( [AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).]) ]) @@ -16,7 +111,7 @@ diff -up openssh-8.7p1/configure.ac.pkcs11-uri openssh-8.7p1/configure.ac fi ] ) -@@ -2019,6 +2021,40 @@ AC_SEARCH_LIBS([dlopen], [dl]) +@@ -2207,6 +2209,40 @@ AC_SEARCH_LIBS([dlopen], [dl]) AC_CHECK_FUNCS([dlopen]) AC_CHECK_DECL([RTLD_NOW], [], [], [#include ]) @@ -57,7 +152,7 @@ diff -up openssh-8.7p1/configure.ac.pkcs11-uri openssh-8.7p1/configure.ac # IRIX has a const char return value for gai_strerror() AC_CHECK_FUNCS([gai_strerror], [ AC_DEFINE([HAVE_GAI_STRERROR]) -@@ -5624,6 +5660,7 @@ echo " BSD Auth support +@@ -5820,6 +5856,7 @@ echo " BSD Auth support: $BSD_AUTH_MSG" echo " Random number source: $RAND_MSG" echo " Privsep sandbox style: $SANDBOX_STYLE" echo " PKCS#11 support: $enable_pkcs11" @@ -65,87 +160,11 @@ diff -up openssh-8.7p1/configure.ac.pkcs11-uri openssh-8.7p1/configure.ac echo " U2F/FIDO support: $enable_sk" echo "" -diff -up openssh-8.7p1/Makefile.in.pkcs11-uri openssh-8.7p1/Makefile.in ---- openssh-8.7p1/Makefile.in.pkcs11-uri 2021-08-30 13:07:43.571699324 +0200 -+++ openssh-8.7p1/Makefile.in 2021-08-30 13:07:43.663700096 +0200 -@@ -103,7 +103,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 \ -@@ -302,6 +302,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 -@@ -339,6 +341,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 -@@ -677,6 +682,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 \ -@@ -711,7 +726,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 unit - echo all tests passed -diff -up openssh-8.7p1/regress/agent-pkcs11.sh.pkcs11-uri openssh-8.7p1/regress/agent-pkcs11.sh ---- openssh-8.7p1/regress/agent-pkcs11.sh.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/regress/agent-pkcs11.sh 2021-08-30 13:07:43.663700096 +0200 -@@ -113,7 +113,7 @@ else - done - - trace "remove pkcs11 keys" -- echo ${TEST_SSH_PIN} | notty ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1 -+ ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1 - r=$? - if [ $r -ne 0 ]; then - fail "ssh-add -e failed: exit code $r" -diff -up openssh-8.7p1/regress/Makefile.pkcs11-uri openssh-8.7p1/regress/Makefile ---- openssh-8.7p1/regress/Makefile.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/regress/Makefile 2021-08-30 13:07:43.663700096 +0200 -@@ -122,7 +122,8 @@ CLEANFILES= *.core actual agent-key.* au +diff --git a/regress/Makefile b/regress/Makefile +index 7e7f95b5..f36de51e 100644 +--- a/regress/Makefile ++++ b/regress/Makefile +@@ -137,7 +137,8 @@ CLEANFILES= *.core actual agent-key.* authorized_keys_${USERNAME} \ known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \ modpipe netcat no_identity_config \ pidfile putty.rsa2 ready regress.log remote_pid \ @@ -155,7 +174,7 @@ diff -up openssh-8.7p1/regress/Makefile.pkcs11-uri openssh-8.7p1/regress/Makefil rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \ scp-ssh-wrapper.scp setuid-allowed sftp-server.log \ sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \ -@@ -252,8 +253,9 @@ unit: +@@ -297,8 +298,9 @@ unit: V="" ; \ test "x${USE_VALGRIND}" = "x" || \ V=${.CURDIR}/valgrind-unit.sh ; \ @@ -167,9 +186,11 @@ diff -up openssh-8.7p1/regress/Makefile.pkcs11-uri openssh-8.7p1/regress/Makefil -d ${.CURDIR}/unittests/sshkey/testdata ; \ $$V ${.OBJDIR}/unittests/sshsig/test_sshsig \ -d ${.CURDIR}/unittests/sshsig/testdata ; \ -diff -up openssh-8.7p1/regress/pkcs11.sh.pkcs11-uri openssh-8.7p1/regress/pkcs11.sh ---- openssh-8.7p1/regress/pkcs11.sh.pkcs11-uri 2021-08-30 13:07:43.663700096 +0200 -+++ openssh-8.7p1/regress/pkcs11.sh 2021-08-30 13:07:43.663700096 +0200 +diff --git a/regress/pkcs11.sh b/regress/pkcs11.sh +new file mode 100644 +index 00000000..a91aee94 +--- /dev/null ++++ b/regress/pkcs11.sh @@ -0,0 +1,349 @@ +# +# Copyright (c) 2017 Red Hat @@ -520,21 +541,24 @@ diff -up openssh-8.7p1/regress/pkcs11.sh.pkcs11-uri openssh-8.7p1/regress/pkcs11 + trace "kill agent" + ${SSHAGENT} -k > /dev/null +fi -diff -up openssh-8.7p1/regress/unittests/Makefile.pkcs11-uri openssh-8.7p1/regress/unittests/Makefile ---- openssh-8.7p1/regress/unittests/Makefile.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/regress/unittests/Makefile 2021-08-30 13:07:43.663700096 +0200 -@@ -2,6 +2,6 @@ +diff --git a/regress/unittests/Makefile b/regress/unittests/Makefile +index e370900e..d6c89c12 100644 +--- a/regress/unittests/Makefile ++++ b/regress/unittests/Makefile +@@ -1,6 +1,6 @@ + # $OpenBSD: Makefile,v 1.13 2023/09/24 08:14:13 claudio Exp $ - REGRESS_FAIL_EARLY?= yes SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion -SUBDIR+=authopt misc sshsig +SUBDIR+=authopt misc sshsig pkcs11 .include -diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1/regress/unittests/pkcs11/tests.c ---- openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri 2021-08-30 13:07:43.664700104 +0200 -+++ openssh-8.7p1/regress/unittests/pkcs11/tests.c 2021-08-30 13:07:43.664700104 +0200 -@@ -0,0 +1,337 @@ +diff --git a/regress/unittests/pkcs11/tests.c b/regress/unittests/pkcs11/tests.c +new file mode 100644 +index 00000000..7d4fa499 +--- /dev/null ++++ b/regress/unittests/pkcs11/tests.c +@@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -563,7 +587,7 @@ diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1 +#include "sshbuf.h" +#include "ssh-pkcs11-uri.h" + -+#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL) ++#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL) + +/* prototypes are not public -- specify them here internally for tests */ +struct sshbuf *percent_encode(const char *, size_t, char *); @@ -596,6 +620,10 @@ diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1 + ASSERT_STRING_EQ(a->lib_manuf, b->lib_manuf); + else /* both should be null */ + ASSERT_PTR_EQ(a->lib_manuf, b->lib_manuf); ++ if (b->serial != NULL) ++ ASSERT_STRING_EQ(a->serial, b->serial); ++ else /* both should be null */ ++ ASSERT_PTR_EQ(a->serial, b->serial); +} + +void @@ -630,7 +658,7 @@ diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1 + +struct pkcs11_uri * +compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf, -+ char *manuf, char *module_path, char *object, char *pin) ++ char *manuf, char *serial, char *module_path, char *object, char *pin) +{ + struct pkcs11_uri *uri = pkcs11_uri_init(); + if (id_len > 0) { @@ -641,6 +669,7 @@ diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1 + uri->token = token; + uri->lib_manuf = lib_manuf; + uri->manuf = manuf; ++ uri->serial = serial; + uri->object = object; + uri->pin = pin; + return uri; @@ -651,47 +680,49 @@ diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1 +{ + /* path arguments */ + check_parse("pkcs11:id=%01", -+ compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + check_parse("pkcs11:id=%00%01", -+ compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + check_parse("pkcs11:token=SSH%20Keys", -+ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL, NULL)); + check_parse("pkcs11:library-manufacturer=OpenSC", -+ compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL, NULL)); + check_parse("pkcs11:manufacturer=piv_II", -+ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL)); ++ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL, NULL)); ++ check_parse("pkcs11:serial=IamSerial", ++ compose_uri(NULL, 0, NULL, NULL, NULL, "IamSerial", NULL, NULL, NULL)); + check_parse("pkcs11:object=SIGN%20Key", -+ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "SIGN Key", NULL)); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, "SIGN Key", NULL)); + /* query arguments */ + check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so", -+ compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); + check_parse("pkcs11:?pin-value=123456", -+ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, "123456")); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, "123456")); + + /* combinations */ + /* ID SHOULD be percent encoded */ + check_parse("pkcs11:token=SSH%20Key;id=0", -+ compose_uri("0", 1, "SSH Key", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("0", 1, "SSH Key", NULL, NULL, NULL, NULL, NULL, NULL)); + check_parse( + "pkcs11:manufacturer=CAC?module-path=/usr/lib64/p11-kit-proxy.so", -+ compose_uri(NULL, 0, NULL, NULL, "CAC", ++ compose_uri(NULL, 0, NULL, NULL, "CAC", NULL, + "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); + check_parse( + "pkcs11:object=RSA%20Key?module-path=/usr/lib64/pkcs11/opencryptoki.so", -+ compose_uri(NULL, 0, NULL, NULL, NULL, ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, + "/usr/lib64/pkcs11/opencryptoki.so", "RSA Key", NULL)); + check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so&pin-value=123456", -+ compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, "123456")); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, "123456")); + + /* empty path component matches everything */ + check_parse("pkcs11:", EMPTY_URI); + + /* empty string is a valid to match against (and different from NULL) */ + check_parse("pkcs11:token=", -+ compose_uri(NULL, 0, "", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "", NULL, NULL, NULL, NULL, NULL, NULL)); + /* Percent character needs to be percent-encoded */ + check_parse("pkcs11:token=%25", -+ compose_uri(NULL, 0, "%", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "%", NULL, NULL, NULL, NULL, NULL, NULL)); +} + +static void @@ -703,7 +734,7 @@ diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1 + check_parse_rv("pkcs11:id=%ZZ", EMPTY_URI, -1); + /* Space MUST be percent encoded -- XXX not enforced yet */ + check_parse("pkcs11:token=SSH Keys", -+ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL, NULL)); + /* MUST NOT contain duplicate attributes of the same name */ + check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1); + /* MUST NOT contain duplicate attributes of the same name */ @@ -734,29 +765,31 @@ diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1 +{ + /* path arguments */ + check_gen("pkcs11:id=%01", -+ compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + check_gen("pkcs11:id=%00%01", -+ compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL, NULL)); + check_gen("pkcs11:token=SSH%20Keys", /* space must be percent encoded */ -+ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL, NULL)); + /* library-manufacturer is not implmented now */ + /*check_gen("pkcs11:library-manufacturer=OpenSC", -+ compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL));*/ ++ compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL, NULL));*/ + check_gen("pkcs11:manufacturer=piv_II", -+ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL)); ++ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL, NULL)); ++ check_gen("pkcs11:serial=IamSerial", ++ compose_uri(NULL, 0, NULL, NULL, NULL, "IamSerial", NULL, NULL, NULL)); + check_gen("pkcs11:object=RSA%20Key", -+ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "RSA Key", NULL)); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, "RSA Key", NULL)); + /* query arguments */ + check_gen("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so", -+ compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); ++ compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); + + /* combinations */ + check_gen("pkcs11:id=%02;token=SSH%20Keys", -+ compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL, NULL, NULL)); ++ compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL, NULL, NULL, NULL)); + check_gen("pkcs11:id=%EE%02?module-path=/usr/lib64/p11-kit-proxy.so", -+ compose_uri("\xEE\x02", 2, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); ++ compose_uri("\xEE\x02", 2, NULL, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL)); + check_gen("pkcs11:object=Encryption%20Key;manufacturer=piv_II", -+ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, "Encryption Key", NULL)); ++ compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, "Encryption Key", NULL)); + + /* empty path component matches everything */ + check_gen("pkcs11:", EMPTY_URI); @@ -872,10 +905,11 @@ diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1 + test_parse_invalid(); + test_generate_valid(); +} -diff -up openssh-8.7p1/ssh-add.c.pkcs11-uri openssh-8.7p1/ssh-add.c ---- openssh-8.7p1/ssh-add.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/ssh-add.c 2021-08-30 13:07:43.664700104 +0200 -@@ -68,6 +68,7 @@ +diff --git a/ssh-add.c b/ssh-add.c +index 0035cb84..b0f47f4d 100644 +--- a/ssh-add.c ++++ b/ssh-add.c +@@ -69,6 +69,7 @@ #include "ssh-sk.h" #include "sk-api.h" #include "hostfile.h" @@ -883,12 +917,16 @@ diff -up openssh-8.7p1/ssh-add.c.pkcs11-uri openssh-8.7p1/ssh-add.c /* argv0 */ extern char *__progname; -@@ -229,6 +230,34 @@ delete_all(int agent_fd, int qflag) +@@ -242,6 +243,38 @@ delete_all(int agent_fd, int qflag) return ret; } +#ifdef ENABLE_PKCS11 -+static int update_card(int, int, const char *, int, struct dest_constraint **, size_t, char *); ++static int ++update_card(int agent_fd, int add, const char *id, int qflag, ++ int key_only, int cert_only, ++ struct dest_constraint **dest_constraints, size_t ndest_constraints, ++ struct sshkey **certs, size_t ncerts, char *pin); + +int +update_pkcs11_uri(int agent_fd, int adding, const char *pkcs11_uri, int qflag, @@ -910,32 +948,35 @@ diff -up openssh-8.7p1/ssh-add.c.pkcs11-uri openssh-8.7p1/ssh-add.c + } + pkcs11_uri_cleanup(uri); + -+ return update_card(agent_fd, adding, pkcs11_uri, qflag, -+ dest_constraints, ndest_constraints, pin); ++ return update_card(agent_fd, adding, pkcs11_uri, qflag, 1, 0, ++ dest_constraints, ndest_constraints, NULL, 0, pin); +} +#endif + static int - add_file(int agent_fd, const char *filename, int key_only, int qflag, - const char *skprovider, struct dest_constraint **dest_constraints, -@@ -445,12 +472,11 @@ add_file(int agent_fd, const char *filen - - static int + add_file(int agent_fd, const char *filename, int key_only, int cert_only, + int qflag, const char *skprovider, +@@ -462,15 +495,14 @@ static int update_card(int agent_fd, int add, const char *id, int qflag, -- struct dest_constraint **dest_constraints, size_t ndest_constraints) -+ struct dest_constraint **dest_constraints, size_t ndest_constraints, char *pin) + int key_only, int cert_only, + struct dest_constraint **dest_constraints, size_t ndest_constraints, +- struct sshkey **certs, size_t ncerts) ++ struct sshkey **certs, size_t ncerts, char *pin) { - char *pin = NULL; int r, ret = -1; + if (key_only) + ncerts = 0; + - if (add) { + if (add && pin == NULL) { if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", RP_ALLOW_STDIN)) == NULL) return -1; -@@ -630,6 +656,14 @@ static int - const char *skprovider, struct dest_constraint **dest_constraints, - size_t ndest_constraints) +@@ -658,6 +690,14 @@ do_file(int agent_fd, int deleting, int key_only, int cert_only, + char *file, int qflag, const char *skprovider, + struct dest_constraint **dest_constraints, size_t ndest_constraints) { +#ifdef ENABLE_PKCS11 + if (strlen(file) >= strlen(PKCS11_URI_SCHEME) && @@ -946,24 +987,25 @@ diff -up openssh-8.7p1/ssh-add.c.pkcs11-uri openssh-8.7p1/ssh-add.c + } +#endif if (deleting) { - if (delete_file(agent_fd, file, key_only, qflag) == -1) - return -1; -@@ -813,7 +846,7 @@ main(int argc, char **argv) - } - if (pkcs11provider != NULL) { + if (delete_file(agent_fd, file, key_only, + cert_only, qflag) == -1) +@@ -1001,7 +1041,7 @@ main(int argc, char **argv) if (update_card(agent_fd, !deleting, pkcs11provider, -- qflag, dest_constraints, ndest_constraints) == -1) -+ qflag, dest_constraints, ndest_constraints, NULL) == -1) + qflag, key_only, cert_only, + dest_constraints, ndest_constraints, +- certs, ncerts) == -1) ++ certs, ncerts, NULL) == -1) ret = 1; goto done; } -diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c ---- openssh-8.7p1/ssh-agent.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/ssh-agent.c 2021-08-30 13:07:43.664700104 +0200 -@@ -847,10 +847,72 @@ no_identities(SocketEntry *e) +diff --git a/ssh-agent.c b/ssh-agent.c +index c27c5a95..798bf9b6 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c +@@ -1569,10 +1569,74 @@ add_p11_identity(struct sshkey *key, char *comment, const char *provider, + idtab->nentries++; } - #ifdef ENABLE_PKCS11 +static char * +sanitize_pkcs11_provider(const char *provider) +{ @@ -974,6 +1016,8 @@ diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c + if (provider == NULL) + return NULL; + ++ memset(canonical_provider, 0, sizeof(canonical_provider)); ++ + if (strlen(provider) >= strlen(PKCS11_URI_SCHEME) && + strncmp(provider, PKCS11_URI_SCHEME, + strlen(PKCS11_URI_SCHEME)) == 0) { @@ -1034,8 +1078,8 @@ diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c char **comments = NULL; int r, i, count = 0, success = 0, confirm = 0; u_int seconds = 0; -@@ -869,33 +931,28 @@ process_add_smartcard_key(SocketEntry *e - error_f("failed to parse constraints"); +@@ -1601,25 +1665,18 @@ process_add_smartcard_key(SocketEntry *e) + "providers is disabled", provider); goto send; } - if (realpath(provider, canonical_provider) == NULL) { @@ -1046,13 +1090,11 @@ diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c - 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; - } - debug_f("add %.100s", canonical_provider); -+ if (lifetime && !death) death = monotime() + lifetime; @@ -1060,31 +1102,38 @@ diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c + debug_f("add %.100s", sane_uri); + count = pkcs11_add_provider(sane_uri, pin, &keys, &comments); for (i = 0; i < count; i++) { - k = keys[i]; - if (lookup_identity(k) == NULL) { - id = xcalloc(1, sizeof(Identity)); - id->key = k; - keys[i] = NULL; /* transferred */ -- id->provider = xstrdup(canonical_provider); -+ id->provider = xstrdup(sane_uri); - if (*comments[i] != '\0') { - id->comment = comments[i]; - comments[i] = NULL; /* transferred */ - } else { -- id->comment = xstrdup(canonical_provider); -+ id->comment = xstrdup(sane_uri); - } - id->death = death; - id->confirm = confirm; -@@ -910,6 +967,7 @@ process_add_smartcard_key(SocketEntry *e + if (comments[i] == NULL || comments[i][0] == '\0') { + free(comments[i]); +- comments[i] = xstrdup(canonical_provider); ++ comments[i] = xstrdup(sane_uri); + } + for (j = 0; j < ncerts; j++) { + if (!sshkey_is_cert(certs[j])) +@@ -1629,13 +1686,13 @@ process_add_smartcard_key(SocketEntry *e) + if (pkcs11_make_cert(keys[i], certs[j], &k) != 0) + continue; + add_p11_identity(k, xstrdup(comments[i]), +- canonical_provider, death, confirm, ++ sane_uri, death, confirm, + dest_constraints, ndest_constraints); + success = 1; + } + if (!cert_only && lookup_identity(keys[i]) == NULL) { + add_p11_identity(keys[i], comments[i], +- canonical_provider, death, confirm, ++ sane_uri, death, confirm, + dest_constraints, ndest_constraints); + keys[i] = NULL; /* transferred */ + comments[i] = NULL; /* transferred */ +@@ -1648,6 +1705,7 @@ process_add_smartcard_key(SocketEntry *e) send: free(pin); free(provider); + free(sane_uri); free(keys); free(comments); - free_dest_constraints(dest_constraints, ndest_constraints); -@@ -918,7 +976,7 @@ send: + free_dest_constraints(dest_constraints, ndest_constraints); +@@ -1660,7 +1718,7 @@ send: static void process_remove_smartcard_key(SocketEntry *e) { @@ -1093,7 +1142,7 @@ diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c int r, success = 0; Identity *id, *nxt; -@@ -930,30 +988,29 @@ process_remove_smartcard_key(SocketEntry +@@ -1672,30 +1730,29 @@ process_remove_smartcard_key(SocketEntry *e) } free(pin); @@ -1130,185 +1179,11 @@ diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c send_status(e, success); } #endif /* ENABLE_PKCS11 */ -diff -up openssh-8.7p1/ssh_config.5.pkcs11-uri openssh-8.7p1/ssh_config.5 ---- openssh-8.7p1/ssh_config.5.pkcs11-uri 2021-08-30 13:07:43.578699383 +0200 -+++ openssh-8.7p1/ssh_config.5 2021-08-30 13:07:43.664700104 +0200 -@@ -1111,6 +1111,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-8.7p1/ssh.c.pkcs11-uri openssh-8.7p1/ssh.c ---- openssh-8.7p1/ssh.c.pkcs11-uri 2021-08-30 13:07:43.578699383 +0200 -+++ openssh-8.7p1/ssh.c 2021-08-30 13:07:43.666700121 +0200 -@@ -826,6 +826,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 " -@@ -1681,6 +1689,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); -@@ -2197,6 +2206,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) -@@ -2211,11 +2259,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)); -@@ -2228,33 +2271,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-8.7p1/ssh-keygen.c.pkcs11-uri openssh-8.7p1/ssh-keygen.c ---- openssh-8.7p1/ssh-keygen.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/ssh-keygen.c 2021-08-30 13:07:43.666700121 +0200 -@@ -860,8 +860,11 @@ do_download(struct passwd *pw) +diff --git a/ssh-keygen.c b/ssh-keygen.c +index 89c3ed28..16cff947 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -906,8 +906,11 @@ do_download(struct passwd *pw) free(fp); } else { (void) sshkey_write(keys[i], stdout); /* XXX check */ @@ -1322,19 +1197,20 @@ diff -up openssh-8.7p1/ssh-keygen.c.pkcs11-uri openssh-8.7p1/ssh-keygen.c } free(comments[i]); sshkey_free(keys[i]); -diff -up openssh-8.7p1/ssh-pkcs11-client.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-client.c ---- openssh-8.7p1/ssh-pkcs11-client.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/ssh-pkcs11-client.c 2021-08-30 13:07:43.666700121 +0200 -@@ -323,6 +323,8 @@ pkcs11_add_provider(char *name, char *pi - u_int nkeys, i; +diff --git a/ssh-pkcs11-client.c b/ssh-pkcs11-client.c +index b8d1700f..64df695e 100644 +--- a/ssh-pkcs11-client.c ++++ b/ssh-pkcs11-client.c +@@ -635,6 +635,8 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, struct sshbuf *msg; + struct helper *helper; + debug_f("called, name = %s", name); + - if (fd < 0 && pkcs11_start_helper() < 0) - return (-1); - -@@ -342,6 +344,7 @@ pkcs11_add_provider(char *name, char *pi + if ((helper = helper_by_provider(name)) == NULL && + (helper = pkcs11_start_helper(name)) == NULL) + return -1; +@@ -655,6 +657,7 @@ pkcs11_add_provider(char *name, char *pin, struct sshkey ***keysp, *keysp = xcalloc(nkeys, sizeof(struct sshkey *)); if (labelsp) *labelsp = xcalloc(nkeys, sizeof(char *)); @@ -1342,1256 +1218,12 @@ diff -up openssh-8.7p1/ssh-pkcs11-client.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-c for (i = 0; i < nkeys; i++) { /* XXX clean up properly instead of fatal() */ if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 || -diff -up openssh-8.7p1/ssh-pkcs11.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11.c ---- openssh-8.7p1/ssh-pkcs11.c.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/ssh-pkcs11.c 2021-08-30 13:12:27.709084157 +0200 -@@ -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); - -- 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; - } - - static RSA_METHOD *rsa_method; -@@ -195,6 +286,55 @@ static EC_KEY_METHOD *ec_key_method; - static int ec_key_idx = 0; - #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ - -+/* -+ * This can't be in the ssh-pkcs11-uri, becase we can not depend on -+ * PKCS#11 structures in ssh-agent (using client-helper communication) -+ */ -+int -+pkcs11_uri_write(const struct sshkey *key, FILE *f) -+{ -+ char *p = NULL; -+ struct pkcs11_uri uri; -+ struct pkcs11_key *k11; -+ -+ /* sanity - is it a RSA key with associated app_data? */ -+ switch (key->type) { -+ case KEY_RSA: -+ k11 = RSA_get_ex_data(key->rsa, rsa_idx); -+ break; -+#ifdef HAVE_EC_KEY_METHOD_NEW -+ case KEY_ECDSA: -+ k11 = EC_KEY_get_ex_data(key->ecdsa, ec_key_idx); -+ break; -+#endif -+ default: -+ error("Unknown key type %d", key->type); -+ return -1; -+ } -+ if (k11 == NULL) { -+ error("Failed to get ex_data for key type %d", key->type); -+ return (-1); -+ } -+ -+ /* omit type -- we are looking for private-public or private-certificate pairs */ -+ uri.id = k11->keyid; -+ uri.id_len = k11->keyid_len; -+ uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label; -+ uri.object = k11->label; -+ uri.module_path = k11->provider->module->module_path; -+ uri.lib_manuf = k11->provider->module->info.manufacturerID; -+ uri.manuf = k11->provider->module->slotinfo[k11->slotidx].token.manufacturerID; -+ -+ 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 +348,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 +363,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); -@@ -262,12 +403,12 @@ pkcs11_login_slot(struct pkcs11_provider - else { - snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ", - 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 +438,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 +461,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 +499,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 +583,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 +628,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 +646,12 @@ pkcs11_rsa_wrap(struct pkcs11_provider * - memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); - } - -+ if (label_attrib->ulValueLen > 0 ) { -+ k11->label = xmalloc(label_attrib->ulValueLen+1); -+ memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen); -+ k11->label[label_attrib->ulValueLen] = 0; -+ } -+ - RSA_set_method(rsa, rsa_method); - RSA_set_ex_data(rsa, rsa_idx, k11); - return (0); -@@ -532,8 +682,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 +748,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; - -@@ -614,6 +764,12 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider - k11->keyid = xmalloc(k11->keyid_len); - memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len); - } -+ if (label_attrib->ulValueLen > 0 ) { -+ k11->label = xmalloc(label_attrib->ulValueLen+1); -+ memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen); -+ k11->label[label_attrib->ulValueLen] = 0; -+ } -+ - EC_KEY_set_method(ec, ec_key_method); - EC_KEY_set_ex_data(ec, ec_key_idx, k11); - -@@ -650,8 +806,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; - -@@ -661,9 +817,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) { -@@ -699,7 +855,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; -@@ -713,14 +870,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); -@@ -731,19 +889,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; -@@ -755,8 +913,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; -@@ -767,13 +925,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; -@@ -790,7 +948,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); -@@ -806,7 +964,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_ - ec = NULL; /* now owned by key */ - - fail: -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattr; i++) - free(key_attr[i].pValue); - if (ec) - EC_KEY_free(ec); -@@ -823,7 +981,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; -@@ -834,14 +993,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); -@@ -852,19 +1012,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; -@@ -876,8 +1036,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; -@@ -886,7 +1046,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); -@@ -901,7 +1061,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr - rsa = NULL; /* now owned by key */ - - fail: -- for (i = 0; i < 3; i++) -+ for (i = 0; i < nattr; i++) - free(key_attr[i].pValue); - RSA_free(rsa); - -@@ -912,7 +1072,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; -@@ -936,14 +1097,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; -@@ -955,18 +1117,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; -@@ -980,8 +1143,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; - } -@@ -1001,7 +1164,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); -@@ -1031,7 +1194,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); -@@ -1051,7 +1214,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); -@@ -1102,11 +1265,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; -@@ -1123,10 +1287,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++; -+ } -+ -+ 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; -@@ -1207,11 +1384,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; -@@ -1227,10 +1405,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++; -+ } - -- 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; -@@ -1499,16 +1690,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; -@@ -1517,164 +1702,298 @@ 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) -+ /* if no provider specified, fallback to p11-kit */ -+ if (uri->module_path == NULL) { -+#ifdef PKCS11_DEFAULT_PROVIDER -+ provider_module = strdup(PKCS11_DEFAULT_PROVIDER); -+#else -+ error_f("No module path provided"); - goto fail; -- *providerp = NULL; -+#endif -+ } else { -+ provider_module = strdup(uri->module_path); -+ } - -- if (keyp != NULL) -- *keyp = NULL; -- if (labelsp != NULL) -- *labelsp = NULL; -+ p = xcalloc(1, sizeof(*p)); -+ p->name = pkcs11_uri_get(uri); - -- if (pkcs11_provider_lookup(provider_id) != NULL) { -- debug_f("provider already registered: %s", provider_id); -- 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) { - error("dlsym(C_GetFunctionList) failed: %s", dlerror()); - goto fail; - } -- 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; -+ } -+ rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID)); -+ if (uri->lib_manuf != NULL && -+ strcmp(uri->lib_manuf, m->info.manufacturerID)) { -+ debug_f("Skipping provider %s not matching library_manufacturer", -+ m->info.manufacturerID); - goto fail; - } -- rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID)); -- rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription)); -+ rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription)); - debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d" - " libraryDescription <%s> libraryVersion %d.%d", -- provider_id, -- p->info.manufacturerID, -- p->info.cryptokiVersion.major, -- p->info.cryptokiVersion.minor, -- p->info.libraryDescription, -- p->info.libraryVersion.major, -- p->info.libraryVersion.minor); -- if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) { -+ 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)); - p->valid = 1; -- nkeys = 0; -- for (i = 0; i < p->nslots; i++) { -- token = &p->slotinfo[i].token; -- if ((rv = f->C_GetTokenInfo(p->slotlist[i], token)) -+ m->slotinfo = xcalloc(m->nslots, sizeof(struct pkcs11_slotinfo)); -+ m->valid = 1; -+ for (i = 0; i < m->nslots; i++) { -+ token = &m->slotinfo[i].token; -+ 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; - } - rmspace(token->label, sizeof(token->label)); - rmspace(token->manufacturerID, sizeof(token->manufacturerID)); - rmspace(token->model, sizeof(token->model)); - rmspace(token->serialNumber, sizeof(token->serialNumber)); -+ } -+ m->module_path = provider_module; -+ provider_module = NULL; -+ -+ /* insert unconditionally -- remove if there will be no keys later */ -+ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next); -+ p->refcount++; /* add to provider list */ -+ *providerp = p; -+ 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 && -+ strcmp(token->label, uri->token) != 0) { -+ debug2_f("ignoring token not matching label (%s) " -+ "specified by PKCS#11 URI in slot %lu", -+ token->label, (unsigned long)i); -+ continue; -+ } -+ if (uri->manuf != NULL && -+ strcmp(token->manufacturerID, uri->manuf) != 0) { -+ debug2_f("ignoring token not matching requrested " -+ "manufacturerID (%s) specified by PKCS#11 URI in " -+ "slot %lu", token->manufacturerID, (unsigned long)i); -+ continue; -+ } - debug("provider %s slot %lu: label <%s> manufacturerID <%s> " - "model <%s> serial <%s> flags 0x%lx", -- provider_id, (unsigned long)i, -+ 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 openend, 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 (%s) ", -+ 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) { -@@ -1683,7 +2002,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-8.7p1/ssh-pkcs11.h.pkcs11-uri openssh-8.7p1/ssh-pkcs11.h ---- openssh-8.7p1/ssh-pkcs11.h.pkcs11-uri 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/ssh-pkcs11.h 2021-08-30 13:07:43.666700121 +0200 -@@ -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-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri.c ---- openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri 2021-08-30 13:07:43.667700130 +0200 -+++ openssh-8.7p1/ssh-pkcs11-uri.c 2021-08-30 13:07:43.667700130 +0200 -@@ -0,0 +1,419 @@ +diff --git a/ssh-pkcs11-uri.c b/ssh-pkcs11-uri.c +new file mode 100644 +index 00000000..8bd97e9e +--- /dev/null ++++ b/ssh-pkcs11-uri.c +@@ -0,0 +1,437 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -2634,13 +1266,14 @@ diff -up openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri. +#define PKCS11_URI_OBJECT "object" +#define PKCS11_URI_LIB_MANUF "library-manufacturer" +#define PKCS11_URI_MANUF "manufacturer" ++#define PKCS11_URI_SERIAL "serial" +#define PKCS11_URI_MODULE_PATH "module-path" +#define PKCS11_URI_PIN_VALUE "pin-value" + +/* Keyword tokens. */ +typedef enum { -+ pId, pToken, pObject, pLibraryManufacturer, pManufacturer, pModulePath, -+ pPinValue, pBadOption ++ pId, pToken, pObject, pLibraryManufacturer, pManufacturer, pSerial, ++ pModulePath, pPinValue, pBadOption +} pkcs11uriOpCodes; + +/* Textual representation of the tokens. */ @@ -2653,6 +1286,7 @@ diff -up openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri. + { PKCS11_URI_OBJECT, pObject }, + { PKCS11_URI_LIB_MANUF, pLibraryManufacturer }, + { PKCS11_URI_MANUF, pManufacturer }, ++ { PKCS11_URI_SERIAL, pSerial }, + { PKCS11_URI_MODULE_PATH, pModulePath }, + { PKCS11_URI_PIN_VALUE, pPinValue }, + { NULL, pBadOption } @@ -2811,6 +1445,16 @@ diff -up openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri. + goto err; + } + ++ /* Write serial */ ++ if (uri->serial) { ++ struct sshbuf *serial = percent_encode(uri->serial, ++ strlen(uri->serial), PKCS11_URI_WHITELIST); ++ path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR, ++ PKCS11_URI_SERIAL, serial); ++ if (path == NULL) ++ goto err; ++ } ++ + /* Write module_path */ + if (uri->module_path) { + struct sshbuf *module = percent_encode(uri->module_path, @@ -2853,6 +1497,7 @@ diff -up openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri. + free(pkcs11->object); + free(pkcs11->lib_manuf); + free(pkcs11->manuf); ++ free(pkcs11->serial); + if (pkcs11->pin) + freezero(pkcs11->pin, strlen(pkcs11->pin)); + free(pkcs11); @@ -2948,6 +1593,11 @@ diff -up openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri. + charptr = &pkcs11->manuf; + goto parse_string; + ++ case pSerial: ++ /* CK_TOKEN_INFO -> serialNumber */ ++ charptr = &pkcs11->serial; ++ goto parse_string; ++ + case pLibraryManufacturer: + /* CK_INFO -> manufacturerID */ + charptr = &pkcs11->lib_manuf; @@ -3011,10 +1661,12 @@ diff -up openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri. +} + +#endif /* ENABLE_PKCS11 */ -diff -up openssh-8.7p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri.h ---- openssh-8.7p1/ssh-pkcs11-uri.h.pkcs11-uri 2021-08-30 13:07:43.667700130 +0200 -+++ openssh-8.7p1/ssh-pkcs11-uri.h 2021-08-30 13:07:43.667700130 +0200 -@@ -0,0 +1,42 @@ +diff --git a/ssh-pkcs11-uri.h b/ssh-pkcs11-uri.h +new file mode 100644 +index 00000000..29e9f732 +--- /dev/null ++++ b/ssh-pkcs11-uri.h +@@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017 Red Hat + * @@ -3046,6 +1698,7 @@ diff -up openssh-8.7p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri. + char *object; + char *lib_manuf; + char *manuf; ++ char *serial; + /* query */ + char *module_path; + char *pin; /* Only parsed, but not printed */ @@ -3057,3 +1710,1473 @@ diff -up openssh-8.7p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri. +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 31b9360f..b96f5b89 100644 +--- a/ssh-pkcs11.c ++++ b/ssh-pkcs11.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #define CRYPTOKI_COMPAT + #include "pkcs11.h" +@@ -55,8 +56,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 +66,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 +83,7 @@ struct pkcs11_key { + CK_ULONG slotidx; + char *keyid; + int keyid_len; ++ char *label; + }; + + int pkcs11_interactive = 0; +@@ -106,26 +115,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 +181,9 @@ 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); + } + } +@@ -159,6 +201,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 +229,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; + } + + static RSA_METHOD *rsa_method; +@@ -195,6 +287,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 +354,7 @@ pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx, + if (k11->provider) + pkcs11_provider_unref(k11->provider); + free(k11->keyid); ++ free(k11->label); + free(k11); + } + +@@ -222,8 +369,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); +@@ -260,14 +407,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)); +@@ -297,13 +444,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); + } + + +@@ -319,13 +467,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; +@@ -356,13 +505,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) { +@@ -439,8 +589,8 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, + 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 +634,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 +652,12 @@ pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, + 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) +@@ -534,8 +690,8 @@ ecdsa_do_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, + 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); +@@ -600,7 +756,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; + +@@ -617,6 +773,12 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, + 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) +@@ -626,7 +788,8 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx, + } + #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) + { +@@ -658,8 +821,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; + +@@ -669,9 +832,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) { +@@ -707,7 +870,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; +@@ -721,14 +885,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); +@@ -739,19 +904,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; +@@ -763,8 +928,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; +@@ -775,13 +940,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; +@@ -798,7 +963,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + 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); +@@ -817,7 +982,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + 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); +@@ -834,7 +999,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; +@@ -845,14 +1011,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); +@@ -863,19 +1030,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; +@@ -887,8 +1054,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; +@@ -897,7 +1064,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + 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); +@@ -915,7 +1082,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + 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); + +@@ -926,7 +1093,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; +@@ -950,14 +1118,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; +@@ -969,18 +1138,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; +@@ -994,8 +1164,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; + } +@@ -1015,7 +1185,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + 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); +@@ -1048,7 +1218,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx, + 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); +@@ -1071,7 +1241,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); +@@ -1122,11 +1292,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; +@@ -1143,10 +1314,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++; ++ } ++ ++ 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; +@@ -1227,11 +1411,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; +@@ -1247,10 +1432,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; +@@ -1532,16 +1730,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; +@@ -1550,162 +1742,309 @@ 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; ++ } ++ 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; + } +- 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.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) { +@@ -1714,7 +2053,37 @@ 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; ++} ++ ++/* ++ * 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 --git a/ssh-pkcs11.h b/ssh-pkcs11.h +index 52602231..9ce20c1f 100644 +--- a/ssh-pkcs11.h ++++ b/ssh-pkcs11.h +@@ -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 --git a/ssh.c b/ssh.c +index c23d3b9e..98b103c9 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -890,6 +890,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 " +@@ -1847,6 +1855,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); +@@ -2370,6 +2379,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) +@@ -2384,11 +2432,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)); +@@ -2401,33 +2444,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 3a8e246c..8d5d0722 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -1263,6 +1263,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.49.0 + diff --git a/openssh-7.8p1-scp-ipv6.patch b/0029-openssh-7.8p1-scp-ipv6.patch similarity index 51% rename from openssh-7.8p1-scp-ipv6.patch rename to 0029-openssh-7.8p1-scp-ipv6.patch index 8ae0948..dbd69aa 100644 --- a/openssh-7.8p1-scp-ipv6.patch +++ b/0029-openssh-7.8p1-scp-ipv6.patch @@ -1,8 +1,17 @@ +From 507e6f245557ae7261806f7ecbd40697cb0dd389 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 29/50] openssh-7.8p1-scp-ipv6 + +--- + scp.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + diff --git a/scp.c b/scp.c -index 60682c68..9344806e 100644 +index 9554b188..7f9795a5 100644 --- a/scp.c +++ b/scp.c -@@ -714,7 +714,9 @@ toremote(int argc, char **argv) +@@ -1183,7 +1183,9 @@ toremote(int argc, char **argv, enum scp_mode_e mode, char *sftp_direct) addargs(&alist, "%s", host); addargs(&alist, "%s", cmd); addargs(&alist, "%s", src); @@ -13,4 +22,6 @@ index 60682c68..9344806e 100644 tuser ? tuser : "", tuser ? "@" : "", thost, targ); if (do_local_cmd(&alist) != 0) +-- +2.49.0 diff --git a/openssh-8.0p1-crypto-policies.patch b/0030-openssh-8.0p1-crypto-policies.patch similarity index 87% rename from openssh-8.0p1-crypto-policies.patch rename to 0030-openssh-8.0p1-crypto-policies.patch index 86c08db..498e3f5 100644 --- a/openssh-8.0p1-crypto-policies.patch +++ b/0030-openssh-8.0p1-crypto-policies.patch @@ -1,7 +1,18 @@ -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 @@ +From b436140fe3abd9f97f01f9af9f5da5cf6c5d7725 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 30/50] 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 8d5d0722..a43b2a27 100644 +--- a/ssh_config.5 ++++ b/ssh_config.5 +@@ -438,17 +438,13 @@ A single argument of causes no CNAMEs to be considered for canonicalization. This is the default behaviour. .It Cm CASignatureAlgorithms @@ -24,7 +35,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x If the specified list begins with a .Sq + character, then the specified algorithms will be appended to the default set -@@ -450,20 +446,25 @@ +@@ -587,20 +583,25 @@ If the option is set to (the default), the check will not be executed. .It Cm Ciphers @@ -54,21 +65,21 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Pp The supported ciphers are: .Bd -literal -offset indent -@@ -479,13 +480,6 @@ +@@ -616,13 +617,6 @@ aes256-gcm@openssh.com chacha20-poly1305@openssh.com .Ed .Pp -The default is: -.Bd -literal -offset indent -chacha20-poly1305@openssh.com, --aes128-ctr,aes192-ctr,aes256-ctr, --aes128-gcm@openssh.com,aes256-gcm@openssh.com +-aes128-gcm@openssh.com,aes256-gcm@openssh.com, +-aes128-ctr,aes192-ctr,aes256-ctr -.Ed -.Pp The list of available ciphers may also be obtained using .Qq ssh -Q cipher . .It Cm ClearAllForwardings -@@ -885,6 +879,11 @@ +@@ -1022,6 +1016,11 @@ command line will be passed untouched to the GSSAPI library. The default is .Dq no . .It Cm GSSAPIKexAlgorithms @@ -80,7 +91,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x The list of key exchange algorithms that are offered for GSSAPI key exchange. Possible values are .Bd -literal -offset 3n -@@ -897,10 +896,8 @@ +@@ -1034,10 +1033,8 @@ gss-nistp256-sha256-, gss-curve25519-sha256- .Ed .Pp @@ -92,7 +103,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .It Cm HashKnownHosts Indicates that .Xr ssh 1 -@@ -919,36 +916,25 @@ +@@ -1056,36 +1053,25 @@ will not be converted automatically, but may be manually hashed using .Xr ssh-keygen 1 . .It Cm HostbasedAcceptedAlgorithms @@ -137,7 +148,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Pp The .Fl Q -@@ -1001,6 +987,17 @@ +@@ -1138,6 +1124,17 @@ to prefer their algorithms. .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . @@ -155,7 +166,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .It Cm HostKeyAlias Specifies an alias that should be used instead of the real host name when looking up or saving the host key -@@ -1232,30 +1229,25 @@ +@@ -1376,6 +1373,11 @@ it may be zero or more of: and .Cm pam . .It Cm KexAlgorithms @@ -164,8 +175,11 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x +Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page +.Xr update-crypto-policies 8 . +.Pp - Specifies the available KEX (Key Exchange) algorithms. - Multiple algorithms must be comma-separated. + Specifies the permitted KEX (Key Exchange) algorithms that will be used and + their preference order. + The selected algorithm will be the first algorithm in this list that +@@ -1384,29 +1386,17 @@ Multiple algorithms must be comma-separated. + .Pp If the specified list begins with a .Sq + -character, then the specified algorithms will be appended to the default set @@ -181,9 +195,11 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Sq ^ character, then the specified algorithms will be placed at the head of the -default set. +-.Pp -The default is: -.Bd -literal -offset indent --sntrup761x25519-sha512@openssh.com, +-mlkem768x25519-sha256, +-sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com, -curve25519-sha256,curve25519-sha256@libssh.org, -ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521, -diffie-hellman-group-exchange-sha256, @@ -191,11 +207,12 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x -diffie-hellman-group18-sha512, -diffie-hellman-group14-sha256 -.Ed -+built-in openssh default set. .Pp - The list of available key exchange algorithms may also be obtained using ++built-in openssh default set. + The list of supported key exchange algorithms may also be obtained using .Qq ssh -Q kex . -@@ -1365,37 +1357,33 @@ + .It Cm KnownHostsCommand +@@ -1522,37 +1512,33 @@ function, and all code in the file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs @@ -242,7 +259,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . .It Cm NoHostAuthenticationForLocalhost -@@ -1567,39 +1555,31 @@ +@@ -1741,39 +1727,31 @@ instead of continuing to execute and pass data. The default is .Cm no . .It Cm PubkeyAcceptedAlgorithms @@ -294,7 +311,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .It Cm PubkeyAuthentication Specifies whether to try public key authentication. The argument to this keyword must be -@@ -2265,7 +2245,9 @@ +@@ -2497,7 +2475,9 @@ for those users who do not have a configuration file. This file must be world-readable. .El .Sh SEE ALSO @@ -305,10 +322,11 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Sh AUTHORS .An -nosplit OpenSSH is a derivative of the original and free -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/sshd_config.5 openssh-9.3p1-patched/sshd_config.5 ---- openssh-9.3p1/sshd_config.5 2023-06-07 10:26:48.277590077 +0200 -+++ openssh-9.3p1-patched/sshd_config.5 2023-06-07 10:26:00.592051845 +0200 -@@ -379,17 +379,13 @@ +diff --git a/sshd_config.5 b/sshd_config.5 +index 26fcdc84..583a01cd 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -379,17 +379,13 @@ If the argument is then no banner is displayed. By default, no banner is displayed. .It Cm CASignatureAlgorithms @@ -331,7 +349,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x If the specified list begins with a .Sq + character, then the specified algorithms will be appended to the default set -@@ -525,20 +521,25 @@ +@@ -533,20 +529,25 @@ The default is indicating not to .Xr chroot 2 . .It Cm Ciphers @@ -361,21 +379,21 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Pp The supported ciphers are: .Pp -@@ -565,13 +566,6 @@ +@@ -573,13 +574,6 @@ aes256-gcm@openssh.com chacha20-poly1305@openssh.com .El .Pp -The default is: -.Bd -literal -offset indent -chacha20-poly1305@openssh.com, --aes128-ctr,aes192-ctr,aes256-ctr, --aes128-gcm@openssh.com,aes256-gcm@openssh.com +-aes128-gcm@openssh.com,aes256-gcm@openssh.com, +-aes128-ctr,aes192-ctr,aes256-ctr -.Ed -.Pp The list of available ciphers may also be obtained using .Qq ssh -Q cipher . .It Cm ClientAliveCountMax -@@ -766,53 +760,43 @@ +@@ -774,53 +768,43 @@ For this to work .Cm GSSAPIKeyExchange needs to be enabled in the server and also used by the client. .It Cm GSSAPIKexAlgorithms @@ -448,7 +466,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q HostbasedAcceptedAlgorithms . -@@ -879,25 +863,14 @@ +@@ -887,25 +871,14 @@ is specified, the location of the socket will be read from the .Ev SSH_AUTH_SOCK environment variable. .It Cm HostKeyAlgorithms @@ -479,7 +497,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . .It Cm IgnoreRhosts -@@ -1044,20 +1017,25 @@ +@@ -1052,6 +1025,11 @@ Specifies whether to look at .k5login file for user's aliases. The default is .Cm yes . .It Cm KexAlgorithms @@ -488,9 +506,12 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x +Information about defaults, how to modify the defaults and how to customize existing policies with sub-policies are present in manual page +.Xr update-crypto-policies 8 . +.Pp - Specifies the available KEX (Key Exchange) algorithms. - Multiple algorithms must be comma-separated. - Alternately if the specified list begins with a + Specifies the permitted KEX (Key Exchange) algorithms that the server will + offer to clients. + The ordering of this list is not important, as the client specifies the +@@ -1060,16 +1038,16 @@ Multiple algorithms must be comma-separated. + .Pp + If the specified list begins with a .Sq + -character, then the specified algorithms will be appended to the default set -instead of replacing them. @@ -506,27 +527,25 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x character, then the specified algorithms will be placed at the head of the -default set. +built-in openssh default set. + .Pp The supported algorithms are: .Pp - .Bl -item -compact -offset indent -@@ -1089,16 +1067,6 @@ +@@ -1106,14 +1084,6 @@ sntrup761x25519-sha512 sntrup761x25519-sha512@openssh.com .El .Pp -The default is: -.Bd -literal -offset indent --sntrup761x25519-sha512@openssh.com, +-mlkem768x25519-sha256, +-sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com, -curve25519-sha256,curve25519-sha256@libssh.org, --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 +-ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521 -.Ed -.Pp - The list of available key exchange algorithms may also be obtained using + The list of supported key exchange algorithms may also be obtained using .Qq ssh -Q KexAlgorithms . .It Cm ListenAddress -@@ -1184,21 +1152,26 @@ +@@ -1200,21 +1170,26 @@ function, and all code in the file. This option is intended for debugging and no overrides are enabled by default. .It Cm MACs @@ -557,7 +576,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Pp The algorithms that contain .Qq -etm -@@ -1241,15 +1214,6 @@ +@@ -1257,15 +1232,6 @@ umac-64-etm@openssh.com umac-128-etm@openssh.com .El .Pp @@ -573,7 +592,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . .It Cm Match -@@ -1633,36 +1597,25 @@ +@@ -1753,36 +1719,25 @@ or equivalent.) The default is .Cm yes . .It Cm PubkeyAcceptedAlgorithms @@ -619,7 +638,7 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Pp The list of available signature algorithms may also be obtained using .Qq ssh -Q PubkeyAcceptedAlgorithms . -@@ -2131,7 +2084,9 @@ +@@ -2289,7 +2244,9 @@ This file should be writable by root only, but it is recommended .El .Sh SEE ALSO .Xr sftp-server 8 , @@ -630,3 +649,6 @@ diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x .Sh AUTHORS .An -nosplit OpenSSH is a derivative of the original and free +-- +2.49.0 + diff --git a/0031-openssh-8.0p1-openssl-kdf.patch b/0031-openssh-8.0p1-openssl-kdf.patch new file mode 100644 index 0000000..529940f --- /dev/null +++ b/0031-openssh-8.0p1-openssl-kdf.patch @@ -0,0 +1,157 @@ +From 430bd33963725beb8ec01a1e581529ae6bf6bec0 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 31/50] openssh-8.0p1-openssl-kdf + +--- + configure.ac | 1 + + kex.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 108 insertions(+) + +diff --git a/configure.ac b/configure.ac +index d9bd2f51..d92a8580 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3137,6 +3137,7 @@ if test "x$openssl" = "xyes" ; then + HMAC_CTX_init \ + RSA_generate_key_ex \ + RSA_get_default_method \ ++ EVP_KDF_CTX_new \ + ]) + + # OpenSSL_add_all_algorithms may be a macro. +diff --git a/kex.c b/kex.c +index 19a56e8e..8b200ff4 100644 +--- a/kex.c ++++ b/kex.c +@@ -40,6 +40,11 @@ + #ifdef WITH_OPENSSL + #include + #include ++# ifdef HAVE_EVP_KDF_CTX_NEW ++# include ++# include ++# include ++# endif + #endif + + #include "ssh.h" +@@ -1078,6 +1083,107 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) + return r; + } + ++#ifdef HAVE_EVP_KDF_CTX_NEW ++static const char * ++digest_to_md(int digest_type) ++{ ++ switch (digest_type) { ++ case SSH_DIGEST_SHA1: ++ return SN_sha1; ++ case SSH_DIGEST_SHA256: ++ return SN_sha256; ++ case SSH_DIGEST_SHA384: ++ return SN_sha384; ++ case SSH_DIGEST_SHA512: ++ return SN_sha512; ++ } ++ return NULL; ++} ++ ++static int ++derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, ++ const struct sshbuf *shared_secret, u_char **keyp) ++{ ++ struct kex *kex = ssh->kex; ++ u_char *key = NULL; ++ int r, key_len; ++ ++ EVP_KDF *kdf = EVP_KDF_fetch(NULL, "SSHKDF", NULL); ++ EVP_KDF_CTX *ctx = EVP_KDF_CTX_new(kdf); ++ OSSL_PARAM_BLD *param_bld = OSSL_PARAM_BLD_new(); ++ OSSL_PARAM *params = NULL; ++ const char *md = digest_to_md(kex->hash_alg); ++ char keytype = (char)id; ++ ++ EVP_KDF_free(kdf); ++ if (!ctx) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (md == NULL) { ++ r = SSH_ERR_INVALID_ARGUMENT; ++ goto out; ++ } ++ ++ if (param_bld == NULL) { ++ EVP_KDF_CTX_free(ctx); ++ return -1; ++ } ++ if ((key_len = ssh_digest_bytes(kex->hash_alg)) == 0) { ++ r = SSH_ERR_INVALID_ARGUMENT; ++ goto out; ++ } ++ ++ key_len = ROUNDUP(need, key_len); ++ if ((key = calloc(1, key_len)) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ r = OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_DIGEST, ++ md, strlen(md)) && /* SN */ ++ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_KEY, ++ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)) && ++ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_XCGHASH, ++ hash, hashlen) && ++ OSSL_PARAM_BLD_push_octet_string(param_bld, OSSL_KDF_PARAM_SSHKDF_SESSION_ID, ++ sshbuf_ptr(kex->session_id), sshbuf_len(kex->session_id)) && ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, OSSL_KDF_PARAM_SSHKDF_TYPE, ++ &keytype, 1); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ params = OSSL_PARAM_BLD_to_param(param_bld); ++ if (params == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ r = EVP_KDF_derive(ctx, key, key_len, params); ++ if (r != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++#ifdef DEBUG_KEX ++ fprintf(stderr, "key '%c'== ", id); ++ dump_digest("key", key, key_len); ++#endif ++ *keyp = key; ++ key = NULL; ++ r = 0; ++ ++out: ++ OSSL_PARAM_BLD_free(param_bld); ++ OSSL_PARAM_free(params); ++ free (key); ++ EVP_KDF_CTX_free(ctx); ++ if (r < 0) { ++ return r; ++ } ++ return 0; ++} ++#else + static int + derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, + const struct sshbuf *shared_secret, u_char **keyp) +@@ -1141,6 +1247,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, + ssh_digest_free(hashctx); + return r; + } ++#endif /* HAVE_OPENSSL_EVP_KDF_CTX_NEW */ + + #define NKEYS 6 + int +-- +2.49.0 + diff --git a/openssh-8.2p1-visibility.patch b/0032-openssh-8.2p1-visibility.patch similarity index 62% rename from openssh-8.2p1-visibility.patch rename to 0032-openssh-8.2p1-visibility.patch index 89c35ef..c67373c 100644 --- a/openssh-8.2p1-visibility.patch +++ b/0032-openssh-8.2p1-visibility.patch @@ -1,8 +1,17 @@ +From 6aa231d9acfeca870ee87e3bf9c4a1239518706d Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 32/50] 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 dca158de..afdcb1d2 100644 +index 347b2122..344f8a8a 100644 --- a/regress/misc/sk-dummy/sk-dummy.c +++ b/regress/misc/sk-dummy/sk-dummy.c -@@ -71,7 +71,7 @@ skdebug(const char *func, const char *fmt, ...) +@@ -81,7 +81,7 @@ skdebug(const char *func, const char *fmt, ...) #endif } @@ -11,7 +20,7 @@ index dca158de..afdcb1d2 100644 sk_api_version(void) { return SSH_SK_VERSION_MAJOR; -@@ -220,7 +220,7 @@ check_options(struct sk_option **options) +@@ -230,7 +230,7 @@ check_options(struct sk_option **options) return 0; } @@ -20,7 +29,7 @@ index dca158de..afdcb1d2 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) -@@ -467,7 +467,7 @@ sig_ed25519(const uint8_t *message, size_t message_len, +@@ -478,7 +478,7 @@ sig_ed25519(const uint8_t *message, size_t message_len, return ret; } @@ -29,7 +38,7 @@ index dca158de..afdcb1d2 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, -@@ -518,7 +518,7 @@ sk_sign(uint32_t alg, const uint8_t *message, size_t message_len, +@@ -535,7 +535,7 @@ sk_sign(uint32_t alg, const uint8_t *data, size_t datalen, return ret; } @@ -38,3 +47,6 @@ index dca158de..afdcb1d2 100644 sk_load_resident_keys(const char *pin, struct sk_option **options, struct sk_resident_key ***rks, size_t *nrks) { +-- +2.49.0 + diff --git a/openssh-8.2p1-x11-without-ipv6.patch b/0033-openssh-8.2p1-x11-without-ipv6.patch similarity index 55% rename from openssh-8.2p1-x11-without-ipv6.patch rename to 0033-openssh-8.2p1-x11-without-ipv6.patch index 8b83bc3..32a9056 100644 --- a/openssh-8.2p1-x11-without-ipv6.patch +++ b/0033-openssh-8.2p1-x11-without-ipv6.patch @@ -1,12 +1,17 @@ +From cfe5a99d335eb57b8c08b4eb6b4535dd042d96e3 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:28 +0200 +Subject: [PATCH 33/50] openssh-8.2p1-x11-without-ipv6 + +--- + channels.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + diff --git a/channels.c b/channels.c +index 7438c1a5..95836d50 100644 --- a/channels.c +++ b/channels.c -@@ -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) { +@@ -5055,6 +5055,16 @@ x11_create_display_inet(struct ssh *ssh, int x11_display_offset, debug2_f("bind port %d: %.100s", port, strerror(errno)); close(sock); @@ -23,8 +28,6 @@ diff --git a/channels.c b/channels.c for (n = 0; n < num_socks; n++) close(socks[n]); num_socks = 0; - break; - } - socks[num_socks++] = sock; - if (num_socks == NUM_SOCKS) - break; +-- +2.49.0 + diff --git a/openssh-8.0p1-preserve-pam-errors.patch b/0034-openssh-8.0p1-preserve-pam-errors.patch similarity index 67% rename from openssh-8.0p1-preserve-pam-errors.patch rename to 0034-openssh-8.0p1-preserve-pam-errors.patch index dbdbe93..15e59c2 100644 --- a/openssh-8.0p1-preserve-pam-errors.patch +++ b/0034-openssh-8.0p1-preserve-pam-errors.patch @@ -1,7 +1,17 @@ -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) +From 8de0391e3b3eb75e23ee9f173f04a9c78f2b96c9 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 34/50] 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 b4100ea1..a042c3c8 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -523,7 +523,11 @@ sshpam_thread(void *ctxtp) goto auth_fail; if (!do_pam_account()) { @@ -14,7 +24,7 @@ diff -up openssh-8.0p1/auth-pam.c.preserve-pam-errors openssh-8.0p1/auth-pam.c goto auth_fail; } if (sshpam_authctxt->force_pwchange) { -@@ -568,8 +572,10 @@ sshpam_thread(void *ctxtp) +@@ -580,8 +584,10 @@ sshpam_thread(void *ctxtp) pam_strerror(sshpam_handle, sshpam_err))) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); /* XXX - can't do much about an error here */ @@ -27,18 +37,20 @@ diff -up openssh-8.0p1/auth-pam.c.preserve-pam-errors openssh-8.0p1/auth-pam.c else if (sshpam_maxtries_reached) ssh_msg_send(ctxt->pam_csock, PAM_MAXTRIES, buffer); else -@@ -856,10 +862,12 @@ sshpam_query(void *ctx, char **name, cha - plen++; +@@ -890,9 +896,11 @@ sshpam_query(void *ctx, char **name, char **info, free(msg); break; -+ case PAM_USER_UNKNOWN: -+ case PAM_PERM_DENIED: case PAM_ACCT_EXPIRED: + sshpam_account_status = 0; + /* FALLTHROUGH */ case PAM_MAXTRIES: - if (type == PAM_ACCT_EXPIRED) - sshpam_account_status = 0; ++ case PAM_USER_UNKNOWN: ++ case PAM_PERM_DENIED: if (type == PAM_MAXTRIES) sshpam_set_maxtries_reached(1); /* FALLTHROUGH */ +-- +2.49.0 + diff --git a/openssh-8.7p1-scp-kill-switch.patch b/0035-openssh-8.7p1-scp-kill-switch.patch similarity index 57% rename from openssh-8.7p1-scp-kill-switch.patch rename to 0035-openssh-8.7p1-scp-kill-switch.patch index 161ab2d..58a5036 100644 --- a/openssh-8.7p1-scp-kill-switch.patch +++ b/0035-openssh-8.7p1-scp-kill-switch.patch @@ -1,6 +1,18 @@ -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 +From a68f3741fdc01bf6823a69d2442caba7de9835f9 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 35/50] 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 1158bec9..43f0c570 100644 +--- a/pathnames.h ++++ b/pathnames.h @@ -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" @@ -9,10 +21,11 @@ diff -up openssh-8.7p1/pathnames.h.kill-scp openssh-8.7p1/pathnames.h #ifndef _PATH_SSH_PROGRAM #define _PATH_SSH_PROGRAM "/usr/bin/ssh" -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 +diff --git a/scp.1 b/scp.1 +index aa2e2d8b..373d7237 100644 +--- a/scp.1 ++++ b/scp.1 +@@ -331,6 +331,13 @@ during download or upload. By default a 32KB buffer is used. .El .El @@ -26,10 +39,11 @@ diff -up openssh-8.7p1/scp.1.kill-scp openssh-8.7p1/scp.1 .Sh EXIT STATUS .Ex -std scp .Sh SEE ALSO -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) +diff --git a/scp.c b/scp.c +index 7f9795a5..7ed1a54c 100644 +--- a/scp.c ++++ b/scp.c +@@ -649,6 +649,14 @@ main(int argc, char **argv) if (iamremote) mode = MODE_SCP; @@ -44,3 +58,6 @@ diff -up openssh-8.7p1/scp.c.kill-scp openssh-8.7p1/scp.c if ((pwd = getpwuid(userid = getuid())) == NULL) fatal("unknown user %u", (u_int) userid); +-- +2.49.0 + diff --git a/0036-openssh-8.7p1-recursive-scp.patch b/0036-openssh-8.7p1-recursive-scp.patch new file mode 100644 index 0000000..929b408 --- /dev/null +++ b/0036-openssh-8.7p1-recursive-scp.patch @@ -0,0 +1,200 @@ +From 99e1e3af524376788e591ca73387f1ca37e6f5ef Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 36/50] 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 7ed1a54c..0c87dd0e 100644 +--- a/scp.c ++++ b/scp.c +@@ -1388,7 +1388,7 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn) + + if (src_is_dir && iamrecursive) { + if (sftp_upload_dir(conn, src, abs_dst, pflag, +- SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) { ++ SFTP_PROGRESS_ONLY, 0, 0, 1, 1, 1) != 0) { + error("failed to upload directory %s to %s", src, targ); + errs = 1; + } +diff --git a/sftp-client.c b/sftp-client.c +index 9f8ab4af..873dec04 100644 +--- a/sftp-client.c ++++ b/sftp-client.c +@@ -1003,7 +1003,7 @@ sftp_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, + + /* Implements both the realpath and expand-path operations */ + static char * +-sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand) ++sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand, int create_dir) + { + struct sshbuf *msg; + u_int expected_id, count, id; +@@ -1049,11 +1049,43 @@ sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand) + if ((r = sshbuf_get_u32(msg, &status)) != 0 || + (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0) + fatal_fr(r, "parse status"); +- error("%s %s: %s", expand ? "expand" : "realpath", +- path, *errmsg == '\0' ? fx2txt(status) : errmsg); +- free(errmsg); +- sshbuf_free(msg); +- return NULL; ++ if ((status == SSH2_FX_NO_SUCH_FILE) && create_dir) { ++ memset(&a, '\0', sizeof(a)); ++ if ((r = sftp_mkdir(conn, path, &a, 0)) != 0) { ++ sshbuf_free(msg); ++ return NULL; ++ } ++ debug2("Sending SSH2_FXP_REALPATH \"%s\" - create dir", path); ++ send_string_request(conn, id, SSH2_FXP_REALPATH, ++ path, strlen(path)); ++ ++ get_msg(conn, msg); ++ if ((r = sshbuf_get_u8(msg, &type)) != 0 || ++ (r = sshbuf_get_u32(msg, &id)) != 0) ++ fatal_fr(r, "parse"); ++ ++ if (id != expected_id) ++ fatal("ID mismatch (%u != %u)", id, expected_id); ++ ++ if (type == SSH2_FXP_STATUS) { ++ free(errmsg); ++ ++ if ((r = sshbuf_get_u32(msg, &status)) != 0 || ++ (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0) ++ fatal_fr(r, "parse status"); ++ error("%s %s: %s", expand ? "expand" : "realpath", ++ path, *errmsg == '\0' ? fx2txt(status) : errmsg); ++ free(errmsg); ++ sshbuf_free(msg); ++ return NULL; ++ } ++ } else { ++ error("%s %s: %s", expand ? "expand" : "realpath", ++ path, *errmsg == '\0' ? fx2txt(status) : errmsg); ++ free(errmsg); ++ sshbuf_free(msg); ++ return NULL; ++ } + } else if (type != SSH2_FXP_NAME) + fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", + SSH2_FXP_NAME, type); +@@ -1078,9 +1110,9 @@ sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand) + } + + char * +-sftp_realpath(struct sftp_conn *conn, const char *path) ++sftp_realpath(struct sftp_conn *conn, const char *path, int create_dir) + { +- return sftp_realpath_expand(conn, path, 0); ++ return sftp_realpath_expand(conn, path, 0, create_dir); + } + + int +@@ -1094,9 +1126,9 @@ sftp_expand_path(struct sftp_conn *conn, const char *path) + { + if (!sftp_can_expand_path(conn)) { + debug3_f("no server support, fallback to realpath"); +- return sftp_realpath_expand(conn, path, 0); ++ return sftp_realpath_expand(conn, path, 0, 0); + } +- return sftp_realpath_expand(conn, path, 1); ++ return sftp_realpath_expand(conn, path, 1, 0); + } + + int +@@ -2016,7 +2048,7 @@ sftp_download_dir(struct sftp_conn *conn, const char *src, const char *dst, + 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, + 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, +- int follow_link_flag, int inplace_flag) ++ int follow_link_flag, int inplace_flag, int create_dir) + { + char *dst_canon; + int ret; + +- if ((dst_canon = 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, + 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 74cdae7d..00ed6630 100644 +--- a/sftp-client.h ++++ b/sftp-client.h +@@ -111,7 +111,7 @@ int sftp_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *); + 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 *); +@@ -163,7 +163,7 @@ int sftp_upload(struct sftp_conn *, const char *, const char *, + * 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 bdedd141..322e6d1f 100644 +--- a/sftp.c ++++ b/sftp.c +@@ -809,7 +809,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, + (rflag || global_rflag)) { + if (sftp_upload_dir(conn, g.gl_pathv[i], abs_dst, + pflag || global_pflag, 1, resume, +- fflag || global_fflag, 0, 0) == -1) ++ fflag || global_fflag, 0, 0, 0) == -1) + err = -1; + } else { + if (sftp_upload(conn, g.gl_pathv[i], abs_dst, +@@ -1644,7 +1644,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd, + if (path1 == NULL || *path1 == '\0') + path1 = xstrdup(startdir); + path1 = sftp_make_absolute(path1, *pwd); +- if ((tmp = sftp_realpath(conn, path1)) == NULL) { ++ if ((tmp = sftp_realpath(conn, path1, 0)) == NULL) { + err = 1; + break; + } +@@ -2249,7 +2249,7 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2) + } + #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.49.0 + diff --git a/0037-openssh-8.7p1-minrsabits.patch b/0037-openssh-8.7p1-minrsabits.patch new file mode 100644 index 0000000..59e530b --- /dev/null +++ b/0037-openssh-8.7p1-minrsabits.patch @@ -0,0 +1,37 @@ +From 286bc4a302b5130f732c857095ae665f7bea01dd Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 37/50] openssh-8.7p1-minrsabits + +--- + readconf.c | 1 + + servconf.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/readconf.c b/readconf.c +index 6c04ed43..f340bf50 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -343,6 +343,7 @@ static struct { + { "securitykeyprovider", oSecurityKeyProvider }, + { "knownhostscommand", oKnownHostsCommand }, + { "requiredrsasize", oRequiredRSASize }, ++ { "rsaminsize", oRequiredRSASize }, /* alias */ + { "enableescapecommandline", oEnableEscapeCommandline }, + { "obscurekeystroketiming", oObscureKeystrokeTiming }, + { "channeltimeout", oChannelTimeout }, +diff --git a/servconf.c b/servconf.c +index 15c99b30..84891544 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -788,6 +788,7 @@ static struct { + { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, + { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, + { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, ++ { "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */ + { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, + { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, + { "sshdsessionpath", sSshdSessionPath, SSHCFG_GLOBAL }, +-- +2.49.0 + diff --git a/0038-openssh-8.7p1-ibmca.patch b/0038-openssh-8.7p1-ibmca.patch new file mode 100644 index 0000000..74dd5b5 --- /dev/null +++ b/0038-openssh-8.7p1-ibmca.patch @@ -0,0 +1,25 @@ +From 26af04432f6404eb03780265a5cce948ecfec8dc Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 38/50] 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 f6112458..417c2048 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.49.0 + diff --git a/openssh-7.6p1-audit.patch b/0039-openssh-7.6p1-audit.patch similarity index 78% rename from openssh-7.6p1-audit.patch rename to 0039-openssh-7.6p1-audit.patch index 748c4b6..e4f89c7 100644 --- a/openssh-7.6p1-audit.patch +++ b/0039-openssh-7.6p1-audit.patch @@ -1,7 +1,57 @@ -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, +From b0505837bfa2dcdf07800634fa80c5cdb78799dc Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 39/50] 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 | 194 +++++++++++++++++++++++++++-- + monitor.h | 8 +- + monitor_wrap.c | 130 +++++++++++++++++++- + monitor_wrap.h | 11 +- + packet.c | 98 +++++++++++++-- + packet.h | 1 + + session.c | 83 ++++++++++++- + session.h | 10 +- + sshd-session.c | 104 ++++++++++++++-- + sshd.c | 10 ++ + 27 files changed, 1258 insertions(+), 104 deletions(-) + create mode 100644 auditstub.c + +diff --git a/Makefile.in b/Makefile.in +index 6c417ef7..a2942392 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -119,7 +119,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 --git a/audit-bsm.c b/audit-bsm.c +index ccfcf6f7..a49abb92 100644 +--- a/audit-bsm.c ++++ b/audit-bsm.c +@@ -373,12 +373,25 @@ audit_connection_from(const char *host, int port) #endif } @@ -19,17 +69,16 @@ diff -up openssh-8.6p1/audit-bsm.c.audit openssh-8.6p1/audit-bsm.c /* not implemented */ } - void ++void +audit_count_session_open(void) +{ + /* not necessary */ +} + -+void + void audit_session_open(struct logininfo *li) { - /* not implemented */ -@@ -391,6 +404,12 @@ audit_session_close(struct logininfo *li +@@ -391,6 +404,12 @@ audit_session_close(struct logininfo *li) /* not implemented */ } @@ -42,7 +91,7 @@ diff -up openssh-8.6p1/audit-bsm.c.audit openssh-8.6p1/audit-bsm.c void audit_event(struct ssh *ssh, ssh_audit_event_t event) { -@@ -452,4 +471,28 @@ audit_event(struct ssh *ssh, ssh_audit_e +@@ -452,4 +471,28 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) debug("%s: unhandled event %d", __func__, event); } } @@ -71,234 +120,10 @@ diff -up openssh-8.6p1/audit-bsm.c.audit openssh-8.6p1/audit-bsm.c + /* not implemented */ +} #endif /* BSM */ -diff -up openssh-8.6p1/audit.c.audit openssh-8.6p1/audit.c ---- openssh-8.6p1/audit.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/audit.c 2021-04-19 16:47:35.753062106 +0200 -@@ -34,6 +34,12 @@ - #include "log.h" - #include "hostfile.h" - #include "auth.h" -+#include "ssh-gss.h" -+#include "monitor_wrap.h" -+#include "xmalloc.h" -+#include "misc.h" -+#include "servconf.h" -+#include "ssherr.h" - - /* - * Care must be taken when using this since it WILL NOT be initialized when -@@ -41,6 +47,7 @@ - * audit_event(CONNECTION_ABANDON) is called. Test for NULL before using. - */ - extern Authctxt *the_authctxt; -+extern ServerOptions options; - - /* Maybe add the audit class to struct Authmethod? */ - ssh_audit_event_t -@@ -69,13 +76,10 @@ audit_classify_auth(const char *method) - const char * - audit_username(void) - { -- static const char unknownuser[] = "(unknown user)"; -- static const char invaliduser[] = "(invalid user)"; -+ static const char unknownuser[] = "(unknown)"; - -- if (the_authctxt == NULL || the_authctxt->user == NULL) -+ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid) - return (unknownuser); -- if (!the_authctxt->valid) -- return (invaliduser); - return (the_authctxt->user); - } - -@@ -109,6 +113,35 @@ audit_event_lookup(ssh_audit_event_t ev) - return(event_lookup[i].name); - } - -+void -+audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) -+{ -+ char *fp; -+ -+ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); -+ if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) -+ *rv = -SSH_ERR_INTERNAL_ERROR; -+ free(fp); -+} -+ -+void -+audit_unsupported(struct ssh *ssh, int what) -+{ -+ PRIVSEP(audit_unsupported_body(ssh, what)); -+} -+ -+void -+audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs) -+{ -+ PRIVSEP(audit_kex_body(ssh, ctos, enc, mac, comp, pfs, getpid(), getuid())); -+} -+ -+void -+audit_session_key_free(struct ssh *ssh, int ctos) -+{ -+ PRIVSEP(audit_session_key_free_body(ssh, ctos, getpid(), getuid())); -+} -+ - # ifndef CUSTOM_SSH_AUDIT_EVENTS - /* - * Null implementations of audit functions. -@@ -138,6 +171,17 @@ audit_event(struct ssh *ssh, ssh_audit_e - } - - /* -+ * Called when a child process has called, or will soon call, -+ * audit_session_open. -+ */ -+void -+audit_count_session_open(void) -+{ -+ debug("audit count session open euid %d user %s", geteuid(), -+ audit_username()); -+} -+ -+/* - * Called when a user session is started. Argument is the tty allocated to - * the session, or NULL if no tty was allocated. - * -@@ -172,13 +216,82 @@ audit_session_close(struct logininfo *li - /* - * This will be called when a user runs a non-interactive command. Note that - * it may be called multiple times for a single connection since SSH2 allows -- * multiple sessions within a single connection. -+ * multiple sessions within a single connection. Returns a "handle" for -+ * audit_end_command. - */ --void --audit_run_command(const char *command) -+int -+audit_run_command(struct ssh *ssh, const char *command) - { - debug("audit run command euid %d user %s command '%.200s'", geteuid(), - audit_username(), command); -+ return 0; -+} -+ -+/* -+ * This will be called when the non-interactive command finishes. Note that -+ * it may be called multiple times for a single connection since SSH2 allows -+ * multiple sessions within a single connection. "handle" should come from -+ * the corresponding audit_run_command. -+ */ -+void -+audit_end_command(struct ssh *ssh, int handle, const char *command) -+{ -+ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(), -+ audit_username(), command); -+} -+ -+/* -+ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key. -+ * -+ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key. -+ */ -+int -+audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) -+{ -+ debug("audit %s key usage euid %d user %s fingerprint %s, result %d", -+ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(), -+ fp, rv); -+} -+ -+/* -+ * This will be called when the protocol negotiation fails. -+ */ -+void -+audit_unsupported_body(struct ssh *ssh, int what) -+{ -+ debug("audit unsupported protocol euid %d type %d", geteuid(), what); -+} -+ -+/* -+ * This will be called on succesfull protocol negotiation. -+ */ -+void -+audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, -+ uid_t uid) -+{ -+ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid, -+ (unsigned)uid); -+} -+ -+/* -+ * This will be called on succesfull session key discard -+ */ -+void -+audit_session_key_free_body(struct ssh *, int ctos, pid_t pid, uid_t uid) -+{ -+ debug("audit session key discard euid %u direction %d from pid %ld uid %u", -+ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid); -+} -+ -+/* -+ * This will be called on destroy private part of the server key -+ */ -+void -+audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid) -+{ -+ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u", -+ geteuid(), fp, (long)pid, (unsigned)uid); - } - # endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */ - #endif /* SSH_AUDIT_EVENTS */ -diff -up openssh-8.6p1/audit.h.audit openssh-8.6p1/audit.h ---- openssh-8.6p1/audit.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/audit.h 2021-04-19 16:47:35.753062106 +0200 -@@ -26,6 +26,7 @@ - # define _SSH_AUDIT_H - - #include "loginrec.h" -+#include "sshkey.h" - - struct ssh; - -@@ -45,13 +46,32 @@ enum ssh_audit_event_type { - SSH_CONNECTION_ABANDON, /* closed without completing auth */ - SSH_AUDIT_UNKNOWN - }; -+ -+enum ssh_audit_kex { -+ SSH_AUDIT_UNSUPPORTED_CIPHER, -+ SSH_AUDIT_UNSUPPORTED_MAC, -+ SSH_AUDIT_UNSUPPORTED_COMPRESSION -+}; - typedef enum ssh_audit_event_type ssh_audit_event_t; - -+int listening_for_clients(void); -+ - void audit_connection_from(const char *, int); - void audit_event(struct ssh *, ssh_audit_event_t); -+void audit_count_session_open(void); - void audit_session_open(struct logininfo *); - void audit_session_close(struct logininfo *); --void audit_run_command(const char *); -+int audit_run_command(struct ssh *, const char *); -+void audit_end_command(struct ssh *, int, const char *); - ssh_audit_event_t audit_classify_auth(const char *); -+int audit_keyusage(struct ssh *, int, char *, int); -+void audit_key(struct ssh *, int, int *, const struct sshkey *); -+void audit_unsupported(struct ssh *, int); -+void audit_kex(struct ssh *, int, char *, char *, char *, char *); -+void audit_unsupported_body(struct ssh *, int); -+void audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t); -+void audit_session_key_free(struct ssh *, int ctos); -+void audit_session_key_free_body(struct ssh *, int ctos, pid_t, uid_t); -+void audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t); - - #endif /* _SSH_AUDIT_H */ -diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c ---- openssh-8.6p1/audit-linux.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/audit-linux.c 2021-04-19 16:47:35.753062106 +0200 +diff --git a/audit-linux.c b/audit-linux.c +index 3fcbe5c5..d484b82b 100644 +--- a/audit-linux.c ++++ b/audit-linux.c @@ -33,27 +33,40 @@ #include "log.h" @@ -310,11 +135,10 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c +#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; @@ -348,7 +172,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c saved_errno = errno; close(audit_fd); -@@ -65,9 +78,96 @@ linux_audit_record_event(int uid, const +@@ -65,9 +78,96 @@ linux_audit_record_event(int uid, const char *username, const char *hostname, rc = 0; errno = saved_errno; @@ -446,7 +270,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c /* Below is the sshd audit API code */ void -@@ -76,49 +176,210 @@ audit_connection_from(const char *host, +@@ -76,49 +176,211 @@ audit_connection_from(const char *host, int port) /* not implemented */ } @@ -525,6 +349,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c case SSH_AUTH_FAIL_PASSWD: + if (options.use_pam) + break; ++ /* Fallthrough */ + case SSH_LOGIN_EXCEED_MAXTRIES: case SSH_AUTH_FAIL_KBDINT: case SSH_AUTH_FAIL_PUBKEY: @@ -564,7 +389,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c +{ +#ifdef AUDIT_CRYPTO_SESSION + char buf[AUDIT_LOG_SIZE]; -+ const static char *name[] = { "cipher", "mac", "comp" }; ++ static const char *name[] = { "cipher", "mac", "comp" }; + char *s; + int audit_fd; + @@ -582,7 +407,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c +#endif +} + -+const static char *direction[] = { "from-server", "from-client", "both" }; ++static const char *direction[] = { "from-server", "from-client", "both" }; + +void +audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, @@ -661,7 +486,7 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c + } + audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, + buf, NULL, -+ listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh), ++ ssh_remote_ipaddr(ssh), /*FIXME listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh) */ + NULL, 1); + audit_close(audit_fd); + /* do not abort if the error is EPERM and sshd is run as non root user */ @@ -669,9 +494,238 @@ diff -up openssh-8.6p1/audit-linux.c.audit openssh-8.6p1/audit-linux.c + error("cannot write into audit"); +} #endif /* USE_LINUX_AUDIT */ -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 +diff --git a/audit.c b/audit.c +index dd2f0355..d0433c3a 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 38cb5ad3..45d66ccf 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 00000000..639a798d +--- /dev/null ++++ b/auditstub.c @@ -0,0 +1,52 @@ +/* $Id: auditstub.c,v 1.1 jfch Exp $ */ + @@ -725,32 +779,56 @@ diff -up openssh-8.6p1/auditstub.c.audit openssh-8.6p1/auditstub.c +audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid) +{ +} -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(); +diff --git a/auth.c b/auth.c +index e4578169..e10e804f 100644 +--- a/auth.c ++++ b/auth.c +@@ -501,9 +501,6 @@ getpwnamallow(struct ssh *ssh, const char *user) + record_failed_login(ssh, user, + auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); + #endif -#ifdef SSH_AUDIT_EVENTS -- PRIVSEP(audit_event(ssh, SSH_INVALID_USER)); --#endif - } - #ifdef USE_PAM - if (options.use_pam) -diff -up openssh-8.6p1/auth2-hostbased.c.audit openssh-8.6p1/auth2-hostbased.c ---- openssh-8.6p1/auth2-hostbased.c.audit 2021-04-19 16:47:35.656061361 +0200 -+++ openssh-8.6p1/auth2-hostbased.c 2021-04-19 16:47:35.754062114 +0200 -@@ -158,7 +158,7 @@ userauth_hostbased(struct ssh *ssh) +- 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 39163035..6be52d70 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 a3be6e49..8cebaffd 100644 +--- a/auth2-hostbased.c ++++ b/auth2-hostbased.c +@@ -157,7 +157,7 @@ userauth_hostbased(struct ssh *ssh, const char *method) authenticated = 0; - if (PRIVSEP(hostbased_key_allowed(ssh, authctxt->pw, cuser, - chost, key)) && -- PRIVSEP(sshkey_verify(key, sig, slen, -+ PRIVSEP(hostbased_key_verify(ssh, key, sig, slen, - sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat, NULL)) == 0) + if (mm_hostbased_key_allowed(ssh, authctxt->pw, cuser, + chost, key) && +- mm_sshkey_verify(key, sig, slen, ++ mm_hostbased_key_verify(ssh, key, sig, slen, + sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat, NULL) == 0) authenticated = 1; -@@ -175,6 +175,20 @@ done: +@@ -174,6 +174,20 @@ done: return authenticated; } @@ -771,19 +849,20 @@ diff -up openssh-8.6p1/auth2-hostbased.c.audit openssh-8.6p1/auth2-hostbased.c /* return 1 if given hostkey is allowed */ int hostbased_key_allowed(struct ssh *ssh, struct passwd *pw, -diff -up openssh-8.6p1/auth2-pubkey.c.audit openssh-8.6p1/auth2-pubkey.c ---- openssh-8.6p1/auth2-pubkey.c.audit 2021-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) +diff --git a/auth2-pubkey.c b/auth2-pubkey.c +index 0d5ae0df..99cb810f 100644 +--- a/auth2-pubkey.c ++++ b/auth2-pubkey.c +@@ -235,7 +235,7 @@ userauth_pubkey(struct ssh *ssh, const char *method) /* test for correct signature */ authenticated = 0; - if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && -- PRIVSEP(sshkey_verify(key, sig, slen, -+ PRIVSEP(user_key_verify(ssh, key, sig, slen, + if (mm_user_key_allowed(ssh, pw, key, 1, &authopts) && +- mm_sshkey_verify(key, sig, slen, ++ mm_user_key_verify(ssh, key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, - ssh->compat, &sig_details)) == 0) { -@@ -305,6 +305,20 @@ done: + ssh->compat, &sig_details) == 0) { +@@ -328,6 +328,20 @@ done: return authenticated; } @@ -804,43 +883,24 @@ diff -up openssh-8.6p1/auth2-pubkey.c.audit openssh-8.6p1/auth2-pubkey.c static int match_principals_file(struct passwd *pw, char *file, struct sshkey_cert *cert, struct sshauthopt **authoptsp) -diff -up openssh-8.6p1/auth.c.audit openssh-8.6p1/auth.c ---- openssh-8.6p1/auth.c.audit 2021-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 +diff --git a/auth2.c b/auth2.c +index 8ec41de2..4a8515ea 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(); -#ifdef SSH_AUDIT_EVENTS -- audit_event(ssh, SSH_INVALID_USER); --#endif /* SSH_AUDIT_EVENTS */ - return (NULL); - } - if (!allowed_user(ssh, pw)) -diff -up openssh-8.6p1/auth.h.audit openssh-8.6p1/auth.h ---- openssh-8.6p1/auth.h.audit 2021-04-19 16:47:35.697061676 +0200 -+++ openssh-8.6p1/auth.h 2021-04-19 16:47:35.754062114 +0200 -@@ -212,6 +214,8 @@ struct sshkey *get_hostkey_private_by_ty - int get_hostkey_index(struct sshkey *, int, struct ssh *); - int sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *, - u_char **, size_t *, const u_char *, size_t, const char *); -+int hostbased_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, -+ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); - - /* Key / cert options linkage to auth layer */ - const struct sshauthopt *auth_options(struct ssh *); -@@ -239,6 +241,8 @@ struct passwd * getpwnamallow(struct ssh - char *, const char *, const char *, const char *, struct sshauthopt **); - int auth_check_authkeys_file(struct passwd *, FILE *, char *, - struct sshkey *, const char *, const char *, struct sshauthopt **); -+int user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t, -+ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); - FILE *auth_openkeyfile(const char *, struct passwd *, int); - FILE *auth_openprincipals(const char *, struct passwd *, int); - -diff -up openssh-8.6p1/cipher.c.audit openssh-8.6p1/cipher.c ---- openssh-8.6p1/cipher.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/cipher.c 2021-04-19 16:47:35.755062122 +0200 +- mm_audit_event(ssh, SSH_INVALID_USER); +-#endif + } + #ifdef USE_PAM + if (options.use_pam) +diff --git a/cipher.c b/cipher.c +index 8a18da2d..57d55325 100644 +--- a/cipher.c ++++ b/cipher.c @@ -64,25 +64,6 @@ struct sshcipher_ctx { const struct sshcipher *cipher; }; @@ -867,7 +927,7 @@ diff -up openssh-8.6p1/cipher.c.audit openssh-8.6p1/cipher.c static const struct sshcipher ciphers[] = { #ifdef WITH_OPENSSL #ifndef OPENSSL_NO_DES -@@ -422,7 +403,7 @@ cipher_get_length(struct sshcipher_ctx * +@@ -420,7 +401,7 @@ cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr, void cipher_free(struct sshcipher_ctx *cc) { @@ -876,9 +936,10 @@ diff -up openssh-8.6p1/cipher.c.audit openssh-8.6p1/cipher.c return; if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { chachapoly_free(cc->cp_ctx); -diff -up openssh-8.6p1/cipher.h.audit openssh-8.6p1/cipher.h ---- openssh-8.6p1/cipher.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/cipher.h 2021-04-19 16:47:35.755062122 +0200 +diff --git a/cipher.h b/cipher.h +index 6533ff2b..2e05a021 100644 +--- a/cipher.h ++++ b/cipher.h @@ -47,7 +47,25 @@ #define CIPHER_ENCRYPT 1 #define CIPHER_DECRYPT 0 @@ -906,18 +967,19 @@ diff -up openssh-8.6p1/cipher.h.audit openssh-8.6p1/cipher.h struct sshcipher_ctx; const struct sshcipher *cipher_by_name(const char *); -diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c ---- openssh-8.6p1/kex.c.audit 2021-04-19 16:47:35.743062030 +0200 -+++ openssh-8.6p1/kex.c 2021-04-19 16:47:35.755062122 +0200 -@@ -65,6 +65,7 @@ +diff --git a/kex.c b/kex.c +index 8b200ff4..62f607d6 100644 +--- a/kex.c ++++ b/kex.c +@@ -68,6 +68,7 @@ #include "sshbuf.h" #include "digest.h" #include "xmalloc.h" +#include "audit.h" - #ifdef GSSAPI - #include "ssh-gss.h" -@@ -816,12 +817,16 @@ kex_start_rekex(struct ssh *ssh) + /* prototype */ + static int kex_choose_conf(struct ssh *, uint32_t seq); +@@ -821,12 +822,16 @@ kex_start_rekex(struct ssh *ssh) } static int @@ -936,7 +998,7 @@ diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c if ((enc->cipher = cipher_by_name(name)) == NULL) { error_f("unsupported cipher %s", name); free(name); -@@ -842,8 +847,12 @@ choose_mac(struct ssh *ssh, struct sshma +@@ -847,8 +852,12 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) { char *name = match_list(client, server, NULL); @@ -950,7 +1012,7 @@ diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c if (mac_setup(mac, name) < 0) { error_f("unsupported MAC %s", name); free(name); -@@ -856,12 +865,16 @@ choose_mac(struct ssh *ssh, struct sshma +@@ -861,12 +870,16 @@ choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) } static int @@ -969,7 +1031,7 @@ diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c #ifdef WITH_ZLIB if (strcmp(name, "zlib@openssh.com") == 0) { comp->type = COMP_DELAYED; -@@ -1002,7 +1015,7 @@ kex_choose_conf(struct ssh *ssh) +@@ -1030,7 +1043,7 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) 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; @@ -978,7 +1040,7 @@ diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c sprop[nenc])) != 0) { kex->failed_choice = peer[nenc]; peer[nenc] = NULL; -@@ -1017,7 +1030,7 @@ kex_choose_conf(struct ssh *ssh) +@@ -1045,7 +1058,7 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) peer[nmac] = NULL; goto out; } @@ -987,7 +1049,7 @@ diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c sprop[ncomp])) != 0) { kex->failed_choice = peer[ncomp]; peer[ncomp] = NULL; -@@ -1040,6 +1053,10 @@ kex_choose_conf(struct ssh *ssh) +@@ -1068,6 +1081,10 @@ kex_choose_conf(struct ssh *ssh, uint32_t seq) 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); @@ -998,7 +1060,7 @@ diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c } /* XXX need runden? */ kex->we_need = need; -@@ -1297,6 +1314,36 @@ dump_digest(const char *msg, const u_cha +@@ -1337,6 +1354,36 @@ dump_digest(const char *msg, const u_char *digest, int len) } #endif @@ -1035,10 +1097,11 @@ diff -up openssh-8.6p1/kex.c.audit openssh-8.6p1/kex.c /* * Send a plaintext error message to the peer, suffixed by \r\n. * Only used during banner exchange, and there only for the server. -diff -up openssh-8.6p1/kex.h.audit openssh-8.6p1/kex.h ---- openssh-8.6p1/kex.h.audit 2021-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 *); +diff --git a/kex.h b/kex.h +index 0e080ea3..6a55aadf 100644 +--- a/kex.h ++++ b/kex.h +@@ -255,6 +255,8 @@ int kexgss_client(struct ssh *); int kexgss_server(struct ssh *); #endif @@ -1047,9 +1110,10 @@ diff -up openssh-8.6p1/kex.h.audit openssh-8.6p1/kex.h int kex_dh_keypair(struct kex *); int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **, struct sshbuf **); -diff -up openssh-8.6p1/mac.c.audit openssh-8.6p1/mac.c ---- openssh-8.6p1/mac.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/mac.c 2021-04-19 16:47:35.756062129 +0200 +diff --git a/mac.c b/mac.c +index f3dda669..bf051baa 100644 +--- a/mac.c ++++ b/mac.c @@ -239,6 +239,20 @@ mac_clear(struct sshmac *mac) mac->umac_ctx = NULL; } @@ -1071,31 +1135,21 @@ diff -up openssh-8.6p1/mac.c.audit openssh-8.6p1/mac.c /* XXX copied from ciphers_valid */ #define MAC_SEP "," 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 +diff --git a/mac.h b/mac.h +index 0b119d7a..5fb593b9 100644 +--- a/mac.h ++++ b/mac.h +@@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int32_t, const u_char *, int, 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 -up openssh-8.6p1/Makefile.in.audit openssh-8.6p1/Makefile.in ---- openssh-8.6p1/Makefile.in.audit 2021-04-19 16:47:35.731061937 +0200 -+++ openssh-8.6p1/Makefile.in 2021-04-19 16:47:35.756062129 +0200 -@@ -112,7 +112,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ - kexsntrup761x25519.o sntrup761.o kexgen.o \ - kexgssc.o \ - sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \ -- sshbuf-io.o -+ sshbuf-io.o auditstub.o - - SKOBJS= ssh-sk-client.o - -diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c ---- openssh-8.6p1/monitor.c.audit 2021-04-19 16:47:35.707061753 +0200 -+++ openssh-8.6p1/monitor.c 2021-04-19 16:47:35.756062129 +0200 +diff --git a/monitor.c b/monitor.c +index 43c10a4e..fbc35782 100644 +--- a/monitor.c ++++ b/monitor.c @@ -93,6 +93,7 @@ #include "compat.h" #include "ssh2.h" @@ -1104,16 +1158,16 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c #include "match.h" #include "ssherr.h" #include "sk-api.h" -@@ -107,6 +108,8 @@ extern u_int utmp_len; - extern struct sshbuf *loginmsg; +@@ -110,6 +111,8 @@ extern struct sshbuf *loginmsg; + extern struct include_list includes; extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */ -+extern void destroy_sensitive_data(struct ssh *, int); ++extern void destroy_sensitive_data(struct ssh *); + /* State exported from the child */ static struct sshbuf *child_state; -@@ -157,6 +160,11 @@ int mm_answer_gss_updatecreds(struct ssh +@@ -154,6 +157,11 @@ int mm_answer_gss_updatecreds(struct ssh *, int, struct sshbuf *); #ifdef SSH_AUDIT_EVENTS int mm_answer_audit_event(struct ssh *, int, struct sshbuf *); int mm_answer_audit_command(struct ssh *, int, struct sshbuf *); @@ -1125,7 +1179,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c #endif static Authctxt *authctxt; -@@ -215,6 +223,10 @@ struct mon_table mon_dispatch_proto20[] +@@ -214,6 +222,10 @@ struct mon_table mon_dispatch_proto20[] = { #endif #ifdef SSH_AUDIT_EVENTS {MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event}, @@ -1136,7 +1190,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c #endif #ifdef BSD_AUTH {MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery}, -@@ -249,6 +261,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}, @@ -1148,7 +1202,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c #endif {0, 0, NULL} }; -@@ -1444,8 +1461,10 @@ mm_answer_keyverify(struct ssh *ssh, int +@@ -1569,8 +1586,10 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) int r, ret, req_presence = 0, req_verify = 0, valid_data = 0; int encoded_ret; struct sshkey_sig_details *sig_details = NULL; @@ -1160,7 +1214,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c (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) -@@ -1454,6 +1473,8 @@ mm_answer_keyverify(struct ssh *ssh, int +@@ -1579,6 +1598,8 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) if (hostbased_cuser == NULL || hostbased_chost == NULL || !monitor_allowed_key(blob, bloblen)) fatal_f("bad key, not previously allowed"); @@ -1169,7 +1223,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c /* Empty signature algorithm means NULL. */ if (*sigalg == '\0') { -@@ -1469,14 +1490,19 @@ mm_answer_keyverify(struct ssh *ssh, int +@@ -1594,14 +1615,19 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) case MM_USERKEY: valid_data = monitor_valid_userblob(ssh, data, datalen); auth_method = "publickey"; @@ -1189,16 +1243,16 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c break; } if (!valid_data) -@@ -1488,8 +1514,6 @@ mm_answer_keyverify(struct ssh *ssh, int +@@ -1613,8 +1639,6 @@ mm_answer_keyverify(struct ssh *ssh, int sock, struct sshbuf *m) 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", -@@ -1576,13 +1600,19 @@ mm_record_login(struct ssh *ssh, Session + debug3_f("%s %s signature using %s %s%s%s", auth_method, + sshkey_type(key), sigalg == NULL ? "default" : sigalg, + (ret == 0) ? "verified" : "unverified", +@@ -1702,13 +1726,19 @@ mm_record_login(struct ssh *ssh, Session *s, struct passwd *pw) } static void @@ -1219,7 +1273,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c session_unused(s->self); } -@@ -1649,7 +1679,7 @@ mm_answer_pty(struct ssh *ssh, int sock, +@@ -1775,7 +1805,7 @@ mm_answer_pty(struct ssh *ssh, int sock, struct sshbuf *m) error: if (s != NULL) @@ -1228,7 +1282,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c if ((r = sshbuf_put_u32(m, 0)) != 0) fatal_fr(r, "assemble 0"); mm_request_send(sock, MONITOR_ANS_PTY, m); -@@ -1668,7 +1698,7 @@ mm_answer_pty_cleanup(struct ssh *ssh, i +@@ -1794,7 +1824,7 @@ mm_answer_pty_cleanup(struct ssh *ssh, int sock, struct sshbuf *m) if ((r = sshbuf_get_cstring(m, &tty, NULL)) != 0) fatal_fr(r, "parse tty"); if ((s = session_by_tty(tty)) != NULL) @@ -1237,16 +1291,16 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c sshbuf_reset(m); free(tty); return (0); -@@ -1690,6 +1720,8 @@ mm_answer_term(struct ssh *ssh, int sock +@@ -1816,6 +1846,8 @@ mm_answer_term(struct ssh *ssh, int sock, struct sshbuf *req) sshpam_cleanup(); #endif -+ destroy_sensitive_data(ssh, 0); ++ destroy_sensitive_data(ssh); + while (waitpid(pmonitor->m_pid, &status, 0) == -1) if (errno != EINTR) exit(1); -@@ -1736,12 +1768,47 @@ mm_answer_audit_command(struct ssh *ssh, +@@ -1862,12 +1894,47 @@ mm_answer_audit_command(struct ssh *ssh, int socket, struct sshbuf *m) { char *cmd; int r; @@ -1295,7 +1349,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c free(cmd); return (0); } -@@ -1813,6 +1880,7 @@ monitor_apply_keystate(struct ssh *ssh, +@@ -1940,6 +2007,7 @@ monitor_apply_keystate(struct ssh *ssh, struct monitor *pmonitor) void mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) { @@ -1303,7 +1357,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c debug3_f("Waiting for new keys"); if ((child_state = sshbuf_new()) == NULL) -@@ -1820,6 +1888,19 @@ mm_get_keystate(struct ssh *ssh, struct +@@ -1947,6 +2015,19 @@ mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor) mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT, child_state); debug3_f("GOT new keys"); @@ -1323,7 +1377,7 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c } -@@ -2111,3 +2192,102 @@ mm_answer_gss_updatecreds(struct ssh *ss +@@ -2234,3 +2315,102 @@ mm_answer_gss_updatecreds(struct ssh *ssh, int socket, struct sshbuf *m) { #endif /* GSSAPI */ @@ -1426,10 +1480,11 @@ diff -up openssh-8.6p1/monitor.c.audit openssh-8.6p1/monitor.c + return 0; +} +#endif /* SSH_AUDIT_EVENTS */ -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 { +diff --git a/monitor.h b/monitor.h +index d4d631dd..2c64f07d 100644 +--- a/monitor.h ++++ b/monitor.h +@@ -66,7 +66,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, @@ -1444,10 +1499,11 @@ diff -up openssh-8.6p1/monitor.h.audit openssh-8.6p1/monitor.h MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, -diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c ---- openssh-8.6p1/monitor_wrap.c.audit 2021-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 +diff --git a/monitor_wrap.c b/monitor_wrap.c +index b6e3b3f3..1a079c15 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -567,7 +567,7 @@ mm_key_allowed(enum mm_keytype type, const char *user, const char *host, */ int @@ -1456,7 +1512,7 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c const u_char *data, size_t datalen, const char *sigalg, u_int compat, struct sshkey_sig_details **sig_detailsp) { -@@ -536,7 +536,8 @@ mm_sshkey_verify(const struct sshkey *ke +@@ -583,7 +583,8 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, *sig_detailsp = NULL; if ((m = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); @@ -1466,7 +1522,7 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c (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) -@@ -569,6 +570,22 @@ mm_sshkey_verify(const struct sshkey *ke +@@ -616,6 +617,22 @@ mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, return 0; } @@ -1489,7 +1545,7 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c void mm_send_keystate(struct ssh *ssh, struct monitor *monitor) { -@@ -921,11 +938,12 @@ mm_audit_event(struct ssh *ssh, ssh_audi +@@ -1032,11 +1049,12 @@ mm_audit_event(struct ssh *ssh, ssh_audit_event_t event) sshbuf_free(m); } @@ -1504,7 +1560,7 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c debug3("%s entering command %s", __func__, command); -@@ -935,6 +953,30 @@ mm_audit_run_command(const char *command +@@ -1046,6 +1064,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); @@ -1535,10 +1591,10 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c sshbuf_free(m); } #endif /* SSH_AUDIT_EVENTS */ -@@ -1095,3 +1137,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc +@@ -1294,3 +1336,83 @@ server_get_connection_info(struct ssh *ssh, int populate, int use_dns) + return &ci; } - #endif /* GSSAPI */ +#ifdef SSH_AUDIT_EVENTS +void +mm_audit_unsupported_body(struct ssh *ssh, int what) @@ -1619,10 +1675,11 @@ diff -up openssh-8.6p1/monitor_wrap.c.audit openssh-8.6p1/monitor_wrap.c + sshbuf_free(m); +} +#endif /* SSH_AUDIT_EVENTS */ -diff -up openssh-8.6p1/monitor_wrap.h.audit openssh-8.6p1/monitor_wrap.h ---- openssh-8.6p1/monitor_wrap.h.audit 2021-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 +diff --git a/monitor_wrap.h b/monitor_wrap.h +index 672dce52..661ed63b 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -58,7 +58,9 @@ int mm_user_key_allowed(struct ssh *ssh, struct passwd *, struct sshkey *, int, struct sshauthopt **); int mm_hostbased_key_allowed(struct ssh *, struct passwd *, const char *, const char *, struct sshkey *); @@ -1632,8 +1689,8 @@ diff -up openssh-8.6p1/monitor_wrap.h.audit openssh-8.6p1/monitor_wrap.h +int mm_user_key_verify(struct ssh*, const struct sshkey *, const u_char *, size_t, const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **); - #ifdef GSSAPI -@@ -86,7 +88,12 @@ void mm_sshpam_free_ctx(void *); + void mm_decode_activate_server_options(struct ssh *ssh, struct sshbuf *m); +@@ -85,7 +87,12 @@ void mm_sshpam_free_ctx(void *); #ifdef SSH_AUDIT_EVENTS #include "audit.h" void mm_audit_event(struct ssh *, ssh_audit_event_t); @@ -1647,9 +1704,10 @@ diff -up openssh-8.6p1/monitor_wrap.h.audit openssh-8.6p1/monitor_wrap.h #endif struct Session; -diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c ---- openssh-8.6p1/packet.c.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/packet.c 2021-04-19 16:48:46.885608837 +0200 +diff --git a/packet.c b/packet.c +index 9dea2cfc..344b5f54 100644 +--- a/packet.c ++++ b/packet.c @@ -81,6 +81,7 @@ #endif @@ -1658,7 +1716,7 @@ diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c #include "compat.h" #include "ssh2.h" #include "cipher.h" -@@ -506,6 +507,13 @@ ssh_packet_get_connection_out(struct ssh +@@ -506,6 +507,13 @@ ssh_packet_get_connection_out(struct ssh *ssh) return ssh->state->connection_out; } @@ -1672,7 +1730,7 @@ diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c /* * Returns the IP-address of the remote host as a string. The returned * string must not be freed. -@@ -583,22 +591,19 @@ ssh_packet_close_internal(struct ssh *ss +@@ -675,22 +683,19 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) { struct session_state *state = ssh->state; u_int mode; @@ -1700,7 +1758,7 @@ diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c 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 +@@ -726,8 +731,18 @@ ssh_packet_close_internal(struct ssh *ssh, int do_close) #endif /* WITH_ZLIB */ cipher_free(state->send_context); cipher_free(state->receive_context); @@ -1719,7 +1777,7 @@ diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c free(ssh->local_ipaddr); ssh->local_ipaddr = NULL; free(ssh->remote_ipaddr); -@@ -892,6 +907,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod +@@ -984,6 +999,7 @@ ssh_set_newkeys(struct ssh *ssh, int mode) (unsigned long long)state->p_send.bytes, (unsigned long long)state->p_send.blocks); kex_free_newkeys(state->newkeys[mode]); @@ -1727,7 +1785,7 @@ diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c state->newkeys[mode] = NULL; } /* note that both bytes and the seqnr are not reset */ -@@ -2173,6 +2189,72 @@ ssh_packet_get_output(struct ssh *ssh) +@@ -2325,6 +2341,72 @@ ssh_packet_get_output(struct ssh *ssh) return (void *)ssh->state->output; } @@ -1800,28 +1858,30 @@ diff -up openssh-8.6p1/packet.c.audit openssh-8.6p1/packet.c /* Reset after_authentication and reset compression in post-auth privsep */ static int ssh_packet_set_postauth(struct ssh *ssh) -diff -up openssh-8.6p1/packet.h.audit openssh-8.6p1/packet.h ---- openssh-8.6p1/packet.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/packet.h 2021-04-19 16:47:35.758062145 +0200 -@@ -218,4 +218,5 @@ const u_char *sshpkt_ptr(struct ssh *, s +diff --git a/packet.h b/packet.h +index 49bb87f0..44a39a9e 100644 +--- a/packet.h ++++ b/packet.h +@@ -223,4 +223,5 @@ const u_char *sshpkt_ptr(struct ssh *, size_t *lenp); # undef EC_POINT #endif +void packet_destroy_all(struct ssh *, int, int); #endif /* PACKET_H */ -diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c ---- openssh-8.6p1/session.c.audit 2021-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; +diff --git a/session.c b/session.c +index 28bbb8a7..83fc9418 100644 +--- a/session.c ++++ b/session.c +@@ -145,7 +145,7 @@ extern char *__progname; extern int debug_flag; extern u_int utmp_len; extern int startup_pipe; -extern void destroy_sensitive_data(void); -+extern void destroy_sensitive_data(struct ssh *, int); ++extern void destroy_sensitive_data(struct ssh *); extern struct sshbuf *loginmsg; extern struct sshauthopt *auth_opts; extern char *tun_fwd_ifnames; /* serverloop.c */ -@@ -644,6 +644,14 @@ do_exec_pty(struct ssh *ssh, Session *s, +@@ -653,6 +653,14 @@ do_exec_pty(struct ssh *ssh, Session *s, const char *command) /* Parent. Close the slave side of the pseudo tty. */ close(ttyfd); @@ -1836,34 +1896,33 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c /* Enter interactive session. */ s->ptymaster = ptymaster; ssh_packet_set_interactive(ssh, 1, -@@ -736,15 +744,19 @@ do_exec(struct ssh *ssh, Session *s, con +@@ -745,15 +753,19 @@ do_exec(struct ssh *ssh, Session *s, const char *command) s->self); #ifdef SSH_AUDIT_EVENTS + if (s->command != NULL || s->command_handle != -1) + fatal("do_exec: command already set"); if (command != NULL) -- PRIVSEP(audit_run_command(command)); +- mm_audit_run_command(command); + s->command = xstrdup(command); else if (s->ttyfd == -1) { char *shell = s->pw->pw_shell; if (shell[0] == '\0') /* empty shell means /bin/sh */ shell =_PATH_BSHELL; -- PRIVSEP(audit_run_command(shell)); +- mm_audit_run_command(shell); + s->command = xstrdup(shell); } + if (s->command != NULL && s->ptyfd == -1) -+ s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); ++ s->command_handle = mm_audit_run_command(ssh, s->command); #endif if (s->ttyfd != -1) ret = do_exec_pty(ssh, s, command); -@@ -1550,8 +1562,11 @@ do_child(struct ssh *ssh, Session *s, co +@@ -1538,7 +1550,11 @@ do_child(struct ssh *ssh, Session *s, const char *command) sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); - /* remove hostkey from the child's memory */ -- destroy_sensitive_data(); -+ destroy_sensitive_data(ssh, 1); + /* remove keys from memory */ ++ destroy_sensitive_data(ssh); ssh_packet_clear_keys(ssh); + /* Don't audit this - both us and the parent would be talking to the + monitor over a single socket, with no synchronization. */ @@ -1871,7 +1930,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c /* Force a password change */ if (s->authctxt->force_pwchange) { -@@ -1763,6 +1778,9 @@ session_unused(int id) +@@ -1750,6 +1766,9 @@ session_unused(int id) sessions[id].ttyfd = -1; sessions[id].ptymaster = -1; sessions[id].x11_chanids = NULL; @@ -1881,10 +1940,11 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c sessions[id].next_unused = sessions_first_unused; sessions_first_unused = id; } -@@ -1843,6 +1861,19 @@ session_open(Authctxt *authctxt, int cha +@@ -1828,6 +1847,19 @@ session_open(Authctxt *authctxt, int chanid) + return 1; } - Session * ++Session * +session_by_id(int id) +{ + if (id >= 0 && id < sessions_nalloc) { @@ -1897,11 +1957,10 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c + return NULL; +} + -+Session * + Session * session_by_tty(char *tty) { - int i; -@@ -2450,6 +2481,32 @@ session_exit_message(struct ssh *ssh, Se +@@ -2445,6 +2477,32 @@ session_exit_message(struct ssh *ssh, Session *s, int status) chan_write_failed(ssh, c); } @@ -1923,7 +1982,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c +{ + if (s->command != NULL) { + if (s->command_handle != -1) -+ PRIVSEP(audit_end_command(ssh, s->command_handle, s->command)); ++ mm_audit_end_command(ssh, s->command_handle, s->command); + free(s->command); + s->command = NULL; + s->command_handle = -1; @@ -1934,7 +1993,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c void session_close(struct ssh *ssh, Session *s) { -@@ -2463,6 +2520,10 @@ session_close(struct ssh *ssh, Session * +@@ -2458,6 +2516,10 @@ session_close(struct ssh *ssh, Session *s) if (s->ttyfd != -1) session_pty_cleanup(s); @@ -1945,7 +2004,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c free(s->term); free(s->display); free(s->x11_chanids); -@@ -2537,14 +2598,14 @@ session_close_by_channel(struct ssh *ssh +@@ -2534,14 +2596,14 @@ session_close_by_channel(struct ssh *ssh, int id, int force, void *arg) } void @@ -1962,7 +2021,7 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c else session_close(ssh, s); } -@@ -2671,6 +2732,15 @@ do_authenticated2(struct ssh *ssh, Authc +@@ -2668,6 +2730,15 @@ do_authenticated2(struct ssh *ssh, Authctxt *authctxt) server_loop2(ssh, authctxt); } @@ -1978,18 +2037,19 @@ diff -up openssh-8.6p1/session.c.audit openssh-8.6p1/session.c void do_cleanup(struct ssh *ssh, Authctxt *authctxt) { -@@ -2734,7 +2804,7 @@ do_cleanup(struct ssh *ssh, Authctxt *au +@@ -2731,7 +2802,7 @@ do_cleanup(struct ssh *ssh, Authctxt *authctxt) * or if running in monitor. */ - if (!use_privsep || mm_is_monitor()) + if (mm_is_monitor()) - session_destroy_all(ssh, session_pty_cleanup2); + session_destroy_all(ssh, do_cleanup_one_session); } /* Return a name for the remote host that fits inside utmp_size */ -diff -up openssh-8.6p1/session.h.audit openssh-8.6p1/session.h ---- openssh-8.6p1/session.h.audit 2021-04-16 05:55:25.000000000 +0200 -+++ openssh-8.6p1/session.h 2021-04-19 16:47:35.758062145 +0200 +diff --git a/session.h b/session.h +index 344a1ddf..a41c6efc 100644 +--- a/session.h ++++ b/session.h @@ -61,6 +61,12 @@ struct Session { char *name; char *val; @@ -2017,48 +2077,67 @@ diff -up openssh-8.6p1/session.h.audit openssh-8.6p1/session.h Session *session_by_tty(char *); void session_close(struct ssh *, Session *); void do_setusercontext(struct passwd *); -diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c ---- openssh-8.6p1/sshd.c.audit 2021-04-19 16:47:35.727061907 +0200 -+++ openssh-8.6p1/sshd.c 2021-04-19 16:47:35.759062152 +0200 -@@ -122,6 +122,7 @@ - #include "ssh-gss.h" - #endif - #include "monitor_wrap.h" -+#include "audit.h" - #include "ssh-sandbox.h" - #include "auth-options.h" - #include "version.h" -@@ -260,8 +261,8 @@ struct sshbuf *loginmsg; - struct passwd *privsep_pw = NULL; +diff --git a/sshd-session.c b/sshd-session.c +index 81d30152..a808ac9a 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -194,8 +194,8 @@ struct include_list includes = TAILQ_HEAD_INITIALIZER(includes); + 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 *, int); -+void demote_sensitive_data(struct ssh *); - static void do_ssh2_kex(struct ssh *); ++void destroy_sensitive_data(struct ssh *ssh); ++void demote_sensitive_data(struct ssh *ssh); - static char *listener_proctitle; -@@ -279,6 +280,15 @@ close_listen_socks(void) - num_listen_socks = 0; + /* XXX reduce to stub once postauth split */ + int +@@ -208,6 +208,41 @@ mm_is_monitor(void) + return (pmonitor && pmonitor->m_pid > 0); } -+/* -+ * Is this process listening for clients (i.e. not specific to any specific -+ * client connection?) -+ */ -+int listening_for_clients(void) ++static int ++sshkey_is_private(const struct sshkey *k) +{ -+ return num_listen_socks > 0; ++ switch (k->type) { ++#ifdef WITH_OPENSSL ++ case KEY_RSA_CERT: ++ case KEY_RSA: { ++ const BIGNUM *d; ++ const RSA *rsa = EVP_PKEY_get0_RSA(k->pkey); ++ RSA_get0_key(rsa, NULL, NULL, &d); ++ return d != NULL; ++ } ++ case KEY_DSA_CERT: ++ case KEY_DSA: { ++ const BIGNUM *priv_key; ++ DSA_get0_key(k->dsa, NULL, &priv_key); ++ return priv_key != NULL; ++ } ++#ifdef OPENSSL_HAS_ECC ++ case KEY_ECDSA_CERT: ++ case KEY_ECDSA: { ++ const EC_KEY * ecdsa = EVP_PKEY_get0_EC_KEY(k->pkey); ++ return EC_KEY_get0_private_key(ecdsa) != NULL; ++ } ++#endif /* OPENSSL_HAS_ECC */ ++#endif /* WITH_OPENSSL */ ++ case KEY_ED25519_CERT: ++ case KEY_ED25519: ++ return (k->ed25519_pk != NULL); ++ default: ++ /* fatal("key_is_private: bad key type %d", k->type); */ ++ return 0; ++ } +} + - static void - close_startup_pipes(void) - { -@@ -377,18 +387,45 @@ grace_alarm_handler(int sig) - ssh_remote_port(the_active_state)); + /* + * 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 +@@ -236,18 +271,40 @@ grace_alarm_handler(int sig) + _exit(EXIT_LOGIN_GRACE); } - + -/* Destroy the host and server keys. They will no longer be needed. */ +/* + * Destroy the host and server keys. They will no longer be needed. Careful, @@ -2066,7 +2145,7 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c + */ void -destroy_sensitive_data(void) -+destroy_sensitive_data(struct ssh *ssh, int privsep) ++destroy_sensitive_data(struct ssh *ssh) { u_int i; +#ifdef SSH_AUDIT_EVENTS @@ -2088,12 +2167,7 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c sensitive_data.host_keys[i] = NULL; + if (fp != NULL) { +#ifdef SSH_AUDIT_EVENTS -+ if (privsep) -+ PRIVSEP(audit_destroy_sensitive_data(ssh, fp, -+ pid, uid)); -+ else -+ audit_destroy_sensitive_data(ssh, fp, -+ pid, uid); ++ audit_destroy_sensitive_data(ssh, fp, pid, uid); +#endif + free(fp); + } @@ -2104,7 +2178,7 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c sshkey_free(sensitive_data.host_certificates[i]); sensitive_data.host_certificates[i] = NULL; } -@@ -397,20 +434,38 @@ destroy_sensitive_data(void) +@@ -256,20 +313,38 @@ destroy_sensitive_data(void) /* Demote private to public keys for network child */ void @@ -2144,43 +2218,7 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c } /* Certs do not need demotion */ } -@@ -438,7 +493,7 @@ reseed_prngs(void) - } - - static void --privsep_preauth_child(void) -+privsep_preauth_child(struct ssh *ssh) - { - gid_t gidset[1]; - -@@ -453,7 +508,7 @@ privsep_preauth_child(void) - reseed_prngs(); - - /* Demote the private keys to public keys. */ -- demote_sensitive_data(); -+ demote_sensitive_data(ssh); - - #ifdef WITH_SELINUX - sshd_selinux_change_privsep_preauth_context(); -@@ -492,7 +547,7 @@ privsep_preauth(struct ssh *ssh) - - if (use_privsep == PRIVSEP_ON) - box = ssh_sandbox_init(pmonitor); -- pid = fork(); -+ pmonitor->m_pid = pid = fork(); - if (pid == -1) { - fatal("fork of unprivileged child failed"); - } else if (pid != 0) { -@@ -537,7 +592,7 @@ privsep_preauth(struct ssh *ssh) - /* Arrange for logging to be sent to the monitor */ - set_log_handler(mm_log_handler, pmonitor); - -- privsep_preauth_child(); -+ privsep_preauth_child(ssh); - setproctitle("%s", "[net]"); - if (box != NULL) - ssh_sandbox_child(box); -@@ -589,7 +644,7 @@ privsep_postauth(struct ssh *ssh, Authct +@@ -463,7 +538,7 @@ privsep_postauth(struct ssh *ssh, Authctxt *authctxt) set_log_handler(mm_log_handler, pmonitor); /* Demote the private keys to public keys. */ @@ -2189,48 +2227,21 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c reseed_prngs(); -@@ -1143,7 +1198,7 @@ server_listen(void) - * from this function are in a forked subprocess. - */ - static void --server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) -+server_accept_loop(struct ssh *ssh, int *sock_in, int *sock_out, int *newsock, int *config_s) - { - struct pollfd *pfd = NULL; - int i, j, ret, npfd; -@@ -1204,6 +1259,7 @@ server_accept_loop(int *sock_in, int *so - if (received_sigterm) { - logit("Received signal %d; terminating.", - (int) received_sigterm); -+ destroy_sensitive_data(ssh, 0); - close_listen_socks(); - if (options.pid_file != NULL) - unlink(options.pid_file); -@@ -2098,7 +2154,7 @@ main(int ac, char **av) - #endif - - /* Accept a connection and return in a forked child */ -- server_accept_loop(&sock_in, &sock_out, -+ server_accept_loop(ssh, &sock_in, &sock_out, - &newsock, config_s); - } - -@@ -2333,6 +2389,9 @@ main(int ac, char **av) +@@ -1387,6 +1462,9 @@ main(int ac, char **av) do_authenticated(ssh, authctxt); /* The connection has been terminated. */ + packet_destroy_all(ssh, 1, 1); -+ destroy_sensitive_data(ssh, 1); ++ destroy_sensitive_data(ssh); + ssh_packet_get_bytes(ssh, &ibytes, &obytes); verbose("Transferred: sent %llu, received %llu bytes", (unsigned long long)obytes, (unsigned long long)ibytes); -@@ -2513,6 +2572,15 @@ do_ssh2_kex(struct ssh *ssh) +@@ -1432,6 +1510,14 @@ sshd_hostkey_sign(struct ssh *ssh, struct sshkey *privkey, void cleanup_exit(int i) { + static int in_cleanup = 0; -+ int is_privsep_child; + + /* cleanup_exit can be called at the very least from the privsep + wrappers used for auditing. Make sure we don't recurse @@ -2238,77 +2249,48 @@ diff -up openssh-8.6p1/sshd.c.audit openssh-8.6p1/sshd.c + if (in_cleanup) + _exit(i); + in_cleanup = 1; + extern int auth_attempted; /* monitor.c */ + if (the_active_state != NULL && the_authctxt != NULL) { - do_cleanup(the_active_state, the_authctxt); - if (use_privsep && privsep_is_preauth && -@@ -2525,9 +2593,16 @@ cleanup_exit(int i) - } - } +@@ -1448,7 +1534,9 @@ cleanup_exit(int i) } -+ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0; -+ if (sensitive_data.host_keys != NULL && the_active_state != NULL) -+ destroy_sensitive_data(the_active_state, is_privsep_child); -+ if (the_active_state != NULL) -+ packet_destroy_all(the_active_state, 1, is_privsep_child); #ifdef SSH_AUDIT_EVENTS /* done after do_cleanup so it can cancel the PAM auth 'thread' */ -- if (the_active_state != NULL && (!use_privsep || mm_is_monitor())) +- if (the_active_state != NULL && mm_is_monitor()) + if (the_active_state != NULL && + (the_authctxt == NULL || !the_authctxt->authenticated) && -+ (!use_privsep || mm_is_monitor())) ++ mm_is_monitor()) audit_event(the_active_state, SSH_CONNECTION_ABANDON); #endif - _exit(i); -diff -up openssh-8.6p1/sshkey.c.audit openssh-8.6p1/sshkey.c ---- openssh-8.6p1/sshkey.c.audit 2021-04-19 16:47:35.741062014 +0200 -+++ openssh-8.6p1/sshkey.c 2021-04-19 16:47:35.759062152 +0200 -@@ -371,6 +371,38 @@ sshkey_type_is_valid_ca(int type) + /* Override default fatal exit value when auth was attempted */ +diff --git a/sshd.c b/sshd.c +index c9ea8e38..8a99f0b2 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -217,6 +217,15 @@ close_listen_socks(void) + num_listen_socks = 0; } - int -+sshkey_is_private(const struct sshkey *k) ++/* ++ * Is this process listening for clients (i.e. not specific to any specific ++ * client connection?) ++ */ ++int listening_for_clients(void) +{ -+ switch (k->type) { -+#ifdef WITH_OPENSSL -+ case KEY_RSA_CERT: -+ case KEY_RSA: { -+ const BIGNUM *d; -+ RSA_get0_key(k->rsa, NULL, NULL, &d); -+ return d != NULL; -+ } -+ case KEY_DSA_CERT: -+ case KEY_DSA: { -+ const BIGNUM *priv_key; -+ DSA_get0_key(k->dsa, NULL, &priv_key); -+ return priv_key != NULL; -+ } -+#ifdef OPENSSL_HAS_ECC -+ case KEY_ECDSA_CERT: -+ case KEY_ECDSA: -+ return EC_KEY_get0_private_key(k->ecdsa) != NULL; -+#endif /* OPENSSL_HAS_ECC */ -+#endif /* WITH_OPENSSL */ -+ case KEY_ED25519_CERT: -+ case KEY_ED25519: -+ return (k->ed25519_pk != NULL); -+ default: -+ /* fatal("key_is_private: bad key type %d", k->type); */ -+ return 0; -+ } ++ return num_listen_socks > 0; +} + -+int - sshkey_is_cert(const struct sshkey *k) - { - if (k == NULL) -diff -up openssh-8.6p1/sshkey.h.audit openssh-8.6p1/sshkey.h ---- openssh-8.6p1/sshkey.h.audit 2021-04-19 16:47:35.741062014 +0200 -+++ openssh-8.6p1/sshkey.h 2021-04-19 16:47:35.759062152 +0200 -@@ -189,6 +189,7 @@ int sshkey_shield_private(struct sshke - int sshkey_unshield_private(struct sshkey *); - - int sshkey_type_from_name(const char *); -+int sshkey_is_private(const struct sshkey *); - int sshkey_is_cert(const struct sshkey *); - int sshkey_is_sk(const struct sshkey *); - int sshkey_type_is_cert(int); + /* Allocate and initialise the children array */ + static void + child_alloc(void) +@@ -959,6 +968,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.49.0 + diff --git a/openssh-7.1p2-audit-race-condition.patch b/0040-openssh-7.1p2-audit-race-condition.patch similarity index 71% rename from openssh-7.1p2-audit-race-condition.patch rename to 0040-openssh-7.1p2-audit-race-condition.patch index b5895f7..fe732a6 100644 --- a/openssh-7.1p2-audit-race-condition.patch +++ b/0040-openssh-7.1p2-audit-race-condition.patch @@ -1,7 +1,19 @@ -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 +From c288d4a26ad44dc481c9d18d2920c9d70474833c Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 40/50] 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 1a079c15..768a59f9 100644 +--- a/monitor_wrap.c ++++ b/monitor_wrap.c +@@ -1415,4 +1415,50 @@ mm_audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m); sshbuf_free(m); } @@ -52,10 +64,11 @@ diff -up openssh-7.4p1/monitor_wrap.c.audit-race openssh-7.4p1/monitor_wrap.c + pmonitor->m_recvfd = fd; +} #endif /* SSH_AUDIT_EVENTS */ -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); +diff --git a/monitor_wrap.h b/monitor_wrap.h +index 661ed63b..e957ba6e 100644 +--- a/monitor_wrap.h ++++ b/monitor_wrap.h +@@ -93,6 +93,8 @@ void mm_audit_unsupported_body(struct ssh *, 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); @@ -64,10 +77,11 @@ diff -up openssh-7.4p1/monitor_wrap.h.audit-race openssh-7.4p1/monitor_wrap.h #endif struct Session; -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; +diff --git a/session.c b/session.c +index 83fc9418..b4753d93 100644 +--- a/session.c ++++ b/session.c +@@ -167,6 +167,10 @@ static Session *sessions = NULL; login_cap_t *lc; #endif @@ -78,7 +92,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c static int is_child = 0; static int in_chroot = 0; static int have_dev_log = 1; -@@ -289,6 +293,8 @@ xauth_valid_string(const char *s) +@@ -390,6 +394,8 @@ xauth_valid_string(const char *s) return 1; } @@ -87,7 +101,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c #define USE_PIPES 1 /* * This is called to fork and execute a command when we have no tty. This -@@ -424,6 +430,8 @@ do_exec_no_pty(Session *s, const char *c +@@ -513,6 +519,8 @@ do_exec_no_pty(struct ssh *ssh, Session *s, const char *command) close(err[0]); #endif @@ -96,7 +110,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c /* Do processing for the child (exec command etc). */ do_child(ssh, s, command); /* NOTREACHED */ -@@ -547,6 +555,9 @@ do_exec_pty(Session *s, const char *comm +@@ -630,6 +638,9 @@ do_exec_pty(struct ssh *ssh, Session *s, const char *command) /* Close the extra descriptor for the pseudo tty. */ close(ttyfd); @@ -106,22 +120,22 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c /* record login, etc. similar to login(1) */ #ifndef HAVE_OSF_SIA do_login(ssh, s, command); -@@ -717,6 +728,8 @@ do_exec(Session *s, const char *command) +@@ -766,6 +777,8 @@ do_exec(struct ssh *ssh, Session *s, const char *command) } if (s->command != NULL && s->ptyfd == -1) - s->command_handle = PRIVSEP(audit_run_command(ssh, s->command)); + s->command_handle = mm_audit_run_command(ssh, s->command); + if (pipe(paudit) < 0) + fatal("pipe: %s", strerror(errno)); #endif if (s->ttyfd != -1) ret = do_exec_pty(ssh, s, command); -@@ -732,6 +745,20 @@ do_exec(Session *s, const char *command) +@@ -781,6 +794,20 @@ do_exec(struct ssh *ssh, Session *s, const char *command) */ sshbuf_reset(loginmsg); +#ifdef SSH_AUDIT_EVENTS + close(paudit[1]); -+ if (use_privsep && ret == 0) { ++ if (ret == 0) { + /* + * Read the audit messages from forked child and send them + * back to monitor. We don't want to communicate directly, @@ -136,7 +150,7 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c return ret; } -@@ -1538,6 +1565,34 @@ child_close_fds(void) +@@ -1532,6 +1559,33 @@ child_close_fds(struct ssh *ssh) log_redirect_stderr_to(NULL); } @@ -147,12 +161,11 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c + int pparent = paudit[1]; + close(paudit[0]); + /* Hack the monitor pipe to avoid race condition with parent */ -+ if (use_privsep) -+ mm_set_monitor_pipe(pparent); ++ mm_set_monitor_pipe(pparent); +#endif + + /* remove hostkey from the child's memory */ -+ destroy_sensitive_data(ssh, use_privsep); ++ /* FIXME beldmit 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 @@ -171,12 +184,12 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c /* * Performs common processing for the child, such as setting up the * environment, closing extra file descriptors, setting the user and group -@@ -1554,13 +1608,6 @@ do_child(Session *s, const char *command +@@ -1549,13 +1603,6 @@ do_child(struct ssh *ssh, Session *s, const char *command) sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id)); -- /* remove hostkey from the child's memory */ -- destroy_sensitive_data(ssh, 1); +- /* remove keys from memory */ +- destroy_sensitive_data(ssh); - ssh_packet_clear_keys(ssh); - /* Don't audit this - both us and the parent would be talking to the - monitor over a single socket, with no synchronization. */ @@ -185,3 +198,6 @@ diff -up openssh-7.4p1/session.c.audit-race openssh-7.4p1/session.c /* Force a password change */ if (s->authctxt->force_pwchange) { do_setusercontext(pw); +-- +2.49.0 + diff --git a/0041-openssh-9.0p1-audit-log.patch b/0041-openssh-9.0p1-audit-log.patch new file mode 100644 index 0000000..e04f31b --- /dev/null +++ b/0041-openssh-9.0p1-audit-log.patch @@ -0,0 +1,265 @@ +From 80d967a18261156573e7385f8e534a89d2767d67 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 41/50] 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 a49abb92..c6f56553 100644 +--- a/audit-bsm.c ++++ b/audit-bsm.c +@@ -405,7 +405,7 @@ audit_session_close(struct logininfo *li) + } + + int +-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) + { + /* not implemented */ + } +diff --git a/audit-linux.c b/audit-linux.c +index d484b82b..dcfde3a9 100644 +--- a/audit-linux.c ++++ b/audit-linux.c +@@ -52,7 +52,7 @@ extern u_int utmp_len; + const char *audit_username(void); + + static void +-linux_audit_user_logxxx(int uid, const char *username, ++linux_audit_user_logxxx(int uid, const char *username, const char *hostname, + const char *ip, const char *ttyn, int success, int event) + { + int audit_fd, rc, saved_errno; +@@ -66,7 +66,7 @@ linux_audit_user_logxxx(int uid, const char *username, + } + rc = audit_log_acct_message(audit_fd, event, + NULL, "login", username ? username : "(unknown)", +- username == NULL ? uid : -1, NULL, ip, ttyn, success); ++ username == NULL ? uid : -1, hostname, ip, ttyn, success); + saved_errno = errno; + close(audit_fd); + +@@ -137,10 +137,12 @@ fatal_report: + } + + int +-audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) ++audit_keyusage(struct ssh *ssh, int host_user, const char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) + { + char buf[AUDIT_LOG_SIZE]; + int audit_fd, rc, saved_errno; ++ const char *rip; ++ u_int i; + + audit_fd = audit_open(); + if (audit_fd < 0) { +@@ -150,14 +152,44 @@ audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) + else + return 0; /* Must prevent login */ + } ++ rip = ssh_remote_ipaddr(ssh); + snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased"); + rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, +- buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv); ++ buf, audit_username(), -1, NULL, rip, NULL, rv); + if ((rc < 0) && ((rc != -1) || (getuid() == 0))) + goto out; +- snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp); ++ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", key_fp); + rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, +- ssh_remote_ipaddr(ssh), NULL, rv); ++ rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ ++ if (cert) { ++ char *pbuf; ++ ++ pbuf = audit_encode_nv_string("key_id", cert->key_id, 0); ++ if (pbuf == NULL) ++ goto out; ++ snprintf(buf, sizeof(buf), "cert %s cert_serial=%llu cert_issuer_alg=\"%s\" cert_issuer_fp=\"%s\"", ++ pbuf, (unsigned long long)cert->serial, sshkey_type(cert->signature_key), issuer_fp); ++ free(pbuf); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ ++ for (i = 0; cert->principals != NULL && i < cert->nprincipals; i++) { ++ pbuf = audit_encode_nv_string("cert_principal", cert->principals[i], 0); ++ if (pbuf == NULL) ++ goto out; ++ snprintf(buf, sizeof(buf), "principal %s", pbuf); ++ free(pbuf); ++ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, ++ buf, audit_username(), -1, NULL, rip, NULL, rv); ++ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) ++ goto out; ++ } ++ } + out: + saved_errno = errno; + audit_close(audit_fd); +@@ -179,26 +211,34 @@ audit_connection_from(const char *host, int port) + int + audit_run_command(struct ssh *ssh, const char *command) + { ++ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; + if (!user_login_count++) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_LOGIN); + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_START); ++ free(audit_hostname); + return 0; + } + + void + audit_end_command(struct ssh *ssh, int handle, const char *command) + { ++ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_END); + if (user_login_count && !--user_login_count) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_LOGOUT); ++ free(audit_hostname); + } + + void +@@ -211,31 +251,41 @@ void + audit_session_open(struct logininfo *li) + { + if (!user_login_count++) +- linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ linux_audit_user_logxxx(li->uid, NULL, ++ options.use_dns ? li->hostname : NULL, ++ options.use_dns ? NULL : li->hostname, + li->line, 1, AUDIT_USER_LOGIN); +- linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ linux_audit_user_logxxx(li->uid, NULL, ++ options.use_dns ? li->hostname : NULL, ++ options.use_dns ? NULL : li->hostname, + li->line, 1, AUDIT_USER_START); + } + + void + audit_session_close(struct logininfo *li) + { +- linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ linux_audit_user_logxxx(li->uid, NULL, ++ options.use_dns ? li->hostname : NULL, ++ options.use_dns ? NULL : li->hostname, + li->line, 1, AUDIT_USER_END); + if (user_login_count && !--user_login_count) +- linux_audit_user_logxxx(li->uid, NULL, li->hostname, ++ linux_audit_user_logxxx(li->uid, NULL, ++ options.use_dns ? li->hostname : NULL, ++ options.use_dns ? NULL : li->hostname, + li->line, 1, AUDIT_USER_LOGOUT); + } + + void + audit_event(struct ssh *ssh, ssh_audit_event_t event) + { ++ char * audit_hostname = options.use_dns ? remote_hostname(ssh) : NULL; ++ + switch(event) { + case SSH_NOLOGIN: + case SSH_LOGIN_ROOT_DENIED: + linux_audit_user_auth(-1, audit_username(), + ssh_remote_ipaddr(ssh), "ssh", 0, event); +- linux_audit_user_logxxx(-1, audit_username(), ++ linux_audit_user_logxxx(-1, audit_username(), audit_hostname, + ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); + break; + case SSH_AUTH_FAIL_PASSWD: +@@ -255,9 +305,11 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) + if (user_login_count) { + while (user_login_count--) + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_END); + linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL, ++ audit_hostname, + ssh_remote_ipaddr(ssh), + "ssh", 1, AUDIT_USER_LOGOUT); + } +@@ -266,12 +318,14 @@ audit_event(struct ssh *ssh, ssh_audit_event_t event) + case SSH_CONNECTION_ABANDON: + case SSH_INVALID_USER: + linux_audit_user_logxxx(-1, audit_username(), ++ audit_hostname, + ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN); + break; + default: + debug("%s: unhandled event %d", __func__, event); + break; + } ++ free(audit_hostname); + } + + void +diff --git a/audit.c b/audit.c +index d0433c3a..28d51a14 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 45d66ccf..05ac132c 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.49.0 + diff --git a/openssh-7.7p1-fips.patch b/0042-openssh-7.7p1-fips.patch similarity index 60% rename from openssh-7.7p1-fips.patch rename to 0042-openssh-7.7p1-fips.patch index 5351571..9a81cc0 100644 --- a/openssh-7.7p1-fips.patch +++ b/0042-openssh-7.7p1-fips.patch @@ -1,6 +1,34 @@ -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 +From 79f9b2763d85ec592cb7e54dcf1c695d8dd138b1 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 28 Aug 2025 14:01:38 +0200 +Subject: [PATCH 42/54] 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 | 16 ++++++--- + ssh-ed25519.c | 9 +++++ + ssh-gss.h | 5 +++ + ssh-keygen.c | 22 ++++++++++-- + ssh-rsa.c | 3 ++ + ssh.c | 5 +++ + sshconnect2.c | 9 ++++- + sshd-session.c | 1 + + sshd.c | 13 +++++++ + sshkey.c | 37 ++++++++++++++++++++ + 19 files changed, 272 insertions(+), 30 deletions(-) + +diff --git a/dh.c b/dh.c +index 168dea1dd..8c9a29fa7 100644 +--- a/dh.c ++++ b/dh.c @@ -36,6 +36,7 @@ #include @@ -9,7 +37,7 @@ diff -up openssh-8.6p1/dh.c.fips openssh-8.6p1/dh.c #include "dh.h" #include "pathnames.h" -@@ -164,6 +164,12 @@ choose_dh(int min, int wantbits, int max +@@ -164,6 +165,12 @@ choose_dh(int min, int wantbits, int max) int best, bestcount, which, linenum; struct dhgroup dhg; @@ -22,7 +50,7 @@ diff -up openssh-8.6p1/dh.c.fips openssh-8.6p1/dh.c 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 +508,38 @@ dh_estimate(int bits) +@@ -502,4 +509,38 @@ dh_estimate(int bits) return 8192; } @@ -61,9 +89,10 @@ diff -up openssh-8.6p1/dh.c.fips openssh-8.6p1/dh.c +} + #endif /* WITH_OPENSSL */ -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 +diff --git a/dh.h b/dh.h +index c6326a39d..e51e292b8 100644 +--- a/dh.h ++++ b/dh.h @@ -45,6 +45,7 @@ DH *dh_new_group_fallback(int); int dh_gen_key(DH *, int); @@ -72,18 +101,19 @@ diff -up openssh-8.6p1/dh.h.fips openssh-8.6p1/dh.h u_int dh_estimate(int); void dh_set_moduli_file(const char *); -diff -up openssh-8.6p1/kex.c.fips openssh-8.6p1/kex.c ---- openssh-8.6p1/kex.c.fips 2021-05-06 12:08:36.489926807 +0200 -+++ openssh-8.6p1/kex.c 2021-05-06 12:08:36.498926877 +0200 -@@ -39,6 +39,7 @@ +diff --git a/kex-names.c b/kex-names.c +index 6c0b7c2b3..cd3902ad2 100644 +--- a/kex-names.c ++++ b/kex-names.c +@@ -33,6 +33,7 @@ #ifdef WITH_OPENSSL #include +#include - #include - # ifdef HAVE_EVP_KDF_CTX_NEW_ID - # include -@@ -203,7 +203,10 @@ kex_names_valid(const char *names) + #include + #endif + +@@ -206,7 +207,10 @@ kex_names_valid(const char *names) for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { if (kex_alg_by_name(p) == NULL) { @@ -95,9 +125,149 @@ diff -up openssh-8.6p1/kex.c.fips openssh-8.6p1/kex.c free(s); return 0; } -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 +diff --git a/kex.c b/kex.c +index 62f607d6f..71fbe5cbe 100644 +--- a/kex.c ++++ b/kex.c +@@ -40,6 +40,7 @@ + #ifdef WITH_OPENSSL + #include + #include ++#include + # ifdef HAVE_EVP_KDF_CTX_NEW + # include + # include +@@ -109,7 +110,7 @@ kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX], + + /* Append EXT_INFO signalling to KexAlgorithms */ + if (kexalgos == NULL) +- kexalgos = defprop[PROPOSAL_KEX_ALGS]; ++ kexalgos = FIPS_mode() ? KEX_DEFAULT_KEX_FIPS : defprop[PROPOSAL_KEX_ALGS]; + if ((cp = kex_names_cat(kexalgos, ssh->kex->server ? + "ext-info-s,kex-strict-s-v00@openssh.com" : + "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL) +diff --git a/kexgen.c b/kexgen.c +index 15df591ca..eecdceba2 100644 +--- a/kexgen.c ++++ b/kexgen.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #include "sshkey.h" + #include "kex.h" +@@ -115,13 +116,28 @@ kex_gen_client(struct ssh *ssh) + break; + #endif + case KEX_C25519_SHA256: +- r = kex_c25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_keypair(kex); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_keypair(kex); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_keypair(kex); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_keypair(kex); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +@@ -189,15 +205,30 @@ input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh) + break; + #endif + case KEX_C25519_SHA256: +- r = kex_c25519_dec(kex, server_blob, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_dec(kex, server_blob, &shared_secret); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_dec(kex, server_blob, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_dec(kex, server_blob, ++ &shared_secret); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_dec(kex, server_blob, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_dec(kex, server_blob, ++ &shared_secret); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +@@ -312,16 +343,31 @@ input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh) + break; + #endif + case KEX_C25519_SHA256: +- r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, +- &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, ++ &shared_secret); ++ } + break; + case KEX_KEM_SNTRUP761X25519_SHA512: +- r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, +- &server_pubkey, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); ++ } + break; + case KEX_KEM_MLKEM768X25519_SHA256: +- r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, +- &server_pubkey, &shared_secret); ++ if (FIPS_mode()) { ++ logit_f("Key exchange type mlkem768x25519 is not allowed in FIPS mode"); ++ r = SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ r = kex_kem_mlkem768x25519_enc(kex, client_pubkey, ++ &server_pubkey, &shared_secret); ++ } + break; + default: + r = SSH_ERR_INVALID_ARGUMENT; +diff --git a/kexgexc.c b/kexgexc.c +index e99e0cf21..4c3feae09 100644 +--- a/kexgexc.c ++++ b/kexgexc.c @@ -28,6 +28,7 @@ #ifdef WITH_OPENSSL @@ -106,7 +276,7 @@ diff -up openssh-8.6p1/kexgexc.c.fips openssh-8.6p1/kexgexc.c #include #include -@@ -115,6 +116,10 @@ input_kex_dh_gex_group(int type, u_int32 +@@ -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; } @@ -117,10 +287,11 @@ diff -up openssh-8.6p1/kexgexc.c.fips openssh-8.6p1/kexgexc.c 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 @@ +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" @@ -138,8 +309,8 @@ diff -up openssh-8.6p1/myproposal.h.fips openssh-8.6p1/myproposal.h + #define KEX_SERVER_ENCRYPT \ "chacha20-poly1305@openssh.com," \ - "aes128-ctr,aes192-ctr,aes256-ctr," \ -@@ -78,6 +92,27 @@ + "aes128-gcm@openssh.com,aes256-gcm@openssh.com," \ +@@ -79,6 +91,27 @@ #define KEX_CLIENT_MAC KEX_SERVER_MAC @@ -167,10 +338,11 @@ diff -up openssh-8.6p1/myproposal.h.fips openssh-8.6p1/myproposal.h /* 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 @@ +diff --git a/readconf.c b/readconf.c +index f340bf501..ea9d293c3 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -43,6 +43,7 @@ #include #include #include @@ -178,7 +350,7 @@ diff -up openssh-8.6p1/readconf.c.fips openssh-8.6p1/readconf.c #ifdef USE_SYSTEM_GLOB # include #else -@@ -2538,11 +2538,16 @@ fill_default_options(Options * options) +@@ -3043,11 +3044,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 */ @@ -200,10 +372,11 @@ diff -up openssh-8.6p1/readconf.c.fips openssh-8.6p1/readconf.c #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_ +diff --git a/sandbox-seccomp-filter.c b/sandbox-seccomp-filter.c +index 1fabf99d0..ccb61586e 100644 +--- a/sandbox-seccomp-filter.c ++++ b/sandbox-seccomp-filter.c +@@ -230,6 +230,9 @@ static const struct sock_filter preauth_insns[] = { #ifdef __NR_open SC_DENY(__NR_open, EACCES), #endif @@ -213,10 +386,11 @@ diff -up openssh-8.6p1/sandbox-seccomp-filter.c.fips openssh-8.6p1/sandbox-secco #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 @@ +diff --git a/servconf.c b/servconf.c +index 84891544b..8b708cbf4 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -37,6 +37,7 @@ #include #include #include @@ -224,7 +398,7 @@ diff -up openssh-8.6p1/servconf.c.fips openssh-8.6p1/servconf.c #ifdef HAVE_UTIL_H #include #endif -@@ -226,11 +226,16 @@ assemble_algorithms(ServerOptions *o) +@@ -247,11 +248,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 */ @@ -246,10 +420,152 @@ diff -up openssh-8.6p1/servconf.c.fips openssh-8.6p1/servconf.c #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 @@ +diff --git a/ssh-ed25519.c b/ssh-ed25519.c +index 22d8db026..41942f4e5 100644 +--- a/ssh-ed25519.c ++++ b/ssh-ed25519.c +@@ -24,6 +24,7 @@ + + #include + #include ++#include + + #include "log.h" + #include "sshbuf.h" +@@ -164,6 +165,10 @@ ssh_ed25519_sign(struct sshkey *key, + key->ed25519_sk == NULL || + datalen >= INT_MAX - crypto_sign_ed25519_BYTES) + return SSH_ERR_INVALID_ARGUMENT; ++ if (FIPS_mode()) { ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } + smlen = slen = datalen + crypto_sign_ed25519_BYTES; + if ((sig = malloc(slen)) == NULL) + return SSH_ERR_ALLOC_FAIL; +@@ -221,6 +226,10 @@ ssh_ed25519_verify(const struct sshkey *key, + dlen >= INT_MAX - crypto_sign_ed25519_BYTES || + sig == NULL || siglen == 0) + return SSH_ERR_INVALID_ARGUMENT; ++ if (FIPS_mode()) { ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } + + if ((b = sshbuf_from(sig, siglen)) == NULL) + return SSH_ERR_ALLOC_FAIL; +diff --git a/ssh-gss.h b/ssh-gss.h +index a894e23c9..329dc9da0 100644 +--- a/ssh-gss.h ++++ b/ssh-gss.h +@@ -88,6 +88,11 @@ extern char **k5users_allowed_cmds; + KEX_GSS_GRP14_SHA1_ID "," \ + KEX_GSS_GEX_SHA1_ID + ++#define GSS_KEX_DEFAULT_KEX_FIPS \ ++ KEX_GSS_GRP14_SHA256_ID "," \ ++ KEX_GSS_GRP16_SHA512_ID "," \ ++ KEX_GSS_NISTP256_SHA256_ID ++ + #include "digest.h" /* SSH_DIGEST_MAX_LENGTH */ + + typedef struct { +diff --git a/ssh-keygen.c b/ssh-keygen.c +index 16cff9473..792aafde0 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -20,6 +20,7 @@ + + #ifdef WITH_OPENSSL + #include ++#include + #include + #include "openbsd-compat/openssl-compat.h" + #endif +@@ -68,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 +@@ -202,6 +204,12 @@ type_bits_valid(int type, const char *name, u_int32_t *bitsp) + #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) +@@ -259,7 +267,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 WITH_DSA +@@ -1144,9 +1152,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)); +@@ -3849,7 +3865,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 3ad1fddc4..6c2f771a3 100644 +--- a/ssh-rsa.c ++++ b/ssh-rsa.c +@@ -23,6 +23,7 @@ + + #include + #include ++#include + + #include + #include +@@ -142,6 +143,8 @@ ssh_rsa_generate(struct sshkey *k, int bits) + goto out; + } + if (EVP_PKEY_keygen(ctx, &res) <= 0 || res == NULL) { ++ if (FIPS_mode()) ++ logit_f("the key length might be unsupported by FIPS mode approved key generation method"); + ret = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +diff --git a/ssh.c b/ssh.c +index 98b103c9e..abc8b8439 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -78,6 +78,7 @@ #include #include #endif @@ -257,7 +573,7 @@ diff -up openssh-8.6p1/ssh.c.fips openssh-8.6p1/ssh.c #include "openbsd-compat/openssl-compat.h" #include "openbsd-compat/sys-queue.h" -@@ -1516,6 +1517,10 @@ main(int ac, char **av) +@@ -1642,6 +1643,10 @@ main(int ac, char **av) exit(0); } @@ -268,9 +584,10 @@ diff -up openssh-8.6p1/ssh.c.fips openssh-8.6p1/ssh.c /* Expand SecurityKeyProvider if it refers to an environment variable */ if (options.sk_provider != NULL && *options.sk_provider == '$' && strlen(options.sk_provider) > 1) { -diff -up openssh-8.6p1/sshconnect2.c.fips openssh-8.6p1/sshconnect2.c ---- openssh-8.6p1/sshconnect2.c.fips 2021-05-06 12:08:36.485926777 +0200 -+++ openssh-8.6p1/sshconnect2.c 2021-05-06 12:08:36.501926900 +0200 +diff --git a/sshconnect2.c b/sshconnect2.c +index 0af15bcc1..3e02f485d 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c @@ -45,6 +45,8 @@ #include #endif @@ -280,95 +597,60 @@ diff -up openssh-8.6p1/sshconnect2.c.fips openssh-8.6p1/sshconnect2.c #include "openbsd-compat/sys-queue.h" #include "xmalloc.h" -@@ -269,36 +271,41 @@ ssh_kex2(struct ssh *ssh, char *host, st +@@ -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) { -- /* Add the GSSAPI mechanisms currently supported on this -- * client to the key exchange algorithm proposal */ -- orig = myproposal[PROPOSAL_KEX_ALGS]; -- -- if (options.gss_server_identity) { -- gss_host = xstrdup(options.gss_server_identity); -- } else if (options.gss_trust_dns) { -- gss_host = remote_hostname(ssh); -- /* Fall back to specified host if we are using proxy command -- * and can not use DNS on that socket */ -- if (strcmp(gss_host, "UNKNOWN") == 0) { -- free(gss_host); -+ if (FIPS_mode()) { -+ logit("Disabling GSSAPIKeyExchange. Not usable in FIPS mode"); -+ options.gss_keyex = 0; -+ } else { -+ /* Add the GSSAPI mechanisms currently supported on this -+ * client to the key exchange algorithm proposal */ -+ orig = myproposal[PROPOSAL_KEX_ALGS]; ++ char * gss_kex_filtered = FIPS_mode() ? ++ match_filter_allowlist(options.gss_kex_algorithms, GSS_KEX_DEFAULT_KEX_FIPS) : xstrdup(options.gss_kex_algorithms); + -+ if (options.gss_server_identity) { -+ gss_host = xstrdup(options.gss_server_identity); -+ } else if (options.gss_trust_dns) { -+ gss_host = remote_hostname(ssh); -+ /* Fall back to specified host if we are using proxy command -+ * and can not use DNS on that socket */ -+ if (strcmp(gss_host, "UNKNOWN") == 0) { -+ free(gss_host); -+ gss_host = xstrdup(host); -+ } -+ } else { - gss_host = xstrdup(host); - } -- } else { -- gss_host = xstrdup(host); -- } - -- gss = ssh_gssapi_client_mechanisms(gss_host, -- options.gss_client_identity, options.gss_kex_algorithms); -- if (gss) { -- debug("Offering GSSAPI proposal: %s", gss); -- xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -- "%s,%s", gss, orig); -- -- /* If we've got GSSAPI algorithms, then we also support the -- * 'null' hostkey, as a last resort */ -- orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; -- xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], -- "%s,null", orig); -+ gss = ssh_gssapi_client_mechanisms(gss_host, -+ options.gss_client_identity, options.gss_kex_algorithms); -+ if (gss) { -+ debug("Offering GSSAPI proposal: %s", gss); -+ xasprintf(&myproposal[PROPOSAL_KEX_ALGS], -+ "%s,%s", gss, orig); -+ -+ /* If we've got GSSAPI algorithms, then we also support the -+ * 'null' hostkey, as a last resort */ -+ orig = myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]; -+ xasprintf(&myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS], -+ "%s,null", orig); -+ } + /* Add the GSSAPI mechanisms currently supported on this + * client to the key exchange algorithm proposal */ + orig = myproposal[PROPOSAL_KEX_ALGS]; +@@ -281,7 +286,9 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, } - } - #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 @@ - #include + + 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-session.c b/sshd-session.c +index a808ac9a6..a67a78391 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -62,6 +62,7 @@ #include + #include #include +#include #include "openbsd-compat/openssl-compat.h" #endif -@@ -1931,6 +1931,13 @@ main(int ac, char **av) +diff --git a/sshd.c b/sshd.c +index 8a99f0b29..5ff0b5ff0 100644 +--- a/sshd.c ++++ b/sshd.c +@@ -52,6 +52,7 @@ + #endif + #include + #include ++#include + #include + #include + #include +@@ -63,6 +64,7 @@ + #ifdef WITH_OPENSSL + #include + #include ++#include + #include "openbsd-compat/openssl-compat.h" + #endif + +@@ -1611,6 +1613,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]); @@ -382,7 +664,7 @@ diff -up openssh-8.6p1/sshd.c.fips openssh-8.6p1/sshd.c 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) +@@ -1830,6 +1839,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); @@ -393,37 +675,19 @@ diff -up openssh-8.6p1/sshd.c.fips openssh-8.6p1/sshd.c /* * Chdir to the root directory so that the current disk can be * unmounted if desired. -@@ -2494,10 +2501,14 @@ do_ssh2_kex(struct ssh *ssh) - 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 @@ +diff --git a/sshkey.c b/sshkey.c +index 4e41a78c7..ca1cdb642 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -35,6 +35,7 @@ + #include + #include #include - #include - #include +#include #endif #include "crypto_api.h" -@@ -57,6 +58,7 @@ +@@ -59,6 +60,7 @@ #define SSHKEY_INTERNAL #include "sshkey.h" #include "match.h" @@ -431,7 +695,7 @@ diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c #include "ssh-sk.h" #ifdef WITH_XMSS -@@ -285,6 +285,18 @@ sshkey_alg_list(int certs_only, int plai +@@ -408,6 +410,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; @@ -450,7 +714,7 @@ diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c 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 +@@ -1441,6 +1455,20 @@ sshkey_read(struct sshkey *ret, char **cpp) return SSH_ERR_EC_CURVE_MISMATCH; } @@ -471,208 +735,29 @@ diff -up openssh-8.6p1/sshkey.c.fips openssh-8.6p1/sshkey.c /* Fill in ret from parsed key */ sshkey_free_contents(ret); *ret = *k; -@@ -2916,6 +2916,11 @@ sshkey_sign(struct sshkey *key, +@@ -2275,6 +2303,11 @@ sshkey_sign(struct sshkey *key, *lenp = 0; if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) return SSH_ERR_INVALID_ARGUMENT; -+ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) { -+ logit_f("Ed25519 keys are not allowed in FIPS mode"); -+ return SSH_ERR_INVALID_ARGUMENT; -+ } -+ /* Fallthrough */ ++ if (FIPS_mode() && ((key->type == KEY_ED25519_SK) || (key->type == KEY_ED25519_SK_CERT))) { ++ logit_f("Ed25519 keys are not allowed in FIPS mode"); ++ return SSH_ERR_INVALID_ARGUMENT; ++ } ++ /* Fallthrough */ if ((impl = sshkey_impl_from_key(key)) == NULL) return SSH_ERR_KEY_TYPE_UNKNOWN; if ((r = sshkey_unshield_private(key)) != 0) -@@ -2973,6 +2978,10 @@ sshkey_verify(const struct sshkey *key, +@@ -2311,6 +2344,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 -@@ -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"); ++ 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; + } - switch (type) { - case KEY_DSA: - if (*bitsp != 1024) -@@ -1098,9 +1104,17 @@ do_gen_all_hostkeys(struct passwd *pw) - first = 1; - printf("%s: generating new host keys: ", __progname); - } -+ type = sshkey_type_from_name(key_types[i].key_type); -+ -+ /* Skip the keys that are not supported in FIPS mode */ -+ if (FIPS_mode() && (type == KEY_DSA || type == KEY_ED25519)) { -+ logit("Skipping %s key in FIPS mode", -+ key_types[i].key_type_display); -+ goto next; -+ } -+ - printf("%s ", key_types[i].key_type_display); - fflush(stdout); -- type = sshkey_type_from_name(key_types[i].key_type); - if ((fd = mkstemp(prv_tmp)) == -1) { - error("Could not save your private key in %s: %s", - prv_tmp, strerror(errno)); -diff -up openssh-9.3p1/ssh-rsa.c.evpgenrsa openssh-9.3p1/ssh-rsa.c ---- openssh-9.3p1/ssh-rsa.c.evpgenrsa 2022-06-30 15:14:58.200518353 +0200 -+++ openssh-9.3p1/ssh-rsa.c 2022-06-30 15:24:31.499641196 +0200 -@@ -33,6 +33,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -1705,6 +1707,8 @@ ssh_rsa_generate(u_int bits, RSA - goto out; + if ((impl = sshkey_impl_from_key(key)) == NULL) + return SSH_ERR_KEY_TYPE_UNKNOWN; + return impl->funcs->verify(key, sig, siglen, data, dlen, +-- +2.51.0 - if (EVP_PKEY_keygen(ctx, &res) <= 0) { -+ if (FIPS_mode()) -+ logit_f("the key length might be unsupported by FIPS mode approved key generation method"); - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -diff -up openssh-8.7p1/kexgen.c.fips3 openssh-8.7p1/kexgen.c ---- openssh-8.7p1/kexgen.c.fips3 2022-07-11 16:11:21.973519913 +0200 -+++ openssh-8.7p1/kexgen.c 2022-07-11 16:25:31.172187365 +0200 -@@ -31,6 +31,7 @@ - #include - #include - #include -+#include - - #include "sshkey.h" - #include "kex.h" -@@ -115,10 +116,20 @@ kex_gen_client(struct ssh *ssh) - break; - #endif - case KEX_C25519_SHA256: -- r = kex_c25519_keypair(kex); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_c25519_keypair(kex); -+ } - break; - case KEX_KEM_SNTRUP761X25519_SHA512: -- r = kex_kem_sntrup761x25519_keypair(kex); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_kem_sntrup761x25519_keypair(kex); -+ } - break; - default: - r = SSH_ERR_INVALID_ARGUMENT; -@@ -186,11 +197,21 @@ input_kex_gen_reply(int type, u_int32_t - break; - #endif - case KEX_C25519_SHA256: -- r = kex_c25519_dec(kex, server_blob, &shared_secret); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_c25519_dec(kex, server_blob, &shared_secret); -+ } - break; - case KEX_KEM_SNTRUP761X25519_SHA512: -- r = kex_kem_sntrup761x25519_dec(kex, server_blob, -- &shared_secret); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_kem_sntrup761x25519_dec(kex, server_blob, -+ &shared_secret); -+ } - break; - default: - r = SSH_ERR_INVALID_ARGUMENT; -@@ -285,12 +306,22 @@ input_kex_gen_init(int type, u_int32_t s - break; - #endif - case KEX_C25519_SHA256: -- r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, -- &shared_secret); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type c25519 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_c25519_enc(kex, client_pubkey, &server_pubkey, -+ &shared_secret); -+ } - break; - case KEX_KEM_SNTRUP761X25519_SHA512: -- r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, -- &server_pubkey, &shared_secret); -+ if (FIPS_mode()) { -+ logit_f("Key exchange type sntrup761 is not allowed in FIPS mode"); -+ r = SSH_ERR_INVALID_ARGUMENT; -+ } else { -+ r = kex_kem_sntrup761x25519_enc(kex, client_pubkey, -+ &server_pubkey, &shared_secret); -+ } - break; - default: - r = SSH_ERR_INVALID_ARGUMENT; -diff -up openssh-8.7p1/ssh-ed25519.c.fips3 openssh-8.7p1/ssh-ed25519.c ---- openssh-8.7p1/ssh-ed25519.c.fips3 2022-07-11 16:53:41.428343304 +0200 -+++ openssh-8.7p1/ssh-ed25519.c 2022-07-11 16:56:09.284663661 +0200 -@@ -24,6 +24,7 @@ - - #include - #include -+#include - - #include "log.h" - #include "sshbuf.h" -@@ -52,6 +53,10 @@ ssh_ed25519_sign(const struct sshkey *ke - key->ed25519_sk == NULL || - datalen >= INT_MAX - crypto_sign_ed25519_BYTES) - return SSH_ERR_INVALID_ARGUMENT; -+ if (FIPS_mode()) { -+ logit_f("Ed25519 keys are not allowed in FIPS mode"); -+ return SSH_ERR_INVALID_ARGUMENT; -+ } - smlen = slen = datalen + crypto_sign_ed25519_BYTES; - if ((sig = malloc(slen)) == NULL) - return SSH_ERR_ALLOC_FAIL; -@@ -108,6 +113,10 @@ ssh_ed25519_verify(const struct sshkey * - dlen >= INT_MAX - crypto_sign_ed25519_BYTES || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; -+ if (FIPS_mode()) { -+ logit_f("Ed25519 keys are not allowed in FIPS mode"); -+ return SSH_ERR_INVALID_ARGUMENT; -+ } - - if ((b = sshbuf_from(sig, siglen)) == NULL) - return SSH_ERR_ALLOC_FAIL; diff --git a/0043-openssh-8.7p1-ssh-manpage.patch b/0043-openssh-8.7p1-ssh-manpage.patch new file mode 100644 index 0000000..89c6ea1 --- /dev/null +++ b/0043-openssh-8.7p1-ssh-manpage.patch @@ -0,0 +1,47 @@ +From 299a602802d7c7d121306eb2aeae1502871a35cb Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 43/50] openssh-8.7p1-ssh-manpage + +--- + ssh.1 | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/ssh.1 b/ssh.1 +index 6a9fbdc5..755cdef2 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.49.0 + diff --git a/openssh-8.7p1-negotiate-supported-algs.patch b/0044-openssh-8.7p1-negotiate-supported-algs.patch similarity index 69% rename from openssh-8.7p1-negotiate-supported-algs.patch rename to 0044-openssh-8.7p1-negotiate-supported-algs.patch index ee3637f..f4c3b8a 100644 --- a/openssh-8.7p1-negotiate-supported-algs.patch +++ b/0044-openssh-8.7p1-negotiate-supported-algs.patch @@ -1,6 +1,17 @@ -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 +From 5c92430c08ac392b5b2ace899cc043247c923734 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 44/50] 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 28dcfe17..b9e716dc 100644 +--- a/regress/hostkey-agent.sh ++++ b/regress/hostkey-agent.sh @@ -17,8 +17,21 @@ trace "make CA key" ${SSHKEYGEN} -qt ed25519 -f $OBJ/agent-ca -N '' || fatal "ssh-keygen CA" @@ -24,7 +35,7 @@ diff -up openssh-9.3p1/regress/hostkey-agent.sh.xxx openssh-9.3p1/regress/hostke ${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 +48,16 @@ rm $OBJ/agent-ca # Don't need CA private +@@ -32,12 +45,16 @@ rm $OBJ/agent-ca # Don't need CA private any more either unset SSH_AUTH_SOCK @@ -44,10 +55,10 @@ diff -up openssh-9.3p1/regress/hostkey-agent.sh.xxx openssh-9.3p1/regress/hostke ( printf 'localhost-with-alias,127.0.0.1,::1 ' ; cat $OBJ/agent-key.$k.pub) > $OBJ/known_hosts SSH_CONNECTION=`${SSH} $opts host 'echo $SSH_CONNECTION'` -@@ -50,15 +70,16 @@ for k in $SSH_KEYTYPES ; do +@@ -50,15 +67,16 @@ for k in $SSH_KEYTYPES ; do done - SSH_CERTTYPES=`ssh -Q key-sig | grep 'cert-v01@openssh.com'` + SSH_CERTTYPES=`ssh -Q key-sig | grep 'cert-v01@openssh.com' | maybe_filter_sk` +SSH_ACCEPTED_CERTTYPES=`echo "$SSH_CERTTYPES" | egrep "$PUBKEY_ACCEPTED_ALGOS"` # Prepare sshd_proxy for certificates. @@ -63,7 +74,7 @@ diff -up openssh-9.3p1/regress/hostkey-agent.sh.xxx openssh-9.3p1/regress/hostke echo "Hostkey $OBJ/agent-key.${k}.pub" >> $OBJ/sshd_proxy echo "HostCertificate $OBJ/agent-key.${k}-cert.pub" >> $OBJ/sshd_proxy test -f $OBJ/agent-key.${k}.pub || fatal "no $k key" -@@ -70,7 +93,7 @@ echo "HostKeyAlgorithms $HOSTKEYALGS" >> +@@ -70,7 +88,7 @@ echo "HostKeyAlgorithms $HOSTKEYALGS" >> $OBJ/sshd_proxy ( printf '@cert-authority localhost-with-alias ' ; cat $OBJ/agent-ca.pub) > $OBJ/known_hosts @@ -72,19 +83,20 @@ diff -up openssh-9.3p1/regress/hostkey-agent.sh.xxx openssh-9.3p1/regress/hostke verbose "cert type $k" opts="-oHostKeyAlgorithms=$k -F $OBJ/ssh_proxy" SSH_CONNECTION=`${SSH} $opts host 'echo $SSH_CONNECTION'` -diff -up openssh-9.3p1/sshconnect2.c.xxx openssh-9.3p1/sshconnect2.c ---- openssh-9.3p1/sshconnect2.c.xxx 2023-04-26 17:37:35.100827792 +0200 -+++ openssh-9.3p1/sshconnect2.c 2023-04-26 17:50:31.860748877 +0200 -@@ -221,7 +221,7 @@ ssh_kex2(struct ssh *ssh, char *host, st +diff --git a/sshconnect2.c b/sshconnect2.c +index 14f7671a..ad3f560f 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -221,7 +221,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, const struct ssh_conn_info *cinfo) { char *myproposal[PROPOSAL_MAX]; -- char *s, *all_key, *hkalgs = NULL; -+ char *s, *all_key, *hkalgs = NULL, *filtered_algs = NULL; +- char *all_key, *hkalgs = NULL; ++ char *all_key, *hkalgs = NULL, *filtered_algs = NULL; int r, use_known_hosts_order = 0; #if defined(GSSAPI) && defined(WITH_OPENSSL) -@@ -260,9 +260,21 @@ ssh_kex2(struct ssh *ssh, char *host, st +@@ -257,10 +257,22 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, if (use_known_hosts_order) hkalgs = order_hostkeyalgs(host, hostaddr, port, cinfo); @@ -100,14 +112,15 @@ diff -up openssh-9.3p1/sshconnect2.c.xxx openssh-9.3p1/sshconnect2.c + options.hostkeyalgorithms, options.pubkey_accepted_algos); + } + - kex_proposal_populate_entries(ssh, myproposal, s, options.ciphers, - options.macs, compression_alg_list(options.compression), + kex_proposal_populate_entries(ssh, myproposal, + options.kex_algorithms, options.ciphers, options.macs, + compression_alg_list(options.compression), - hkalgs ? hkalgs : options.hostkeyalgorithms); + filtered_algs); #if defined(GSSAPI) && defined(WITH_OPENSSL) if (options.gss_keyex) { -@@ -303,6 +315,7 @@ ssh_kex2(struct ssh *ssh, char *host, st +@@ -304,6 +316,7 @@ ssh_kex2(struct ssh *ssh, char *host, struct sockaddr *hostaddr, u_short port, #endif free(hkalgs); @@ -115,3 +128,6 @@ diff -up openssh-9.3p1/sshconnect2.c.xxx openssh-9.3p1/sshconnect2.c /* start key exchange */ if ((r = kex_setup(ssh, myproposal)) != 0) +-- +2.49.0 + diff --git a/0045-openssh-9.0p1-evp-fips-kex.patch b/0045-openssh-9.0p1-evp-fips-kex.patch new file mode 100644 index 0000000..610cea0 --- /dev/null +++ b/0045-openssh-9.0p1-evp-fips-kex.patch @@ -0,0 +1,616 @@ +From be23afbab800c9b5ffea56b3f410a04156c08df2 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 45/50] 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 8c9a29fa..ea0a0b09 100644 +--- a/dh.c ++++ b/dh.c +@@ -37,6 +37,9 @@ + #include + #include + #include ++#include ++#include ++#include + + #include "dh.h" + #include "pathnames.h" +@@ -290,10 +293,15 @@ dh_pub_is_valid(const DH *dh, const BIGNUM *dh_pub) + int + dh_gen_key(DH *dh, int need) + { +- int pbits; +- const BIGNUM *dh_p, *pub_key; ++ const BIGNUM *dh_p, *dh_g; ++ BIGNUM *pub_key = NULL, *priv_key = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ int pbits, r = 0; + +- DH_get0_pqg(dh, &dh_p, NULL, NULL); ++ DH_get0_pqg(dh, &dh_p, NULL, &dh_g); + + if (need < 0 || dh_p == NULL || + (pbits = BN_num_bits(dh_p)) <= 0 || +@@ -301,19 +309,85 @@ dh_gen_key(DH *dh, int need) + return SSH_ERR_INVALID_ARGUMENT; + if (need < 256) + need = 256; ++ ++ if ((param_bld = OSSL_PARAM_BLD_new()) == NULL || ++ (ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) { ++ OSSL_PARAM_BLD_free(param_bld); ++ return SSH_ERR_ALLOC_FAIL; ++ } ++ ++ if (OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) { ++ error_f("Could not set p,q,g parameters"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } + /* + * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), + * so double requested need here. + */ +- if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1))) +- return SSH_ERR_LIBCRYPTO_ERROR; +- +- if (DH_generate_key(dh) == 0) +- return SSH_ERR_LIBCRYPTO_ERROR; +- DH_get0_key(dh, &pub_key, NULL); +- if (!dh_pub_is_valid(dh, pub_key)) +- return SSH_ERR_INVALID_FORMAT; +- return 0; ++ if (OSSL_PARAM_BLD_push_int(param_bld, ++ OSSL_PKEY_PARAM_DH_PRIV_LEN, ++ MINIMUM(need * 2, pbits - 1)) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata(ctx, &pkey, ++ EVP_PKEY_KEY_PARAMETERS, params) != 1) { ++ error_f("Failed key generation"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ /* reuse context for key generation */ ++ EVP_PKEY_CTX_free(ctx); ++ ctx = NULL; ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ EVP_PKEY_keygen_init(ctx) != 1) { ++ error_f("Could not create or init context"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_generate(ctx, &pkey) != 1) { ++ error_f("Could not generate keys"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_public_check(ctx) != 1) { ++ error_f("The public key is incorrect"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, ++ &pub_key) != 1 || ++ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, ++ &priv_key) != 1 || ++ DH_set0_key(dh, pub_key, priv_key) != 1) { ++ error_f("Could not set pub/priv keys to DH struct"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++ /* transferred */ ++ pub_key = NULL; ++ priv_key = NULL; ++out: ++ OSSL_PARAM_free(params); ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(pkey); ++ BN_clear_free(pub_key); ++ BN_clear_free(priv_key); ++ return r; + } + + DH * +diff --git a/kex.c b/kex.c +index 71fbe5cb..ce6a7b81 100644 +--- a/kex.c ++++ b/kex.c +@@ -1614,3 +1614,142 @@ kex_exchange_identification(struct ssh *ssh, int timeout_ms, + return r; + } + ++#ifdef WITH_OPENSSL ++/* ++ * Creates an EVP_PKEY from the given parameters and keys. ++ * The private key can be omitted. ++ */ ++EVP_PKEY * ++sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) ++{ ++ EVP_PKEY *ret = NULL; ++ OSSL_PARAM *params = NULL; ++ if (param_bld == NULL || ctx == NULL) { ++ debug2_f("param_bld or ctx is NULL"); ++ return NULL; ++ } ++ if ((params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ debug2_f("Could not build param list"); ++ return NULL; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1 || ++ EVP_PKEY_fromdata(ctx, &ret, EVP_PKEY_KEYPAIR, params) != 1) { ++ debug2_f("EVP_PKEY_fromdata failed"); ++ OSSL_PARAM_free(params); ++ return NULL; ++ } ++ return ret; ++} ++ ++int ++kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) ++{ ++ OSSL_PARAM_BLD *param_bld = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ BN_CTX *bn_ctx = NULL; ++ uint8_t *pub_ser = NULL; ++ const char *group_name; ++ const EC_POINT *pub = NULL; ++ const BIGNUM *priv = NULL; ++ int ret = 0; ++ ++ if (k == NULL) ++ return SSH_ERR_INVALID_ARGUMENT; ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL || ++ (bn_ctx = BN_CTX_new()) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ ++ if ((group_name = OSSL_EC_curve_nid2name(ecdsa_nid)) == NULL || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, ++ group_name, ++ strlen(group_name)) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((pub = EC_KEY_get0_public_key(k)) != NULL) { ++ const EC_GROUP *group; ++ size_t len; ++ ++ group = EC_KEY_get0_group(k); ++ len = EC_POINT_point2oct(group, pub, ++ POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); ++ if ((pub_ser = malloc(len)) == NULL) { ++ ret = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ EC_POINT_point2oct(group, ++ pub, ++ POINT_CONVERSION_UNCOMPRESSED, ++ pub_ser, ++ len, ++ bn_ctx); ++ if (OSSL_PARAM_BLD_push_octet_string(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, ++ pub_ser, ++ len) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ } ++ if ((priv = EC_KEY_get0_private_key(k)) != NULL && ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ ++out: ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ BN_CTX_free(bn_ctx); ++ free(pub_ser); ++ return ret; ++} ++ ++int ++kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, ++ const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) ++{ ++ OSSL_PARAM_BLD *param_bld = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = 0; ++ ++ /* create EVP_PKEY-DH key */ ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { ++ error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { ++ error_f("Failed pushing params to OSSL_PARAM_BLD"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (priv != NULL && ++ OSSL_PARAM_BLD_push_BN(param_bld, ++ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { ++ error_f("Failed pushing private key to OSSL_PARAM_BLD"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++out: ++ OSSL_PARAM_BLD_free(param_bld); ++ EVP_PKEY_CTX_free(ctx); ++ return r; ++} ++#endif /* WITH_OPENSSL */ +diff --git a/kex.h b/kex.h +index 6a55aadf..48f3bb87 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 */ +@@ -311,6 +314,9 @@ int kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE], + const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int) + __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) + __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); ++int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, ++ const BIGNUM *, const BIGNUM *, const BIGNUM *); ++int kex_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey); + + #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) + void dump_digest(const char *, const u_char *, int); +diff --git a/kexdh.c b/kexdh.c +index 0faab21b..32e1de51 100644 +--- a/kexdh.c ++++ b/kexdh.c +@@ -35,6 +35,10 @@ + + #include "openbsd-compat/openssl-compat.h" + #include ++#include ++#include ++#include ++#include + + #include "sshkey.h" + #include "kex.h" +@@ -83,9 +87,12 @@ int + kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) + { + BIGNUM *shared_secret = NULL; ++ const BIGNUM *pub, *priv, *p, *q, *g; ++ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; + u_char *kbuf = NULL; + size_t klen = 0; +- int kout, r; ++ int r = 0; + + #ifdef DEBUG_KEXDH + fprintf(stderr, "dh_pub= "); +@@ -100,24 +107,59 @@ kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) + r = SSH_ERR_MESSAGE_INCOMPLETE; + goto out; + } +- klen = DH_size(kex->dh); ++ ++ DH_get0_key(kex->dh, &pub, &priv); ++ DH_get0_pqg(kex->dh, &p, &q, &g); ++ /* import key */ ++ r = kex_create_evp_dh(&pkey, p, q, g, pub, priv); ++ if (r != 0) { ++ error_f("Could not create EVP_PKEY for dh"); ++ ERR_print_errors_fp(stderr); ++ goto out; ++ } ++ /* import peer key ++ * the parameters should be the same as with pkey ++ */ ++ r = kex_create_evp_dh(&dh_pkey, p, q, g, dh_pub, NULL); ++ if (r != 0) { ++ error_f("Could not import peer key for dh"); ++ ERR_print_errors_fp(stderr); ++ goto out; ++ } ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) { ++ error_f("Could not init EVP_PKEY_CTX for dh"); ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (EVP_PKEY_derive_init(ctx) != 1 || ++ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || ++ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { ++ error_f("Could not get key size"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } + if ((kbuf = malloc(klen)) == NULL || + (shared_secret = BN_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || +- BN_bin2bn(kbuf, kout, shared_secret) == NULL) { ++ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1 || ++ BN_bin2bn(kbuf, klen, shared_secret) == NULL) { ++ error_f("Could not derive key"); + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + #ifdef DEBUG_KEXDH +- dump_digest("shared secret", kbuf, kout); ++ dump_digest("shared secret", kbuf, klen); + #endif + r = sshbuf_put_bignum2(out, shared_secret); + out: + freezero(kbuf, klen); + BN_clear_free(shared_secret); ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_free(dh_pkey); ++ EVP_PKEY_CTX_free(ctx); + return r; + } + +diff --git a/kexecdh.c b/kexecdh.c +index efb2e55a..d92ba54f 100644 +--- a/kexecdh.c ++++ b/kexecdh.c +@@ -35,17 +35,57 @@ + #include + + #include ++#include ++#include ++#include ++#include + + #include "sshkey.h" + #include "kex.h" + #include "sshbuf.h" + #include "digest.h" + #include "ssherr.h" ++#include "log.h" + + static int + kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, + const EC_GROUP *, struct sshbuf **); + ++static EC_KEY * ++generate_ec_keys(int ec_nid) ++{ ++ EC_KEY *client_key = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ const char *group_name; ++ ++ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) ++ goto out; ++ if ((group_name = OSSL_EC_curve_nid2name(ec_nid)) == NULL || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ error_f("Could not create OSSL_PARAM"); ++ goto out; ++ } ++ if (EVP_PKEY_keygen_init(ctx) != 1 || ++ EVP_PKEY_CTX_set_params(ctx, params) != 1 || ++ EVP_PKEY_generate(ctx, &pkey) != 1 || ++ (client_key = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { ++ error_f("Could not generate ec keys"); ++ goto out; ++ } ++out: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ OSSL_PARAM_BLD_free(param_bld); ++ OSSL_PARAM_free(params); ++ return client_key; ++} ++ + int + kex_ecdh_keypair(struct kex *kex) + { +@@ -55,11 +95,7 @@ kex_ecdh_keypair(struct kex *kex) + struct sshbuf *buf = NULL; + int r; + +- if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { +- r = SSH_ERR_ALLOC_FAIL; +- goto out; +- } +- if (EC_KEY_generate_key(client_key) != 1) { ++ if ((client_key = generate_ec_keys(kex->ec_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +@@ -101,11 +137,7 @@ kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, + *server_blobp = NULL; + *shared_secretp = NULL; + +- if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { +- r = SSH_ERR_ALLOC_FAIL; +- goto out; +- } +- if (EC_KEY_generate_key(server_key) != 1) { ++ if ((server_key = generate_ec_keys(kex->ec_nid)) == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +@@ -140,11 +172,21 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, + { + struct sshbuf *buf = NULL; + BIGNUM *shared_secret = NULL; +- EC_POINT *dh_pub = NULL; +- u_char *kbuf = NULL; +- size_t klen = 0; ++ EVP_PKEY_CTX *ctx = NULL; ++ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; ++ OSSL_PARAM_BLD *param_bld = NULL; ++ OSSL_PARAM *params = NULL; ++ u_char *kbuf = NULL, *pub = NULL; ++ size_t klen = 0, publen; ++ const char *group_name; + int r; + ++ /* import EC_KEY to EVP_PKEY */ ++ if ((r = kex_create_evp_ec(key, kex->ec_nid, &pkey)) != 0) { ++ error_f("Could not create EVP_PKEY"); ++ goto out; ++ } ++ + *shared_secretp = NULL; + + if ((buf = sshbuf_new()) == NULL) { +@@ -153,45 +195,82 @@ kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, + } + if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) + goto out; +- if ((dh_pub = EC_POINT_new(group)) == NULL) { ++ ++ /* the public key is in the buffer in octet string UNCOMPRESSED ++ * format. See sshbuf_put_ec */ ++ if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0) ++ goto out; ++ sshbuf_reset(buf); ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { ++ if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (OSSL_PARAM_BLD_push_octet_string(param_bld, ++ OSSL_PKEY_PARAM_PUB_KEY, pub, publen) != 1 || ++ OSSL_PARAM_BLD_push_utf8_string(param_bld, ++ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || ++ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { ++ error_f("Failed to set params for dh_pkey"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto out; ++ } ++ if (EVP_PKEY_fromdata_init(ctx) != 1 || ++ EVP_PKEY_fromdata(ctx, &dh_pkey, ++ EVP_PKEY_PUBLIC_KEY, params) != 1 || ++ EVP_PKEY_public_check(ctx) != 1) { ++ error_f("Peer public key import failed"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- sshbuf_reset(buf); + + #ifdef DEBUG_KEXECDH + fputs("public key:\n", stderr); +- sshkey_dump_ec_point(group, dh_pub); ++ EVP_PKEY_print_public_fp(stderr, dh_pkey, 0, NULL); + #endif +- if (sshkey_ec_validate_public(group, dh_pub) != 0) { +- r = SSH_ERR_MESSAGE_INCOMPLETE; ++ EVP_PKEY_CTX_free(ctx); ++ ctx = NULL; ++ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || ++ EVP_PKEY_derive_init(ctx) != 1 || ++ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || ++ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { ++ error_f("Failed to get derive information"); ++ r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } +- klen = (EC_GROUP_get_degree(group) + 7) / 8; +- if ((kbuf = malloc(klen)) == NULL || +- (shared_secret = BN_new()) == NULL) { ++ if ((kbuf = malloc(klen)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } +- if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || +- BN_bin2bn(kbuf, klen, shared_secret) == NULL) { ++ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + #ifdef DEBUG_KEXECDH + dump_digest("shared secret", kbuf, klen); + #endif ++ if ((shared_secret = BN_new()) == NULL || ++ (BN_bin2bn(kbuf, klen, shared_secret) == NULL)) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } + if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) + goto out; + *shared_secretp = buf; + buf = NULL; + out: +- EC_POINT_clear_free(dh_pub); ++ EVP_PKEY_CTX_free(ctx); ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_free(dh_pkey); ++ OSSL_PARAM_BLD_free(param_bld); ++ OSSL_PARAM_free(params); + BN_clear_free(shared_secret); + freezero(kbuf, klen); ++ freezero(pub, publen); + sshbuf_free(buf); + return r; + } +-- +2.49.0 + diff --git a/0046-openssh-8.7p1-nohostsha1proof.patch b/0046-openssh-8.7p1-nohostsha1proof.patch new file mode 100644 index 0000000..9e75c8a --- /dev/null +++ b/0046-openssh-8.7p1-nohostsha1proof.patch @@ -0,0 +1,334 @@ +From e4ca3b9dba1cc832a9974493c91207d42e218a68 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 46/50] 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 | 32 +++++++++++++++++--------- + serverloop.c | 6 ++++- + ssh-rsa.c | 3 ++- + sshconnect2.c | 8 +++++++ + sshd-session.c | 21 +++++++++++++++++ + 11 files changed, 90 insertions(+), 24 deletions(-) + +diff --git a/compat.c b/compat.c +index b59f0bfc..4e611dc3 100644 +--- a/compat.c ++++ b/compat.c +@@ -42,6 +42,7 @@ void + compat_banner(struct ssh *ssh, const char *version) + { + int i; ++ int forbid_ssh_rsa = 0; + static struct { + char *pat; + int bugs; +@@ -125,16 +126,21 @@ compat_banner(struct ssh *ssh, const char *version) + }; + + /* process table, return first match */ ++ forbid_ssh_rsa = (ssh->compat & SSH_RH_RSASIGSHA); + ssh->compat = 0; + for (i = 0; check[i].pat; i++) { + if (match_pattern_list(version, check[i].pat, 0) == 1) { + debug_f("match: %s pat %s compat 0x%08x", + version, check[i].pat, check[i].bugs); + ssh->compat = check[i].bugs; ++ if (forbid_ssh_rsa) ++ ssh->compat |= SSH_RH_RSASIGSHA; + return; + } + } + debug_f("no match: %s", version); ++ if (forbid_ssh_rsa) ++ ssh->compat |= SSH_RH_RSASIGSHA; + } + + /* Always returns pointer to allocated memory, caller must free. */ +diff --git a/compat.h b/compat.h +index 1a19060f..2e6db5bf 100644 +--- a/compat.h ++++ b/compat.h +@@ -30,7 +30,7 @@ + #define SSH_BUG_UTF8TTYMODE 0x00000001 + #define SSH_BUG_SIGTYPE 0x00000002 + #define SSH_BUG_SIGTYPE74 0x00000004 +-/* #define unused 0x00000008 */ ++#define SSH_RH_RSASIGSHA 0x00000008 + #define SSH_OLD_SESSIONID 0x00000010 + /* #define unused 0x00000020 */ + #define SSH_BUG_DEBUG 0x00000040 +diff --git a/monitor.c b/monitor.c +index fbc35782..19cb058e 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -747,11 +747,12 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m) + struct sshkey *pubkey, *key; + struct sshbuf *sigbuf = NULL; + u_char *p = NULL, *signature = NULL; +- char *alg = NULL; +- size_t datlen, siglen; +- int r, is_proof = 0, keyid; +- u_int compat; ++ char *alg = NULL, *effective_alg; ++ size_t datlen, siglen, alglen; ++ int r, is_proof = 0; ++ u_int keyid, compat; + const char proof_req[] = "hostkeys-prove-00@openssh.com"; ++ const char safe_rsa[] = "rsa-sha2-256"; + + debug3_f("entering"); + +@@ -809,18 +810,30 @@ mm_answer_sign(struct ssh *ssh, int sock, struct sshbuf *m) + } + + if ((key = get_hostkey_by_index(keyid)) != NULL) { +- if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg, ++ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 ++ && (sshkey_type_plain(key->type) == KEY_RSA)) { ++ effective_alg = safe_rsa; ++ } else { ++ effective_alg = alg; ++ } ++ if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, effective_alg, + options.sk_provider, NULL, compat)) != 0) + fatal_fr(r, "sign"); + } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && + auth_sock > 0) { ++ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 ++ && (sshkey_type_plain(key->type) == KEY_RSA)) { ++ effective_alg = safe_rsa; ++ } else { ++ effective_alg = alg; ++ } + if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, +- p, datlen, alg, compat)) != 0) ++ p, datlen, effective_alg, compat)) != 0) + fatal_fr(r, "agent sign"); + } else + fatal_f("no hostkey from index %d", keyid); + +- debug3_f("%s %s signature len=%zu", alg, ++ debug3_f("%s (effective: %s) %s signature len=%zu", alg, effective_alg, + is_proof ? "hostkey proof" : "KEX", siglen); + + sshbuf_reset(m); +diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c +index caf8f57f..09016aea 100644 +--- a/regress/unittests/kex/test_kex.c ++++ b/regress/unittests/kex/test_kex.c +@@ -97,7 +97,8 @@ do_kex_with_key(char *kex, int keytype, int bits) + 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 3babe604..cc80fe97 100644 +--- a/regress/unittests/sshkey/test_file.c ++++ b/regress/unittests/sshkey/test_file.c +@@ -109,6 +109,7 @@ sshkey_file_tests(void) + sshkey_free(k2); + TEST_DONE(); + ++ /* Skip this test, SHA1 signatures are not supported + TEST_START("load RSA cert with SHA1 signature"); + ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha1"), &k2), 0); + ASSERT_PTR_NE(k2, NULL); +@@ -116,7 +117,7 @@ sshkey_file_tests(void) + ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1); + ASSERT_STRING_EQ(k2->cert->signature_type, "ssh-rsa"); + sshkey_free(k2); +- TEST_DONE(); ++ TEST_DONE(); */ + + TEST_START("load RSA cert with SHA512 signature"); + ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha512"), &k2), 0); +diff --git a/regress/unittests/sshkey/test_fuzz.c b/regress/unittests/sshkey/test_fuzz.c +index 0aff7c9b..951122e1 100644 +--- a/regress/unittests/sshkey/test_fuzz.c ++++ b/regress/unittests/sshkey/test_fuzz.c +@@ -338,13 +338,14 @@ sshkey_fuzz_tests(void) + TEST_DONE(); + + #ifdef WITH_OPENSSL ++ /* Skip this test, SHA1 signatures are not supported + TEST_START("fuzz RSA sig"); + buf = load_file("rsa_1"); + ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); + sshbuf_free(buf); + sig_fuzz(k1, "ssh-rsa"); + sshkey_free(k1); +- TEST_DONE(); ++ TEST_DONE();*/ + + TEST_START("fuzz RSA SHA256 sig"); + buf = load_file("rsa_1"); +diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c +index 5bf4b65c..6d0a35bb 100644 +--- a/regress/unittests/sshkey/test_sshkey.c ++++ b/regress/unittests/sshkey/test_sshkey.c +@@ -61,6 +61,9 @@ build_cert(struct sshbuf *b, struct sshkey *k, const char *type, + u_char *sigblob; + size_t siglen; + ++ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp */ ++ int expected = (sig_alg == NULL || strcmp(sig_alg, "ssh-rsa") == 0) ? SSH_ERR_LIBCRYPTO_ERROR : 0; ++ + ca_buf = sshbuf_new(); + ASSERT_PTR_NE(ca_buf, NULL); + ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0); +@@ -102,8 +105,9 @@ build_cert(struct sshbuf *b, struct sshkey *k, const char *type, + ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ + ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ + ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, +- sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), 0); +- ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ ++ sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), expected); ++ if (expected == 0) ++ ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ + + free(sigblob); + sshbuf_free(ca_buf); +@@ -120,16 +124,22 @@ signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg, + { + size_t len; + u_char *sig; ++ /* ssh-rsa implies SHA1, forbidden in DEFAULT 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); +- ASSERT_SIZE_T_GT(len, 8); +- ASSERT_PTR_NE(sig, NULL); +- ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); +- ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); +- /* Fuzz test is more comprehensive, this is just a smoke test */ +- sig[len - 5] ^= 0x10; +- ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ NULL, NULL, 0), expected); ++ if (expected == 0) { ++ ASSERT_SIZE_T_GT(len, 8); ++ ASSERT_PTR_NE(sig, NULL); ++ ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); ++ /* Fuzz test is more comprehensive, this is just a smoke test */ ++ sig[len - 5] ^= 0x10; ++ ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); ++ } + free(sig); + } + +@@ -526,7 +536,7 @@ sshkey_tests(void) + ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, + NULL), 0); + k3 = get_private("rsa_1"); +- build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, NULL); ++ build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, "rsa-sha2-256"); + ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4), + SSH_ERR_KEY_CERT_INVALID_SIGN_KEY); + ASSERT_PTR_EQ(k4, NULL); +diff --git a/serverloop.c b/serverloop.c +index 40ddfb04..9c5b1567 100644 +--- a/serverloop.c ++++ b/serverloop.c +@@ -80,6 +80,7 @@ + #include "auth-options.h" + #include "serverloop.h" + #include "ssherr.h" ++#include "compat.h" + + extern ServerOptions options; + +@@ -699,7 +700,10 @@ server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp) + else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) + sigalg = "rsa-sha2-256"; + } +- ++ if (ssh->compat & SSH_RH_RSASIGSHA && sigalg == NULL) { ++ sigalg = "rsa-sha2-512"; ++ debug3_f("SHA1 signature is not supported, falling back to %s", sigalg); ++ } + debug3_f("sign %s key (index %d) using sigalg %s", + sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); + if ((r = sshbuf_put_cstring(sigbuf, +diff --git a/ssh-rsa.c b/ssh-rsa.c +index 6c2f771a..8dd4ab01 100644 +--- a/ssh-rsa.c ++++ b/ssh-rsa.c +@@ -509,7 +509,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 ad3f560f..3941e089 100644 +--- a/sshconnect2.c ++++ b/sshconnect2.c +@@ -1434,6 +1434,14 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, + retried = 1; + goto retry_pin; + } ++ if ((r == SSH_ERR_LIBCRYPTO_ERROR) && strcmp("ssh-rsa", alg)) { ++ char rsa_safe_alg[] = "rsa-sha2-512"; ++ debug3_f("trying to fallback to algorithm %s", rsa_safe_alg); ++ ++ if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, ++ rsa_safe_alg, options.sk_provider, pin, compat)) != 0) ++ debug_fr(r, "sshkey_sign - RSA fallback"); ++ } + goto out; + } + +diff --git a/sshd-session.c b/sshd-session.c +index a808ac9a..c3349a8a 100644 +--- a/sshd-session.c ++++ b/sshd-session.c +@@ -1316,6 +1316,27 @@ main(int ac, char **av) + + check_ip_options(ssh); + ++ { ++ struct sshkey *rsakey = NULL; ++ rsakey = get_hostkey_private_by_type(KEY_RSA, 0, ssh); ++ if (rsakey == NULL) ++ rsakey = get_hostkey_private_by_type(KEY_RSA_CERT, 0, ssh); ++ ++ if (rsakey != NULL) { ++ size_t sign_size = 0; ++ u_char *tmp = NULL; ++ u_char data[] = "Test SHA1 vector"; ++ int res; ++ ++ res = sshkey_sign(rsakey, &tmp, &sign_size, data, sizeof(data), NULL, NULL, NULL, 0); ++ free(tmp); ++ if (res == SSH_ERR_LIBCRYPTO_ERROR) { ++ verbose_f("SHA1 in signatures is disabled for RSA keys"); ++ ssh->compat |= SSH_RH_RSASIGSHA; ++ } ++ } ++ } ++ + /* Prepare the channels layer */ + channel_init_channels(ssh); + channel_set_af(ssh, options.address_family); +-- +2.49.0 + diff --git a/0047-openssh-9.6p1-pam-rhost.patch b/0047-openssh-9.6p1-pam-rhost.patch new file mode 100644 index 0000000..968e60a --- /dev/null +++ b/0047-openssh-9.6p1-pam-rhost.patch @@ -0,0 +1,25 @@ +From 497de886faaddec60b7ad1013396c7d4f3145968 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 47/50] openssh-9.6p1-pam-rhost + +--- + auth-pam.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/auth-pam.c b/auth-pam.c +index a042c3c8..a321e0d3 100644 +--- a/auth-pam.c ++++ b/auth-pam.c +@@ -741,7 +741,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.49.0 + diff --git a/0048-openssh-9.9p1-separate-keysign.patch b/0048-openssh-9.9p1-separate-keysign.patch new file mode 100644 index 0000000..8d0f691 --- /dev/null +++ b/0048-openssh-9.9p1-separate-keysign.patch @@ -0,0 +1,25 @@ +From b97b1040bc0918fe9be89cdb482d046270e92d9c Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 48/50] 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 a43b2a27..9d5da2a6 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.49.0 + diff --git a/0049-openssh-9.9p1-openssl-mlkem.patch b/0049-openssh-9.9p1-openssl-mlkem.patch new file mode 100644 index 0000000..e04d194 --- /dev/null +++ b/0049-openssh-9.9p1-openssl-mlkem.patch @@ -0,0 +1,398 @@ +From 0a621a2ccb8444e4c6da906b0e112e0522658122 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 49/50] openssh-9.9p1-openssl-mlkem + +--- + kex-names.c | 20 +++ + kexmlkem768x25519.c | 291 ++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 311 insertions(+) + +diff --git a/kex-names.c b/kex-names.c +index cd3902ad..36a953ab 100644 +--- a/kex-names.c ++++ b/kex-names.c +@@ -108,6 +108,19 @@ static const struct kexalg gss_kexalgs[] = { + { NULL, 0, -1, -1}, + }; + ++static int is_mlkem768_available() ++{ ++ static int is_fetched = -1; ++ ++ if (is_fetched == -1) { ++ EVP_KEM *mlkem768 = EVP_KEM_fetch(NULL, "mlkem768", NULL); ++ is_fetched = mlkem768 != NULL ? 1 : 0; ++ EVP_KEM_free(mlkem768); ++ } ++ ++ return is_fetched; ++} ++ + static char * + kex_alg_list_internal(char sep, const struct kexalg *algs) + { +@@ -116,6 +129,9 @@ kex_alg_list_internal(char sep, const struct kexalg *algs) + const struct kexalg *k; + + for (k = algs; k->name != NULL; k++) { ++ if (strcmp(k->name, KEX_MLKEM768X25519_SHA256) == 0 ++ && !is_mlkem768_available()) ++ continue; + if (ret != NULL) + ret[rlen++] = sep; + nlen = strlen(k->name); +@@ -147,6 +163,10 @@ kex_alg_by_name(const char *name) + { + const struct kexalg *k; + ++ if (strcmp(name, KEX_MLKEM768X25519_SHA256) == 0 ++ && !is_mlkem768_available()) ++ return NULL; ++ + for (k = kexalgs; k->name != NULL; k++) { + if (strcmp(k->name, name) == 0) + return k; +diff --git a/kexmlkem768x25519.c b/kexmlkem768x25519.c +index 2b5d3960..670049dc 100644 +--- a/kexmlkem768x25519.c ++++ b/kexmlkem768x25519.c +@@ -48,10 +48,127 @@ + #ifdef USE_MLKEM768X25519 + + #include "libcrux_mlkem768_sha3.h" ++#include ++#include ++#include ++ ++static int ++mlkem768_keypair_gen(unsigned char *pubkeybuf, unsigned char *privkeybuf) ++{ ++ EVP_PKEY_CTX *ctx = NULL; ++ EVP_PKEY *pkey = NULL; ++ int ret = SSH_ERR_INTERNAL_ERROR; ++ size_t pubkey_size = crypto_kem_mlkem768_PUBLICKEYBYTES, privkey_size = crypto_kem_mlkem768_SECRETKEYBYTES; ++ ++ ctx = EVP_PKEY_CTX_new_from_name(NULL, "mlkem768", NULL); ++ if (ctx == NULL) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (EVP_PKEY_keygen_init(ctx) <= 0 ++ || EVP_PKEY_keygen(ctx, &pkey) <= 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (EVP_PKEY_get_raw_public_key(pkey, pubkeybuf, &pubkey_size) <= 0 ++ || EVP_PKEY_get_raw_private_key(pkey, privkeybuf, &privkey_size) <= 0) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ if (privkey_size != crypto_kem_mlkem768_SECRETKEYBYTES ++ || pubkey_size != crypto_kem_mlkem768_PUBLICKEYBYTES) { ++ ret = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ret = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ if (ret == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ return ret; ++} ++ ++static int ++mlkem768_encap_secret(const u_char *pubkeybuf, u_char *secret, u_char *out) ++{ ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ size_t outlen = crypto_kem_mlkem768_CIPHERTEXTBYTES, ++ secretlen = crypto_kem_mlkem768_BYTES; ++ ++ pkey = EVP_PKEY_new_raw_public_key_ex(NULL, "mlkem768", NULL, ++ pubkeybuf, crypto_kem_mlkem768_PUBLICKEYBYTES); ++ if (pkey == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); ++ if (ctx == NULL ++ || EVP_PKEY_encapsulate_init(ctx, NULL) <= 0 ++ || EVP_PKEY_encapsulate(ctx, out, &outlen, secret, &secretlen) <= 0 ++ || secretlen != crypto_kem_mlkem768_BYTES ++ || outlen != crypto_kem_mlkem768_CIPHERTEXTBYTES) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ r = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ if (r == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ ++ return r; ++} ++ ++static int ++mlkem768_decap_secret(const u_char *privkeybuf, const u_char *wrapped, u_char *secret) ++{ ++ EVP_PKEY *pkey = NULL; ++ EVP_PKEY_CTX *ctx = NULL; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ size_t wrappedlen = crypto_kem_mlkem768_CIPHERTEXTBYTES, ++ secretlen = crypto_kem_mlkem768_BYTES; ++ ++ pkey = EVP_PKEY_new_raw_private_key_ex(NULL, "mlkem768", NULL, ++ privkeybuf, crypto_kem_mlkem768_SECRETKEYBYTES); ++ if (pkey == NULL) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ ++ ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL); ++ if (ctx == NULL ++ || EVP_PKEY_decapsulate_init(ctx, NULL) <= 0 ++ || EVP_PKEY_decapsulate(ctx, secret, &secretlen, wrapped, wrappedlen) <= 0 ++ || secretlen != crypto_kem_mlkem768_BYTES) { ++ r = SSH_ERR_LIBCRYPTO_ERROR; ++ goto err; ++ } ++ r = 0; ++ ++ err: ++ EVP_PKEY_free(pkey); ++ EVP_PKEY_CTX_free(ctx); ++ ++ if (r == SSH_ERR_LIBCRYPTO_ERROR) ++ ERR_print_errors_fp(stderr); ++ ++ return r; ++} + + int + kex_kem_mlkem768x25519_keypair(struct kex *kex) + { ++#if 0 + struct sshbuf *buf = NULL; + u_char rnd[LIBCRUX_ML_KEM_KEY_PAIR_PRNG_LEN], *cp = NULL; + size_t need; +@@ -86,6 +203,36 @@ kex_kem_mlkem768x25519_keypair(struct kex *kex) + explicit_bzero(rnd, sizeof(rnd)); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *buf = NULL; ++ u_char *cp = NULL; ++ size_t need; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ ++ if ((buf = sshbuf_new()) == NULL) ++ return SSH_ERR_ALLOC_FAIL; ++ need = crypto_kem_mlkem768_PUBLICKEYBYTES + CURVE25519_SIZE; ++ if ((r = sshbuf_reserve(buf, need, &cp)) != 0) ++ goto out; ++ if ((r = mlkem768_keypair_gen(cp, kex->mlkem768_client_key)) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key mlkem768:", cp, ++ crypto_kem_mlkem768_PUBLICKEYBYTES); ++#endif ++ cp += crypto_kem_mlkem768_PUBLICKEYBYTES; ++ kexc25519_keygen(kex->c25519_client_key, cp); ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key c25519:", cp, CURVE25519_SIZE); ++#endif ++ /* success */ ++ r = 0; ++ kex->client_pub = buf; ++ buf = NULL; ++ out: ++ sshbuf_free(buf); ++ return r; ++#endif + } + + int +@@ -93,6 +240,7 @@ kex_kem_mlkem768x25519_enc(struct kex *kex, + const struct sshbuf *client_blob, struct sshbuf **server_blobp, + struct sshbuf **shared_secretp) + { ++#if 0 + struct sshbuf *server_blob = NULL; + struct sshbuf *buf = NULL; + const u_char *client_pub; +@@ -185,12 +333,97 @@ kex_kem_mlkem768x25519_enc(struct kex *kex, + sshbuf_free(server_blob); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *server_blob = NULL; ++ struct sshbuf *buf = NULL; ++ const u_char *client_pub; ++ u_char server_pub[CURVE25519_SIZE], server_key[CURVE25519_SIZE]; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ size_t need; ++ int r = SSH_ERR_INTERNAL_ERROR; ++ struct libcrux_mlkem768_enc_result enc; /* FIXME */ ++ ++ *server_blobp = NULL; ++ *shared_secretp = NULL; ++ ++ /* client_blob contains both KEM and ECDH client pubkeys */ ++ need = crypto_kem_mlkem768_PUBLICKEYBYTES + CURVE25519_SIZE; ++ if (sshbuf_len(client_blob) != need) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ client_pub = sshbuf_ptr(client_blob); ++#ifdef DEBUG_KEXECDH ++ dump_digest("client public key mlkem768:", client_pub, ++ crypto_kem_mlkem768_PUBLICKEYBYTES); ++ dump_digest("client public key 25519:", ++ client_pub + crypto_kem_mlkem768_PUBLICKEYBYTES, ++ CURVE25519_SIZE); ++#endif ++ ++ /* allocate buffer for concatenation of KEM key and ECDH shared key */ ++ /* the buffer will be hashed and the result is the shared secret */ ++ if ((buf = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ /* allocate space for encrypted KEM key and ECDH pub key */ ++ if ((server_blob = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++ if (mlkem768_encap_secret(client_pub, enc.snd, enc.fst.value) != 0) ++ goto out; ++ ++ /* generate ECDH key pair, store server pubkey after ciphertext */ ++ kexc25519_keygen(server_key, server_pub); ++ if ((r = sshbuf_put(buf, enc.snd, sizeof(enc.snd))) != 0 || ++ (r = sshbuf_put(server_blob, enc.fst.value, sizeof(enc.fst.value))) != 0 || ++ (r = sshbuf_put(server_blob, server_pub, sizeof(server_pub))) != 0) ++ goto out; ++ /* append ECDH shared key */ ++ client_pub += crypto_kem_mlkem768_PUBLICKEYBYTES; ++ if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0) ++ goto out; ++ if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE); ++ dump_digest("server cipher text:", ++ enc.fst.value, sizeof(enc.fst.value)); ++ dump_digest("server kem key:", enc.snd, sizeof(enc.snd)); ++ dump_digest("concatenation of KEM key and ECDH shared key:", ++ sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* string-encoded hash is resulting shared secret */ ++ sshbuf_reset(buf); ++ if ((r = sshbuf_put_string(buf, hash, ++ ssh_digest_bytes(kex->hash_alg))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* success */ ++ r = 0; ++ *server_blobp = server_blob; ++ *shared_secretp = buf; ++ server_blob = NULL; ++ buf = NULL; ++ out: ++ explicit_bzero(hash, sizeof(hash)); ++ explicit_bzero(server_key, sizeof(server_key)); ++ explicit_bzero(&enc, sizeof(enc)); ++ sshbuf_free(server_blob); ++ sshbuf_free(buf); ++ return r; ++#endif + } + + int + kex_kem_mlkem768x25519_dec(struct kex *kex, + const struct sshbuf *server_blob, struct sshbuf **shared_secretp) + { ++#if 0 + struct sshbuf *buf = NULL; + u_char mlkem_key[crypto_kem_mlkem768_BYTES]; + const u_char *ciphertext, *server_pub; +@@ -258,6 +491,64 @@ kex_kem_mlkem768x25519_dec(struct kex *kex, + explicit_bzero(mlkem_key, sizeof(mlkem_key)); + sshbuf_free(buf); + return r; ++#else ++ struct sshbuf *buf = NULL; ++ const u_char *ciphertext, *server_pub; ++ u_char hash[SSH_DIGEST_MAX_LENGTH]; ++ u_char decap[crypto_kem_mlkem768_BYTES]; ++ size_t need; ++ int r; ++ ++ *shared_secretp = NULL; ++ ++ need = crypto_kem_mlkem768_CIPHERTEXTBYTES + CURVE25519_SIZE; ++ if (sshbuf_len(server_blob) != need) { ++ r = SSH_ERR_SIGNATURE_INVALID; ++ goto out; ++ } ++ ciphertext = sshbuf_ptr(server_blob); ++ server_pub = ciphertext + crypto_kem_mlkem768_CIPHERTEXTBYTES; ++ /* hash concatenation of KEM key and ECDH shared key */ ++ if ((buf = sshbuf_new()) == NULL) { ++ r = SSH_ERR_ALLOC_FAIL; ++ goto out; ++ } ++#ifdef DEBUG_KEXECDH ++ dump_digest("server cipher text:", ciphertext, crypto_kem_mlkem768_CIPHERTEXTBYTES); ++ dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE); ++#endif ++ if ((r = mlkem768_decap_secret(kex->mlkem768_client_key, ciphertext, decap)) != 0) ++ goto out; ++ if ((r = sshbuf_put(buf, decap, sizeof(decap))) != 0) ++ goto out; ++ if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub, ++ buf, 1)) < 0) ++ goto out; ++ if ((r = ssh_digest_buffer(kex->hash_alg, buf, ++ hash, sizeof(hash))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("client kem key:", decap, sizeof(decap)); ++ dump_digest("concatenation of KEM key and ECDH shared key:", ++ sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ sshbuf_reset(buf); ++ if ((r = sshbuf_put_string(buf, hash, ++ ssh_digest_bytes(kex->hash_alg))) != 0) ++ goto out; ++#ifdef DEBUG_KEXECDH ++ dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf)); ++#endif ++ /* success */ ++ r = 0; ++ *shared_secretp = buf; ++ buf = NULL; ++ out: ++ explicit_bzero(hash, sizeof(hash)); ++ explicit_bzero(decap, sizeof(decap)); ++ sshbuf_free(buf); ++ return r; ++#endif + } + #else /* USE_MLKEM768X25519 */ + int +-- +2.49.0 + diff --git a/0050-openssh-9.9p2-error_processing.patch b/0050-openssh-9.9p2-error_processing.patch new file mode 100644 index 0000000..aed1c30 --- /dev/null +++ b/0050-openssh-9.9p2-error_processing.patch @@ -0,0 +1,25 @@ +From fd32e753ae7f3b314712e6aa8b2bed3c1fca1ef5 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Fri, 16 May 2025 14:53:54 +0200 +Subject: [PATCH 50/51] 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 798bf9b6..dfb6ac72 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c +@@ -1377,6 +1377,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.49.0 + diff --git a/0051-Provide-better-error-for-non-supported-private-keys.patch b/0051-Provide-better-error-for-non-supported-private-keys.patch new file mode 100644 index 0000000..9c1aa4d --- /dev/null +++ b/0051-Provide-better-error-for-non-supported-private-keys.patch @@ -0,0 +1,27 @@ +From 4965cdbc1ee1e6a0c665797bb8b944d96d3d411f Mon Sep 17 00:00:00 2001 +From: Zoltan Fridrich +Date: Wed, 16 Apr 2025 15:11:59 +0200 +Subject: [PATCH 51/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 ca1cdb642..aada474e0 100644 +--- a/sshkey.c ++++ b/sshkey.c +@@ -3582,6 +3582,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.49.0 + diff --git a/0052-Ignore-bad-hostkeys-in-known_hosts-file.patch b/0052-Ignore-bad-hostkeys-in-known_hosts-file.patch new file mode 100644 index 0000000..f071225 --- /dev/null +++ b/0052-Ignore-bad-hostkeys-in-known_hosts-file.patch @@ -0,0 +1,86 @@ +From 9ed09ef158a113e21be7b3fefa7c5f932632749b Mon Sep 17 00:00:00 2001 +From: Zoltan Fridrich +Date: Mon, 5 May 2025 11:52:25 +0200 +Subject: [PATCH 52/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 c5669c703..5c402f501 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 abc8b8439..33787a8d4 100644 +--- a/ssh.c ++++ b/ssh.c +@@ -110,6 +110,7 @@ + #include "ssherr.h" + #include "myproposal.h" + #include "utf8.h" ++#include "hostfile.h" + + #ifdef ENABLE_PKCS11 + #include "ssh-pkcs11.h" +@@ -1397,6 +1398,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.49.0 + diff --git a/0053-support-authentication-indicators-in-GSSAPI.patch b/0053-support-authentication-indicators-in-GSSAPI.patch new file mode 100644 index 0000000..237e45d --- /dev/null +++ b/0053-support-authentication-indicators-in-GSSAPI.patch @@ -0,0 +1,450 @@ +From 5d5a66e96ad03132f65371070f4fa475f10207d9 Mon Sep 17 00:00:00 2001 +From: Alexander Bokovoy +Date: Mon, 10 Jun 2024 23:00:03 +0300 +Subject: [PATCH] support authentication indicators in GSSAPI + +RFC 6680 defines a set of GSSAPI extensions to handle attributes +associated with the GSSAPI names. MIT Kerberos and FreeIPA use +name attributes to add information about pre-authentication methods used +to acquire the initial Kerberos ticket. The attribute 'auth-indicators' +may contain list of strings that KDC has associated with the ticket +issuance process. + +Use authentication indicators to authorise or deny access to SSH server. +GSSAPIIndicators setting allows to specify a list of possible indicators +that a Kerberos ticket presented must or must not contain. More details +on the syntax are provided in sshd_config(5) man page. + +Fixes: https://bugzilla.mindrot.org/show_bug.cgi?id=2696 + +Signed-off-by: Alexander Bokovoy +--- + configure.ac | 1 + + gss-serv-krb5.c | 64 +++++++++++++++++++++++++++--- + gss-serv.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++- + servconf.c | 15 ++++++- + servconf.h | 2 + + ssh-gss.h | 7 ++++ + sshd_config.5 | 44 +++++++++++++++++++++ + 7 files changed, 228 insertions(+), 8 deletions(-) + +diff --git a/configure.ac b/configure.ac +index d92a85809..2cbe20bf3 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -5004,6 +5004,7 @@ AC_ARG_WITH([kerberos5], + AC_CHECK_HEADERS([gssapi.h gssapi/gssapi.h]) + AC_CHECK_HEADERS([gssapi_krb5.h gssapi/gssapi_krb5.h]) + AC_CHECK_HEADERS([gssapi_generic.h gssapi/gssapi_generic.h]) ++ AC_CHECK_HEADERS([gssapi_ext.h gssapi/gssapi_ext.h]) + + AC_SEARCH_LIBS([k_hasafs], [kafs], [AC_DEFINE([USE_AFS], [1], + [Define this if you want to use libkafs' AFS support])]) +diff --git a/gss-serv-krb5.c b/gss-serv-krb5.c +index 03188d9b3..2c786ef14 100644 +--- a/gss-serv-krb5.c ++++ b/gss-serv-krb5.c +@@ -43,6 +43,7 @@ + #include "log.h" + #include "misc.h" + #include "servconf.h" ++#include "match.h" + + #include "ssh-gss.h" + +@@ -87,6 +88,32 @@ ssh_gssapi_krb5_init(void) + return 1; + } + ++/* Check if any of the indicators in the Kerberos ticket match ++ * one of indicators in the list of allowed/denied rules. ++ * In case of the match, apply the decision from the rule. ++ * In case of no indicator from the ticket matching the rule, deny ++ */ ++ ++static int ++ssh_gssapi_check_indicators(ssh_gssapi_client *client, int *matched) ++{ ++ int ret; ++ u_int i; ++ ++ /* Check indicators */ ++ for (i = 0; client->indicators[i] != NULL; i++) { ++ ret = match_pattern_list(client->indicators[i], ++ options.gss_indicators, 1); ++ /* negative or positive match */ ++ if (ret != 0) { ++ *matched = i; ++ return ret; ++ } ++ } ++ /* No rule matched */ ++ return 0; ++} ++ + /* Check if this user is OK to login. This only works with krb5 - other + * GSSAPI mechanisms will need their own. + * Returns true if the user is OK to log in, otherwise returns 0 +@@ -193,7 +220,7 @@ static int + ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) + { + krb5_principal princ; +- int retval; ++ int retval, matched; + const char *errmsg; + int k5login_exists; + +@@ -216,17 +243,42 @@ ssh_gssapi_krb5_userok(ssh_gssapi_client *client, char *name) + if (k5login_exists && + ssh_krb5_kuserok(krb_context, princ, name, k5login_exists)) { + retval = 1; +- logit("Authorized to %s, krb5 principal %s (krb5_kuserok)", +- name, (char *)client->displayname.value); ++ errmsg = "krb5_kuserok"; + } else if (ssh_gssapi_krb5_cmdok(princ, client->exportedname.value, + name, k5login_exists)) { + retval = 1; +- logit("Authorized to %s, krb5 principal %s " +- "(ssh_gssapi_krb5_cmdok)", +- name, (char *)client->displayname.value); ++ errmsg = "ssh_gssapi_krb5_cmdok"; + } else + retval = 0; + ++ if ((retval == 1) && (options.gss_indicators != NULL)) { ++ /* At this point the configuration enforces presence of indicators ++ * so we drop the authorization result again */ ++ retval = 0; ++ if (client->indicators) { ++ matched = -1; ++ retval = ssh_gssapi_check_indicators(client, &matched); ++ if (retval != 0) { ++ retval = (retval == 1); ++ logit("Ticket contains indicator %s, " ++ "krb5 principal %s is %s", ++ client->indicators[matched], ++ (char *)client->displayname.value, ++ retval ? "allowed" : "denied"); ++ goto cont; ++ } ++ } ++ if (retval == 0) { ++ logit("GSSAPI authentication indicators enforced " ++ "but not matched. krb5 principal %s denied", ++ (char *)client->displayname.value); ++ } ++ } ++cont: ++ if (retval == 1) { ++ logit("Authorized to %s, krb5 principal %s (%s)", ++ name, (char *)client->displayname.value, errmsg); ++ } + krb5_free_principal(krb_context, princ); + return retval; + } +diff --git a/gss-serv.c b/gss-serv.c +index 9d5435eda..5c0491cf1 100644 +--- a/gss-serv.c ++++ b/gss-serv.c +@@ -54,7 +54,7 @@ extern ServerOptions options; + + static ssh_gssapi_client gssapi_client = + { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, +- GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0}; ++ GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, 0, 0, NULL}; + + ssh_gssapi_mech gssapi_null_mech = + { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; +@@ -296,6 +296,92 @@ ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name) + return GSS_S_COMPLETE; + } + ++ ++/* Extract authentication indicators from the Kerberos ticket. Authentication ++ * indicators are GSSAPI name attributes for the name "auth-indicators". ++ * Multiple indicators might be present in the ticket. ++ * Each indicator is a utf8 string. */ ++ ++#define AUTH_INDICATORS_TAG "auth-indicators" ++ ++/* Privileged (called from accept_secure_ctx) */ ++static OM_uint32 ++ssh_gssapi_getindicators(Gssctxt *ctx, gss_name_t gss_name, ssh_gssapi_client *client) ++{ ++ gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET; ++ gss_buffer_desc value = GSS_C_EMPTY_BUFFER; ++ gss_buffer_desc display_value = GSS_C_EMPTY_BUFFER; ++ int is_mechname, authenticated, complete, more; ++ size_t count, i; ++ ++ ctx->major = gss_inquire_name(&ctx->minor, gss_name, ++ &is_mechname, NULL, &attrs); ++ if (ctx->major != GSS_S_COMPLETE) { ++ return (ctx->major); ++ } ++ ++ if (attrs == GSS_C_NO_BUFFER_SET) { ++ /* No indicators in the ticket */ ++ return (0); ++ } ++ ++ count = 0; ++ for (i = 0; i < attrs->count; i++) { ++ /* skip anything but auth-indicators */ ++ if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) || ++ strncmp(AUTH_INDICATORS_TAG, ++ attrs->elements[i].value, ++ sizeof(AUTH_INDICATORS_TAG) - 1) != 0) ++ continue; ++ count++; ++ } ++ ++ if (count == 0) { ++ /* No auth-indicators in the ticket */ ++ (void) gss_release_buffer_set(&ctx->minor, &attrs); ++ return (0); ++ } ++ ++ client->indicators = recallocarray(NULL, 0, count + 1, sizeof(char*)); ++ count = 0; ++ for (i = 0; i < attrs->count; i++) { ++ authenticated = 0; ++ complete = 0; ++ more = -1; ++ /* skip anything but auth-indicators */ ++ if (((sizeof(AUTH_INDICATORS_TAG) - 1) != attrs->elements[i].length) || ++ strncmp(AUTH_INDICATORS_TAG, ++ attrs->elements[i].value, ++ sizeof(AUTH_INDICATORS_TAG) - 1) != 0) ++ continue; ++ /* retrieve all indicators */ ++ while (more != 0) { ++ value.value = NULL; ++ display_value.value = NULL; ++ ctx->major = gss_get_name_attribute(&ctx->minor, gss_name, ++ &attrs->elements[i], &authenticated, ++ &complete, &value, &display_value, &more); ++ if (ctx->major != GSS_S_COMPLETE) { ++ goto out; ++ } ++ ++ if ((value.value != NULL) && authenticated) { ++ client->indicators[count] = xmalloc(value.length + 1); ++ memcpy(client->indicators[count], value.value, value.length); ++ client->indicators[count][value.length] = '\0'; ++ count++; ++ } ++ } ++ } ++ ++out: ++ (void) gss_release_buffer(&ctx->minor, &value); ++ (void) gss_release_buffer(&ctx->minor, &display_value); ++ (void) gss_release_buffer_set(&ctx->minor, &attrs); ++ return (ctx->major); ++} ++ ++ + /* Extract the client details from a given context. This can only reliably + * be called once for a context */ + +@@ -385,6 +471,12 @@ ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client) + } + + gss_release_buffer(&ctx->minor, &ename); ++ /* Retrieve authentication indicators, if they exist */ ++ if ((ctx->major = ssh_gssapi_getindicators(ctx, ++ ctx->client, client))) { ++ ssh_gssapi_error(ctx); ++ return (ctx->major); ++ } + + /* We can't copy this structure, so we just move the pointer to it */ + client->creds = ctx->client_creds; +@@ -447,6 +539,7 @@ int + ssh_gssapi_userok(char *user, struct passwd *pw, int kex) + { + OM_uint32 lmin; ++ size_t i; + + (void) kex; /* used in privilege separation */ + +@@ -465,6 +558,14 @@ ssh_gssapi_userok(char *user, struct passwd *pw, int kex) + gss_release_buffer(&lmin, &gssapi_client.displayname); + gss_release_buffer(&lmin, &gssapi_client.exportedname); + gss_release_cred(&lmin, &gssapi_client.creds); ++ ++ if (gssapi_client.indicators != NULL) { ++ for(i = 0; gssapi_client.indicators[i] != NULL; i++) { ++ free(gssapi_client.indicators[i]); ++ } ++ free(gssapi_client.indicators); ++ } ++ + explicit_bzero(&gssapi_client, + sizeof(ssh_gssapi_client)); + return 0; +diff --git a/servconf.c b/servconf.c +index e7e4ad046..aab653244 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -147,6 +147,7 @@ initialize_server_options(ServerOptions *options) + options->gss_strict_acceptor = -1; + options->gss_store_rekey = -1; + options->gss_kex_algorithms = NULL; ++ options->gss_indicators = NULL; + options->use_kuserok = -1; + options->enable_k5users = -1; + options->password_authentication = -1; +@@ -598,7 +599,7 @@ typedef enum { + sPerSourcePenalties, sPerSourcePenaltyExemptList, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, +- sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, ++ sGssKeyEx, sGssIndicators, sGssKexAlgorithms, sGssStoreRekey, + sAcceptEnv, sSetEnv, sPermitTunnel, + sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory, + sUsePrivilegeSeparation, sAllowAgentForwarding, +@@ -694,6 +695,7 @@ static struct { + { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, + { "gssapikexalgorithms", sGssKexAlgorithms, SSHCFG_GLOBAL }, + { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL }, ++ { "gssapiindicators", sGssIndicators, SSHCFG_ALL }, + #else + { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapicleanupcredentials", sUnsupported, SSHCFG_GLOBAL }, +@@ -703,6 +705,7 @@ static struct { + { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, + { "gssapikexalgorithms", sUnsupported, SSHCFG_GLOBAL }, + { "gssapienablek5users", sUnsupported, SSHCFG_ALL }, ++ { "gssapiindicators", sUnsupported, SSHCFG_ALL }, + #endif + { "gssusesessionccache", sUnsupported, SSHCFG_GLOBAL }, + { "gssapiusesessioncredcache", sUnsupported, SSHCFG_GLOBAL }, +@@ -1730,6 +1733,15 @@ process_server_config_line_depth(ServerOptions *options, char *line, + options->gss_kex_algorithms = xstrdup(arg); + break; + ++ case sGssIndicators: ++ arg = argv_next(&ac, &av); ++ if (!arg || *arg == '\0') ++ fatal("%s line %d: %s missing argument.", ++ filename, linenum, keyword); ++ if (options->gss_indicators == NULL) ++ options->gss_indicators = xstrdup(arg); ++ break; ++ + case sPasswordAuthentication: + intptr = &options->password_authentication; + goto parse_flag; +@@ -3351,6 +3363,7 @@ dump_config(ServerOptions *o) + dump_cfg_fmtint(sGssStrictAcceptor, o->gss_strict_acceptor); + dump_cfg_fmtint(sGssStoreRekey, o->gss_store_rekey); + dump_cfg_string(sGssKexAlgorithms, o->gss_kex_algorithms); ++ dump_cfg_string(sGssIndicators, o->gss_indicators); + #endif + dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); + dump_cfg_fmtint(sKbdInteractiveAuthentication, +diff --git a/servconf.h b/servconf.h +index 7c7e5d434..7c41df417 100644 +--- a/servconf.h ++++ b/servconf.h +@@ -181,6 +181,7 @@ typedef struct { + char **allow_groups; + u_int num_deny_groups; + char **deny_groups; ++ char *gss_indicators; + + u_int num_subsystems; + char **subsystem_name; +@@ -310,6 +311,7 @@ TAILQ_HEAD(include_list, include_item); + M_CP_STROPT(routing_domain); \ + M_CP_STROPT(permit_user_env_allowlist); \ + M_CP_STROPT(pam_service_name); \ ++ M_CP_STROPT(gss_indicators); \ + M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \ + M_CP_STRARRAYOPT(allow_users, num_allow_users); \ + M_CP_STRARRAYOPT(deny_users, num_deny_users); \ +diff --git a/ssh-gss.h b/ssh-gss.h +index a894e23c9..59cf46d47 100644 +--- a/ssh-gss.h ++++ b/ssh-gss.h +@@ -34,6 +34,12 @@ + #include + #endif + ++#ifdef HAVE_GSSAPI_EXT_H ++#include ++#elif defined(HAVE_GSSAPI_GSSAPI_EXT_H) ++#include ++#endif ++ + #ifdef KRB5 + # ifndef HEIMDAL + # ifdef HAVE_GSSAPI_GENERIC_H +@@ -107,6 +113,7 @@ typedef struct { + ssh_gssapi_ccache store; + int used; + int updated; ++ char **indicators; /* auth indicators */ + } ssh_gssapi_client; + + typedef struct ssh_gssapi_mech_struct { +diff --git a/sshd_config.5 b/sshd_config.5 +index 583a01cdb..90ab87edd 100644 +--- a/sshd_config.5 ++++ b/sshd_config.5 +@@ -785,6 +785,50 @@ gss-nistp256-sha256- + gss-curve25519-sha256- + .Ed + This option only applies to connections using GSSAPI. ++.It Cm GSSAPIIndicators ++Specifies whether to accept or deny GSSAPI authenticated access if Kerberos ++mechanism is used and Kerberos ticket contains a particular set of ++authentication indicators. The values can be specified as a comma-separated list ++.Cm [!]name1,[!]name2,... . ++When indicator's name is prefixed with !, the authentication indicator 'name' ++will deny access to the system. Otherwise, one of non-negated authentication ++indicators must be present in the Kerberos ticket to allow access. If ++.Cm GSSAPIIndicators ++is defined, a Kerberos ticket that has indicators but does not match the ++policy will get denial. If at least one indicator is configured, whether for ++access or denial, tickets without authentication indicators will be explicitly ++rejected. ++.Pp ++By default systems using MIT Kerberos 1.17 or later will not assign any ++indicators. SPAKE and PKINIT methods add authentication indicators ++to all successful authentications. The SPAKE pre-authentication method is ++preferred over an encrypted timestamp pre-authentication when passwords used to ++authenticate user principals. Kerberos KDCs built with Heimdal Kerberos ++(including Samba AD DC built with Heimdal) do not add authentication ++indicators. However, OpenSSH built against Heimdal Kerberos library is able to ++inquire authentication indicators and thus can be used to check for their presence. ++.Pp ++Indicator name is case-sensitive and depends on the configuration of a ++particular Kerberos deployment. Indicators available in MIT Kerberos and ++FreeIPA environments: ++.Pp ++.Bl -tag -width XXXX -offset indent -compact ++.It Cm hardened ++SPAKE or encrypted timestamp pre-authentication mechanisms in MIT Kerberos and FreeIPA ++.It Cm pkinit ++smartcard or PKCS11 token-based pre-authentication in MIT Kerberos and FreeIPA ++.It Cm radius ++pre-authentication based on a RADIUS server in MIT Kerberos and FreeIPA ++.It Cm otp ++TOTP/HOTP-based two-factor pre-authentication in FreeIPA ++.It Cm idp ++OAuth2-based pre-authentication in FreeIPA using an external identity provider ++and device authorization grant flow ++.It Cm passkey ++FIDO2-based pre-authentication in FreeIPA, using FIDO2 USB and NFC tokens ++.El ++.Pp ++The default is to not use GSSAPI authentication indicators for access decisions. + .It Cm HostbasedAcceptedAlgorithms + The default is handled system-wide by + .Xr crypto-policies 7 . +-- +2.49.0 + diff --git a/1000-openssh-coverity.patch b/1000-openssh-coverity.patch new file mode 100644 index 0000000..88362eb --- /dev/null +++ b/1000-openssh-coverity.patch @@ -0,0 +1,257 @@ +From 24c411970682dc67873c36bac05b4b460d68a628 Mon Sep 17 00:00:00 2001 +From: Dmitry Belyavskiy +Date: Thu, 15 May 2025 13:43:29 +0200 +Subject: [PATCH 50/50] 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 +- + ssh-agent.c | 1 + + ssh-keygen.c | 3 +++ + 13 files changed, 28 insertions(+), 11 deletions(-) + +diff --git a/auth-krb5.c b/auth-krb5.c +index bae153c9..209a3265 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 3034370c..c357e973 100644 +--- a/gss-genr.c ++++ b/gss-genr.c +@@ -168,8 +168,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 0d0f6953..d8517f12 100644 +--- a/krl.c ++++ b/krl.c +@@ -1202,6 +1202,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; +@@ -1212,6 +1213,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; +@@ -1223,6 +1225,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 c4a9bd48..2583612c 100644 +--- a/loginrec.c ++++ b/loginrec.c +@@ -683,9 +683,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 09722962..cd71c1b2 100644 +--- a/misc.c ++++ b/misc.c +@@ -1556,6 +1556,8 @@ sanitise_stdfd(void) + } + if (nullfd > STDERR_FILENO) + close(nullfd); ++ /* coverity[leaked_handle : FALSE]*/ ++ /* coverity[leaked_handle : FALSE]*/ + } + + char * +@@ -2749,6 +2751,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 19cb058e..58fbac9d 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -415,7 +415,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) + ; + + if (pmonitor->m_recvfd >= 0) +@@ -1813,7 +1813,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 346c7fe5..f42792fd 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 26bdc3e0..8e2939b9 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 ea9d293c..9680c38c 100644 +--- a/readconf.c ++++ b/readconf.c +@@ -2164,6 +2164,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 8b708cbf..e7e4ad04 100644 +--- a/servconf.c ++++ b/servconf.c +@@ -2293,8 +2293,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 9c5b1567..768ee9fa 100644 +--- a/serverloop.c ++++ b/serverloop.c +@@ -511,7 +511,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 --git a/ssh-agent.c b/ssh-agent.c +index 798bf9b6..0e39dff7 100644 +--- a/ssh-agent.c ++++ b/ssh-agent.c +@@ -1593,6 +1593,7 @@ sanitize_pkcs11_provider(const char *provider) + + 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 --git a/ssh-keygen.c b/ssh-keygen.c +index 792aafde..96b3474d 100644 +--- a/ssh-keygen.c ++++ b/ssh-keygen.c +@@ -2424,6 +2424,9 @@ update_krl_from_file(struct passwd *pw, const char *file, int wild_ca, + 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; +-- +2.49.0 + diff --git a/openssh-9.3p1-gsissh.patch b/2000-openssh-10.0p1-gsissh.patch similarity index 81% rename from openssh-9.3p1-gsissh.patch rename to 2000-openssh-10.0p1-gsissh.patch index acf160d..4a1a329 100644 --- a/openssh-9.3p1-gsissh.patch +++ b/2000-openssh-10.0p1-gsissh.patch @@ -1,7 +1,7 @@ -diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c ---- openssh-9.3p1.orig/auth2.c 2023-06-26 17:34:46.576956191 +0200 -+++ openssh-9.3p1/auth2.c 2023-06-26 17:36:05.807175554 +0200 -@@ -275,7 +275,28 @@ +diff -Nur openssh-10.0p1.orig/auth2.c openssh-10.0p1/auth2.c +--- openssh-10.0p1.orig/auth2.c 2025-06-14 08:24:55.444264765 +0200 ++++ openssh-10.0p1/auth2.c 2025-06-14 08:25:50.314922659 +0200 +@@ -286,7 +286,28 @@ (r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 || (r = sshpkt_get_cstring(ssh, &method, NULL)) != 0) goto out; @@ -12,7 +12,7 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c + debug("received empty username for %s", method); + if (strcmp(method, "gssapi-keyex") == 0) { + char *lname = NULL; -+ PRIVSEP(ssh_gssapi_localname(&lname)); ++ mm_ssh_gssapi_localname(&lname); + if (lname && lname[0] != '\0') { + free(user); + user = lname; @@ -31,13 +31,13 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); #ifdef WITH_SELINUX -@@ -288,11 +309,33 @@ +@@ -299,11 +320,33 @@ if (authctxt->attempt >= 1024) auth_maxtries_exceeded(ssh); - if (authctxt->attempt++ == 0) { - /* setup auth context */ -- authctxt->pw = PRIVSEP(getpwnamallow(ssh, user)); +- authctxt->pw = mm_getpwnamallow(ssh, user); + /* If first time or username changed or empty username, + setup/reset authentication context. */ + if ((authctxt->attempt++ == 0) || @@ -64,12 +64,12 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c + authctxt->pw = fakepw(); + } else { +#endif -+ authctxt->pw = PRIVSEP(getpwnamallow(ssh, user)); ++ authctxt->pw = mm_getpwnamallow(ssh, user); + if (authctxt->pw) { authctxt->valid = 1; debug2_f("setting up authctxt for %s", user); } else { -@@ -300,6 +343,9 @@ +@@ -311,6 +354,9 @@ /* Invalid user, fake password information */ authctxt->pw = fakepw(); } @@ -78,16 +78,16 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c +#endif #ifdef USE_PAM if (options.use_pam) - PRIVSEP(start_pam(ssh)); -@@ -308,6 +354,7 @@ + mm_start_pam(ssh); +@@ -318,6 +364,7 @@ + ssh_packet_set_log_preamble(ssh, "%suser %s", authctxt->valid ? "authenticating " : "invalid ", user); - setproctitle("%s%s", authctxt->valid ? user : "unknown", - use_privsep ? " [net]" : ""); + setproctitle("%s [net]", authctxt->valid ? user : "unknown"); + if (authctxt->attempt == 1) { authctxt->service = xstrdup(service); authctxt->style = style ? xstrdup(style) : NULL; #ifdef WITH_SELINUX -@@ -323,9 +370,10 @@ +@@ -333,9 +380,10 @@ if (auth2_setup_methods_lists(authctxt) != 0) ssh_packet_disconnect(ssh, "no authentication methods enabled"); @@ -101,18 +101,18 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c "not allowed: (%s,%s) -> (%s,%s)", authctxt->user, authctxt->service, user, service); } -diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c ---- openssh-9.3p1.orig/auth2-gss.c 2023-06-26 17:34:46.462955875 +0200 -+++ openssh-9.3p1/auth2-gss.c 2023-06-26 17:36:05.808175557 +0200 -@@ -50,6 +50,7 @@ - - extern ServerOptions options; +diff -Nur openssh-10.0p1.orig/auth2-gss.c openssh-10.0p1/auth2-gss.c +--- openssh-10.0p1.orig/auth2-gss.c 2025-06-14 08:24:54.946580198 +0200 ++++ openssh-10.0p1/auth2-gss.c 2025-06-14 08:25:50.315696363 +0200 +@@ -54,6 +54,7 @@ + extern struct authmethod_cfg methodcfg_gsskeyex; + extern struct authmethod_cfg methodcfg_gssapi; +static void ssh_gssapi_userauth_error(Gssctxt *ctxt, struct ssh *ssh); static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh); 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); -@@ -63,8 +64,8 @@ +@@ -67,8 +68,8 @@ { Authctxt *authctxt = ssh->authctxt; int r, authenticated = 0; @@ -123,7 +123,7 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c u_char *p; size_t len; -@@ -75,6 +76,9 @@ +@@ -79,6 +80,9 @@ if ((b = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); @@ -133,7 +133,7 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c mic.value = p; mic.length = len; -@@ -85,13 +89,29 @@ +@@ -89,13 +93,28 @@ fatal_f("sshbuf_mutable_ptr failed"); gssbuf.length = sshbuf_len(b); @@ -147,17 +147,16 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c + gssbuf2.length = sshbuf_len(b2); + /* gss_kex_context is NULL with privsep, so we can't check it here */ - if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -- &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -- authctxt->pw, 1)); -+ &gssbuf, &mic))) || -+ !GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gss_kex_context, -+ &gssbuf2, &mic)))) { + if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gss_kex_context, +- &gssbuf, &mic))) +- authenticated = mm_ssh_gssapi_userok(authctxt->user, +- authctxt->pw, 1); ++ &gssbuf, &mic)) || ++ !GSS_ERROR(mm_ssh_gssapi_checkmic(gss_kex_context, ++ &gssbuf2, &mic))) { + if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = -+ PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1); + } + } @@ -166,7 +165,7 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c free(mic.value); return (authenticated); -@@ -146,7 +166,9 @@ +@@ -154,7 +173,9 @@ return (0); } @@ -177,7 +176,7 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c debug2_f("disabled because of invalid user"); free(doid); return (0); -@@ -184,7 +206,7 @@ +@@ -192,7 +213,7 @@ Gssctxt *gssctxt; gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; gss_buffer_desc recv_tok; @@ -186,7 +185,7 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c u_char *p; size_t len; int r; -@@ -205,6 +227,7 @@ +@@ -213,6 +234,7 @@ free(p); if (GSS_ERROR(maj_status)) { @@ -194,7 +193,7 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c if (send_tok.length != 0) { if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK)) != 0 || -@@ -279,6 +302,34 @@ +@@ -287,6 +309,34 @@ return 0; } @@ -205,17 +204,17 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c + char *lname = NULL; + + if ((authctxt->user == NULL) || (authctxt->user[0] == '\0')) { -+ PRIVSEP(ssh_gssapi_localname(&lname)); ++ mm_ssh_gssapi_localname(&lname); + if (lname && lname[0] != '\0') { + if (authctxt->user) free(authctxt->user); + authctxt->user = lname; + debug("set username to %s from gssapi context", lname); -+ authctxt->pw = PRIVSEP(getpwnamallow(ssh, authctxt->user)); ++ authctxt->pw = mm_getpwnamallow(ssh, authctxt->user); + if (authctxt->pw) { + authctxt->valid = 1; +#ifdef USE_PAM + if (options.use_pam) -+ PRIVSEP(start_pam(ssh)); ++ mm_start_pam(ssh); +#endif + } + } else { @@ -229,15 +228,14 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c /* * This is called when the client thinks we've completed authentication. * It should only be enabled in the dispatch handler by the function above, -@@ -289,12 +340,14 @@ +@@ -297,11 +347,13 @@ input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; - int r, authenticated; + int r, authenticated = 0; - const char *displayname; - if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) + if (authctxt == NULL) fatal("No authentication or GSSAPI context"); + gssapi_set_username(ssh); @@ -245,35 +243,32 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c /* * We don't need to check the status, because we're only enabled in * the dispatcher once the exchange is complete -@@ -303,8 +356,11 @@ +@@ -310,7 +362,11 @@ if ((r = sshpkt_get_end(ssh)) != 0) fatal_fr(r, "parse packet"); -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -- authctxt->pw, 1)); +- authenticated = mm_ssh_gssapi_userok(authctxt->user, authctxt->pw, 1); + /* user should be set if valid but we double-check here */ + if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 1)); ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 1); + } - if ((!use_privsep || mm_is_monitor()) && - (displayname = ssh_gssapi_displayname()) != NULL) -@@ -356,11 +412,17 @@ + authctxt->postponed = 0; + ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); +@@ -357,10 +413,16 @@ fatal_f("sshbuf_mutable_ptr failed"); gssbuf.length = sshbuf_len(b); -- if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) -- authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user, -- authctxt->pw, 0)); +- if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))) +- authenticated = mm_ssh_gssapi_userok(authctxt->user, authctxt->pw, 0); - else + gssapi_set_username(ssh); + -+ if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) { ++ if (!GSS_ERROR(mm_ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))) { + if (authctxt->valid && authctxt->user && authctxt->user[0]) { -+ authenticated = -+ PRIVSEP(ssh_gssapi_userok(authctxt->user, -+ authctxt->pw, 0)); ++ authenticated = mm_ssh_gssapi_userok(authctxt->user, ++ authctxt->pw, 0); + } + } else { logit("GSSAPI MIC check failed"); @@ -281,7 +276,7 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c sshbuf_free(b); if (micuser != authctxt->user) -@@ -380,6 +442,26 @@ +@@ -376,6 +438,26 @@ return 0; } @@ -290,7 +285,7 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c + OM_uint32 maj, min; + int r; + -+ errstr = PRIVSEP(ssh_gssapi_last_error(ctxt, &maj, &min)); ++ errstr = mm_ssh_gssapi_last_error(ctxt, &maj, &min); + if (errstr) { + if ((r = sshpkt_start(ssh, + SSH2_MSG_USERAUTH_GSSAPI_ERROR)) != 0 || @@ -306,12 +301,12 @@ diff -Nur openssh-9.3p1.orig/auth2-gss.c openssh-9.3p1/auth2-gss.c +} + Authmethod method_gsskeyex = { - "gssapi-keyex", - NULL, -diff -Nur openssh-9.3p1.orig/auth.c openssh-9.3p1/auth.c ---- openssh-9.3p1.orig/auth.c 2023-06-26 17:34:46.577956193 +0200 -+++ openssh-9.3p1/auth.c 2023-06-26 17:36:05.808175557 +0200 -@@ -299,7 +299,8 @@ + &methodcfg_gsskeyex, + userauth_gsskeyex, +diff -Nur openssh-10.0p1.orig/auth.c openssh-10.0p1/auth.c +--- openssh-10.0p1.orig/auth.c 2025-06-14 08:24:55.443524655 +0200 ++++ openssh-10.0p1/auth.c 2025-06-14 08:25:50.316281495 +0200 +@@ -298,7 +298,8 @@ method, submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod, authctxt->valid ? "" : "invalid user ", @@ -321,7 +316,7 @@ diff -Nur openssh-9.3p1.orig/auth.c openssh-9.3p1/auth.c ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), extra != NULL ? ": " : "", -@@ -487,13 +488,18 @@ +@@ -490,13 +491,18 @@ #endif pw = getpwnam(user); @@ -341,9 +336,9 @@ diff -Nur openssh-9.3p1.orig/auth.c openssh-9.3p1/auth.c #ifdef CUSTOM_FAILED_LOGIN record_failed_login(ssh, user, auth_get_canonical_hostname(ssh, options.use_dns), "ssh"); -diff -Nur openssh-9.3p1.orig/auth.h openssh-9.3p1/auth.h ---- openssh-9.3p1.orig/auth.h 2023-06-26 17:34:46.578956196 +0200 -+++ openssh-9.3p1/auth.h 2023-06-26 17:36:05.809175560 +0200 +diff -Nur openssh-10.0p1.orig/auth.h openssh-10.0p1/auth.h +--- openssh-10.0p1.orig/auth.h 2025-06-14 08:24:55.443709595 +0200 ++++ openssh-10.0p1/auth.h 2025-06-14 08:25:50.316833592 +0200 @@ -85,6 +85,8 @@ krb5_principal krb5_user; char *krb5_ticket_file; @@ -353,10 +348,10 @@ diff -Nur openssh-9.3p1.orig/auth.h openssh-9.3p1/auth.h int krb5_set_env; #endif struct sshbuf *loginmsg; -diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c ---- openssh-9.3p1.orig/auth-pam.c 2023-06-26 17:34:46.562956152 +0200 -+++ openssh-9.3p1/auth-pam.c 2023-06-26 17:45:46.130781404 +0200 -@@ -252,6 +252,7 @@ +diff -Nur openssh-10.0p1.orig/auth-pam.c openssh-10.0p1/auth-pam.c +--- openssh-10.0p1.orig/auth-pam.c 2025-06-14 08:24:55.609208310 +0200 ++++ openssh-10.0p1/auth-pam.c 2025-06-14 08:25:50.317378775 +0200 +@@ -248,6 +248,7 @@ static const char *sshpam_password = NULL; static char *sshpam_rhost = NULL; static char *sshpam_laddr = NULL; @@ -364,7 +359,7 @@ diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c /* Some PAM implementations don't implement this */ #ifndef HAVE_PAM_GETENVLIST -@@ -300,6 +301,56 @@ +@@ -296,6 +297,56 @@ # define pam_chauthtok(a,b) (sshpam_chauthtok_ruid((a), (b))) #endif @@ -421,7 +416,7 @@ diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c static void sshpam_password_change_required(int reqd) { -@@ -331,7 +382,7 @@ +@@ -327,7 +378,7 @@ static void import_environments(struct sshbuf *b) { @@ -430,7 +425,7 @@ diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c u_int n, i, num_env; int r; -@@ -347,6 +398,19 @@ +@@ -343,6 +394,19 @@ if ((r = sshbuf_get_u32(b, &n)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); sshpam_password_change_required(n != 0); @@ -450,7 +445,7 @@ diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c /* Import environment from subprocess */ if ((r = sshbuf_get_u32(b, &num_env)) != 0) -@@ -526,6 +590,13 @@ +@@ -522,6 +586,13 @@ if (sshpam_err != PAM_SUCCESS) goto auth_fail; @@ -464,7 +459,7 @@ diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c if (!do_pam_account()) { /* Preserve PAM_PERM_DENIED and PAM_USER_UNKNOWN. * Backward compatibility for other errors. */ -@@ -550,6 +621,13 @@ +@@ -546,6 +617,13 @@ if ((r = sshbuf_put_u32(buffer, sshpam_account_status)) != 0 || (r = sshbuf_put_u32(buffer, sshpam_authctxt->force_pwchange)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); @@ -485,9 +480,9 @@ diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c + /* Save so allowed_user can be called later */ + sshpam_ssh = ssh; } - if (sshpam_rhost != NULL) { + if (sshpam_rhost != NULL && strcmp(sshpam_rhost, "UNKNOWN") != 0) { debug("PAM: setting PAM_RHOST to \"%s\"", sshpam_rhost); -@@ -1094,6 +1174,18 @@ +@@ -1096,6 +1176,18 @@ debug3("PAM: %s pam_acct_mgmt = %d (%s)", __func__, sshpam_err, pam_strerror(sshpam_handle, sshpam_err)); @@ -506,8 +501,8 @@ diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c if (sshpam_err != PAM_SUCCESS && sshpam_err != PAM_NEW_AUTHTOK_REQD) { sshpam_account_status = 0; return (sshpam_account_status); -@@ -1382,6 +1474,9 @@ - pam_strerror(sshpam_handle, sshpam_err)); +@@ -1384,6 +1476,9 @@ + expose_authinfo(__func__); sshpam_err = pam_authenticate(sshpam_handle, flags); + if (options.permit_pam_user_change) { @@ -516,9 +511,9 @@ diff -Nur openssh-9.3p1.orig/auth-pam.c openssh-9.3p1/auth-pam.c sshpam_password = NULL; free(fake); if (sshpam_err == PAM_MAXTRIES) -diff -Nur openssh-9.3p1.orig/auth-pam.h openssh-9.3p1/auth-pam.h ---- openssh-9.3p1.orig/auth-pam.h 2023-06-26 17:34:46.430955786 +0200 -+++ openssh-9.3p1/auth-pam.h 2023-06-26 17:36:05.812175568 +0200 +diff -Nur openssh-10.0p1.orig/auth-pam.h openssh-10.0p1/auth-pam.h +--- openssh-10.0p1.orig/auth-pam.h 2025-06-14 08:24:54.755199761 +0200 ++++ openssh-10.0p1/auth-pam.h 2025-06-14 08:25:50.318085082 +0200 @@ -43,5 +43,6 @@ int sshpam_get_maxtries_reached(void); void sshpam_set_maxtries_reached(int); @@ -526,9 +521,9 @@ diff -Nur openssh-9.3p1.orig/auth-pam.h openssh-9.3p1/auth-pam.h +struct passwd *sshpam_getpw(const char *); #endif /* USE_PAM */ -diff -Nur openssh-9.3p1.orig/canohost.c openssh-9.3p1/canohost.c ---- openssh-9.3p1.orig/canohost.c 2023-06-26 17:34:46.463955878 +0200 -+++ openssh-9.3p1/canohost.c 2023-06-26 17:36:05.812175568 +0200 +diff -Nur openssh-10.0p1.orig/canohost.c openssh-10.0p1/canohost.c +--- openssh-10.0p1.orig/canohost.c 2025-06-14 08:24:54.947106244 +0200 ++++ openssh-10.0p1/canohost.c 2025-06-14 08:25:50.318537655 +0200 @@ -17,6 +17,7 @@ #include #include @@ -537,7 +532,7 @@ diff -Nur openssh-9.3p1.orig/canohost.c openssh-9.3p1/canohost.c #include #include -@@ -298,3 +299,33 @@ +@@ -300,3 +301,33 @@ { return get_sock_port(sock, 1); } @@ -571,9 +566,9 @@ diff -Nur openssh-9.3p1.orig/canohost.c openssh-9.3p1/canohost.c + } + } +} -diff -Nur openssh-9.3p1.orig/canohost.h openssh-9.3p1/canohost.h ---- openssh-9.3p1.orig/canohost.h 2023-06-26 17:34:46.463955878 +0200 -+++ openssh-9.3p1/canohost.h 2023-06-26 17:36:05.813175570 +0200 +diff -Nur openssh-10.0p1.orig/canohost.h openssh-10.0p1/canohost.h +--- openssh-10.0p1.orig/canohost.h 2025-06-14 08:24:54.947234403 +0200 ++++ openssh-10.0p1/canohost.h 2025-06-14 08:25:50.318980799 +0200 @@ -26,4 +26,6 @@ #endif /* _CANOHOST_H */ @@ -581,10 +576,10 @@ diff -Nur openssh-9.3p1.orig/canohost.h openssh-9.3p1/canohost.h +void resolve_localhost(char **host); + void ipv64_normalise_mapped(struct sockaddr_storage *, socklen_t *); -diff -Nur openssh-9.3p1.orig/configure.ac openssh-9.3p1/configure.ac ---- openssh-9.3p1.orig/configure.ac 2023-06-26 17:34:46.553956127 +0200 -+++ openssh-9.3p1/configure.ac 2023-06-26 17:36:05.814175573 +0200 -@@ -4858,6 +4858,14 @@ +diff -Nur openssh-10.0p1.orig/configure.ac openssh-10.0p1/configure.ac +--- openssh-10.0p1.orig/configure.ac 2025-06-14 08:24:55.711190794 +0200 ++++ openssh-10.0p1/configure.ac 2025-06-14 08:25:50.319884827 +0200 +@@ -4992,6 +4992,14 @@ AC_CHECK_HEADER([gssapi_krb5.h], , [ CPPFLAGS="$oldCPP" ]) @@ -599,7 +594,7 @@ diff -Nur openssh-9.3p1.orig/configure.ac openssh-9.3p1/configure.ac fi fi if test -n "${rpath_opt}" ; then -@@ -4899,6 +4907,40 @@ +@@ -5034,6 +5042,40 @@ AC_SUBST([K5LIBS]) AC_SUBST([CHANNELLIBS]) @@ -637,12 +632,12 @@ diff -Nur openssh-9.3p1.orig/configure.ac openssh-9.3p1/configure.ac + AC_CHECK_FUNCS(globus_gss_assist_map_and_authorize) +fi + - # Check whether user wants systemd support - SYSTEMD_MSG="no" - AC_ARG_WITH(systemd, -diff -Nur openssh-9.3p1.orig/gss-genr.c openssh-9.3p1/gss-genr.c ---- openssh-9.3p1.orig/gss-genr.c 2023-06-26 17:34:46.623956321 +0200 -+++ openssh-9.3p1/gss-genr.c 2023-06-26 17:36:05.815175576 +0200 + # Looking for programs, paths and files + + PRIVSEP_PATH=/var/empty +diff -Nur openssh-10.0p1.orig/gss-genr.c openssh-10.0p1/gss-genr.c +--- openssh-10.0p1.orig/gss-genr.c 2025-06-14 08:24:55.730946369 +0200 ++++ openssh-10.0p1/gss-genr.c 2025-06-14 08:25:50.321274952 +0200 @@ -41,6 +41,7 @@ #include "ssherr.h" #include "sshbuf.h" @@ -651,7 +646,7 @@ diff -Nur openssh-9.3p1.orig/gss-genr.c openssh-9.3p1/gss-genr.c #include "ssh2.h" #include "cipher.h" #include "sshkey.h" -@@ -409,9 +410,18 @@ +@@ -416,9 +417,18 @@ ssh_gssapi_import_name(Gssctxt *ctx, const char *host) { gss_buffer_desc gssbuf; @@ -671,7 +666,7 @@ diff -Nur openssh-9.3p1.orig/gss-genr.c openssh-9.3p1/gss-genr.c gssbuf.value = val; gssbuf.length = strlen(gssbuf.value); -@@ -419,6 +429,7 @@ +@@ -426,6 +436,7 @@ &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &ctx->name))) ssh_gssapi_error(ctx); @@ -679,10 +674,10 @@ diff -Nur openssh-9.3p1.orig/gss-genr.c openssh-9.3p1/gss-genr.c free(gssbuf.value); return (ctx->major); } -diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c ---- openssh-9.3p1.orig/gss-serv.c 2023-06-26 17:34:46.483955933 +0200 -+++ openssh-9.3p1/gss-serv.c 2023-06-26 17:36:05.816175578 +0200 -@@ -50,10 +50,12 @@ +diff -Nur openssh-10.0p1.orig/gss-serv.c openssh-10.0p1/gss-serv.c +--- openssh-10.0p1.orig/gss-serv.c 2025-06-14 08:24:55.712377680 +0200 ++++ openssh-10.0p1/gss-serv.c 2025-06-14 14:29:38.679799497 +0200 +@@ -51,10 +51,12 @@ #include "monitor_wrap.h" extern ServerOptions options; @@ -690,14 +685,14 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c 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}; + { {0, NULL}, GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER, GSS_C_NO_CREDENTIAL, + GSS_C_NO_NAME, GSS_C_NO_NAME, NULL, {NULL, NULL, NULL, NULL, NULL}, -+ GSS_C_NO_CONTEXT, 0, 0}; ++ GSS_C_NO_CONTEXT, 0, 0, NULL}; ssh_gssapi_mech gssapi_null_mech = { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL, NULL}; -@@ -61,14 +63,26 @@ +@@ -62,14 +64,26 @@ #ifdef KRB5 extern ssh_gssapi_mech gssapi_kerberos_mech; #endif @@ -724,7 +719,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c /* * ssh_gssapi_supported_oids() can cause sandbox violations, so prepare the * list of supported mechanisms before privsep is set up. -@@ -229,6 +243,10 @@ +@@ -230,6 +244,10 @@ (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) { if (ssh_gssapi_getclient(ctx, &gssapi_client)) fatal("Couldn't convert client name"); @@ -735,7 +730,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c } return (status); -@@ -248,6 +266,20 @@ +@@ -249,6 +267,20 @@ tok = ename->value; @@ -756,7 +751,23 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c /* * Check that ename is long enough for all of the fixed length * header, and that the initial ID bytes are correct -@@ -308,21 +340,24 @@ +@@ -297,6 +329,7 @@ + } + + ++#ifdef KRB5 + /* 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. +@@ -380,6 +413,7 @@ + (void) gss_release_buffer_set(&ctx->minor, &attrs); + return (ctx->major); + } ++#endif + + + /* Extract the client details from a given context. This can only reliably +@@ -395,21 +429,24 @@ gss_buffer_desc ename = GSS_C_EMPTY_BUFFER; if (options.gss_store_rekey && client->used && ctx->client_creds) { @@ -786,7 +797,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c new_name, &equal); if (GSS_ERROR(ctx->major)) { -@@ -337,9 +372,9 @@ +@@ -424,9 +461,9 @@ debug("Marking rekeyed credentials for export"); @@ -798,7 +809,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c client->creds = ctx->client_creds; ctx->client_creds = GSS_C_NO_CREDENTIAL; client->updated = 1; -@@ -356,12 +391,17 @@ +@@ -443,12 +480,17 @@ i++; } @@ -818,7 +829,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c ssh_gssapi_error(ctx); return (ctx->major); } -@@ -378,16 +418,25 @@ +@@ -465,22 +507,33 @@ return (ctx->major); } @@ -834,6 +845,14 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c + return ctx->major; + gss_release_buffer(&ctx->minor, &ename); ++#ifdef KRB5 + /* Retrieve authentication indicators, if they exist */ + if ((ctx->major = ssh_gssapi_getindicators(ctx, + ctx->client, client))) { + ssh_gssapi_error(ctx); + return (ctx->major); + } ++#endif /* We can't copy this structure, so we just move the pointer to it */ client->creds = ctx->client_creds; @@ -845,7 +864,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c return (ctx->major); } -@@ -395,6 +444,7 @@ +@@ -488,6 +541,7 @@ void ssh_gssapi_cleanup_creds(void) { @@ -853,7 +872,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c krb5_ccache ccache = NULL; krb5_error_code problem; -@@ -410,6 +460,14 @@ +@@ -503,6 +557,14 @@ gssapi_client.store.data = NULL; } } @@ -868,7 +887,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c } /* As user */ -@@ -417,6 +475,11 @@ +@@ -510,6 +572,11 @@ ssh_gssapi_storecreds(void) { if (gssapi_client.mech && gssapi_client.mech->storecreds) { @@ -880,7 +899,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c return (*gssapi_client.mech->storecreds)(&gssapi_client); } else debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism"); -@@ -449,11 +512,13 @@ +@@ -543,11 +610,13 @@ (void) kex; /* used in privilege separation */ @@ -897,15 +916,15 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c if (gssapi_client.mech && gssapi_client.mech->userok) if ((*gssapi_client.mech->userok)(&gssapi_client, user)) { gssapi_client.used = 1; -@@ -464,6 +529,7 @@ +@@ -558,6 +627,7 @@ gss_release_buffer(&lmin, &gssapi_client.displayname); gss_release_buffer(&lmin, &gssapi_client.exportedname); gss_release_cred(&lmin, &gssapi_client.creds); + gss_release_name(&lmin, &gssapi_client.ctx_name); - explicit_bzero(&gssapi_client, - sizeof(ssh_gssapi_client)); - return 0; -@@ -473,6 +539,24 @@ + + if (gssapi_client.indicators != NULL) { + for(i = 0; gssapi_client.indicators[i] != NULL; i++) { +@@ -575,6 +645,24 @@ return (0); } @@ -930,7 +949,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c /* These bits are only used for rekeying. The unpriviledged child is running * as the user, the monitor is root. * -@@ -499,9 +583,11 @@ +@@ -601,9 +689,11 @@ pam_handle_t *pamh = NULL; struct pam_conv pamconv = {ssh_gssapi_simple_conv, NULL}; char *envstr; @@ -942,8 +961,8 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c + gssapi_client.store.envval == NULL) return; - ok = PRIVSEP(ssh_gssapi_update_creds(&gssapi_client.store)); -@@ -526,6 +612,18 @@ + ok = mm_ssh_gssapi_update_creds(&gssapi_client.store); +@@ -623,6 +713,18 @@ if (ret) return; @@ -962,9 +981,9 @@ diff -Nur openssh-9.3p1.orig/gss-serv.c openssh-9.3p1/gss-serv.c xasprintf(&envstr, "%s=%s", gssapi_client.store.envvar, gssapi_client.store.envval); -diff -Nur openssh-9.3p1.orig/gss-serv-gsi.c openssh-9.3p1/gss-serv-gsi.c ---- openssh-9.3p1.orig/gss-serv-gsi.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/gss-serv-gsi.c 2023-06-26 17:36:05.816175578 +0200 +diff -Nur openssh-10.0p1.orig/gss-serv-gsi.c openssh-10.0p1/gss-serv-gsi.c +--- openssh-10.0p1.orig/gss-serv-gsi.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/gss-serv-gsi.c 2025-06-14 08:25:50.323228698 +0200 @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. @@ -1294,10 +1313,10 @@ diff -Nur openssh-9.3p1.orig/gss-serv-gsi.c openssh-9.3p1/gss-serv-gsi.c + +#endif /* GSI */ +#endif /* GSSAPI */ -diff -Nur openssh-9.3p1.orig/gss-serv-krb5.c openssh-9.3p1/gss-serv-krb5.c ---- openssh-9.3p1.orig/gss-serv-krb5.c 2023-06-26 17:34:46.506955997 +0200 -+++ openssh-9.3p1/gss-serv-krb5.c 2023-06-26 17:36:05.817175581 +0200 -@@ -379,6 +379,34 @@ +diff -Nur openssh-10.0p1.orig/gss-serv-krb5.c openssh-10.0p1/gss-serv-krb5.c +--- openssh-10.0p1.orig/gss-serv-krb5.c 2025-06-14 08:24:55.712149299 +0200 ++++ openssh-10.0p1/gss-serv-krb5.c 2025-06-14 08:25:50.323586985 +0200 +@@ -431,6 +431,34 @@ return found_principal; } @@ -1332,7 +1351,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv-krb5.c openssh-9.3p1/gss-serv-krb5.c /* This writes out any forwarded credentials from the structure populated * during userauth. Called after we have setuid to the user */ -@@ -473,7 +501,7 @@ +@@ -525,7 +553,7 @@ return set_env; } @@ -1341,7 +1360,7 @@ diff -Nur openssh-9.3p1.orig/gss-serv-krb5.c openssh-9.3p1/gss-serv-krb5.c ssh_gssapi_krb5_updatecreds(ssh_gssapi_ccache *store, ssh_gssapi_client *client) { -@@ -544,7 +572,7 @@ +@@ -596,7 +624,7 @@ {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}, NULL, &ssh_gssapi_krb5_userok, @@ -1350,9 +1369,9 @@ diff -Nur openssh-9.3p1.orig/gss-serv-krb5.c openssh-9.3p1/gss-serv-krb5.c &ssh_gssapi_krb5_storecreds, &ssh_gssapi_krb5_updatecreds }; -diff -Nur openssh-9.3p1.orig/kexgsss.c openssh-9.3p1/kexgsss.c ---- openssh-9.3p1.orig/kexgsss.c 2023-06-26 17:34:46.634956351 +0200 -+++ openssh-9.3p1/kexgsss.c 2023-06-26 17:36:05.817175581 +0200 +diff -Nur openssh-10.0p1.orig/kexgsss.c openssh-10.0p1/kexgsss.c +--- openssh-10.0p1.orig/kexgsss.c 2025-06-14 08:24:54.950961355 +0200 ++++ openssh-10.0p1/kexgsss.c 2025-06-14 08:25:50.324355451 +0200 @@ -48,6 +48,7 @@ #include "digest.h" #include "ssherr.h" @@ -1360,27 +1379,27 @@ diff -Nur openssh-9.3p1.orig/kexgsss.c openssh-9.3p1/kexgsss.c +static void kex_gss_send_error(Gssctxt *ctxt, struct ssh *ssh); extern ServerOptions options; - int -@@ -96,8 +97,10 @@ + static int input_kexgss_init(int, u_int32_t, struct ssh *); +@@ -81,8 +82,10 @@ debug2_f("Acquiring credentials"); -- if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) -+ if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, oid)))) { -+ kex_gss_send_error(ctxt, ssh); +- if (GSS_ERROR(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) ++ if (GSS_ERROR(mm_ssh_gssapi_server_ctx(&kex->gss, oid))) { ++ kex_gss_send_error(kex->gss, ssh); fatal("Unable to acquire credentials for the server"); + } - do { - debug("Wait SSH2_MSG_KEXGSS_INIT"); -@@ -195,13 +198,14 @@ - } while (maj_status & GSS_S_CONTINUE_NEEDED); + ssh_gssapi_build_ctx(&kex->gss); + if (kex->gss == NULL) +@@ -139,13 +142,14 @@ + ssh_dispatch_set(ssh, SSH2_MSG_KEXGSS_CONTINUE, NULL); - if (GSS_ERROR(maj_status)) { -+ kex_gss_send_error(ctxt, ssh); - if (send_tok.length > 0) { + if (GSS_ERROR(gss->major)) { ++ kex_gss_send_error(kex->gss, ssh); + if (send_tok->length > 0) { if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_CONTINUE)) != 0 || - (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || + (r = sshpkt_put_string(ssh, send_tok->value, send_tok->length)) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("sshpkt failed: %s", ssh_err(r)); } @@ -1388,19 +1407,18 @@ diff -Nur openssh-9.3p1.orig/kexgsss.c openssh-9.3p1/kexgsss.c + ssh_packet_disconnect(ssh, "GSSAPI Key Exchange handshake failed"); } - if (!(ret_flags & GSS_C_MUTUAL_FLAG)) -@@ -479,4 +483,26 @@ - sshbuf_free(shared_secret); - return r; + if (!(*ret_flags & GSS_C_MUTUAL_FLAG)) +@@ -598,4 +602,26 @@ + return kexgssgex_final(ssh, &send_tok, &ret_flags); } -+ + +static void +kex_gss_send_error(Gssctxt *ctxt, struct ssh *ssh) { + char *errstr; + OM_uint32 maj, min; + int r; + -+ errstr = PRIVSEP(ssh_gssapi_last_error(ctxt, &maj, &min)); ++ errstr = mm_ssh_gssapi_last_error(ctxt, &maj, &min); + if (errstr) { + if ((r = sshpkt_start(ssh, SSH2_MSG_KEXGSS_ERROR)) != 0 || + (r = sshpkt_put_u32(ssh, maj)) != 0 || @@ -1415,22 +1433,33 @@ diff -Nur openssh-9.3p1.orig/kexgsss.c openssh-9.3p1/kexgsss.c + free(errstr); + } +} ++ #endif /* defined(GSSAPI) && defined(WITH_OPENSSL) */ -diff -Nur openssh-9.3p1.orig/Makefile.in openssh-9.3p1/Makefile.in ---- openssh-9.3p1.orig/Makefile.in 2023-06-26 17:34:46.580956202 +0200 -+++ openssh-9.3p1/Makefile.in 2023-06-26 17:36:05.818175584 +0200 -@@ -130,6 +130,7 @@ +diff -Nur openssh-10.0p1.orig/Makefile.in openssh-10.0p1/Makefile.in +--- openssh-10.0p1.orig/Makefile.in 2025-06-14 08:24:55.442297261 +0200 ++++ openssh-10.0p1/Makefile.in 2025-06-14 14:49:48.752490751 +0200 +@@ -140,7 +140,7 @@ + auth-bsdauth.o auth2-hostbased.o auth2-kbdint.o \ auth2-none.o auth2-passwd.o auth2-pubkey.o auth2-pubkeyfile.o \ - monitor.o monitor_wrap.o auth-krb5.o \ - auth2-gss.o gss-serv.o gss-serv-krb5.o kexgsss.o \ -+ gss-serv-gsi.o \ + monitor.o monitor_wrap.o auth-krb5.o kexgsss.o \ +- auth2-gss.o gss-serv.o gss-serv-krb5.o \ ++ auth2-gss.o gss-serv.o gss-serv-krb5.o gss-serv-gsi.o \ loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ - srclimit.o sftp-server.o sftp-common.o \ - sandbox-null.o sandbox-rlimit.o sandbox-systrace.o sandbox-darwin.o \ -diff -Nur openssh-9.3p1.orig/misc.c openssh-9.3p1/misc.c ---- openssh-9.3p1.orig/misc.c 2023-06-26 17:34:46.625956326 +0200 -+++ openssh-9.3p1/misc.c 2023-06-26 17:36:05.819175586 +0200 -@@ -393,11 +393,14 @@ + sftp-server.o sftp-common.o \ + uidswap.o platform-listen.o $(SKOBJS) +@@ -151,7 +151,7 @@ + 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 kexgsss.o \ ++ auth2-gss.o gss-serv.o gss-serv-krb5.o gss-serv-gsi.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 \ +diff -Nur openssh-10.0p1.orig/misc.c openssh-10.0p1/misc.c +--- openssh-10.0p1.orig/misc.c 2025-06-14 08:24:55.731834474 +0200 ++++ openssh-10.0p1/misc.c 2025-06-14 08:25:50.325895875 +0200 +@@ -440,11 +440,14 @@ #define WHITESPACE " \t\r\n" #define QUOTE "\"" @@ -1446,7 +1475,7 @@ diff -Nur openssh-9.3p1.orig/misc.c openssh-9.3p1/misc.c int wspace = 0; if (*s == NULL) -@@ -405,6 +408,21 @@ +@@ -452,6 +455,21 @@ old = *s; @@ -1468,7 +1497,7 @@ diff -Nur openssh-9.3p1.orig/misc.c openssh-9.3p1/misc.c *s = strpbrk(*s, split_equals ? WHITESPACE QUOTE "=" : WHITESPACE QUOTE); if (*s == NULL) -@@ -480,6 +498,20 @@ +@@ -527,6 +545,20 @@ return copy; } @@ -1489,10 +1518,10 @@ diff -Nur openssh-9.3p1.orig/misc.c openssh-9.3p1/misc.c /* * Convert ASCII string to TCP/IP port number. * Port must be >=0 and <=65535. -diff -Nur openssh-9.3p1.orig/misc.h openssh-9.3p1/misc.h ---- openssh-9.3p1.orig/misc.h 2023-06-26 17:34:46.526956052 +0200 -+++ openssh-9.3p1/misc.h 2023-06-26 17:36:05.820175589 +0200 -@@ -100,6 +100,7 @@ +diff -Nur openssh-10.0p1.orig/misc.h openssh-10.0p1/misc.h +--- openssh-10.0p1.orig/misc.h 2025-06-14 08:24:55.216960866 +0200 ++++ openssh-10.0p1/misc.h 2025-06-14 08:25:50.326898660 +0200 +@@ -112,6 +112,7 @@ void sock_set_v6only(int); struct passwd *pwcopy(struct passwd *); @@ -1500,10 +1529,10 @@ diff -Nur openssh-9.3p1.orig/misc.h openssh-9.3p1/misc.h const char *ssh_gai_strerror(int); typedef void privdrop_fn(struct passwd *); -diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c ---- openssh-9.3p1.orig/monitor.c 2023-06-26 17:34:46.625956326 +0200 -+++ openssh-9.3p1/monitor.c 2023-06-26 17:36:05.821175592 +0200 -@@ -152,6 +152,9 @@ +diff -Nur openssh-10.0p1.orig/monitor.c openssh-10.0p1/monitor.c +--- openssh-10.0p1.orig/monitor.c 2025-06-14 08:24:55.732232011 +0200 ++++ openssh-10.0p1/monitor.c 2025-06-14 08:25:50.327682491 +0200 +@@ -151,6 +151,9 @@ int mm_answer_gss_userok(struct ssh *, int, struct sshbuf *); int mm_answer_gss_checkmic(struct ssh *, int, struct sshbuf *); int mm_answer_gss_sign(struct ssh *, int, struct sshbuf *); @@ -1513,7 +1542,7 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c int mm_answer_gss_updatecreds(struct ssh *, int, struct sshbuf *); #endif -@@ -204,7 +207,7 @@ +@@ -205,7 +208,7 @@ {MONITOR_REQ_MODULI, MON_ONCE, mm_answer_moduli}, #endif {MONITOR_REQ_SIGN, MON_ONCE, mm_answer_sign}, @@ -1522,7 +1551,7 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c {MONITOR_REQ_AUTHSERV, MON_ONCE, mm_answer_authserv}, #ifdef WITH_SELINUX {MONITOR_REQ_AUTHROLE, MON_ONCE, mm_answer_authrole}, -@@ -212,7 +215,7 @@ +@@ -213,7 +216,7 @@ {MONITOR_REQ_AUTH2_READ_BANNER, MON_ONCE, mm_answer_auth2_read_banner}, {MONITOR_REQ_AUTHPASSWORD, MON_AUTH, mm_answer_authpassword}, #ifdef USE_PAM @@ -1531,7 +1560,7 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c {MONITOR_REQ_PAM_ACCOUNT, 0, mm_answer_pam_account}, {MONITOR_REQ_PAM_INIT_CTX, MON_ONCE, mm_answer_pam_init_ctx}, {MONITOR_REQ_PAM_QUERY, 0, mm_answer_pam_query}, -@@ -236,8 +239,11 @@ +@@ -237,8 +240,11 @@ {MONITOR_REQ_GSSSETUP, MON_ISAUTH, mm_answer_gss_setup_ctx}, {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, {MONITOR_REQ_GSSUSEROK, MON_ONCE|MON_AUTHDECIDE, mm_answer_gss_userok}, @@ -1544,7 +1573,7 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c #endif {0, 0, NULL} }; -@@ -247,6 +253,8 @@ +@@ -248,6 +254,8 @@ {MONITOR_REQ_GSSSETUP, 0, mm_answer_gss_setup_ctx}, {MONITOR_REQ_GSSSTEP, 0, mm_answer_gss_accept_ctx}, {MONITOR_REQ_GSSSIGN, 0, mm_answer_gss_sign}, @@ -1552,8 +1581,8 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c + {MONITOR_REQ_GSSMECHS, 0, mm_answer_gss_indicate_mechs}, {MONITOR_REQ_GSSUPCREDS, 0, mm_answer_gss_updatecreds}, #endif - #ifdef WITH_OPENSSL -@@ -327,6 +335,8 @@ + {MONITOR_REQ_STATE, MON_ONCE, mm_answer_state}, +@@ -328,6 +336,8 @@ #ifdef GSSAPI /* and for the GSSAPI key exchange */ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); @@ -1562,7 +1591,7 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c #endif /* The first few requests do not require asynchronous access */ -@@ -451,6 +461,8 @@ +@@ -461,6 +471,8 @@ #ifdef GSSAPI /* and for the GSSAPI key exchange */ monitor_permit(mon_dispatch, MONITOR_REQ_GSSSETUP, 1); @@ -1571,7 +1600,7 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c #endif if (auth_opts->permit_pty_flag) { -@@ -779,14 +791,17 @@ +@@ -895,14 +907,17 @@ debug3_f("entering"); @@ -1592,7 +1621,7 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c setproctitle("%s [priv]", pwent ? authctxt->user : "unknown"); sshbuf_reset(m); -@@ -2142,6 +2157,79 @@ +@@ -2249,6 +2264,79 @@ } int @@ -1672,10 +1701,10 @@ diff -Nur openssh-9.3p1.orig/monitor.c openssh-9.3p1/monitor.c mm_answer_gss_sign(struct ssh *ssh, int socket, struct sshbuf *m) { gss_buffer_desc data; -diff -Nur openssh-9.3p1.orig/monitor.h openssh-9.3p1/monitor.h ---- openssh-9.3p1.orig/monitor.h 2023-06-26 17:34:46.581956204 +0200 -+++ openssh-9.3p1/monitor.h 2023-06-26 17:36:05.821175592 +0200 -@@ -75,6 +75,10 @@ +diff -Nur openssh-10.0p1.orig/monitor.h openssh-10.0p1/monitor.h +--- openssh-10.0p1.orig/monitor.h 2025-06-14 08:24:55.446043209 +0200 ++++ openssh-10.0p1/monitor.h 2025-06-14 08:25:50.328788501 +0200 +@@ -76,6 +76,10 @@ MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151, MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153, @@ -1686,10 +1715,10 @@ diff -Nur openssh-9.3p1.orig/monitor.h openssh-9.3p1/monitor.h }; struct ssh; -diff -Nur openssh-9.3p1.orig/monitor_wrap.c openssh-9.3p1/monitor_wrap.c ---- openssh-9.3p1.orig/monitor_wrap.c 2023-06-26 17:34:46.626956329 +0200 -+++ openssh-9.3p1/monitor_wrap.c 2023-06-26 17:36:05.822175594 +0200 -@@ -1085,6 +1085,94 @@ +diff -Nur openssh-10.0p1.orig/monitor_wrap.c openssh-10.0p1/monitor_wrap.c +--- openssh-10.0p1.orig/monitor_wrap.c 2025-06-14 08:24:55.468434323 +0200 ++++ openssh-10.0p1/monitor_wrap.c 2025-06-14 08:25:50.329256997 +0200 +@@ -1195,6 +1195,94 @@ return (authenticated); } @@ -1784,10 +1813,10 @@ diff -Nur openssh-9.3p1.orig/monitor_wrap.c openssh-9.3p1/monitor_wrap.c OM_uint32 mm_ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *data, gss_buffer_desc *hash) { -diff -Nur openssh-9.3p1.orig/monitor_wrap.h openssh-9.3p1/monitor_wrap.h ---- openssh-9.3p1.orig/monitor_wrap.h 2023-06-26 17:34:46.588956224 +0200 -+++ openssh-9.3p1/monitor_wrap.h 2023-06-26 17:36:05.823175597 +0200 -@@ -73,6 +73,10 @@ +diff -Nur openssh-10.0p1.orig/monitor_wrap.h openssh-10.0p1/monitor_wrap.h +--- openssh-10.0p1.orig/monitor_wrap.h 2025-06-14 08:24:55.468730870 +0200 ++++ openssh-10.0p1/monitor_wrap.h 2025-06-14 08:25:50.329790028 +0200 +@@ -72,6 +72,10 @@ int mm_ssh_gssapi_userok(char *user, struct passwd *, int kex); OM_uint32 mm_ssh_gssapi_checkmic(Gssctxt *, gss_buffer_t, gss_buffer_t); OM_uint32 mm_ssh_gssapi_sign(Gssctxt *, gss_buffer_t, gss_buffer_t); @@ -1798,10 +1827,10 @@ diff -Nur openssh-9.3p1.orig/monitor_wrap.h openssh-9.3p1/monitor_wrap.h int mm_ssh_gssapi_update_creds(ssh_gssapi_ccache *); #endif -diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c ---- openssh-9.3p1.orig/readconf.c 2023-06-26 17:34:46.627956332 +0200 -+++ openssh-9.3p1/readconf.c 2023-06-26 17:36:05.824175600 +0200 -@@ -2554,11 +2554,11 @@ +diff -Nur openssh-10.0p1.orig/readconf.c openssh-10.0p1/readconf.c +--- openssh-10.0p1.orig/readconf.c 2025-06-14 08:24:55.733023595 +0200 ++++ openssh-10.0p1/readconf.c 2025-06-14 08:25:50.330266207 +0200 +@@ -2881,11 +2881,11 @@ if (options->pubkey_authentication == -1) options->pubkey_authentication = SSH_PUBKEY_AUTH_ALL; if (options->gss_authentication == -1) @@ -1816,9 +1845,9 @@ diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c if (options->gss_trust_dns == -1) options->gss_trust_dns = 0; if (options->gss_renewal_rekey == -1) -diff -Nur openssh-9.3p1.orig/readconf.h openssh-9.3p1/readconf.h ---- openssh-9.3p1.orig/readconf.h 2023-06-26 17:34:46.470955897 +0200 -+++ openssh-9.3p1/readconf.h 2023-06-26 17:36:05.825175603 +0200 +diff -Nur openssh-10.0p1.orig/readconf.h openssh-10.0p1/readconf.h +--- openssh-10.0p1.orig/readconf.h 2025-06-14 08:24:54.953487731 +0200 ++++ openssh-10.0p1/readconf.h 2025-06-14 08:25:50.330993746 +0200 @@ -79,6 +79,8 @@ char *host_key_alias; /* hostname alias for .ssh/known_hosts */ char *proxy_command; /* Proxy command for connecting the host. */ @@ -1828,18 +1857,18 @@ diff -Nur openssh-9.3p1.orig/readconf.h openssh-9.3p1/readconf.h int escape_char; /* Escape character; -2 = none */ u_int num_system_hostfiles; /* Paths for /etc/ssh/ssh_known_hosts */ -diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c ---- openssh-9.3p1.orig/servconf.c 2023-06-26 17:34:46.628956335 +0200 -+++ openssh-9.3p1/servconf.c 2023-06-26 17:36:05.826175605 +0200 -@@ -93,6 +93,7 @@ - +diff -Nur openssh-10.0p1.orig/servconf.c openssh-10.0p1/servconf.c +--- openssh-10.0p1.orig/servconf.c 2025-06-14 08:24:55.733579673 +0200 ++++ openssh-10.0p1/servconf.c 2025-06-14 08:25:50.331610935 +0200 +@@ -96,6 +96,7 @@ /* Portable-specific options */ options->use_pam = -1; + options->pam_service_name = NULL; + options->permit_pam_user_change = -1; /* Standard Options */ options->num_ports = 0; -@@ -139,9 +140,11 @@ +@@ -142,9 +143,11 @@ options->kerberos_get_afs_token = -1; options->kerberos_unique_ccache = -1; options->gss_authentication=-1; @@ -1850,17 +1879,17 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c + options->gsi_allow_limited_proxy = -1; options->gss_store_rekey = -1; options->gss_kex_algorithms = NULL; - options->use_kuserok = -1; -@@ -295,6 +298,8 @@ - /* Portable-specific options */ - if (options->use_pam == -1) + options->gss_indicators = NULL; +@@ -317,6 +320,8 @@ options->use_pam = 0; + if (options->pam_service_name == NULL) + options->pam_service_name = xstrdup(SSHD_PAM_SERVICE); + if (options->permit_pam_user_change == -1) + options->permit_pam_user_change = 0; /* Standard Options */ if (options->num_host_key_files == 0) { -@@ -376,13 +381,17 @@ +@@ -398,13 +403,17 @@ if (options->kerberos_unique_ccache == -1) options->kerberos_unique_ccache = 0; if (options->gss_authentication == -1) @@ -1880,37 +1909,38 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c if (options->gss_store_rekey == -1) options->gss_store_rekey = 0; #ifdef GSSAPI -@@ -529,7 +538,7 @@ +@@ -578,7 +587,7 @@ typedef enum { sBadOption, /* == unknown option */ /* Portable-specific options */ -- sUsePAM, -+ sUsePAM, sPermitPAMUserChange, +- sUsePAM, sPAMServiceName, ++ sUsePAM, sPAMServiceName, sPermitPAMUserChange, /* Standard Options */ sPort, sHostKeyFile, sLoginGraceTime, sPermitRootLogin, sLogFacility, sLogLevel, sLogVerbose, -@@ -548,6 +557,9 @@ - sHostbasedUsesNameFromPacketOnly, sHostbasedAcceptedAlgorithms, +@@ -598,6 +607,9 @@ sHostKeyAlgorithms, sPerSourceMaxStartups, sPerSourceNetBlockSize, + sPerSourcePenalties, sPerSourcePenaltyExemptList, sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, + sGssDelegateCreds, + sGssCredsPath, + sGsiAllowLimitedProxy, sGssAuthentication, sGssCleanupCreds, sGssEnablek5users, sGssStrictAcceptor, - sGssKeyEx, sGssKexAlgorithms, sGssStoreRekey, + sGssKeyEx, sGssIndicators, sGssKexAlgorithms, sGssStoreRekey, sAcceptEnv, sSetEnv, sPermitTunnel, -@@ -581,8 +593,10 @@ - /* Portable-specific options */ +@@ -633,9 +645,11 @@ #ifdef USE_PAM { "usepam", sUsePAM, SSHCFG_GLOBAL }, + { "pamservicename", sPAMServiceName, SSHCFG_ALL }, + { "permitpamuserchange", sPermitPAMUserChange, SSHCFG_GLOBAL }, #else { "usepam", sUnsupported, SSHCFG_GLOBAL }, + { "pamservicename", sUnsupported, SSHCFG_ALL }, + { "permitpamuserchange", sUnsupported, SSHCFG_GLOBAL }, #endif { "pamauthenticationviakbdint", sDeprecated, SSHCFG_GLOBAL }, /* Standard Options */ -@@ -635,8 +649,15 @@ +@@ -688,8 +702,15 @@ { "afstokenpassing", sUnsupported, SSHCFG_GLOBAL }, #ifdef GSSAPI { "gssapiauthentication", sGssAuthentication, SSHCFG_ALL }, @@ -1926,8 +1956,8 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c { "gssapistrictacceptorcheck", sGssStrictAcceptor, SSHCFG_GLOBAL }, { "gssapikeyexchange", sGssKeyEx, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sGssStoreRekey, SSHCFG_GLOBAL }, -@@ -644,8 +665,11 @@ - { "gssapienablek5users", sGssEnablek5users, SSHCFG_ALL }, +@@ -698,8 +719,11 @@ + { "gssapiindicators", sGssIndicators, SSHCFG_ALL }, #else { "gssapiauthentication", sUnsupported, SSHCFG_ALL }, + { "gssapidelegatecredentials", sUnsupported, SSHCFG_ALL }, @@ -1938,7 +1968,7 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c { "gssapistrictacceptorcheck", sUnsupported, SSHCFG_GLOBAL }, { "gssapikeyexchange", sUnsupported, SSHCFG_GLOBAL }, { "gssapistorecredentialsonrekey", sUnsupported, SSHCFG_GLOBAL }, -@@ -717,6 +741,8 @@ +@@ -774,6 +798,8 @@ { "permitlisten", sPermitListen, SSHCFG_ALL }, { "forcecommand", sForceCommand, SSHCFG_ALL }, { "chrootdirectory", sChrootDirectory, SSHCFG_ALL }, @@ -1947,9 +1977,9 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c { "hostcertificate", sHostCertificate, SSHCFG_GLOBAL }, { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, -@@ -1450,6 +1476,10 @@ - intptr = &options->use_pam; - goto parse_flag; +@@ -1454,6 +1480,10 @@ + *charptr = xstrdup(arg); + break; + case sPermitPAMUserChange: + intptr = &options->permit_pam_user_change; @@ -1958,7 +1988,7 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c /* Standard Options */ case sBadOption: goto out; -@@ -1696,6 +1726,10 @@ +@@ -1705,6 +1735,10 @@ intptr = &options->gss_authentication; goto parse_flag; @@ -1969,7 +1999,7 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c case sGssKeyEx: intptr = &options->gss_keyex; goto parse_flag; -@@ -1704,6 +1738,10 @@ +@@ -1713,6 +1747,10 @@ intptr = &options->gss_cleanup_creds; goto parse_flag; @@ -1980,8 +2010,8 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c case sGssStrictAcceptor: intptr = &options->gss_strict_acceptor; goto parse_flag; -@@ -1724,6 +1762,12 @@ - options->gss_kex_algorithms = xstrdup(arg); +@@ -1742,6 +1780,12 @@ + options->gss_indicators = xstrdup(arg); break; +#ifdef GSI @@ -1993,7 +2023,7 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c case sPasswordAuthentication: intptr = &options->password_authentication; goto parse_flag; -@@ -2776,6 +2820,7 @@ +@@ -3012,6 +3056,7 @@ M_CP_INTOPT(password_authentication); M_CP_INTOPT(gss_authentication); @@ -2001,10 +2031,10 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c M_CP_INTOPT(pubkey_authentication); M_CP_INTOPT(pubkey_auth_options); M_CP_INTOPT(kerberos_authentication); -diff -Nur openssh-9.3p1.orig/servconf.h openssh-9.3p1/servconf.h ---- openssh-9.3p1.orig/servconf.h 2023-06-26 17:34:46.519956033 +0200 -+++ openssh-9.3p1/servconf.h 2023-06-26 17:36:05.827175608 +0200 -@@ -146,9 +146,12 @@ +diff -Nur openssh-10.0p1.orig/servconf.h openssh-10.0p1/servconf.h +--- openssh-10.0p1.orig/servconf.h 2025-06-14 08:24:55.713201111 +0200 ++++ openssh-10.0p1/servconf.h 2025-06-14 08:25:50.332635999 +0200 +@@ -155,9 +155,12 @@ * be stored in per-session ccache */ int use_kuserok; int enable_k5users; @@ -2017,18 +2047,18 @@ diff -Nur openssh-9.3p1.orig/servconf.h openssh-9.3p1/servconf.h 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. */ -@@ -209,6 +212,7 @@ - char *adm_forced_command; +@@ -222,6 +225,7 @@ int use_pam; /* Enable auth via PAM */ + char *pam_service_name; + int permit_pam_user_change; /* Allow PAM to change user name */ int permit_tun; -diff -Nur openssh-9.3p1.orig/ssh.1 openssh-9.3p1/ssh.1 ---- openssh-9.3p1.orig/ssh.1 2023-06-26 17:34:46.606956274 +0200 -+++ openssh-9.3p1/ssh.1 2023-06-26 17:36:05.828175611 +0200 -@@ -1514,6 +1514,18 @@ +diff -Nur openssh-10.0p1.orig/ssh.1 openssh-10.0p1/ssh.1 +--- openssh-10.0p1.orig/ssh.1 2025-06-14 08:24:55.527924262 +0200 ++++ openssh-10.0p1/ssh.1 2025-06-14 08:25:50.333158134 +0200 +@@ -1528,6 +1528,18 @@ on to new connections). .It Ev USER Set to the name of the user logging in. @@ -2047,10 +2077,10 @@ diff -Nur openssh-9.3p1.orig/ssh.1 openssh-9.3p1/ssh.1 .El .Pp Additionally, -diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c ---- openssh-9.3p1.orig/ssh.c 2023-06-26 17:34:46.630956340 +0200 -+++ openssh-9.3p1/ssh.c 2023-06-26 17:36:05.829175614 +0200 -@@ -571,6 +571,38 @@ +diff -Nur openssh-10.0p1.orig/ssh.c openssh-10.0p1/ssh.c +--- openssh-10.0p1.orig/ssh.c 2025-06-14 08:24:55.693276450 +0200 ++++ openssh-10.0p1/ssh.c 2025-06-14 13:58:47.186170059 +0200 +@@ -578,6 +578,38 @@ fatal("Can't open user config file %.100s: " "%.100s", config, strerror(errno)); } else { @@ -2066,14 +2096,14 @@ diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c + r = snprintf(buf, sizeof buf, "%s/%s.gssapi", pw->pw_dir, + _PATH_SSH_USER_CONFFILE); + if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_name, ++ (void)read_config_file(buf, pw, host, host_name, cmd, + &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | + (final_pass ? SSHCONF_FINAL : 0), want_final_pass); +#ifdef GSI + r = snprintf(buf, sizeof buf, "%s/%s.gsi", pw->pw_dir, + _PATH_SSH_USER_CONFFILE); + if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_name, ++ (void)read_config_file(buf, pw, host, host_name, cmd, + &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | + (final_pass ? SSHCONF_FINAL : 0), want_final_pass); +#endif @@ -2081,7 +2111,7 @@ diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c + r = snprintf(buf, sizeof buf, "%s/%s.krb", pw->pw_dir, + _PATH_SSH_USER_CONFFILE); + if (r > 0 && (size_t)r < sizeof(buf)) -+ (void)read_config_file(buf, pw, host, host_name, ++ (void)read_config_file(buf, pw, host, host_name, cmd, + &options, SSHCONF_CHECKPERM | SSHCONF_USERCONF | + (final_pass ? SSHCONF_FINAL : 0), want_final_pass); +#endif @@ -2089,7 +2119,7 @@ diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c r = snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, _PATH_SSH_USER_CONFFILE); if (r > 0 && (size_t)r < sizeof(buf)) -@@ -1251,8 +1283,12 @@ +@@ -1313,8 +1345,12 @@ if (fill_default_options(&options) != 0) cleanup_exit(255); @@ -2103,9 +2133,9 @@ diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c /* * If ProxyJump option specified, then construct a ProxyCommand now. -diff -Nur openssh-9.3p1.orig/ssh_config openssh-9.3p1/ssh_config ---- openssh-9.3p1.orig/ssh_config 2023-06-26 17:34:46.473955906 +0200 -+++ openssh-9.3p1/ssh_config 2023-06-26 17:36:05.830175617 +0200 +diff -Nur openssh-10.0p1.orig/ssh_config openssh-10.0p1/ssh_config +--- openssh-10.0p1.orig/ssh_config 2025-06-14 08:24:54.955694862 +0200 ++++ openssh-10.0p1/ssh_config 2025-06-14 08:25:50.334427503 +0200 @@ -22,9 +22,9 @@ # ForwardX11 no # PasswordAuthentication yes @@ -2118,10 +2148,10 @@ diff -Nur openssh-9.3p1.orig/ssh_config openssh-9.3p1/ssh_config +# GSSAPIKeyExchange yes # GSSAPITrustDNS no # BatchMode no - # CheckHostIP yes -diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 ---- openssh-9.3p1.orig/ssh_config.5 2023-06-26 17:34:46.544956102 +0200 -+++ openssh-9.3p1/ssh_config.5 2023-06-26 17:36:05.831175620 +0200 + # CheckHostIP no +diff -Nur openssh-10.0p1.orig/ssh_config.5 openssh-10.0p1/ssh_config.5 +--- openssh-10.0p1.orig/ssh_config.5 2025-06-14 08:24:55.625225410 +0200 ++++ openssh-10.0p1/ssh_config.5 2025-06-14 08:25:50.334845923 +0200 @@ -52,6 +52,12 @@ user's configuration file .Pq Pa ~/.ssh/config @@ -2135,7 +2165,7 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 system-wide configuration file .Pq Pa /etc/ssh/ssh_config .El -@@ -832,7 +838,7 @@ +@@ -969,7 +975,7 @@ .It Cm GSSAPIAuthentication Specifies whether user authentication based on GSSAPI is allowed. The default is @@ -2144,7 +2174,7 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 .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 -@@ -840,12 +846,12 @@ +@@ -977,12 +983,12 @@ .It Cm GSSAPIDelegateCredentials Forward (delegate) credentials to the server. The default is @@ -2159,7 +2189,7 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 .It Cm GSSAPIRenewalForcesRekey If set to .Dq yes -@@ -1471,7 +1477,7 @@ +@@ -1645,7 +1651,7 @@ .Cm password ) . The default is: .Bd -literal -offset indent @@ -2168,10 +2198,10 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 keyboard-interactive,password .Ed .It Cm ProxyCommand -diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c ---- openssh-9.3p1.orig/sshconnect2.c 2023-06-26 17:34:46.619956310 +0200 -+++ openssh-9.3p1/sshconnect2.c 2023-06-26 17:36:05.832175622 +0200 -@@ -861,6 +861,11 @@ +diff -Nur openssh-10.0p1.orig/sshconnect2.c openssh-10.0p1/sshconnect2.c +--- openssh-10.0p1.orig/sshconnect2.c 2025-06-14 08:24:55.591449573 +0200 ++++ openssh-10.0p1/sshconnect2.c 2025-06-14 08:25:50.335562288 +0200 +@@ -858,6 +858,11 @@ gss_OID mech = NULL; char *gss_host = NULL; @@ -2183,7 +2213,7 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c if (options.gss_server_identity) { gss_host = xstrdup(options.gss_server_identity); } else if (options.gss_trust_dns) { -@@ -972,7 +977,8 @@ +@@ -966,7 +971,8 @@ if (status == GSS_S_COMPLETE) { /* send either complete or MIC, depending on mechanism */ @@ -2193,7 +2223,7 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE)) != 0 || (r = sshpkt_send(ssh)) != 0) -@@ -1139,6 +1145,20 @@ +@@ -1133,6 +1139,20 @@ return r; } @@ -2214,7 +2244,7 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c int userauth_gsskeyex(struct ssh *ssh) { -@@ -1161,6 +1181,12 @@ +@@ -1155,6 +1175,12 @@ if ((b = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); @@ -2227,7 +2257,7 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c ssh_gssapi_buildmic(b, authctxt->server_user, authctxt->service, "gssapi-keyex", ssh->kex->session_id); -@@ -1174,7 +1200,9 @@ +@@ -1168,7 +1194,9 @@ } if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_REQUEST)) != 0 || @@ -2238,10 +2268,10 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c (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 || -diff -Nur openssh-9.3p1.orig/sshd.8 openssh-9.3p1/sshd.8 ---- openssh-9.3p1.orig/sshd.8 2023-06-26 17:34:46.488955947 +0200 -+++ openssh-9.3p1/sshd.8 2023-06-26 17:36:05.833175625 +0200 -@@ -839,6 +839,29 @@ +diff -Nur openssh-10.0p1.orig/sshd.8 openssh-10.0p1/sshd.8 +--- openssh-10.0p1.orig/sshd.8 2025-06-14 08:24:55.024336971 +0200 ++++ openssh-10.0p1/sshd.8 2025-06-14 08:25:50.336280328 +0200 +@@ -840,6 +840,29 @@ # A CA key, accepted for any host in *.mydomain.com or *.mydomain.org @cert-authority *.mydomain.org,*.mydomain.com ssh-rsa AAAAB5W... .Ed @@ -2271,22 +2301,10 @@ diff -Nur openssh-9.3p1.orig/sshd.8 openssh-9.3p1/sshd.8 .Sh FILES .Bl -tag -width Ds -compact .It Pa ~/.hushlogin -diff -Nur openssh-9.3p1.orig/sshd.c openssh-9.3p1/sshd.c ---- openssh-9.3p1.orig/sshd.c 2023-06-26 17:34:46.631956343 +0200 -+++ openssh-9.3p1/sshd.c 2023-06-26 17:36:05.835175630 +0200 -@@ -2438,7 +2438,7 @@ - #endif - - #ifdef GSSAPI -- if (options.gss_authentication) { -+ if (options.gss_authentication && options.gss_deleg_creds) { - temporarily_use_uid(authctxt->pw); - authctxt->krb5_set_env = ssh_gssapi_storecreds(); - restore_uid(); -diff -Nur openssh-9.3p1.orig/sshd_config openssh-9.3p1/sshd_config ---- openssh-9.3p1.orig/sshd_config 2023-06-26 17:34:46.508956002 +0200 -+++ openssh-9.3p1/sshd_config 2023-06-26 17:36:05.835175630 +0200 -@@ -76,10 +76,11 @@ +diff -Nur openssh-10.0p1.orig/sshd_config openssh-10.0p1/sshd_config +--- openssh-10.0p1.orig/sshd_config 2025-06-14 08:24:55.129477337 +0200 ++++ openssh-10.0p1/sshd_config 2025-06-14 08:25:50.336709644 +0200 +@@ -78,10 +78,11 @@ #KerberosUseKuserok yes # GSSAPI options @@ -2300,7 +2318,7 @@ diff -Nur openssh-9.3p1.orig/sshd_config openssh-9.3p1/sshd_config #GSSAPIEnablek5users no # Set this to 'yes' to enable PAM authentication, account processing, -@@ -95,6 +96,10 @@ +@@ -97,6 +98,10 @@ # problems. #UsePAM no @@ -2311,10 +2329,10 @@ diff -Nur openssh-9.3p1.orig/sshd_config openssh-9.3p1/sshd_config #AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no -diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 ---- openssh-9.3p1.orig/sshd_config.5 2023-06-26 17:34:46.545956105 +0200 -+++ openssh-9.3p1/sshd_config.5 2023-06-26 17:36:05.836175633 +0200 -@@ -716,15 +716,34 @@ +diff -Nur openssh-10.0p1.orig/sshd_config.5 openssh-10.0p1/sshd_config.5 +--- openssh-10.0p1.orig/sshd_config.5 2025-06-14 08:24:55.713605773 +0200 ++++ openssh-10.0p1/sshd_config.5 2025-06-14 08:25:50.337207823 +0200 +@@ -724,15 +724,34 @@ to allow the client to select the address to which the forwarding is bound. The default is .Cm no . @@ -2350,7 +2368,7 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 .It Cm GSSAPIEnablek5users Specifies whether to look at .k5users file for GSSAPI authentication access control. Further details are described in -@@ -735,7 +754,7 @@ +@@ -743,7 +762,7 @@ 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 @@ -2359,7 +2377,7 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 .It Cm GSSAPIStrictAcceptorCheck Determines whether to be strict about the identity of the GSSAPI acceptor a client authenticates against. -@@ -1900,6 +1919,12 @@ +@@ -2100,6 +2119,12 @@ as a non-root user. The default is .Cm no . @@ -2372,12 +2390,12 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 .It Cm VersionAddendum Optionally specifies additional text to append to the SSH protocol banner sent by the server upon connection. -diff -Nur openssh-9.3p1.orig/sshd_config_redhat openssh-9.3p1/sshd_config_redhat ---- openssh-9.3p1.orig/sshd_config_redhat 2023-06-26 17:34:46.457955861 +0200 -+++ openssh-9.3p1/sshd_config_redhat 2023-06-26 17:36:05.837175636 +0200 -@@ -9,9 +9,6 @@ +diff -Nur openssh-10.0p1.orig/sshd_config_redhat openssh-10.0p1/sshd_config_redhat +--- openssh-10.0p1.orig/sshd_config_redhat 2025-06-14 08:24:54.911947266 +0200 ++++ openssh-10.0p1/sshd_config_redhat 2025-06-14 08:25:50.337806574 +0200 +@@ -2,9 +2,6 @@ - ChallengeResponseAuthentication no + KbdInteractiveAuthentication no -GSSAPIAuthentication yes -GSSAPICleanupCredentials no @@ -2385,10 +2403,22 @@ diff -Nur openssh-9.3p1.orig/sshd_config_redhat openssh-9.3p1/sshd_config_redhat UsePAM yes X11Forwarding yes -diff -Nur openssh-9.3p1.orig/ssh-gss.h openssh-9.3p1/ssh-gss.h ---- openssh-9.3p1.orig/ssh-gss.h 2023-06-26 17:34:46.486955941 +0200 -+++ openssh-9.3p1/ssh-gss.h 2023-06-26 17:36:05.837175636 +0200 -@@ -97,12 +97,14 @@ +diff -Nur openssh-10.0p1.orig/sshd-session.c openssh-10.0p1/sshd-session.c +--- openssh-10.0p1.orig/sshd-session.c 2025-06-14 08:24:55.591819733 +0200 ++++ openssh-10.0p1/sshd-session.c 2025-06-14 08:25:50.338154455 +0200 +@@ -1448,7 +1448,7 @@ + #endif + + #ifdef GSSAPI +- if (options.gss_authentication) { ++ if (options.gss_authentication && options.gss_deleg_creds) { + temporarily_use_uid(authctxt->pw); + authctxt->krb5_set_env = ssh_gssapi_storecreds(); + restore_uid(); +diff -Nur openssh-10.0p1.orig/ssh-gss.h openssh-10.0p1/ssh-gss.h +--- openssh-10.0p1.orig/ssh-gss.h 2025-06-14 08:24:55.713368522 +0200 ++++ openssh-10.0p1/ssh-gss.h 2025-06-14 08:25:50.338720590 +0200 +@@ -105,12 +105,14 @@ } ssh_gssapi_ccache; typedef struct { @@ -2403,8 +2433,8 @@ diff -Nur openssh-9.3p1.orig/ssh-gss.h openssh-9.3p1/ssh-gss.h + gss_ctx_id_t context; /* needed for globus_gss_assist_map_and_authorize() */ int used; int updated; - } ssh_gssapi_client; -@@ -123,7 +125,7 @@ + char **indicators; /* auth indicators */ +@@ -132,7 +134,7 @@ OM_uint32 minor; /* both */ gss_ctx_id_t context; /* both */ gss_name_t name; /* both */ @@ -2413,7 +2443,7 @@ diff -Nur openssh-9.3p1.orig/ssh-gss.h openssh-9.3p1/ssh-gss.h gss_cred_id_t creds; /* server */ gss_name_t client; /* server */ gss_cred_id_t client_creds; /* both */ -@@ -161,6 +163,9 @@ +@@ -179,6 +181,9 @@ OM_uint32 ssh_gssapi_client_identity(Gssctxt *, const char *); int ssh_gssapi_credentials_updated(Gssctxt *); @@ -2423,12 +2453,12 @@ diff -Nur openssh-9.3p1.orig/ssh-gss.h openssh-9.3p1/ssh-gss.h /* In the server */ typedef int ssh_gssapi_check_fn(Gssctxt **, gss_OID, const char *, const char *); -diff -Nur openssh-9.3p1.orig/version.h openssh-9.3p1/version.h ---- openssh-9.3p1.orig/version.h 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/version.h 2023-06-26 17:36:05.838175639 +0200 +diff -Nur openssh-10.0p1.orig/version.h openssh-10.0p1/version.h +--- openssh-10.0p1.orig/version.h 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/version.h 2025-06-14 08:41:29.417798618 +0200 @@ -2,5 +2,19 @@ - #define SSH_VERSION "OpenSSH_9.3" + #define SSH_VERSION "OpenSSH_10.0" +#ifdef GSI +#define GSI_VERSION " GSI" @@ -2442,7 +2472,7 @@ diff -Nur openssh-9.3p1.orig/version.h openssh-9.3p1/version.h +#define KRB5_VERSION "" +#endif + - #define SSH_PORTABLE "p1" + #define SSH_PORTABLE "p2" -#define SSH_RELEASE SSH_VERSION SSH_PORTABLE +#define GSI_PORTABLE "c-GSI" +#define SSH_RELEASE SSH_VERSION SSH_PORTABLE GSI_PORTABLE \ diff --git a/openssh-9.3p1-hpn-17.13.patch b/2001-openssh-10.0p1-hpn-18.7.0.patch similarity index 77% rename from openssh-9.3p1-hpn-17.13.patch rename to 2001-openssh-10.0p1-hpn-18.7.0.patch index 10db813..8349a52 100644 --- a/openssh-9.3p1-hpn-17.13.patch +++ b/2001-openssh-10.0p1-hpn-18.7.0.patch @@ -1,6 +1,6 @@ -diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c ---- openssh-9.3p1.orig/auth2.c 2024-07-10 09:07:09.801082054 +0200 -+++ openssh-9.3p1/auth2.c 2024-07-10 09:18:45.456118963 +0200 +diff -Nur openssh-10.0p1.orig/auth2.c openssh-10.0p1/auth2.c +--- openssh-10.0p1.orig/auth2.c 2025-06-14 10:53:02.012331859 +0200 ++++ openssh-10.0p1/auth2.c 2025-06-14 11:42:37.929224784 +0200 @@ -52,6 +52,8 @@ #include "dispatch.h" #include "pathnames.h" @@ -10,7 +10,7 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c #ifdef GSSAPI #include "ssh-gss.h" #endif -@@ -74,6 +76,8 @@ +@@ -75,6 +77,8 @@ extern Authmethod method_gssapi; #endif @@ -19,7 +19,7 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c Authmethod *authmethods[] = { &method_none, &method_pubkey, -@@ -103,6 +107,9 @@ +@@ -104,6 +108,9 @@ #define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */ static int list_starts_with(const char *, const char *, const char *); @@ -29,7 +29,7 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c char * auth2_read_banner(void) { -@@ -297,6 +304,11 @@ +@@ -308,6 +315,11 @@ debug("userauth-request for user %s service %s method %s", user[0] ? user : "", service, method); @@ -41,10 +41,10 @@ diff -Nur openssh-9.3p1.orig/auth2.c openssh-9.3p1/auth2.c debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); #ifdef WITH_SELINUX -diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c ---- openssh-9.3p1.orig/binn.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/binn.c 2024-07-10 09:09:55.896568391 +0200 -@@ -0,0 +1,3498 @@ +diff -Nur openssh-10.0p1.orig/binn.c openssh-10.0p1/binn.c +--- openssh-10.0p1.orig/binn.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/binn.c 2025-06-14 10:54:01.301771902 +0200 +@@ -0,0 +1,3541 @@ +#include +#include +#include @@ -193,7 +193,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +#define strnicmp strncasecmp +#endif + -+BINN_PRIVATE BOOL IsValidBinnHeader(void *pbuf, int *ptype, int *pcount, int *psize, int *pheadersize); ++BINN_PRIVATE BOOL IsValidBinnHeader(const void *pbuf, int *ptype, int *pcount, int *psize, int *pheadersize); + +/***************************************************************************/ + @@ -230,7 +230,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+BINN_PRIVATE void * binn_memdup(void *src, int size) { ++BINN_PRIVATE void * binn_memdup(const void *src, int size) { + void *dest; + + if (src == NULL || size <= 0) return NULL; @@ -254,7 +254,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +int APIENTRY binn_create_type(int storage_type, int data_type_index) { + if (data_type_index < 0) return -1; -+ if ((storage_type < BINN_STORAGE_MIN) || (storage_type > BINN_STORAGE_MAX)) return -1; ++ if (storage_type < BINN_STORAGE_MIN || storage_type > BINN_STORAGE_MAX) return -1; + if (data_type_index < 16) + return storage_type | data_type_index; + else if (data_type_index < 4096) { @@ -317,7 +317,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + goto loc_exit; + } + -+ if ((item == NULL) || (size < 0)) goto loc_exit; ++ if (item == NULL || size < 0) goto loc_exit; + if (size < MIN_BINN_SIZE) { + if (pointer) goto loc_exit; + else size = 0; @@ -327,17 +327,16 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + if (pointer) { + item->pre_allocated = TRUE; -+ item->pbuf = pointer; -+ item->alloc_size = size; + } else { + item->pre_allocated = FALSE; + if (size == 0) size = CHUNK_SIZE; + pointer = binn_malloc(size); + if (pointer == 0) return INVALID_BINN; -+ item->pbuf = pointer; -+ item->alloc_size = size; + } + ++ item->pbuf = pointer; ++ item->alloc_size = size; ++ + item->header = BINN_MAGIC; + //item->allocated = FALSE; -- already zeroed + item->writable = TRUE; @@ -414,7 +413,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+binn * APIENTRY binn_copy(void *old) { ++binn * APIENTRY binn_copy(const void *old) { + int type, count, size, header_size; + unsigned char *old_ptr = binn_ptr(old); + binn *item; @@ -436,23 +435,39 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/*************************************************************************************/ + -+BOOL APIENTRY binn_load(void *data, binn *value) { ++// deprecated: unsecure. the size can be corrupted accidentally or intentionally ++BOOL APIENTRY binn_load(const void *data, binn *value) { + -+ if ((data == NULL) || (value == NULL)) return FALSE; ++ if (data == NULL || value == NULL) return FALSE; + memset(value, 0, sizeof(binn)); + value->header = BINN_MAGIC; + //value->allocated = FALSE; -- already zeroed + //value->writable = FALSE; + + if (binn_is_valid(data, &value->type, &value->count, &value->size) == FALSE) return FALSE; -+ value->ptr = data; ++ value->ptr = (void*) data; ++ return TRUE; ++ ++} ++ ++BOOL APIENTRY binn_load_ex(const void *data, int size, binn *value) { ++ ++ if (data == NULL || value == NULL || size <= 0) return FALSE; ++ memset(value, 0, sizeof(binn)); ++ value->header = BINN_MAGIC; ++ //value->allocated = FALSE; -- already zeroed ++ //value->writable = FALSE; ++ ++ if (binn_is_valid_ex(data, &value->type, &value->count, &size) == FALSE) return FALSE; ++ value->ptr = (void*) data; ++ value->size = size; + return TRUE; + +} + +/*************************************************************************************/ + -+binn * APIENTRY binn_open(void *data) { ++binn * APIENTRY binn_open(const void *data) { + binn *item; + + item = (binn*) binn_malloc(sizeof(binn)); @@ -467,9 +482,24 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +} + ++binn * APIENTRY binn_open_ex(const void *data, int size) { ++ binn *item; ++ ++ item = (binn*) binn_malloc(sizeof(binn)); ++ ++ if (binn_load_ex(data, size, item) == FALSE) { ++ free_fn(item); ++ return NULL; ++ } ++ ++ item->allocated = TRUE; ++ return item; ++ ++} ++ +/***************************************************************************/ + -+BINN_PRIVATE int binn_get_ptr_type(void *ptr) { ++BINN_PRIVATE int binn_get_ptr_type(const void *ptr) { + + if (ptr == NULL) return 0; + @@ -484,7 +514,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+BOOL APIENTRY binn_is_struct(void *ptr) { ++BOOL APIENTRY binn_is_struct(const void *ptr) { + + if (ptr == NULL) return FALSE; + @@ -614,8 +644,6 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return 0; + } + -+ if (p > plimit) return 0; -+ + return p; + +} @@ -641,6 +669,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + int id, extra_bytes; + + p = *pp; ++ if (p > plimit) return 0; + + c = *p++; + @@ -703,7 +732,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + if (int32 == id) return p; + // xxx + p = AdvanceDataPos(p, plimit); -+ if ((p == 0) || (p < base)) break; ++ if (p == 0 || p < base) break; + } + + return NULL; @@ -724,9 +753,10 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + // search for the key in all the arguments. + for (i = 0; i < numitems; i++) { ++ if (p > plimit) break; + len = *((unsigned char *)p); + p++; -+ if (p > plimit) break; ++ if (p + len > plimit) break; + // Compare if the strings are equal. + if (len > 0) { + if (strnicmp((char*)p, key, len) == 0) { // note that there is no null terminator here @@ -736,13 +766,12 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + } + } + p += len; -+ if (p > plimit) break; + } else if (len == keylen) { // in the case of empty string: "" + return p; + } + // xxx + p = AdvanceDataPos(p, plimit); -+ if ((p == 0) || (p < base)) break; ++ if (p == 0 || p < base) break; + } + + return NULL; @@ -757,7 +786,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +BINN_PRIVATE BOOL binn_list_add_raw(binn *item, int type, void *pvalue, int size) { + -+ if ((item == NULL) || (item->type != BINN_LIST) || (item->writable == FALSE)) return FALSE; ++ if (item == NULL || item->type != BINN_LIST || item->writable == FALSE) return FALSE; + + //if (CheckAllocation(item, 4) == FALSE) return FALSE; // 4 bytes used for data_store and data_format. + @@ -775,7 +804,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + unsigned char *p, len; + int int32; + -+ if ((item == NULL) || (item->type != BINN_OBJECT) || (item->writable == FALSE)) return FALSE; ++ if (item == NULL || item->type != BINN_OBJECT || item->writable == FALSE) return FALSE; + + if (key == NULL) return FALSE; + int32 = strlen(key); @@ -814,7 +843,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + unsigned char *base, *p, sign; + int id_size; + -+ if ((item == NULL) || (item->type != BINN_MAP) || (item->writable == FALSE)) return FALSE; ++ if (item == NULL || item->type != BINN_MAP || item->writable == FALSE) return FALSE; + + // is the ID already in it? + p = SearchForID(item->pbuf, MAX_BINN_HEADER, item->used_size, item->count, id); @@ -937,7 +966,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + pvalue = (char *) psource; + -+ if ((type2) && (type2 != type)) { ++ if (type2 && type2 != type) { + *ptype = type2; + storage_type2 = binn_get_write_storage(type2); + *pstorage_type = storage_type2; @@ -975,7 +1004,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + } + } + -+ if ((type_family(type) == BINN_FAMILY_INT) && (item->disable_int_compression == FALSE)) ++ if (type_family(type) == BINN_FAMILY_INT && item->disable_int_compression == FALSE) + pvalue = compress_int(&storage_type, &type, pvalue); + + switch (storage_type) { @@ -1165,7 +1194,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + if (item == NULL) return; + -+ if ((item->writable) && (item->pre_allocated == FALSE)) { ++ if (item->writable && item->pre_allocated == FALSE) { + free_fn(item->pbuf); + } + @@ -1207,7 +1236,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+BINN_PRIVATE BOOL IsValidBinnHeader(void *pbuf, int *ptype, int *pcount, int *psize, int *pheadersize) { ++BINN_PRIVATE BOOL IsValidBinnHeader(const void *pbuf, int *ptype, int *pcount, int *psize, int *pheadersize) { + unsigned char byte, *p, *plimit=0; + int int32, type, size, count; + @@ -1216,6 +1245,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + p = (unsigned char *) pbuf; + + if (psize && *psize > 0) { ++ if (*psize < MIN_BINN_SIZE) return FALSE; + plimit = p + *psize - 1; + } + @@ -1260,31 +1290,19 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + } + count = int32; + -+#if 0 -+ // get the size -+ copy_be32((u32*)&size, (u32*)p); -+ size &= 0x7FFFFFFF; -+ p+=4; -+ -+ // get the count -+ copy_be32((u32*)&count, (u32*)p); -+ count &= 0x7FFFFFFF; -+ p+=4; -+#endif -+ -+ if ((size < MIN_BINN_SIZE) || (count < 0)) return FALSE; ++ if (size < MIN_BINN_SIZE || count < 0) return FALSE; + + // return the values + if (ptype) *ptype = type; + if (pcount) *pcount = count; -+ if (psize && *psize==0) *psize = size; ++ if (psize) *psize = size; + if (pheadersize) *pheadersize = (int) (p - (unsigned char*)pbuf); + return TRUE; +} + +/***************************************************************************/ + -+BINN_PRIVATE int binn_buf_type(void *pbuf) { ++BINN_PRIVATE int binn_buf_type(const void *pbuf) { + int type; + + if (!IsValidBinnHeader(pbuf, &type, NULL, NULL, NULL)) return INVALID_BINN; @@ -1295,7 +1313,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+BINN_PRIVATE int binn_buf_count(void *pbuf) { ++BINN_PRIVATE int binn_buf_count(const void *pbuf) { + int nitems; + + if (!IsValidBinnHeader(pbuf, NULL, &nitems, NULL, NULL)) return 0; @@ -1306,7 +1324,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+BINN_PRIVATE int binn_buf_size(void *pbuf) { ++BINN_PRIVATE int binn_buf_size(const void *pbuf) { + int size=0; + + if (!IsValidBinnHeader(pbuf, NULL, NULL, &size, NULL)) return 0; @@ -1317,7 +1335,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+void * APIENTRY binn_ptr(void *ptr) { ++void * APIENTRY binn_ptr(const void *ptr) { + binn *item; + + switch (binn_get_ptr_type(ptr)) { @@ -1328,7 +1346,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + } + return item->ptr; + case BINN_BUFFER: -+ return ptr; ++ return (void*)ptr; + default: + return NULL; + } @@ -1337,7 +1355,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+int APIENTRY binn_size(void *ptr) { ++int APIENTRY binn_size(const void *ptr) { + binn *item; + + switch (binn_get_ptr_type(ptr)) { @@ -1357,7 +1375,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+int APIENTRY binn_type(void *ptr) { ++int APIENTRY binn_type(const void *ptr) { + binn *item; + + switch (binn_get_ptr_type(ptr)) { @@ -1374,7 +1392,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+int APIENTRY binn_count(void *ptr) { ++int APIENTRY binn_count(const void *ptr) { + binn *item; + + switch (binn_get_ptr_type(ptr)) { @@ -1391,13 +1409,12 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+BOOL APIENTRY binn_is_valid_ex(void *ptr, int *ptype, int *pcount, int *psize) { ++// the container can be smaller than the informed size ++BINN_PRIVATE BOOL binn_is_valid_ex2(const void *ptr, int *ptype, int *pcount, int *psize) { + int i, type, count, size, header_size; + unsigned char *p, *plimit, *base, len; -+ void *pbuf; + -+ pbuf = binn_ptr(ptr); -+ if (pbuf == NULL) return FALSE; ++ if (ptr == NULL) return FALSE; + + // is there an informed size? + if (psize && *psize > 0) { @@ -1406,12 +1423,12 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + size = 0; + } + -+ if (!IsValidBinnHeader(pbuf, &type, &count, &size, &header_size)) return FALSE; ++ if (!IsValidBinnHeader(ptr, &type, &count, &size, &header_size)) return FALSE; + + // is there an informed size? + if (psize && *psize > 0) { -+ // is it the same as the one in the buffer? -+ if (size != *psize) return FALSE; ++ // is it bigger than the buffer? ++ if (size > *psize) return FALSE; + } + // is there an informed count? + if (pcount && *pcount > 0) { @@ -1424,40 +1441,51 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + if (type != *ptype) return FALSE; + } + -+ // it could compare the content size with the size informed on the header -+ -+ p = (unsigned char *)pbuf; ++ p = (unsigned char *)ptr; + base = p; -+ plimit = p + size; ++ plimit = p + size - 1; + + p += header_size; + -+ // process all the arguments. ++ // process each (key and) value + for (i = 0; i < count; i++) { + switch (type) { + case BINN_OBJECT: -+ // gets the string size (argument name) ++ if (p > plimit) goto Invalid; ++ // get the key (string) size + len = *p; + p++; + //if (len == 0) goto Invalid; -+ // increment the used space ++ // advance over the key + p += len; + break; + case BINN_MAP: -+ // increment the used space ++ // advance over the key + read_map_id(&p, plimit); + break; -+ //case BINN_LIST: -+ // break; ++ case BINN_LIST: ++ // no key ++ break; ++ default: ++ goto Invalid; ++ } ++ // check the value ++ if (p > plimit) goto Invalid; ++ if ((*p & BINN_STORAGE_MASK) == BINN_STORAGE_CONTAINER) { ++ // recursively check the internal container ++ int size2 = plimit - p + 1; // maximum container size ++ if (binn_is_valid_ex2(p, NULL, NULL, &size2) == FALSE) goto Invalid; ++ p += size2; ++ } else { ++ // advance over the value ++ p = AdvanceDataPos(p, plimit); ++ if (p == 0 || p < base) goto Invalid; + } -+ // xxx -+ p = AdvanceDataPos(p, plimit); -+ if ((p == 0) || (p < base)) goto Invalid; + } + -+ if (ptype && *ptype==0) *ptype = type; ++ if (ptype && *ptype==0) *ptype = type; + if (pcount && *pcount==0) *pcount = count; -+ if (psize && *psize==0) *psize = size; ++ if (psize) *psize = size; + return TRUE; + +Invalid: @@ -1465,9 +1493,32 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +} + ++// the container must have the informed size, if informed ++BOOL APIENTRY binn_is_valid_ex(const void *ptr, int *ptype, int *pcount, int *psize) { ++ int size; ++ ++ if (psize && *psize > 0) { ++ size = *psize; ++ } else { ++ size = 0; ++ } ++ ++ if (binn_is_valid_ex2(ptr, ptype, pcount, &size) == FALSE) return FALSE; ++ ++ if (psize) { ++ if (*psize > 0) { ++ if (size != *psize) return FALSE; ++ } else if (*psize==0) { ++ *psize = size; ++ } ++ } ++ ++ return TRUE; ++} ++ +/***************************************************************************/ + -+BOOL APIENTRY binn_is_valid(void *ptr, int *ptype, int *pcount, int *psize) { ++BOOL APIENTRY binn_is_valid(const void *ptr, int *ptype, int *pcount, int *psize) { + + if (ptype) *ptype = 0; + if (pcount) *pcount = 0; @@ -1481,7 +1532,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +/*** INTERNAL FUNCTIONS ****************************************************/ +/***************************************************************************/ + -+BINN_PRIVATE BOOL GetValue(unsigned char *p, binn *value) { ++BINN_PRIVATE BOOL GetValue(unsigned char *p, unsigned char *plimit, binn *value) { + unsigned char byte; + int data_type, storage_type; //, extra_type; + int DataSize; @@ -1497,10 +1548,12 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + p2 = p; + + // read the data type ++ if (p > plimit) return FALSE; + byte = *p; p++; + storage_type = byte & BINN_STORAGE_MASK; + if (byte & BINN_STORAGE_HAS_MORE) { + data_type = byte << 8; ++ if (p > plimit) return FALSE; + byte = *p; p++; + data_type |= byte; + //extra_type = data_type & BINN_TYPE_MASK16; @@ -1516,31 +1569,38 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + case BINN_STORAGE_NOBYTES: + break; + case BINN_STORAGE_BYTE: ++ if (p > plimit) return FALSE; + value->vuint8 = *((unsigned char *) p); + value->ptr = p; //value->ptr = &value->vuint8; + break; + case BINN_STORAGE_WORD: ++ if (p + 1 > plimit) return FALSE; + copy_be16((u16*)&value->vint16, (u16*)p); + value->ptr = &value->vint16; + break; + case BINN_STORAGE_DWORD: ++ if (p + 3 > plimit) return FALSE; + copy_be32((u32*)&value->vint32, (u32*)p); + value->ptr = &value->vint32; + break; + case BINN_STORAGE_QWORD: ++ if (p + 7 > plimit) return FALSE; + copy_be64((u64*)&value->vint64, (u64*)p); + value->ptr = &value->vint64; + break; + case BINN_STORAGE_BLOB: + case BINN_STORAGE_STRING: ++ if (p > plimit) return FALSE; + DataSize = *((unsigned char*)p); + if (DataSize & 0x80) { ++ if (p + 3 > plimit) return FALSE; + copy_be32((u32*)&DataSize, (u32*)p); + DataSize &= 0x7FFFFFFF; + p+=4; + } else { + p++; + } ++ if (p + DataSize - 1 > plimit) return FALSE; + value->size = DataSize; + value->ptr = p; + break; @@ -1622,12 +1682,12 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +/*** READ FUNCTIONS ********************************************************/ +/***************************************************************************/ + -+BOOL APIENTRY binn_object_get_value(void *ptr, const char *key, binn *value) { ++BOOL APIENTRY binn_object_get_value(const void *ptr, const char *key, binn *value) { + int type, count, size=0, header_size; -+ unsigned char *p; ++ unsigned char *p, *plimit; + + ptr = binn_ptr(ptr); -+ if ((ptr == 0) || (key == 0) || (value == 0)) return FALSE; ++ if (ptr == NULL || key == NULL || value == NULL) return FALSE; + + // check the header + if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE; @@ -1636,21 +1696,23 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + if (count == 0) return FALSE; + + p = (unsigned char *) ptr; ++ plimit = p + size - 1; ++ + p = SearchForKey(p, header_size, size, count, key); + if (p == FALSE) return FALSE; + -+ return GetValue(p, value); ++ return GetValue(p, plimit, value); + +} + +/***************************************************************************/ + -+BOOL APIENTRY binn_map_get_value(void* ptr, int id, binn *value) { ++BOOL APIENTRY binn_map_get_value(const void *ptr, int id, binn *value) { + int type, count, size=0, header_size; -+ unsigned char *p; ++ unsigned char *p, *plimit; + + ptr = binn_ptr(ptr); -+ if ((ptr == 0) || (value == 0)) return FALSE; ++ if (ptr == NULL || value == NULL) return FALSE; + + // check the header + if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE; @@ -1659,41 +1721,43 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + if (count == 0) return FALSE; + + p = (unsigned char *) ptr; ++ plimit = p + size - 1; ++ + p = SearchForID(p, header_size, size, count, id); + if (p == FALSE) return FALSE; + -+ return GetValue(p, value); ++ return GetValue(p, plimit, value); + +} + +/***************************************************************************/ + -+BOOL APIENTRY binn_list_get_value(void* ptr, int pos, binn *value) { ++BOOL APIENTRY binn_list_get_value(const void *ptr, int pos, binn *value) { + int i, type, count, size=0, header_size; + unsigned char *p, *plimit, *base; + + ptr = binn_ptr(ptr); -+ if ((ptr == 0) || (value == 0)) return FALSE; ++ if (ptr == NULL || value == NULL) return FALSE; + + // check the header + if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE; + + if (type != BINN_LIST) return FALSE; + if (count == 0) return FALSE; -+ if ((pos <= 0) | (pos > count)) return FALSE; ++ if (pos <= 0 || pos > count) return FALSE; + pos--; // convert from base 1 to base 0 + + p = (unsigned char *) ptr; + base = p; -+ plimit = p + size; ++ plimit = p + size - 1; + p += header_size; + + for (i = 0; i < pos; i++) { + p = AdvanceDataPos(p, plimit); -+ if ((p == 0) || (p < base)) return FALSE; ++ if (p == 0 || p < base) return FALSE; + } + -+ return GetValue(p, value); ++ return GetValue(p, plimit, value); + +} + @@ -1701,7 +1765,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +/*** READ PAIR BY POSITION *************************************************/ +/***************************************************************************/ + -+BINN_PRIVATE BOOL binn_read_pair(int expected_type, void *ptr, int pos, int *pid, char *pkey, binn *value) { ++BINN_PRIVATE BOOL binn_read_pair(int expected_type, const void *ptr, int pos, int *pid, char *pkey, binn *value) { + int type, count, size=0, header_size; + int i, int32, id = 0, counter=0; + unsigned char *p, *plimit, *base, *key = NULL, len = 0; @@ -1711,7 +1775,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + // check the header + if (IsValidBinnHeader(ptr, &type, &count, &size, &header_size) == FALSE) return FALSE; + -+ if ((type != expected_type) || (count == 0) || (pos < 1) || (pos > count)) return FALSE; ++ if (type != expected_type || count == 0 || pos < 1 || pos > count) return FALSE; + + p = (unsigned char *) ptr; + base = p; @@ -1737,7 +1801,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + if (counter == pos) goto found; + // + p = AdvanceDataPos(p, plimit); -+ if ((p == 0) || (p < base)) return FALSE; ++ if (p == 0 || p < base) return FALSE; + } + + return FALSE; @@ -1756,13 +1820,13 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + break; + } + -+ return GetValue(p, value); ++ return GetValue(p, plimit, value); + +} + +/***************************************************************************/ + -+BOOL APIENTRY binn_map_get_pair(void *ptr, int pos, int *pid, binn *value) { ++BOOL APIENTRY binn_map_get_pair(const void *ptr, int pos, int *pid, binn *value) { + + return binn_read_pair(BINN_MAP, ptr, pos, pid, NULL, value); + @@ -1770,7 +1834,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+BOOL APIENTRY binn_object_get_pair(void *ptr, int pos, char *pkey, binn *value) { ++BOOL APIENTRY binn_object_get_pair(const void *ptr, int pos, char *pkey, binn *value) { + + return binn_read_pair(BINN_OBJECT, ptr, pos, NULL, pkey, value); + @@ -1778,7 +1842,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+binn * APIENTRY binn_map_pair(void *map, int pos, int *pid) { ++binn * APIENTRY binn_map_pair(const void *map, int pos, int *pid) { + binn *value; + + value = (binn *) binn_malloc(sizeof(binn)); @@ -1795,7 +1859,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+binn * APIENTRY binn_object_pair(void *obj, int pos, char *pkey) { ++binn * APIENTRY binn_object_pair(const void *obj, int pos, char *pkey) { + binn *value; + + value = (binn *) binn_malloc(sizeof(binn)); @@ -1813,7 +1877,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +/***************************************************************************/ +/***************************************************************************/ + -+void * APIENTRY binn_map_read_pair(void *ptr, int pos, int *pid, int *ptype, int *psize) { ++void * APIENTRY binn_map_read_pair(const void *ptr, int pos, int *pid, int *ptype, int *psize) { + binn value; + + if (binn_map_get_pair(ptr, pos, pid, &value) == FALSE) return NULL; @@ -1829,7 +1893,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+void * APIENTRY binn_object_read_pair(void *ptr, int pos, char *pkey, int *ptype, int *psize) { ++void * APIENTRY binn_object_read_pair(const void *ptr, int pos, char *pkey, int *ptype, int *psize) { + binn value; + + if (binn_object_get_pair(ptr, pos, pkey, &value) == FALSE) return NULL; @@ -1847,11 +1911,11 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +/*** SEQUENTIAL READ FUNCTIONS *********************************************/ +/***************************************************************************/ + -+BOOL APIENTRY binn_iter_init(binn_iter *iter, void *ptr, int expected_type) { ++BOOL APIENTRY binn_iter_init(binn_iter *iter, const void *ptr, int expected_type) { + int type, count, size=0, header_size; + + ptr = binn_ptr(ptr); -+ if ((ptr == 0) || (iter == 0)) return FALSE; ++ if (ptr == NULL || iter == NULL) return FALSE; + memset(iter, 0, sizeof(binn_iter)); + + // check the header @@ -1874,7 +1938,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +BOOL APIENTRY binn_list_next(binn_iter *iter, binn *value) { + unsigned char *pnow; + -+ if ((iter == 0) || (iter->pnext == 0) || (iter->pnext > iter->plimit) || (iter->current > iter->count) || (iter->type != BINN_LIST)) return FALSE; ++ if (iter == NULL || iter->pnext == NULL || iter->pnext > iter->plimit || iter->current > iter->count || iter->type != BINN_LIST) return FALSE; + + iter->current++; + if (iter->current > iter->count) return FALSE; @@ -1883,7 +1947,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + iter->pnext = AdvanceDataPos(pnow, iter->plimit); + if (iter->pnext != 0 && iter->pnext < pnow) return FALSE; + -+ return GetValue(pnow, value); ++ return GetValue(pnow, iter->plimit, value); + +} + @@ -1894,7 +1958,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + unsigned char *p, *key; + unsigned short len; + -+ if ((iter == 0) || (iter->pnext == 0) || (iter->pnext > iter->plimit) || (iter->current > iter->count) || (iter->type != expected_type)) return FALSE; ++ if (iter == NULL || iter->pnext == NULL || iter->pnext > iter->plimit || iter->current > iter->count || iter->type != expected_type) return FALSE; + + iter->current++; + if (iter->current > iter->count) return FALSE; @@ -1923,7 +1987,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + iter->pnext = AdvanceDataPos(p, iter->plimit); + if (iter->pnext != 0 && iter->pnext < p) return FALSE; + -+ return GetValue(p, value); ++ return GetValue(p, iter->plimit, value); + +} + @@ -2255,7 +2319,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/*************************************************************************************/ + -+BINN_PRIVATE BOOL copy_raw_value(void *psource, void *pdest, int data_store) { ++BINN_PRIVATE BOOL copy_raw_value(const void *psource, void *pdest, int data_store) { + + switch (data_store) { + case BINN_STORAGE_NOBYTES: @@ -2287,7 +2351,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/*************************************************************************************/ + -+BINN_PRIVATE BOOL copy_int_value(void *psource, void *pdest, int source_type, int dest_type) { ++BINN_PRIVATE BOOL copy_int_value(const void *psource, void *pdest, int source_type, int dest_type) { + uint64 vuint64 = 0; int64 vint64 = 0; + + switch (source_type) { @@ -2324,10 +2388,10 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + // copy from int64 to uint64, if possible + -+ if ((int_type(source_type) == BINN_UNSIGNED_INT) && (int_type(dest_type) == BINN_SIGNED_INT)) { ++ if (int_type(source_type) == BINN_UNSIGNED_INT && int_type(dest_type) == BINN_SIGNED_INT) { + if (vuint64 > INT64_MAX) return FALSE; + vint64 = vuint64; -+ } else if ((int_type(source_type) == BINN_SIGNED_INT) && (int_type(dest_type) == BINN_UNSIGNED_INT)) { ++ } else if (int_type(source_type) == BINN_SIGNED_INT && int_type(dest_type) == BINN_UNSIGNED_INT) { + if (vint64 < 0) return FALSE; + vuint64 = vint64; + } @@ -2335,15 +2399,15 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + switch (dest_type) { + case BINN_INT8: -+ if ((vint64 < INT8_MIN) || (vint64 > INT8_MAX)) return FALSE; ++ if (vint64 < INT8_MIN || vint64 > INT8_MAX) return FALSE; + *(signed char *)pdest = (signed char) vint64; + break; + case BINN_INT16: -+ if ((vint64 < INT16_MIN) || (vint64 > INT16_MAX)) return FALSE; ++ if (vint64 < INT16_MIN || vint64 > INT16_MAX) return FALSE; + *(short *)pdest = (short) vint64; + break; + case BINN_INT32: -+ if ((vint64 < INT32_MIN) || (vint64 > INT32_MAX)) return FALSE; ++ if (vint64 < INT32_MIN || vint64 > INT32_MAX) return FALSE; + *(int *)pdest = (int) vint64; + break; + case BINN_INT64: @@ -2376,7 +2440,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/*************************************************************************************/ + -+BINN_PRIVATE BOOL copy_float_value(void *psource, void *pdest, int source_type) { ++BINN_PRIVATE BOOL copy_float_value(const void *psource, void *pdest, int source_type, int dest_type) { + + switch (source_type) { + case BINN_FLOAT32: @@ -2395,7 +2459,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/*************************************************************************************/ + -+BINN_PRIVATE void zero_value(void *pvalue, int type) { ++BINN_PRIVATE void zero_value(const void *pvalue, int type) { + //int size=0; + + switch (binn_get_read_storage(type)) { @@ -2434,10 +2498,10 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + if (type_family(source_type) != type_family(dest_type)) return FALSE; + -+ if ((type_family(source_type) == BINN_FAMILY_INT) && (source_type != dest_type)) { ++ if (type_family(source_type) == BINN_FAMILY_INT && source_type != dest_type) { + return copy_int_value(psource, pdest, source_type, dest_type); -+ } else if ((type_family(source_type) == BINN_FAMILY_FLOAT) && (source_type != dest_type)) { -+ return copy_float_value(psource, pdest, source_type); ++ } else if (type_family(source_type) == BINN_FAMILY_FLOAT && source_type != dest_type) { ++ return copy_float_value(psource, pdest, source_type, dest_type); + } else { + return copy_raw_value(psource, pdest, data_store); + } @@ -2532,7 +2596,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +/*** READ FUNCTIONS ******************************************************************/ +/*************************************************************************************/ + -+binn * APIENTRY binn_list_value(void *ptr, int pos) { ++binn * APIENTRY binn_list_value(const void *ptr, int pos) { + binn *value; + + value = (binn *) binn_malloc(sizeof(binn)); @@ -2549,7 +2613,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/*************************************************************************************/ + -+binn * APIENTRY binn_map_value(void *ptr, int id) { ++binn * APIENTRY binn_map_value(const void *ptr, int id) { + binn *value; + + value = (binn *) binn_malloc(sizeof(binn)); @@ -2566,7 +2630,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/*************************************************************************************/ + -+binn * APIENTRY binn_object_value(void *ptr, const char *key) { ++binn * APIENTRY binn_object_value(const void *ptr, const char *key) { + binn *value; + + value = (binn *) binn_malloc(sizeof(binn)); @@ -2584,7 +2648,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +/***************************************************************************/ +/***************************************************************************/ + -+void * APIENTRY binn_list_read(void *list, int pos, int *ptype, int *psize) { ++void * APIENTRY binn_list_read(const void *list, int pos, int *ptype, int *psize) { + binn value; + + if (binn_list_get_value(list, pos, &value) == FALSE) return NULL; @@ -2600,7 +2664,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+void * APIENTRY binn_map_read(void *map, int id, int *ptype, int *psize) { ++void * APIENTRY binn_map_read(const void *map, int id, int *ptype, int *psize) { + binn value; + + if (binn_map_get_value(map, id, &value) == FALSE) return NULL; @@ -2616,7 +2680,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+void * APIENTRY binn_object_read(void *obj, const char *key, int *ptype, int *psize) { ++void * APIENTRY binn_object_read(const void *obj, const char *key, int *ptype, int *psize) { + binn value; + + if (binn_object_get_value(obj, key, &value) == FALSE) return NULL; @@ -2633,12 +2697,12 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +/***************************************************************************/ +/***************************************************************************/ + -+BOOL APIENTRY binn_list_get(void *ptr, int pos, int type, void *pvalue, int *psize) { ++BOOL APIENTRY binn_list_get(const void *ptr, int pos, int type, void *pvalue, int *psize) { + binn value; + int storage_type; + + storage_type = binn_get_read_storage(type); -+ if ((storage_type != BINN_STORAGE_NOBYTES) && (pvalue == NULL)) return FALSE; ++ if (storage_type != BINN_STORAGE_NOBYTES && pvalue == NULL) return FALSE; + + zero_value(pvalue, type); + @@ -2654,12 +2718,12 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+BOOL APIENTRY binn_map_get(void *ptr, int id, int type, void *pvalue, int *psize) { ++BOOL APIENTRY binn_map_get(const void *ptr, int id, int type, void *pvalue, int *psize) { + binn value; + int storage_type; + + storage_type = binn_get_read_storage(type); -+ if ((storage_type != BINN_STORAGE_NOBYTES) && (pvalue == NULL)) return FALSE; ++ if (storage_type != BINN_STORAGE_NOBYTES && pvalue == NULL) return FALSE; + + zero_value(pvalue, type); + @@ -2677,12 +2741,12 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +// if (binn_object_get(obj, "multiplier", BINN_INT32, &multiplier, NULL) == FALSE) xxx; + -+BOOL APIENTRY binn_object_get(void *ptr, const char *key, int type, void *pvalue, int *psize) { ++BOOL APIENTRY binn_object_get(const void *ptr, const char *key, int type, void *pvalue, int *psize) { + binn value; + int storage_type; + + storage_type = binn_get_read_storage(type); -+ if ((storage_type != BINN_STORAGE_NOBYTES) && (pvalue == NULL)) return FALSE; ++ if (storage_type != BINN_STORAGE_NOBYTES && pvalue == NULL) return FALSE; + + zero_value(pvalue, type); + @@ -2706,7 +2770,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +// is there any problem with wrappers? can these wrappers implement these functions using the header? +// if as static, will they be present even on modules that don't use the functions? + -+signed char APIENTRY binn_list_int8(void *list, int pos) { ++signed char APIENTRY binn_list_int8(const void *list, int pos) { + signed char value; + + binn_list_get(list, pos, BINN_INT8, &value, NULL); @@ -2714,7 +2778,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+short APIENTRY binn_list_int16(void *list, int pos) { ++short APIENTRY binn_list_int16(const void *list, int pos) { + short value; + + binn_list_get(list, pos, BINN_INT16, &value, NULL); @@ -2722,7 +2786,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+int APIENTRY binn_list_int32(void *list, int pos) { ++int APIENTRY binn_list_int32(const void *list, int pos) { + int value; + + binn_list_get(list, pos, BINN_INT32, &value, NULL); @@ -2730,7 +2794,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+int64 APIENTRY binn_list_int64(void *list, int pos) { ++int64 APIENTRY binn_list_int64(const void *list, int pos) { + int64 value; + + binn_list_get(list, pos, BINN_INT64, &value, NULL); @@ -2738,7 +2802,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned char APIENTRY binn_list_uint8(void *list, int pos) { ++unsigned char APIENTRY binn_list_uint8(const void *list, int pos) { + unsigned char value; + + binn_list_get(list, pos, BINN_UINT8, &value, NULL); @@ -2746,7 +2810,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned short APIENTRY binn_list_uint16(void *list, int pos) { ++unsigned short APIENTRY binn_list_uint16(const void *list, int pos) { + unsigned short value; + + binn_list_get(list, pos, BINN_UINT16, &value, NULL); @@ -2754,7 +2818,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned int APIENTRY binn_list_uint32(void *list, int pos) { ++unsigned int APIENTRY binn_list_uint32(const void *list, int pos) { + unsigned int value; + + binn_list_get(list, pos, BINN_UINT32, &value, NULL); @@ -2762,7 +2826,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+uint64 APIENTRY binn_list_uint64(void *list, int pos) { ++uint64 APIENTRY binn_list_uint64(const void *list, int pos) { + uint64 value; + + binn_list_get(list, pos, BINN_UINT64, &value, NULL); @@ -2770,7 +2834,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+float APIENTRY binn_list_float(void *list, int pos) { ++float APIENTRY binn_list_float(const void *list, int pos) { + float value; + + binn_list_get(list, pos, BINN_FLOAT32, &value, NULL); @@ -2778,7 +2842,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+double APIENTRY binn_list_double(void *list, int pos) { ++double APIENTRY binn_list_double(const void *list, int pos) { + double value; + + binn_list_get(list, pos, BINN_FLOAT64, &value, NULL); @@ -2786,21 +2850,21 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+BOOL APIENTRY binn_list_bool(void *list, int pos) { -+ BOOL value; ++BOOL APIENTRY binn_list_bool(const void *list, int pos) { ++ BOOL value = TRUE; + + binn_list_get(list, pos, BINN_BOOL, &value, NULL); + + return value; +} + -+BOOL APIENTRY binn_list_null(void *list, int pos) { ++BOOL APIENTRY binn_list_null(const void *list, int pos) { + + return binn_list_get(list, pos, BINN_NULL, NULL, NULL); + +} + -+char * APIENTRY binn_list_str(void *list, int pos) { ++char * APIENTRY binn_list_str(const void *list, int pos) { + char *value; + + binn_list_get(list, pos, BINN_STRING, &value, NULL); @@ -2808,7 +2872,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_list_blob(void *list, int pos, int *psize) { ++void * APIENTRY binn_list_blob(const void *list, int pos, int *psize) { + void *value; + + binn_list_get(list, pos, BINN_BLOB, &value, psize); @@ -2816,7 +2880,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_list_list(void *list, int pos) { ++void * APIENTRY binn_list_list(const void *list, int pos) { + void *value; + + binn_list_get(list, pos, BINN_LIST, &value, NULL); @@ -2824,7 +2888,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_list_map(void *list, int pos) { ++void * APIENTRY binn_list_map(const void *list, int pos) { + void *value; + + binn_list_get(list, pos, BINN_MAP, &value, NULL); @@ -2832,7 +2896,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_list_object(void *list, int pos) { ++void * APIENTRY binn_list_object(const void *list, int pos) { + void *value; + + binn_list_get(list, pos, BINN_OBJECT, &value, NULL); @@ -2842,7 +2906,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+signed char APIENTRY binn_map_int8(void *map, int id) { ++signed char APIENTRY binn_map_int8(const void *map, int id) { + signed char value; + + binn_map_get(map, id, BINN_INT8, &value, NULL); @@ -2850,7 +2914,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+short APIENTRY binn_map_int16(void *map, int id) { ++short APIENTRY binn_map_int16(const void *map, int id) { + short value; + + binn_map_get(map, id, BINN_INT16, &value, NULL); @@ -2858,7 +2922,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+int APIENTRY binn_map_int32(void *map, int id) { ++int APIENTRY binn_map_int32(const void *map, int id) { + int value; + + binn_map_get(map, id, BINN_INT32, &value, NULL); @@ -2866,7 +2930,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+int64 APIENTRY binn_map_int64(void *map, int id) { ++int64 APIENTRY binn_map_int64(const void *map, int id) { + int64 value; + + binn_map_get(map, id, BINN_INT64, &value, NULL); @@ -2874,7 +2938,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned char APIENTRY binn_map_uint8(void *map, int id) { ++unsigned char APIENTRY binn_map_uint8(const void *map, int id) { + unsigned char value; + + binn_map_get(map, id, BINN_UINT8, &value, NULL); @@ -2882,7 +2946,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned short APIENTRY binn_map_uint16(void *map, int id) { ++unsigned short APIENTRY binn_map_uint16(const void *map, int id) { + unsigned short value; + + binn_map_get(map, id, BINN_UINT16, &value, NULL); @@ -2890,7 +2954,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned int APIENTRY binn_map_uint32(void *map, int id) { ++unsigned int APIENTRY binn_map_uint32(const void *map, int id) { + unsigned int value; + + binn_map_get(map, id, BINN_UINT32, &value, NULL); @@ -2898,7 +2962,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+uint64 APIENTRY binn_map_uint64(void *map, int id) { ++uint64 APIENTRY binn_map_uint64(const void *map, int id) { + uint64 value; + + binn_map_get(map, id, BINN_UINT64, &value, NULL); @@ -2906,7 +2970,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+float APIENTRY binn_map_float(void *map, int id) { ++float APIENTRY binn_map_float(const void *map, int id) { + float value; + + binn_map_get(map, id, BINN_FLOAT32, &value, NULL); @@ -2914,7 +2978,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+double APIENTRY binn_map_double(void *map, int id) { ++double APIENTRY binn_map_double(const void *map, int id) { + double value; + + binn_map_get(map, id, BINN_FLOAT64, &value, NULL); @@ -2922,21 +2986,21 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+BOOL APIENTRY binn_map_bool(void *map, int id) { -+ BOOL value; ++BOOL APIENTRY binn_map_bool(const void *map, int id) { ++ BOOL value = TRUE; + + binn_map_get(map, id, BINN_BOOL, &value, NULL); + + return value; +} + -+BOOL APIENTRY binn_map_null(void *map, int id) { ++BOOL APIENTRY binn_map_null(const void *map, int id) { + + return binn_map_get(map, id, BINN_NULL, NULL, NULL); + +} + -+char * APIENTRY binn_map_str(void *map, int id) { ++char * APIENTRY binn_map_str(const void *map, int id) { + char *value; + + binn_map_get(map, id, BINN_STRING, &value, NULL); @@ -2944,7 +3008,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_map_blob(void *map, int id, int *psize) { ++void * APIENTRY binn_map_blob(const void *map, int id, int *psize) { + void *value; + + binn_map_get(map, id, BINN_BLOB, &value, psize); @@ -2952,7 +3016,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_map_list(void *map, int id) { ++void * APIENTRY binn_map_list(const void *map, int id) { + void *value; + + binn_map_get(map, id, BINN_LIST, &value, NULL); @@ -2960,7 +3024,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_map_map(void *map, int id) { ++void * APIENTRY binn_map_map(const void *map, int id) { + void *value; + + binn_map_get(map, id, BINN_MAP, &value, NULL); @@ -2968,7 +3032,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_map_object(void *map, int id) { ++void * APIENTRY binn_map_object(const void *map, int id) { + void *value; + + binn_map_get(map, id, BINN_OBJECT, &value, NULL); @@ -2978,7 +3042,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +/***************************************************************************/ + -+signed char APIENTRY binn_object_int8(void *obj, const char *key) { ++signed char APIENTRY binn_object_int8(const void *obj, const char *key) { + signed char value; + + binn_object_get(obj, key, BINN_INT8, &value, NULL); @@ -2986,7 +3050,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+short APIENTRY binn_object_int16(void *obj, const char *key) { ++short APIENTRY binn_object_int16(const void *obj, const char *key) { + short value; + + binn_object_get(obj, key, BINN_INT16, &value, NULL); @@ -2994,7 +3058,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+int APIENTRY binn_object_int32(void *obj, const char *key) { ++int APIENTRY binn_object_int32(const void *obj, const char *key) { + int value; + + binn_object_get(obj, key, BINN_INT32, &value, NULL); @@ -3002,7 +3066,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+int64 APIENTRY binn_object_int64(void *obj, const char *key) { ++int64 APIENTRY binn_object_int64(const void *obj, const char *key) { + int64 value; + + binn_object_get(obj, key, BINN_INT64, &value, NULL); @@ -3010,7 +3074,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned char APIENTRY binn_object_uint8(void *obj, const char *key) { ++unsigned char APIENTRY binn_object_uint8(const void *obj, const char *key) { + unsigned char value; + + binn_object_get(obj, key, BINN_UINT8, &value, NULL); @@ -3018,7 +3082,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned short APIENTRY binn_object_uint16(void *obj, const char *key) { ++unsigned short APIENTRY binn_object_uint16(const void *obj, const char *key) { + unsigned short value; + + binn_object_get(obj, key, BINN_UINT16, &value, NULL); @@ -3026,7 +3090,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+unsigned int APIENTRY binn_object_uint32(void *obj, const char *key) { ++unsigned int APIENTRY binn_object_uint32(const void *obj, const char *key) { + unsigned int value; + + binn_object_get(obj, key, BINN_UINT32, &value, NULL); @@ -3034,7 +3098,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+uint64 APIENTRY binn_object_uint64(void *obj, const char *key) { ++uint64 APIENTRY binn_object_uint64(const void *obj, const char *key) { + uint64 value; + + binn_object_get(obj, key, BINN_UINT64, &value, NULL); @@ -3042,7 +3106,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+float APIENTRY binn_object_float(void *obj, const char *key) { ++float APIENTRY binn_object_float(const void *obj, const char *key) { + float value; + + binn_object_get(obj, key, BINN_FLOAT32, &value, NULL); @@ -3050,7 +3114,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+double APIENTRY binn_object_double(void *obj, const char *key) { ++double APIENTRY binn_object_double(const void *obj, const char *key) { + double value; + + binn_object_get(obj, key, BINN_FLOAT64, &value, NULL); @@ -3058,21 +3122,21 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+BOOL APIENTRY binn_object_bool(void *obj, const char *key) { -+ BOOL value; ++BOOL APIENTRY binn_object_bool(const void *obj, const char *key) { ++ BOOL value = TRUE; + + binn_object_get(obj, key, BINN_BOOL, &value, NULL); + + return value; +} + -+BOOL APIENTRY binn_object_null(void *obj, const char *key) { ++BOOL APIENTRY binn_object_null(const void *obj, const char *key) { + + return binn_object_get(obj, key, BINN_NULL, NULL, NULL); + +} + -+char * APIENTRY binn_object_str(void *obj, const char *key) { ++char * APIENTRY binn_object_str(const void *obj, const char *key) { + char *value; + + binn_object_get(obj, key, BINN_STRING, &value, NULL); @@ -3080,7 +3144,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_object_blob(void *obj, const char *key, int *psize) { ++void * APIENTRY binn_object_blob(const void *obj, const char *key, int *psize) { + void *value; + + binn_object_get(obj, key, BINN_BLOB, &value, psize); @@ -3088,7 +3152,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_object_list(void *obj, const char *key) { ++void * APIENTRY binn_object_list(const void *obj, const char *key) { + void *value; + + binn_object_get(obj, key, BINN_LIST, &value, NULL); @@ -3096,7 +3160,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_object_map(void *obj, const char *key) { ++void * APIENTRY binn_object_map(const void *obj, const char *key) { + void *value; + + binn_object_get(obj, key, BINN_MAP, &value, NULL); @@ -3104,7 +3168,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + return value; +} + -+void * APIENTRY binn_object_object(void *obj, const char *key) { ++void * APIENTRY binn_object_object(const void *obj, const char *key) { + void *value; + + binn_object_get(obj, key, BINN_OBJECT, &value, NULL); @@ -3242,7 +3306,7 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + retval = TRUE; + + for (; *p; p++) { -+ if ( (*p < '0') || (*p > '9') ) { ++ if ( (*p < '0' || *p > '9') ) { + retval = FALSE; + } + } @@ -3262,9 +3326,9 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + retval = TRUE; + + for (; *p; p++) { -+ if ((*p == '.') || (*p == ',')) { ++ if (*p == '.' || *p == ',') { + if (!number_found) retval = FALSE; -+ } else if ( (*p >= '0') && (*p <= '9') ) { ++ } else if ( *p >= '0' && *p <= '9' ) { + number_found = TRUE; + } else { + return FALSE; @@ -3314,27 +3378,6 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + +} + -+/* these three functions are used to -+ * suppress warnings about implicit conversions -+ * in binn_get_int32 and binn_get_int64 -+ * CJR 2/9/2023 -+ */ -+ -+float -+binn_cvt_int2float (int value) { -+ return (float)value; -+} -+ -+float -+binn_cvt_long2float (long int value) { -+ return (float)value; -+} -+ -+float -+binn_cvt_long2dbl (long int value) { -+ return (long long int)value; -+} -+ +/*************************************************************************************/ + +BOOL APIENTRY binn_get_int32(binn *value, int *pint) { @@ -3347,11 +3390,11 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + switch (value->type) { + case BINN_FLOAT: -+ if ((value->vfloat < binn_cvt_int2float(INT32_MIN)) || (value->vfloat > binn_cvt_int2float(INT32_MAX))) return FALSE; ++ if (value->vfloat < (float)INT32_MIN || value->vfloat > (float)INT32_MAX) return FALSE; + *pint = roundval(value->vfloat); + break; + case BINN_DOUBLE: -+ if ((value->vdouble < INT32_MIN) || (value->vdouble > INT32_MAX)) return FALSE; ++ if (value->vdouble < (double)INT32_MIN || value->vdouble > (double)INT32_MAX) return FALSE; + *pint = roundval(value->vdouble); + break; + case BINN_STRING: @@ -3384,11 +3427,11 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c + + switch (value->type) { + case BINN_FLOAT: -+ if ((value->vfloat < binn_cvt_long2float(INT64_MIN)) || (value->vfloat > binn_cvt_long2float(INT64_MAX))) return FALSE; ++ if (value->vfloat < (float)INT64_MIN || value->vfloat > (float)INT64_MAX) return FALSE; + *pint = roundval(value->vfloat); + break; + case BINN_DOUBLE: -+ if ((value->vdouble < binn_cvt_long2dbl(INT64_MIN)) || (value->vdouble > binn_cvt_long2dbl(INT64_MAX))) return FALSE; ++ if (value->vdouble < (double)INT64_MIN || value->vdouble > (double)INT64_MAX) return FALSE; + *pint = roundval(value->vdouble); + break; + case BINN_STRING: @@ -3543,10 +3586,10 @@ diff -Nur openssh-9.3p1.orig/binn.c openssh-9.3p1/binn.c +} + +/*************************************************************************************/ -diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h ---- openssh-9.3p1.orig/binn.h 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/binn.h 2024-07-10 09:09:55.897568393 +0200 -@@ -0,0 +1,943 @@ +diff -Nur openssh-10.0p1.orig/binn.h openssh-10.0p1/binn.h +--- openssh-10.0p1.orig/binn.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/binn.h 2025-06-14 10:54:01.303905629 +0200 +@@ -0,0 +1,945 @@ + +// TO ENABLE INLINE FUNCTIONS: +// ON MSVC: enable the 'Inline Function Expansion' (/Ob2) compiler option, and maybe the @@ -3555,7 +3598,7 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h + +#ifndef BINN_H +#define BINN_H -+#include ++ +#ifdef __cplusplus +extern "C" { +#endif @@ -3831,7 +3874,7 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h +BOOL APIENTRY binn_create_object(binn *object); + +// create a new binn as a copy from another -+binn * APIENTRY binn_copy(void *old); ++binn * APIENTRY binn_copy(const void *old); + + +BOOL APIENTRY binn_list_add_new(binn *list, binn *value); @@ -3903,19 +3946,19 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h +// --- READ FUNCTIONS ------------------------------------------------------------- + +// these functions accept pointer to the binn structure and pointer to the binn buffer -+void * APIENTRY binn_ptr(void *ptr); -+int APIENTRY binn_size(void *ptr); -+int APIENTRY binn_type(void *ptr); -+int APIENTRY binn_count(void *ptr); ++void * APIENTRY binn_ptr(const void *ptr); ++int APIENTRY binn_size(const void *ptr); ++int APIENTRY binn_type(const void *ptr); ++int APIENTRY binn_count(const void *ptr); + -+BOOL APIENTRY binn_is_valid(void *ptr, int *ptype, int *pcount, int *psize); ++BOOL APIENTRY binn_is_valid(const void *ptr, int *ptype, int *pcount, int *psize); +/* the function returns the values (type, count and size) and they don't need to be + initialized. these values are read from the buffer. example: + + int type, count, size; + result = binn_is_valid(ptr, &type, &count, &size); +*/ -+BOOL APIENTRY binn_is_valid_ex(void *ptr, int *ptype, int *pcount, int *psize); ++BOOL APIENTRY binn_is_valid_ex(const void *ptr, int *ptype, int *pcount, int *psize); +/* if some value is informed (type, count or size) then the function will check if + the value returned from the serialized data matches the informed value. otherwise + the values must be initialized to zero. example: @@ -3924,94 +3967,96 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h + result = binn_is_valid_ex(ptr, &type, &count, &size); +*/ + -+BOOL APIENTRY binn_is_struct(void *ptr); ++BOOL APIENTRY binn_is_struct(const void *ptr); + + +// Loading a binn buffer into a binn value - this is optional + -+BOOL APIENTRY binn_load(void *data, binn *item); // on stack -+binn * APIENTRY binn_open(void *data); // allocated ++binn * APIENTRY binn_open(const void *data); // allocated - unsecure ++binn * APIENTRY binn_open_ex(const void *data, int size); // allocated - secure ++BOOL APIENTRY binn_load(const void *data, binn *item); // on stack - unsecure ++BOOL APIENTRY binn_load_ex(const void *data, int size, binn *value); // secure + + +// easiest interface to use, but don't check if the value is there + -+signed char APIENTRY binn_list_int8(void *list, int pos); -+short APIENTRY binn_list_int16(void *list, int pos); -+int APIENTRY binn_list_int32(void *list, int pos); -+int64 APIENTRY binn_list_int64(void *list, int pos); -+unsigned char APIENTRY binn_list_uint8(void *list, int pos); -+unsigned short APIENTRY binn_list_uint16(void *list, int pos); -+unsigned int APIENTRY binn_list_uint32(void *list, int pos); -+uint64 APIENTRY binn_list_uint64(void *list, int pos); -+float APIENTRY binn_list_float(void *list, int pos); -+double APIENTRY binn_list_double(void *list, int pos); -+BOOL APIENTRY binn_list_bool(void *list, int pos); -+BOOL APIENTRY binn_list_null(void *list, int pos); -+char * APIENTRY binn_list_str(void *list, int pos); -+void * APIENTRY binn_list_blob(void *list, int pos, int *psize); -+void * APIENTRY binn_list_list(void *list, int pos); -+void * APIENTRY binn_list_map(void *list, int pos); -+void * APIENTRY binn_list_object(void *list, int pos); ++signed char APIENTRY binn_list_int8(const void *list, int pos); ++short APIENTRY binn_list_int16(const void *list, int pos); ++int APIENTRY binn_list_int32(const void *list, int pos); ++int64 APIENTRY binn_list_int64(const void *list, int pos); ++unsigned char APIENTRY binn_list_uint8(const void *list, int pos); ++unsigned short APIENTRY binn_list_uint16(const void *list, int pos); ++unsigned int APIENTRY binn_list_uint32(const void *list, int pos); ++uint64 APIENTRY binn_list_uint64(const void *list, int pos); ++float APIENTRY binn_list_float(const void *list, int pos); ++double APIENTRY binn_list_double(const void *list, int pos); ++BOOL APIENTRY binn_list_bool(const void *list, int pos); ++BOOL APIENTRY binn_list_null(const void *list, int pos); ++char * APIENTRY binn_list_str(const void *list, int pos); ++void * APIENTRY binn_list_blob(const void *list, int pos, int *psize); ++void * APIENTRY binn_list_list(const void *list, int pos); ++void * APIENTRY binn_list_map(const void *list, int pos); ++void * APIENTRY binn_list_object(const void *list, int pos); + -+signed char APIENTRY binn_map_int8(void *map, int id); -+short APIENTRY binn_map_int16(void *map, int id); -+int APIENTRY binn_map_int32(void *map, int id); -+int64 APIENTRY binn_map_int64(void *map, int id); -+unsigned char APIENTRY binn_map_uint8(void *map, int id); -+unsigned short APIENTRY binn_map_uint16(void *map, int id); -+unsigned int APIENTRY binn_map_uint32(void *map, int id); -+uint64 APIENTRY binn_map_uint64(void *map, int id); -+float APIENTRY binn_map_float(void *map, int id); -+double APIENTRY binn_map_double(void *map, int id); -+BOOL APIENTRY binn_map_bool(void *map, int id); -+BOOL APIENTRY binn_map_null(void *map, int id); -+char * APIENTRY binn_map_str(void *map, int id); -+void * APIENTRY binn_map_blob(void *map, int id, int *psize); -+void * APIENTRY binn_map_list(void *map, int id); -+void * APIENTRY binn_map_map(void *map, int id); -+void * APIENTRY binn_map_object(void *map, int id); ++signed char APIENTRY binn_map_int8(const void *map, int id); ++short APIENTRY binn_map_int16(const void *map, int id); ++int APIENTRY binn_map_int32(const void *map, int id); ++int64 APIENTRY binn_map_int64(const void *map, int id); ++unsigned char APIENTRY binn_map_uint8(const void *map, int id); ++unsigned short APIENTRY binn_map_uint16(const void *map, int id); ++unsigned int APIENTRY binn_map_uint32(const void *map, int id); ++uint64 APIENTRY binn_map_uint64(const void *map, int id); ++float APIENTRY binn_map_float(const void *map, int id); ++double APIENTRY binn_map_double(const void *map, int id); ++BOOL APIENTRY binn_map_bool(const void *map, int id); ++BOOL APIENTRY binn_map_null(const void *map, int id); ++char * APIENTRY binn_map_str(const void *map, int id); ++void * APIENTRY binn_map_blob(const void *map, int id, int *psize); ++void * APIENTRY binn_map_list(const void *map, int id); ++void * APIENTRY binn_map_map(const void *map, int id); ++void * APIENTRY binn_map_object(const void *map, int id); + -+signed char APIENTRY binn_object_int8(void *obj, const char *key); -+short APIENTRY binn_object_int16(void *obj, const char *key); -+int APIENTRY binn_object_int32(void *obj, const char *key); -+int64 APIENTRY binn_object_int64(void *obj, const char *key); -+unsigned char APIENTRY binn_object_uint8(void *obj, const char *key); -+unsigned short APIENTRY binn_object_uint16(void *obj, const char *key); -+unsigned int APIENTRY binn_object_uint32(void *obj, const char *key); -+uint64 APIENTRY binn_object_uint64(void *obj, const char *key); -+float APIENTRY binn_object_float(void *obj, const char *key); -+double APIENTRY binn_object_double(void *obj, const char *key); -+BOOL APIENTRY binn_object_bool(void *obj, const char *key); -+BOOL APIENTRY binn_object_null(void *obj, const char *key); -+char * APIENTRY binn_object_str(void *obj, const char *key); -+void * APIENTRY binn_object_blob(void *obj, const char *key, int *psize); -+void * APIENTRY binn_object_list(void *obj, const char *key); -+void * APIENTRY binn_object_map(void *obj, const char *key); -+void * APIENTRY binn_object_object(void *obj, const char *key); ++signed char APIENTRY binn_object_int8(const void *obj, const char *key); ++short APIENTRY binn_object_int16(const void *obj, const char *key); ++int APIENTRY binn_object_int32(const void *obj, const char *key); ++int64 APIENTRY binn_object_int64(const void *obj, const char *key); ++unsigned char APIENTRY binn_object_uint8(const void *obj, const char *key); ++unsigned short APIENTRY binn_object_uint16(const void *obj, const char *key); ++unsigned int APIENTRY binn_object_uint32(const void *obj, const char *key); ++uint64 APIENTRY binn_object_uint64(const void *obj, const char *key); ++float APIENTRY binn_object_float(const void *obj, const char *key); ++double APIENTRY binn_object_double(const void *obj, const char *key); ++BOOL APIENTRY binn_object_bool(const void *obj, const char *key); ++BOOL APIENTRY binn_object_null(const void *obj, const char *key); ++char * APIENTRY binn_object_str(const void *obj, const char *key); ++void * APIENTRY binn_object_blob(const void *obj, const char *key, int *psize); ++void * APIENTRY binn_object_list(const void *obj, const char *key); ++void * APIENTRY binn_object_map(const void *obj, const char *key); ++void * APIENTRY binn_object_object(const void *obj, const char *key); + + +// return a pointer to an allocated binn structure - must be released with the free() function or equivalent set in binn_set_alloc_functions() -+binn * APIENTRY binn_list_value(void *list, int pos); -+binn * APIENTRY binn_map_value(void *map, int id); -+binn * APIENTRY binn_object_value(void *obj, const char *key); ++binn * APIENTRY binn_list_value(const void *list, int pos); ++binn * APIENTRY binn_map_value(const void *map, int id); ++binn * APIENTRY binn_object_value(const void *obj, const char *key); + +// read the value to a binn structure on the stack -+BOOL APIENTRY binn_list_get_value(void* list, int pos, binn *value); -+BOOL APIENTRY binn_map_get_value(void* map, int id, binn *value); -+BOOL APIENTRY binn_object_get_value(void *obj, const char *key, binn *value); ++BOOL APIENTRY binn_list_get_value(const void *list, int pos, binn *value); ++BOOL APIENTRY binn_map_get_value(const void *map, int id, binn *value); ++BOOL APIENTRY binn_object_get_value(const void *obj, const char *key, binn *value); + +// single interface - these functions check the data type -+BOOL APIENTRY binn_list_get(void *list, int pos, int type, void *pvalue, int *psize); -+BOOL APIENTRY binn_map_get(void *map, int id, int type, void *pvalue, int *psize); -+BOOL APIENTRY binn_object_get(void *obj, const char *key, int type, void *pvalue, int *psize); ++BOOL APIENTRY binn_list_get(const void *list, int pos, int type, void *pvalue, int *psize); ++BOOL APIENTRY binn_map_get(const void *map, int id, int type, void *pvalue, int *psize); ++BOOL APIENTRY binn_object_get(const void *obj, const char *key, int type, void *pvalue, int *psize); + +// these 3 functions return a pointer to the value and the data type +// they are thread-safe on big-endian devices +// on little-endian devices they are thread-safe only to return pointers to list, map, object, blob and strings +// the returned pointer to 16, 32 and 64 bits values must be used only by single-threaded applications -+void * APIENTRY binn_list_read(void *list, int pos, int *ptype, int *psize); -+void * APIENTRY binn_map_read(void *map, int id, int *ptype, int *psize); -+void * APIENTRY binn_object_read(void *obj, const char *key, int *ptype, int *psize); ++void * APIENTRY binn_list_read(const void *list, int pos, int *ptype, int *psize); ++void * APIENTRY binn_map_read(const void *map, int id, int *ptype, int *psize); ++void * APIENTRY binn_object_read(const void *obj, const char *key, int *ptype, int *psize); + + +// READ PAIR FUNCTIONS @@ -4019,19 +4064,19 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h +// these functions use base 1 in the 'pos' argument + +// on stack -+BOOL APIENTRY binn_map_get_pair(void *map, int pos, int *pid, binn *value); -+BOOL APIENTRY binn_object_get_pair(void *obj, int pos, char *pkey, binn *value); // must free the memory returned in the pkey ++BOOL APIENTRY binn_map_get_pair(const void *map, int pos, int *pid, binn *value); ++BOOL APIENTRY binn_object_get_pair(const void *obj, int pos, char *pkey, binn *value); // the key must be declared as: char key[256]; + +// allocated -+binn * APIENTRY binn_map_pair(void *map, int pos, int *pid); -+binn * APIENTRY binn_object_pair(void *obj, int pos, char *pkey); // must free the memory returned in the pkey ++binn * APIENTRY binn_map_pair(const void *map, int pos, int *pid); ++binn * APIENTRY binn_object_pair(const void *obj, int pos, char *pkey); // the key must be declared as: char key[256]; + +// these 2 functions return a pointer to the value and the data type +// they are thread-safe on big-endian devices +// on little-endian devices they are thread-safe only to return pointers to list, map, object, blob and strings +// the returned pointer to 16, 32 and 64 bits values must be used only by single-threaded applications -+void * APIENTRY binn_map_read_pair(void *ptr, int pos, int *pid, int *ptype, int *psize); -+void * APIENTRY binn_object_read_pair(void *ptr, int pos, char *pkey, int *ptype, int *psize); ++void * APIENTRY binn_map_read_pair(const void *ptr, int pos, int *pid, int *ptype, int *psize); ++void * APIENTRY binn_object_read_pair(const void *ptr, int pos, char *pkey, int *ptype, int *psize); + + +// SEQUENTIAL READ FUNCTIONS @@ -4044,7 +4089,7 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h + int current; +} binn_iter; + -+BOOL APIENTRY binn_iter_init(binn_iter *iter, void *pbuf, int type); ++BOOL APIENTRY binn_iter_init(binn_iter *iter, const void *pbuf, int type); + +// allocated +binn * APIENTRY binn_list_next_value(binn_iter *iter); @@ -4314,103 +4359,103 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h +/*** GET FUNCTIONS *******************************************************************/ +/*************************************************************************************/ + -+ALWAYS_INLINE BOOL binn_list_get_int8(void *list, int pos, signed char *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_int8(const void *list, int pos, signed char *pvalue) { + return binn_list_get(list, pos, BINN_INT8, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_int16(void *list, int pos, short *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_int16(const void *list, int pos, short *pvalue) { + return binn_list_get(list, pos, BINN_INT16, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_int32(void *list, int pos, int *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_int32(const void *list, int pos, int *pvalue) { + return binn_list_get(list, pos, BINN_INT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_int64(void *list, int pos, int64 *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_int64(const void *list, int pos, int64 *pvalue) { + return binn_list_get(list, pos, BINN_INT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_uint8(void *list, int pos, unsigned char *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_uint8(const void *list, int pos, unsigned char *pvalue) { + return binn_list_get(list, pos, BINN_UINT8, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_uint16(void *list, int pos, unsigned short *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_uint16(const void *list, int pos, unsigned short *pvalue) { + return binn_list_get(list, pos, BINN_UINT16, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_uint32(void *list, int pos, unsigned int *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_uint32(const void *list, int pos, unsigned int *pvalue) { + return binn_list_get(list, pos, BINN_UINT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_uint64(void *list, int pos, uint64 *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_uint64(const void *list, int pos, uint64 *pvalue) { + return binn_list_get(list, pos, BINN_UINT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_float(void *list, int pos, float *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_float(const void *list, int pos, float *pvalue) { + return binn_list_get(list, pos, BINN_FLOAT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_double(void *list, int pos, double *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_double(const void *list, int pos, double *pvalue) { + return binn_list_get(list, pos, BINN_FLOAT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_bool(void *list, int pos, BOOL *pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_bool(const void *list, int pos, BOOL *pvalue) { + return binn_list_get(list, pos, BINN_BOOL, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_str(void *list, int pos, char **pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_str(const void *list, int pos, char **pvalue) { + return binn_list_get(list, pos, BINN_STRING, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_blob(void *list, int pos, void **pvalue, int *psize) { ++ALWAYS_INLINE BOOL binn_list_get_blob(const void *list, int pos, void **pvalue, int *psize) { + return binn_list_get(list, pos, BINN_BLOB, pvalue, psize); +} -+ALWAYS_INLINE BOOL binn_list_get_list(void *list, int pos, void **pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_list(const void *list, int pos, void **pvalue) { + return binn_list_get(list, pos, BINN_LIST, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_map(void *list, int pos, void **pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_map(const void *list, int pos, void **pvalue) { + return binn_list_get(list, pos, BINN_MAP, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_list_get_object(void *list, int pos, void **pvalue) { ++ALWAYS_INLINE BOOL binn_list_get_object(const void *list, int pos, void **pvalue) { + return binn_list_get(list, pos, BINN_OBJECT, pvalue, NULL); +} + +/***************************************************************************/ + -+ALWAYS_INLINE BOOL binn_map_get_int8(void *map, int id, signed char *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_int8(const void *map, int id, signed char *pvalue) { + return binn_map_get(map, id, BINN_INT8, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_int16(void *map, int id, short *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_int16(const void *map, int id, short *pvalue) { + return binn_map_get(map, id, BINN_INT16, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_int32(void *map, int id, int *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_int32(const void *map, int id, int *pvalue) { + return binn_map_get(map, id, BINN_INT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_int64(void *map, int id, int64 *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_int64(const void *map, int id, int64 *pvalue) { + return binn_map_get(map, id, BINN_INT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_uint8(void *map, int id, unsigned char *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_uint8(const void *map, int id, unsigned char *pvalue) { + return binn_map_get(map, id, BINN_UINT8, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_uint16(void *map, int id, unsigned short *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_uint16(const void *map, int id, unsigned short *pvalue) { + return binn_map_get(map, id, BINN_UINT16, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_uint32(void *map, int id, unsigned int *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_uint32(const void *map, int id, unsigned int *pvalue) { + return binn_map_get(map, id, BINN_UINT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_uint64(void *map, int id, uint64 *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_uint64(const void *map, int id, uint64 *pvalue) { + return binn_map_get(map, id, BINN_UINT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_float(void *map, int id, float *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_float(const void *map, int id, float *pvalue) { + return binn_map_get(map, id, BINN_FLOAT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_double(void *map, int id, double *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_double(const void *map, int id, double *pvalue) { + return binn_map_get(map, id, BINN_FLOAT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_bool(void *map, int id, BOOL *pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_bool(const void *map, int id, BOOL *pvalue) { + return binn_map_get(map, id, BINN_BOOL, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_str(void *map, int id, char **pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_str(const void *map, int id, char **pvalue) { + return binn_map_get(map, id, BINN_STRING, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_blob(void *map, int id, void **pvalue, int *psize) { ++ALWAYS_INLINE BOOL binn_map_get_blob(const void *map, int id, void **pvalue, int *psize) { + return binn_map_get(map, id, BINN_BLOB, pvalue, psize); +} -+ALWAYS_INLINE BOOL binn_map_get_list(void *map, int id, void **pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_list(const void *map, int id, void **pvalue) { + return binn_map_get(map, id, BINN_LIST, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_map(void *map, int id, void **pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_map(const void *map, int id, void **pvalue) { + return binn_map_get(map, id, BINN_MAP, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_map_get_object(void *map, int id, void **pvalue) { ++ALWAYS_INLINE BOOL binn_map_get_object(const void *map, int id, void **pvalue) { + return binn_map_get(map, id, BINN_OBJECT, pvalue, NULL); +} + @@ -4419,52 +4464,52 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h +// usage: +// if (binn_object_get_int32(obj, "key", &value) == FALSE) xxx; + -+ALWAYS_INLINE BOOL binn_object_get_int8(void *obj, const char *key, signed char *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_int8(const void *obj, const char *key, signed char *pvalue) { + return binn_object_get(obj, key, BINN_INT8, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_int16(void *obj, const char *key, short *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_int16(const void *obj, const char *key, short *pvalue) { + return binn_object_get(obj, key, BINN_INT16, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_int32(void *obj, const char *key, int *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_int32(const void *obj, const char *key, int *pvalue) { + return binn_object_get(obj, key, BINN_INT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_int64(void *obj, const char *key, int64 *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_int64(const void *obj, const char *key, int64 *pvalue) { + return binn_object_get(obj, key, BINN_INT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_uint8(void *obj, const char *key, unsigned char *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_uint8(const void *obj, const char *key, unsigned char *pvalue) { + return binn_object_get(obj, key, BINN_UINT8, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_uint16(void *obj, const char *key, unsigned short *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_uint16(const void *obj, const char *key, unsigned short *pvalue) { + return binn_object_get(obj, key, BINN_UINT16, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_uint32(void *obj, const char *key, unsigned int *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_uint32(const void *obj, const char *key, unsigned int *pvalue) { + return binn_object_get(obj, key, BINN_UINT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_uint64(void *obj, const char *key, uint64 *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_uint64(const void *obj, const char *key, uint64 *pvalue) { + return binn_object_get(obj, key, BINN_UINT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_float(void *obj, const char *key, float *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_float(const void *obj, const char *key, float *pvalue) { + return binn_object_get(obj, key, BINN_FLOAT32, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_double(void *obj, const char *key, double *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_double(const void *obj, const char *key, double *pvalue) { + return binn_object_get(obj, key, BINN_FLOAT64, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_bool(void *obj, const char *key, BOOL *pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_bool(const void *obj, const char *key, BOOL *pvalue) { + return binn_object_get(obj, key, BINN_BOOL, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_str(void *obj, const char *key, char **pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_str(const void *obj, const char *key, char **pvalue) { + return binn_object_get(obj, key, BINN_STRING, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_blob(void *obj, const char *key, void **pvalue, int *psize) { ++ALWAYS_INLINE BOOL binn_object_get_blob(const void *obj, const char *key, void **pvalue, int *psize) { + return binn_object_get(obj, key, BINN_BLOB, pvalue, psize); +} -+ALWAYS_INLINE BOOL binn_object_get_list(void *obj, const char *key, void **pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_list(const void *obj, const char *key, void **pvalue) { + return binn_object_get(obj, key, BINN_LIST, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_map(void *obj, const char *key, void **pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_map(const void *obj, const char *key, void **pvalue) { + return binn_object_get(obj, key, BINN_MAP, pvalue, NULL); +} -+ALWAYS_INLINE BOOL binn_object_get_object(void *obj, const char *key, void **pvalue) { ++ALWAYS_INLINE BOOL binn_object_get_object(const void *obj, const char *key, void **pvalue) { + return binn_object_get(obj, key, BINN_OBJECT, pvalue, NULL); +} + @@ -4490,30 +4535,49 @@ diff -Nur openssh-9.3p1.orig/binn.h openssh-9.3p1/binn.h +#endif + +#endif //BINN_H -diff -Nur openssh-9.3p1.orig/channels.c openssh-9.3p1/channels.c ---- openssh-9.3p1.orig/channels.c 2024-07-10 09:07:09.714081799 +0200 -+++ openssh-9.3p1/channels.c 2024-07-10 11:29:27.911096803 +0200 -@@ -229,6 +229,9 @@ +diff -Nur openssh-10.0p1.orig/channels.c openssh-10.0p1/channels.c +--- openssh-10.0p1.orig/channels.c 2025-06-14 10:53:01.614387370 +0200 ++++ openssh-10.0p1/channels.c 2025-06-14 11:44:14.886309096 +0200 +@@ -99,6 +99,11 @@ + /* Maximum number of fake X11 displays to try. */ + #define MAX_DISPLAYS 1000 + ++/* in version of OpenSSH later than 8.8 if we advertise a window ++ * 16MB or larger is causes a pathological behaviour that reduces ++ * throughput. This is not a great solution. */ ++#define NON_HPN_WINDOW_MAX (15 * 1024 * 1024) ++ + /* Per-channel callback for pre/post IO actions */ + typedef void chan_fn(struct ssh *, Channel *c); + +@@ -227,6 +232,9 @@ /* Setup helper */ static void channel_handler_init(struct ssh_channels *sc); ++/* default values to enable hpn and the initial buffer size */ +static int hpn_disabled = 0; -+static int hpn_buffer_size = 2 * 1024 * 1024; + /* -- channel core */ void -@@ -484,6 +487,9 @@ +@@ -521,6 +529,16 @@ (c->output = sshbuf_new()) == NULL || (c->extended = sshbuf_new()) == NULL) fatal_f("sshbuf_new failed"); ++ ++ /* these buffers are important in terms of tracking channel ++ * buffer usage so label and type them with descriptive names */ + sshbuf_relabel(c->input, "channel input"); ++ sshbuf_type(c->input, BUF_CHANNEL_INPUT); + sshbuf_relabel(c->output, "channel output"); ++ sshbuf_type(c->output, BUF_CHANNEL_OUTPUT); + sshbuf_relabel(c->extended, "channel extended"); ++ sshbuf_type(c->extended, BUF_CHANNEL_EXTENDED); ++ if ((r = sshbuf_set_max_size(c->input, CHAN_INPUT_MAX)) != 0) fatal_fr(r, "sshbuf_set_max_size"); c->ostate = CHAN_OUTPUT_OPEN; -@@ -495,6 +501,7 @@ +@@ -532,6 +550,7 @@ c->local_window = window; c->local_window_max = window; c->local_maxpacket = maxpack; @@ -4521,7 +4585,7 @@ diff -Nur openssh-9.3p1.orig/channels.c openssh-9.3p1/channels.c c->remote_name = xstrdup(remote_name); c->ctl_chan = -1; c->delayed = 1; /* prevent call to channel_post handler */ -@@ -1203,6 +1210,28 @@ +@@ -1259,6 +1278,33 @@ c->io_want = SSH_CHAN_IO_SOCK_W; } @@ -4541,54 +4605,33 @@ diff -Nur openssh-9.3p1.orig/channels.c openssh-9.3p1/channels.c + /* return no more than SSHBUF_SIZE_MAX (currently 256MB) */ + if ((ret == 0) && tcpwinsz > SSHBUF_SIZE_MAX) + tcpwinsz = SSHBUF_SIZE_MAX; ++ /* if the remote side is OpenSSH after version 8.8 we need to restrict ++ * the size of the advertised window. Now this means that any HPN to non-HPN ++ * connection will be window limited to 15MB of receive space. This is a ++ * non-optimal solution. ++ */ + -+ debug3_f("tcp connection %d, Receive window: %d", -+ ssh_packet_get_connection_in(ssh), tcpwinsz); -+ return tcpwinsz; ++ if ((ssh->compat & SSH_RESTRICT_WINDOW) && (tcpwinsz > NON_HPN_WINDOW_MAX)) ++ tcpwinsz = NON_HPN_WINDOW_MAX; ++ return (tcpwinsz); +} + static void channel_pre_open(struct ssh *ssh, Channel *c) { -@@ -2303,24 +2332,55 @@ - { - int r; - -+ /* going back to a set denominator of 2. Prior versions had a -+ * dynamic denominator based on the size of the buffer. This may -+ * have been helpful in some situations but it isn't helping in -+ * the general case -cjr 6/30/23 */ - if (c->type == SSH_CHANNEL_OPEN && - !(c->flags & (CHAN_CLOSE_SENT|CHAN_CLOSE_RCVD)) && - ((c->local_window_max - c->local_window > +@@ -2366,18 +2412,29 @@ c->local_maxpacket*3) || c->local_window < c->local_window_max/2) && c->local_consumed > 0) { -+ u_int addition = 0; ++ int addition = 0; + u_int32_t tcpwinsz = channel_tcpwinsz(ssh); + /* adjust max window size if we are in a dynamic environment + * and the tcp receive buffer is larger than the ssh window */ + if (c->dynamic_window && (tcpwinsz > c->local_window_max)) { -+ if (c->hpn_buffer_limit) { -+ /* limit window growth to prevent buffer issues -+ * still not sure what is causing the buffer issues -+ * but it may be an issue with c->local_consumed not being -+ * handled properly in the cases of bottenecked IO to the -+ * wfd endpoint. This does have an impact on throughput -+ * as we're essentially maxing out local_window_max to -+ * half of the window size */ -+ addition = (tcpwinsz/2 - c->local_window_max); -+ } -+ else { -+ /* aggressively grow the window */ -+ addition = tcpwinsz - c->local_window_max; -+ } ++ /* aggressively grow the window */ ++ addition = tcpwinsz - c->local_window_max; + c->local_window_max += addition; -+ sshbuf_set_window_max(c->output, c->local_window_max); -+ sshbuf_set_window_max(c->input, c->local_window_max); -+ //c->output->window_max = c->local_window_max; -+ //c->input->window_max = c->local_window_max; -+ debug("Channel %d: Window growth to %d by %d bytes",c->self, ++ debug_f("Channel %d: Window growth to %d by %d bytes",c->self, + c->local_window_max, addition); + } if (!c->have_remote_id) @@ -4601,24 +4644,26 @@ diff -Nur openssh-9.3p1.orig/channels.c openssh-9.3p1/channels.c (r = sshpkt_send(ssh)) != 0) { fatal_fr(r, "channel %i", c->self); } -- debug2("channel %d: window %d sent adjust %d", c->self, + debug2("channel %d: window %d sent adjust %d", c->self, - c->local_window, c->local_consumed); - c->local_window += c->local_consumed; -+ debug3_f("channel %d: window %d sent adjust %d", c->self, + c->local_window, c->local_consumed + addition); + c->local_window += c->local_consumed + addition; c->local_consumed = 0; } return 1; -@@ -2939,7 +2999,6 @@ - (r = sshpkt_send(ssh)) != 0) - fatal_fr(r, "channel %i: send datagram", c->self); - c->remote_window -= plen; -- return; - } - - /* Enqueue packet for buffered data. */ -@@ -3602,7 +3661,7 @@ +@@ -2963,9 +3020,7 @@ + * in use. + */ + if (CHANNEL_EFD_INPUT_ACTIVE(c)) +- debug2("channel %d: " +- "ibuf_empty delayed efd %d/(%zu)", +- c->self, c->efd, sshbuf_len(c->extended)); ++ {} + else + chan_ibuf_empty(ssh, c); + } +@@ -3674,7 +3729,7 @@ error_fr(r, "parse adjust"); ssh_packet_disconnect(ssh, "Invalid window adjust message"); } @@ -4627,75 +4672,51 @@ diff -Nur openssh-9.3p1.orig/channels.c openssh-9.3p1/channels.c if ((new_rwin = c->remote_window + adjust) < c->remote_window) { fatal("channel %d: adjust %u overflows remote window %u", c->self, adjust, c->remote_window); -@@ -3717,6 +3776,14 @@ +@@ -3789,6 +3844,13 @@ return addr; } +void -+channel_set_hpn(int external_hpn_disabled, int external_hpn_buffer_size) ++channel_set_hpn_disabled(int external_hpn_disabled) +{ + hpn_disabled = external_hpn_disabled; -+ hpn_buffer_size = external_hpn_buffer_size; -+ debug("HPN Disabled: %d, HPN Buffer Size: %d", hpn_disabled, hpn_buffer_size); ++ debug("HPN Disabled: %d", hpn_disabled); +} + static int channel_setup_fwd_listener_tcpip(struct ssh *ssh, int type, struct Forward *fwd, int *allocated_listen_port, -@@ -3856,8 +3923,10 @@ - } - - /* Allocate a channel number for the socket. */ -+ /* explicitly test for hpn disabled option. if true use smaller window size */ - c = channel_new(ssh, "port-listener", type, sock, sock, -1, -- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, -+ hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : hpn_buffer_size, -+ CHAN_TCP_PACKET_DEFAULT, - 0, "port listener", 1); - c->path = xstrdup(host); - c->host_port = fwd->connect_port; -@@ -5041,7 +5110,8 @@ - sock = socks[n]; - nc = channel_new(ssh, "x11-listener", - SSH_CHANNEL_X11_LISTENER, sock, sock, -1, -- CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, -+ hpn_disabled ? CHAN_X11_WINDOW_DEFAULT : hpn_buffer_size, -+ CHAN_X11_PACKET_DEFAULT, - 0, "X11 inet listener", 1); - nc->single_connection = single_connection; - (*chanids)[n] = nc->self; -diff -Nur openssh-9.3p1.orig/channels.h openssh-9.3p1/channels.h ---- openssh-9.3p1.orig/channels.h 2024-07-10 09:07:09.675081685 +0200 -+++ openssh-9.3p1/channels.h 2024-07-10 11:14:08.804403496 +0200 -@@ -173,6 +173,8 @@ +diff -Nur openssh-10.0p1.orig/channels.h openssh-10.0p1/channels.h +--- openssh-10.0p1.orig/channels.h 2025-06-14 10:53:01.467785388 +0200 ++++ openssh-10.0p1/channels.h 2025-06-14 10:54:01.306120024 +0200 +@@ -175,6 +175,7 @@ u_int local_window_max; u_int local_consumed; u_int local_maxpacket; + int dynamic_window; -+ int hpn_buffer_limit; int extended_usage; int single_connection; -@@ -254,7 +256,7 @@ +@@ -256,7 +257,7 @@ #define SSH_CHAN_IO_SOCK (SSH_CHAN_IO_SOCK_R|SSH_CHAN_IO_SOCK_W) /* Read buffer size */ -#define CHAN_RBUF (16*1024) -+#define CHAN_RBUF CHAN_SES_PACKET_DEFAULT ++#define CHAN_RBUF CHAN_SES_PACKET_DEFAULT /* Maximum size for direct reads to buffers */ #define CHANNEL_MAX_READ CHAN_SES_PACKET_DEFAULT -@@ -396,4 +398,6 @@ +@@ -399,4 +400,6 @@ void chan_write_failed(struct ssh *, Channel *); void chan_obuf_empty(struct ssh *, Channel *); +/* hpn handler */ -+void channel_set_hpn(int, int); ++void channel_set_hpn_disabled(int); #endif -diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c ---- openssh-9.3p1.orig/cipher.c 2024-07-10 09:07:09.734081857 +0200 -+++ openssh-9.3p1/cipher.c 2024-07-10 09:09:55.899568399 +0200 -@@ -48,23 +48,36 @@ +diff -Nur openssh-10.0p1.orig/cipher.c openssh-10.0p1/cipher.c +--- openssh-10.0p1.orig/cipher.c 2025-06-14 10:53:01.716919856 +0200 ++++ openssh-10.0p1/cipher.c 2025-06-14 12:01:51.076334585 +0200 +@@ -48,23 +48,39 @@ #include "sshbuf.h" #include "ssherr.h" #include "digest.h" @@ -4704,7 +4725,7 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c #include "openbsd-compat/openssl-compat.h" +/* for provider functions */ -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++#ifdef WITH_OPENSSL3 +#include +#include +#include @@ -4724,6 +4745,9 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c EVP_CIPHER_CTX *evp; + const EVP_CIPHER *meth_ptr; /*used to free memory in aes_ctr_mt */ struct chachapoly_ctx *cp_ctx; ++#ifdef WITH_OPENSSL ++ struct chachapoly_ctx_mt *cp_ctx_mt; ++#endif struct aesctr_ctx ac_ctx; /* XXX union with evp? */ const struct sshcipher *cipher; }; @@ -4733,12 +4757,24 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c #ifdef WITH_OPENSSL #ifndef OPENSSL_NO_DES { "3des-cbc", 8, 24, 0, 0, CFLAG_CBC, EVP_des_ede3_cbc }, -@@ -131,12 +144,62 @@ +@@ -86,6 +102,10 @@ + #endif + { "chacha20-poly1305@openssh.com", + 8, 64, 0, 16, CFLAG_CHACHAPOLY, NULL }, ++#ifdef WITH_OPENSSL ++ { "chacha20-poly1305-mt@hpnssh.org", ++ 8, 64, 0, 16, CFLAG_CHACHAPOLY|CFLAG_MT, NULL }, ++#endif + { "none", 8, 0, 0, 0, CFLAG_NONE, NULL }, + + { NULL, 0, 0, 0, 0, 0, NULL } +@@ -131,12 +151,63 @@ #endif } -+/* used to get the cipher name so when force rekeying to handle the -+ * single to multithreaded ctr cipher swap we only rekey when appropriate ++/* used to get the cipher name when we are testing to ++ * see if we can move from a serial to parallel cipher ++ * only called in cipher-switch.c + */ +const char * +cipher_ctx_name(const struct sshcipher_ctx *cc) @@ -4796,7 +4832,7 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c u_int cipher_keylen(const struct sshcipher *c) { -@@ -180,10 +243,10 @@ +@@ -180,10 +251,10 @@ return cc->plaintext; } @@ -4809,7 +4845,7 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c for (c = ciphers; c->name != NULL; c++) if (strcmp(c->name, name) == 0) return c; -@@ -205,7 +268,8 @@ +@@ -205,7 +276,8 @@ for ((p = strsep(&cp, CIPHER_SEP)); p && *p != '\0'; (p = strsep(&cp, CIPHER_SEP))) { c = cipher_by_name(p); @@ -4819,16 +4855,16 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c free(cipher_list); return 0; } -@@ -226,7 +290,7 @@ +@@ -226,7 +298,7 @@ int cipher_init(struct sshcipher_ctx **ccp, const struct sshcipher *cipher, const u_char *key, u_int keylen, const u_char *iv, u_int ivlen, - int do_encrypt) -+ int do_encrypt, int post_auth) ++ u_int seqnr, int do_encrypt, int enable_threads) { struct sshcipher_ctx *cc = NULL; int ret = SSH_ERR_INTERNAL_ERROR; -@@ -241,6 +305,7 @@ +@@ -241,6 +313,7 @@ cc->plaintext = (cipher->flags & CFLAG_NONE) != 0; cc->encrypt = do_encrypt; @@ -4836,7 +4872,27 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c if (keylen < cipher->key_len || (iv != NULL && ivlen < cipher_ivlen(cipher))) { -@@ -273,6 +338,53 @@ +@@ -250,8 +323,19 @@ + + cc->cipher = cipher; + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { ++#ifdef WITH_OPENSSL ++ if ((cc->cipher->flags & CFLAG_MT) != 0) { ++ cc->cp_ctx_mt = chachapoly_new_mt(seqnr, key, keylen); ++ ret = cc->cp_ctx_mt != NULL ? 0 : ++ SSH_ERR_INVALID_ARGUMENT; ++ } else { ++ cc->cp_ctx = chachapoly_new(key, keylen); ++ ret = cc->cp_ctx != NULL ? 0 : SSH_ERR_INVALID_ARGUMENT; ++ } ++#else + cc->cp_ctx = chachapoly_new(key, keylen); + ret = cc->cp_ctx != NULL ? 0 : SSH_ERR_INVALID_ARGUMENT; ++#endif + goto out; + } + if ((cc->cipher->flags & CFLAG_NONE) != 0) { +@@ -273,6 +357,53 @@ ret = SSH_ERR_ALLOC_FAIL; goto out; } @@ -4845,8 +4901,8 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c + * start the threaded cipher. If OSSL supports providers (OSSL 3.0+) then + * we load our hpnssh provider. If it doesn't (OSSL < 1.1) then we use the + * _meth_new process found in cipher-ctr-mt.c */ -+ if (strstr(cc->cipher->name, "ctr") && post_auth) { -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++ if (strstr(cc->cipher->name, "ctr") && enable_threads) { ++#ifdef WITH_OPENSSL3 + /* this version of openssl uses providers */ + OSSL_LIB_CTX *aes_lib = NULL; /* probably not needed */ + OSSL_PROVIDER *aes_mt_provider = NULL; @@ -4885,12 +4941,60 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c + * then we'd only have to call EVP_CIPHER_meth once but this + * works for now. TODO: This. cjr 02.22.2023 */ + cc->meth_ptr = type; -+#endif /* OPENSSL_VERSION_NUMBER */ ++#endif /* WITH_OPENSSL3 */ + } /* if (strstr()) */ if (EVP_CipherInit(cc->evp, type, NULL, (u_char *)iv, (do_encrypt == CIPHER_ENCRYPT)) == 0) { ret = SSH_ERR_LIBCRYPTO_ERROR; -@@ -411,6 +523,16 @@ +@@ -327,6 +458,12 @@ + const u_char *src, u_int len, u_int aadlen, u_int authlen) + { + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { ++#ifdef WITH_OPENSSL ++ if ((cc->cipher->flags & CFLAG_MT) != 0) { ++ return chachapoly_crypt_mt(cc->cp_ctx_mt, seqnr, dest, ++ src, len, aadlen, authlen, cc->encrypt); ++ } ++#endif + return chachapoly_crypt(cc->cp_ctx, seqnr, dest, src, + len, aadlen, authlen, cc->encrypt); + } +@@ -389,9 +526,16 @@ + cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr, + const u_char *cp, u_int len) + { +- if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) ++ if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { ++#ifdef WITH_OPENSSL ++ if ((cc->cipher->flags & CFLAG_MT) != 0) { ++ return chachapoly_get_length_mt(cc->cp_ctx_mt, plenp, ++ seqnr, cp, len); ++ } ++#endif + return chachapoly_get_length(cc->cp_ctx, plenp, seqnr, + cp, len); ++ } + if (len < 4) + return SSH_ERR_MESSAGE_INCOMPLETE; + *plenp = PEEK_U32(cp); +@@ -404,13 +548,33 @@ + if (cc == NULL || cc->cipher == NULL) + return; + if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { ++#ifdef WITH_OPENSSL ++ if ((cc->cipher->flags & CFLAG_MT) != 0) { ++ chachapoly_free_mt(cc->cp_ctx_mt); ++ cc->cp_ctx_mt = NULL; ++ } else { ++ chachapoly_free(cc->cp_ctx); ++ cc->cp_ctx = NULL; ++ } ++#else + chachapoly_free(cc->cp_ctx); + cc->cp_ctx = NULL; ++#endif + } else if ((cc->cipher->flags & CFLAG_AESCTR) != 0) + explicit_bzero(&cc->ac_ctx, sizeof(cc->ac_ctx)); #ifdef WITH_OPENSSL EVP_CIPHER_CTX_free(cc->evp); cc->evp = NULL; @@ -4907,10 +5011,10 @@ diff -Nur openssh-9.3p1.orig/cipher.c openssh-9.3p1/cipher.c #endif freezero(cc, sizeof(*cc)); } -diff -Nur openssh-9.3p1.orig/cipher-chachapoly.c openssh-9.3p1/cipher-chachapoly.c ---- openssh-9.3p1.orig/cipher-chachapoly.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/cipher-chachapoly.c 2024-07-10 09:09:55.900568402 +0200 -@@ -89,7 +89,7 @@ +diff -Nur openssh-10.0p1.orig/cipher-chachapoly.c openssh-10.0p1/cipher-chachapoly.c +--- openssh-10.0p1.orig/cipher-chachapoly.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/cipher-chachapoly.c 2025-06-14 10:54:01.307925846 +0200 +@@ -88,7 +88,7 @@ if (!do_encrypt) { const u_char *tag = src + aadlen + len; @@ -4919,7 +5023,7 @@ diff -Nur openssh-9.3p1.orig/cipher-chachapoly.c openssh-9.3p1/cipher-chachapoly if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { r = SSH_ERR_MAC_INVALID; goto out; -@@ -109,7 +109,7 @@ +@@ -108,7 +108,7 @@ /* If encrypting, calculate and append tag */ if (do_encrypt) { @@ -4928,10 +5032,10 @@ diff -Nur openssh-9.3p1.orig/cipher-chachapoly.c openssh-9.3p1/cipher-chachapoly poly_key); } r = 0; -diff -Nur openssh-9.3p1.orig/cipher-chachapoly-libcrypto.c openssh-9.3p1/cipher-chachapoly-libcrypto.c ---- openssh-9.3p1.orig/cipher-chachapoly-libcrypto.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/cipher-chachapoly-libcrypto.c 2024-07-10 09:09:55.900568402 +0200 -@@ -35,8 +35,18 @@ +diff -Nur openssh-10.0p1.orig/cipher-chachapoly-libcrypto.c openssh-10.0p1/cipher-chachapoly-libcrypto.c +--- openssh-10.0p1.orig/cipher-chachapoly-libcrypto.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/cipher-chachapoly-libcrypto.c 2025-06-14 10:54:01.308400139 +0200 +@@ -34,8 +34,18 @@ #include "ssherr.h" #include "cipher-chachapoly.h" @@ -4950,7 +5054,7 @@ diff -Nur openssh-9.3p1.orig/cipher-chachapoly-libcrypto.c openssh-9.3p1/cipher- }; struct chachapoly_ctx * -@@ -57,6 +67,15 @@ +@@ -56,6 +66,15 @@ goto fail; if (EVP_CIPHER_CTX_iv_length(ctx->header_evp) != 16) goto fail; @@ -4966,7 +5070,7 @@ diff -Nur openssh-9.3p1.orig/cipher-chachapoly-libcrypto.c openssh-9.3p1/cipher- return ctx; fail: chachapoly_free(ctx); -@@ -70,6 +89,9 @@ +@@ -69,6 +88,9 @@ return; EVP_CIPHER_CTX_free(cpctx->main_evp); EVP_CIPHER_CTX_free(cpctx->header_evp); @@ -4976,7 +5080,7 @@ diff -Nur openssh-9.3p1.orig/cipher-chachapoly-libcrypto.c openssh-9.3p1/cipher- freezero(cpctx, sizeof(*cpctx)); } -@@ -108,7 +130,7 @@ +@@ -107,7 +129,7 @@ if (!do_encrypt) { const u_char *tag = src + aadlen + len; @@ -4985,7 +5089,7 @@ diff -Nur openssh-9.3p1.orig/cipher-chachapoly-libcrypto.c openssh-9.3p1/cipher- if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) != 0) { r = SSH_ERR_MAC_INVALID; goto out; -@@ -134,7 +156,7 @@ +@@ -133,7 +155,7 @@ /* If encrypting, calculate and append tag */ if (do_encrypt) { @@ -4994,10 +5098,758 @@ diff -Nur openssh-9.3p1.orig/cipher-chachapoly-libcrypto.c openssh-9.3p1/cipher- poly_key); } r = 0; -diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c ---- openssh-9.3p1.orig/cipher-ctr-mt.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/cipher-ctr-mt.c 2024-07-10 09:37:30.560413838 +0200 -@@ -0,0 +1,679 @@ +diff -Nur openssh-10.0p1.orig/cipher-chachapoly-libcrypto-mt.c openssh-10.0p1/cipher-chachapoly-libcrypto-mt.c +--- openssh-10.0p1.orig/cipher-chachapoly-libcrypto-mt.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/cipher-chachapoly-libcrypto-mt.c 2025-06-14 10:54:01.309077322 +0200 +@@ -0,0 +1,695 @@ ++/* ++ * Copyright (c) 2023 The Board of Trustees of Carnegie Mellon University. ++ * ++ * Author: Mitchell Dorrell ++ * Author: Chris Rapier ++ * ++ * This library is free software; you can redistribute it and/or modify it ++ * under the terms of the MIT License. ++ * ++ * This library is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the MIT License for more details. ++ * ++ * You should have received a copy of the MIT License along with this library; ++ * if not, see http://opensource.org/licenses/MIT. ++ * ++ */ ++ ++/* TODO: audit includes */ ++ ++#include "includes.h" ++#ifdef WITH_OPENSSL ++#include "openbsd-compat/openssl-compat.h" ++#endif ++ ++#if defined(HAVE_EVP_CHACHA20) && !defined(HAVE_BROKEN_CHACHA20) ++ ++#include ++#include /* needed for getpid under C99 */ ++#include /* needed for log.h */ ++#include ++#include /* needed for misc.h */ ++#include ++ ++#include ++ ++#include "defines.h" ++#include "log.h" ++#include "sshbuf.h" ++#include "ssherr.h" ++ ++#include "xmalloc.h" ++#include "cipher-chachapoly.h" ++#include "cipher-chachapoly-libcrypto-mt.h" ++ ++#ifndef likely ++# define likely(x) __builtin_expect(!!(x), 1) ++#endif ++#ifndef unlikely ++# define unlikely(x) __builtin_expect(!!(x), 0) ++#endif ++ ++/* Size of keystream to pregenerate, measured in bytes ++ * we want to round up to the nearest chacha block and have ++ * 128 bytes for overhead */ ++#define ROUND_UP(x,y) (((((x)-1)/(y))+1)*(y)) ++#define KEYSTREAMLEN (ROUND_UP((SSH_IOBUFSZ) + 128, (CHACHA_BLOCKLEN))) ++ ++/* BEGIN TUNABLES */ ++ ++/* Number of worker threads to spawn. */ ++/* the goal is to ensure that main is never ++ * waiting on the worker threads for keystream data */ ++#define NUMTHREADS 1 ++ ++/* 64 seems to be a pretty blance between memory and performance ++ * 128 is another option with somewhat higher memory consumption */ ++#define NUMSTREAMS 64 ++ ++/* END TUNABLES */ ++ ++struct mt_keystream { ++ u_char poly_key[POLY1305_KEYLEN]; /* POLY1305_KEYLEN == 32 */ ++ u_char headerStream[CHACHA_BLOCKLEN]; /* CHACHA_BLOCKLEN == 64 */ ++ u_char mainStream[KEYSTREAMLEN]; /* KEYSTREAMLEN == 32768 */ ++}; ++ ++struct threadData { ++ EVP_CIPHER_CTX * main_evp; ++ EVP_CIPHER_CTX * header_evp; ++ u_char seqbuf[16]; ++}; ++ ++struct mt_keystream_batch { ++ u_int batchID; ++ struct threadData tds[NUMTHREADS]; ++ struct mt_keystream streams[NUMSTREAMS]; ++}; ++ ++struct chachapoly_ctx_mt { ++ u_int seqnr; ++ u_int batchID; ++ ++ struct mt_keystream_batch batches[2]; ++ ++ pthread_t manager_tid[2]; ++ pthread_t self_tid; ++ ++ pid_t mainpid; ++ u_char zeros[KEYSTREAMLEN]; /* KEYSTREAMLEN == 32768 */ ++ ++ /* if OpenSSL has support for Poly1305 in the MAC EVPs ++ * use that (OSSL >= 3.0) if not then it's OSSL 1.1 so ++ * use the Poly1305 digest methods. Failing that use the ++ * internal poly1305 methods */ ++#ifdef OPENSSL_HAVE_POLY_EVP ++ EVP_MAC_CTX *poly_ctx; ++#elif !defined(WITH_OPENSSL3) && defined(EVP_PKEY_POLY1305) ++ EVP_PKEY_CTX *poly_ctx; ++ EVP_MD_CTX *md_ctx; ++ EVP_PKEY *pkey; ++ size_t ptaglen; ++#else ++ char *poly_ctx; ++#endif ++}; ++ ++struct manager_thread_args { ++ struct chachapoly_ctx_mt * ctx_mt; ++ u_int oldBatchID; ++ int retval; ++}; ++ ++struct worker_thread_args { ++ u_int batchID; ++ struct mt_keystream_batch * batch; ++ int threadIndex; ++ u_char * zeros; ++ int retval; ++}; ++ ++/* generate the keystream and header ++ * we use nulls for the "data" (the zeros variable) in order to ++ * get the raw keystream ++ * Returns 0 on success and -1 on failure */ ++int ++generate_keystream(struct mt_keystream * ks, u_int seqnr, ++ struct threadData * td, u_char * zeros) ++{ ++ /* generate poly1305 key */ ++ memset(td->seqbuf, 0, sizeof(td->seqbuf)); ++ POKE_U64(td->seqbuf + 8, seqnr); ++ memset(ks->poly_key , 0, sizeof(ks->poly_key)); ++ if (!EVP_CipherInit(td->main_evp, NULL, NULL, td->seqbuf, 1) || ++ EVP_Cipher(td->main_evp, ks->poly_key, ks->poly_key, ++ sizeof(ks->poly_key)) < 0) ++ return -1; ++ ++ /* generate header keystream for encrypting payload length */ ++ if (!EVP_CipherInit(td->header_evp, NULL, NULL, td->seqbuf, 1) || ++ EVP_Cipher(td->header_evp, ks->headerStream, zeros, CHACHA_BLOCKLEN) ++ < 0 ) ++ return -1; ++ ++ /* generate main keystream for encrypting payload */ ++ td->seqbuf[0] = 1; ++ if (!EVP_CipherInit(td->main_evp, NULL, NULL, td->seqbuf, 1) || ++ EVP_Cipher(td->main_evp, ks->mainStream, zeros, KEYSTREAMLEN) < 0) ++ return -1; ++ ++ return 0; ++} ++ ++/* free the EVP contexts associated with the give thread */ ++void ++free_threadData(struct threadData * td) ++{ ++ if (td == NULL) ++ return; ++ if (td->main_evp) /* false if initialization didn't get this far */ ++ EVP_CIPHER_CTX_free(td->main_evp); ++ if (td->header_evp) /* false if initialization didn't get this far */ ++ EVP_CIPHER_CTX_free(td->header_evp); ++ explicit_bzero(td, sizeof(*td)); ++} ++ ++/* initialize the EVPs used by the worker thread ++ Returns 0 on success and -1 on failure */ ++int ++initialize_threadData(struct threadData * td, const u_char *key) ++{ ++ memset(td,0,sizeof(*td)); ++ if ((td->main_evp = EVP_CIPHER_CTX_new()) == NULL || ++ (td->header_evp = EVP_CIPHER_CTX_new()) == NULL) ++ goto fail; ++ if (!EVP_CipherInit(td->main_evp, EVP_chacha20(), key, NULL, 1)) ++ goto fail; ++ if (!EVP_CipherInit(td->header_evp, EVP_chacha20(), key + 32, NULL, 1)) ++ goto fail; ++ if (EVP_CIPHER_CTX_iv_length(td->header_evp) != 16) ++ goto fail; ++ return 0; ++ fail: ++ free_threadData(td); ++ return -1; ++} ++ ++struct worker_thread_args * ++worker_thread(struct worker_thread_args * args) ++{ ++ /* check first */ ++ if (args == NULL) ++ return NULL; ++ if (args->batch == NULL || args->zeros == NULL) { ++ args->retval = 1; ++ return args; ++ } ++ ++ int threadIndex = args->threadIndex; ++ struct threadData * td = &(args->batch->tds[threadIndex]); ++ u_int refseqnr = args->batchID * NUMSTREAMS; ++ ++ for (int i = threadIndex; i < NUMSTREAMS; i += NUMTHREADS) { ++ if (generate_keystream(&(args->batch->streams[i]), refseqnr + i, ++ td, args->zeros) == -1) { ++ args->retval = 1; ++ return args; ++ } ++ } ++ ++ args->retval = 0; ++ return args; ++} ++ ++int ++join_manager_thread(pthread_t manager_tid) ++{ ++ struct manager_thread_args * args; ++ if (pthread_join(manager_tid, (void **) &args) == 0) { ++ if (args == NULL) { ++ debug_f("Manager thread returned NULL!"); ++ return 1; ++ } else if (args == PTHREAD_CANCELED) { ++ debug_f("Manager thread canceled!"); ++ return 1; ++ } else if (args->retval != 0) { ++ debug_f("Manager thread error (%d)", args->retval); ++ free(args); ++ return 1; ++ } else { ++ free(args); ++ return 0; ++ } ++ } else { ++ debug_f("pthread_join error!"); ++ return 1; ++ } ++} ++ ++void ++chachapoly_free_mt(struct chachapoly_ctx_mt * ctx_mt) ++{ ++ if (ctx_mt == NULL) ++ return; ++ ++#ifdef OPENSSL_HAVE_POLY_EVP ++ if (ctx_mt->poly_ctx != NULL) { ++ EVP_MAC_CTX_free(ctx_mt->poly_ctx); ++ ctx_mt->poly_ctx = NULL; ++ } ++#elif !defined(WITH_OPENSSL3) && defined(EVP_PKEY_POLY1305) ++ if (ctx_mt->md_ctx != NULL) { ++ EVP_MD_CTX_free(ctx_mt->md_ctx); ++ ctx_mt->md_ctx = NULL; ++ } ++ if (ctx_mt->pkey != NULL) { ++ EVP_PKEY_free(ctx_mt->pkey); ++ ctx_mt->pkey = NULL; ++ } ++#endif ++ ++ /* ++ * Only cleanup the manager threads if we are the PID that initialized ++ * them! If we're a fork, the threads don't really exist. ++ */ ++ ++ if (getpid() == ctx_mt->mainpid) { ++ if (ctx_mt->manager_tid[0] != ctx_mt->self_tid) { ++ join_manager_thread(ctx_mt->manager_tid[0]); ++ ctx_mt->manager_tid[0] = ctx_mt->self_tid; ++ } ++ if (ctx_mt->manager_tid[1] != ctx_mt->self_tid) { ++ join_manager_thread(ctx_mt->manager_tid[1]); ++ ctx_mt->manager_tid[1] = ctx_mt->self_tid; ++ } ++ } ++ ++ /* Cleanup thread data structures. */ ++ for (int i=0; i<2; i++) ++ for (int j=0; jbatches[i].tds[j])); ++ ++ /* Zero and free the whole multithreaded cipher context. */ ++ freezero(ctx_mt, sizeof(*ctx_mt)); ++ ++ return; ++} ++ ++struct chachapoly_ctx_mt * ++chachapoly_new_mt(u_int startseqnr, const u_char * key, u_int keylen) ++{ ++ struct chachapoly_ctx_mt * ctx_mt = xmalloc(sizeof(*ctx_mt)); ++ memset(ctx_mt, 0, sizeof(*ctx_mt)); ++ /* Initialize the sequence number. When rekeying, this won't be zero. */ ++ ctx_mt->seqnr = startseqnr; ++ ctx_mt->batchID = startseqnr / NUMSTREAMS; ++ struct threadData mainData; ++ int tDataI; ++ int genKSfailed = 0; ++ ++#ifdef OPENSSL_HAVE_POLY_EVP ++ EVP_MAC *mac = NULL; ++ if ((mac = EVP_MAC_fetch(NULL, "POLY1305", NULL)) == NULL) ++ goto fail; ++ if ((ctx_mt->poly_ctx = EVP_MAC_CTX_new(mac)) == NULL) ++ goto fail; ++#elif !defined(WITH_OPENSSL3) && defined(EVP_PKEY_POLY1305) ++ if ((ctx_mt->md_ctx = EVP_MD_CTX_new()) == NULL) ++ goto fail; ++ if ((ctx_mt->pkey = EVP_PKEY_new_mac_key(EVP_PKEY_POLY1305, NULL, ++ ctx_mt->zeros, POLY1305_KEYLEN)) == NULL) ++ goto fail; ++ if (EVP_DigestSignInit(ctx_mt->md_ctx, &ctx_mt->poly_ctx, NULL, NULL, ++ ctx_mt->pkey) == 0) ++ goto fail; ++#else ++ ctx_mt->poly_ctx = NULL; ++#endif ++ ++ ctx_mt->batches[ctx_mt->batchID % 2].batchID = ctx_mt->batchID; ++ ctx_mt->batches[(ctx_mt->batchID + 1) % 2].batchID = ++ ctx_mt->batchID + 1; ++ ++ /* initialize batches[0] tds */ ++ for (tDataI = 0; tDataI < NUMTHREADS; tDataI++) { ++ if (initialize_threadData(&(ctx_mt->batches[0].tds[tDataI]), ++ key) != 0) ++ break; ++ } ++ if (tDataI < NUMTHREADS) { ++ /* Backtrack starting with 'tDataI - 1' */ ++ for (tDataI--; tDataI >= 0; tDataI--) ++ free_threadData(&(ctx_mt->batches[0].tds[tDataI])); ++ goto fail; ++ } ++ /* initialize batches[1] tds */ ++ for (tDataI = 0; tDataI < NUMTHREADS; tDataI++) { ++ if (initialize_threadData(&(ctx_mt->batches[1].tds[tDataI]), ++ key) != 0) ++ break; ++ } ++ if (tDataI < NUMTHREADS) { ++ /* Backtrack starting with 'tDataI - 1' */ ++ for (tDataI--; tDataI >= 0; tDataI--) ++ free_threadData(&(ctx_mt->batches[1].tds[tDataI])); ++ /* Free the batches[0] tds too */ ++ for (tDataI = NUMTHREADS; tDataI >= 0; tDataI--) ++ free_threadData(&(ctx_mt->batches[0].tds[tDataI])); ++ goto fail; ++ } ++ ++ if (initialize_threadData(&mainData, key) != 0) { ++ chachapoly_free_mt(ctx_mt); ++ explicit_bzero(&startseqnr, sizeof(startseqnr)); ++ return NULL; ++ } ++ ++ for (int i=0; i<2; i++) { ++ u_int refseqnr = ctx_mt->batches[i].batchID * NUMSTREAMS; ++ for (int j = startseqnr > refseqnr ? startseqnr - refseqnr : 0; ++ jbatches[i].streams[j]), ++ refseqnr + j, &mainData, ctx_mt->zeros) == -1) { ++ debug_f("generate_keystream failed in " ++ "chacha20-poly1305@hpnssh.org"); ++ genKSfailed = 1; ++ break; /* imperfect, but it helps */ ++ } ++ } ++ } ++ ++ free_threadData(&mainData); ++ ++ if (genKSfailed != 0) { ++ chachapoly_free_mt(ctx_mt); ++ explicit_bzero(&startseqnr, sizeof(startseqnr)); ++ return NULL; ++ } ++ ++ /* Store the PID so that in the future, we can tell if we're a fork */ ++ ctx_mt->mainpid = getpid(); ++ ctx_mt->self_tid = pthread_self(); ++ ctx_mt->manager_tid[0] = ctx_mt->self_tid; ++ ctx_mt->manager_tid[1] = ctx_mt->self_tid; ++ /* was reporting the TID using gettid() but it's not portable */ ++ debug2_f("
", getpid(), pthread_self()); ++ ++ /* Success! */ ++ explicit_bzero(&startseqnr, sizeof(startseqnr)); ++ return ctx_mt; ++ ++ fail: ++#ifdef OPENSSL_HAVE_POLY_EVP ++ if (ctx_mt->poly_ctx != NULL) { ++ EVP_MAC_CTX_free(ctx_mt->poly_ctx); ++ ctx_mt->poly_ctx = NULL; ++ } ++#elif !defined(WITH_OPENSSL3) && defined(EVP_PKEY_POLY1305) ++ if (ctx_mt->md_ctx != NULL) { ++ EVP_MD_CTX_free(ctx_mt->md_ctx); ++ ctx_mt->md_ctx = NULL; ++ } ++ if (ctx_mt->pkey != NULL) { ++ EVP_PKEY_free(ctx_mt->pkey); ++ ctx_mt->pkey = NULL; ++ } ++#endif ++ freezero(ctx_mt, sizeof(*ctx_mt)); ++ explicit_bzero(&startseqnr, sizeof(startseqnr)); ++ return NULL; ++} ++ ++/* a fast method to XOR the keystream against the data */ ++static inline void ++fastXOR(u_char *dest, const u_char *src, const u_char *keystream, u_int len) ++{ ++ ++ /* XXX: this was __uint128_t but that was causing unaligned load errors. ++ * this works but we need to explore it more. */ ++ typedef uint32_t chunk; ++ size_t i; ++ ++ for (i=0; i < (len / sizeof(chunk)); i++) ++ ((chunk *)dest)[i]=((chunk *)src)[i]^((chunk *)keystream)[i]; ++ for (i=i*(sizeof(chunk) / sizeof(char)); i < len; i++) ++ dest[i]=src[i]^keystream[i]; ++} ++ ++struct manager_thread_args * ++manager_thread(struct manager_thread_args * margs) { ++ /* make sure we have valid data before proceeding */ ++ if (margs == NULL) ++ return NULL; ++ ++ struct chachapoly_ctx_mt * ctx_mt = margs->ctx_mt; ++ if (ctx_mt == NULL) { ++ margs->retval = 1; ++ return margs; ++ } ++ ++ u_int oldBatchID = margs->oldBatchID; ++ ++ struct mt_keystream_batch * batch = &(ctx_mt->batches[oldBatchID % 2]); ++ if (batch->batchID != oldBatchID) { ++ debug_f("Post-crypt batch miss! Seeking %u, found %u. Failing.", ++ oldBatchID, batch->batchID); ++ margs->retval = 1; ++ return margs; ++ } ++ ++ margs->retval = 0; ++ u_int batchID = oldBatchID + 2; ++ ++ pthread_t tid[NUMTHREADS]; ++ struct worker_thread_args * wargs = malloc(NUMTHREADS * sizeof(*wargs)); ++ int ti; ++ ++ for (ti = 0; ti < NUMTHREADS; ti++) { ++ wargs[ti].batchID = batchID; ++ wargs[ti].batch = batch; ++ wargs[ti].threadIndex = ti; ++ wargs[ti].zeros = ctx_mt->zeros; ++ if (pthread_create(&(tid[ti]), NULL, (void *) worker_thread, ++ &(wargs[ti])) != 0) { ++ margs->retval = 1; ++ break; ++ } ++ } ++ for (; ti < NUMTHREADS; ti++) /* for error condition */ ++ tid[ti] = pthread_self(); ++ ++ struct worker_thread_args * retwargs; ++ ++ for (ti = 0; ti < NUMTHREADS; ti++) { ++ if (tid[ti] == pthread_self()) { ++ margs->retval = 1; /* redundant, but harmless */ ++ continue; ++ } ++ if (pthread_join(tid[ti], (void **) &retwargs) == 0) { ++ if (retwargs == NULL) { ++ debug_f("Worker thread returned NULL!"); ++ margs->retval = 1; ++ } else if (retwargs == PTHREAD_CANCELED) { ++ debug_f("Worker thread canceled!"); ++ margs->retval = 1; ++ } else { ++ if (retwargs->retval != 0) { ++ debug_f("Worker thread error (%d)", ++ retwargs->retval); ++ margs->retval = 1; ++ } ++ if (retwargs != &(wargs[ti])) { ++ debug_f("Worker thread didn't return " ++ "expected structure!"); ++ margs->retval = 1; ++ } ++ } ++ } else { ++ debug_f("pthread_join error!"); ++ margs->retval = 1; ++ } ++ } ++ free(wargs); ++ ++ if (margs->retval == 0) { ++ batch->batchID = batchID; ++ } ++ ++ return margs; ++} ++ ++int ++chachapoly_crypt_mt(struct chachapoly_ctx_mt *ctx_mt, u_int seqnr, u_char *dest, ++ const u_char *src, u_int len, u_int aadlen, u_int authlen, int do_encrypt) ++{ ++#ifdef SAFETY ++ if (ctx_mt->mainpid != getpid()) { /* we're a fork */ ++ /* ++ * TODO: this is EXTREMELY RARE, may never happen at all (only ++ * if the fork calls crypt), so we should tell the compiler. ++ */ ++ /* The worker threads don't exist, we could spawn them? */ ++ debug_f("Fork called crypt without workers!"); ++ chachapoly_free_mt(ctx_mt); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++#endif ++ ++ pthread_t * manager_tid = &(ctx_mt->manager_tid[ctx_mt->batchID % 2]); ++ if (unlikely(*manager_tid != ctx_mt->self_tid)) { ++ int ret = join_manager_thread(*manager_tid); ++ *manager_tid = ctx_mt->self_tid; ++ if (ret != 0) ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++ ++ struct mt_keystream_batch * batch = ++ &(ctx_mt->batches[ctx_mt->batchID % 2]); ++ ++ struct mt_keystream * ks = &(batch->streams[seqnr % NUMSTREAMS]); ++ ++ int r = SSH_ERR_INTERNAL_ERROR; ++ ++#ifdef SAFETY ++ if (batch->batchID == ctx_mt->batchID) { /* Safety check */ ++#endif ++ /* check tag before anything else */ ++ if (!do_encrypt) { ++ const u_char *tag = src + aadlen + len; ++ u_char expected_tag[POLY1305_TAGLEN]; ++#if !defined(WITH_OPENSSL3) && defined(EVP_PKEY_POLY1305) ++ if ((EVP_PKEY_CTX_ctrl(ctx_mt->poly_ctx, -1, ++ EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_MAC_KEY, ++ POLY1305_KEYLEN, ks->poly_key) <= 0) || ++ (EVP_DigestSignUpdate(ctx_mt->md_ctx, src, aadlen + len) == 0)) { ++ debug_f("SSL error while decrypting poly1305 tag"); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++ ctx_mt->ptaglen = POLY1305_TAGLEN; ++ if (EVP_DigestSignFinal(ctx_mt->md_ctx, expected_tag, ++ &ctx_mt->ptaglen) == 0) { ++ debug_f("SSL error while finalizing decyrpted poly1305"); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++#else ++ poly1305_auth(ctx_mt->poly_ctx, expected_tag, src, ++ aadlen + len, ks->poly_key); ++#endif ++ if (timingsafe_bcmp(expected_tag, tag, POLY1305_TAGLEN) ++ != 0) ++ r = SSH_ERR_MAC_INVALID; ++ explicit_bzero(expected_tag, sizeof(expected_tag)); ++ } ++ if (r != SSH_ERR_MAC_INVALID) { ++ /* Crypt additional data (i.e., packet length) */ ++ /* TODO: is aadlen always four bytes? */ ++ /* TODO: do we always have an aadlen? */ ++ if (aadlen) ++ for (u_int i=0; iheaderStream[i] ^ src[i]; ++ /* Crypt payload */ ++ fastXOR(dest+aadlen,src+aadlen,ks->mainStream,len); ++ /* calculate and append tag */ ++#if !defined(WITH_OPENSSL3) && defined(EVP_PKEY_POLY1305) ++ if (do_encrypt) { ++ if ((EVP_PKEY_CTX_ctrl(ctx_mt->poly_ctx, -1, ++ EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_MAC_KEY, ++ POLY1305_KEYLEN, ks->poly_key) <=0) || ++ (EVP_DigestSignUpdate(ctx_mt->md_ctx, dest, aadlen + len) == 0)) { ++ debug_f ("SSL error while encrypting poly1305 tag"); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++ ctx_mt->ptaglen = POLY1305_TAGLEN; ++ if (EVP_DigestSignFinal(ctx_mt->md_ctx, dest+aadlen+len, ++ &ctx_mt->ptaglen) == 0) { ++ debug_f("SSL error while finalizing decyrpted poly1305"); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++ } ++#else ++ if (do_encrypt) ++ poly1305_auth(ctx_mt->poly_ctx, dest+aadlen+len, ++ dest, aadlen+len, ks->poly_key); ++#endif ++ r=0; /* Success! */ ++ } ++ if (r) /* Anything nonzero is an error. */ ++ return r; ++ ++ ctx_mt->seqnr = seqnr + 1; ++ ++ if (unlikely(ctx_mt->seqnr / NUMSTREAMS > ctx_mt->batchID)) { ++ struct manager_thread_args * args = ++ malloc(sizeof(*args)); ++ if (args == NULL) { ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++ args->ctx_mt = ctx_mt; ++ args->oldBatchID = ctx_mt->batchID; ++ if (pthread_create(&(ctx_mt->manager_tid[ctx_mt->batchID ++ % 2]), NULL, (void *) manager_thread, args) != 0) { ++ free(args); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++ ctx_mt->batchID = ctx_mt->seqnr / NUMSTREAMS; ++ } ++ ++ /* TODO: Nothing we need to sanitize here? */ ++ ++ return 0; ++#ifdef SAFETY ++ } else { /* Bad, it's the wrong batch. */ ++ debug_f( "Pre-crypt batch miss! Seeking %u, found %u. Failing.", ++ ctx_mt->batchID, batch->batchID); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++#endif ++} ++ ++int ++chachapoly_get_length_mt(struct chachapoly_ctx_mt *ctx_mt, u_int *plenp, ++ u_int seqnr, const u_char *cp, u_int len) ++{ ++ /* TODO: add compiler hints */ ++#ifdef SAFETY ++ if (ctx_mt->mainpid != getpid()) { /* Use serial mode if we're a fork */ ++ debug_f("We're a fork. Failing."); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++#endif ++ ++ if (len < 4) ++ return SSH_ERR_MESSAGE_INCOMPLETE; ++ ++ pthread_t * manager_tid = &(ctx_mt->manager_tid[ctx_mt->batchID % 2]); ++ if (unlikely(*manager_tid != ctx_mt->self_tid)) { ++ int ret = join_manager_thread(*manager_tid); ++ *manager_tid = ctx_mt->self_tid; ++ if (ret != 0) ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++ ++ u_char buf[4]; ++#ifdef SAFETY ++ u_int sought_batchID = seqnr / NUMSTREAMS; ++#endif ++ struct mt_keystream_batch * batch = ++ &(ctx_mt->batches[ctx_mt->batchID % 2]); ++ struct mt_keystream * ks = &(batch->streams[seqnr % NUMSTREAMS]); ++#ifdef SAFETY ++ if (batch->batchID == sought_batchID) { ++#endif ++ for (u_int i=0; i < sizeof(buf); i++) ++ buf[i]=ks->headerStream[i] ^ cp[i]; ++ *plenp = PEEK_U32(buf); ++ return 0; ++#ifdef SAFETY ++ } else { ++ debug_f("Batch miss! Seeking %u, found %u. Failing.", ++ sought_batchID, batch->batchID); ++ return SSH_ERR_INTERNAL_ERROR; ++ } ++#endif ++} ++#endif /* defined(HAVE_EVP_CHACHA20) && !defined(HAVE_BROKEN_CHACHA20) */ +diff -Nur openssh-10.0p1.orig/cipher-chachapoly-libcrypto-mt.h openssh-10.0p1/cipher-chachapoly-libcrypto-mt.h +--- openssh-10.0p1.orig/cipher-chachapoly-libcrypto-mt.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/cipher-chachapoly-libcrypto-mt.h 2025-06-14 10:54:01.309455724 +0200 +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 2023 The Board of Trustees of Carnegie Mellon University. ++ * ++ * Author: Mitchell Dorrell ++ * Author: Chris Rapier ++ * ++ * This library is free software; you can redistribute it and/or modify it ++ * under the terms of the MIT License. ++ * ++ * This library is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the MIT License for more details. ++ * ++ * You should have received a copy of the MIT License along with this library; ++ * if not, see http://opensource.org/licenses/MIT. ++ * ++ */ ++ ++#ifndef CHACHA_POLY_LIBCRYPTO_MT_H ++#define CHACHA_POLY_LIBCRYPTO_MT_H ++ ++#include ++#include "chacha.h" ++#include "poly1305.h" ++ ++#ifndef CHACHA_KEYLEN ++#define CHACHA_KEYLEN 32 /* Only 256 bit keys used here */ ++#endif ++ ++struct chachapoly_ctx_mt; /* defined in cipher-chachapoly-libcrypto-mt.c */ ++ ++struct chachapoly_ctx_mt *chachapoly_new_mt(u_int startseqnr, const u_char *key, u_int keylen) ++ __attribute__((__bounded__(__buffer__, 2, 3))); ++ ++void chachapoly_free_mt(struct chachapoly_ctx_mt *cpctx); ++ ++int chachapoly_crypt_mt(struct chachapoly_ctx_mt *cpctx, u_int seqnr, ++ u_char *dest, const u_char *src, u_int len, u_int aadlen, ++ u_int authlen, int do_encrypt); ++ ++int chachapoly_get_length_mt(struct chachapoly_ctx_mt *cpctx, ++ u_int *plenp, u_int seqnr, const u_char *cp, u_int len) ++ __attribute__((__bounded__(__buffer__, 4, 5))); ++ ++#endif /* CHACHA_POLY_LIBCRYPTO_MT_H */ +diff -Nur openssh-10.0p1.orig/cipher-ctr-mt.c openssh-10.0p1/cipher-ctr-mt.c +--- openssh-10.0p1.orig/cipher-ctr-mt.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/cipher-ctr-mt.c 2025-06-14 10:54:01.309949084 +0200 +@@ -0,0 +1,677 @@ +/* + * OpenSSH Multi-threaded AES-CTR Cipher + * @@ -5023,8 +5875,7 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c + */ +#include "includes.h" + -+#if defined(WITH_OPENSSL) -+#if OPENSSL_VERSION_NUMBER < 0x30000000UL ++#if defined(WITH_OPENSSL) && !defined(WITH_OPENSSL3) +#include + +#include @@ -5072,8 +5923,8 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c + +/*-------------------- TUNABLES --------------------*/ +/* maximum number of threads and queues */ -+#define MAX_THREADS 4 -+#define MAX_NUMKQ (MAX_THREADS + 1) ++#define MAX_THREADS 4 ++#define MAX_NUMKQ (MAX_THREADS + 1) + +/* Number of pregen threads to use */ +/* this is a default value. The actual number is @@ -5110,9 +5961,9 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c +#endif +/*-------------------- END TUNABLES --------------------*/ + -+#define HAVE_NONE 0 -+#define HAVE_KEY 1 -+#define HAVE_IV 2 ++#define HAVE_NONE 0 ++#define HAVE_KEY 1 ++#define HAVE_IV 2 +int X = 0; + +const EVP_CIPHER *evp_aes_ctr_mt(void); @@ -5130,24 +5981,24 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c +struct kq { + u_char keys[KQLEN][AES_BLOCK_SIZE]; /* [32768][16B] */ + u_char ctr[AES_BLOCK_SIZE]; /* 16B */ -+ u_char pad0[CACHELINE_LEN]; ++ u_char pad0[CACHELINE_LEN]; + pthread_mutex_t lock; + pthread_cond_t cond; -+ int qstate; -+ u_char pad1[CACHELINE_LEN]; ++ int qstate; ++ u_char pad1[CACHELINE_LEN]; +}; + +/* Context struct */ +struct ssh_aes_ctr_ctx_mt +{ + long unsigned int struct_id; -+ int keylen; ++ int keylen; + int state; + int qidx; + int ridx; -+ int id[MAX_THREADS]; /* 32 */ -+ AES_KEY aes_key; -+ const u_char *orig_key; ++ int id[MAX_THREADS]; /* 32 */ ++ AES_KEY aes_key; ++ const u_char *orig_key; + u_char aes_counter[AES_BLOCK_SIZE]; /* 16B */ + pthread_t tid[MAX_THREADS]; /* 32 */ + pthread_rwlock_t tid_lock; @@ -5416,7 +6267,7 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c +/* this may also benefit from upgrading to the EVP API */ +static int +ssh_aes_ctr(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, -+ LIBCRYPTO_EVP_INL_TYPE len) ++ size_t len) +{ + typedef union { +#ifdef CIPHER_INT128_OK @@ -5462,9 +6313,15 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c + * may need to do it in 8 or 4 bytes chunks + * worst case is doing it as a loop */ +#ifdef CIPHER_INT128_OK -+ if ((align & 0xf) == 0) { -+ destp.u128[0] = srcp.u128[0] ^ bufp.u128[0]; -+ } else ++ /* with GCC 13 we have having consistent seg faults ++ * in this section of code. Since this is a critical ++ * code path we are removing this until we have a solution ++ * in place -cjr 02/22/24 ++ * TODO: FIX THIS ++ */ ++ /* if ((align & 0xf) == 0) { */ ++ /* destp.u128[0] = srcp.u128[0] ^ bufp.u128[0]; */ ++ /* } else */ +#endif + /* 64 bits */ + if ((align & 0x7) == 0) { @@ -5652,12 +6509,6 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c +} + +/* */ -+/* we've stipped out support for LibreSSL and OpenSSL < 1.1 -+ * it was getting to be too much to maintain. If LibreSSL -+ * ever incorporates the meth_new() functionality we'll -+ * reinstate support in configure.ac -+ * cjr 2/8/2023 -+ */ +const EVP_CIPHER * +evp_aes_ctr_mt(void) +{ @@ -5675,12 +6526,11 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt.c openssh-9.3p1/cipher-ctr-mt.c +# endif /*SSH_OLD_EVP*/ + return aes_ctr; +} -+#endif /* OSSL VERSION NUMBER */ -+#endif /* OSSL */ -diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.c openssh-9.3p1/cipher-ctr-mt-functions.c ---- openssh-9.3p1.orig/cipher-ctr-mt-functions.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/cipher-ctr-mt-functions.c 2024-07-10 09:09:55.901568405 +0200 -@@ -0,0 +1,652 @@ ++#endif /* OSSL Check */ +diff -Nur openssh-10.0p1.orig/cipher-ctr-mt-functions.c openssh-10.0p1/cipher-ctr-mt-functions.c +--- openssh-10.0p1.orig/cipher-ctr-mt-functions.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/cipher-ctr-mt-functions.c 2025-06-14 10:54:01.310535264 +0200 +@@ -0,0 +1,668 @@ +/* + * OpenSSH Multi-threaded AES-CTR Cipher Provider for OpenSSL 3 + * @@ -5707,9 +6557,8 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.c openssh-9.3p1/cipher-ctr- + +#include "includes.h" + -+#ifdef WITH_OPENSSL +/* only for systems with OSSL 3 */ -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++#ifdef WITH_OPENSSL3 +#include +#include +#include @@ -5899,7 +6748,6 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.c openssh-9.3p1/cipher-ctr- + struct aes_mt_ctx_st *aes_mt_ctx = job; + struct kq *q; + struct aes_mt_ctx_ptrs *ptr; -+ int qidx; + pthread_t first_tid; + int outlen; + u_char mynull[KQLEN * AES_BLOCK_SIZE]; @@ -5965,9 +6813,15 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.c openssh-9.3p1/cipher-ctr- + * a draining queue to become empty. + * + * Multiple threads may be waiting on a draining queue and awoken -+ * when empty. The first thread to wake will mark it as filling, ++ * when empty. The first thread to wake will mark it as filling, + * others will move on to fill, skip, or wait on the next queue. ++ * We init qidx here because if we do it at the top of the function ++ * we get a warning about it possibly being clobbered. The exact reason ++ * doesn't make a lot of sense but it has to happen after the ++ * first pthread_rwlock_rdlock(). Might have something to do with ++ * incorrect compiler optimizations. + */ ++ int qidx; + for (qidx = 1;; qidx = (qidx + 1) % numkq) { + /* Check if I was cancelled, also checked in cond_wait */ + pthread_testcancel(); @@ -6201,10 +7055,17 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.c openssh-9.3p1/cipher-ctr- + aes_mt_ctx->ridx = 0; + aes_mt_ctx->struct_id = global_struct_id++; + -+ /* Start threads */ ++ /* Start threads. Make sure we have enough stack space (under alpine) ++ * and aren't using more than we need (linux). This can be as low as ++ * 512KB but that's a minimum. 1024KB gives us a little headroom if we ++ * need it */ ++#define STACK_SIZE (1024 * 1024) ++ pthread_attr_t attr; ++ pthread_attr_init(&attr); ++ pthread_attr_setstacksize(&attr, STACK_SIZE); + for (int i = 0; i < cipher_threads; i++) { + pthread_rwlock_wrlock(&aes_mt_ctx->tid_lock); -+ if (pthread_create(&aes_mt_ctx->tid[i], NULL, thread_loop, aes_mt_ctx) != 0) ++ if (pthread_create(&aes_mt_ctx->tid[i], &attr, thread_loop, aes_mt_ctx) != 0) + fatal ("AES-CTR MT Could not create thread in %s", __func__); + else { + aes_mt_ctx->id[i] = i; @@ -6280,9 +7141,15 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.c openssh-9.3p1/cipher-ctr- + * may need to do it in 8 or 4 bytes chunks + * worst case is doing it as a loop */ +#ifdef CIPHER_INT128_OK -+ if ((align & 0xf) == 0) { -+ destp.u128[0] = srcp.u128[0] ^ bufp.u128[0]; -+ } else ++ /* with GCC 13 we have having consistent seg faults ++ * in this section of code. Since this is a critical ++ * code path we are removing this until we have a solution ++ * in place -cjr 02/22/24 ++ * TODO: FIX THIS ++ */ ++ /* if ((align & 0xf) == 0) { */ ++ /* destp.u128[0] = srcp.u128[0] ^ bufp.u128[0]; */ ++ /* } else */ +#endif + /* 64 bits */ + if ((align & 0x7) == 0) { @@ -6331,12 +7198,11 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.c openssh-9.3p1/cipher-ctr- + return 1; +} + -+#endif /*OPENSSL_VERSION_NUMBER */ -+#endif /*WITH_OPENSSL*/ -diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.h openssh-9.3p1/cipher-ctr-mt-functions.h ---- openssh-9.3p1.orig/cipher-ctr-mt-functions.h 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/cipher-ctr-mt-functions.h 2024-07-10 09:09:55.901568405 +0200 -@@ -0,0 +1,144 @@ ++#endif /*WITH_OPENSSL3*/ +diff -Nur openssh-10.0p1.orig/cipher-ctr-mt-functions.h openssh-10.0p1/cipher-ctr-mt-functions.h +--- openssh-10.0p1.orig/cipher-ctr-mt-functions.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/cipher-ctr-mt-functions.h 2025-06-14 10:54:01.310937760 +0200 +@@ -0,0 +1,142 @@ +/* + * OpenSSH Multi-threaded AES-CTR Cipher Provider for OpenSSL 3 + * @@ -6375,9 +7241,8 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.h openssh-9.3p1/cipher-ctr- +#include +#endif + -+#ifdef WITH_OPENSSL +/* only for systems with OSSL 3 */ -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++#ifdef WITH_OPENSSL3 + +/*-------------------- TUNABLES --------------------*/ +/* maximum number of threads and queues */ @@ -6478,13 +7343,12 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-functions.h openssh-9.3p1/cipher-ctr- +void *aes_mt_newctx_192(void *); +void *aes_mt_newctx_128(void *); + -+#endif /* VERSION NUMBER */ +#endif /* WITH OPENSSL */ +#endif /* CTR_MT_FUNCS */ -diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-provider.c openssh-9.3p1/cipher-ctr-mt-provider.c ---- openssh-9.3p1.orig/cipher-ctr-mt-provider.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/cipher-ctr-mt-provider.c 2024-07-10 09:09:55.902568408 +0200 -@@ -0,0 +1,392 @@ +diff -Nur openssh-10.0p1.orig/cipher-ctr-mt-provider.c openssh-10.0p1/cipher-ctr-mt-provider.c +--- openssh-10.0p1.orig/cipher-ctr-mt-provider.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/cipher-ctr-mt-provider.c 2025-06-14 10:54:01.311329711 +0200 +@@ -0,0 +1,390 @@ +/* + * OpenSSH Multi-threaded AES-CTR Cipher Provider for OpenSSL 3 + * @@ -6509,9 +7373,8 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-provider.c openssh-9.3p1/cipher-ctr-m + +#include "includes.h" + -+#ifdef WITH_OPENSSL +/* only for systems with OSSL 3.0+ */ -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++#ifdef WITH_OPENSSL3 + +#include +#include @@ -6635,10 +7498,10 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-provider.c openssh-9.3p1/cipher-ctr-m + +/* the ciphers found in this provider */ +const OSSL_ALGORITHM aes_mt_ciphers[] = { -+ { "aes_ctr_mt_256", "provider=hpnssh", aes_mt_funcs_256 }, -+ { "aes_ctr_mt_192", "provider=hpnssh", aes_mt_funcs_192 }, -+ { "aes_ctr_mt_128", "provider=hpnssh", aes_mt_funcs_128 }, -+ { NULL, NULL, NULL } ++ { "aes_ctr_mt_256", "provider=hpnssh", aes_mt_funcs_256, NULL }, ++ { "aes_ctr_mt_192", "provider=hpnssh", aes_mt_funcs_192, NULL }, ++ { "aes_ctr_mt_128", "provider=hpnssh", aes_mt_funcs_128, NULL }, ++ { NULL, NULL, NULL, NULL } +}; + +/* function mapping for provider methods */ @@ -6875,12 +7738,37 @@ diff -Nur openssh-9.3p1.orig/cipher-ctr-mt-provider.c openssh-9.3p1/cipher-ctr-m + return ok; +} + -+#endif /*OPENSSL_VERSION_NUMBER */ -+#endif /*WITH_OPENSSL*/ -diff -Nur openssh-9.3p1.orig/cipher.h openssh-9.3p1/cipher.h ---- openssh-9.3p1.orig/cipher.h 2024-07-10 09:07:09.734081857 +0200 -+++ openssh-9.3p1/cipher.h 2024-07-10 09:09:55.902568408 +0200 -@@ -68,25 +68,29 @@ ++#endif /*WITH_OPENSSL3*/ +diff -Nur openssh-10.0p1.orig/cipher.h openssh-10.0p1/cipher.h +--- openssh-10.0p1.orig/cipher.h 2025-06-14 10:53:01.717078466 +0200 ++++ openssh-10.0p1/cipher.h 2025-06-14 13:45:10.880862884 +0200 +@@ -42,11 +42,17 @@ + #include + #endif + #include "cipher-chachapoly.h" ++#ifdef WITH_OPENSSL ++#include "cipher-chachapoly-libcrypto-mt.h" ++#endif + #include "cipher-aesctr.h" + + #define CIPHER_ENCRYPT 1 + #define CIPHER_DECRYPT 0 + ++#define CIPHER_MULTITHREAD 1 ++#define CIPHER_SERIAL 0 ++ + struct sshcipher { + char *name; + u_int block_size; +@@ -60,6 +66,7 @@ + #define CFLAG_NONE (1<<3) + #define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */ + #ifdef WITH_OPENSSL ++#define CFLAG_MT (1<<4) + const EVP_CIPHER *(*evptype)(void); + #else + void *ignored; +@@ -68,24 +75,27 @@ struct sshcipher_ctx; @@ -6892,7 +7780,7 @@ diff -Nur openssh-9.3p1.orig/cipher.h openssh-9.3p1/cipher.h const char *compression_alg_list(int); int cipher_init(struct sshcipher_ctx **, const struct sshcipher *, - const u_char *, u_int, const u_char *, u_int, int); -+ const u_char *, u_int, const u_char *, u_int, int, int); ++ const u_char *, u_int, const u_char *, u_int, u_int, int, int); int cipher_crypt(struct sshcipher_ctx *, u_int, u_char *, const u_char *, u_int, u_int, u_int); int cipher_get_length(struct sshcipher_ctx *, u_int *, u_int, @@ -6908,13 +7796,110 @@ diff -Nur openssh-9.3p1.orig/cipher.h openssh-9.3p1/cipher.h +void cipher_reset_multithreaded(void); +const char *cipher_ctx_name(const struct sshcipher_ctx *); -+const char *cipher_ctx_name(const struct sshcipher_ctx *); u_int cipher_ctx_is_plaintext(struct sshcipher_ctx *); - int cipher_get_keyiv(struct sshcipher_ctx *, u_char *, size_t); -diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c ---- openssh-9.3p1.orig/clientloop.c 2024-07-10 09:07:09.623081532 +0200 -+++ openssh-9.3p1/clientloop.c 2024-07-10 09:09:55.903568411 +0200 +diff -Nur openssh-10.0p1.orig/cipher-switch.c openssh-10.0p1/cipher-switch.c +--- openssh-10.0p1.orig/cipher-switch.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/cipher-switch.c 2025-06-14 10:54:01.312566045 +0200 +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (c) 2023 The Board of Trustees of Carnegie Mellon University. ++ * ++ * Author: Chris Rapier ++ * ++ * This library is free software; you can redistribute it and/or modify it ++ * under the terms of the MIT License. ++ * ++ * This library is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the MIT License for more details. ++ * ++ * You should have received a copy of the MIT License along with this library; ++ * if not, see http://opensource.org/licenses/MIT. ++ * ++ */ ++ ++/* This provides the function to switch from a serial to parallel ++ * cipher. This has been moved into it's own file in order to make it ++ * available to both the client and server without having to clutter ++ * up other files. ++ */ ++ ++#include "includes.h" ++#include ++#include ++#include "cipher.h" ++#include "log.h" ++#include "packet.h" ++ ++ ++/* if we are using a parallel cipher there can be issues in either ++ * a fork or sandbox. Essentially, if we switch too early the ++ * threads get lost and the application hangs. So what we do is ++ * test if either the send or receive context cipher name ++ * matches the known available parallel ciphers. If it does ++ * then we force a rekey which automatically loads the parallel ++ * cipher. */ ++ ++void ++cipher_switch(struct ssh *ssh) { ++#ifdef WITH_OPENSSL ++ /* get the send and receive context and extract the cipher name */ ++ const void *send_cc = ssh_packet_get_send_context(ssh); ++ const void *recv_cc = ssh_packet_get_receive_context(ssh); ++ const char *send = cipher_ctx_name(send_cc); ++ const char *recv = cipher_ctx_name(recv_cc); ++ ++ debug_f("Send: %s Recv: %s", send, recv); ++ ++ /* if the name of the cipher matches then we set the context ++ * to authenticated (it likely already is though) and then ++ * force the rekey. Either side can do this. One downside of ++ * this method is that both sides can request a rekey so you ++ * can end up duplicating work. This is annoying but the ++ * performance gains make it worthwhile. Also I ++ * use strstr here because strcmp would require a 6 part ++ * if statement */ ++ if (strstr(send, "ctr") || strstr(recv, "ctr")) { ++ debug("Serial to parallel AES-CTR cipher swap"); ++ /* cipher_reset_multithreaded(); */ ++ ssh_packet_set_authenticated(ssh); ++ packet_request_rekeying(); ++ } ++ /* do the same for multithreaded chacha20 but with strcmp */ ++ if ((strcmp(send, "chacha20-poly1305@openssh.com") == 0) || ++ (strcmp(recv, "chacha20-poly1305@openssh.com") == 0)) { ++ debug("Serial to parallel Chacha20-poly1305 cipher swap"); ++ ssh_packet_set_authenticated(ssh); ++ packet_request_rekeying(); ++ } ++#endif ++} +diff -Nur openssh-10.0p1.orig/cipher-switch.h openssh-10.0p1/cipher-switch.h +--- openssh-10.0p1.orig/cipher-switch.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/cipher-switch.h 2025-06-14 10:54:01.312822014 +0200 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (c) 2015 The Board of Trustees of Carnegie Mellon University. ++ * ++ * Author: Chris Rapier ++ * ++ * This library is free software; you can redistribute it and/or modify it ++ * under the terms of the MIT License. ++ * ++ * This library is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the MIT License for more details. ++ * ++ * You should have received a copy of the MIT License along with this library; ++ * if not, see http://opensource.org/licenses/MIT. ++ * ++ */ ++ ++void cipher_switch (struct ssh *); +diff -Nur openssh-10.0p1.orig/clientloop.c openssh-10.0p1/clientloop.c +--- openssh-10.0p1.orig/clientloop.c 2025-06-14 10:53:01.223339310 +0200 ++++ openssh-10.0p1/clientloop.c 2025-06-14 10:54:01.313407565 +0200 @@ -114,6 +114,7 @@ #include "msg.h" #include "ssherr.h" @@ -6923,7 +7908,7 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c #ifdef GSSAPI #include "ssh-gss.h" -@@ -169,6 +170,10 @@ +@@ -171,6 +172,10 @@ static void client_init_dispatch(struct ssh *ssh); int session_ident = -1; @@ -6934,25 +7919,24 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c /* Track escape per proto2 channel */ struct escape_filter_ctx { -@@ -196,6 +201,9 @@ +@@ -197,6 +202,8 @@ + static struct global_confirms global_confirms = TAILQ_HEAD_INITIALIZER(global_confirms); - void ssh_process_session2_setup(int, int, int, struct sshbuf *); -+ +void client_request_metrics(struct ssh *); + static void quit_message(const char *fmt, ...) __attribute__((__format__ (printf, 1, 2))); -@@ -1283,6 +1291,7 @@ +@@ -1453,6 +1460,7 @@ double start_time, total_time; - int r, len; + int channel_did_enqueue = 0, r; u_int64_t ibytes, obytes; + time_t previous_time; int conn_in_ready, conn_out_ready; + sigset_t bsigset, osigset; - debug("Entering interactive session."); -@@ -1323,6 +1332,7 @@ +@@ -1494,6 +1502,7 @@ client_repledge(); start_time = monotime_double(); @@ -6960,13 +7944,17 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c /* Initialize variables. */ last_was_cr = 1; -@@ -1368,9 +1378,17 @@ +@@ -1535,6 +1544,8 @@ } schedule_server_alive_check(); + if (options.metrics) + client_request_metrics(ssh); /* initial metrics polling */ + if (sigemptyset(&bsigset) == -1 || + sigaddset(&bsigset, SIGHUP) == -1 || +@@ -1545,6 +1556,12 @@ + /* Main loop of the client for the interactive session mode. */ while (!quit_pending) { + if (options.metrics) { @@ -6975,10 +7963,10 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c + previous_time = time(NULL); + } + } + channel_did_enqueue = 0; /* Process buffered packets sent by the server. */ - client_process_buffered_input_packets(ssh); -@@ -1459,6 +1477,10 @@ +@@ -1637,6 +1654,10 @@ } } } @@ -6989,38 +7977,7 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c free(pfd); /* Terminate the session. */ -@@ -1646,7 +1668,9 @@ - return NULL; - c = channel_new(ssh, "x11", - SSH_CHANNEL_X11_OPEN, sock, sock, -1, -- CHAN_TCP_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); -+ /* again is this really necessary for X11? */ -+ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, -+ CHAN_X11_PACKET_DEFAULT, 0, "x11", 1); - c->force_drain = 1; - return c; - } -@@ -1681,7 +1705,8 @@ - - c = channel_new(ssh, "authentication agent connection", - SSH_CHANNEL_OPEN, sock, sock, -1, -- CHAN_X11_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, -+ options.hpn_disabled ? CHAN_X11_WINDOW_DEFAULT : options.hpn_buffer_size, -+ CHAN_TCP_PACKET_DEFAULT, 0, - "authentication agent connection", 1); - c->force_drain = 1; - return c; -@@ -1708,7 +1733,8 @@ - debug("Tunnel forwarding using interface %s", ifname); - - c = channel_new(ssh, "tun", SSH_CHANNEL_OPENING, fd, fd, -1, -- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); -+ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, -+ CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); - c->datagram = 1; - - #if defined(SSH_TUN_FILTER) -@@ -2502,6 +2528,167 @@ +@@ -2648,6 +2669,167 @@ return 1; } @@ -7095,7 +8052,7 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c + kernel_version = binn_object_int32((void *)blob, "kernel_version"); + + /* create a string of the data from the binn object blob */ -+ metrics_read_binn_object((void *)blob, &metricsstring); ++ metrics_read_binn_object((void *)blob, metricsstring); + + /* have we printed the header? */ + if (metrics_hdr_remote_flag == 0) { @@ -7140,7 +8097,7 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c + metrics_write_binn_object(&local_tcp_info, metricsobj); + + /* create a string of the data from the binn object metricsobj */ -+ metrics_read_binn_object((void *)metricsobj, &metricsstring); ++ metrics_read_binn_object((void *)metricsobj, metricsstring); + + /* get the kernel version printing the header */ + kernel_version = binn_object_int32(metricsobj, "kernel_version"); @@ -7169,7 +8126,7 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c +void client_request_metrics(struct ssh *ssh) { + int r; + -+ debug("Asking server for TCP stack metrics"); ++ debug_f("Asking server for TCP stack metrics"); + /* create a pakcet of GLOBAL_REQUEST type */ + if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 || + /* define the type of GLOBAL_REQUEST message */ @@ -7188,19 +8145,7 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c static int client_input_global_request(int type, u_int32_t seq, struct ssh *ssh) { -@@ -2557,6 +2744,11 @@ - if ((c = channel_lookup(ssh, id)) == NULL) - fatal_f("channel %d: unknown channel", id); - -+ if (options.hpn_buffer_limit) { -+ debug("Limiting receive buffer size"); -+ c->hpn_buffer_limit = 1; -+ } -+ - ssh_packet_set_interactive(ssh, want_tty, - options.ip_qos_interactive, options.ip_qos_bulk); - -@@ -2627,6 +2819,43 @@ +@@ -2773,6 +2955,43 @@ len = sshbuf_len(cmd); if (len > 0) { @@ -7208,7 +8153,7 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c + * binaries installed. In that case we need to rewrite any + * scp commands to look for hpnscp instead. + */ -+ if (ssh->compat & SSH_HPNSSH) { ++ if (ssh->compat & SSH_HPNSSH_PREFIX) { + char *new_cmd; + new_cmd = malloc(len+4); + /* read the existing command into a temp buffer */ @@ -7221,9 +8166,9 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c + * haystack. If it's 0 then we can mess with it + */ + if (pos - new_cmd == 0) { -+ debug("Rewriting scp command for hpnscp."); ++ debug_f("Rewriting scp command for hpnscp."); + sprintf(new_cmd, "hpn%s", (const u_char*)sshbuf_ptr(cmd)); -+ debug("Command was: %s and is now %s", ++ debug_f("Command was: %s and is now %s", + (const u_char*)sshbuf_ptr(cmd), new_cmd); + /* free the existing sshbuf 'cmd' + * recreate it and then write our new_cmd into @@ -7244,20 +8189,19 @@ diff -Nur openssh-9.3p1.orig/clientloop.c openssh-9.3p1/clientloop.c if (len > 900) len = 900; if (want_subsystem) { -diff -Nur openssh-9.3p1.orig/compat.c openssh-9.3p1/compat.c ---- openssh-9.3p1.orig/compat.c 2024-07-10 09:07:09.766081951 +0200 -+++ openssh-9.3p1/compat.c 2024-07-10 09:09:55.904568414 +0200 -@@ -135,6 +135,29 @@ +diff -Nur openssh-10.0p1.orig/compat.c openssh-10.0p1/compat.c +--- openssh-10.0p1.orig/compat.c 2025-06-14 10:53:01.849953032 +0200 ++++ openssh-10.0p1/compat.c 2025-06-14 12:24:07.747714342 +0200 +@@ -135,6 +135,35 @@ ssh->compat = check[i].bugs; if (forbid_ssh_rsa) ssh->compat |= SSH_RH_RSASIGSHA; + /* Check to see if the remote side is OpenSSH and not HPN */ + /* TODO: See if we can work this into the new method for bug checks */ + if (strstr(version, "OpenSSH") != NULL) { -+ if (strstr(version, "hpn") == NULL) { -+ ssh->compat |= SSH_BUG_LARGEWINDOW; -+ debug("Remote is NOT HPN enabled"); -+ } else { ++ if (strstr(version, "hpn")) { ++ ssh->compat |= SSH_HPNSSH; ++ debug("Remote is HPN enabled"); + /* this checks to see if the remote + * version string indicates that we + * have access to hpn prefixed binaries @@ -7268,38 +8212,111 @@ diff -Nur openssh-9.3p1.orig/compat.c openssh-9.3p1/compat.c + */ + if ((strstr(version, "hpn16") != NULL) || + (strstr(version, "hpn17") != NULL) || -+ (strstr(version, "hpn18") != NULL)) -+ ssh->compat |= SSH_HPNSSH; -+ debug("Remote is HPN Enabled"); ++ (strstr(version, "hpn18") != NULL)) { ++ ssh->compat |= SSH_HPNSSH_PREFIX; ++ debug("Remote uses HPNSSH prefixes."); ++ } ++ } ++ /* if it's openssh and not hpn */ ++ else if ((strstr(version, "OpenSSH_8.9") != NULL) || ++ (strstr(version, "OpenSSH_9") != NULL)) { ++ ssh->compat |= SSH_RESTRICT_WINDOW; ++ debug("Restricting advertised window size."); + } + } + debug("ssh->compat is %u", ssh->compat); return; } } -diff -Nur openssh-9.3p1.orig/compat.h openssh-9.3p1/compat.h ---- openssh-9.3p1.orig/compat.h 2024-07-10 09:07:09.766081951 +0200 -+++ openssh-9.3p1/compat.h 2024-07-10 09:09:55.904568414 +0200 -@@ -51,12 +51,13 @@ +diff -Nur openssh-10.0p1.orig/compat.h openssh-10.0p1/compat.h +--- openssh-10.0p1.orig/compat.h 2025-06-14 10:53:01.850139160 +0200 ++++ openssh-10.0p1/compat.h 2025-06-14 12:25:55.470697341 +0200 +@@ -46,17 +46,18 @@ + /* #define unused 0x00010000 */ + /* #define unused 0x00020000 */ + /* #define unused 0x00040000 */ +-/* #define unused 0x00100000 */ ++#define SSH_HPNSSH 0x00100000 /* basically a notice that this is HPN aware */ + #define SSH_BUG_EXTEOF 0x00200000 #define SSH_BUG_PROBE 0x00400000 - /* #define unused 0x00800000 */ +-/* #define unused 0x00800000 */ ++#define SSH_RESTRICT_WINDOW 0x00800000 /* restrict advertised window to OpenSSH clients */ #define SSH_OLD_FORWARD_ADDR 0x01000000 -/* #define unused 0x02000000 */ -+#define SSH_HPNSSH 0x02000000 /* indicates that we have hpn prefixes binaries */ ++#define SSH_HPNSSH_PREFIX 0x02000000 /* indicates that we have hpn prefixes binaries */ #define SSH_NEW_OPENSSH 0x04000000 #define SSH_BUG_DYNAMIC_RPORT 0x08000000 #define SSH_BUG_CURVE25519PAD 0x10000000 #define SSH_BUG_HOSTKEYS 0x20000000 #define SSH_BUG_DHGEX_LARGE 0x40000000 -+#define SSH_BUG_LARGEWINDOW 0x80000000 /* basically a notice that this is HPN aware */ ++/* #define unused 0x80000000 */ struct ssh; -diff -Nur openssh-9.3p1.orig/configure.ac openssh-9.3p1/configure.ac ---- openssh-9.3p1.orig/configure.ac 2024-07-10 09:07:09.804082062 +0200 -+++ openssh-9.3p1/configure.ac 2024-07-10 09:09:55.905568417 +0200 -@@ -3056,6 +3056,30 @@ - EVP_chacha20 \ +diff -Nur openssh-10.0p1.orig/configure.ac openssh-10.0p1/configure.ac +--- openssh-10.0p1.orig/configure.ac 2025-06-14 10:53:02.015907743 +0200 ++++ openssh-10.0p1/configure.ac 2025-06-14 10:54:01.316233073 +0200 +@@ -2621,6 +2621,39 @@ + ) + fi + ++ ++# Testing MPTCP Support ++# Does the OS support MPTCP? ++# We don't use this at the moment ++# but I am holding it in resrve -cjr 04/04/2025 ++ AC_MSG_CHECKING([whether the OS supports MPTCP]) ++ AC_RUN_IFELSE( ++ [AC_LANG_PROGRAM([[ ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ #include ++ ++ ]], [[ ++ int sock = -1; ++ sock = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP); ++ if (sock < 0) { ++ exit(1); ++ } ++ ]])], ++ [ ++ AC_MSG_RESULT([yes]) ++ AC_DEFINE([HAVE_MPTCP], [1], ++ [OS Supports MPTCP]) ++ ], ++ [ ++ AC_MSG_RESULT([no]) ++ ] ++ ) ++ + if test "x$ac_cv_func_getaddrinfo" = "xyes" && \ + test "x$check_for_hpux_broken_getaddrinfo" = "x1"; then + AC_MSG_CHECKING([if getaddrinfo seems to work]) +@@ -3029,8 +3062,8 @@ + 200*) # LibreSSL + lver=`echo "$sslver" | sed 's/.*libressl-//'` + case "$lver" in +- 2*|300*) # 2.x, 3.0.0 +- AC_MSG_ERROR([LibreSSL >= 3.1.0 required (have "$ssl_showver")]) ++ 2*|300*|301*|302*|303*|304*|306*) # 2.x, 3.0.0 ++ AC_MSG_ERROR([LibreSSL >= 3.7.0 required (have "$ssl_showver")]) + ;; + *) ;; # Assume all other versions are good. + esac +@@ -3039,6 +3072,7 @@ + # OpenSSL 3; we use the 1.1x API + # https://openssl.org/policies/general/versioning-policy.html + CPPFLAGS="$CPPFLAGS -DOPENSSL_API_COMPAT=0x10100000L" ++ AC_DEFINE([WITH_OPENSSL3], [1], [With OpenSSL3]) + ;; + *) + AC_MSG_ERROR([Unknown/unsupported OpenSSL version ("$ssl_showver")]) +@@ -3158,6 +3192,29 @@ + EVP_CIPHER_CTX_set_iv \ ]) + # OpenSSL 3.0 API @@ -7324,26 +8341,42 @@ diff -Nur openssh-9.3p1.orig/configure.ac openssh-9.3p1/configure.ac + AC_MSG_RESULT([no]) + ] + ) -+ + if test "x$openssl_engine" = "xyes" ; then AC_MSG_CHECKING([for OpenSSL ENGINE support]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ -diff -Nur openssh-9.3p1.orig/defines.h openssh-9.3p1/defines.h ---- openssh-9.3p1.orig/defines.h 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/defines.h 2024-07-10 09:09:55.906568420 +0200 -@@ -889,7 +889,7 @@ +diff -Nur openssh-10.0p1.orig/defines.h openssh-10.0p1/defines.h +--- openssh-10.0p1.orig/defines.h 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/defines.h 2025-06-14 10:54:01.317208898 +0200 +@@ -931,7 +931,11 @@ #endif #ifndef SSH_IOBUFSZ -# define SSH_IOBUFSZ 8192 -+# define SSH_IOBUFSZ 32*1024 ++# define SSH_IOBUFSZ (32*1024) ++#endif ++ ++#ifndef IPPROTO_MPTCP ++#define IPPROTO_MPTCP 262 #endif /* -diff -Nur openssh-9.3p1.orig/digest.h openssh-9.3p1/digest.h ---- openssh-9.3p1.orig/digest.h 2024-07-10 09:07:09.704081770 +0200 -+++ openssh-9.3p1/digest.h 2024-07-10 09:09:55.906568420 +0200 +@@ -987,3 +991,12 @@ + # define USE_MLKEM768X25519 1 + #endif + #endif /* _DEFINES_H */ ++ ++/* used to enable checking linux kernel versions */ ++#if defined(__linux__) && !defined(__alpine__) ++#include ++#endif ++ ++#ifndef KERNEL_VERSION /* shouldn't be necessary to define this */ ++#define KERNEL_VERSION(a,b,c) (((a) <<16) + ((b) << 8) +(c)) ++#endif +diff -Nur openssh-10.0p1.orig/digest.h openssh-10.0p1/digest.h +--- openssh-10.0p1.orig/digest.h 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/digest.h 2025-06-14 10:54:01.317584436 +0200 @@ -27,7 +27,8 @@ #define SSH_DIGEST_SHA256 2 #define SSH_DIGEST_SHA384 3 @@ -7354,9 +8387,9 @@ diff -Nur openssh-9.3p1.orig/digest.h openssh-9.3p1/digest.h struct sshbuf; struct ssh_digest_ctx; -diff -Nur openssh-9.3p1.orig/digest-openssl.c openssh-9.3p1/digest-openssl.c ---- openssh-9.3p1.orig/digest-openssl.c 2024-07-10 09:07:09.704081770 +0200 -+++ openssh-9.3p1/digest-openssl.c 2024-07-10 09:09:55.907568423 +0200 +diff -Nur openssh-10.0p1.orig/digest-openssl.c openssh-10.0p1/digest-openssl.c +--- openssh-10.0p1.orig/digest-openssl.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/digest-openssl.c 2025-06-14 10:54:01.317859402 +0200 @@ -61,6 +61,7 @@ { SSH_DIGEST_SHA256, "SHA256", 32, EVP_sha256 }, { SSH_DIGEST_SHA384, "SHA384", 48, EVP_sha384 }, @@ -7365,9 +8398,9 @@ diff -Nur openssh-9.3p1.orig/digest-openssl.c openssh-9.3p1/digest-openssl.c { -1, NULL, 0, NULL }, }; -diff -Nur openssh-9.3p1.orig/FUNDING.yml openssh-9.3p1/FUNDING.yml ---- openssh-9.3p1.orig/FUNDING.yml 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/FUNDING.yml 2024-07-10 09:09:55.907568423 +0200 +diff -Nur openssh-10.0p1.orig/FUNDING.yml openssh-10.0p1/FUNDING.yml +--- openssh-10.0p1.orig/FUNDING.yml 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/FUNDING.yml 2025-06-14 10:54:01.318133600 +0200 @@ -0,0 +1,12 @@ +# These are supported funding model platforms + @@ -7381,16 +8414,26 @@ diff -Nur openssh-9.3p1.orig/FUNDING.yml openssh-9.3p1/FUNDING.yml +#issuehunt: # Replace with a single IssueHunt username +#otechie: # Replace with a single Otechie username +#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] -diff -Nur openssh-9.3p1.orig/HPN-README openssh-9.3p1/HPN-README ---- openssh-9.3p1.orig/HPN-README 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/HPN-README 2024-07-10 09:09:55.907568423 +0200 -@@ -0,0 +1,230 @@ +diff -Nur openssh-10.0p1.orig/HPN-README openssh-10.0p1/HPN-README +--- openssh-10.0p1.orig/HPN-README 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/HPN-README 2025-06-14 10:54:01.318366032 +0200 +@@ -0,0 +1,180 @@ +Notes: + ++MPTCP Support in 18.7.0: ++Multipath TCP is now available as a runtime option for HPN-SSH. MPTCP ++is available only on Linux and Mac OSX operating systems. Using MPTCP on a system that ++doesn't support it will result in a notice and failure. The use cases for MPTCP include ++seamless handovers when changing networks and aggregating multiple interfaces to improve ++available bandwidth. As of 18.7.0 this options should be considered somewhat experimental. ++ ++Usage: ++-oUseMPTCP=[Yes|No] will enable MPTCP. The default is no. ++ +LibreSSL Support: -+Changes in LibreSSL version 3.5 and 3.6 prevent the use of the threaded AES CTR cipher. -+In those cases HPNSSH will fallback to the serial versionof the AES CTR cipher. A warning -+is printed to stderr. ++Changes in LibreSSL version 3.5 and 3.6 prevent the use of the threaded AES CTR cipher. ++In those cases HPNSSH will fallback to the serial version of the AES CTR cipher. A warning ++is printed to stderr. + +Automatic Port Fallback (in version 17v3) +The hpnssh client now uses TCP port 2222 to connect automatically as this is the @@ -7438,16 +8481,16 @@ diff -Nur openssh-9.3p1.orig/HPN-README openssh-9.3p1/HPN-README +This will likely result in less clear results and, as such, we suggest only gathering metrics +from non-multiplexed session. + -+SCP with Resume functionality -+This feature allows SCP to resume failed transfers. In the event of a failed transfer ++HPNSCP with Resume functionality ++This feature allows hpnscp to resume failed transfers. In the event of a failed transfer +issues the same scp command with the '-R' option. For example - if you issued: -+'scp myhugefile me@host:~' ++'hpnscp myhugefile me@host:~' +and it dies halfway through the transfer issuing -+'scp -Z myhugefile me@host:~' ++'hpnscp -Z myhugefile me@host:~' +will resume the transfer at the point where it left off. + +This is implemented by having the source host send a hash (blake2b512) of the file to the -+target host. Teh target host then computes it's own hash of the target file. If the hashes match ++target host. The target host then computes it's own hash of the target file. If the hashes match +then the file is skipped as this indicates a successful transfer. However, if the hashes do not +match then the target sends the source its hash along with the size of the file. The source then +computes the hash of the file *up to* the size of the target file. If those hashes match then @@ -7455,13 +8498,8 @@ diff -Nur openssh-9.3p1.orig/HPN-README openssh-9.3p1/HPN-README +the entire file is resent. If the target file is larger then the source file then the entire +source file is sent and any existing target file is overwritten. + -+SCP however, will use the first scp in the user's path. This might not support the resume -+function and the attempt will fail. In those cases the user can explicitly define the path to the -+resume enabled scp with the '-z' option. For example: + -+'scp -Z -z /opt/hpnssh/usr/bin/scp myhugefile me@host:~' -+ -+MULTI-THREADED CIPHER: ++MULTI-THREADED AES CIPHER: +The AES cipher in CTR mode has been multithreaded (MTR-AES-CTR). This will allow ssh installations +on hosts with multiple cores to use more than one processing core during encryption. +Tests have show significant throughput performance increases when using MTR-AES-CTR up @@ -7472,10 +8510,22 @@ diff -Nur openssh-9.3p1.orig/HPN-README openssh-9.3p1/HPN-README +performance requires the MTR-AES-CTR mode be enabled on both ends of the connection. +The MTR-AES-CTR replaces ST-AES-CTR and is used in exactly the same way with the same +nomenclature. -+Use examples: ++Usage examples: + ssh -caes128-ctr you@host.com + scp -oCipher=aes256-ctr file you@host.com:~/file + ++MULTI-THREADED ChaCha20-Poly1305 CIPHER: ++The default cipher used by HPN-SSH is now a threaded implementation of the ++ChaCha20-Poly1305 cipher. In tests this cipher results in an approximately 90% gain in ++throughput performance in comparison to the serial implementation found in OpenSSH. ++This cipher is fully compatible with all known existing implementations of ChaCha20-Poly1305. ++ ++Internally this cipher is referred to as chacha20-poly1305-mt@hpnssh.org (CC20-MT) ++similar to how the OpenSSH implementation is known as chacha20-poly1305@openssh.com ++(CC20-S (for serial)). No changes are required on the part of the user to make use of CC20-MT. ++However, if the users doesn't want to make use of this cipher they can explicitly load CC20-S using ++'-cchach20-poly1305@openssh.com` on the command line. ++ +NONE CIPHER: +To use the NONE option you must have the NoneEnabled switch set on the server and +you *must* have *both* NoneEnabled and NoneSwitch set to yes on the client. The NONE @@ -7499,63 +8549,8 @@ diff -Nur openssh-9.3p1.orig/HPN-README openssh-9.3p1/HPN-README + +ex: scp -oNoneSwitch=yes -oNoneEnabled=yes -oNoneMacEnabled=yes file host:~ + -+BUFFER SIZES: -+ -+If HPN is disabled the receive buffer size will be set to the -+OpenSSH default of 2MB (for OpenSSH versions before 4.7: 64KB). -+ -+If an HPN system connects to a nonHPN system the receive buffer will -+be set to the HPNBufferSize value. The default is 2MB but user adjustable. -+ -+If an HPN to HPN connection is established a number of different things might -+happen based on the user options and conditions. -+ -+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set -+HPN Buffer Size = up to 64MB -+This is the default state. The HPN buffer size will grow to a maximum of 64MB -+as the TCP receive buffer grows. The maximum HPN Buffer size of 64MB is -+geared towards 10GigE transcontinental connections. -+ -+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set -+HPN Buffer Size = TCP receive buffer value. -+Users on non-autotuning systems should disable TCPRcvBufPoll in the -+ssh_config and sshd_config -+ -+Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf NOT Set -+HPN Buffer Size = minimum of TCP receive buffer and HPNBufferSize. -+This would be the system defined TCP receive buffer (RWIN). -+ -+Conditions: HPNBufferSize SET, TCPRcvBufPoll disabled, TCPRcvBuf SET -+HPN Buffer Size = minimum of TCPRcvBuf and HPNBufferSize. -+Generally there is no need to set both. -+ -+Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf NOT Set -+HPN Buffer Size = grows to HPNBufferSize -+The buffer will grow up to the maximum size specified here. -+ -+Conditions: HPNBufferSize SET, TCPRcvBufPoll enabled, TCPRcvBuf SET -+HPN Buffer Size = minimum of TCPRcvBuf and HPNBufferSize. -+Generally there is no need to set both of these, especially on autotuning -+systems. However, if the users wishes to override the autotuning this would be -+one way to do it. -+ -+Conditions: HPNBufferSize NOT Set, TCPRcvBufPoll enabled, TCPRcvBuf SET -+HPN Buffer Size = TCPRcvBuf. -+This will override autotuning and set the TCP recieve buffer to the user defined -+value. -+ -+ +HPN Specific Configuration options + -+TcpRcvBuf=[int]KB client -+ Set the TCP socket receive buffer to n Kilobytes. It can be set up to the -+maximum socket size allowed by the system. This is useful in situations where -+the tcp receive window is set low but the maximum buffer size is set -+higher (as is typical). This works on a per TCP connection basis. You can also -+use this to artifically limit the transfer rate of the connection. In these -+cases the throughput will be no more than n/RTT. The minimum buffer size is 1KB. -+Default is the current system wide tcp receive buffer size. -+ +TcpRcvBufPoll=[yes/no] client/server + Enable of disable the polling of the tcp receive buffer through the life +of the connection. You would want to make sure that this option is enabled @@ -7589,21 +8584,6 @@ diff -Nur openssh-9.3p1.orig/HPN-README openssh-9.3p1/HPN-README +of the HPN code produces a net decrease in performance. In these cases it is +helpful to disable the HPN functionality. By default HPNDisabled is set to no. + -+HPNBufferSize=[int]KB client/server -+ This is the default buffer size the HPN functionality uses when interacting -+with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf -+option as applied to the internal SSH flow control. This value can range from -+1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance -+problems depending on the length of the network path. The default size of this buffer -+is 2MB. -+ -+DisableMTAES=[yes/no] client/server -+ Switch the encryption cipher being used from the multithreaded MT-AES-CTR cipher -+back to the stock single-threaded AES-CTR cipher. Useful on modern processors with -+AES-NI instructions which make the stock single-threaded AES-CTR cipher faster than -+the multithreaded MT-AES-CTR cipher. Set to no by default. -+ -+ +Credits: This patch was conceived, designed, and led by Chris Rapier (rapier@psc.edu) + The majority of the actual coding for versions up to HPN12v1 was performed + by Michael Stevens (mstevens@andrew.cmu.edu). The MT-AES-CTR cipher was @@ -7615,36 +8595,39 @@ diff -Nur openssh-9.3p1.orig/HPN-README openssh-9.3p1/HPN-README + +Sponsors: Thanks to Niklas Hambuchen for being the first sponsor of HPN-SSH + via github's sponsor program! -diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstallation.txt ---- openssh-9.3p1.orig/HPNSSHInstallation.txt 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/HPNSSHInstallation.txt 2024-07-10 09:09:55.908568426 +0200 -@@ -0,0 +1,350 @@ ++ ++ ++Edited: October 11, 2023 +diff -Nur openssh-10.0p1.orig/HPNSSHInstallation.txt openssh-10.0p1/HPNSSHInstallation.txt +--- openssh-10.0p1.orig/HPNSSHInstallation.txt 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/HPNSSHInstallation.txt 2025-06-14 10:54:01.318659925 +0200 +@@ -0,0 +1,354 @@ +HPN-SSH Installation + +The process of installing HPN-SSH from source is a relatively painless process -+but does have some nuances. This document will go through the process step by -+step to help you get the most from your installation. If you find any errors ++but does have some nuances. This document will go through the process step by ++step to help you get the most from your installation. If you find any errors +please contact us at hpnssh@psc.edu. + + +Step 1: Get the source code. + -+The official repository for HPN-SSH is found at -+https://github.com/rapier1/openssh-portable. Get a copy with -+"git clone https://github.com/rapier1/openssh-portable”. ++The official repository for HPN-SSH is found at ++https://github.com/rapier1/hpn-ssh. Get a copy with ++"git clone https://github.com/rapier1/hpn-ssh”. + + -+Step 2: Install dependencies. ++Step 2: Install dependencies. + +What you need to install is dependent on your distribution but will include: +* OpenSSL development package + * Debian: libssl-dev + * Fedora: openssl-devel +* Alternatively you can use LIbreSSL -+ * However, in this case we suggest compiling and installing libressl manually as -+ there are few maintained linux packages for LibreSSL. -+ * Also, LibreSSL v3.5 and v3.6 do not support the threaded AES-CTR cipher. -+ If that’s important to you then you should use OpenSSL. ++ * However, in this case we suggest compiling and installing libressl manually as ++ there are few maintained linux packages for LibreSSL. ++ * Also, LibreSSL v3.5 and v3.6 do not support the threaded AES-CTR cipher. ++ If that’s important to you then you should use OpenSSL. +* Z compression library + * Debian: zlib1g-dev + * Fedora: zlib-devel @@ -7652,10 +8635,10 @@ diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstalla +* Automake + + -+Step 3: Install optional dependencies. ++Step 3: Install optional dependencies. + -+This optional libraries will extend the functionality of HPN-SSH to allow the use of PAM -+authentication, Kerberos, graphical password tools, etc. ++This optional libraries will extend the functionality of HPN-SSH to allow the use of PAM ++authentication, Kerberos, graphical password tools, etc. +* PAM +* Kerberos +* GTK @@ -7668,35 +8651,22 @@ diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstalla + +Step 5: Configuration + -+Configure the installation. You can get detailed information on how to do this by -+issuing “./configure --help”. However, commonly you will want to change the default installation -+location of the binaries. This can be done with “--prefix=/[desired_path]”. For example, -+if you want the binaries installed into /usr/bin as opposed to the default of -+/usr/local/bin you’d use “./configure --prefix=/usr”. Other common options would be to -+incorporate pam, kerberos, alternative SSL libraries, and so forth. However, for most users -+either no additional configuration options or modifying the prefix will suffice. ++Configure the installation. You can get detailed information on how to do this by ++issuing “./configure --help”. However, commonly you will want to change the default installation ++location of the binaries. This can be done with “--prefix=/[desired_path]”. For example, ++if you want the binaries installed into /usr/bin as opposed to the default of ++/usr/local/bin you’d use “./configure --prefix=/usr”. Other common options would be to ++incorporate pam, kerberos, alternative SSL libraries, and so forth. However, for most users ++either no additional configuration options or modifying the prefix will suffice. + + +Step 6: Make + -+Make the application with “make -j[num cores]”. So if you have an 8 core system ++Make the application with “make -j[num cores]”. So if you have an 8 core system +you’d use “make -j8” + + -+Step 7: Installation -+ -+After HPN-SSH successfully builds, install it with “sudo make install”. This will install the -+binaries, configuration files, and generate the unique host keys used. At this point you can -+make changes to the ssh client and server default configuration. These files are -+found, generally, in /etc/hpnssh/ssh_config and sshd_config respectively. You may want to -+change the default port from 2222 to some other value. You may also want to enable the -+NoneCipher and NoneMac options. For more information use “man hpnsshd_config” and -+“man hpnssh_config”. Note: The hpnssh client expects the server to be on port 2222 but will -+fallback to 22 if it’s not found there. So if you do change the default port you’ll need to -+make sure the clients point at the correct port. -+ -+ -+Step 8: Set up the hpnsshd user. ++Step 7: Set up the hpnsshd user. + +This user is part of the privilege separation routines used in the +pre-authentication sandbox. I suggest using the following command: @@ -7707,20 +8677,32 @@ diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstalla +Alternatively, you can use vipw to add the user manually. + + ++Step 8: Installation ++ ++After HPN-SSH successfully builds, install it with “sudo make install”. This will install the ++binaries, configuration files, and generate the unique host keys used. At this point you can ++make changes to the ssh client and server default configuration. These files are ++found, generally, in /etc/hpnssh/ssh_config and sshd_config respectively. You may want to ++change the default port from 2222 to some other value. You may also want to enable the ++NoneCipher and NoneMac options. For more information use “man hpnsshd_config” and ++“man hpnssh_config”. Note: The hpnssh client expects the server to be on port 2222 but will ++fallback to 22 if it’s not found there. So if you do change the default port you’ll need to ++make sure the clients point at the correct port. ++ +Step 9: Finishing up. + -+At this point you can start hpnsshd manually by running “sudo /usr/sbin/hpnsshd” -+or whatever the full path to the hpnsshd binary might be. However, this won’t -+restart automatically on reboot. To do this you’ll need to install an appropriate -+systemd configuration file. If that seems like a good idea to you then following steps may be ++At this point you can start hpnsshd manually by running “sudo /usr/sbin/hpnsshd” ++or whatever the full path to the hpnsshd binary might be. However, this won’t ++restart automatically on reboot. To do this you’ll need to install an appropriate ++systemd configuration file. If that seems like a good idea to you then following steps may be +of help. Otherwise, you are done. Enjoy! + + -+Step 10: Installing a systemd startup file. ++Step 10: Installing a systemd startup file. + -+The correct systemd startup file depends on the distribution you are using. For system -+using systemd (you start a service with systemctl) create a file at /lib/systemd/system/hpnssh.service -+with the following contents NB: you may need to update the paths to match your installation: ++The correct systemd startup file depends on the distribution you are using. For system ++using systemd (you start a service with systemctl) create a file at /lib/systemd/system/hpnsshd.service ++with the following contents NB: you may need to update the paths to match your installation: + +[Unit] +Description=HPN/OpenBSD Secure Shell server @@ -7745,22 +8727,28 @@ diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstalla +WantedBy=multi-user.target +Alias=hpnsshd.service + ++Alternatively, the ./configure command will generate a hpnsshd.service file from ++hpnsshd.service.in. You can use this file by copying it to ++/libsystemd/system/hpnsshd.service instead of copying the above text. + -+Then create the defaults file at /etc/defaults/hpnssh with the following content: -+# Default settings for openssh-server. ++Then create the defaults file at /etc/default/hpnsshd with the following content: ++# Default settings for openssh-server. +# Options to pass to sshd -+SSHD_OPTS= ++SSHD_OPTS= + -+Enter any runtime options you want on the SSHD_OPTS line. If you can’t think of any, simply -+leave it blank. ++Enter any runtime options you want on the SSHD_OPTS line. If you can’t think of any, simply ++leave it blank. A sample /etc/defauls/hpnssh file may be found in defaults.hpnsshd. + -+You must then reload the systemd service to make it aware of this new service with ++You must then reload the systemd service to make it aware of this new service with +sudo systemctl daemon-reload + -+If you are using an init.d (you start a service with ‘system’) then you need to install an -+init.d. Create the file /etc/init.d/hpnssh and copy the following into it. NB: The following is -+for where hpnsshd is found at /usr/sbin/hpnsshd. If it is not in that location you’ll need to -+update the paths. ++If you are using an init.d (you start a service with ‘system’) then you need to install an ++init.d. Create the file /etc/init.d/hpnssh and copy the following into it. NB: The following is ++for where hpnsshd is found at /usr/sbin/hpnsshd. If it is not in that location you’ll need to ++update the paths. ++ ++Alternatively, you may use the hpnsshd.init file created during configure. This will be ++prepopulated with the correct paths by the configure script. + +#! /bin/sh + @@ -7769,7 +8757,7 @@ diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstalla +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 -+# Default-Stop: ++# Default-Stop: +# Short-Description: OpenBSD Secure Shell server with HPN +### END INIT INFO + @@ -7800,7 +8788,7 @@ diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstalla + +check_for_no_start() { + # forget it if we're trying to start, and /etc/hpnssh/sshd_not_to_be_run exists -+ if [ -e /etc/hpnssh/sshd_not_to_be_run ]; then ++ if [ -e /etc/hpnssh/sshd_not_to_be_run ]; then + if [ "$1" = log_end_msg ]; then + log_end_msg 0 || true + fi @@ -7936,29 +8924,29 @@ diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstalla +exit 0 + + -+Step 10: Working with SELinux. ++Step 10: Working with SELinux. + -+If you are using SELinux you’ll need to run a few more commands in order to grant hpnssh the -+necessary exceptions to open sockets, files, read keys, and so forth. Run the following commands -+to allow this. Note, I’m not sure every single one of these is needed so if someone knows better -+please let me know. Again, double check the paths of the files being updated. ++If you are using SELinux you’ll need to run a few more commands in order to grant hpnssh the ++necessary exceptions to open sockets, files, read keys, and so forth. Run the following commands ++to allow this. Note, I’m not sure every single one of these is needed so if someone knows better ++please let me know. Again, double check the paths of the files being updated. + -+semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_dsa_key ++semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_dsa_key +semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_rsa_key -+semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_ecdsa_key -+semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_ed25519_key -+semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_dsa_key.pub -+semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_rsa_key.pub -+semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_ecdsa_key.pub -+semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_ed25519_key.pub -+semanage fcontext -a -f f -t sshd_exec_t /usr/sbin/hpnsshd -+semanage fcontext -a -f f -t sshd_keygen_exec_t /usr/libexec/hpnssh/hpnsshd-keygen -+semanage fcontext -a -f f -t bin_t /usr/libexec/hpnssh/hpnsftp-server -+semanage fcontext -a -f f -t ssh_exec_t /usr/bin/hpnssh -+semanage fcontext -a -f f -t ssh_agent_exec_t /usr/bin/hpnssh-agent -+semanage fcontext -a -f f -t ssh_keygen_exec_t /usr/bin/hpnssh-keygen -+semanage fcontext -a -f f -t etc_t /etc/pam.d/hpnsshd -+semanage port -a -t ssh_port_t -p tcp 2222 ++semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_ecdsa_key ++semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_ed25519_key ++semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_dsa_key.pub ++semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_rsa_key.pub ++semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_ecdsa_key.pub ++semanage fcontext -a -f f -t sshd_key_t /etc/hpnssh/ssh_host_ed25519_key.pub ++semanage fcontext -a -f f -t sshd_exec_t /usr/sbin/hpnsshd ++semanage fcontext -a -f f -t sshd_keygen_exec_t /usr/libexec/hpnssh/hpnsshd-keygen ++semanage fcontext -a -f f -t bin_t /usr/libexec/hpnssh/hpnsftp-server ++semanage fcontext -a -f f -t ssh_exec_t /usr/bin/hpnssh ++semanage fcontext -a -f f -t ssh_agent_exec_t /usr/bin/hpnssh-agent ++semanage fcontext -a -f f -t ssh_keygen_exec_t /usr/bin/hpnssh-keygen ++semanage fcontext -a -f f -t etc_t /etc/pam.d/hpnsshd ++semanage port -a -t ssh_port_t -p tcp 2222 +restorecon /usr/sbin/hpnsshd +restorecon /etc/hpnssh/ssh*_key +restorecon /etc/hpnssh/ssh*_key\.pub @@ -7968,11 +8956,10 @@ diff -Nur openssh-9.3p1.orig/HPNSSHInstallation.txt openssh-9.3p1/HPNSSHInstalla +restorecon /usr/bin/hpnssh-agent +restorecon /usr/bin/hpnssh-keygen +restorecon /etc/pam.d/hpnsshd -+ -diff -Nur openssh-9.3p1.orig/kex.c openssh-9.3p1/kex.c ---- openssh-9.3p1.orig/kex.c 2024-07-10 09:07:09.780081992 +0200 -+++ openssh-9.3p1/kex.c 2024-07-10 09:44:57.239722141 +0200 -@@ -65,6 +65,7 @@ +diff -Nur openssh-10.0p1.orig/kex.c openssh-10.0p1/kex.c +--- openssh-10.0p1.orig/kex.c 2025-06-14 10:53:01.833082539 +0200 ++++ openssh-10.0p1/kex.c 2025-06-14 10:54:01.319010460 +0200 +@@ -67,6 +67,7 @@ #include "ssherr.h" #include "sshbuf.h" @@ -7980,7 +8967,94 @@ diff -Nur openssh-9.3p1.orig/kex.c openssh-9.3p1/kex.c #include "digest.h" #include "xmalloc.h" #include "audit.h" -@@ -1079,6 +1080,11 @@ +@@ -775,17 +776,83 @@ + free(kex); + } + ++/* ++ * This function seeks through a comma-separated list and checks for instances ++ * of the multithreaded CC20 cipher. If found, it then ensures that the serial ++ * CC20 cipher is also in the list, adding it if necessary. ++ */ ++char * ++patch_list(char * orig) ++{ ++ char * adj = xstrdup(orig); ++ char * match; ++ u_int next; ++ ++ const char * ccpstr = "chacha20-poly1305@openssh.com"; ++ const char * ccpmtstr = "chacha20-poly1305-mt@hpnssh.org"; ++ ++ match = match_list(ccpmtstr, orig, &next); ++ if (match != NULL) { /* CC20-MT found in the list */ ++ free(match); ++ match = match_list(ccpstr, orig, NULL); ++ if (match == NULL) { /* CC20-Serial NOT found in the list */ ++ adj = xreallocarray(adj, ++ strlen(adj) /* original string length */ ++ + 1 /* for the original null-terminator */ ++ + strlen(ccpstr) /* make room for ccpstr */ ++ + 1 /* make room for the comma delimiter */ ++ , sizeof(char)); ++ /* ++ * adj[next] points to the character after the CC20-MT ++ * string. adj[next] might be ',' or '\0' at this point. ++ */ ++ adj[next] = ','; ++ /* adj + next + 1 is the character after that comma */ ++ memcpy(adj + next + 1, ccpstr, strlen(ccpstr)); ++ /* rewrite the rest of the original list */ ++ memcpy(adj + next + 1 + strlen(ccpstr), orig + next, ++ strlen(orig + next) + 1); ++ } else { /* CC20-Serial found in the list, nothing to do */ ++ free(match); ++ } ++ } ++ ++ return adj; ++} ++ + int + kex_ready(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) + { +- int r; ++ int r = 0; ++ ++#ifdef WITH_OPENSSL ++ char * orig_ctos = proposal[PROPOSAL_ENC_ALGS_CTOS]; ++ char * orig_stoc = proposal[PROPOSAL_ENC_ALGS_STOC]; ++ proposal[PROPOSAL_ENC_ALGS_CTOS] = ++ patch_list(proposal[PROPOSAL_ENC_ALGS_CTOS]); ++ proposal[PROPOSAL_ENC_ALGS_STOC] = ++ patch_list(proposal[PROPOSAL_ENC_ALGS_STOC]); ++ ++ /* ++ * TODO: Likely memory leak here. The original contents of ++ * proposal[PROPOSAL_ENC_ALGS_CTOS] are no longer accessible or ++ * freeable. ++ */ ++#endif + + if ((r = kex_prop2buf(ssh->kex->my, proposal)) != 0) +- return r; ++ goto restoreProposal; + ssh->kex->flags = KEX_INITIAL; + kex_reset_dispatch(ssh); + ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); +- return 0; ++ restoreProposal: ++#ifdef WITH_OPENSSL ++ free(proposal[PROPOSAL_ENC_ALGS_CTOS]); ++ free(proposal[PROPOSAL_ENC_ALGS_STOC]); ++ proposal[PROPOSAL_ENC_ALGS_CTOS] = orig_ctos; ++ proposal[PROPOSAL_ENC_ALGS_STOC] = orig_stoc; ++#endif ++ return r; + } + + int +@@ -974,6 +1041,11 @@ int nenc, nmac, ncomp; u_int mode, ctos, need, dh_need, authlen; int r, first_kex_follows; @@ -7992,7 +9066,39 @@ diff -Nur openssh-9.3p1.orig/kex.c openssh-9.3p1/kex.c debug2("local %s KEXINIT proposal", kex->server ? "server" : "client"); if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0) -@@ -1169,11 +1175,40 @@ +@@ -1050,6 +1122,31 @@ + peer[nenc] = NULL; + goto out; + } ++#ifdef WITH_OPENSSL ++ if ((strcmp(newkeys->enc.name, "chacha20-poly1305@openssh.com") ++ == 0) && (match_list("chacha20-poly1305-mt@hpnssh.org", ++ my[nenc], NULL) != NULL)) { ++ /* ++ * if we're using the serial CC20 cipher while the ++ * multithreaded implementation is an option... ++ */ ++ free(newkeys->enc.name); ++ newkeys->enc.cipher = cipher_by_name( ++ "chacha20-poly1305-mt@hpnssh.org"); ++ if (newkeys->enc.cipher == NULL) { ++ error_f("%s cipher not found.", ++ "chacha20-poly1305-mt@hpnssh.org"); ++ r = SSH_ERR_INTERNAL_ERROR; ++ kex->failed_choice = peer[nenc]; ++ peer[nenc] = NULL; ++ goto out; ++ } else { ++ newkeys->enc.name = xstrdup( ++ "chacha20-poly1305-mt@hpnssh.org"); ++ } ++ /* we promote to the multithreaded implementation */ ++ } ++#endif + authlen = cipher_authlen(newkeys->enc.cipher); + /* ignore mac for authenticated encryption */ + if (authlen == 0 && +@@ -1065,11 +1162,43 @@ peer[ncomp] = NULL; goto out; } @@ -8005,8 +9111,11 @@ diff -Nur openssh-9.3p1.orig/kex.c openssh-9.3p1/kex.c + } + else + fatal("Pre-authentication none cipher requests are not allowed."); -+ if (newkeys->mac.name != NULL && strcmp(newkeys->mac.name, "none") == 0) ++ ++ if (newkeys->mac.name != NULL && strcmp(newkeys->mac.name, "none") == 0) { + debug("Requesting: NONEMAC. Authflag is %d", auth_flag); ++ ssh->none_mac = 1; ++ } + } + debug("kex: %s cipher: %s MAC: %s compression: %s", @@ -8033,33 +9142,66 @@ diff -Nur openssh-9.3p1.orig/kex.c openssh-9.3p1/kex.c } need = dh_need = 0; for (mode = 0; mode < MODE_MAX; mode++) { -@@ -1521,7 +1556,7 @@ +@@ -1429,7 +1558,7 @@ if (version_addendum != NULL && *version_addendum == '\0') version_addendum = NULL; - if ((r = sshbuf_putf(our_version, "SSH-%d.%d-%.100s%s%s\r\n", + if ((r = sshbuf_putf(our_version, "SSH-%d.%d-%s%s%s\r\n", - PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_VERSION, + PROTOCOL_MAJOR_2, PROTOCOL_MINOR_2, SSH_RELEASE, version_addendum == NULL ? "" : " ", version_addendum == NULL ? "" : version_addendum)) != 0) { oerrno = errno; -@@ -1657,6 +1692,14 @@ +@@ -1565,9 +1694,24 @@ r = SSH_ERR_INVALID_FORMAT; goto out; } + + /* report the version information to syslog if this is the server */ -+ if (timeout_ms == -1) { /* only the server uses this value */ ++ if (timeout_ms == -1) { /* only the server uses this value */ + logit("SSH: Server;Ltype: Version;Remote: %s-%d;Protocol: %d.%d;Client: %.100s", -+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), -+ remote_major, remote_minor, remote_version); ++ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), ++ remote_major, remote_minor, remote_version); + } + debug("Remote protocol version %d.%d, remote software version %.100s", remote_major, remote_minor, remote_version); compat_banner(ssh, remote_version); -diff -Nur openssh-9.3p1.orig/mac.c openssh-9.3p1/mac.c ---- openssh-9.3p1.orig/mac.c 2024-07-10 09:07:09.735081860 +0200 -+++ openssh-9.3p1/mac.c 2024-07-10 09:09:55.908568426 +0200 ++ if (ssh->compat & SSH_HPNSSH) ++ debug("HPN to HPN Connection."); ++ else ++ debug("Non-HPN to HPN Connection."); ++ ++ if(ssh->compat & SSH_RESTRICT_WINDOW) ++ debug ("Window size restricted."); + + mismatch = 0; + switch (remote_major) { +diff -Nur openssh-10.0p1.orig/log.c openssh-10.0p1/log.c +--- openssh-10.0p1.orig/log.c 2025-06-14 10:53:01.364646329 +0200 ++++ openssh-10.0p1/log.c 2025-06-14 10:54:01.319781160 +0200 +@@ -48,6 +48,10 @@ + #include + #include + #include ++#include "packet.h" /* needed for host and port look ups */ ++#ifdef HAVE_SYS_TIME_H ++# include /* to get current time */ ++#endif + #if defined(HAVE_STRNVIS) && defined(HAVE_VIS_H) && !defined(BROKEN_STRNVIS) + # include + #endif +@@ -67,6 +71,8 @@ + + extern char *__progname; + ++extern struct ssh *active_state; ++ + #define LOG_SYSLOG_VIS (VIS_CSTYLE|VIS_NL|VIS_TAB|VIS_OCTAL) + #define LOG_STDERR_VIS (VIS_SAFE|VIS_OCTAL) + +diff -Nur openssh-10.0p1.orig/mac.c openssh-10.0p1/mac.c +--- openssh-10.0p1.orig/mac.c 2025-06-14 10:53:01.717727014 +0200 ++++ openssh-10.0p1/mac.c 2025-06-14 10:54:01.320122336 +0200 @@ -63,6 +63,7 @@ { "hmac-sha2-512", SSH_DIGEST, SSH_DIGEST_SHA512, 0, 0, 0, 0 }, { "hmac-md5", SSH_DIGEST, SSH_DIGEST_MD5, 0, 0, 0, 0 }, @@ -8068,10 +9210,10 @@ diff -Nur openssh-9.3p1.orig/mac.c openssh-9.3p1/mac.c { "umac-64@openssh.com", SSH_UMAC, 0, 0, 128, 64, 0 }, { "umac-128@openssh.com", SSH_UMAC128, 0, 0, 128, 128, 0 }, -diff -Nur openssh-9.3p1.orig/Makefile.in openssh-9.3p1/Makefile.in ---- openssh-9.3p1.orig/Makefile.in 2024-07-10 09:07:09.806082068 +0200 -+++ openssh-9.3p1/Makefile.in 2024-07-10 09:09:55.909568429 +0200 -@@ -49,7 +49,7 @@ +diff -Nur openssh-10.0p1.orig/Makefile.in openssh-10.0p1/Makefile.in +--- openssh-10.0p1.orig/Makefile.in 2025-06-14 14:54:57.417594122 +0200 ++++ openssh-10.0p1/Makefile.in 2025-06-14 14:54:42.451734455 +0200 +@@ -53,7 +53,7 @@ CFLAGS_NOPIE=@CFLAGS_NOPIE@ CPPFLAGS=-I. -I$(srcdir) @CPPFLAGS@ $(PATHS) @DEFS@ PICFLAG=@PICFLAG@ @@ -8080,7 +9222,7 @@ diff -Nur openssh-9.3p1.orig/Makefile.in openssh-9.3p1/Makefile.in CHANNELLIBS=@CHANNELLIBS@ K5LIBS=@K5LIBS@ GSSLIBS=@GSSLIBS@ -@@ -97,7 +97,7 @@ +@@ -102,7 +102,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \ authfd.o authfile.o \ canohost.o channels.o cipher.o cipher-aes.o cipher-aesctr.o \ @@ -8089,8 +9231,16 @@ diff -Nur openssh-9.3p1.orig/Makefile.in openssh-9.3p1/Makefile.in compat.o fatal.o hostfile.o \ log.o match.o moduli.o nchan.o packet.o \ readpass.o ttymodes.o xmalloc.o addr.o addrmatch.o \ -@@ -114,7 +114,8 @@ - kexsntrup761x25519.o sntrup761.o kexgen.o \ +@@ -112,6 +112,7 @@ + msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \ + ssh-pkcs11.o ssh-pkcs11-uri.o smult_curve25519_ref.o \ + poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \ ++ cipher-chachapoly-libcrypto-mt.o \ + ssh-ed25519.o digest-openssl.o digest-libc.o \ + hmac.o ed25519.o hash.o \ + kex.o kex-names.o kexdh.o kexgex.o kexecdh.o kexc25519.o \ +@@ -119,12 +120,13 @@ + 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 auditstub.o @@ -8099,8 +9249,32 @@ diff -Nur openssh-9.3p1.orig/Makefile.in openssh-9.3p1/Makefile.in SKOBJS= ssh-sk-client.o -@@ -214,7 +215,7 @@ - $(LD) -o $@ $(SSHDOBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS) + SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \ +- sshconnect.o sshconnect2.o mux.o $(SKOBJS) ++ sshconnect.o sshconnect2.o mux.o cipher-switch.o $(SKOBJS) + + SSHDOBJS=sshd.o \ + platform-listen.o \ +@@ -143,7 +145,7 @@ + auth2-gss.o gss-serv.o gss-serv-krb5.o gss-serv-gsi.o \ + loginrec.o auth-pam.o auth-shadow.o auth-sia.o \ + sftp-server.o sftp-common.o \ +- uidswap.o platform-listen.o $(SKOBJS) ++ uidswap.o platform-listen.o cipher-switch.o $(SKOBJS) + + SSHD_AUTH_OBJS=sshd-auth.o \ + auth2-methods.o \ +@@ -158,7 +160,7 @@ + sandbox-null.o sandbox-rlimit.o sandbox-darwin.o \ + sandbox-seccomp-filter.o sandbox-capsicum.o sandbox-solaris.o \ + sftp-server.o sftp-common.o \ +- uidswap.o $(SKOBJS) ++ uidswap.o cipher-switch.o $(SKOBJS) + + SFTP_CLIENT_OBJS=sftp-common.o sftp-client.o sftp-glob.o + +@@ -243,7 +245,7 @@ + $(LD) -o $@ $(SSHD_AUTH_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(SSHDLIBS) $(LIBS) $(GSSLIBS) $(K5LIBS) $(CHANNELLIBS) $(LIBWTMPDB) scp$(EXEEXT): $(LIBCOMPAT) libssh.a $(SCP_OBJS) - $(LD) -o $@ $(SCP_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) @@ -8108,21 +9282,34 @@ diff -Nur openssh-9.3p1.orig/Makefile.in openssh-9.3p1/Makefile.in ssh-add$(EXEEXT): $(LIBCOMPAT) libssh.a $(SSHADD_OBJS) $(LD) -o $@ $(SSHADD_OBJS) $(LDFLAGS) -lssh -lopenbsd-compat $(LIBS) $(CHANNELLIBS) -diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c ---- openssh-9.3p1.orig/metrics.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/metrics.c 2024-07-10 09:09:55.909568429 +0200 -@@ -0,0 +1,426 @@ +diff -Nur openssh-10.0p1.orig/metrics.c openssh-10.0p1/metrics.c +--- openssh-10.0p1.orig/metrics.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/metrics.c 2025-06-14 10:54:01.321376410 +0200 +@@ -0,0 +1,439 @@ ++/* ++ * Copyright (c) 2022 The Board of Trustees of Carnegie Mellon University. ++ * ++ * Author: Chris Rapier ++ * ++ * This library is free software; you can redistribute it and/or modify it ++ * under the terms of the MIT License. ++ * ++ * This library is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the MIT License for more details. ++ * ++ * You should have received a copy of the MIT License along with this library; ++ * if not, see http://opensource.org/licenses/MIT. ++ * ++ */ ++ +#include "includes.h" +#include "metrics.h" +#include "ssherr.h" +#include -+#ifdef __linux__ -+#include -+#endif ++#include + -+#ifndef KERNEL_VERSION /* shouldn't be necessary to define this */ -+#define KERNEL_VERSION(a,b,c) (((a) <<16) + ((b) << 8) +(c)) -+#endif ++/* kernel version macro moved to defines.h */ + +/* add the information from the tcp_info struct to the + * serialized binary object @@ -8142,7 +9329,7 @@ diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c + * on non linux systems we set the kernel version to 0 + * which will get us the base set of metrics from netinet/tcp.h + */ -+#ifdef __linux__ ++#if (defined __linux__) && !defined(__alpine__) + binn_object_set_uint32(binnobj, "kernel_version", LINUX_VERSION_CODE); +#else + binn_object_set_uint32(binnobj, "kernel_version", 0); @@ -8349,7 +9536,7 @@ diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c + * the object will not necessarily have all of the elements. If it's empty it + * current just spits out 0. This isn't optimal as 0 can also be a valid value */ +void -+metrics_read_binn_object (void *binnobj, char **output) { ++metrics_read_binn_object (void *binnobj, char *output) { + int len = 0; + int buflen = 1023; + int kernel_version = 0; @@ -8360,7 +9547,7 @@ diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c + kernel_version = binn_object_uint32(binnobj, "kernel_version"); + + /* base set of metrics */ -+ len = snprintf(*output, buflen, "%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", ++ len = snprintf(output, buflen, "%d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", + binn_object_uint8(binnobj, "tcpi_state"), + binn_object_uint8(binnobj, "tcpi_ca_state"), + binn_object_uint8(binnobj, "tcpi_retransmits"), @@ -8401,28 +9588,28 @@ diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c + * the remote kernel version. Only necessary under linux*/ +#ifdef __linux__ + if (kernel_version >= KERNEL_VERSION(3,15,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %llu, %llu", ++ len += snprintf(output+len, (buflen-len), ", %llu, %llu", + binn_object_uint64(binnobj, "tcpi_max_pacing_rate"), + binn_object_uint64(binnobj, "tcpi_pacing_rate") + ); + } + + if (kernel_version >= KERNEL_VERSION(4,1,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %llu, %llu", ++ len += snprintf(output+len, (buflen-len), ", %llu, %llu", + binn_object_uint64(binnobj, "tcpi_bytes_acked"), + binn_object_uint64(binnobj, "tcpi_bytes_received") + ); + } + + if (kernel_version >= KERNEL_VERSION(4,2,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %d, %d", ++ len += snprintf(output+len, (buflen-len), ", %d, %d", + binn_object_uint32(binnobj, "tcpi_segs_in"), + binn_object_uint32(binnobj, "tcpi_segs_out") + ); + } + + if (kernel_version >= KERNEL_VERSION(4,6,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %d, %d, %d, %d", ++ len += snprintf(output+len, (buflen-len), ", %d, %d, %d, %d", + binn_object_uint32(binnobj, "tcpi_notsent_bytes"), + binn_object_uint32(binnobj, "tcpi_min_rtt"), + binn_object_uint32(binnobj, "tcpi_data_segs_in"), @@ -8431,14 +9618,14 @@ diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c + } + + if (kernel_version >= KERNEL_VERSION(4,9,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %d, %llu", ++ len += snprintf(output+len, (buflen-len), ", %d, %llu", + binn_object_uint8(binnobj, "tcpi_delivery_rate_app_limited"), + binn_object_uint64(binnobj, "tcpi_delivery_rate") + ); + } + + if (kernel_version >= KERNEL_VERSION(4,10,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %llu, %llu, %llu", ++ len += snprintf(output+len, (buflen-len), ", %llu, %llu, %llu", + binn_object_uint64(binnobj, "tcpi_busy_time"), + binn_object_uint64(binnobj, "tcpi_sndbuf_limited"), + binn_object_uint64(binnobj, "tcpi_rwnd_limited") @@ -8446,14 +9633,14 @@ diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c + } + + if (kernel_version >= KERNEL_VERSION(4,18,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %d, %d", ++ len += snprintf(output+len, (buflen-len), ", %d, %d", + binn_object_uint32(binnobj, "tcpi_delivered"), + binn_object_uint32(binnobj, "tcpi_delivered_ce") + ); + } + + if (kernel_version >= KERNEL_VERSION(4,19,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %llu, %llu, %d, %d", ++ len += snprintf(output+len, (buflen-len), ", %llu, %llu, %d, %d", + binn_object_uint64(binnobj, "tcpi_bytes_sent"), + binn_object_uint64(binnobj, "tcpi_bytes_retrans"), + binn_object_uint32(binnobj, "tcpi_dsack_dups"), @@ -8462,14 +9649,14 @@ diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c + } + + if (kernel_version >= KERNEL_VERSION(5,4,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %d, %d", ++ len += snprintf(output+len, (buflen-len), ", %d, %d", + binn_object_uint32(binnobj, "tcpi_snd_wnd"), + binn_object_uint32(binnobj, "tcpi_rcv_ooopack") + ); + } + + if (kernel_version >= KERNEL_VERSION(5,5,0)) { -+ len += snprintf(*output+len, (buflen-len), ", %d", ++ len += snprintf(output+len, (buflen-len), ", %d", + binn_object_uint8(binnobj, "tcpi_fastopen_client_fail") + ); + } @@ -8538,10 +9725,27 @@ diff -Nur openssh-9.3p1.orig/metrics.c openssh-9.3p1/metrics.c +#endif /* ifdef __linux__ */ + fprintf(fptr, "\n\n"); +} -diff -Nur openssh-9.3p1.orig/metrics.h openssh-9.3p1/metrics.h ---- openssh-9.3p1.orig/metrics.h 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/metrics.h 2024-07-10 09:09:55.909568429 +0200 -@@ -0,0 +1,28 @@ +diff -Nur openssh-10.0p1.orig/metrics.h openssh-10.0p1/metrics.h +--- openssh-10.0p1.orig/metrics.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/metrics.h 2025-06-14 10:54:01.321618830 +0200 +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 2022 The Board of Trustees of Carnegie Mellon University. ++ * ++ * Author: Chris Rapier ++ * ++ * This library is free software; you can redistribute it and/or modify it ++ * under the terms of the MIT License. ++ * ++ * This library is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the MIT License for more details. ++ * ++ * You should have received a copy of the MIT License along with this library; ++ * if not, see http://opensource.org/licenses/MIT. ++ * ++ */ ++ +#ifndef METRICS_H +#define METRICS_H + @@ -8550,9 +9754,9 @@ diff -Nur openssh-9.3p1.orig/metrics.h openssh-9.3p1/metrics.h +/* linux, freebsd, and netbsd have tcp_info structs. + * I don't know about other systems so we disable this + * functionality for them */ -+#if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ ++#if defined __linux__ || defined __FreeBSD__ || defined __NetBSD__ && !defined(__alpine__) +#define TCP_INFO 1 -+#if defined __linux__ ++#if defined __linux__ && !defined(__alpine__) +#include +#else +#include @@ -8565,15 +9769,15 @@ diff -Nur openssh-9.3p1.orig/metrics.h openssh-9.3p1/metrics.h +#endif + +void metrics_write_binn_object(struct tcp_info *, struct binn_struct *); -+void metrics_read_binn_object(void *, char **); ++void metrics_read_binn_object(void *, char *); +void metrics_print_header(FILE *, char *, int); + + +#endif /* define metrics_h */ -diff -Nur openssh-9.3p1.orig/misc.c openssh-9.3p1/misc.c ---- openssh-9.3p1.orig/misc.c 2024-07-10 09:07:09.806082068 +0200 -+++ openssh-9.3p1/misc.c 2024-07-10 09:09:55.910568431 +0200 -@@ -70,6 +70,29 @@ +diff -Nur openssh-10.0p1.orig/misc.c openssh-10.0p1/misc.c +--- openssh-10.0p1.orig/misc.c 2025-06-14 10:53:02.019076801 +0200 ++++ openssh-10.0p1/misc.c 2025-06-14 10:54:01.321922850 +0200 +@@ -77,6 +77,29 @@ #include "ssherr.h" #include "platform.h" @@ -8603,7 +9807,7 @@ diff -Nur openssh-9.3p1.orig/misc.c openssh-9.3p1/misc.c /* remove newline at end of string */ char * chop(char *s) -@@ -1606,20 +1629,6 @@ +@@ -1670,20 +1693,6 @@ return (v); } @@ -8624,7 +9828,7 @@ diff -Nur openssh-9.3p1.orig/misc.c openssh-9.3p1/misc.c u_int16_t get_u16(const void *vp) { -@@ -1659,17 +1668,6 @@ +@@ -1723,17 +1732,6 @@ } void @@ -8642,10 +9846,10 @@ diff -Nur openssh-9.3p1.orig/misc.c openssh-9.3p1/misc.c put_u16(void *vp, u_int16_t v) { u_char *p = (u_char *)vp; -diff -Nur openssh-9.3p1.orig/misc.h openssh-9.3p1/misc.h ---- openssh-9.3p1.orig/misc.h 2024-07-10 09:07:09.806082068 +0200 -+++ openssh-9.3p1/misc.h 2024-07-10 09:09:55.910568431 +0200 -@@ -155,12 +155,6 @@ +diff -Nur openssh-10.0p1.orig/misc.h openssh-10.0p1/misc.h +--- openssh-10.0p1.orig/misc.h 2025-06-14 10:53:02.019622613 +0200 ++++ openssh-10.0p1/misc.h 2025-06-14 10:54:01.322621684 +0200 +@@ -167,12 +167,6 @@ void put_u16(void *, u_int16_t) __attribute__((__bounded__( __minbytes__, 1, 2))); @@ -8658,7 +9862,7 @@ diff -Nur openssh-9.3p1.orig/misc.h openssh-9.3p1/misc.h struct bwlimit { size_t buflen; u_int64_t rate; /* desired rate in kbit/s */ -@@ -244,4 +238,16 @@ +@@ -259,4 +253,16 @@ /* On OpenBSD time_t is int64_t which is long long. */ /* #define SSH_TIME_T_MAX LLONG_MAX */ @@ -8675,17 +9879,27 @@ diff -Nur openssh-9.3p1.orig/misc.h openssh-9.3p1/misc.h +void read_mem_stats(struct statm_t *, int); + #endif /* _MISC_H */ -diff -Nur openssh-9.3p1.orig/num.c openssh-9.3p1/num.c ---- openssh-9.3p1.orig/num.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/num.c 2024-07-10 09:09:55.910568431 +0200 -@@ -0,0 +1,158 @@ +diff -Nur openssh-10.0p1.orig/myproposal.h openssh-10.0p1/myproposal.h +--- openssh-10.0p1.orig/myproposal.h 2025-06-14 10:53:01.775906378 +0200 ++++ openssh-10.0p1/myproposal.h 2025-06-14 10:54:01.323105546 +0200 +@@ -71,6 +71,7 @@ + "rsa-sha2-256" + + #define KEX_SERVER_ENCRYPT \ ++ "chacha20-poly1305-mt@hpnssh.org," \ + "chacha20-poly1305@openssh.com," \ + "aes128-gcm@openssh.com,aes256-gcm@openssh.com," \ + "aes128-ctr,aes192-ctr,aes256-ctr" +diff -Nur openssh-10.0p1.orig/num.c openssh-10.0p1/num.c +--- openssh-10.0p1.orig/num.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/num.c 2025-06-14 10:54:01.323584938 +0200 +@@ -0,0 +1,156 @@ +/* CC0 license applied, see LICENCE.md */ + +#include +#include "num.h" + -+#ifdef WITH_OPENSSL -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++#ifdef WITH_OPENSSL3 + +typedef enum { BIG = 1, LITTLE = -1 } endian_t; +typedef enum { NEGATIVE = 0xff, POSITIVE = 0x00 } sign_t; @@ -8835,17 +10049,15 @@ diff -Nur openssh-9.3p1.orig/num.c openssh-9.3p1/num.c + +implement_provnum(size_t, OSSL_PARAM_UNSIGNED_INTEGER) + -+#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000UL */ -+#endif /* WITH_OPENSSL */ -diff -Nur openssh-9.3p1.orig/num.h openssh-9.3p1/num.h ---- openssh-9.3p1.orig/num.h 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/num.h 2024-07-10 09:09:55.910568431 +0200 -@@ -0,0 +1,17 @@ ++#endif /* WITH_OPENSSL3 */ +diff -Nur openssh-10.0p1.orig/num.h openssh-10.0p1/num.h +--- openssh-10.0p1.orig/num.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/num.h 2025-06-14 10:54:01.323769040 +0200 +@@ -0,0 +1,15 @@ +/* CC0 license applied, see LICENCE.md */ + +#include "includes.h" -+#ifdef WITH_OPENSSL -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++#ifdef WITH_OPENSSL3 + +#include + @@ -8856,20 +10068,18 @@ diff -Nur openssh-9.3p1.orig/num.h openssh-9.3p1/num.h +#define PROVNUM_E_WRONG_TYPE -1 +#define PROVNUM_E_TOOBIG -2 +#define PROVNUM_E_UNSUPPORTED -3 -+#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000UL */ -+#endif /* WITH_OPENSSL */ -diff -Nur openssh-9.3p1.orig/ossl3-provider-err.c openssh-9.3p1/ossl3-provider-err.c ---- openssh-9.3p1.orig/ossl3-provider-err.c 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/ossl3-provider-err.c 2024-07-10 09:09:55.910568431 +0200 -@@ -0,0 +1,110 @@ ++#endif /* WITH_OPENSSL3 */ +diff -Nur openssh-10.0p1.orig/ossl3-provider-err.c openssh-10.0p1/ossl3-provider-err.c +--- openssh-10.0p1.orig/ossl3-provider-err.c 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/ossl3-provider-err.c 2025-06-14 10:54:01.323964806 +0200 +@@ -0,0 +1,108 @@ +/* CC0 license applied, see LICENCE.md */ + +#include +#include +#include "ossl3-provider-err.h" + -+#ifdef WITH_OPENSSL -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++#ifdef WITH_OPENSSL3 + +struct proverr_functions_st { + const OSSL_CORE_HANDLE *core; @@ -8970,17 +10180,15 @@ diff -Nur openssh-9.3p1.orig/ossl3-provider-err.c openssh-9.3p1/ossl3-provider-e + va_end(ap); +} + -+#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000UL */ -+#endif /* WITH_OPENSSL */ -diff -Nur openssh-9.3p1.orig/ossl3-provider-err.h openssh-9.3p1/ossl3-provider-err.h ---- openssh-9.3p1.orig/ossl3-provider-err.h 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/ossl3-provider-err.h 2024-07-10 09:09:55.911568435 +0200 -@@ -0,0 +1,75 @@ ++#endif /* WITH_OPENSSL3 */ +diff -Nur openssh-10.0p1.orig/ossl3-provider-err.h openssh-10.0p1/ossl3-provider-err.h +--- openssh-10.0p1.orig/ossl3-provider-err.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/ossl3-provider-err.h 2025-06-14 10:54:01.324153727 +0200 +@@ -0,0 +1,73 @@ +/* CC0 license applied, see LICENCE.md */ + +#include "includes.h" -+#ifdef WITH_OPENSSL -+#if OPENSSL_VERSION_NUMBER >= 0x30000000UL ++#ifdef WITH_OPENSSL3 +#include +#include +#include @@ -9049,11 +10257,10 @@ diff -Nur openssh-9.3p1.orig/ossl3-provider-err.h openssh-9.3p1/ossl3-provider-e + const char *file, int line, const char *func); +void proverr_set_error(const struct proverr_functions_st *handle, + uint32_t reason, const char *fmt, ...); -+#endif /* OPENSSL_VERSION_NUMBER >= 0x30000000UL */ -+#endif /* WITH_OPENSSL */ -diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c ---- openssh-9.3p1.orig/packet.c 2024-07-10 09:07:09.781081995 +0200 -+++ openssh-9.3p1/packet.c 2024-07-10 15:18:33.232847035 +0200 ++#endif /* WITH_OPENSSL3 */ +diff -Nur openssh-10.0p1.orig/packet.c openssh-10.0p1/packet.c +--- openssh-10.0p1.orig/packet.c 2025-06-14 10:53:01.719334626 +0200 ++++ openssh-10.0p1/packet.c 2025-06-14 10:54:01.324483728 +0200 @@ -63,6 +63,9 @@ #endif #include @@ -9086,16 +10293,20 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c struct packet_state { u_int32_t seqnr; -@@ -241,12 +257,19 @@ +@@ -241,12 +257,23 @@ (state->outgoing_packet = sshbuf_new()) == NULL || (state->incoming_packet = sshbuf_new()) == NULL) goto fail; + /* these buffers are important in terms of tracking buffer usage -+ * so we explicitly label them with descriptive names */ ++ * so we explicitly label and type them with descriptive names */ + sshbuf_relabel(state->input, "input"); ++ sshbuf_type(state->input, BUF_PACKET_INPUT); + sshbuf_relabel(state->incoming_packet, "inpacket"); ++ sshbuf_type(state->incoming_packet, BUF_PACKET_INCOMING); + sshbuf_relabel(state->output, "output"); ++ sshbuf_type(state->output, BUF_PACKET_OUTPUT); + sshbuf_relabel(state->outgoing_packet, "outpacket"); ++ sshbuf_type(state->outgoing_packet, BUF_PACKET_OUTGOING); + TAILQ_INIT(&state->outgoing); TAILQ_INIT(&ssh->private_keys); @@ -9107,7 +10318,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c state->packet_timeout_ms = -1; state->p_send.packets = state->p_read.packets = 0; state->initialized = 1; -@@ -294,7 +317,7 @@ +@@ -294,7 +321,7 @@ ssh_packet_set_connection(struct ssh *ssh, int fd_in, int fd_out) { struct session_state *state; @@ -9116,21 +10327,21 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c int r; if (none == NULL) { -@@ -311,9 +334,11 @@ +@@ -311,9 +338,11 @@ state->connection_in = fd_in; state->connection_out = fd_out; if ((r = cipher_init(&state->send_context, none, - (const u_char *)"", 0, NULL, 0, CIPHER_ENCRYPT)) != 0 || -+ (const u_char *)"", 0, NULL, 0, -+ CIPHER_ENCRYPT, state->after_authentication)) != 0 || ++ (const u_char *)"", 0, NULL, 0, 0, CIPHER_ENCRYPT, ++ state->after_authentication)) != 0 || (r = cipher_init(&state->receive_context, none, - (const u_char *)"", 0, NULL, 0, CIPHER_DECRYPT)) != 0) { -+ (const u_char *)"", 0, NULL, 0, -+ CIPHER_DECRYPT, state->after_authentication)) != 0) { ++ (const u_char *)"", 0, NULL, 0, 0, CIPHER_DECRYPT, ++ state->after_authentication)) != 0) { error_fr(r, "cipher_init failed"); free(ssh); /* XXX need ssh_free_session_state? */ return NULL; -@@ -384,7 +409,7 @@ +@@ -384,7 +413,7 @@ if (state->packet_discard_mac) { char buf[1024]; @@ -9139,7 +10350,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c if (dlen > state->packet_discard_mac_already) dlen -= state->packet_discard_mac_already; -@@ -885,6 +910,7 @@ +@@ -977,6 +1006,7 @@ const char *wmsg; int r, crypt_type; const char *dir = mode == MODE_OUT ? "out" : "in"; @@ -9147,17 +10358,42 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c debug2_f("mode %d", mode); -@@ -928,7 +954,8 @@ +@@ -1015,12 +1045,32 @@ + if ((r = mac_init(mac)) != 0) + return r; + } +- mac->enabled = 1; ++ ++ /* if we are using NONE MAC then we don't need to enable the ++ * mac routines. This disables them and we can claw back some cycles ++ * from the CPU -cjr 3/21/2023 */ ++ if (ssh->none_mac != 1) ++ mac->enabled = 1; ++ + DBG(debug_f("cipher_init: %s", dir)); cipher_free(*ccp); *ccp = NULL; ++#ifdef WITH_OPENSSL ++ if (strcmp(enc->name, "chacha20-poly1305-mt@hpnssh.org") == 0) { ++ if (state->after_authentication) ++ enc->cipher = cipher_by_name( ++ "chacha20-poly1305-mt@hpnssh.org"); ++ else ++ enc->cipher = cipher_by_name( ++ "chacha20-poly1305@openssh.com"); ++ if (enc->cipher == NULL) ++ return r; ++ } ++#endif if ((r = cipher_init(ccp, enc->cipher, enc->key, enc->key_len, - enc->iv, enc->iv_len, crypt_type)) != 0) -+ enc->iv, enc->iv_len, crypt_type, -+ state->after_authentication)) != 0) ++ enc->iv, enc->iv_len, ++ crypt_type ? state->p_send.seqnr : state->p_read.seqnr, ++ crypt_type, state->after_authentication)) != 0) return r; if (!state->cipher_warning_done && (wmsg = cipher_warning_message(*ccp)) != NULL) { -@@ -953,23 +980,45 @@ +@@ -1044,23 +1094,45 @@ } comp->enabled = 1; } @@ -9170,20 +10406,17 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c - *max_blocks = (u_int64_t)1 << (enc->block_size*2); - else - *max_blocks = ((u_int64_t)1 << 30) / enc->block_size; -- if (state->rekey_limit) -- *max_blocks = MINIMUM(*max_blocks, -- state->rekey_limit / enc->block_size); -- debug("rekey %s after %llu blocks", dir, -- (unsigned long long)*max_blocks); + + /* get the maximum number of blocks the cipher can + * handle safely */ + *max_blocks = cipher_rekey_blocks(enc->cipher); + + /* if we have a custom oRekeyLimit use that. */ -+ if (state->rekey_limit) -+ *max_blocks = MINIMUM(*max_blocks, -+ state->rekey_limit / enc->block_size); + if (state->rekey_limit) + *max_blocks = MINIMUM(*max_blocks, + state->rekey_limit / enc->block_size); +- debug("rekey %s after %llu blocks", dir, +- (unsigned long long)*max_blocks); + + /* these lines support the debug */ + strlcpy(blocks_s, "?", sizeof(blocks_s)); @@ -9217,7 +10450,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c #define MAX_PACKETS (1U<<31) static int ssh_packet_need_rekeying(struct ssh *ssh, u_int outbound_packet_len) -@@ -996,6 +1045,14 @@ +@@ -1087,6 +1159,14 @@ if (state->p_send.packets == 0 && state->p_read.packets == 0) return 0; @@ -9232,7 +10465,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c /* Time-based rekeying */ if (state->rekey_interval != 0 && (int64_t)state->rekey_time + state->rekey_interval <= monotime()) -@@ -1352,7 +1409,7 @@ +@@ -1445,7 +1525,7 @@ struct session_state *state = ssh->state; int len, r, ms_remain = 0; struct pollfd pfd; @@ -9241,7 +10474,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c struct timeval start; struct timespec timespec, *timespecp = NULL; -@@ -1479,7 +1536,7 @@ +@@ -1549,7 +1629,7 @@ return 0; /* packet is incomplete */ state->packlen = PEEK_U32(cp); if (state->packlen < 4 + 1 || @@ -9250,7 +10483,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c return SSH_ERR_MESSAGE_INCOMPLETE; } need = state->packlen + 4; -@@ -1538,7 +1595,7 @@ +@@ -1608,7 +1688,7 @@ sshbuf_ptr(state->input), sshbuf_len(state->input)) != 0) return 0; if (state->packlen < 1 + 4 || @@ -9259,7 +10492,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c #ifdef PACKET_DEBUG sshbuf_dump(state->input, stderr); #endif -@@ -1565,7 +1622,7 @@ +@@ -1635,7 +1715,7 @@ goto out; state->packlen = PEEK_U32(sshbuf_ptr(state->incoming_packet)); if (state->packlen < 1 + 4 || @@ -9268,7 +10501,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c #ifdef PACKET_DEBUG fprintf(stderr, "input: \n"); sshbuf_dump(state->input, stderr); -@@ -1574,7 +1631,7 @@ +@@ -1644,7 +1724,7 @@ #endif logit("Bad packet length %u.", state->packlen); return ssh_packet_start_discard(ssh, enc, mac, 0, @@ -9277,7 +10510,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c } if ((r = sshbuf_consume(state->input, block_size)) != 0) goto out; -@@ -1597,7 +1654,7 @@ +@@ -1667,7 +1747,7 @@ logit("padding error: need %d block %d mod %d", need, block_size, need % block_size); return ssh_packet_start_discard(ssh, enc, mac, 0, @@ -9286,7 +10519,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c } /* * check if the entire packet has been received and -@@ -1641,11 +1698,11 @@ +@@ -1711,11 +1791,11 @@ if (r != SSH_ERR_MAC_INVALID) goto out; logit("Corrupted MAC on input."); @@ -9300,7 +10533,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c } /* Remove MAC from input buffer */ DBG(debug("MAC #%d ok", state->p_read.seqnr)); -@@ -1843,7 +1900,7 @@ +@@ -1938,7 +2018,7 @@ int r; size_t rlen; @@ -9309,7 +10542,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c return r; if (state->packet_discard) { -@@ -1922,17 +1979,21 @@ +@@ -2017,17 +2097,21 @@ switch (r) { case SSH_ERR_CONN_CLOSED: ssh_packet_clear_keys(ssh); @@ -9331,7 +10564,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c logdie("Connection reset by %s", remote_id); } /* FALLTHROUGH */ -@@ -1974,6 +2035,24 @@ +@@ -2069,6 +2153,24 @@ logdie_f("should have exited"); } @@ -9356,7 +10589,7 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c /* * Logs the error plus constructs and sends a disconnect packet, closes the * connection, and exits. This function never returns. The error message -@@ -2216,10 +2295,19 @@ +@@ -2323,10 +2425,19 @@ ssh->kex->server = 1; /* XXX unify? */ } @@ -9376,21 +10609,28 @@ diff -Nur openssh-9.3p1.orig/packet.c openssh-9.3p1/packet.c } void * -@@ -2837,3 +2925,10 @@ +@@ -2949,3 +3060,17 @@ ssh->state->extra_pad = pad; return 0; } + -+/* need this for the moment for the aes-ctr cipher */ ++/* used for cipher switching ++ * only called in cipher-swtich.c */ +void * +ssh_packet_get_send_context(struct ssh *ssh) +{ + return ssh->state->send_context; +} -diff -Nur openssh-9.3p1.orig/packet.h openssh-9.3p1/packet.h ---- openssh-9.3p1.orig/packet.h 2024-07-10 09:07:09.738081869 +0200 -+++ openssh-9.3p1/packet.h 2024-07-10 09:09:55.912568437 +0200 -@@ -86,6 +86,17 @@ ++ ++void * ++ssh_packet_get_receive_context(struct ssh *ssh) ++{ ++ return ssh->state->receive_context; ++} +diff -Nur openssh-10.0p1.orig/packet.h openssh-10.0p1/packet.h +--- openssh-10.0p1.orig/packet.h 2025-06-14 10:53:01.719644792 +0200 ++++ openssh-10.0p1/packet.h 2025-06-14 10:54:01.325502017 +0200 +@@ -88,6 +88,17 @@ /* APP data */ void *app_data; @@ -9400,11 +10640,11 @@ diff -Nur openssh-9.3p1.orig/packet.h openssh-9.3p1/packet.h + u_long fdout_bytes; + u_long stdin_bytes; + -+ /* track that we are in a none cipher/mac state */ ++ /* track that we are in a none cipher state */ + int none; + -+ /* use the less agressive window growth option */ -+ int hpn_buffer_limit; ++ /* track if we have disabled the mac as well */ ++ int none_mac; }; typedef int (ssh_packet_hook_fn)(struct ssh *, struct sshbuf *, @@ -9417,12 +10657,12 @@ diff -Nur openssh-9.3p1.orig/packet.h openssh-9.3p1/packet.h int ssh_packet_get_state(struct ssh *, struct sshbuf *); int ssh_packet_set_state(struct ssh *, struct sshbuf *); -@@ -171,6 +184,13 @@ +@@ -172,6 +185,13 @@ void *ssh_packet_get_input(struct ssh *); void *ssh_packet_get_output(struct ssh *); +void *ssh_packet_get_receive_context(struct ssh *); -+void *ssh_packet_get_send_context(struct ssh *); ++void *ssh_packet_get_send_context(struct ssh *); + +/* for forced packet rekeying post auth */ +void packet_request_rekeying(void); @@ -9431,10 +10671,10 @@ diff -Nur openssh-9.3p1.orig/packet.h openssh-9.3p1/packet.h /* new API */ int sshpkt_start(struct ssh *ssh, u_char type); -diff -Nur openssh-9.3p1.orig/poly1305.c openssh-9.3p1/poly1305.c ---- openssh-9.3p1.orig/poly1305.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/poly1305.c 2024-07-10 09:09:55.912568437 +0200 -@@ -14,6 +14,16 @@ +diff -Nur openssh-10.0p1.orig/poly1305.c openssh-10.0p1/poly1305.c +--- openssh-10.0p1.orig/poly1305.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/poly1305.c 2025-06-14 10:54:01.325842914 +0200 +@@ -13,6 +13,16 @@ #include "poly1305.h" @@ -9451,7 +10691,7 @@ diff -Nur openssh-9.3p1.orig/poly1305.c openssh-9.3p1/poly1305.c #define mul32x32_64(a,b) ((uint64_t)(a) * (b)) #define U8TO32_LE(p) \ -@@ -31,7 +41,7 @@ +@@ -30,7 +40,7 @@ } while (0) void @@ -9460,14 +10700,14 @@ diff -Nur openssh-9.3p1.orig/poly1305.c openssh-9.3p1/poly1305.c uint32_t t0,t1,t2,t3; uint32_t h0,h1,h2,h3,h4; uint32_t r0,r1,r2,r3,r4; -@@ -158,3 +168,4 @@ +@@ -157,3 +167,4 @@ U32TO8_LE(&out[ 8], f2); f3 += (f2 >> 32); U32TO8_LE(&out[12], f3); } +#endif /* OPENSSL_HAVE_POLY_EVP */ -diff -Nur openssh-9.3p1.orig/poly1305.h openssh-9.3p1/poly1305.h ---- openssh-9.3p1.orig/poly1305.h 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/poly1305.h 2024-07-10 09:09:55.912568437 +0200 +diff -Nur openssh-10.0p1.orig/poly1305.h openssh-10.0p1/poly1305.h +--- openssh-10.0p1.orig/poly1305.h 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/poly1305.h 2025-06-14 10:54:01.326132826 +0200 @@ -13,8 +13,15 @@ #define POLY1305_KEYLEN 32 #define POLY1305_TAGLEN 16 @@ -9485,10 +10725,10 @@ diff -Nur openssh-9.3p1.orig/poly1305.h openssh-9.3p1/poly1305.h __attribute__((__bounded__(__minbytes__, 1, POLY1305_TAGLEN))) __attribute__((__bounded__(__buffer__, 2, 3))) __attribute__((__bounded__(__minbytes__, 4, POLY1305_KEYLEN))); -diff -Nur openssh-9.3p1.orig/progressmeter.c openssh-9.3p1/progressmeter.c ---- openssh-9.3p1.orig/progressmeter.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/progressmeter.c 2024-07-10 09:09:55.912568437 +0200 -@@ -67,6 +67,8 @@ +diff -Nur openssh-10.0p1.orig/progressmeter.c openssh-10.0p1/progressmeter.c +--- openssh-10.0p1.orig/progressmeter.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/progressmeter.c 2025-06-14 10:54:01.326416661 +0200 +@@ -65,6 +65,8 @@ static off_t start_pos; /* initial position of transfer */ static off_t end_pos; /* ending position of transfer */ static off_t cur_pos; /* transfer position as of last refresh */ @@ -9497,7 +10737,7 @@ diff -Nur openssh-9.3p1.orig/progressmeter.c openssh-9.3p1/progressmeter.c static volatile off_t *counter; /* progress counter */ static long stalled; /* how long we have been stalled */ static int bytes_per_second; /* current speed in bytes per second */ -@@ -133,6 +135,7 @@ +@@ -131,6 +133,7 @@ int cur_speed; int hours, minutes, seconds; int file_len, cols; @@ -9505,7 +10745,7 @@ diff -Nur openssh-9.3p1.orig/progressmeter.c openssh-9.3p1/progressmeter.c if ((!force_update && !alarm_fired && !win_resized) || !can_output()) return; -@@ -148,6 +151,10 @@ +@@ -146,6 +149,10 @@ now = monotime_double(); bytes_left = end_pos - cur_pos; @@ -9516,7 +10756,7 @@ diff -Nur openssh-9.3p1.orig/progressmeter.c openssh-9.3p1/progressmeter.c if (bytes_left > 0) elapsed = now - last_update; else { -@@ -177,7 +184,7 @@ +@@ -175,7 +182,7 @@ return; /* filename */ @@ -9525,7 +10765,7 @@ diff -Nur openssh-9.3p1.orig/progressmeter.c openssh-9.3p1/progressmeter.c if (file_len > 0) { asmprintf(&buf, INT_MAX, &cols, "%-*s", file_len, file); /* If we used fewer columns than expected then pad */ -@@ -194,6 +201,12 @@ +@@ -192,6 +199,12 @@ xextendf(&buf, NULL, " %3d%% %s %s/s ", percent, format_size(cur_pos), format_rate((off_t)bytes_per_second)); @@ -9538,7 +10778,7 @@ diff -Nur openssh-9.3p1.orig/progressmeter.c openssh-9.3p1/progressmeter.c /* ETA */ if (!transferred) stalled += elapsed; -@@ -236,6 +249,7 @@ +@@ -234,6 +247,7 @@ } free(buf); free(obuf); @@ -9546,35 +10786,37 @@ diff -Nur openssh-9.3p1.orig/progressmeter.c openssh-9.3p1/progressmeter.c } static void -diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c ---- openssh-9.3p1.orig/readconf.c 2024-07-10 09:07:09.808082074 +0200 -+++ openssh-9.3p1/readconf.c 2024-07-10 09:09:55.913568440 +0200 -@@ -68,6 +68,7 @@ +diff -Nur openssh-10.0p1.orig/readconf.c openssh-10.0p1/readconf.c +--- openssh-10.0p1.orig/readconf.c 2025-06-14 10:53:02.021809909 +0200 ++++ openssh-10.0p1/readconf.c 2025-06-14 10:54:01.327045863 +0200 +@@ -71,6 +71,7 @@ + #include "uidswap.h" #include "myproposal.h" #include "digest.h" - #include "ssh-gss.h" +#include "sshbuf.h" + #include "version.h" + #include "ssh-gss.h" - /* Format of the configuration file: - -@@ -169,6 +170,9 @@ +@@ -174,6 +175,10 @@ oHashKnownHosts, oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand, oRemoteCommand, -+ oTcpRcvBufPoll, oTcpRcvBuf, oHPNDisabled, oHPNBufferSize, -+ oNoneEnabled, oNoneMacEnabled, oNoneSwitch, oHPNBufferLimit, ++ oTcpRcvBufPoll, oHPNDisabled, ++ oNoneEnabled, oNoneMacEnabled, oNoneSwitch, ++ oDisableMTAES, oUseMPTCP, + oMetrics, oMetricsPath, oMetricsInterval, oFallback, oFallbackPort, oVisualHostKey, oKexAlgorithms, oIPQoS, oRequestTTY, oSessionType, oStdinNull, oForkAfterAuthentication, oIgnoreUnknown, oProxyUseFdpass, -@@ -314,6 +318,15 @@ +@@ -321,6 +326,16 @@ { "kexalgorithms", oKexAlgorithms }, { "ipqos", oIPQoS }, { "requesttty", oRequestTTY }, + { "noneenabled", oNoneEnabled }, + { "nonemacenabled", oNoneMacEnabled }, + { "noneswitch", oNoneSwitch }, -+ { "hpnbufferlimit", oHPNBufferLimit }, ++ { "usemptcp", oUseMPTCP}, ++ { "disablemtaes", oDisableMTAES }, + { "metrics", oMetrics }, + { "metricspath", oMetricsPath }, + { "metricsinterval", oMetricsInterval }, @@ -9583,18 +10825,16 @@ diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c { "sessiontype", oSessionType }, { "stdinnull", oStdinNull }, { "forkafterauthentication", oForkAfterAuthentication }, -@@ -336,6 +349,10 @@ +@@ -343,6 +358,8 @@ { "proxyjump", oProxyJump }, { "securitykeyprovider", oSecurityKeyProvider }, { "knownhostscommand", oKnownHostsCommand }, + { "tcprcvbufpoll", oTcpRcvBufPoll }, -+ { "tcprcvbuf", oTcpRcvBuf }, + { "hpndisabled", oHPNDisabled }, -+ { "hpnbuffersize", oHPNBufferSize }, { "requiredrsasize", oRequiredRSASize }, { "rsaminsize", oRequiredRSASize }, /* alias */ { "enableescapecommandline", oEnableEscapeCommandline }, -@@ -531,7 +548,7 @@ +@@ -542,7 +559,7 @@ if (port == 0) { sp = getservbyname(SSH_SERVICE_NAME, "tcp"); @@ -9603,7 +10843,7 @@ diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c } return port; } -@@ -1182,6 +1199,67 @@ +@@ -1381,6 +1398,67 @@ intptr = &options->check_host_ip; goto parse_flag; @@ -9611,10 +10851,6 @@ diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c + intptr = &options->hpn_disabled; + goto parse_flag; + -+ case oHPNBufferSize: -+ intptr = &options->hpn_buffer_size; -+ goto parse_int; -+ + case oTcpRcvBufPoll: + intptr = &options->tcp_rcv_buf_poll; + goto parse_flag; @@ -9627,8 +10863,12 @@ diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c + intptr = &options->nonemac_enabled; + goto parse_flag; + -+ case oHPNBufferLimit: -+ intptr = &options->hpn_buffer_limit; ++ case oUseMPTCP: ++ intptr = &options->use_mptcp; ++ goto parse_flag; ++ ++ case oDisableMTAES: ++ intptr = &options->disable_multithreaded; + goto parse_flag; + + case oMetrics: @@ -9671,61 +10911,31 @@ diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c case oVerifyHostKeyDNS: intptr = &options->verify_host_key_dns; multistate_ptr = multistate_yesnoask; -@@ -1436,6 +1514,10 @@ - *intptr = value; - break; - -+ case oTcpRcvBuf: -+ intptr = &options->tcp_rcv_buf; -+ goto parse_int; -+ - case oCiphers: - arg = argv_next(&ac, &av); - if (!arg || *arg == '\0') { -@@ -2476,6 +2558,19 @@ +@@ -2798,6 +2876,18 @@ options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; options->request_tty = -1; + options->none_switch = -1; + options->none_enabled = -1; + options->nonemac_enabled = -1; ++ options->use_mptcp = -1; ++ options->disable_multithreaded = -1; + options->metrics = -1; + options->metrics_path = NULL; + options->metrics_interval = -1; + options->hpn_disabled = -1; -+ options->hpn_buffer_size = -1; -+ options->hpn_buffer_limit = -1; + options->fallback = -1; + options->fallback_port = -1; + options->tcp_rcv_buf_poll = -1; -+ options->tcp_rcv_buf = -1; options->session_type = -1; options->stdin_null = -1; options->fork_after_authentication = -1; -@@ -2653,8 +2748,53 @@ +@@ -2982,8 +3072,39 @@ options->server_alive_interval = 0; if (options->server_alive_count_max == -1) options->server_alive_count_max = 3; + if (options->hpn_disabled == -1) + options->hpn_disabled = 0; -+ if (options->hpn_buffer_size > -1) { -+ /* if a user tries to set the size to 0 set it to 1KB */ -+ if (options->hpn_buffer_size == 0) -+ options->hpn_buffer_size = 1; -+ /* limit the buffer to SSHBUF_SIZE_MAX (currently 256MB) */ -+ if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024)) { -+ options->hpn_buffer_size = SSHBUF_SIZE_MAX; -+ debug("User requested buffer larger than 256MB. Request reverted to 256MB"); -+ } else -+ options->hpn_buffer_size *= 1024; -+ debug("hpn_buffer_size set to %d", options->hpn_buffer_size); -+ } -+ if (options->hpn_buffer_limit == -1) -+ options->hpn_buffer_limit = 0; -+ if (options->tcp_rcv_buf == 0) -+ options->tcp_rcv_buf = 1; -+ if (options->tcp_rcv_buf > -1) -+ options->tcp_rcv_buf *=1024; + if (options->tcp_rcv_buf_poll == -1) + options->tcp_rcv_buf_poll = 1; + if (options->none_switch == -1) @@ -9743,6 +10953,10 @@ diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c + fprintf(stderr, "None MAC can only be used with the None cipher. None MAC disabled.\n"); + options->nonemac_enabled = 0; + } ++ if (options->use_mptcp == -1) ++ options->use_mptcp = 0; ++ if (options->disable_multithreaded == -1) ++ options->disable_multithreaded = 0; + if (options->metrics == -1) + options->metrics = 0; + if (options->metrics_interval == -1) @@ -9756,54 +10970,81 @@ diff -Nur openssh-9.3p1.orig/readconf.c openssh-9.3p1/readconf.c if (options->control_persist == -1) { options->control_persist = 0; options->control_persist_timeout = 0; -diff -Nur openssh-9.3p1.orig/readconf.h openssh-9.3p1/readconf.h ---- openssh-9.3p1.orig/readconf.h 2024-07-10 09:07:09.809082077 +0200 -+++ openssh-9.3p1/readconf.h 2024-07-10 09:09:55.913568440 +0200 -@@ -56,6 +56,11 @@ - int strict_host_key_checking; /* Strict host key checking. */ - int compression; /* Compress packets in both directions. */ - int tcp_keep_alive; /* Set SO_KEEPALIVE. */ -+ int tcp_rcv_buf; /* user switch to set tcp recv buffer */ -+ int tcp_rcv_buf_poll; /* Option to poll recv buf every window transfer */ -+ int hpn_disabled; /* Switch to disable HPN buffer management */ -+ int hpn_buffer_size; /* User definable size for HPN buffer window */ -+ int hpn_buffer_limit; /* limit local_window_max to 1/2 receive buffer */ - int ip_qos_interactive; /* IP ToS/DSCP/class for interactive */ - int ip_qos_bulk; /* IP ToS/DSCP/class for bulk traffic */ - SyslogFacility log_facility; /* Facility for system logging. */ -@@ -128,6 +133,16 @@ +@@ -3757,6 +3878,14 @@ + dump_cfg_fmtint(oVisualHostKey, o->visual_host_key); + dump_cfg_fmtint(oUpdateHostkeys, o->update_hostkeys); + dump_cfg_fmtint(oEnableEscapeCommandline, o->enable_escape_commandline); ++ dump_cfg_fmtint(oTcpRcvBufPoll, o->tcp_rcv_buf_poll); ++ dump_cfg_fmtint(oHPNDisabled, o->hpn_disabled); ++ dump_cfg_fmtint(oNoneSwitch, o->none_switch); ++ dump_cfg_fmtint(oNoneEnabled, o->none_enabled); ++ dump_cfg_fmtint(oNoneMacEnabled, o->nonemac_enabled); ++ dump_cfg_fmtint(oFallback, o->fallback); ++ dump_cfg_fmtint(oMetrics, o->metrics); ++ + + /* Integer options */ + dump_cfg_int(oCanonicalizeMaxDots, o->canonicalize_max_dots); +@@ -3768,6 +3897,8 @@ + dump_cfg_int(oRequiredRSASize, o->required_rsa_size); + dump_cfg_int(oObscureKeystrokeTiming, + o->obscure_keystroke_timing_interval); ++ dump_cfg_int(oMetricsInterval, o->metrics_interval); ++ dump_cfg_int(oFallbackPort, o->fallback_port); + + /* String options */ + dump_cfg_string(oBindAddress, o->bind_address); +@@ -3796,6 +3927,7 @@ + dump_cfg_string(oXAuthLocation, o->xauth_location); + dump_cfg_string(oKnownHostsCommand, o->known_hosts_command); + dump_cfg_string(oTag, o->tag); ++ dump_cfg_string(oMetricsPath, o->metrics_path); + dump_cfg_string(oVersionAddendum, o->version_addendum); + + /* Forwards */ +diff -Nur openssh-10.0p1.orig/readconf.h openssh-10.0p1/readconf.h +--- openssh-10.0p1.orig/readconf.h 2025-06-14 10:53:02.022395739 +0200 ++++ openssh-10.0p1/readconf.h 2025-06-14 10:54:01.328092159 +0200 +@@ -128,6 +128,21 @@ int enable_ssh_keysign; int64_t rekey_limit; int rekey_interval; + ++ /* hpnssh options */ ++ int tcp_rcv_buf_poll; /* Option to poll recv buf every window transfer */ ++ int hpn_disabled; /* Switch to disable HPN buffer management */ + int none_switch; /* Use none cipher */ + int none_enabled; /* Allow none to be used */ + int nonemac_enabled; /* Allow none to be used */ ++ int disable_multithreaded; /* Disable multithreaded aes-ctr */ + int metrics; /* enable metrics */ + int metrics_interval; /* time in seconds between polls */ + char *metrics_path; /* path for the metrics files */ + int fallback; /* en|disable fallback port (def: true) */ + int fallback_port; /* port to fallback to (def: 22) */ ++ int use_mptcp; + int no_host_authentication_for_localhost; int identities_only; int server_alive_interval; -diff -Nur openssh-9.3p1.orig/README.md openssh-9.3p1/README.md ---- openssh-9.3p1.orig/README.md 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/README.md 2024-07-10 09:09:55.914568443 +0200 -@@ -1,16 +1,20 @@ +diff -Nur openssh-10.0p1.orig/README.md openssh-10.0p1/README.md +--- openssh-10.0p1.orig/README.md 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/README.md 2025-06-14 10:54:01.328596415 +0200 +@@ -1,16 +1,22 @@ -# Portable OpenSSH +# HPNSSH: Based on Portable OpenSSH -[![C/C++ CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml) -[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/openssh.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:openssh) -[![Coverity Status](https://scan.coverity.com/projects/21341/badge.svg)](https://scan.coverity.com/projects/openssh-portable) -+Starting with version HPN17v0 there will be significant changes to the naming convention used for executables and installation locations. The last version that does not include these changes is HPN16v1 corresponding to the HPN-8_8_P1 tag on the master branch. ++HPN-SSH is a high performance soft fork of OpenSSH that can provide significnatly faster throughput for bulk data transfers over a wide range of network paths. In some situations we've seen throughput rates more than 100 times faster than OpenSSH. HPN-SSH is able to do this by optimizing the application layer receive buffer to match the TCP receive buffer. Notably, to see performance improvements HPN-SSH only needs to be the data receiver so users can see notable improvements with many other SSH implementations. HPN-SSH also incorporate two parallelized ciphers, AES-CTR and Chacha20 (the default). When using these ciphers a throughput performance increase of 30% is typical. More information on how we do this work and other features of HPN-SSH is available from [https://hpnssh.org](https://hpnssh.org). -OpenSSH is a complete implementation of the SSH protocol (version 2) for secure remote login, command execution and file transfer. It includes a client ``ssh`` and server ``sshd``, file transfer utilities ``scp`` and ``sftp`` as well as tools for key generation (``ssh-keygen``), run-time key storage (``ssh-agent``) and a number of supporting programs. -+HPNSSH is a variant of OpenSSH. It a complete implementation of the SSH protocol (version 2) for secure remote login, command execution and file transfer. It includes a client ``hpnssh`` and server ``hpnsshd``, file transfer utilities ``hpnscp`` and ``hpnsftp`` as well as tools for key generation (``hpnssh-keygen``), run-time key storage (``hpnssh-agent``) and a number of supporting programs. It includes numerous performance and functionality enhancements focused on high performance networks and computing envrironments. Complete information can be found in the HPN-README file. ++Starting with version HPN17v0 there will be significant changes to the naming convention used for executables and installation locations. The last version that does not include these changes is HPN16v1 corresponding to the HPN-8_8_P1 tag on the master branch. -This is a port of OpenBSD's [OpenSSH](https://openssh.com) to most Unix-like operating systems, including Linux, OS X and Cygwin. Portable OpenSSH polyfills OpenBSD APIs that are not available elsewhere, adds sshd sandboxing for more operating systems and includes support for OS-native authentication and auditing (e.g. using PAM). ++HPNSSH is a variant of OpenSSH. It a complete implementation of the SSH protocol (version 2) for secure remote login, command execution and file transfer. It includes a client ``hpnssh`` and server ``hpnsshd``, file transfer utilities ``hpnscp`` and ``hpnsftp`` as well as tools for key generation (``hpnssh-keygen``), run-time key storage (``hpnssh-agent``) and a number of supporting programs. It includes numerous performance and functionality enhancements focused on high performance networks and computing envrironments. Complete information can be found in the HPN-README file. ++ +It is fully compatible with all compliant implementations of the SSH protocol and OpenSSH in particular. + +This version of HPNSSH is significant departure in terms of naming executables and installation locations. Specifically, all executables are now prefixed with ``hpn``. So ``ssh`` becomes ``hpnssh`` and ``scp`` is now ``hpnscp``. Configuation files and host keys can now be found in ``/etc/hpnssh``. By default ``hpnsshd`` now runs on port 2222 but this is configurable. This change was made in order to prevent installations of hpnssh, particularly from package distributions, from interfering with default installations of OpenSSH. HPNSSH is backwards compatible with all versions of OpenSSH including configuration files, keys, and run time options. Additionally, the client will, by default attempt to connect to port 2222 but will automatically fall back to port 22. This is also user configurable. @@ -9819,7 +11060,7 @@ diff -Nur openssh-9.3p1.orig/README.md openssh-9.3p1/README.md * [ssh(1)](https://man.openbsd.org/ssh.1) * [sshd(8)](https://man.openbsd.org/sshd.8) -@@ -21,15 +25,15 @@ +@@ -21,15 +27,15 @@ * [ssh-keyscan(8)](https://man.openbsd.org/ssh-keyscan.8) * [sftp-server(8)](https://man.openbsd.org/sftp-server.8) @@ -9839,27 +11080,32 @@ diff -Nur openssh-9.3p1.orig/README.md openssh-9.3p1/README.md ``libcrypto`` from either [LibreSSL](https://www.libressl.org/) or [OpenSSL](https://www.openssl.org) may also be used. OpenSSH may be built without either of these, but the resulting binaries will have only a subset of the cryptographic algorithms normally available. -@@ -44,8 +48,8 @@ - Releases include a pre-built copy of the ``configure`` script and may be built using: +@@ -44,8 +50,9 @@ + Release tarballs and release branches in git include a pre-built copy of the ``configure`` script and may be built using: ``` -tar zxvf openssh-X.YpZ.tar.gz -cd openssh +tar zxvf hpnssh-X.YpZ.tar.gz -+cd hpnssh ++cd hpn-ssh ++autoreconf -f -i ./configure # [options] make && make tests ``` -@@ -57,7 +61,7 @@ - If building from git, you'll need [autoconf](https://www.gnu.org/software/autoconf/) installed to build the ``configure`` script. The following commands will check out and build portable OpenSSH from git: +@@ -57,9 +64,9 @@ + If building from the git master branch, you'll need [autoconf](https://www.gnu.org/software/autoconf/) installed to build the ``configure`` script. The following commands will check out and build portable OpenSSH from git: ``` -git clone https://github.com/openssh/openssh-portable # or https://anongit.mindrot.org/openssh.git -+git clone https://github.com/rapier1/openssh-portable - cd openssh-portable - autoreconf +-cd openssh-portable +-autoreconf ++git clone https://github.com/rapier1/hpn-ssh ++cd hpn-ssh ++autoreconf -f -i ./configure -@@ -76,6 +80,7 @@ + make && make tests + ``` +@@ -76,6 +83,7 @@ ``--with-libedit`` | Enable [libedit](https://www.thrysoee.dk/editline/) support for sftp. ``--with-kerberos5`` | Enable Kerberos/GSSAPI support. Both [Heimdal](https://www.h5l.org/) and [MIT](https://web.mit.edu/kerberos/) Kerberos implementations are supported. ``--with-selinux`` | Enable [SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux) support. @@ -9867,9 +11113,14 @@ diff -Nur openssh-9.3p1.orig/README.md openssh-9.3p1/README.md ## Development -diff -Nur openssh-9.3p1.orig/sandbox-seccomp-filter.c openssh-9.3p1/sandbox-seccomp-filter.c ---- openssh-9.3p1.orig/sandbox-seccomp-filter.c 2024-07-10 09:07:09.751081907 +0200 -+++ openssh-9.3p1/sandbox-seccomp-filter.c 2024-07-10 09:09:55.914568443 +0200 +@@ -84,3 +92,4 @@ + ## Reporting bugs + + _Non-security_ bugs may be reported to the developers via [Bugzilla](https://bugzilla.mindrot.org/) or via the mailing list above. Security bugs should be reported to [openssh@openssh.com](mailto:openssh.openssh.com). ++ +diff -Nur openssh-10.0p1.orig/sandbox-seccomp-filter.c openssh-10.0p1/sandbox-seccomp-filter.c +--- openssh-10.0p1.orig/sandbox-seccomp-filter.c 2025-06-14 10:53:01.776677219 +0200 ++++ openssh-10.0p1/sandbox-seccomp-filter.c 2025-06-14 10:54:01.328916358 +0200 @@ -295,6 +295,9 @@ #ifdef __NR_geteuid32 SC_ALLOW(__NR_geteuid32), @@ -9890,9 +11141,9 @@ diff -Nur openssh-9.3p1.orig/sandbox-seccomp-filter.c openssh-9.3p1/sandbox-secc #ifdef __NR_time SC_ALLOW(__NR_time), #endif -diff -Nur openssh-9.3p1.orig/scp.1 openssh-9.3p1/scp.1 ---- openssh-9.3p1.orig/scp.1 2024-07-10 09:07:09.720081816 +0200 -+++ openssh-9.3p1/scp.1 2024-07-10 10:06:25.921495807 +0200 +diff -Nur openssh-10.0p1.orig/scp.1 openssh-10.0p1/scp.1 +--- openssh-10.0p1.orig/scp.1 2025-06-14 10:53:01.646933368 +0200 ++++ openssh-10.0p1/scp.1 2025-06-14 10:54:01.329403433 +0200 @@ -18,7 +18,7 @@ .Nd OpenSSH secure file copy .Sh SYNOPSIS @@ -9902,7 +11153,24 @@ diff -Nur openssh-9.3p1.orig/scp.1 openssh-9.3p1/scp.1 .Op Fl c Ar cipher .Op Fl D Ar sftp_server_path .Op Fl F Ar ssh_config -@@ -252,6 +252,10 @@ +@@ -33,6 +33,8 @@ + .Sh DESCRIPTION + .Nm + copies files between hosts on a network. ++It is binary compatible with OpenSSH's scp including ++the use of the same directives and configuration options except where noted. + .Pp + .Nm + uses the SFTP protocol over a +@@ -257,6 +259,7 @@ + .It Tunnel + .It TunnelDevice + .It UpdateHostKeys ++.It UseMPTCP + .It User + .It UserKnownHostsFile + .It VerifyHostKeyDNS +@@ -291,6 +294,10 @@ Note that .Nm follows symbolic links encountered in the tree traversal. @@ -9913,7 +11181,22 @@ diff -Nur openssh-9.3p1.orig/scp.1 openssh-9.3p1/scp.1 .It Fl S Ar program Name of .Ar program -@@ -285,10 +289,13 @@ +@@ -298,6 +305,14 @@ + The program must understand + .Xr ssh 1 + options. ++.It Fl z Ar program ++Path to hpnscp on remote system. Useful if remote has multiple scp installs. ++For example, using the resume option but the default remote scp does not have the resume option. ++Use -z to point the version that does - e.g. -z /opt/hpnssh/bin/hpnscp. ++.Nm ++only option. ++.It Fl s ++Use the SFTP protocol for transfers rather than the original scp protocol. + .It Fl T + Disable strict filename checking. + By default when copying files from a remote host to a local directory +@@ -324,10 +339,13 @@ .It Cm nrequests Ns = Ns Ar value Controls how many concurrent SFTP read or write requests may be in progress at any point in time during a download or upload. @@ -9928,7 +11211,7 @@ diff -Nur openssh-9.3p1.orig/scp.1 openssh-9.3p1/scp.1 By default a 32KB buffer is used. .El .El -@@ -322,6 +329,7 @@ +@@ -361,6 +379,7 @@ .Sh AUTHORS .An Timo Rinne Aq Mt tri@iki.fi .An Tatu Ylonen Aq Mt ylo@cs.hut.fi @@ -9936,9 +11219,9 @@ diff -Nur openssh-9.3p1.orig/scp.1 openssh-9.3p1/scp.1 .Sh CAVEATS The legacy SCP protocol (selected by the .Fl O -diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c ---- openssh-9.3p1.orig/scp.c 2024-07-10 09:07:09.793082030 +0200 -+++ openssh-9.3p1/scp.c 2024-07-10 09:09:55.915568446 +0200 +diff -Nur openssh-10.0p1.orig/scp.c openssh-10.0p1/scp.c +--- openssh-10.0p1.orig/scp.c 2025-06-14 10:53:01.663335155 +0200 ++++ openssh-10.0p1/scp.c 2025-06-14 12:35:32.946245567 +0200 @@ -17,6 +17,7 @@ /* * Copyright (c) 1999 Theo de Raadt. All rights reserved. @@ -9947,17 +11230,20 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions -@@ -133,6 +134,9 @@ +@@ -133,6 +134,12 @@ #include "misc.h" #include "progressmeter.h" #include "utf8.h" -+#ifdef WITH_OPENSSL ++/* libressl doesn't support the blake2b512 digest so ++ * we need to prevent libressl from using the resume feature ++ * cjr 7/18/2023 */ ++#if (defined WITH_OPENSSL) && !defined(LIBRESSL_VERSION_NUMBER) +#include +#endif #include "sftp.h" #include "sftp-common.h" -@@ -175,6 +179,10 @@ +@@ -175,6 +182,10 @@ /* This is the program to execute for the secured connection. ("ssh" or -S) */ char *ssh_program = _PATH_SSH_PROGRAM; @@ -9968,8 +11254,8 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c /* This is used to store the pid of ssh_program */ pid_t do_cmd_pid = -1; pid_t do_cmd_pid2 = -1; -@@ -189,6 +197,17 @@ - int remote_glob(struct sftp_conn *, const char *, int, +@@ -189,6 +200,17 @@ + int sftp_glob(struct sftp_conn *, const char *, int, int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */ +/* Flag to indicate that this is a file resume */ @@ -9981,12 +11267,12 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c +/* defines for the resume function. Need them even if not supported */ +#define HASH_LEN 128 /*40 sha1, 64 blake2s256 128 blake2b512*/ +#define BUF_AND_HASH HASH_LEN + 64 /* length of the hash and other data to get size of buffer */ -+#define HASH_BUFLEN 8192 /* 8192 seems to be a good balance between freads ++#define HASH_BUFLEN 8192 /* 8192 seems to be a good balance between freads + * and the digest func*/ static void killchild(int signo) { -@@ -234,6 +253,9 @@ +@@ -236,6 +258,9 @@ int status; pid_t pid; @@ -9996,7 +11282,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if (a->num == 0) fatal("do_local_cmd: no arguments"); -@@ -460,6 +482,8 @@ +@@ -462,6 +487,8 @@ void tolocal(int, char *[], enum scp_mode_e, char *sftp_direct); void toremote(int, char *[], enum scp_mode_e, char *sftp_direct); void usage(void); @@ -10005,7 +11291,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c void source_sftp(int, char *, char *, struct sftp_conn *); void sink_sftp(int, char *, const char *, struct sftp_conn *); -@@ -478,11 +502,18 @@ +@@ -480,11 +507,18 @@ char *sftp_direct = NULL; long long llv; @@ -10024,7 +11310,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c /* Copy argv, because we modify it */ argv0 = argv[0]; newargv = xcalloc(MAXIMUM(argc + 1, 1), sizeof(*newargv)); -@@ -506,7 +537,7 @@ +@@ -509,7 +543,7 @@ fflag = Tflag = tflag = 0; while ((ch = getopt(argc, argv, @@ -10033,11 +11319,11 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c switch (ch) { /* User-visible flags. */ case '1': -@@ -587,24 +618,36 @@ +@@ -590,24 +624,36 @@ addargs(&remote_remote_args, "-q"); showprogress = 0; break; -+#ifdef WITH_OPENSSL ++#if (defined WITH_OPENSSL) && !defined(LIBRESSL_VERSION_NUMBER) + case 'Z': + /* currently resume only works in SCP mode */ + resume_flag = 1; @@ -10059,7 +11345,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c - fatal("Invalid buffer size \"%s\": %s", - optarg + 7, strerror(errno)); + fatal("Invalid buffer size. Must be between 1B and 255KB." -+ "\"%s\": %s", optarg + 7, strerror(errno)); ++ "\"%s\": %s", optarg + 7, strerror(errno)); } sftp_copy_buflen = (size_t)llv; } else if (strncmp(optarg, "nrequests=", 10) == 0) { @@ -10075,7 +11361,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c "\"%s\": %s", optarg + 10, errstr); } sftp_nrequests = (size_t)llv; -@@ -692,11 +735,20 @@ +@@ -695,11 +741,20 @@ remin = remout = -1; do_cmd_pid = -1; /* Command to be executed on remote system using "ssh". */ @@ -10083,34 +11369,33 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c - verbose_mode ? " -v" : "", - iamrecursive ? " -r" : "", pflag ? " -p" : "", - targetshouldbedirectory ? " -d" : ""); -- + /* In the event of an hpn to hpn connection the scp -+ * command is rewritten to hpnscp. This happens in ++ * command is rewritten to hpnscp. This happens in + * clientloop.c -cjr 12/12/2022 */ -+ + + (void) snprintf(cmd, sizeof cmd, "%s%s%s%s%s%s", -+ remote_path ? remote_path : "scp", -+ verbose_mode ? " -v" : "", -+ iamrecursive ? " -r" : "", -+ pflag ? " -p" : "", -+ targetshouldbedirectory ? " -d" : "", -+ resume_flag ? " -Z" : ""); ++ remote_path ? remote_path : "scp", ++ verbose_mode ? " -v" : "", ++ iamrecursive ? " -r" : "", ++ pflag ? " -p" : "", ++ targetshouldbedirectory ? " -d" : "", ++ resume_flag ? " -Z" : ""); +#ifdef DEBUG -+ fprintf(stderr, "%s: Sending cmd %s\n", hostname, cmd); ++ fprintf(stderr, "%s: Sending cmd %s\n", hostname, cmd); +#endif (void) ssh_signal(SIGPIPE, lostconn); if (colon(argv[argc - 1])) /* Dest is remote host. */ -@@ -1310,6 +1362,74 @@ +@@ -1324,6 +1379,74 @@ free(src); } +/* calculate the hash of a file up to length bytes + * this is used to determine if remote and local file -+ * fragments match. There may be a more efficient process for the hashing -+ * TODO: I'd like to XXHash for the hashing but that requires that both -+ * ends have xxhash installed and then dealing with fallbacks */ -+#ifdef WITH_OPENSSL ++ * fragments match. There may be a more efficient process for the hashing ++ * Note: LibreSSL doesn't support blake2b512 so we can't offer them ++ * the resume feature cjr 7/18/2023 */ ++#if (defined WITH_OPENSSL) && !defined(LIBRESSL_VERSION_NUMBER) +void calculate_hash(char *filename, char *output, off_t length) +{ + int n, md_len; @@ -10141,7 +11426,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c + + while (length > 0) { + if (length > HASH_BUFLEN) -+ /* fread returns the number of elements read. ++ /* fread returns the number of elements read. + * in this case 1. Multiply by the length to get the bytes */ + bytes=fread(buf, HASH_BUFLEN, 1, file_ptr) * HASH_BUFLEN; + else @@ -10164,7 +11449,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c +#else +void calculate_hash(char *filename, char *output, off_t length) +{ -+ /* empty function for builds without openssl */ ++ /* empty function for builds without openssl or are using libressl */ +} +#endif /* WITH_OPENSSL */ + @@ -10176,7 +11461,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c /* Prepare remote path, handling ~ by assuming cwd is the homedir */ static char * prepare_remote_path(struct sftp_conn *conn, const char *path) -@@ -1393,14 +1513,23 @@ +@@ -1407,14 +1530,23 @@ struct stat stb; static BUF buffer; BUF *bp; @@ -10202,7 +11487,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c statbytes = 0; len = strlen(name); while (len > 1 && name[len-1] == '/') -@@ -1422,6 +1551,14 @@ +@@ -1436,6 +1568,14 @@ unset_nonblock(fd); switch (stb.st_mode & S_IFMT) { case S_IFREG: @@ -10217,7 +11502,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c break; case S_IFDIR: if (iamrecursive) { -@@ -1443,14 +1580,133 @@ +@@ -1457,14 +1597,133 @@ goto next; } #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) @@ -10229,12 +11514,12 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c + /* Add a hash of the file along with the filemode if in resume */ + if (resume_flag) + snprintf(buf, sizeof buf, "C%04o %lld %s %s\n", -+ (u_int) (stb.st_mode & FILEMODEMASK), -+ (long long)stb.st_size, hashsum, last); ++ (u_int) (stb.st_mode & FILEMODEMASK), ++ (long long)stb.st_size, hashsum, last); + else + snprintf(buf, sizeof buf, "C%04o %lld %s\n", -+ (u_int) (stb.st_mode & FILEMODEMASK), -+ (long long)stb.st_size, last); ++ (u_int) (stb.st_mode & FILEMODEMASK), ++ (long long)stb.st_size, last); + +#ifdef DEBUG + fprintf(stderr, "%s: Sending file modes: %s", hostname, buf); @@ -10357,7 +11642,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) { next: if (fd != -1) { (void) close(fd); -@@ -1458,13 +1714,17 @@ +@@ -1472,13 +1731,17 @@ } continue; } @@ -10379,12 +11664,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if (!haderr) { if ((nr = atomicio(read, fd, bp->buf, amt)) != amt) { -@@ -1657,28 +1917,40 @@ - (sizeof(type) == 8 && (val) > INT64_MAX) || \ - (sizeof(type) != 4 && sizeof(type) != 8)) - -+ - void +@@ -1675,24 +1938,35 @@ sink(int argc, char **argv, const char *src) { static BUF buffer; @@ -10418,12 +11698,12 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c #define SCREWUP(str) { why = str; goto screwup; } +#ifdef DEBUG -+ fprintf (stderr, "%s: LOCAL In sink with %s\n", hostname, src); -+#endif ++ fprintf (stderr, "%s: LOCAL In sink with %s\n", hostname, src); ++#endif if (TYPE_OVERFLOW(time_t, 0) || TYPE_OVERFLOW(off_t, 0)) SCREWUP("Unexpected off_t/time_t size"); -@@ -1694,9 +1966,16 @@ +@@ -1708,9 +1982,16 @@ if (targetshouldbedirectory) verifydir(targ); @@ -10440,11 +11720,9 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if (src != NULL && !iamrecursive && !Tflag) { /* * Prepare to try to restrict incoming filenames to match -@@ -1705,7 +1984,12 @@ - if (brace_expand(src, &patterns, &npatterns) != 0) +@@ -1720,6 +2001,10 @@ fatal_f("could not expand pattern"); } -+ for (first = 1;; first = 0) { + bad_match_flag = 0; /* used in resume mode. */ +#ifdef DEBUG @@ -10453,7 +11731,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c cp = buf; if (atomicio(read, remin, cp, 1) != 1) goto done; -@@ -1733,6 +2017,9 @@ +@@ -1747,6 +2032,9 @@ continue; } if (buf[0] == 'E') { @@ -10463,7 +11741,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c (void) atomicio(vwrite, remout, "", 1); goto done; } -@@ -1740,6 +2027,9 @@ +@@ -1754,6 +2042,9 @@ *--cp = 0; cp = buf; @@ -10473,7 +11751,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if (*cp == 'T') { setimes++; cp++; -@@ -1767,9 +2057,19 @@ +@@ -1781,9 +2072,19 @@ if (!cp || *cp++ != '\0' || atime.tv_usec < 0 || atime.tv_usec > 999999) SCREWUP("atime.usec not delimited"); @@ -10493,7 +11771,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if (*cp != 'C' && *cp != 'D') { /* * Check for the case "rcp remote:foo\* local:bar". -@@ -1785,6 +2085,18 @@ +@@ -1799,6 +2100,18 @@ SCREWUP("expected control record"); } mode = 0; @@ -10512,7 +11790,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c for (++cp; cp < buf + 5; cp++) { if (*cp < '0' || *cp > '7') SCREWUP("bad mode"); -@@ -1795,6 +2107,10 @@ +@@ -1809,6 +2122,10 @@ if (*cp++ != ' ') SCREWUP("mode not delimited"); @@ -10523,7 +11801,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if (!isdigit((unsigned char)*cp)) SCREWUP("size not present"); ull = strtoull(cp, &cp, 10); -@@ -1804,11 +2120,32 @@ +@@ -1818,11 +2135,32 @@ SCREWUP("size out of range"); size = (off_t)ull; @@ -10556,7 +11834,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if (npatterns > 0) { for (n = 0; n < npatterns; n++) { if (strcmp(patterns[n], cp) == 0 || -@@ -1870,11 +2207,195 @@ +@@ -1892,11 +2230,195 @@ } omode = mode; mode |= S_IWUSR; @@ -10725,7 +12003,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c + fprintf(stderr, "%s match status is M\n", hostname); +#endif + bad_match_flag = 0; /* while this is set at the beginning of the -+ * loop I'm setting it here explicitly as well */ ++ * loop I'm setting it here explicitly as well */ + } + } + @@ -10753,7 +12031,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) { (void) close(ofd); continue; -@@ -1889,13 +2410,17 @@ +@@ -1911,13 +2433,17 @@ */ statbytes = 0; if (showprogress) @@ -10775,7 +12053,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c do { j = atomicio6(read, remin, cp, amt, scpio, &statbytes); -@@ -1930,8 +2455,78 @@ +@@ -1952,8 +2478,78 @@ wrerr = 1; } if (!wrerr && (!exists || S_ISREG(stb.st_mode)) && @@ -10783,7 +12061,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c + ftruncate(ofd, xfer_size) != 0) note_err("%s: truncate: %s", np, strerror(errno)); + -+ /* if np_tmp isn't set then we don't have a resume file to cat */ ++ /* if np_tmp isn't set then we don't have a resume file to cat */ + /* likewise, bad match flag means no resume flag */ +#ifdef DEBUG + fprintf (stderr, "%s: resume_flag: %d, np_tmp: %s, bad_match_flag: %d\n", @@ -10855,7 +12133,7 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c if (pflag) { if (exists || omode != mode) #ifdef HAVE_FCHMOD -@@ -1966,8 +2561,17 @@ +@@ -1988,8 +2584,17 @@ } } /* If no error was noted then signal success for this file */ @@ -10874,11 +12152,11 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c } done: for (n = 0; n < npatterns; n++) -@@ -2111,11 +2715,19 @@ +@@ -2133,11 +2738,20 @@ void usage(void) { -+#ifdef WITH_OPENSSL ++#if (defined WITH_OPENSSL) && !defined(LIBRESSL_VERSION_NUMBER) + (void) fprintf(stderr, + "usage: scp [-346ABCOpqRrsTvZ] [-c cipher] [-D sftp_server_path] [-F ssh_config]\n" + " [-i identity_file] [-J destination] [-l limit] [-o ssh_option]\n" @@ -10891,10 +12169,11 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c " [-P port] [-S program] [-X sftp_option] source ... target\n"); exit(1); +#endif ++ } void -@@ -2254,6 +2866,18 @@ +@@ -2276,6 +2890,18 @@ exit(1); } @@ -10913,34 +12192,23 @@ diff -Nur openssh-9.3p1.orig/scp.c openssh-9.3p1/scp.c void cleanup_exit(int i) { -diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c ---- openssh-9.3p1.orig/servconf.c 2024-07-10 09:07:09.809082077 +0200 -+++ openssh-9.3p1/servconf.c 2024-07-10 10:16:09.316203959 +0200 -@@ -200,6 +200,12 @@ +diff -Nur openssh-10.0p1.orig/servconf.c openssh-10.0p1/servconf.c +--- openssh-10.0p1.orig/servconf.c 2025-06-14 10:53:02.022835252 +0200 ++++ openssh-10.0p1/servconf.c 2025-06-14 12:36:43.529579310 +0200 +@@ -217,6 +217,12 @@ options->authorized_principals_file = NULL; options->authorized_principals_command = NULL; options->authorized_principals_command_user = NULL; + options->tcp_rcv_buf_poll = -1; + options->hpn_disabled = -1; -+ options->hpn_buffer_size = -1; + options->none_enabled = -1; + options->nonemac_enabled = -1; -+ options->hpn_buffer_limit = -1; ++ options->use_mptcp = -1; ++ options->disable_multithreaded = -1; options->ip_qos_interactive = -1; options->ip_qos_bulk = -1; options->version_addendum = NULL; -@@ -294,6 +300,10 @@ - fill_default_server_options(ServerOptions *options) - { - u_int i; -+ /* needed for hpn socket tests */ -+ int sock; -+ int socksize; -+ int socksizelen = sizeof(int); - - /* Portable-specific options */ - if (options->use_pam == -1) -@@ -465,6 +475,51 @@ +@@ -511,6 +517,22 @@ } if (options->permit_tun == -1) options->permit_tun = SSH_TUNMODE_NO; @@ -10952,69 +12220,40 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c + debug ("Attempted to enabled None MAC without setting None Enabled to true. None MAC disabled."); + options->nonemac_enabled = 0; + } ++ if (options->tcp_rcv_buf_poll == -1) ++ options->tcp_rcv_buf_poll = 1; ++ if (options->disable_multithreaded == -1) ++ options->disable_multithreaded = 0; + if (options->hpn_disabled == -1) + options->hpn_disabled = 0; -+ if (options->hpn_buffer_limit == -1) -+ options->hpn_buffer_limit = 0; -+ -+ if (options->hpn_buffer_size == -1) { -+ /* option not explicitly set. Now we have to figure out */ -+ /* what value to use */ -+ if (options->hpn_disabled == 1) { -+ options->hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; -+ } else { -+ /* get the current RCV size and set it to that */ -+ /*create a socket but don't connect it */ -+ /* we use that the get the rcv socket size */ -+ sock = socket(AF_INET, SOCK_STREAM, 0); -+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, -+ &socksize, &socksizelen); -+ close(sock); -+ options->hpn_buffer_size = socksize; -+ debug("HPN Buffer Size: %d", options->hpn_buffer_size); -+ } -+ } else { -+ /* we have to do this in case the user sets both values in a contradictory */ -+ /* manner. hpn_disabled overrrides hpn_buffer_size*/ -+ if (options->hpn_disabled <= 0) { -+ if (options->hpn_buffer_size == 0) -+ options->hpn_buffer_size = 1; -+ /* limit the maximum buffer to SSHBUF_SIZE_MAX (currently 256MB) */ -+ if (options->hpn_buffer_size > (SSHBUF_SIZE_MAX / 1024)) { -+ options->hpn_buffer_size = SSHBUF_SIZE_MAX; -+ } else { -+ options->hpn_buffer_size *= 1024; -+ } -+ } else -+ options->hpn_buffer_size = CHAN_TCP_WINDOW_DEFAULT; -+ } -+ ++ if (options->use_mptcp == -1) ++ options->use_mptcp = 0; if (options->ip_qos_interactive == -1) options->ip_qos_interactive = IPTOS_DSCP_AF21; if (options->ip_qos_bulk == -1) -@@ -546,6 +601,8 @@ +@@ -595,6 +617,8 @@ sKerberosGetAFSToken, sKerberosUniqueCCache, sKerberosUseKuserok, sPasswordAuthentication, sKbdInteractiveAuthentication, sListenAddress, sAddressFamily, sPrintMotd, sPrintLastLog, sIgnoreRhosts, -+ sNoneEnabled, sNoneMacEnabled, sHPNBufferLimit, -+ sTcpRcvBufPoll, sHPNDisabled, sHPNBufferSize, ++ sNoneEnabled, sNoneMacEnabled, sTcpRcvBufPoll, sHPNDisabled, ++ sDisableMTAES, sUseMPTCP, sX11Forwarding, sX11DisplayOffset, sX11MaxDisplays, sX11UseLocalhost, sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive, sPermitUserEnvironment, sAllowTcpForwarding, sCompression, -@@ -747,6 +804,12 @@ +@@ -804,6 +828,12 @@ { "revokedkeys", sRevokedKeys, SSHCFG_ALL }, { "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL }, { "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL }, + { "hpndisabled", sHPNDisabled, SSHCFG_ALL }, -+ { "hpnbuffersize", sHPNBufferSize, SSHCFG_ALL }, + { "tcprcvbufpoll", sTcpRcvBufPoll, SSHCFG_ALL }, + { "noneenabled", sNoneEnabled, SSHCFG_ALL }, + { "nonemacenabled", sNoneMacEnabled, SSHCFG_ALL }, -+ { "hpnbufferlimit", sHPNBufferLimit, SSHCFG_ALL }, ++ { "usemptcp", sUseMPTCP, SSHCFG_GLOBAL }, ++ { "disableMTAES", sDisableMTAES, SSHCFG_ALL }, { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL }, { "include", sInclude, SSHCFG_ALL }, { "ipqos", sIPQoS, SSHCFG_ALL }, -@@ -809,6 +872,7 @@ +@@ -869,6 +899,7 @@ for (i = 0; keywords[i].name; i++) if (strcasecmp(cp, keywords[i].name) == 0) { @@ -11022,7 +12261,7 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c *flags = keywords[i].flags; return keywords[i].opcode; } -@@ -1636,12 +1700,36 @@ +@@ -1640,6 +1671,30 @@ multistate_ptr = multistate_ignore_rhosts; goto parse_multistate; @@ -11034,16 +12273,6 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c + intptr = &options->hpn_disabled; + goto parse_flag; + -+ case sHPNBufferSize: -+ intptr = &options->hpn_buffer_size; -+ goto parse_int; -+ - case sIgnoreUserKnownHosts: - intptr = &options->ignore_user_known_hosts; - parse_flag: - multistate_ptr = multistate_flag; - goto parse_multistate; - + case sNoneEnabled: + intptr = &options->none_enabled; + goto parse_flag; @@ -11052,41 +12281,59 @@ diff -Nur openssh-9.3p1.orig/servconf.c openssh-9.3p1/servconf.c + intptr = &options->nonemac_enabled; + goto parse_flag; + -+ case sHPNBufferLimit: -+ intptr = &options->hpn_buffer_limit; -+ goto parse_flag; ++ case sDisableMTAES: ++ intptr = &options->disable_multithreaded; ++ goto parse_flag; + - case sHostbasedAuthentication: - intptr = &options->hostbased_authentication; - goto parse_flag; -diff -Nur openssh-9.3p1.orig/servconf.h openssh-9.3p1/servconf.h ---- openssh-9.3p1.orig/servconf.h 2024-07-10 09:07:09.810082080 +0200 -+++ openssh-9.3p1/servconf.h 2024-07-10 10:19:26.757782065 +0200 -@@ -213,6 +213,12 @@ ++ case sUseMPTCP: ++ intptr = &options->use_mptcp; ++ goto parse_flag; ++ + case sIgnoreUserKnownHosts: + intptr = &options->ignore_user_known_hosts; + parse_flag: +@@ -3434,6 +3489,11 @@ + dump_cfg_fmtint(sStreamLocalBindUnlink, o->fwd_opts.streamlocal_bind_unlink); + dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash); + dump_cfg_fmtint(sExposeAuthInfo, o->expose_userauth_info); ++ dump_cfg_fmtint(sHPNDisabled, o->hpn_disabled); ++ dump_cfg_fmtint(sTcpRcvBufPoll, o->tcp_rcv_buf_poll); ++ dump_cfg_fmtint(sNoneEnabled, o->none_enabled); ++ dump_cfg_fmtint(sNoneMacEnabled, o->nonemac_enabled); ++ dump_cfg_fmtint(sUseMPTCP, o->use_mptcp); + dump_cfg_fmtint(sRefuseConnection, o->refuse_connection); - int use_pam; /* Enable auth via PAM */ + /* string arguments */ +diff -Nur openssh-10.0p1.orig/servconf.h openssh-10.0p1/servconf.h +--- openssh-10.0p1.orig/servconf.h 2025-06-14 10:53:02.023331755 +0200 ++++ openssh-10.0p1/servconf.h 2025-06-14 10:54:01.332534777 +0200 +@@ -227,6 +227,13 @@ + char *pam_service_name; int permit_pam_user_change; /* Allow PAM to change user name */ -+ int tcp_rcv_buf_poll; /* poll tcp rcv window in autotuning kernels*/ + ++ /* hpnssh options */ ++ int tcp_rcv_buf_poll; /* poll tcp rcv window in autotuning kernels*/ + int hpn_disabled; /* disable hpn functionality. false by default */ -+ int hpn_buffer_size; /* set the hpn buffer size - default 3MB */ + int none_enabled; /* Enable NONE cipher switch */ + int nonemac_enabled; /* Enable NONE MAC switch */ -+ int hpn_buffer_limit; /* limit local_window_max to 1/2 receive buffer */ - ++ int use_mptcp; /* Use MPTCP - Linux only */ ++ int disable_multithreaded; /* Disable multithreaded aes-ctr cipher */ int permit_tun; -diff -Nur openssh-9.3p1.orig/serverloop.c openssh-9.3p1/serverloop.c ---- openssh-9.3p1.orig/serverloop.c 2024-07-10 09:07:09.794082033 +0200 -+++ openssh-9.3p1/serverloop.c 2024-07-10 12:49:21.563392024 +0200 -@@ -81,6 +81,7 @@ + char **permitted_opens; /* May also be one of PERMITOPEN_* */ +diff -Nur openssh-10.0p1.orig/serverloop.c openssh-10.0p1/serverloop.c +--- openssh-10.0p1.orig/serverloop.c 2025-06-14 10:53:01.992010916 +0200 ++++ openssh-10.0p1/serverloop.c 2025-06-14 12:39:09.690199658 +0200 +@@ -81,6 +81,8 @@ #include "serverloop.h" #include "ssherr.h" #include "compat.h" +#include "metrics.h" ++#include "cipher-switch.h" extern ServerOptions options; -@@ -347,6 +348,7 @@ +@@ -326,6 +328,7 @@ sigset_t bsigset, osigset; debug("Entering interactive session for SSH2."); @@ -11094,21 +12341,11 @@ diff -Nur openssh-9.3p1.orig/serverloop.c openssh-9.3p1/serverloop.c if (sigemptyset(&bsigset) == -1 || sigaddset(&bsigset, SIGCHLD) == -1) error_f("bsigset setup: %s", strerror(errno)); -@@ -385,7 +387,9 @@ - error_f("osigset sigprocmask: %s", strerror(errno)); - - if (received_sigterm) { -+ sshpkt_final_log_entry(ssh); - logit("Exiting on signal %d", (int)received_sigterm); -+ sshpkt_final_log_entry(ssh); - /* Clean up sessions, utmp, etc. */ - cleanup_exit(255); - } -@@ -403,9 +407,15 @@ +@@ -370,9 +373,15 @@ collect_children(ssh); free(pfd); -+ /* write final log entry */ ++ /* write final log entry (do we need this here? -cjr)*/ + sshpkt_final_log_entry(ssh); + /* free all channels, no more reads and writes */ @@ -11120,28 +12357,16 @@ diff -Nur openssh-9.3p1.orig/serverloop.c openssh-9.3p1/serverloop.c /* free remaining sessions, e.g. remove wtmp entries */ session_destroy_all(ssh, NULL); } -@@ -556,7 +566,8 @@ - debug("Tunnel forwarding using interface %s", ifname); - - c = channel_new(ssh, "tun", SSH_CHANNEL_OPEN, sock, sock, -1, -- CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); -+ options.hpn_disabled ? CHAN_TCP_WINDOW_DEFAULT : options.hpn_buffer_size, -+ CHAN_TCP_PACKET_DEFAULT, 0, "tun", 1); - c->datagram = 1; - #if defined(SSH_TUN_FILTER) - if (mode == SSH_TUNMODE_POINTOPOINT) -@@ -607,6 +618,10 @@ +@@ -574,6 +583,8 @@ c = channel_new(ssh, "session", SSH_CHANNEL_LARVAL, -1, -1, -1, /*window size*/0, CHAN_SES_PACKET_DEFAULT, 0, "server-session", 1); + if ((options.tcp_rcv_buf_poll) && (!options.hpn_disabled)) + c->dynamic_window = 1; -+ if (options.hpn_buffer_limit) -+ c->hpn_buffer_limit = 1; if (session_open(the_authctxt, c->self) != 1) { debug("session open failed, free channel %d", c->self); channel_free(ssh, c); -@@ -675,6 +690,67 @@ +@@ -642,6 +653,67 @@ return 0; } @@ -11209,7 +12434,7 @@ diff -Nur openssh-9.3p1.orig/serverloop.c openssh-9.3p1/serverloop.c static int server_input_hostkeys_prove(struct ssh *ssh, struct sshbuf **respp) { -@@ -854,6 +930,10 @@ +@@ -818,6 +890,10 @@ success = 1; } else if (strcmp(rtype, "hostkeys-prove-00@openssh.com") == 0) { success = server_input_hostkeys_prove(ssh, &resp); @@ -11220,10 +12445,18 @@ diff -Nur openssh-9.3p1.orig/serverloop.c openssh-9.3p1/serverloop.c } /* XXX sshpkt_get_end() */ if (want_reply) { -diff -Nur openssh-9.3p1.orig/session.c openssh-9.3p1/session.c ---- openssh-9.3p1.orig/session.c 2024-07-10 09:07:09.744081887 +0200 -+++ openssh-9.3p1/session.c 2024-07-10 09:09:55.917568452 +0200 -@@ -226,6 +226,7 @@ +diff -Nur openssh-10.0p1.orig/session.c openssh-10.0p1/session.c +--- openssh-10.0p1.orig/session.c 2025-06-14 10:53:01.741334418 +0200 ++++ openssh-10.0p1/session.c 2025-06-14 10:54:01.333888095 +0200 +@@ -94,6 +94,7 @@ + #include "monitor_wrap.h" + #include "sftp.h" + #include "atomicio.h" ++#include "cipher-switch.h" + + #if defined(KRB5) && defined(USE_AFS) + #include +@@ -237,6 +238,7 @@ goto authsock_err; /* Allocate a channel for the authentication agent socket. */ @@ -11231,20 +12464,40 @@ diff -Nur openssh-9.3p1.orig/session.c openssh-9.3p1/session.c nc = channel_new(ssh, "auth-listener", SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, -@@ -2369,7 +2370,8 @@ - channel_set_fds(ssh, s->chanid, - fdout, fdin, fderr, - ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, -- 1, is_tty, CHAN_SES_WINDOW_DEFAULT); -+ 1, is_tty, -+ options.hpn_disabled ? CHAN_SES_WINDOW_DEFAULT : options.hpn_buffer_size); +@@ -564,6 +566,9 @@ + session_set_fds(ssh, s, inout[1], inout[1], err[1], + s->is_subsystem, 0); + #endif ++ /* switch to the parallel ciphers if necessary */ ++ if (options.disable_multithreaded == 0) ++ cipher_switch(ssh); + return 0; } - /* -diff -Nur openssh-9.3p1.orig/sftp.1 openssh-9.3p1/sftp.1 ---- openssh-9.3p1.orig/sftp.1 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/sftp.1 2024-07-10 09:09:55.917568452 +0200 -@@ -299,7 +299,8 @@ +@@ -677,6 +682,9 @@ + ssh_packet_set_interactive(ssh, 1, + options.ip_qos_interactive, options.ip_qos_bulk); + session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1); ++ /* switch to the parallel cipher if appropriate */ ++ if (options.disable_multithreaded == 0) ++ cipher_switch(ssh); + return 0; + } + +diff -Nur openssh-10.0p1.orig/sftp.1 openssh-10.0p1/sftp.1 +--- openssh-10.0p1.orig/sftp.1 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/sftp.1 2025-06-14 10:54:01.334573170 +0200 +@@ -55,6 +55,9 @@ + transport. + It may also use many features of ssh, such as public key authentication and + compression. ++.Nm ++is binary compatible with OpenSSH's sftp and uses the same directive and configuration ++options except where noted. + .Pp + The + .Ar destination +@@ -338,7 +341,8 @@ Specify how many requests may be outstanding at any one time. Increasing this may slightly improve file transfer speed but will increase memory usage. @@ -11254,7 +12507,7 @@ diff -Nur openssh-9.3p1.orig/sftp.1 openssh-9.3p1/sftp.1 .It Fl r Recursively copy entire directories when uploading and downloading. Note that -@@ -328,10 +329,13 @@ +@@ -367,10 +371,13 @@ .It Cm nrequests Ns = Ns Ar value Controls how many concurrent SFTP read or write requests may be in progress at any point in time during a download or upload. @@ -11269,15 +12522,11 @@ diff -Nur openssh-9.3p1.orig/sftp.1 openssh-9.3p1/sftp.1 By default a 32KB buffer is used. .El .El -diff -Nur openssh-9.3p1.orig/sftp.c openssh-9.3p1/sftp.c ---- openssh-9.3p1.orig/sftp.c 2024-07-10 09:07:09.794082033 +0200 -+++ openssh-9.3p1/sftp.c 2024-07-10 09:09:55.918568455 +0200 -@@ -2546,23 +2546,28 @@ - replacearg(&args, 0, "%s", ssh_program); - break; - case 'X': -- /* Please keep in sync with ssh.c -X */ -+ /* Please keep in sync with scp.c -X */ +diff -Nur openssh-10.0p1.orig/sftp.c openssh-10.0p1/sftp.c +--- openssh-10.0p1.orig/sftp.c 2025-06-14 10:53:01.664429990 +0200 ++++ openssh-10.0p1/sftp.c 2025-06-14 10:54:01.335020156 +0200 +@@ -2570,20 +2570,25 @@ + /* Please keep in sync with ssh.c -X */ if (strncmp(optarg, "buffer=", 7) == 0) { r = scan_scaled(optarg + 7, &llv); - if (r == 0 && (llv <= 0 || llv > 256 * 1024)) { @@ -11307,9 +12556,9 @@ diff -Nur openssh-9.3p1.orig/sftp.c openssh-9.3p1/sftp.c "\"%s\": %s", optarg + 10, errstr); } num_requests = (size_t)llv; -diff -Nur openssh-9.3p1.orig/sftp-client.c openssh-9.3p1/sftp-client.c ---- openssh-9.3p1.orig/sftp-client.c 2024-07-10 09:07:09.724081828 +0200 -+++ openssh-9.3p1/sftp-client.c 2024-07-10 09:09:55.919568458 +0200 +diff -Nur openssh-10.0p1.orig/sftp-client.c openssh-10.0p1/sftp-client.c +--- openssh-10.0p1.orig/sftp-client.c 2025-06-14 10:53:01.663814268 +0200 ++++ openssh-10.0p1/sftp-client.c 2025-06-14 10:54:01.335625123 +0200 @@ -72,7 +72,8 @@ #define DEFAULT_COPY_BUFLEN 32768 @@ -11320,10 +12569,25 @@ diff -Nur openssh-9.3p1.orig/sftp-client.c openssh-9.3p1/sftp-client.c /* Minimum amount of data to read at a time */ #define MIN_READ_SIZE 512 -diff -Nur openssh-9.3p1.orig/ssh.1 openssh-9.3p1/ssh.1 ---- openssh-9.3p1.orig/ssh.1 2024-07-10 09:07:09.810082080 +0200 -+++ openssh-9.3p1/ssh.1 2024-07-10 09:09:55.919568458 +0200 -@@ -522,6 +522,7 @@ +diff -Nur openssh-10.0p1.orig/ssh.1 openssh-10.0p1/ssh.1 +--- openssh-10.0p1.orig/ssh.1 2025-06-14 10:53:02.023904385 +0200 ++++ openssh-10.0p1/ssh.1 2025-06-14 11:29:03.370919913 +0200 +@@ -77,6 +77,14 @@ + X11 connections, arbitrary TCP ports and + .Ux Ns -domain + sockets can also be forwarded over the secure channel. ++.Nm ++is binary compatible with the more well known OpenSSH and uses the same configuration ++directives, methods, and keywords except where noted with the exception of the default port. ++HPN-SSH servers, by default, use port 2222 for connection, and as such, ++.Nm ++clients ++attempt to connect on that port. If the connection attempt on port 2222 fails it will fallback to ++port 22. Please see the -p switch for more information. + .Pp + .Nm + connects and logs into the specified +@@ -527,12 +535,14 @@ .It ControlMaster .It ControlPath .It ControlPersist @@ -11331,20 +12595,25 @@ diff -Nur openssh-9.3p1.orig/ssh.1 openssh-9.3p1/ssh.1 .It DynamicForward .It EnableSSHKeysign .It EnableEscapeCommandline -@@ -550,6 +551,9 @@ - .It HostKeyAlgorithms - .It HostKeyAlias + .It EnableSSHKeysign + .It EscapeChar + .It ExitOnForwardFailure ++.It FallbackPort + .It FingerprintHash + .It ForkAfterAuthentication + .It ForwardAgent +@@ -556,6 +566,7 @@ + .It HostbasedAcceptedAlgorithms + .It HostbasedAuthentication .It Hostname +.It HPNDisabled* -+.It HPNBufferLimit* -+.It HPNBufferSize* + .It IPQoS .It IdentitiesOnly .It IdentityAgent - .It IdentityFile -@@ -566,7 +570,13 @@ +@@ -571,7 +582,13 @@ + .It LogLevel .It LogVerbose .It MACs - .It Match +.It Metrics +.It MetricsInterval +.It MetricsPath @@ -11353,38 +12622,54 @@ diff -Nur openssh-9.3p1.orig/ssh.1 openssh-9.3p1/ssh.1 +.It NoneEnabled* +.It NoneMacEnabled* .It NumberOfPasswordPrompts - .It PasswordAuthentication - .It PermitLocalCommand -@@ -597,6 +607,8 @@ + .It ObscureKeystrokeTiming + .It PKCS11Provider +@@ -605,15 +622,19 @@ .It StrictHostKeyChecking .It SyslogFacility .It TCPKeepAlive -+.It TcpRcvBuf* +.It TcpRcvBufPoll* + .It Tag .It Tunnel .It TunnelDevice .It UpdateHostKeys -@@ -605,6 +617,8 @@ ++.It UseMPTCP + .It User + .It UserKnownHostsFile .It VerifyHostKeyDNS .It VisualHostKey .It XAuthLocation +.Pp -+.It * Hpnssh specific configuration option. ++.It * Hpnssh specific configuration option. .El .Pp - .It Fl p Ar port -@@ -1811,3 +1825,7 @@ + .It Fl P Ar tag +@@ -630,6 +651,13 @@ + Port to connect to on the remote host. + This can be specified on a + per-host basis in the configuration file. ++HPN-SSH uses a default port of 2222. It will automatically ++fallback to use the SSH standard port 22 if it cannot connect ++on port 2222. This fallback behaviour can be modified with the ++FallbackPort option. Note: if outbound port 2222 is ++blocked it may appear that the hpnssh client is non-responsive. In that event, ++either specify the correct port or use the ConnectTimeout option ++to trigger the port fallback more quickly. + .Pp + .It Fl Q Ar query_option + Queries for the algorithms supported by one of the following features: +@@ -1821,3 +1849,7 @@ created OpenSSH. Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. +Chris Rapier, Michael Stevens, Ben Bennet, and Mike Tasota developed +the HPN extensions at the Pittsburgh Supercomuting Center with grants +from Cisco, the National Library of Medicine, and the National Science -+Foundation. -diff -Nur openssh-9.3p1.orig/ssh_api.c openssh-9.3p1/ssh_api.c ---- openssh-9.3p1.orig/ssh_api.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/ssh_api.c 2024-07-10 09:09:55.919568458 +0200 -@@ -410,7 +410,7 @@ ++Foundation. +diff -Nur openssh-10.0p1.orig/ssh_api.c openssh-10.0p1/ssh_api.c +--- openssh-10.0p1.orig/ssh_api.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/ssh_api.c 2025-06-14 10:54:01.337078874 +0200 +@@ -427,7 +427,7 @@ char *cp; int r; @@ -11393,43 +12678,29 @@ diff -Nur openssh-9.3p1.orig/ssh_api.c openssh-9.3p1/ssh_api.c return r; if ((r = sshbuf_putb(ssh_packet_get_output(ssh), banner)) != 0) return r; -diff -Nur openssh-9.3p1.orig/sshbuf.c openssh-9.3p1/sshbuf.c ---- openssh-9.3p1.orig/sshbuf.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/sshbuf.c 2024-07-10 09:09:55.920568461 +0200 -@@ -27,6 +27,20 @@ +diff -Nur openssh-10.0p1.orig/sshbuf.c openssh-10.0p1/sshbuf.c +--- openssh-10.0p1.orig/sshbuf.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/sshbuf.c 2025-06-14 10:54:01.337433040 +0200 +@@ -27,6 +27,9 @@ #define SSHBUF_INTERNAL #include "sshbuf.h" #include "misc.h" +/* #include "log.h" */ + +#define BUF_WATERSHED 256*1024 -+ -+#ifdef SSHBUF_DEBUG -+# define SSHBUF_TELL(what) do { \ -+ printf("%s:%d %s: %s size %zu alloc %zu off %zu max %zu\n", \ -+ __FILE__, __LINE__, __func__, what, \ -+ buf->size, buf->alloc, buf->off, buf->max_size); \ -+ fflush(stdout); \ -+ } while (0) -+#else -+# define SSHBUF_TELL(what) -+#endif #ifdef SSHBUF_DEBUG # define SSHBUF_TELL(what) do { \ -@@ -45,12 +59,27 @@ - size_t off; /* First available byte is buf->d + buf->off */ - size_t size; /* Last byte is buf->d + buf->size - 1 */ - size_t max_size; /* Maximum size of buffer */ -+ size_t window_max; /* channel window max */ - size_t alloc; /* Total bytes allocated to buf->d */ +@@ -49,8 +52,29 @@ int readonly; /* Refers to external, const data */ u_int refcount; /* Tracks self and number of child buffers */ struct sshbuf *parent; /* If child, pointer to parent */ + char label[MAX_LABEL_LEN]; /* String for buffer label - debugging use */ -+ struct timeval buf_ts; /* creation time of buffer */ ++ int type; /* type of buffer enum (sshbuf_types)*/ }; ++/* update the label string for a given sshbuf. Useful ++ * for debugging */ +void +sshbuf_relabel(struct sshbuf *buf, const char *label) +{ @@ -11437,15 +12708,20 @@ diff -Nur openssh-9.3p1.orig/sshbuf.c openssh-9.3p1/sshbuf.c + strncpy(buf->label, label, MAX_LABEL_LEN-1); +} + -+float time_diff(struct timeval *start, struct timeval *end) ++/* set the type (from enum sshbuf_type) of the given sshbuf. ++ * The purpose is to allow different classes of buffers to ++ * follow different code paths if necessary */ ++void ++sshbuf_type(struct sshbuf *buf, int type) +{ -+ return (end->tv_sec - start->tv_sec) + 1e-6*(end->tv_usec - start->tv_usec); ++ if (type < BUF_MAX_TYPE) ++ buf->type = type; +} + static inline int sshbuf_check_sanity(const struct sshbuf *buf) { -@@ -89,7 +118,7 @@ +@@ -90,7 +114,7 @@ } struct sshbuf * @@ -11454,7 +12730,7 @@ diff -Nur openssh-9.3p1.orig/sshbuf.c openssh-9.3p1/sshbuf.c { struct sshbuf *ret; -@@ -100,6 +129,8 @@ +@@ -101,6 +125,8 @@ ret->readonly = 0; ret->refcount = 1; ret->parent = NULL; @@ -11463,99 +12739,27 @@ diff -Nur openssh-9.3p1.orig/sshbuf.c openssh-9.3p1/sshbuf.c if ((ret->cd = ret->d = calloc(1, ret->alloc)) == NULL) { free(ret); return NULL; -@@ -218,7 +249,7 @@ - size_t - sshbuf_max_size(const struct sshbuf *buf) - { -- return buf->max_size; -+ return buf->max_size / 2; - } - - size_t -@@ -240,13 +271,18 @@ - } - - int --sshbuf_set_max_size(struct sshbuf *buf, size_t max_size) -+sshbuf_set_max_size(struct sshbuf *buf, size_t requested_size) - { -- size_t rlen; -+ size_t rlen, max_size = requested_size * 2; - u_char *dp; - int r; - -- SSHBUF_DBG(("set max buf = %p len = %zu", buf, max_size)); -+ /* -+ * Note that we set the actual allocation limit to be 2x the requested -+ * size. This is to avoid some pathological compaction behaviour later -+ * when a buffer is at capacity and has small drains/fills on it. -+ */ -+ SSHBUF_DBG(("set max buf = %p requested = %zu", buf, requested_size)); - if ((r = sshbuf_check_sanity(buf)) != 0) - return r; - if (max_size == buf->max_size) -@@ -255,9 +291,17 @@ - return SSH_ERR_BUFFER_READ_ONLY; - if (max_size > SSHBUF_SIZE_MAX) - return SSH_ERR_NO_BUFFER_SPACE; -- /* pack and realloc if necessary */ -- sshbuf_maybe_pack(buf, max_size < buf->size); -- if (max_size < buf->alloc && max_size > buf->size) { -+ /* -+ * Always pack as it makes everything that follows easier. -+ * Potentially expensive, but this should seldom be called on buffers -+ * that already contain data. -+ */ -+ sshbuf_maybe_pack(buf, 1); -+ /* Refuse setting a maximum below current amount of data in buffer */ -+ if (requested_size < buf->size) -+ return SSH_ERR_NO_BUFFER_SPACE; -+ /* Shrink alloc if the existing allocation is larger than requested */ -+ if (requested_size < buf->alloc) { - if (buf->size < SSHBUF_SIZE_INIT) - rlen = SSHBUF_SIZE_INIT; - else -@@ -271,8 +315,6 @@ - buf->alloc = rlen; - } - SSHBUF_TELL("new-max"); -- if (max_size < buf->alloc) -- return SSH_ERR_NO_BUFFER_SPACE; - buf->max_size = max_size; - return 0; - } -@@ -290,7 +332,7 @@ +@@ -290,7 +316,18 @@ { if (sshbuf_check_sanity(buf) != 0 || buf->readonly || buf->refcount > 1) return 0; - return buf->max_size - (buf->size - buf->off); -+ return (buf->max_size / 2) - (buf->size - buf->off); ++ /* we need to reserve a small amount of overhead on the input buffer ++ * or we can enter into a pathological state during bulk ++ * data transfers. We use a fraction of the max size as we want it to scale ++ * with the size of the input buffer. If we do it for all of the buffers ++ * we fail the regression unit tests. This seems like a reasonable ++ * solution. Of course, I still need to figure out *why* this is ++ * happening and come up with an actual fix. TODO ++ * cjr 4/19/2024 */ ++ if (buf->type == BUF_CHANNEL_INPUT) ++ return buf->max_size / 1.05 - (buf->size - buf->off); ++ else ++ return buf->max_size - (buf->size - buf->off); } const u_char * -@@ -319,12 +361,19 @@ - if (buf->readonly || buf->refcount > 1) - return SSH_ERR_BUFFER_READ_ONLY; - SSHBUF_TELL("check"); -- /* Check that len is reasonable and that max_size + available < len */ -- if (len > buf->max_size || buf->max_size - len < buf->size - buf->off) -+ /* Check that len is reasonable and that max size + available < len */ -+ if (len > (buf->max_size / 2) || -+ (buf->max_size / 2) - len < buf->size - buf->off) - return SSH_ERR_NO_BUFFER_SPACE; - return 0; - } - -+void -+sshbuf_set_window_max(struct sshbuf *buf, size_t len) -+{ -+ buf->window_max = len; -+} -+ - int - sshbuf_allocate(struct sshbuf *buf, size_t len) - { -@@ -350,9 +399,42 @@ +@@ -350,9 +387,36 @@ */ need = len + buf->size - buf->alloc; rlen = ROUNDUP(buf->alloc + need, SSHBUF_SIZE_INC); @@ -11563,66 +12767,70 @@ diff -Nur openssh-9.3p1.orig/sshbuf.c openssh-9.3p1/sshbuf.c + * slowly. It's knows that it needs to grow but it only does so 32K + * at a time. This means a lot of calls to realloc and memcpy which + * kills performance until the buffer reaches some maximum size. -+ * so we explicitly test for a buffer that's trying to grow and -+ * if it is then we push the growth to whatever the adjusted value of -+ * local_window_max happens to be. This significantly reduces overhead ++ * So we explicitly test for a buffer that's trying to grow and ++ * if it is then we push the growth by 4MB at a time. This can result in ++ * the buffer being over allocated (in terms of actual needs) but the ++ * process is fast. This significantly reduces overhead + * and improves performance. In this case we look for a buffer that is trying + * to grow larger than BUF_WATERSHED (256*1024 taken from PACKET_MAX_SIZE) -+ * and where the local_window_max isn't zero (which is usally in the Channels -+ * struct but we copied it into the shhbuf as window_max). If it is zero or -+ * the buffer is smaller than BUF_WATERSHED we just use the -+ * normal value for need. We also don't want to grow the buffer past -+ * what we need (the size of window_max) so if the current allocation (in -+ * buf->alloc) is greater than window_max we skip it. -+ * -+ * Turns out the extra functions on the following conditional aren't needed -+ * -cjr 04/06/23 ++ * and explcitly check that the buffer is being used for inbound outbound ++ * channel buffering. ++ * Updated for 18.4.1 -cjr 04/20/24 + */ -+ if (rlen > BUF_WATERSHED) { -+ /* debug_f ("Prior: label: %s, %p, rlen is %zu need is %zu win_max is %zu max_size is %zu", -+ buf->label, buf, rlen, need, buf->window_max, buf->max_size); */ ++ if (rlen > BUF_WATERSHED && (buf->type == BUF_CHANNEL_OUTPUT || buf->type == BUF_CHANNEL_INPUT)) { ++ /* debug_f ("Prior: label: %s, %p, rlen is %zu need is %zu max_size is %zu", ++ buf->label, buf, rlen, need, buf->max_size); */ + /* easiest thing to do is grow the nuffer by 4MB each time. It might end + * up being somewhat overallocated but works quickly */ + need = (4*1024*1024); + rlen = ROUNDUP(buf->alloc + need, SSHBUF_SIZE_INC); -+ /* debug_f ("Post: label: %s, %p, rlen is %zu need is %zu win_max is %zu max_size is %zu", */ -+ /* buf->label, buf, rlen, need, buf->window_max, buf->max_size); */ ++ /* debug_f ("Post: label: %s, %p, rlen is %zu need is %zu max_size is %zu", */ ++ /* buf->label, buf, rlen, need, buf->max_size); */ + } SSHBUF_DBG(("need %zu initial rlen %zu", need, rlen)); -- if (rlen > buf->max_size) -- rlen = buf->alloc + need; + + /* rlen might be above the max allocation */ -+ if (rlen > buf->max_size) { + if (rlen > buf->max_size) +- rlen = buf->alloc + need; + rlen = buf->max_size; -+ /* debug_f("set rlen to %zu", buf->max_size);*/ -+ } ++ SSHBUF_DBG(("adjusted rlen %zu", rlen)); if ((dp = recallocarray(buf->d, buf->alloc, rlen, 1)) == NULL) { SSHBUF_DBG(("realloc fail")); -diff -Nur openssh-9.3p1.orig/sshbuf.h openssh-9.3p1/sshbuf.h ---- openssh-9.3p1.orig/sshbuf.h 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/sshbuf.h 2024-07-10 09:09:55.920568461 +0200 -@@ -28,10 +28,12 @@ +diff -Nur openssh-10.0p1.orig/sshbuf.h openssh-10.0p1/sshbuf.h +--- openssh-10.0p1.orig/sshbuf.h 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/sshbuf.h 2025-06-14 10:54:01.337808997 +0200 +@@ -29,18 +29,49 @@ # endif /* OPENSSL_HAS_ECC */ #endif /* WITH_OPENSSL */ -#define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size */ -+#define SSHBUF_SIZE_MAX 0xFFFFFFF /* Hard maximum size 256MB */ ++#define SSHBUF_SIZE_MAX 0x8000000 /* Hard maximum size 128MB */ #define SSHBUF_REFS_MAX 0x100000 /* Max child buffers */ #define SSHBUF_MAX_BIGNUM (16384 / 8) /* Max bignum *bytes* */ #define SSHBUF_MAX_ECPOINT ((528 * 2 / 8) + 1) /* Max EC point *bytes* */ -+#define MAX_LABEL_LEN 64 /*maximum size of sshbuf label */ ++#define MAX_LABEL_LEN 64 /*maximum size of sshbuf label */ +#define sshbuf_new() sshbuf_new_label(__func__) struct sshbuf; -@@ -39,7 +41,18 @@ ++enum buffer_types { ++ BUF_CHANNEL_OUTPUT, ++ BUF_CHANNEL_INPUT, ++ BUF_CHANNEL_EXTENDED, ++ BUF_PACKET_INPUT, ++ BUF_PACKET_INCOMING, ++ BUF_PACKET_OUTPUT, ++ BUF_PACKET_OUTGOING, ++ BUF_MAX_TYPE ++}; ++ + /* * Create a new sshbuf buffer. * Returns pointer to buffer on success, or NULL on allocation failure. */ -struct sshbuf *sshbuf_new(void); -+/* struct sshbuf *sshbuf_new(void); */ ++/* struct sshbuf *sshbuf_new(void);*/ + +/* + * Create a new labeled sshbuf buffer. @@ -11634,10 +12842,17 @@ diff -Nur openssh-9.3p1.orig/sshbuf.h openssh-9.3p1/sshbuf.h + * relabel the sshbuf struct + */ +void sshbuf_relabel(struct sshbuf *, const char *); ++ ++/* ++ * assign a type (from the buffer_types enum) to ++ * the buffer. Used to quickly identify the purpose of ++ * the buffer. ++ */ ++void sshbuf_type(struct sshbuf *, int); /* * Create a new, read-only sshbuf buffer from existing data. -@@ -75,12 +88,13 @@ +@@ -76,12 +107,13 @@ void sshbuf_reset(struct sshbuf *buf); /* @@ -11653,7 +12868,7 @@ diff -Nur openssh-9.3p1.orig/sshbuf.h openssh-9.3p1/sshbuf.h * Returns 0 on success, or a negative SSH_ERR_* error code on failure. */ int sshbuf_set_max_size(struct sshbuf *buf, size_t max_size); -@@ -344,6 +358,9 @@ +@@ -346,6 +378,9 @@ ((u_char *)(p))[1] = __v & 0xff; \ } while (0) @@ -11663,10 +12878,18 @@ diff -Nur openssh-9.3p1.orig/sshbuf.h openssh-9.3p1/sshbuf.h /* Internal definitions follow. Exposed for regress tests */ #ifdef SSHBUF_INTERNAL -diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c ---- openssh-9.3p1.orig/ssh.c 2024-07-10 09:07:09.811082083 +0200 -+++ openssh-9.3p1/ssh.c 2024-07-10 09:09:55.921568464 +0200 -@@ -1104,6 +1104,10 @@ +diff -Nur openssh-10.0p1.orig/ssh.c openssh-10.0p1/ssh.c +--- openssh-10.0p1.orig/ssh.c 2025-06-14 10:53:02.024428197 +0200 ++++ openssh-10.0p1/ssh.c 2025-06-14 11:26:41.535259834 +0200 +@@ -111,6 +111,7 @@ + #include "myproposal.h" + #include "utf8.h" + #include "hostfile.h" ++#include "cipher-switch.h" + + #ifdef ENABLE_PKCS11 + #include "ssh-pkcs11.h" +@@ -1122,6 +1123,10 @@ break; case 'T': options.request_tty = REQUEST_TTY_NO; @@ -11677,8 +12900,8 @@ diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c break; case 'o': line = xstrdup(optarg); -@@ -1649,10 +1653,36 @@ - timeout_ms = options.connection_timeout * 1000; +@@ -1743,10 +1748,36 @@ + } /* Open a connection to the remote host. */ + /* we try initially on the default hpnssh port returned by @@ -11715,102 +12938,82 @@ diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c if (addrs != NULL) freeaddrinfo(addrs); -@@ -2171,6 +2201,82 @@ +@@ -1957,7 +1988,7 @@ + + /* Do fork() after authentication. Used by "ssh -f" */ + static void +-fork_postauth(void) ++fork_postauth(struct ssh *ssh) + { + if (need_controlpersist_detach) + control_persist_detach(); +@@ -1967,17 +1998,21 @@ + fatal("daemon() failed: %.200s", strerror(errno)); + if (stdfd_devnull(1, 1, !(log_is_on_stderr() && debug_flag)) == -1) + error_f("stdfd_devnull failed"); ++ /* we do the cipher switch here in the event that the client ++ is forking or has a delayed fork */ ++ if (options.disable_multithreaded == 0) ++ cipher_switch(ssh); + } + + static void +-forwarding_success(void) ++forwarding_success(struct ssh *ssh) + { + if (forward_confirms_pending == -1) + return; + if (--forward_confirms_pending == 0) { + debug_f("all expected forwarding replies received"); + if (options.fork_after_authentication) +- fork_postauth(); ++ fork_postauth(ssh); + } else { + debug2_f("%d expected forwarding replies remaining", + forward_confirms_pending); +@@ -2044,7 +2079,7 @@ + "for listen port %d", rfwd->listen_port); + } + } +- forwarding_success(); ++ forwarding_success(ssh); + } + + static void +@@ -2071,7 +2106,7 @@ + } + + debug_f("tunnel forward established, id=%d", id); +- forwarding_success(); ++ forwarding_success(ssh); + } + + static void +@@ -2272,6 +2307,15 @@ NULL, fileno(stdin), command, environ); } ++/* this used to do a lot more but now it just checks to see ++ * if we are disabling hpn */ +static void +hpn_options_init(struct ssh *ssh) +{ -+ /* -+ * We need to check to see if what they want to do about buffer -+ * sizes here. In a hpn to nonhpn connection we want to limit -+ * the window size to something reasonable in case the far side -+ * has the large window bug. In hpn to hpn connection we want to -+ * use the max window size but allow the user to override it -+ * lastly if they disabled hpn then use the ssh std window size. -+ * -+ * So why don't we just do a getsockopt() here and set the -+ * ssh window to that? In the case of a autotuning receive -+ * window the window would get stuck at the initial buffer -+ * size generally less than 96k. Therefore we need to set the -+ * maximum ssh window size to the maximum hpn buffer size -+ * unless the user has specifically set the tcprcvbufpoll -+ * to no. In which case we *can* just set the window to the -+ * minimum of the hpn buffer size and tcp receive buffer size. -+ */ -+ -+ if (tty_flag) -+ options.hpn_buffer_size = CHAN_SES_WINDOW_DEFAULT; -+ else -+ options.hpn_buffer_size = 2 * 1024 * 1024; -+ -+ if (ssh->compat & SSH_BUG_LARGEWINDOW) { -+ debug("HPN to Non-HPN connection"); -+ } else { -+ debug("HPN to HPN connection"); -+ if (ssh->compat & SSH_HPNSSH) { -+ debug("Using 'hpn' prefixed binaries"); -+ } -+ int sock, socksize; -+ socklen_t socksizelen; -+ if (options.tcp_rcv_buf_poll <= 0) { -+ sock = socket(AF_INET, SOCK_STREAM, 0); -+ socksizelen = sizeof(socksize); -+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, -+ &socksize, &socksizelen); -+ close(sock); -+ debug("socksize %d", socksize); -+ options.hpn_buffer_size = socksize; -+ debug("HPNBufferSize set to TCP RWIN: %d", options.hpn_buffer_size); -+ } else { -+ if (options.tcp_rcv_buf > 0) { -+ /* -+ * Create a socket but don't connect it: -+ * we use that the get the rcv socket size -+ */ -+ sock = socket(AF_INET, SOCK_STREAM, 0); -+ /* -+ * If they are using the tcp_rcv_buf option, -+ * attempt to set the buffer size to that. -+ */ -+ if (options.tcp_rcv_buf) { -+ socksizelen = sizeof(options.tcp_rcv_buf); -+ setsockopt(sock, SOL_SOCKET, SO_RCVBUF, -+ &options.tcp_rcv_buf, socksizelen); -+ } -+ socksizelen = sizeof(socksize); -+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, -+ &socksize, &socksizelen); -+ close(sock); -+ debug("socksize %d", socksize); -+ options.hpn_buffer_size = socksize; -+ debug("HPNBufferSize set to user TCPRcvBuf: %d", options.hpn_buffer_size); -+ } -+ } -+ } -+ -+ debug("Final hpn_buffer_size = %d", options.hpn_buffer_size); -+ -+ channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); ++ channel_set_hpn_disabled(options.hpn_disabled); ++ debug_f("HPN disabled: %d", options.hpn_disabled); +} + /* open new channel for a session */ static int ssh_session2_open(struct ssh *ssh) -@@ -2189,9 +2295,10 @@ - if (in == -1 || out == -1 || err == -1) - fatal("dup() in/out/err failed"); - -- window = CHAN_SES_WINDOW_DEFAULT; -+ window = options.hpn_buffer_size; +@@ -2293,6 +2337,7 @@ + window = CHAN_SES_WINDOW_DEFAULT; packetmax = CHAN_SES_PACKET_DEFAULT; if (tty_flag) { + window = CHAN_SES_WINDOW_DEFAULT; window >>= 1; packetmax >>= 1; } -@@ -2200,6 +2307,16 @@ +@@ -2301,6 +2346,12 @@ window, packetmax, CHAN_EXTENDED_WRITE, "client-session", CHANNEL_NONBLOCK_STDIO); @@ -11819,16 +13022,12 @@ diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c + c->dynamic_window = 1; + debug("Enabled Dynamic Window Scaling"); + } -+ -+ if (options.hpn_buffer_limit) -+ c->hpn_buffer_limit = 1; -+ + debug3_f("channel_new: %d", c->self); channel_send_open(ssh, c->self); -@@ -2216,6 +2333,13 @@ - int r, id = -1; +@@ -2317,6 +2368,13 @@ + int r, interactive, id = -1; char *cp, *tun_fwd_ifname = NULL; + /* @@ -11841,9 +13040,36 @@ diff -Nur openssh-9.3p1.orig/ssh.c openssh-9.3p1/ssh.c /* XXX should be pre-session */ if (!options.control_persist) ssh_init_stdio_forwarding(ssh); -diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 ---- openssh-9.3p1.orig/ssh_config.5 2024-07-10 09:07:09.811082083 +0200 -+++ openssh-9.3p1/ssh_config.5 2024-07-10 09:09:55.921568464 +0200 +@@ -2415,7 +2473,14 @@ + debug("deferring postauth fork until remote forward " + "confirmation received"); + } else +- fork_postauth(); ++ fork_postauth(ssh); ++ } else { ++ /* check to see if we are switching ciphers to ++ * one of our parallel versions. If the client is ++ * forking then we handle it in fork_postauth() ++ */ ++ if (options.disable_multithreaded == 0) ++ cipher_switch(ssh); + } + + return client_loop(ssh, tty_flag, tty_flag ? +diff -Nur openssh-10.0p1.orig/ssh_config openssh-10.0p1/ssh_config +--- openssh-10.0p1.orig/ssh_config 2025-06-14 10:53:02.024947608 +0200 ++++ openssh-10.0p1/ssh_config 2025-06-14 11:01:39.412445292 +0200 +@@ -46,6 +46,7 @@ + # ProxyCommand ssh -q -W %h:%p gateway.example.com + # RekeyLimit 1G 1h + # UserKnownHostsFile ~/.ssh/known_hosts.d/%k ++# UseMPTCP no + # + # This system is following system-wide crypto policy. + # To modify the crypto properties (Ciphers, MACs, ...), create a *.conf +diff -Nur openssh-10.0p1.orig/ssh_config.5 openssh-10.0p1/ssh_config.5 +--- openssh-10.0p1.orig/ssh_config.5 2025-06-14 10:53:02.025331736 +0200 ++++ openssh-10.0p1/ssh_config.5 2025-06-14 10:54:01.339955855 +0200 @@ -62,6 +62,19 @@ .Pq Pa /etc/ssh/ssh_config .El @@ -11859,24 +13085,22 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 +use +.Xr hpnssh 1 +specific directives in their default ssh_config files or ensure that they always use a -+custom config file. ++custom config file. +.Pp Unless noted otherwise, for each parameter, the first obtained value will be used. The configuration files contain sections separated by -@@ -611,6 +624,11 @@ - then the backgrounded master connection will automatically terminate - after it has remained idle (with no client connections) for the - specified time. -+.It Cm DisableMTAES -+Switch the encryption cipher being used from the multithreaded MT-AES-CTR cipher -+back to the stock single-threaded AES-CTR cipher. This may prove to be more -+effcient in some circumstances. Default is -+.Cm no. HPNSSH only. - .It Cm DynamicForward - Specifies that a TCP port on the local machine be forwarded - over the secure channel, and the application -@@ -1022,6 +1040,28 @@ +@@ -833,6 +846,9 @@ + or + .Cm no + (the default). ++.It Cm FallbackPort ++Specifies the port hpnssh should try to connect to if it fails connecting to the ++default hpnsshd port of 2222. The default is port 22. HPN-SSH only. + .It Cm FingerprintHash + Specifies the hash algorithm used when displaying key fingerprints. + Valid options are: +@@ -1159,6 +1175,11 @@ .Cm Hostname specifications). The default is the name given on the command line. @@ -11885,27 +13109,10 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 +of the HPN code produces a net decrease in performance. In these cases it is +helpful to disable the HPN functionality. By default HPNDisabled is set to +.Cm no. HPNSSH only. -+.It Cm HPNBufferLimit -+This option will force the hpnssh receive buffer to grow more slowly and limits -+the growth to one half of the TCP receive buffer. This option can prove useful -+in situation where a high speed path with larger RTTs are writing to a slower -+device or file system. Enabling this option will reduce performance but may provide -+a more stable connection. The option only impacts the receiving side of the connection. -+For example, a client receiving data from a server but not a client sending data. -+By default this option is set to -+.Cm no. HPNSSH only. -+.It Cm HPNBufferSize -+This is the default buffer size, in kilobytes, the HPN functionality uses when interacting -+with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf -+option as applied to the internal SSH flow control. This value can range from -+1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance -+problems depending on the length of the network path. The default size of this buffer -+is 2MB. -+.Cm HPNSSH only. .It Cm IdentitiesOnly Specifies that .Xr ssh 1 -@@ -1392,6 +1432,63 @@ +@@ -1547,6 +1568,63 @@ .Pp The list of available MAC algorithms may also be obtained using .Qq ssh -Q mac . @@ -11969,7 +13176,7 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 .It Cm NoHostAuthenticationForLocalhost Disable host authentication for localhost (loopback addresses). The argument to this keyword must be -@@ -1399,6 +1496,36 @@ +@@ -1554,6 +1632,36 @@ or .Cm no (the default). @@ -12006,19 +13213,10 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 .It Cm NumberOfPasswordPrompts Specifies the number of password prompts before giving up. The argument to this keyword must be an integer. -@@ -1925,6 +2052,21 @@ - See also - .Cm ServerAliveInterval - for protocol-level keepalives. -+.It Cm TcpRcvBuf -+Set the TCP socket receive buffer to n Kilobytes. It can be set up to the -+maximum socket size allowed by the system. This is useful in situations where -+the tcp receive window is set low but the maximum buffer size is set -+higher (as is typical). This works on a per TCP connection basis. You can also -+use this to artifically limit the transfer rate of the connection. In these -+cases the throughput will be no more than n/RTT. The minimum buffer size is 1KB. -+Default is the current system wide tcp receive buffer size. -+.Cm HPNSSH only. +@@ -2124,6 +2232,12 @@ + Specify a configuration tag name that may be later used by a + .Cm Match + directive to select a block of configuration. +.It Cm TcpRcvBufPoll +Enable of disable the polling of the tcp receive buffer through the life +of the connection. You would want to make sure that this option is enabled @@ -12028,7 +13226,20 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 .It Cm Tunnel Request .Xr tun 4 -@@ -2267,3 +2409,11 @@ +@@ -2209,6 +2323,12 @@ + from OpenSSH 6.8 and greater support the + .Qq hostkeys@openssh.com + protocol extension used to inform the client of all the server's hostkeys. ++.It Cm UseMPTCP ++If set to ++.Cm yes , ++this will enable Multipath TCP (MPTCP) instead of TCP (this only works on Linux). ++The default is ++.Cm no . + .It Cm User + Specifies the user to log in as. + This can be useful when a different user name is used on different machines. +@@ -2497,3 +2617,11 @@ created OpenSSH. .An Markus Friedl contributed the support for SSH protocol versions 1.5 and 2.0. @@ -12040,10 +13251,18 @@ diff -Nur openssh-9.3p1.orig/ssh_config.5 openssh-9.3p1/ssh_config.5 +developed the HPN extensions at the Pittsburgh Supercomuting Center +with grants from Cisco, the National Library of Medicine, and +the National Science Foundation. -diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c ---- openssh-9.3p1.orig/sshconnect2.c 2024-07-10 09:07:09.812082086 +0200 -+++ openssh-9.3p1/sshconnect2.c 2024-07-10 09:09:55.922568467 +0200 -@@ -85,6 +85,13 @@ +diff -Nur openssh-10.0p1.orig/sshconnect2.c openssh-10.0p1/sshconnect2.c +--- openssh-10.0p1.orig/sshconnect2.c 2025-06-14 10:53:02.025925109 +0200 ++++ openssh-10.0p1/sshconnect2.c 2025-06-14 10:54:01.340908632 +0200 +@@ -76,6 +76,7 @@ + #include "utf8.h" + #include "ssh-sk.h" + #include "sk-api.h" ++#include "cipher-switch.h" + + #ifdef GSSAPI + #include "ssh-gss.h" +@@ -85,6 +86,13 @@ extern Options options; /* @@ -12057,7 +13276,7 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c * SSH2 key exchange */ -@@ -576,6 +583,60 @@ +@@ -574,6 +582,42 @@ if (!authctxt.success) fatal("Authentication failed."); @@ -12074,7 +13293,8 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c + if (!tty_flag) { /* no null on tty sessions */ + debug("Requesting none rekeying..."); + kex_proposal_populate_entries(ssh, myproposal, s, none_cipher, -+ options.macs, compression_alg_list(options.compression), ++ options.macs, ++ compression_alg_list(options.compression), + options.hostkeyalgorithms); + fprintf(stderr, "WARNING: ENABLED NONE CIPHER!!!\n"); + @@ -12082,7 +13302,8 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c + if (options.nonemac_enabled == 1) { + const char *none_mac = "none"; + kex_proposal_populate_entries(ssh, myproposal, s, none_cipher, -+ none_mac, compression_alg_list(options.compression), ++ none_mac, ++ compression_alg_list(options.compression), + options.hostkeyalgorithms); + fprintf(stderr, "WARNING: ENABLED NONE MAC\n"); + } @@ -12094,78 +13315,33 @@ diff -Nur openssh-9.3p1.orig/sshconnect2.c openssh-9.3p1/sshconnect2.c + fprintf(stderr, "NONE cipher switch disabled when a TTY is allocated\n"); + } + } -+ -+#ifdef WITH_OPENSSL -+ /* if we are using aes-ctr there can be issues in either a fork or sandbox -+ * so the initial aes-ctr is defined to point to the original single process -+ * evp. After authentication we'll be past the fork and the sandboxed privsep -+ * so we repoint the define to the multithreaded evp. To start the threads we -+ * then force a rekey -+ */ -+ /* We now explicitly call the mt cipher in cipher.c so we don't need -+ * the cipher_reset_multithreaded() anymore. We just need to -+ * force a rekey -cjr 09/08/2022 */ -+ const void *cc = ssh_packet_get_send_context(ssh); -+ /* only do this for the ctr cipher. otherwise gcm mode breaks. */ -+ if (strstr(cipher_ctx_name(cc), "ctr")) { -+ debug("Single to Multithread CTR cipher swap - client request"); -+ /* cipher_reset_multithreaded(); */ -+ ssh_packet_set_authenticated(ssh); -+ packet_request_rekeying(); -+ } -+#endif + if (ssh_packet_connection_is_on_socket(ssh)) { verbose("Authenticated to %s ([%s]:%d) using \"%s\".", host, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh), -diff -Nur openssh-9.3p1.orig/sshconnect.c openssh-9.3p1/sshconnect.c ---- openssh-9.3p1.orig/sshconnect.c 2024-07-10 09:07:09.685081714 +0200 -+++ openssh-9.3p1/sshconnect.c 2024-07-10 09:09:55.922568467 +0200 -@@ -344,6 +344,30 @@ +diff -Nur openssh-10.0p1.orig/sshconnect.c openssh-10.0p1/sshconnect.c +--- openssh-10.0p1.orig/sshconnect.c 2025-06-14 10:53:01.488393170 +0200 ++++ openssh-10.0p1/sshconnect.c 2025-06-14 10:54:01.341617244 +0200 +@@ -359,9 +359,14 @@ #endif + char ntop[NI_MAXHOST]; - /* -+ * Set TCP receive buffer if requested. -+ * Note: tuning needs to happen after the socket is -+ * created but before the connection happens -+ * so winscale is negotiated properly -cjr -+ */ -+static void -+ssh_set_socket_recvbuf(int sock) -+{ -+ void *buf = (void *)&options.tcp_rcv_buf; -+ int sz = sizeof(options.tcp_rcv_buf); -+ int socksize; -+ int socksizelen = sizeof(int); -+ -+ debug("setsockopt Attempting to set SO_RCVBUF to %d", options.tcp_rcv_buf); -+ if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF, buf, sz) >= 0) { -+ getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &socksize, &socksizelen); -+ debug("setsockopt SO_RCVBUF: %.100s %d", strerror(errno), socksize); -+ } +- sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); ++ if (options.use_mptcp) ++ sock = socket(ai->ai_family, ai->ai_socktype, IPPROTO_MPTCP); + else -+ error("Couldn't set socket receive buffer to %d: %.100s", -+ options.tcp_rcv_buf, strerror(errno)); -+} -+ -+/* - * Creates a socket for use as the ssh connection. - */ - static int -@@ -365,6 +389,9 @@ ++ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (sock == -1) { + error("socket: %s", strerror(errno)); ++ if (options.use_mptcp) ++ error ("You asked to use MPTCP. Please ensure it is enabled."); + return -1; } (void)fcntl(sock, F_SETFD, FD_CLOEXEC); - -+ if (options.tcp_rcv_buf > 0) -+ ssh_set_socket_recvbuf(sock); -+ - /* Use interactive QOS (if specified) until authentication completed */ - if (options.ip_qos_interactive != INT_MAX) - set_sock_tos(sock, options.ip_qos_interactive); -diff -Nur openssh-9.3p1.orig/sshd.8 openssh-9.3p1/sshd.8 ---- openssh-9.3p1.orig/sshd.8 2024-07-10 09:07:09.812082086 +0200 -+++ openssh-9.3p1/sshd.8 2024-07-10 09:09:55.923568470 +0200 -@@ -1078,3 +1078,7 @@ +diff -Nur openssh-10.0p1.orig/sshd.8 openssh-10.0p1/sshd.8 +--- openssh-10.0p1.orig/sshd.8 2025-06-14 10:53:02.026331727 +0200 ++++ openssh-10.0p1/sshd.8 2025-06-14 10:54:01.342080852 +0200 +@@ -1079,3 +1079,7 @@ protocol versions 1.5 and 2.0. Niels Provos and Markus Friedl contributed support for privilege separation. @@ -12173,10 +13349,39 @@ diff -Nur openssh-9.3p1.orig/sshd.8 openssh-9.3p1/sshd.8 +the HPN extensions at the Pittsburgh Supercomuting Center with grants +from Cisco, the National Library of Medicine, and the National Science +Foundation. -diff -Nur openssh-9.3p1.orig/sshd.c openssh-9.3p1/sshd.c ---- openssh-9.3p1.orig/sshd.c 2024-07-10 09:07:09.813082089 +0200 -+++ openssh-9.3p1/sshd.c 2024-07-10 10:29:13.426499996 +0200 -@@ -1093,6 +1093,8 @@ +diff -Nur openssh-10.0p1.orig/sshd-auth.c openssh-10.0p1/sshd-auth.c +--- openssh-10.0p1.orig/sshd-auth.c 2025-06-14 10:53:01.779184668 +0200 ++++ openssh-10.0p1/sshd-auth.c 2025-06-14 10:54:01.342636371 +0200 +@@ -832,6 +832,25 @@ + struct kex *kex; + int r; + ++ /* this used to be in sshd.c when we read the configuration file ++ * but needed to be moved here as do_ssh2_kex in sshd-auth wasn't ++ * picking up the none options. CJR 4/10/2025 ++ */ ++ if (options.none_enabled == 1) { ++ debug("WARNING: None cipher enabled"); ++ char *old_ciphers = options.ciphers; ++ xasprintf(&options.ciphers, "%s,none", old_ciphers); ++ free(old_ciphers); ++ ++ /* only enable the none MAC in context of the none cipher -cjr */ ++ if (options.nonemac_enabled == 1) { ++ debug("WARNING: None MAC enabled"); ++ char *old_macs = options.macs; ++ xasprintf(&options.macs, "%s,none", old_macs); ++ free(old_macs); ++ } ++ } ++ + if (options.rekey_limit || options.rekey_interval) + ssh_packet_set_rekey_limits(ssh, options.rekey_limit, + options.rekey_interval); +diff -Nur openssh-10.0p1.orig/sshd.c openssh-10.0p1/sshd.c +--- openssh-10.0p1.orig/sshd.c 2025-06-14 10:53:01.779446364 +0200 ++++ openssh-10.0p1/sshd.c 2025-06-14 10:54:01.343195243 +0200 +@@ -822,6 +822,8 @@ int ret, listen_sock; struct addrinfo *ai; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; @@ -12185,111 +13390,58 @@ diff -Nur openssh-9.3p1.orig/sshd.c openssh-9.3p1/sshd.c for (ai = la->addrs; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) -@@ -1138,6 +1140,11 @@ +@@ -837,11 +839,17 @@ + continue; + } + /* Create socket for listening. */ +- listen_sock = socket(ai->ai_family, ai->ai_socktype, +- ai->ai_protocol); ++ if (options.use_mptcp) ++ listen_sock = socket(ai->ai_family, ai->ai_socktype, ++ IPPROTO_MPTCP); ++ else ++ listen_sock = socket(ai->ai_family, ai->ai_socktype, ++ ai->ai_protocol); + if (listen_sock == -1) { + /* kernel may not support ipv6 */ + verbose("socket: %.100s", strerror(errno)); ++ if (options.use_mptcp) ++ verbose("MPTCP requested but may not be available."); + continue; + } + if (set_nonblock(listen_sock) == -1) { +@@ -867,6 +875,10 @@ debug("Bind to port %s on %s.", strport, ntop); + getsockopt(listen_sock, SOL_SOCKET, SO_RCVBUF, + &socksize, &socksizelen); + debug("Server TCP RWIN socket size: %d", socksize); -+ debug("HPN Buffer Size: %d", options.hpn_buffer_size); + /* Bind the socket to the desired port. */ if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) == -1) { error("Bind to port %s on %s failed: %.200s.", -@@ -1793,8 +1800,8 @@ - free(line); - break; - case 'V': -- fprintf(stderr, "%s, %s\n", -- SSH_VERSION, SSH_OPENSSL_VERSION); -+ fprintf(stderr, "%s%s, %s\n", -+ SSH_VERSION, SSH_HPN, SSH_OPENSSL_VERSION); - exit(0); - default: - usage(); -@@ -1876,6 +1883,19 @@ - /* Fill in default values for those options not explicitly set. */ - fill_default_server_options(&options); - -+ if (options.none_enabled == 1) { -+ char *old_ciphers = options.ciphers; -+ xasprintf(&options.ciphers, "%s,none", old_ciphers); -+ free(old_ciphers); -+ -+ /* only enable the none MAC in context of the none cipher -cjr */ -+ if (options.nonemac_enabled == 1) { -+ char *old_macs = options.macs; -+ xasprintf(&options.macs, "%s,none", old_macs); -+ free(old_macs); -+ } -+ } -+ - /* Check that options are sensible */ - if (options.authorized_keys_command_user == NULL && - (options.authorized_keys_command != NULL && -@@ -2359,6 +2379,9 @@ - rdomain == NULL ? "" : "\""); - free(laddr); - -+ /* set the HPN options for the child */ -+ channel_set_hpn(options.hpn_disabled, options.hpn_buffer_size); -+ - /* - * We don't want to listen forever unless the other side - * successfully authenticates itself. So we set up an alarm which is -@@ -2471,6 +2494,27 @@ - /* Try to send all our hostkeys to the client */ - notify_hostkeys(ssh); - -+#ifdef WITH_OPENSSL -+ /* if we are using aes-ctr there can be issues in either a fork or sandbox -+ * so the initial aes-ctr is defined to point to the original single process -+ * evp. After authentication we'll be past the fork and the sandboxed privsep -+ * so we repoint the define to the multithreaded evp. To start the threads we -+ * then force a rekey -+ */ -+ /* We now explicitly call the mt cipher in cipher.c so we don't need -+ * the cipher_reset_multithreaded() anymore. We just need to -+ * force a rekey -cjr 09/08/2022 */ -+ const void *cc = ssh_packet_get_send_context(the_active_state); -+ -+ /* only rekey if necessary. If we don't do this gcm mode cipher breaks */ -+ if (strstr(cipher_ctx_name(cc), "ctr")) { -+ debug("Single to Multithreaded CTR cipher swap - server request"); -+ /* cipher_reset_multithreaded(); */ -+ ssh_packet_set_authenticated(ssh); -+ packet_request_rekeying(); -+ } -+#endif -+ - /* Start session. */ - do_authenticated(ssh, authctxt); - -@@ -2545,6 +2589,11 @@ - struct kex *kex; - int r; - -+ if (options.none_enabled == 1) -+ debug("WARNING: None cipher enabled"); -+ if (options.nonemac_enabled == 1) -+ debug("WARNING: None MAC enabled"); -+ - if (options.rekey_limit || options.rekey_interval) - ssh_packet_set_rekey_limits(ssh, options.rekey_limit, - options.rekey_interval); -diff -Nur openssh-9.3p1.orig/sshd_config openssh-9.3p1/sshd_config ---- openssh-9.3p1.orig/sshd_config 2024-07-10 09:07:09.813082089 +0200 -+++ openssh-9.3p1/sshd_config 2024-07-10 09:09:55.923568470 +0200 -@@ -19,6 +19,7 @@ +diff -Nur openssh-10.0p1.orig/sshd_config openssh-10.0p1/sshd_config +--- openssh-10.0p1.orig/sshd_config 2025-06-14 10:53:02.026903728 +0200 ++++ openssh-10.0p1/sshd_config 2025-06-14 11:00:18.384210561 +0200 +@@ -18,7 +18,7 @@ + # SELinux about this change. # semanage port -a -t ssh_port_t -p tcp #PORTNUMBER # - #Port 22 +-#Port 22 +Port 2222 #AddressFamily any #ListenAddress 0.0.0.0 #ListenAddress :: -@@ -127,6 +128,27 @@ +@@ -122,6 +122,7 @@ + #PermitTunnel no + #ChrootDirectory none + #VersionAddendum none ++#UseMPTCP no + + # no default banner path + #Banner none +@@ -129,6 +130,19 @@ # override default of no subsystems Subsystem sftp /usr/libexec/sftp-server @@ -12300,26 +13452,18 @@ diff -Nur openssh-9.3p1.orig/sshd_config openssh-9.3p1/sshd_config +# disable hpn performance boosts +#HPNDisabled no + -+# buffer size for hpn to non-hpn connections -+#HPNBufferSize 2048 -+ +# allow the use of the none cipher +#NoneEnabled no + +# allow the use of the none MAC +#NoneMacEnabled no -+ -+# clamp the server's receive buffer to -+# 1/2 the tcp receive window. This may be useful -+# in some environments. -+#HPNBufferLimit no + # Example of overriding settings on a per-user basis #Match User anoncvs # X11Forwarding no -diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 ---- openssh-9.3p1.orig/sshd_config.5 2024-07-10 09:07:09.814082092 +0200 -+++ openssh-9.3p1/sshd_config.5 2024-07-10 09:09:55.924568473 +0200 +diff -Nur openssh-10.0p1.orig/sshd_config.5 openssh-10.0p1/sshd_config.5 +--- openssh-10.0p1.orig/sshd_config.5 2025-06-14 10:53:02.027286949 +0200 ++++ openssh-10.0p1/sshd_config.5 2025-06-14 10:54:01.344536060 +0200 @@ -56,6 +56,16 @@ .Pq \&" in order to represent arguments containing spaces. @@ -12337,7 +13481,7 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 The possible keywords and their meanings are as follows (note that keywords are case-insensitive and arguments are case-sensitive): -@@ -659,6 +669,10 @@ +@@ -667,6 +677,10 @@ TCP and StreamLocal. This option overrides all other forwarding-related options and may simplify restricted configurations. @@ -12348,7 +13492,7 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 .It Cm ExposeAuthInfo Writes a temporary file containing a list of authentication methods and public credentials (e.g. keys) used to authenticate the user. -@@ -892,6 +906,28 @@ +@@ -944,6 +958,11 @@ The default for this option is: The list of available signature algorithms may also be obtained using .Qq ssh -Q HostKeyAlgorithms . @@ -12357,27 +13501,10 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 +of the HPN code produces a net decrease in performance. In these cases it is +helpful to disable the HPN functionality. By default HPNDisabled is set to +.CM no. -+.It Cm HPNBufferLimit -+This option will force the hpnssh receive buffer to grow more slowly and limits -+the growth to one half of the TCP receive buffer. This option can prove useful -+in situation where a high speed path with larger RTTs are writing to a slower -+device or file system. Enabling this option will reduce performance but may provide -+a more stable connection. The option only impacts the receiving side of the connection. -+For example, a client receiving data from a server but not a client sending data. If -+enabled on a server this will impact all incoming connections. -+By default this option is set to -+.Cm no. HPNSSH only. -+.It Cm HPNBufferSize -+This is the default buffer size, in kilobytes, that HPN functionality uses when interacting -+with nonHPN SSH installations. Conceptually this is similar to the TcpRcvBuf -+option as applied to the internal SSH flow control. This value can range from -+1KB to 64MB (1-65536). Use of oversized or undersized buffers can cause performance -+problems depending on the length of the network path. The default size of this buffer -+is 2MB. .It Cm IgnoreRhosts Specifies whether to ignore per-user .Pa .rhosts -@@ -1393,6 +1429,19 @@ +@@ -1467,6 +1486,19 @@ key exchange methods. The default is .Pa /etc/moduli . @@ -12394,21 +13521,13 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 +protection against man-in-the-middle attacks. As with NoneEnabled all authentication +remains encrypted and integrity is ensured. Default is +.Cm no. - .It Cm PasswordAuthentication - Specifies whether password authentication is allowed. - The default is -@@ -1835,6 +1884,21 @@ + .It Cm PAMServiceName + Specifies the service name used for Pluggable Authentication Modules (PAM) + authentication, authorisation and session controls when +@@ -2035,6 +2067,13 @@ .Pp To disable TCP keepalive messages, the value should be set to .Cm no . -+.It Cm TcpRcvBuf -+Set the TCP socket receive buffer to n Kilobytes. It can be set up to the -+maximum socket size allowed by the system. This is useful in situations where -+the tcp receive window is set low but the maximum buffer size is set -+higher (as is typical). This works on a per TCP connection basis. You can also -+use this to artifically limit the transfer rate of the connection. In these -+cases the throughput will be no more than n/RTT KB/s. The minimum buffer size is 1KB. -+Default is the current system wide tcp receive buffer size. +.IT Cm TcpRcvBufPoll +Enable of disable the polling of the tcp receive buffer throughout the life +of the connection. Make sure that this option is enabled for systems making @@ -12419,7 +13538,20 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 .It Cm TrustedUserCAKeys Specifies a file containing public keys of certificate authorities that are trusted to sign user certificates for authentication, or -@@ -2129,3 +2193,11 @@ +@@ -2095,6 +2134,12 @@ + .Cm Match + .Cm Host + directives. ++.It Cm UseMPTCP ++If set to ++.Cm yes , ++this will enable Multipath TCP (MPTCP) instead of TCP (this only works on Linux). ++The default is ++.Cm no . + .It Cm UsePAM + Enables the Pluggable Authentication Module interface. + If set to +@@ -2333,3 +2378,11 @@ and .An Markus Friedl contributed support for privilege separation. @@ -12431,10 +13563,44 @@ diff -Nur openssh-9.3p1.orig/sshd_config.5 openssh-9.3p1/sshd_config.5 +developed the HPN extensions at the Pittsburgh Supercomuting Center +with grants from Cisco, the National Library of Medicine, and +the National Science Foundation. -diff -Nur openssh-9.3p1.orig/ssh.h openssh-9.3p1/ssh.h ---- openssh-9.3p1.orig/ssh.h 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/ssh.h 2024-07-10 09:09:55.924568473 +0200 -@@ -17,6 +17,7 @@ +diff -Nur openssh-10.0p1.orig/sshd-session.c openssh-10.0p1/sshd-session.c +--- openssh-10.0p1.orig/sshd-session.c 2025-06-14 10:53:02.028087821 +0200 ++++ openssh-10.0p1/sshd-session.c 2025-06-14 10:54:01.345322405 +0200 +@@ -1164,6 +1164,20 @@ + } + endpwent(); + ++ /* get NONE options */ ++ if (options.none_enabled == 1) { ++ char *old_ciphers = options.ciphers; ++ xasprintf(&options.ciphers, "%s,none", old_ciphers); ++ free(old_ciphers); ++ ++ /* only enable the none MAC in context of the none cipher -cjr */ ++ if (options.nonemac_enabled == 1) { ++ char *old_macs = options.macs; ++ xasprintf(&options.macs, "%s,none", old_macs); ++ free(old_macs); ++ } ++ } ++ + if (!debug_flag && !inetd_flag) { + if ((startup_pipe = dup(REEXEC_CONFIG_PASS_FD)) == -1) + fatal("internal error: no startup pipe"); +@@ -1375,6 +1389,9 @@ + rdomain == NULL ? "" : "\""); + free(laddr); + ++ /* set the HPN options for the child */ ++ channel_set_hpn_disabled(options.hpn_disabled); ++ + /* + * We don't want to listen forever unless the other side + * successfully authenticates itself. So we set up an alarm which is +diff -Nur openssh-10.0p1.orig/ssh.h openssh-10.0p1/ssh.h +--- openssh-10.0p1.orig/ssh.h 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/ssh.h 2025-06-14 10:54:01.345905093 +0200 +@@ -14,6 +14,7 @@ /* Default port number. */ #define SSH_DEFAULT_PORT 22 @@ -12442,7 +13608,7 @@ diff -Nur openssh-9.3p1.orig/ssh.h openssh-9.3p1/ssh.h /* * Maximum number of certificate files that can be specified -@@ -48,7 +49,7 @@ +@@ -43,7 +44,7 @@ * Name for the service. The port named by this service overrides the * default port if present. */ @@ -12451,69 +13617,160 @@ diff -Nur openssh-9.3p1.orig/ssh.h openssh-9.3p1/ssh.h /* * Name of the environment variable containing the process ID of the -diff -Nur openssh-9.3p1.orig/sshkey.c openssh-9.3p1/sshkey.c ---- openssh-9.3p1.orig/sshkey.c 2024-07-10 09:07:09.754081916 +0200 -+++ openssh-9.3p1/sshkey.c 2024-07-10 09:09:55.925568475 +0200 -@@ -1776,7 +1776,7 @@ +diff -Nur openssh-10.0p1.orig/sshkey.c openssh-10.0p1/sshkey.c +--- openssh-10.0p1.orig/sshkey.c 2025-06-14 10:53:01.935152884 +0200 ++++ openssh-10.0p1/sshkey.c 2025-06-14 10:54:01.346333152 +0200 +@@ -1775,7 +1775,8 @@ stderr); #endif if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher), - keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 1)) != 0) -+ keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 1, 0)) != 0) ++ keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 0, ++ CIPHER_ENCRYPT, CIPHER_SERIAL)) != 0) goto out; /* Serialise and encrypt the private key using the ephemeral key */ -@@ -1911,7 +1911,7 @@ +@@ -1910,7 +1911,8 @@ keyiv, SSH_DIGEST_MAX_LENGTH)) != 0) goto out; if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher), - keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 0)) != 0) -+ keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 0, 0)) != 0) ++ keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 0, ++ CIPHER_DECRYPT, CIPHER_SERIAL)) != 0) goto out; #ifdef DEBUG_PK fprintf(stderr, "%s: key+iv\n", __func__); -@@ -3015,7 +3015,7 @@ +@@ -2965,6 +2967,13 @@ + kdfname = "none"; + } else if (ciphername == NULL) + ciphername = DEFAULT_CIPHERNAME; ++ /* ++ * NOTE: Without OpenSSL, this string comparison is still safe, even ++ * though it will never match because the multithreaded cipher is not ++ * enabled. ++ */ ++ else if (strcmp(ciphername, "chacha20-poly1305-mt@hpnssh.org") == 0) ++ ciphername = "chacha20-poly1305@openssh.com"; + if ((cipher = cipher_by_name(ciphername)) == NULL) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; +@@ -3000,7 +3009,7 @@ goto out; } if ((r = cipher_init(&ciphercontext, cipher, key, keylen, - key + keylen, ivlen, 1)) != 0) -+ key + keylen, ivlen, 1, 0)) != 0) ++ key + keylen, ivlen, 0, CIPHER_ENCRYPT, CIPHER_SERIAL)) != 0) goto out; if ((r = sshbuf_put(encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC))) != 0 || -@@ -3259,7 +3259,7 @@ +@@ -3187,6 +3196,8 @@ + (r = sshbuf_get_u32(decoded, &encrypted_len)) != 0) + goto out; + ++ if (strcmp(ciphername, "chacha20-poly1305-mt@hpnssh.org") == 0) ++ strcpy(ciphername, "chacha20-poly1305@openssh.com"); + if ((cipher = cipher_by_name(ciphername)) == NULL) { + r = SSH_ERR_KEY_UNKNOWN_CIPHER; + goto out; +@@ -3242,7 +3253,7 @@ /* decrypt private portion of key */ if ((r = sshbuf_reserve(decrypted, encrypted_len, &dp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, - key + keylen, ivlen, 0)) != 0) -+ key + keylen, ivlen, 0, 0)) != 0) ++ key + keylen, ivlen, 0, CIPHER_DECRYPT, CIPHER_SERIAL)) != 0) goto out; if ((r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(decoded), encrypted_len, 0, authlen)) != 0) { -diff -Nur openssh-9.3p1.orig/sshkey-xmss.c openssh-9.3p1/sshkey-xmss.c ---- openssh-9.3p1.orig/sshkey-xmss.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/sshkey-xmss.c 2024-07-10 09:09:55.925568475 +0200 -@@ -956,7 +956,7 @@ +diff -Nur openssh-10.0p1.orig/sshkey-xmss.c openssh-10.0p1/sshkey-xmss.c +--- openssh-10.0p1.orig/sshkey-xmss.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/sshkey-xmss.c 2025-06-14 10:54:01.347175650 +0200 +@@ -903,9 +903,29 @@ + state->enc_keyiv == NULL || + state->enc_ciphername == NULL) + return SSH_ERR_INTERNAL_ERROR; +- if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { +- r = SSH_ERR_INTERNAL_ERROR; +- goto out; ++ /* ++ * chacha20-poly1305-mt@hpnssh.org and chacha20-poly1305@openssh.com ++ * represent different implementations of the same cipher. For key ++ * encryption purposes, they're equivalent, and the multithreaded ++ * implementation is excessive. It can be assumed that references to the ++ * multithreaded implementation in this context are unintentional, so ++ * these checks should look for the serial implementation instead. ++ * ++ * Additionally, the following code is safe regardless of whether the ++ * multithreaded implementation is enabled, so no #ifdefs are necessary. ++ */ ++ if (strcmp(state->enc_ciphername, "chacha20-poly1305-mt@hpnssh.org") ++ == 0) { ++ if ((cipher = cipher_by_name("chacha20-poly1305@openssh.com")) ++ == NULL) { ++ r = SSH_ERR_INTERNAL_ERROR; ++ goto out; ++ } ++ } else { ++ if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { ++ r = SSH_ERR_INTERNAL_ERROR; ++ goto out; ++ } + } + blocksize = cipher_blocksize(cipher); + keylen = cipher_keylen(cipher); +@@ -956,7 +976,7 @@ if ((r = sshbuf_reserve(encrypted, encrypted_len + aadlen + authlen, &cp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, - iv, ivlen, 1)) != 0 || -+ iv, ivlen, 1, 0)) != 0 || ++ iv, ivlen, 0, CIPHER_ENCRYPT, CIPHER_SERIAL)) != 0 || (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded), encrypted_len, aadlen, authlen)) != 0) goto out; -@@ -1049,7 +1049,7 @@ +@@ -995,9 +1015,29 @@ + state->enc_keyiv == NULL || + state->enc_ciphername == NULL) + return SSH_ERR_INTERNAL_ERROR; +- if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { +- r = SSH_ERR_INVALID_FORMAT; +- goto out; ++ /* ++ * chacha20-poly1305-mt@hpnssh.org and chacha20-poly1305@openssh.com ++ * represent different implementations of the same cipher. For key ++ * encryption purposes, they're equivalent, and the multithreaded ++ * implementation is excessive. It can be assumed that references to the ++ * multithreaded implementation in this context are unintentional, so ++ * these checks should look for the serial implementation instead. ++ * ++ * Additionally, the following code is safe regardless of whether the ++ * multithreaded implementation is enabled, so no #ifdefs are necessary. ++ */ ++ if (strcmp(state->enc_ciphername, "chacha20-poly1305-mt@hpnssh.org") ++ == 0) { ++ if ((cipher = cipher_by_name("chacha20-poly1305@openssh.com")) ++ == NULL) { ++ r = SSH_ERR_INVALID_FORMAT; ++ goto out; ++ } ++ } else { ++ if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) { ++ r = SSH_ERR_INVALID_FORMAT; ++ goto out; ++ } + } + blocksize = cipher_blocksize(cipher); + keylen = cipher_keylen(cipher); +@@ -1049,7 +1089,7 @@ /* decrypt private state of key */ if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 || (r = cipher_init(&ciphercontext, cipher, key, keylen, - iv, ivlen, 0)) != 0 || -+ iv, ivlen, 0, 0)) != 0 || ++ iv, ivlen, 0, CIPHER_DECRYPT, CIPHER_SERIAL)) != 0 || (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy), encrypted_len, aadlen, authlen)) != 0) goto out; -diff -Nur openssh-9.3p1.orig/umac.c openssh-9.3p1/umac.c ---- openssh-9.3p1.orig/umac.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1/umac.c 2024-07-10 09:09:55.926568478 +0200 +diff -Nur openssh-10.0p1.orig/umac.c openssh-10.0p1/umac.c +--- openssh-10.0p1.orig/umac.c 2025-04-09 09:02:43.000000000 +0200 ++++ openssh-10.0p1/umac.c 2025-06-14 10:54:01.347637721 +0200 @@ -134,15 +134,48 @@ /* --- Endian Conversion --- Forcing assembly on some platforms */ /* ---------------------------------------------------------------------- */ @@ -12566,9 +13823,9 @@ diff -Nur openssh-9.3p1.orig/umac.c openssh-9.3p1/umac.c #define STORE_UINT32_BIG(p,v) put_u32(p, v) /* ---------------------------------------------------------------------- */ -diff -Nur openssh-9.3p1.orig/uthash.h openssh-9.3p1/uthash.h ---- openssh-9.3p1.orig/uthash.h 1970-01-01 01:00:00.000000000 +0100 -+++ openssh-9.3p1/uthash.h 2024-07-10 09:09:55.926568478 +0200 +diff -Nur openssh-10.0p1.orig/uthash.h openssh-10.0p1/uthash.h +--- openssh-10.0p1.orig/uthash.h 1970-01-01 01:00:00.000000000 +0100 ++++ openssh-10.0p1/uthash.h 2025-06-14 10:54:01.348457241 +0200 @@ -0,0 +1,1140 @@ +/* +Copyright (c) 2003-2022, Troy D. Hanson https://troydhanson.github.io/uthash/ @@ -13710,14 +14967,14 @@ diff -Nur openssh-9.3p1.orig/uthash.h openssh-9.3p1/uthash.h +} UT_hash_handle; + +#endif /* UTHASH_H */ -diff -Nur openssh-9.3p1.orig/version.h openssh-9.3p1/version.h ---- openssh-9.3p1.orig/version.h 2024-07-10 09:07:09.814082092 +0200 -+++ openssh-9.3p1/version.h 2024-07-10 10:31:57.907981932 +0200 +diff -Nur openssh-10.0p1.orig/version.h openssh-10.0p1/version.h +--- openssh-10.0p1.orig/version.h 2025-06-14 10:53:02.028786585 +0200 ++++ openssh-10.0p1/version.h 2025-06-14 11:34:35.359783615 +0200 @@ -16,5 +16,6 @@ - #define SSH_PORTABLE "p1" + #define SSH_PORTABLE "p2" #define GSI_PORTABLE "c-GSI" -+#define SSH_HPN "-hpn17v13" - #define SSH_RELEASE SSH_VERSION SSH_PORTABLE GSI_PORTABLE \ -- GSI_VERSION KRB5_VERSION -+ GSI_VERSION KRB5_VERSION SSH_HPN +-#define SSH_RELEASE SSH_VERSION SSH_PORTABLE GSI_PORTABLE \ ++#define SSH_HPN "_hpn18.7.0" ++#define SSH_RELEASE SSH_VERSION SSH_PORTABLE GSI_PORTABLE SSH_HPN \ + GSI_VERSION KRB5_VERSION diff --git a/gsi-openssh.spec b/gsi-openssh.spec index 9304f81..ef847b1 100644 --- a/gsi-openssh.spec +++ b/gsi-openssh.spec @@ -23,13 +23,12 @@ # Do we want libedit support %global libedit 1 -%global openssh_ver 9.3p1 -%global openssh_rel 6 +%global openssh_ver 10.0p1 Summary: An implementation of the SSH protocol with GSI authentication Name: gsi-openssh Version: %{openssh_ver} -Release: %{openssh_rel}%{?dist} +Release: 4%{?dist} Provides: gsissh = %{version}-%{release} Obsoletes: gsissh < 5.8p2-2 URL: http://www.openssh.com/portable.html @@ -49,168 +48,150 @@ Source20: gsissh-host-keys-migration.sh Source21: gsissh-host-keys-migration.service Source99: README.sshd-and-gsisshd -#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) -Patch400: openssh-7.8p1-role-mls.patch +Patch0001: 0001-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 - +Patch0002: 0002-openssh-6.6p1-privsep-selinux.patch +Patch0003: 0003-openssh-6.6p1-keycat.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1644 -Patch601: openssh-6.6p1-allow-ip-opts.patch +Patch0004: 0004-openssh-6.6p1-allow-ip-opts.patch #(drop?) https://bugzilla.mindrot.org/show_bug.cgi?id=1925 -Patch606: openssh-5.9p1-ipv6man.patch -#? -Patch607: openssh-5.8p2-sigpipe.patch +Patch0005: 0005-openssh-5.9p1-ipv6man.patch +Patch0006: 0006-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 +Patch0007: 0007-openssh-7.2p2-x11.patch +Patch0008: 0008-openssh-5.1p1-askpass-progress.patch #https://bugzilla.redhat.com/show_bug.cgi?id=198332 -Patch703: openssh-4.3p2-askpass-grab-info.patch +Patch0009: 0009-openssh-4.3p2-askpass-grab-info.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1635 (WONTFIX) -Patch707: openssh-7.7p1-redhat.patch +Patch0010: 0010-openssh-8.7p1-redhat.patch # warn users for unsupported UsePAM=no (#757545) -Patch711: openssh-7.8p1-UsePAM-warning.patch - +Patch0011: 0011-openssh-7.8p1-UsePAM-warning.patch # GSSAPI Key Exchange (RFC 4462 + RFC 8732) # from https://github.com/openssh-gsskex/openssh-gsskex/tree/fedora/master # and # Reenable MONITOR_REQ_GSSCHECKMIC after gssapi-with-mic failures # upstream MR: # https://github.com/openssh-gsskex/openssh-gsskex/pull/21 -Patch800: openssh-8.0p1-gssapi-keyex.patch +Patch0012: 0012-openssh-9.6p1-gssapi-keyex.patch #http://www.mail-archive.com/kerberos@mit.edu/msg17591.html -Patch801: openssh-6.6p1-force_krb.patch -# add new option GSSAPIEnablek5users and disable using ~/.k5users by default (#1169843) -# CVE-2014-9278 -Patch802: openssh-6.6p1-GSSAPIEnablek5users.patch +Patch0013: 0013-openssh-6.6p1-force_krb.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 +Patch0014: 0014-openssh-7.7p1-gssapi-new-unique.patch # Respect k5login_directory option in krk5.conf (#1328243) -Patch805: openssh-7.2p2-k5login_directory.patch - +Patch0015: 0015-openssh-7.2p2-k5login_directory.patch #https://bugzilla.mindrot.org/show_bug.cgi?id=1780 -Patch901: openssh-6.6p1-kuserok.patch +Patch0016: 0016-openssh-6.6p1-kuserok.patch # Use tty allocation for a remote scp (#985650) -Patch906: openssh-6.4p1-fromto-remote.patch +Patch0017: 0017-openssh-6.4p1-fromto-remote.patch # privsep_preauth: use SELinux context from selinux-policy (#1008580) -Patch916: openssh-6.6.1p1-selinux-contexts.patch +Patch0018: 0018-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 +Patch0019: 0019-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 +Patch0020: 0020-openssh-6.6.1p1-scp-non-existing-directory.patch +# add new option GSSAPIEnablek5users and disable using ~/.k5users by default (#1169843) +# CVE-2014-9278 +Patch0021: 0021-openssh-6.6p1-GSSAPIEnablek5users.patch # apply upstream patch and make sshd -T more consistent (#1187521) -Patch922: openssh-6.8p1-sshdT-output.patch +Patch0022: 0022-openssh-6.8p1-sshdT-output.patch # Add sftp option to force mode of created files (#1191055) -Patch926: openssh-6.7p1-sftp-force-permission.patch +Patch0023: 0023-openssh-6.7p1-sftp-force-permission.patch # make s390 use /dev/ crypto devices -- ignore closefrom -Patch939: openssh-7.2p2-s390-closefrom.patch +Patch0024: 0024-openssh-7.2p2-s390-closefrom.patch # Move MAX_DISPLAYS to a configuration option (#1341302) -Patch944: openssh-7.3p1-x11-max-displays.patch -# Help systemd to track the running service -Patch948: openssh-7.4p1-systemd.patch +Patch0025: 0025-openssh-7.3p1-x11-max-displays.patch # Pass inetd flags for SELinux down to openbsd compat level -Patch949: openssh-7.6p1-cleanup-selinux.patch +Patch0026: 0026-openssh-7.6p1-cleanup-selinux.patch # Sandbox adjustments for s390 and audit -Patch950: openssh-7.5p1-sandbox.patch +Patch0027: 0027-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 +Patch0028: 0028-openssh-8.0p1-pkcs11-uri.patch # Unbreak scp between two IPv6 hosts (#1620333) -Patch953: openssh-7.8p1-scp-ipv6.patch +Patch0029: 0029-openssh-7.8p1-scp-ipv6.patch # Mention crypto-policies in manual pages (#1668325) # clarify rhbz#2068423 on the man page of ssh_config -Patch962: openssh-8.0p1-crypto-policies.patch -# Use OpenSSL high-level API to produce and verify signatures (#1707485) -# TODO fix the comment above ^ -Patch963: openssh-9.3p1-merged-openssl-evp.patch +Patch0030: 0030-openssh-8.0p1-crypto-policies.patch # Use OpenSSL KDF (#1631761) -Patch964: openssh-8.0p1-openssl-kdf.patch +Patch0031: 0031-openssh-8.0p1-openssl-kdf.patch # sk-dummy.so built with -fvisibility=hidden does not work -Patch965: openssh-8.2p1-visibility.patch +Patch0032: 0032-openssh-8.2p1-visibility.patch # Do not break X11 without IPv6 -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 +Patch0033: 0033-openssh-8.2p1-x11-without-ipv6.patch # sshd provides PAM an incorrect error code (#1879503) -Patch975: openssh-8.0p1-preserve-pam-errors.patch +Patch0034: 0034-openssh-8.0p1-preserve-pam-errors.patch # Implement kill switch for SCP protocol -Patch977: openssh-8.7p1-scp-kill-switch.patch +Patch0035: 0035-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 -Patch981: openssh-8.7p1-recursive-scp.patch -# https://github.com/djmdjm/openssh-wip/pull/13 -Patch982: openssh-8.7p1-minrsabits.patch +Patch0036: 0036-openssh-8.7p1-recursive-scp.patch +# Downstream alias for MinRSABits +Patch0037: 0037-openssh-8.7p1-minrsabits.patch # downstream only, IBMCA tentative fix # From https://bugzilla.redhat.com/show_bug.cgi?id=1976202#c14 -Patch984: openssh-8.7p1-ibmca.patch - +Patch0038: 0038-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 +Patch0039: 0039-openssh-7.6p1-audit.patch +# Audit race condition in forked child (#1310684) +Patch0040: 0040-openssh-7.1p2-audit-race-condition.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2049947 +Patch0041: 0041-openssh-9.0p1-audit-log.patch +Patch0042: 0042-openssh-7.7p1-fips.patch # Add missing options from ssh_config into ssh manpage # upstream bug: # https://bugzilla.mindrot.org/show_bug.cgi?id=3455 -Patch1002: openssh-8.7p1-ssh-manpage.patch +Patch0043: 0043-openssh-8.7p1-ssh-manpage.patch # Don't propose disallowed algorithms during hostkey negotiation # upstream MR: # https://github.com/openssh/openssh-portable/pull/323 -Patch1006: openssh-8.7p1-negotiate-supported-algs.patch +Patch0044: 0044-openssh-8.7p1-negotiate-supported-algs.patch +Patch0045: 0045-openssh-9.0p1-evp-fips-kex.patch +Patch0046: 0046-openssh-8.7p1-nohostsha1proof.patch +Patch0047: 0047-openssh-9.6p1-pam-rhost.patch +Patch0048: 0048-openssh-9.9p1-separate-keysign.patch +Patch0049: 0049-openssh-9.9p1-openssl-mlkem.patch +# https://www.openwall.com/lists/oss-security/2025/02/22/1 +Patch0050: 0050-openssh-9.9p2-error_processing.patch +# https://github.com/openssh/openssh-portable/pull/564 +Patch0051: 0051-Provide-better-error-for-non-supported-private-keys.patch +# https://github.com/openssh/openssh-portable/pull/567 +Patch0052: 0052-Ignore-bad-hostkeys-in-known_hosts-file.patch +# https://github.com/openssh/openssh-portable/pull/500 +Patch0053: 0053-support-authentication-indicators-in-GSSAPI.patch -Patch1012: openssh-9.0p1-evp-fips-dh.patch -Patch1013: openssh-9.0p1-evp-fips-ecdh.patch -Patch1014: openssh-8.7p1-nohostsha1proof.patch -Patch1015: openssh-9.3p1-upstream-cve-2023-38408.patch -# upstream b7afd8a4ecaca8afd3179b55e9db79c0ff210237 -Patch1016: openssh-9.3p1-openssl-compat.patch -Patch1017: openssh-9.6p1-CVE-2023-51385.patch -Patch1018: openssh-9.6p1-CVE-2023-48795.patch -Patch1019: openssh-9.6p1-CVE-2023-51384.patch -# https://bugzilla.redhat.com/show_bug.cgi?id=2294879 -# Merged in OpenSSH 9.8 -Patch1020: openssh-9.6p1-cve-2024-6387.patch +#https://bugzilla.mindrot.org/show_bug.cgi?id=2581 +Patch1000: 1000-openssh-coverity.patch -# Fix issue with read-only ssh buffer during gssapi key exchange (#1938224) -# https://github.com/openssh-gsskex/openssh-gsskex/pull/19 -Patch97: openssh-8.0p1-sshbuf-readonly.patch # This is the patch that adds GSI support # Based on hpn_isshd-gsi.7.5p1b.patch from Globus upstream -Patch98: openssh-9.3p1-gsissh.patch +Patch2000: 2000-openssh-10.0p1-gsissh.patch # This is the HPN patch -# Based on https://github.com/rapier1/hpn-ssh/ tag: hpn-9_3_P1 (hpn17v13) -Patch99: openssh-9.3p1-hpn-17.13.patch +# Based on https://github.com/rapier1/hpn-ssh/ tag: hpn-18.7.0 +Patch2001: 2001-openssh-10.0p1-hpn-18.7.0.patch -License: BSD +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 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 >= 0.9.8j +BuildRequires: openssl-devel >= 3.5.0 BuildRequires: systemd-devel BuildRequires: systemd-rpm-macros BuildRequires: gcc make BuildRequires: p11-kit-devel BuildRequires: libfido2-devel +BuildRequires: libxcrypt-devel Recommends: p11-kit %if %{kerberos5} @@ -245,6 +226,10 @@ Obsoletes: gsissh-clients < 5.8p2-2 Requires: %{name} = %{version}-%{release} Requires: crypto-policies >= 20220824-1 +%package keysign +Summary: A helper program used for host-based authentication +Requires: %{name} = %{version}-%{release} + %package server Summary: SSH server daemon with GSI authentication Provides: gsissh-server = %{version}-%{release} @@ -280,6 +265,11 @@ the clients necessary to make encrypted connections to SSH servers. This version of OpenSSH has been modified to support GSI authentication. +%description keysign +OpenSSH is a free version of SSH (Secure SHell), a program for logging +into and executing commands on a remote machine. ssh-keysign is a +helper program used for host-based authentication disabled by default. + %description server OpenSSH is a free version of SSH (Secure SHell), a program for logging into and executing commands on a remote machine. This package contains @@ -290,82 +280,11 @@ This version of OpenSSH has been modified to support GSI authentication. %prep gpgv2 --quiet --keyring %{SOURCE3} %{SOURCE1} %{SOURCE0} -%setup -q -n openssh-%{version} - -%patch -P 400 -p1 -b .role-mls -%patch -P 404 -p1 -b .privsep-selinux - -%patch -P 502 -p1 -b .keycat - -%patch -P 601 -p1 -b .ip-opts -%patch -P 606 -p1 -b .ipv6man -%patch -P 607 -p1 -b .sigpipe -%patch -P 609 -p1 -b .x11 - -%patch -P 702 -p1 -b .progress -%patch -P 703 -p1 -b .grab-info -%patch -P 707 -p1 -b .redhat -%patch -P 711 -p1 -b .log-usepam-no - -%patch -P 800 -p1 -b .gsskex -%patch -P 801 -p1 -b .force_krb -%patch -P 804 -p1 -b .ccache_name -%patch -P 805 -p1 -b .k5login - -%patch -P 901 -p1 -b .kuserok -%patch -P 906 -p1 -b .fromto-remote -%patch -P 916 -p1 -b .contexts -%patch -P 918 -p1 -b .log-in-chroot -%patch -P 919 -p1 -b .scp -%patch -P 802 -p1 -b .GSSAPIEnablek5users -%patch -P 922 -p1 -b .sshdt -%patch -P 926 -p1 -b .sftp-force-mode -%patch -P 939 -p1 -b .s390-dev -%patch -P 944 -p1 -b .x11max -%patch -P 948 -p1 -b .systemd -%patch -P 949 -p1 -b .refactor -%patch -P 950 -p1 -b .sandbox -%patch -P 951 -p1 -b .pkcs11-uri -%patch -P 953 -p1 -b .scp-ipv6 -%patch -P 962 -p1 -b .crypto-policies -%patch -P 963 -p1 -b .openssl-evp -%patch -P 964 -p1 -b .openssl-kdf -%patch -P 965 -p1 -b .visibility -%patch -P 966 -p1 -b .x11-ipv6 -%patch -P 974 -p1 -b .keygen-strip-doseol -%patch -P 975 -p1 -b .preserve-pam-errors -%patch -P 977 -p1 -b .kill-scp -%patch -P 981 -p1 -b .scp-sftpdirs -%patch -P 982 -p1 -b .minrsabits -%patch -P 984 -p1 -b .ibmca - -%patch -P 200 -p1 -b .audit -%patch -P 201 -p1 -b .audit-race -%patch -P 202 -p1 -b .audit-log -%patch -P 700 -p1 -b .fips - -%patch -P 1002 -p1 -b .ssh-manpage -%patch -P 1006 -p1 -b .negotiate-supported-algs -%patch -P 1012 -p1 -b .evp-fips-dh -%patch -P 1013 -p1 -b .evp-fips-ecdh -%patch -P 1014 -p1 -b .nosha1hostproof -%patch -P 1015 -p1 -b .cve-2023-38408 -%patch -P 1016 -p1 -b .ossl-version -%patch -P 1017 -p1 -b .cve-2023-51385 -%patch -P 1018 -p1 -b .cve-2023-48795 -%patch -P 1019 -p1 -b .cve-2023-51384 -%patch -P 1020 -p1 -b .cve-2024-6387 - -%patch -P 100 -p1 -b .coverity - -%patch -P 97 -p1 -b .sshbuf-ro -%patch -P 98 -p1 -b .gsi -%patch -P 99 -p1 -b .hpn +%autosetup -T -b 0 -p1 -n openssh-%{version} sed 's/sshd.pid/gsisshd.pid/' -i pathnames.h sed 's!$(piddir)/sshd.pid!$(piddir)/gsisshd.pid!' -i Makefile.in -sed 's!/etc/sysconfig/sshd!/etc/sysconfig/gsisshd!' -i sshd_config -sed 's!/etc/pam.d/sshd!/etc/pam.d/gsisshd!' -i sshd_config +sed 's!/etc/pam.d/sshd!/etc/pam.d/gsisshd!' -i sshd_config_redhat cp -p %{SOURCE99} . @@ -373,7 +292,6 @@ autoreconf %build %set_build_flags -CFLAGS="$CFLAGS"; export CFLAGS %if %{pie} %ifarch s390 s390x sparc sparcv9 sparc64 CFLAGS="$CFLAGS -fPIC" @@ -406,12 +324,11 @@ fi --sysconfdir=%{_sysconfdir}/gsissh \ --libexecdir=%{_libexecdir}/gsissh \ --datadir=%{_datadir}/gsissh \ - --with-default-path=%{_libexecdir}/gsissh/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin \ - --with-superuser-path=%{_libexecdir}/gsissh/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin \ + --with-default-path=%{_libexecdir}/gsissh/bin:/usr/local/bin:/usr/bin \ + --with-superuser-path=%{_libexecdir}/gsissh/bin:/usr/local/bin:/usr/bin \ --with-privsep-path=%{_datadir}/empty.sshd \ --disable-strip \ --without-zlib-version-check \ - --with-ssl-engine \ --with-ipaddr-display \ --with-pie=no \ --without-hardening `# The hardening flags are configured by system` \ @@ -419,6 +336,7 @@ fi --with-default-pkcs11-provider=yes \ --with-security-key-builtin=yes \ --with-pam \ + --with-pam-service=gsisshd \ %if %{WITH_SELINUX} --with-selinux --with-audit=linux \ --with-sandbox=seccomp_filter \ @@ -486,7 +404,9 @@ rm $RPM_BUILD_ROOT%{_mandir}/man1/ssh-keyscan.1* rm $RPM_BUILD_ROOT%{_mandir}/man8/ssh-pkcs11-helper.8* for f in $RPM_BUILD_ROOT%{_bindir}/* \ +%if "%{_sbindir}" != "%{_bindir}" $RPM_BUILD_ROOT%{_sbindir}/* \ +%endif $RPM_BUILD_ROOT%{_mandir}/man*/* ; do mv $f `dirname $f`/gsi`basename $f` done @@ -532,8 +452,6 @@ fi %attr(0755,root,root) %{_bindir}/gsissh-keygen %attr(0644,root,root) %{_mandir}/man1/gsissh-keygen.1* %attr(0755,root,root) %dir %{_libexecdir}/gsissh -%attr(4555,root,root) %{_libexecdir}/gsissh/ssh-keysign -%attr(0644,root,root) %{_mandir}/man8/gsissh-keysign.8* %files clients %attr(0755,root,root) %{_bindir}/gsissh @@ -552,9 +470,15 @@ fi %{_libexecdir}/gsissh/bin/scp %{_libexecdir}/gsissh/bin/hpnscp +%files keysign +%attr(4555,root,root) %{_libexecdir}/gsissh/ssh-keysign +%attr(0644,root,root) %{_mandir}/man8/gsissh-keysign.8* + %files server %dir %attr(0711,root,root) %{_datadir}/empty.sshd %attr(0755,root,root) %{_sbindir}/gsisshd +%attr(0755,root,root) %{_libexecdir}/gsissh/sshd-session +%attr(0755,root,root) %{_libexecdir}/gsissh/sshd-auth %attr(0755,root,root) %{_libexecdir}/gsissh/sftp-server %attr(0755,root,root) %{_libexecdir}/gsissh/sshd-keygen %attr(0644,root,root) %{_mandir}/man5/gsisshd_config.5* @@ -578,11 +502,76 @@ fi %ghost %attr(0644,root,root) %{_localstatedir}/lib/.gsissh-host-keys-migration %changelog -* Fri Jul 12 2024 Mattias Ellert - 9.3p1-6 +* Mon Sep 01 2025 Mattias Ellert - 10.0p1-4 +- Based on openssh-10.0p1-6.fc44 + +* Mon Sep 01 2025 Mattias Ellert - 10.0p1-3 +- Based on openssh-10.0p1-4.fc43 + +* Thu Jul 24 2025 Fedora Release Engineering - 10.0p1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + +* Mon Jun 16 2025 Mattias Ellert - 10.0p1-1 +- Based on openssh-10.0p1-3.fc43 + +* Sun Apr 20 2025 Mattias Ellert - 9.9p1-6 +- Based on openssh-9.9p1-15.fc43 + +* Wed Mar 05 2025 Mattias Ellert - 9.9p1-5 +- Based on openssh-9.9p1-11.fc43 + +* Wed Mar 05 2025 Mattias Ellert - 9.9p1-4 +- Based on openssh-9.9p1-9.fc42 + +* Wed Feb 05 2025 Mattias Ellert - 9.9p1-3 +- Based on openssh-9.9p1-8.fc42 + +* Wed Feb 05 2025 Mattias Ellert - 9.9p1-2 +- Based on openssh-9.9p1-7.fc42 / openssh-9.9p1-2.fc41 + +* Sat Feb 01 2025 Björn Esser - 9.9p1-1.1 +- Add explicit BR: libxcrypt-devel + +* Mon Jan 20 2025 Mattias Ellert - 9.9p1-1 +- Based on openssh-9.9p1-5.fc42 / openssh-9.9p1-1.fc41 + +* Fri Jan 17 2025 Fedora Release Engineering - 9.8p1-2.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + +* Wed Oct 02 2024 Mattias Ellert - 9.8p1-2 +- Based on openssh-9.8p1-4.fc42 + +* Fri Sep 27 2024 Mattias Ellert - 9.8p1-1 +- Based on openssh-9.8p1-3.fc41.1 + +* Thu Jul 18 2024 Fedora Release Engineering - 9.6p1-3.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Fri Jul 12 2024 Mattias Ellert - 9.6p1-3 - Add scp and hpnscp symlinks in gsisshd's path -* Mon Jul 08 2024 Mattias Ellert - 9.3p1-5 -- Based on openssh-9.3p1-11.fc39 +* Sat Jul 06 2024 Mattias Ellert - 9.6p1-2 +- Based on openssh-9.6p1-1.fc41.13 + +* Sat Jul 06 2024 Mattias Ellert - 9.6p1-1 +- Based on openssh-9.6p1-1.fc40.4 + +* Wed Jan 24 2024 Fedora Release Engineering - 9.3p1-7.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Sat Jan 20 2024 Mattias Ellert - 9.3p1-7 +- Based on openssh-9.3p1-13.fc40.1 + +* Sat Jan 20 2024 Fedora Release Engineering - 9.3p1-6.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Tue Oct 24 2023 Mattias Ellert - 9.3p1-6 +- Based on openssh-9.3p1-13.fc40 +- Drop patch openssh-8.0p1-sshbuf-readonly.patch (now included in + openssh-8.0p1-gssapi-keyex.patch) + +* Tue Oct 17 2023 Mattias Ellert - 9.3p1-5 +- Based on openssh-9.3p1-12.fc40 * Tue Oct 17 2023 Mattias Ellert - 9.3p1-4 - Based on openssh-9.3p1-9.fc39 diff --git a/gsisshd-keygen b/gsisshd-keygen index 772550e..c49da87 100644 --- a/gsisshd-keygen +++ b/gsisshd-keygen @@ -9,8 +9,14 @@ case $KEYTYPE in if [[ -r "$FIPS" && $(cat $FIPS) == "1" ]]; then exit 0 fi ;; - "rsa") ;; # always ok - "ecdsa") ;; + "rsa") + if [[ ! -z $SSH_RSA_BITS ]]; then + SSH_KEYGEN_OPTIONS="-b $SSH_RSA_BITS" + fi ;; # always ok + "ecdsa") + if [[ ! -z $SSH_ECDSA_BITS ]]; then + SSH_KEYGEN_OPTIONS="-b $SSH_ECDSA_BITS" + fi ;; *) # wrong argument exit 12 ;; esac @@ -25,7 +31,7 @@ fi rm -f $KEY{,.pub} # create new keys -if ! $KEYGEN -q -t $KEYTYPE -f $KEY -C '' -N '' >&/dev/null; then +if ! $KEYGEN -q -t $KEYTYPE $SSH_KEYGEN_OPTIONS -f $KEY -C '' -N '' >&/dev/null; then exit 1 fi diff --git a/gsisshd-keygen@.service b/gsisshd-keygen@.service index 6b2898b..62a1898 100644 --- a/gsisshd-keygen@.service +++ b/gsisshd-keygen@.service @@ -4,6 +4,9 @@ ConditionFileNotEmpty=|!/etc/gsissh/ssh_host_%i_key [Service] Type=oneshot +# Set option as empty variable to suppress warnings upon expanding the command line +# when the config file under /etc does not exist or is empty. +Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/gsisshd ExecStart=/usr/libexec/gsissh/sshd-keygen %i diff --git a/gsisshd.service b/gsisshd.service index 6272ced..55dd115 100644 --- a/gsisshd.service +++ b/gsisshd.service @@ -9,6 +9,9 @@ Wants=gsissh-host-keys-migration.service [Service] Type=notify +# Set option as empty variable to suppress warnings upon expanding the command line +# when the config file under /etc does not exist or is empty. +Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/gsisshd ExecStart=/usr/sbin/gsisshd -D $OPTIONS ExecReload=/bin/kill -HUP $MAINPID diff --git a/gsisshd.sysconfig b/gsisshd.sysconfig index 904d8c1..e968b50 100644 --- a/gsisshd.sysconfig +++ b/gsisshd.sysconfig @@ -5,3 +5,7 @@ # example using systemctl enable gsisshd-keygen@dsa.service to allow creation # of DSA key or systemctl mask gsisshd-keygen@rsa.service to disable RSA key # creation. + +#SSH_RSA_BITS=3072 +#SSH_ECDSA_BITS=256 +OPTIONS="" diff --git a/gsisshd@.service b/gsisshd@.service index 8a3fff2..093931e 100644 --- a/gsisshd@.service +++ b/gsisshd@.service @@ -8,6 +8,11 @@ After=gsisshd-keygen.target Wants=gsissh-host-keys-migration.service [Service] +# Set option as empty variable to suppress warnings upon expanding the command line +# when the config file under /etc does not exist or is empty. +Environment=OPTIONS= EnvironmentFile=-/etc/sysconfig/gsisshd ExecStart=-/usr/sbin/gsisshd -i $OPTIONS +ExecStart=-/usr/sbin/gsisshd -i $OPTIONS -o "AuthorizedKeysFile ${CREDENTIALS_DIRECTORY}/ssh.ephemeral-authorized_keys-all .ssh/authorized_keys" StandardInput=socket +ImportCredential=ssh.ephemeral-authorized_keys-all diff --git a/openssh-5.8p2-sigpipe.patch b/openssh-5.8p2-sigpipe.patch deleted file mode 100644 index 554e346..0000000 --- a/openssh-5.8p2-sigpipe.patch +++ /dev/null @@ -1,14 +0,0 @@ -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/openssh-6.4p1-fromto-remote.patch b/openssh-6.4p1-fromto-remote.patch deleted file mode 100644 index 4a7d849..0000000 --- a/openssh-6.4p1-fromto-remote.patch +++ /dev/null @@ -1,16 +0,0 @@ -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/openssh-6.6.1p1-scp-non-existing-directory.patch b/openssh-6.6.1p1-scp-non-existing-directory.patch deleted file mode 100644 index bb55c0b..0000000 --- a/openssh-6.6.1p1-scp-non-existing-directory.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- 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.6p1-privsep-selinux.patch b/openssh-6.6p1-privsep-selinux.patch deleted file mode 100644 index 8047fc3..0000000 --- a/openssh-6.6p1-privsep-selinux.patch +++ /dev/null @@ -1,121 +0,0 @@ -diff -up openssh-7.4p1/openbsd-compat/port-linux.h.privsep-selinux openssh-7.4p1/openbsd-compat/port-linux.h ---- openssh-7.4p1/openbsd-compat/port-linux.h.privsep-selinux 2016-12-23 18:58:52.972122201 +0100 -+++ openssh-7.4p1/openbsd-compat/port-linux.h 2016-12-23 18:58:52.974122201 +0100 -@@ -23,6 +23,7 @@ void ssh_selinux_setup_pty(char *, const - void ssh_selinux_change_context(const char *); - void ssh_selinux_setfscreatecon(const char *); - -+void sshd_selinux_copy_context(void); - void sshd_selinux_setup_exec_context(char *); - #endif - -diff -up openssh-7.4p1/openbsd-compat/port-linux-sshd.c.privsep-selinux openssh-7.4p1/openbsd-compat/port-linux-sshd.c ---- openssh-7.4p1/openbsd-compat/port-linux-sshd.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100 -+++ openssh-7.4p1/openbsd-compat/port-linux-sshd.c 2016-12-23 18:58:52.974122201 +0100 -@@ -419,6 +419,28 @@ sshd_selinux_setup_exec_context(char *pw - debug3_f("done"); - } - -+void -+sshd_selinux_copy_context(void) -+{ -+ security_context_t *ctx; -+ -+ if (!ssh_selinux_enabled()) -+ return; -+ -+ if (getexeccon((security_context_t *)&ctx) != 0) { -+ logit_f("getexeccon failed with %s", strerror(errno)); -+ return; -+ } -+ if (ctx != NULL) { -+ /* unset exec context before we will lose this capabililty */ -+ if (setexeccon(NULL) != 0) -+ fatal_f("setexeccon failed with %s", strerror(errno)); -+ if (setcon(ctx) != 0) -+ fatal_f("setcon failed with %s", strerror(errno)); -+ freecon(ctx); -+ } -+} -+ - #endif - #endif - -diff -up openssh-7.4p1/session.c.privsep-selinux openssh-7.4p1/session.c ---- openssh-7.4p1/session.c.privsep-selinux 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/session.c 2016-12-23 18:58:52.974122201 +0100 -@@ -1331,7 +1331,7 @@ do_setusercontext(struct passwd *pw) - - platform_setusercontext(pw); - -- if (platform_privileged_uidswap()) { -+ if (platform_privileged_uidswap() && (!is_child || !use_privsep)) { - #ifdef HAVE_LOGIN_CAP - if (setusercontext(lc, pw, pw->pw_uid, - (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) { -@@ -1361,6 +1361,9 @@ do_setusercontext(struct passwd *pw) - (unsigned long long)pw->pw_uid); - chroot_path = percent_expand(tmp, "h", pw->pw_dir, - "u", pw->pw_name, "U", uidstr, (char *)NULL); -+#ifdef WITH_SELINUX -+ sshd_selinux_copy_context(); -+#endif - safely_chroot(chroot_path, pw->pw_uid); - free(tmp); - free(chroot_path); -@@ -1396,6 +1399,11 @@ do_setusercontext(struct passwd *pw) - /* Permanently switch to the desired uid. */ - permanently_set_uid(pw); - #endif -+ -+#ifdef WITH_SELINUX -+ if (in_chroot == 0) -+ sshd_selinux_copy_context(); -+#endif - } else if (options.chroot_directory != NULL && - strcasecmp(options.chroot_directory, "none") != 0) { - fatal("server lacks privileges to chroot to ChrootDirectory"); -@@ -1413,9 +1421,6 @@ do_pwchange(Session *s) - if (s->ttyfd != -1) { - fprintf(stderr, - "You must change your password now and login again!\n"); --#ifdef WITH_SELINUX -- setexeccon(NULL); --#endif - #ifdef PASSWD_NEEDS_USERNAME - execl(_PATH_PASSWD_PROG, "passwd", s->pw->pw_name, - (char *)NULL); -@@ -1625,9 +1630,6 @@ do_child(Session *s, const char *command - argv[i] = NULL; - optind = optreset = 1; - __progname = argv[0]; --#ifdef WITH_SELINUX -- ssh_selinux_change_context("sftpd_t"); --#endif - exit(sftp_server_main(i, argv, s->pw)); - } - -diff -up openssh-7.4p1/sshd.c.privsep-selinux openssh-7.4p1/sshd.c ---- openssh-7.4p1/sshd.c.privsep-selinux 2016-12-23 18:58:52.973122201 +0100 -+++ openssh-7.4p1/sshd.c 2016-12-23 18:59:13.808124269 +0100 -@@ -540,6 +540,10 @@ privsep_preauth_child(void) - /* Demote the private keys to public keys. */ - demote_sensitive_data(); - -+#ifdef WITH_SELINUX -+ ssh_selinux_change_context("sshd_net_t"); -+#endif -+ - /* Demote the child */ - if (privsep_chroot) { - /* Change our root directory */ -@@ -633,6 +637,9 @@ privsep_postauth(Authctxt *authctxt) - { - #ifdef DISABLE_FD_PASSING - if (1) { -+#elif defined(WITH_SELINUX) -+ if (0) { -+ /* even root user can be confined by SELinux */ - #else - if (authctxt->pw->pw_uid == 0) { - #endif diff --git a/openssh-6.7p1-coverity.patch b/openssh-6.7p1-coverity.patch deleted file mode 100644 index 494f4c6..0000000 --- a/openssh-6.7p1-coverity.patch +++ /dev/null @@ -1,366 +0,0 @@ -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/auth-options.c.coverity openssh-8.5p1/auth-options.c ---- openssh-8.5p1/auth-options.c.coverity 2021-03-02 11:31:47.000000000 +0100 -+++ openssh-8.5p1/auth-options.c 2021-03-24 12:03:33.782968159 +0100 -@@ -706,6 +708,7 @@ serialise_array(struct sshbuf *m, char * - return r; - } - /* success */ -+ sshbuf_free(b); - return 0; - } - -diff -up openssh-8.5p1/gss-genr.c.coverity openssh-8.5p1/gss-genr.c ---- openssh-8.5p1/gss-genr.c.coverity 2021-03-26 11:52:46.613942552 +0100 -+++ openssh-8.5p1/gss-genr.c 2021-03-26 11:54:37.881726318 +0100 -@@ -167,8 +167,9 @@ ssh_gssapi_kex_mechs(gss_OID_set gss_sup - enclen = __b64_ntop(digest, - ssh_digest_bytes(SSH_DIGEST_MD5), encoded, - ssh_digest_bytes(SSH_DIGEST_MD5) * 2); -- -+#pragma GCC diagnostic ignored "-Wstringop-overflow" - cp = strncpy(s, kex, strlen(kex)); -+#pragma pop - for ((p = strsep(&cp, ",")); p && *p != '\0'; - (p = strsep(&cp, ","))) { - if (sshbuf_len(buf) != 0 && -diff -up openssh-8.5p1/kexgssc.c.coverity openssh-8.5p1/kexgssc.c ---- openssh-8.5p1/kexgssc.c.coverity 2021-03-24 12:03:33.711967665 +0100 -+++ openssh-8.5p1/kexgssc.c 2021-03-24 12:03:33.783968166 +0100 -@@ -98,8 +98,10 @@ kexgss_client(struct ssh *ssh) - default: - fatal_f("Unexpected KEX type %d", kex->kex_type); - } -- if (r != 0) -+ if (r != 0) { -+ ssh_gssapi_delete_ctx(&ctxt); - return r; -+ } - - token_ptr = GSS_C_NO_BUFFER; - -diff -up openssh-8.5p1/krl.c.coverity openssh-8.5p1/krl.c ---- openssh-8.5p1/krl.c.coverity 2021-03-02 11:31:47.000000000 +0100 -+++ openssh-8.5p1/krl.c 2021-03-24 12:03:33.783968166 +0100 -@@ -1209,6 +1209,7 @@ ssh_krl_from_blob(struct sshbuf *buf, st - sshkey_free(key); - sshbuf_free(copy); - sshbuf_free(sect); -+ /* coverity[leaked_storage : FALSE] */ - return r; - } - -@@ -1261,6 +1262,7 @@ is_key_revoked(struct ssh_krl *krl, cons - return r; - erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb); - free(rb.blob); -+ rb.blob = NULL; /* make coverity happy */ - if (erb != NULL) { - KRL_DBG(("revoked by key SHA1")); - return SSH_ERR_KEY_REVOKED; -@@ -1271,6 +1273,7 @@ is_key_revoked(struct ssh_krl *krl, cons - return r; - erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha256s, &rb); - free(rb.blob); -+ rb.blob = NULL; /* make coverity happy */ - if (erb != NULL) { - KRL_DBG(("revoked by key SHA256")); - return SSH_ERR_KEY_REVOKED; -@@ -1282,6 +1285,7 @@ is_key_revoked(struct ssh_krl *krl, cons - return r; - erb = RB_FIND(revoked_blob_tree, &krl->revoked_keys, &rb); - free(rb.blob); -+ rb.blob = NULL; /* make coverity happy */ - if (erb != NULL) { - KRL_DBG(("revoked by explicit key")); - return SSH_ERR_KEY_REVOKED; -diff -up openssh-8.5p1/loginrec.c.coverity openssh-8.5p1/loginrec.c ---- openssh-8.5p1/loginrec.c.coverity 2021-03-24 13:18:53.793225885 +0100 -+++ openssh-8.5p1/loginrec.c 2021-03-24 13:21:27.948404751 +0100 -@@ -690,9 +690,11 @@ construct_utmp(struct logininfo *li, - */ - - /* Use strncpy because we don't necessarily want null termination */ -+ /* coverity[buffer_size_warning : FALSE] */ - strncpy(ut->ut_name, li->username, - MIN_SIZEOF(ut->ut_name, li->username)); - # ifdef HAVE_HOST_IN_UTMP -+ /* coverity[buffer_size_warning : FALSE] */ - strncpy(ut->ut_host, li->hostname, - MIN_SIZEOF(ut->ut_host, li->hostname)); - # endif -@@ -1690,6 +1692,7 @@ record_failed_login(struct ssh *ssh, con - - memset(&ut, 0, sizeof(ut)); - /* strncpy because we don't necessarily want nul termination */ -+ /* coverity[buffer_size_warning : FALSE] */ - strncpy(ut.ut_user, username, sizeof(ut.ut_user)); - strlcpy(ut.ut_line, "ssh:notty", sizeof(ut.ut_line)); - -@@ -1699,6 +1702,7 @@ record_failed_login(struct ssh *ssh, con - ut.ut_pid = getpid(); - - /* strncpy because we don't necessarily want nul termination */ -+ /* coverity[buffer_size_warning : FALSE] */ - strncpy(ut.ut_host, hostname, sizeof(ut.ut_host)); - - if (ssh_packet_connection_is_on_socket(ssh) && -diff -up openssh-8.5p1/misc.c.coverity openssh-8.5p1/misc.c ---- openssh-8.5p1/misc.c.coverity 2021-03-24 12:03:33.745967902 +0100 -+++ openssh-8.5p1/misc.c 2021-03-24 13:31:47.037079617 +0100 -@@ -1425,6 +1425,8 @@ sanitise_stdfd(void) - } - if (nullfd > STDERR_FILENO) - close(nullfd); -+ /* coverity[leaked_handle : FALSE]*/ -+ /* coverity[leaked_handle : FALSE]*/ - } - - char * -@@ -2511,6 +2513,7 @@ stdfd_devnull(int do_stdin, int do_stdou - } - if (devnull > STDERR_FILENO) - close(devnull); -+ /* coverity[leaked_handle : FALSE]*/ - return ret; - } - -diff -up openssh-7.4p1/monitor.c.coverity openssh-7.4p1/monitor.c ---- openssh-7.4p1/monitor.c.coverity 2016-12-23 16:40:26.888788688 +0100 -+++ openssh-7.4p1/monitor.c 2016-12-23 16:40:26.900788691 +0100 -@@ -411,7 +411,7 @@ monitor_child_preauth(Authctxt *_authctx - mm_get_keystate(ssh, pmonitor); - - /* Drain any buffered messages from the child */ -- while (pmonitor->m_log_recvfd != -1 && monitor_read_log(pmonitor) == 0) -+ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0) - ; - - if (pmonitor->m_recvfd >= 0) -@@ -1678,7 +1678,7 @@ mm_answer_pty(struct ssh *ssh, int sock, - s->ptymaster = s->ptyfd; - - debug3_f("tty %s ptyfd %d", s->tty, s->ttyfd); -- -+ /* coverity[leaked_handle : FALSE] */ - return (0); - - error: -diff -up openssh-7.4p1/monitor_wrap.c.coverity openssh-7.4p1/monitor_wrap.c ---- openssh-7.4p1/monitor_wrap.c.coverity 2016-12-23 16:40:26.892788689 +0100 -+++ openssh-7.4p1/monitor_wrap.c 2016-12-23 16:40:26.900788691 +0100 -@@ -525,10 +525,10 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, - if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 || - (tmp2 = dup(pmonitor->m_recvfd)) == -1) { - error_f("cannot allocate fds for pty"); -- if (tmp1 > 0) -+ if (tmp1 >= 0) - close(tmp1); -- if (tmp2 > 0) -- close(tmp2); -+ /*DEAD CODE if (tmp2 >= 0) -+ close(tmp2);*/ - return 0; - } - close(tmp1); -diff -up openssh-7.4p1/openbsd-compat/bindresvport.c.coverity openssh-7.4p1/openbsd-compat/bindresvport.c ---- openssh-7.4p1/openbsd-compat/bindresvport.c.coverity 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/openbsd-compat/bindresvport.c 2016-12-23 16:40:26.901788691 +0100 -@@ -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-8.7p1/scp.c.coverity openssh-8.7p1/scp.c ---- openssh-8.7p1/scp.c.coverity 2021-08-30 16:23:35.389741329 +0200 -+++ openssh-8.7p1/scp.c 2021-08-30 16:27:04.854555296 +0200 -@@ -186,11 +186,11 @@ killchild(int signo) - { - if (do_cmd_pid > 1) { - kill(do_cmd_pid, signo ? signo : SIGTERM); -- waitpid(do_cmd_pid, NULL, 0); -+ (void) waitpid(do_cmd_pid, NULL, 0); - } - if (do_cmd_pid2 > 1) { - kill(do_cmd_pid2, signo ? signo : SIGTERM); -- waitpid(do_cmd_pid2, NULL, 0); -+ (void) waitpid(do_cmd_pid2, NULL, 0); - } - - if (signo) -diff -up openssh-7.4p1/servconf.c.coverity openssh-7.4p1/servconf.c ---- openssh-7.4p1/servconf.c.coverity 2016-12-23 16:40:26.896788690 +0100 -+++ openssh-7.4p1/servconf.c 2016-12-23 16:40:26.901788691 +0100 -@@ -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/sftp.c.coverity openssh-7.4p1/sftp.c ---- openssh-7.4p1/sftp.c.coverity 2016-12-19 05:59:41.000000000 +0100 -+++ openssh-7.4p1/sftp.c 2016-12-23 16:40:26.903788691 +0100 -@@ -224,7 +224,7 @@ killchild(int signo) - pid = sshpid; - if (pid > 1) { - kill(pid, SIGTERM); -- waitpid(pid, NULL, 0); -+ (void) waitpid(pid, NULL, 0); - } - - _exit(1); -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 */ -@@ -1220,8 +1220,8 @@ main(int ac, char **av) - sanitise_stdfd(); - - /* drop */ -- setegid(getgid()); -- setgid(getgid()); -+ (void) setegid(getgid()); -+ (void) setgid(getgid()); - - platform_disable_tracing(0); /* strict=no */ - -diff -up openssh-8.5p1/ssh.c.coverity openssh-8.5p1/ssh.c ---- openssh-8.5p1/ssh.c.coverity 2021-03-24 12:03:33.779968138 +0100 -+++ openssh-8.5p1/ssh.c 2021-03-24 12:03:33.786968187 +0100 -@@ -1746,6 +1746,7 @@ control_persist_detach(void) - close(muxserver_sock); - muxserver_sock = -1; - options.control_master = SSHCTL_MASTER_NO; -+ /* coverity[leaked_handle: FALSE]*/ - muxclient(options.control_path); - /* muxclient() doesn't return on success. */ - fatal("Failed to connect to new control master"); -diff -up openssh-7.4p1/sshd.c.coverity openssh-7.4p1/sshd.c ---- openssh-7.4p1/sshd.c.coverity 2016-12-23 16:40:26.897788690 +0100 -+++ openssh-7.4p1/sshd.c 2016-12-23 16:40:26.904788692 +0100 -@@ -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/openssh-6.8p1-sshdT-output.patch b/openssh-6.8p1-sshdT-output.patch deleted file mode 100644 index 156e66d..0000000 --- a/openssh-6.8p1-sshdT-output.patch +++ /dev/null @@ -1,12 +0,0 @@ -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/openssh-7.4p1-systemd.patch b/openssh-7.4p1-systemd.patch deleted file mode 100644 index 1242aac..0000000 --- a/openssh-7.4p1-systemd.patch +++ /dev/null @@ -1,98 +0,0 @@ -commit 0e22b79bfde45a7cf7a2e51a68ec11c4285f3b31 -Author: Jakub Jelen -Date: Mon Nov 21 15:04:06 2016 +0100 - - systemd stuff - -diff --git a/configure.ac b/configure.ac -index 2ffc369..162ce92 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -4265,6 +4265,30 @@ AC_ARG_WITH([kerberos5], - AC_SUBST([K5LIBS]) - AC_SUBST([CHANNELLIBS]) - -+# Check whether user wants systemd support -+SYSTEMD_MSG="no" -+AC_ARG_WITH(systemd, -+ [ --with-systemd Enable systemd support], -+ [ if test "x$withval" != "xno" ; then -+ AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no]) -+ if test "$PKGCONFIG" != "no"; then -+ AC_MSG_CHECKING([for libsystemd]) -+ if $PKGCONFIG --exists libsystemd; then -+ SYSTEMD_CFLAGS=`$PKGCONFIG --cflags libsystemd` -+ SYSTEMD_LIBS=`$PKGCONFIG --libs libsystemd` -+ CPPFLAGS="$CPPFLAGS $SYSTEMD_CFLAGS" -+ SSHDLIBS="$SSHDLIBS $SYSTEMD_LIBS" -+ AC_MSG_RESULT([yes]) -+ AC_DEFINE(HAVE_SYSTEMD, 1, [Define if you want systemd support.]) -+ SYSTEMD_MSG="yes" -+ else -+ AC_MSG_RESULT([no]) -+ fi -+ fi -+ fi ] -+) -+ -+ - # Looking for programs, paths and files - - PRIVSEP_PATH=/var/empty -@@ -5097,6 +5121,7 @@ echo " libedit support: $LIBEDIT_MSG" - echo " Solaris process contract support: $SPC_MSG" - echo " Solaris project support: $SP_MSG" - echo " Solaris privilege support: $SPP_MSG" -+echo " systemd support: $SYSTEMD_MSG" - echo " IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG" - echo " Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG" - echo " BSD Auth support: $BSD_AUTH_MSG" -diff --git a/contrib/sshd.service b/contrib/sshd.service -new file mode 100644 -index 0000000..e0d4923 ---- /dev/null -+++ b/contrib/sshd.service -@@ -0,0 +1,16 @@ -+[Unit] -+Description=OpenSSH server daemon -+Documentation=man:sshd(8) man:sshd_config(5) -+After=network.target -+ -+[Service] -+Type=notify -+ExecStart=/usr/sbin/sshd -D $OPTIONS -+ExecReload=/bin/kill -HUP $MAINPID -+KillMode=process -+Restart=on-failure -+RestartPreventExitStatus=255 -+ -+[Install] -+WantedBy=multi-user.target -+ -diff --git a/sshd.c b/sshd.c -index 816611c..b8b9d13 100644 ---- a/sshd.c -+++ b/sshd.c -@@ -85,6 +85,10 @@ - #include - #endif - -+#ifdef HAVE_SYSTEMD -+#include -+#endif -+ - #include "xmalloc.h" - #include "ssh.h" - #include "ssh2.h" -@@ -1888,6 +1892,11 @@ main(int ac, char **av) - } - } - -+#ifdef HAVE_SYSTEMD -+ /* Signal systemd that we are ready to accept connections */ -+ sd_notify(0, "READY=1"); -+#endif -+ - /* Accept a connection and return in a forked child */ - server_accept_loop(&sock_in, &sock_out, - &newsock, config_s); diff --git a/openssh-7.5p1-sandbox.patch b/openssh-7.5p1-sandbox.patch deleted file mode 100644 index 90640a0..0000000 --- a/openssh-7.5p1-sandbox.patch +++ /dev/null @@ -1,86 +0,0 @@ -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/openssh-7.8p1-UsePAM-warning.patch b/openssh-7.8p1-UsePAM-warning.patch deleted file mode 100644 index a94419e..0000000 --- a/openssh-7.8p1-UsePAM-warning.patch +++ /dev/null @@ -1,26 +0,0 @@ -diff -up openssh-8.6p1/sshd.c.log-usepam-no openssh-8.6p1/sshd.c ---- openssh-8.6p1/sshd.c.log-usepam-no 2021-04-19 14:00:45.099735129 +0200 -+++ openssh-8.6p1/sshd.c 2021-04-19 14:03:21.140920974 +0200 -@@ -1749,6 +1749,10 @@ main(int ac, char **av) - parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, - cfg, &includes, NULL, rexeced_flag); - -+ /* 'UsePAM no' is not supported in Fedora */ -+ if (! options.use_pam) -+ logit("WARNING: 'UsePAM no' is not supported in Fedora and may cause several problems."); -+ - #ifdef WITH_OPENSSL - if (options.moduli_file != NULL) - dh_set_moduli_file(options.moduli_file); -diff -up openssh-8.6p1/sshd_config.log-usepam-no openssh-8.6p1/sshd_config ---- openssh-8.6p1/sshd_config.log-usepam-no 2021-04-19 14:00:45.098735121 +0200 -+++ openssh-8.6p1/sshd_config 2021-04-19 14:00:45.099735129 +0200 -@@ -87,6 +87,8 @@ AuthorizedKeysFile .ssh/authorized_keys - # If you just want the PAM account and session checks to run without - # PAM authentication, then enable this but set PasswordAuthentication - # and KbdInteractiveAuthentication to 'no'. -+# WARNING: 'UsePAM no' is not supported in Fedora and may cause several -+# problems. - #UsePAM no - - #AllowAgentForwarding yes diff --git a/openssh-8.0p1-keygen-strip-doseol.patch b/openssh-8.0p1-keygen-strip-doseol.patch deleted file mode 100644 index 3117a7a..0000000 --- a/openssh-8.0p1-keygen-strip-doseol.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff -up openssh-8.0p1/ssh-keygen.c.strip-doseol openssh-8.0p1/ssh-keygen.c ---- openssh-8.0p1/ssh-keygen.c.strip-doseol 2021-03-18 17:41:34.472404994 +0100 -+++ openssh-8.0p1/ssh-keygen.c 2021-03-18 17:41:55.255538761 +0100 -@@ -901,7 +901,7 @@ do_fingerprint(struct passwd *pw) - while (getline(&line, &linesize, f) != -1) { - lnum++; - cp = line; -- cp[strcspn(cp, "\n")] = '\0'; -+ cp[strcspn(cp, "\r\n")] = '\0'; - /* Trim leading space and comments */ - cp = line + strspn(line, " \t"); - if (*cp == '#' || *cp == '\0') diff --git a/openssh-8.0p1-openssl-kdf.patch b/openssh-8.0p1-openssl-kdf.patch deleted file mode 100644 index 5d76a4f..0000000 --- a/openssh-8.0p1-openssl-kdf.patch +++ /dev/null @@ -1,137 +0,0 @@ -commit 2c3ef499bfffce3cfd315edeebf202850ba4e00a -Author: Jakub Jelen -Date: Tue Apr 16 15:35:18 2019 +0200 - - Use the new OpenSSL KDF - -diff --git a/configure.ac b/configure.ac -index 2a455e4e..e01c3d43 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -2712,6 +2712,7 @@ if test "x$openssl" = "xyes" ; then - HMAC_CTX_init \ - RSA_generate_key_ex \ - RSA_get_default_method \ -+ EVP_KDF_CTX_new_id \ - ]) - - # OpenSSL_add_all_algorithms may be a macro. -diff --git a/kex.c b/kex.c -index b6f041f4..1fbce2bb 100644 ---- a/kex.c -+++ b/kex.c -@@ -38,6 +38,9 @@ - #ifdef WITH_OPENSSL - #include - #include -+# ifdef HAVE_EVP_KDF_CTX_NEW_ID -+# include -+# endif - #endif - - #include "ssh.h" -@@ -942,6 +945,95 @@ kex_choose_conf(struct ssh *ssh) - return r; - } - -+#ifdef HAVE_EVP_KDF_CTX_NEW_ID -+static const EVP_MD * -+digest_to_md(int digest_type) -+{ -+ switch (digest_type) { -+ case SSH_DIGEST_SHA1: -+ return EVP_sha1(); -+ case SSH_DIGEST_SHA256: -+ return EVP_sha256(); -+ case SSH_DIGEST_SHA384: -+ return EVP_sha384(); -+ case SSH_DIGEST_SHA512: -+ return EVP_sha512(); -+ } -+ return NULL; -+} -+ -+static int -+derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, -+ const struct sshbuf *shared_secret, u_char **keyp) -+{ -+ struct kex *kex = ssh->kex; -+ EVP_KDF_CTX *ctx = NULL; -+ u_char *key = NULL; -+ int r, key_len; -+ -+ if ((key_len = ssh_digest_bytes(kex->hash_alg)) == 0) -+ return SSH_ERR_INVALID_ARGUMENT; -+ key_len = ROUNDUP(need, key_len); -+ if ((key = calloc(1, key_len)) == NULL) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ ctx = EVP_KDF_CTX_new_id(EVP_KDF_SSHKDF); -+ if (!ctx) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, digest_to_md(kex->hash_alg)); -+ if (r != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, -+ sshbuf_ptr(shared_secret), sshbuf_len(shared_secret)); -+ if (r != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, hash, hashlen); -+ if (r != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_TYPE, id); -+ if (r != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ r = EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, -+ sshbuf_ptr(kex->session_id), sshbuf_len(kex->session_id)); -+ if (r != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ r = EVP_KDF_derive(ctx, key, key_len); -+ if (r != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+#ifdef DEBUG_KEX -+ fprintf(stderr, "key '%c'== ", id); -+ dump_digest("key", key, key_len); -+#endif -+ *keyp = key; -+ key = NULL; -+ r = 0; -+ -+out: -+ free (key); -+ EVP_KDF_CTX_free(ctx); -+ if (r < 0) { -+ return r; -+ } -+ return 0; -+} -+#else - static int - derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, - const struct sshbuf *shared_secret, u_char **keyp) -@@ -1004,6 +1096,7 @@ derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, - ssh_digest_free(hashctx); - return r; - } -+#endif /* HAVE_OPENSSL_EVP_KDF_CTX_NEW_ID */ - - #define NKEYS 6 - int - diff --git a/openssh-8.0p1-sshbuf-readonly.patch b/openssh-8.0p1-sshbuf-readonly.patch deleted file mode 100644 index edc8bec..0000000 --- a/openssh-8.0p1-sshbuf-readonly.patch +++ /dev/null @@ -1,152 +0,0 @@ -From 063e1a255b53abde1147522f9aceccfd2a7ceb9b Mon Sep 17 00:00:00 2001 -From: Jakub Jelen -Date: Tue, 2 Mar 2021 19:45:25 +0100 -Subject: [PATCH] Unbreak gsi-openssh by not holding the sshbuf structures - originated from incoming packet buffer - -Keeping buffers from sshpkt_getb_froms() for breaks further packet -processing because the "derived" buffer keeps a "link" to te parent -buffer, which is then considered readonly. - -This addresses the visible issue in the kexgss_server(), which -demonstrated with GSI (requiring more round trips than GSSAPI -with kerberos). - -The additional two places in the client were never hit, because the host -keys are never sent as part of the gssapi key exchange but in case we -would have different server or we would start sending hostkeys as the -code is ready for that, we would hit it anyway. - -Fixes #18 ---- - kexgssc.c | 14 ++++++++++++-- - kexgsss.c | 48 ++++++++++++++++++++++++++++-------------------- - 2 files changed, 40 insertions(+), 22 deletions(-) - -diff --git a/kexgssc.c b/kexgssc.c -index 1c62740e..29b8b031 100644 ---- a/kexgssc.c -+++ b/kexgssc.c -@@ -162,11 +162,16 @@ kexgss_client(struct ssh *ssh) - do { - type = ssh_packet_read(ssh); - if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ char *tmp = NULL; -+ size_t tmp_len = 0; -+ - debug("Received KEXGSS_HOSTKEY"); - if (server_host_key_blob) - fatal("Server host key received more than once"); -- if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) -+ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) - fatal("Failed to read server host key: %s", ssh_err(r)); -+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) -+ fatal("sshbuf_from failed"); - } - } while (type == SSH2_MSG_KEXGSS_HOSTKEY); - -@@ -453,11 +458,16 @@ kexgssgex_client(struct ssh *ssh) - do { - type = ssh_packet_read(ssh); - if (type == SSH2_MSG_KEXGSS_HOSTKEY) { -+ char *tmp = NULL; -+ size_t tmp_len = 0; -+ - debug("Received KEXGSS_HOSTKEY"); - if (server_host_key_blob) - fatal("Server host key received more than once"); -- if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) -+ if ((r = sshpkt_get_string(ssh, &tmp, &tmp_len)) != 0) - fatal("sshpkt failed: %s", ssh_err(r)); -+ if ((server_host_key_blob = sshbuf_from(tmp, tmp_len)) == NULL) -+ fatal("sshbuf_from failed"); - } - } while (type == SSH2_MSG_KEXGSS_HOSTKEY); - -diff --git a/kexgsss.c b/kexgsss.c -index a2c02148..c8b7d652 100644 ---- a/kexgsss.c -+++ b/kexgsss.c -@@ -64,7 +64,7 @@ kexgss_server(struct ssh *ssh) - */ - - OM_uint32 ret_flags = 0; -- gss_buffer_desc gssbuf, recv_tok, msg_tok; -+ gss_buffer_desc gssbuf = {0, NULL}, recv_tok, msg_tok; - gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; - Gssctxt *ctxt = NULL; - struct sshbuf *shared_secret = NULL; -@@ -104,7 +104,7 @@ kexgss_server(struct ssh *ssh) - type = ssh_packet_read(ssh); - switch(type) { - case SSH2_MSG_KEXGSS_INIT: -- if (client_pubkey != NULL) -+ if (gssbuf.value != NULL) - fatal("Received KEXGSS_INIT after initialising"); - if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, - &recv_tok)) != 0 || -@@ -135,6 +135,31 @@ kexgss_server(struct ssh *ssh) - goto out; - - /* Send SSH_MSG_KEXGSS_HOSTKEY here, if we want */ -+ -+ /* Calculate the hash early so we can free the -+ * client_pubkey, which has reference to the parent -+ * buffer state->incoming_packet -+ */ -+ hashlen = sizeof(hash); -+ if ((r = kex_gen_hash( -+ kex->hash_alg, -+ kex->client_version, -+ kex->server_version, -+ kex->peer, -+ kex->my, -+ empty, -+ client_pubkey, -+ server_pubkey, -+ shared_secret, -+ hash, &hashlen)) != 0) -+ goto out; -+ -+ gssbuf.value = hash; -+ gssbuf.length = hashlen; -+ -+ sshbuf_free(client_pubkey); -+ client_pubkey = NULL; -+ - break; - case SSH2_MSG_KEXGSS_CONTINUE: - if ((r = ssh_gssapi_sshpkt_get_buffer_desc(ssh, -@@ -156,7 +181,7 @@ kexgss_server(struct ssh *ssh) - if (maj_status != GSS_S_COMPLETE && send_tok.length == 0) - fatal("Zero length token output when incomplete"); - -- if (client_pubkey == NULL) -+ if (gssbuf.value == NULL) - fatal("No client public key"); - - if (maj_status & GSS_S_CONTINUE_NEEDED) { -@@ -185,23 +210,6 @@ kexgss_server(struct ssh *ssh) - if (!(ret_flags & GSS_C_INTEG_FLAG)) - fatal("Integrity flag wasn't set"); - -- hashlen = sizeof(hash); -- if ((r = kex_gen_hash( -- kex->hash_alg, -- kex->client_version, -- kex->server_version, -- kex->peer, -- kex->my, -- empty, -- client_pubkey, -- server_pubkey, -- shared_secret, -- hash, &hashlen)) != 0) -- goto out; -- -- gssbuf.value = hash; -- gssbuf.length = hashlen; -- - if (GSS_ERROR(PRIVSEP(ssh_gssapi_sign(ctxt, &gssbuf, &msg_tok)))) - fatal("Couldn't get MIC"); - diff --git a/openssh-8.7p1-ibmca.patch b/openssh-8.7p1-ibmca.patch deleted file mode 100644 index 88914bf..0000000 --- a/openssh-8.7p1-ibmca.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- 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/openssh-8.7p1-minrsabits.patch b/openssh-8.7p1-minrsabits.patch deleted file mode 100644 index 2ed59a3..0000000 --- a/openssh-8.7p1-minrsabits.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/readconf.c b/readconf.c -index 7f26c680..42be690b 100644 ---- a/readconf.c -+++ b/readconf.c -@@ -320,6 +320,7 @@ static struct { - { "securitykeyprovider", oSecurityKeyProvider }, - { "knownhostscommand", oKnownHostsCommand }, - { "requiredrsasize", oRequiredRSASize }, -+ { "rsaminsize", oRequiredRSASize }, /* alias */ - { "enableescapecommandline", oEnableEscapeCommandline }, - - { NULL, oBadOption } -diff --git a/servconf.c b/servconf.c -index 29df0463..423772b1 100644 ---- a/servconf.c -+++ b/servconf.c -@@ -676,6 +680,7 @@ static struct { - { "casignaturealgorithms", sCASignatureAlgorithms, SSHCFG_ALL }, - { "securitykeyprovider", sSecurityKeyProvider, SSHCFG_GLOBAL }, - { "requiredrsasize", sRequiredRSASize, SSHCFG_ALL }, -+ { "rsaminsize", sRequiredRSASize, SSHCFG_ALL }, /* alias */ - { "channeltimeout", sChannelTimeout, SSHCFG_ALL }, - { "unusedconnectiontimeout", sUnusedConnectionTimeout, SSHCFG_ALL }, - { NULL, sBadOption, 0 } diff --git a/openssh-8.7p1-nohostsha1proof.patch b/openssh-8.7p1-nohostsha1proof.patch deleted file mode 100644 index 7fea800..0000000 --- a/openssh-8.7p1-nohostsha1proof.patch +++ /dev/null @@ -1,402 +0,0 @@ -diff -up openssh-8.7p1/compat.c.sshrsacheck openssh-8.7p1/compat.c ---- openssh-8.7p1/compat.c.sshrsacheck 2023-01-12 13:29:06.338710923 +0100 -+++ openssh-8.7p1/compat.c 2023-01-12 13:29:06.357711165 +0100 -@@ -43,6 +43,7 @@ void - compat_banner(struct ssh *ssh, const char *version) - { - int i; -+ int forbid_ssh_rsa = 0; - static struct { - char *pat; - int bugs; -@@ -145,16 +146,21 @@ compat_banner(struct ssh *ssh, const cha - }; - - /* process table, return first match */ -+ forbid_ssh_rsa = (ssh->compat & SSH_RH_RSASIGSHA); - ssh->compat = 0; - for (i = 0; check[i].pat; i++) { - if (match_pattern_list(version, check[i].pat, 0) == 1) { - debug_f("match: %s pat %s compat 0x%08x", - version, check[i].pat, check[i].bugs); - ssh->compat = check[i].bugs; -+ if (forbid_ssh_rsa) -+ ssh->compat |= SSH_RH_RSASIGSHA; - return; - } - } - debug_f("no match: %s", version); -+ if (forbid_ssh_rsa) -+ ssh->compat |= SSH_RH_RSASIGSHA; - } - - /* Always returns pointer to allocated memory, caller must free. */ -diff -up openssh-8.7p1/compat.h.sshrsacheck openssh-8.7p1/compat.h ---- openssh-8.7p1/compat.h.sshrsacheck 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/compat.h 2023-01-12 13:29:06.358711178 +0100 -@@ -30,7 +30,7 @@ - #define SSH_BUG_UTF8TTYMODE 0x00000001 - #define SSH_BUG_SIGTYPE 0x00000002 - #define SSH_BUG_SIGTYPE74 0x00000004 --/* #define unused 0x00000008 */ -+#define SSH_RH_RSASIGSHA 0x00000008 - #define SSH_OLD_SESSIONID 0x00000010 - /* #define unused 0x00000020 */ - #define SSH_BUG_DEBUG 0x00000040 -diff -up openssh-8.7p1/monitor.c.sshrsacheck openssh-8.7p1/monitor.c ---- openssh-8.7p1/monitor.c.sshrsacheck 2023-01-20 13:07:54.279676981 +0100 -+++ openssh-8.7p1/monitor.c 2023-01-20 15:01:07.007821379 +0100 -@@ -660,11 +660,12 @@ mm_answer_sign(struct ssh *ssh, int sock - struct sshkey *key; - struct sshbuf *sigbuf = NULL; - u_char *p = NULL, *signature = NULL; -- char *alg = NULL; -+ char *alg = NULL, *effective_alg; - size_t datlen, siglen, alglen; - int r, is_proof = 0; - u_int keyid, compat; - const char proof_req[] = "hostkeys-prove-00@openssh.com"; -+ const char safe_rsa[] = "rsa-sha2-256"; - - debug3_f("entering"); - -@@ -719,18 +720,30 @@ mm_answer_sign(struct ssh *ssh, int sock - } - - if ((key = get_hostkey_by_index(keyid)) != NULL) { -- if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, alg, -+ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 -+ && (sshkey_type_plain(key->type) == KEY_RSA)) { -+ effective_alg = safe_rsa; -+ } else { -+ effective_alg = alg; -+ } -+ if ((r = sshkey_sign(key, &signature, &siglen, p, datlen, effective_alg, - options.sk_provider, NULL, compat)) != 0) - fatal_fr(r, "sign"); - } else if ((key = get_hostkey_public_by_index(keyid, ssh)) != NULL && - auth_sock > 0) { -+ if (ssh->compat & SSH_RH_RSASIGSHA && strcmp(alg, "ssh-rsa") == 0 -+ && (sshkey_type_plain(key->type) == KEY_RSA)) { -+ effective_alg = safe_rsa; -+ } else { -+ effective_alg = alg; -+ } - if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, -- p, datlen, alg, compat)) != 0) -+ p, datlen, effective_alg, compat)) != 0) - fatal_fr(r, "agent sign"); - } else - fatal_f("no hostkey from index %d", keyid); - -- debug3_f("%s %s signature len=%zu", alg, -+ debug3_f("%s (effective: %s) %s signature len=%zu", alg, effective_alg, - is_proof ? "hostkey proof" : "KEX", siglen); - - sshbuf_reset(m); -diff -up openssh-8.7p1/regress/cert-userkey.sh.sshrsacheck openssh-8.7p1/regress/cert-userkey.sh ---- openssh-8.7p1/regress/cert-userkey.sh.sshrsacheck 2023-01-25 14:26:52.885963113 +0100 -+++ openssh-8.7p1/regress/cert-userkey.sh 2023-01-25 14:27:25.757219800 +0100 -@@ -7,7 +7,8 @@ rm -f $OBJ/authorized_keys_$USER $OBJ/us - cp $OBJ/sshd_proxy $OBJ/sshd_proxy_bak - cp $OBJ/ssh_proxy $OBJ/ssh_proxy_bak - --PLAIN_TYPES=`$SSH -Q key-plain | maybe_filter_sk | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` -+#ssh-dss keys are incompatible with DEFAULT crypto policy -+PLAIN_TYPES=`$SSH -Q key-plain | maybe_filter_sk | grep -v 'ssh-dss' | sed 's/^ssh-dss/ssh-dsa/;s/^ssh-//'` - EXTRA_TYPES="" - rsa="" - -diff -up openssh-8.7p1/regress/Makefile.sshrsacheck openssh-8.7p1/regress/Makefile ---- openssh-8.7p1/regress/Makefile.sshrsacheck 2023-01-20 13:07:54.169676051 +0100 -+++ openssh-8.7p1/regress/Makefile 2023-01-20 13:07:54.290677074 +0100 -@@ -2,7 +2,8 @@ - - tests: prep file-tests t-exec unit - --REGRESS_TARGETS= t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 -+#ssh-dss tests will not pass on DEFAULT crypto-policy because of SHA1, skipping -+REGRESS_TARGETS= t1 t2 t3 t4 t5 t7 t8 t9 t10 t11 t12 - - # File based tests - file-tests: $(REGRESS_TARGETS) -diff -up openssh-8.7p1/regress/test-exec.sh.sshrsacheck openssh-8.7p1/regress/test-exec.sh ---- openssh-8.7p1/regress/test-exec.sh.sshrsacheck 2023-01-25 14:24:54.778040819 +0100 -+++ openssh-8.7p1/regress/test-exec.sh 2023-01-25 14:26:39.500858590 +0100 -@@ -581,8 +581,9 @@ maybe_filter_sk() { - fi - } - --SSH_KEYTYPES=`$SSH -Q key-plain | maybe_filter_sk` --SSH_HOSTKEY_TYPES=`$SSH -Q key-plain | maybe_filter_sk` -+#ssh-dss keys are incompatible with DEFAULT crypto policy -+SSH_KEYTYPES=`$SSH -Q key-plain | maybe_filter_sk | grep -v 'ssh-dss'` -+SSH_HOSTKEY_TYPES=`$SSH -Q key-plain | maybe_filter_sk | grep -v 'ssh-dss'` - - for t in ${SSH_KEYTYPES}; do - # generate user key -diff -up openssh-8.7p1/regress/unittests/kex/test_kex.c.sshrsacheck openssh-8.7p1/regress/unittests/kex/test_kex.c ---- openssh-8.7p1/regress/unittests/kex/test_kex.c.sshrsacheck 2023-01-26 13:34:52.645743677 +0100 -+++ openssh-8.7p1/regress/unittests/kex/test_kex.c 2023-01-26 13:36:56.220745823 +0100 -@@ -97,7 +97,8 @@ do_kex_with_key(char *kex, int keytype, - memcpy(kex_params.proposal, myproposal, sizeof(myproposal)); - if (kex != NULL) - kex_params.proposal[PROPOSAL_KEX_ALGS] = kex; -- keyname = strdup(sshkey_ssh_name(private)); -+ keyname = (strcmp(sshkey_ssh_name(private), "ssh-rsa")) ? -+ strdup(sshkey_ssh_name(private)) : strdup("rsa-sha2-256"); - ASSERT_PTR_NE(keyname, NULL); - kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname; - ASSERT_INT_EQ(ssh_init(&client, 0, &kex_params), 0); -@@ -180,7 +181,7 @@ do_kex(char *kex) - { - #ifdef WITH_OPENSSL - do_kex_with_key(kex, KEY_RSA, 2048); -- do_kex_with_key(kex, KEY_DSA, 1024); -+ /* do_kex_with_key(kex, KEY_DSA, 1024); */ - #ifdef OPENSSL_HAS_ECC - do_kex_with_key(kex, KEY_ECDSA, 256); - #endif /* OPENSSL_HAS_ECC */ -diff -up openssh-8.7p1/regress/unittests/sshkey/test_file.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_file.c ---- openssh-8.7p1/regress/unittests/sshkey/test_file.c.sshrsacheck 2023-01-26 12:04:55.946343408 +0100 -+++ openssh-8.7p1/regress/unittests/sshkey/test_file.c 2023-01-26 12:06:35.235164432 +0100 -@@ -110,6 +110,7 @@ sshkey_file_tests(void) - sshkey_free(k2); - TEST_DONE(); - -+ /* Skip this test, SHA1 signatures are not supported - TEST_START("load RSA cert with SHA1 signature"); - ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha1"), &k2), 0); - ASSERT_PTR_NE(k2, NULL); -@@ -117,7 +118,7 @@ sshkey_file_tests(void) - ASSERT_INT_EQ(sshkey_equal_public(k1, k2), 1); - ASSERT_STRING_EQ(k2->cert->signature_type, "ssh-rsa"); - sshkey_free(k2); -- TEST_DONE(); -+ TEST_DONE(); */ - - TEST_START("load RSA cert with SHA512 signature"); - ASSERT_INT_EQ(sshkey_load_cert(test_data_file("rsa_1_sha512"), &k2), 0); -diff -up openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c ---- openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c.sshrsacheck 2023-01-26 12:10:37.533168013 +0100 -+++ openssh-8.7p1/regress/unittests/sshkey/test_fuzz.c 2023-01-26 12:15:35.637631860 +0100 -@@ -333,13 +333,14 @@ sshkey_fuzz_tests(void) - TEST_DONE(); - - #ifdef WITH_OPENSSL -+ /* Skip this test, SHA1 signatures are not supported - TEST_START("fuzz RSA sig"); - buf = load_file("rsa_1"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); - sshbuf_free(buf); - sig_fuzz(k1, "ssh-rsa"); - sshkey_free(k1); -- TEST_DONE(); -+ TEST_DONE();*/ - - TEST_START("fuzz RSA SHA256 sig"); - buf = load_file("rsa_1"); -@@ -357,6 +358,7 @@ sshkey_fuzz_tests(void) - sshkey_free(k1); - TEST_DONE(); - -+ /* Skip this test, SHA1 signatures are not supported - TEST_START("fuzz DSA sig"); - buf = load_file("dsa_1"); - ASSERT_INT_EQ(sshkey_parse_private_fileblob(buf, "", &k1, NULL), 0); -@@ -364,6 +366,7 @@ sshkey_fuzz_tests(void) - sig_fuzz(k1, NULL); - sshkey_free(k1); - TEST_DONE(); -+ */ - - #ifdef OPENSSL_HAS_ECC - TEST_START("fuzz ECDSA sig"); -diff -up openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c.sshrsacheck openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c ---- openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c.sshrsacheck 2023-01-26 11:02:52.339413463 +0100 -+++ openssh-8.7p1/regress/unittests/sshkey/test_sshkey.c 2023-01-26 11:58:42.324253896 +0100 -@@ -60,6 +60,9 @@ build_cert(struct sshbuf *b, struct sshk - u_char *sigblob; - size_t siglen; - -+ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp */ -+ int expected = (sig_alg == NULL || strcmp(sig_alg, "ssh-rsa") == 0) ? SSH_ERR_LIBCRYPTO_ERROR : 0; -+ - ca_buf = sshbuf_new(); - ASSERT_PTR_NE(ca_buf, NULL); - ASSERT_INT_EQ(sshkey_putb(ca_key, ca_buf), 0); -@@ -101,8 +104,9 @@ build_cert(struct sshbuf *b, struct sshk - ASSERT_INT_EQ(sshbuf_put_string(b, NULL, 0), 0); /* reserved */ - ASSERT_INT_EQ(sshbuf_put_stringb(b, ca_buf), 0); /* signature key */ - ASSERT_INT_EQ(sshkey_sign(sign_key, &sigblob, &siglen, -- sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), 0); -- ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ -+ sshbuf_ptr(b), sshbuf_len(b), sig_alg, NULL, NULL, 0), expected); -+ if (expected == 0) -+ ASSERT_INT_EQ(sshbuf_put_string(b, sigblob, siglen), 0); /* signature */ - - free(sigblob); - sshbuf_free(ca_buf); -@@ -119,16 +123,22 @@ signature_test(struct sshkey *k, struct - { - size_t len; - u_char *sig; -+ /* ssh-rsa implies SHA1, forbidden in DEFAULT cp */ -+ int expected = (sig_alg && strcmp(sig_alg, "ssh-rsa") == 0) ? SSH_ERR_LIBCRYPTO_ERROR : 0; -+ if (k && (sshkey_type_plain(k->type) == KEY_DSA || sshkey_type_plain(k->type) == KEY_DSA_CERT)) -+ expected = SSH_ERR_LIBCRYPTO_ERROR; - - ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg, -- NULL, NULL, 0), 0); -- ASSERT_SIZE_T_GT(len, 8); -- ASSERT_PTR_NE(sig, NULL); -- ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); -- ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); -- /* Fuzz test is more comprehensive, this is just a smoke test */ -- sig[len - 5] ^= 0x10; -- ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); -+ NULL, NULL, 0), expected); -+ if (expected == 0) { -+ ASSERT_SIZE_T_GT(len, 8); -+ ASSERT_PTR_NE(sig, NULL); -+ ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); -+ ASSERT_INT_NE(sshkey_verify(bad, sig, len, d, l, NULL, 0, NULL), 0); -+ /* Fuzz test is more comprehensive, this is just a smoke test */ -+ sig[len - 5] ^= 0x10; -+ ASSERT_INT_NE(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0); -+ } - free(sig); - } - -@@ -514,7 +524,7 @@ sshkey_tests(void) - ASSERT_INT_EQ(sshkey_load_public(test_data_file("rsa_1.pub"), &k2, - NULL), 0); - k3 = get_private("rsa_1"); -- build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, NULL); -+ build_cert(b, k2, "ssh-rsa-cert-v01@openssh.com", k3, k1, "rsa-sha2-256"); - ASSERT_INT_EQ(sshkey_from_blob(sshbuf_ptr(b), sshbuf_len(b), &k4), - SSH_ERR_KEY_CERT_INVALID_SIGN_KEY); - ASSERT_PTR_EQ(k4, NULL); -diff -up openssh-8.7p1/regress/unittests/sshsig/tests.c.sshrsacheck openssh-8.7p1/regress/unittests/sshsig/tests.c ---- openssh-8.7p1/regress/unittests/sshsig/tests.c.sshrsacheck 2023-01-26 12:19:23.659513651 +0100 -+++ openssh-8.7p1/regress/unittests/sshsig/tests.c 2023-01-26 12:20:28.021044803 +0100 -@@ -102,9 +102,11 @@ tests(void) - check_sig("rsa.pub", "rsa.sig", msg, namespace); - TEST_DONE(); - -+ /* Skip this test, SHA1 signatures are not supported - TEST_START("check DSA signature"); - check_sig("dsa.pub", "dsa.sig", msg, namespace); - TEST_DONE(); -+ */ - - #ifdef OPENSSL_HAS_ECC - TEST_START("check ECDSA signature"); -diff -up openssh-8.7p1/serverloop.c.sshrsacheck openssh-8.7p1/serverloop.c ---- openssh-8.7p1/serverloop.c.sshrsacheck 2023-01-12 14:57:08.118400073 +0100 -+++ openssh-8.7p1/serverloop.c 2023-01-12 14:59:17.330470518 +0100 -@@ -80,6 +80,7 @@ - #include "auth-options.h" - #include "serverloop.h" - #include "ssherr.h" -+#include "compat.h" - - extern ServerOptions options; - -@@ -737,6 +737,10 @@ server_input_hostkeys_prove(struct ssh * - else if (ssh->kex->flags & KEX_RSA_SHA2_256_SUPPORTED) - sigalg = "rsa-sha2-256"; - } -+ if (ssh->compat & SSH_RH_RSASIGSHA && sigalg == NULL) { -+ sigalg = "rsa-sha2-512"; -+ debug3_f("SHA1 signature is not supported, falling back to %s", sigalg); -+ } - debug3_f("sign %s key (index %d) using sigalg %s", - sshkey_type(key), ndx, sigalg == NULL ? "default" : sigalg); - if ((r = sshbuf_put_cstring(sigbuf, -diff -up openssh-8.7p1/sshconnect2.c.sshrsacheck openssh-8.7p1/sshconnect2.c ---- openssh-8.7p1/sshconnect2.c.sshrsacheck 2023-01-25 15:33:29.140353651 +0100 -+++ openssh-8.7p1/sshconnect2.c 2023-01-25 15:59:34.225364883 +0100 -@@ -1461,6 +1464,14 @@ identity_sign(struct identity *id, u_cha - retried = 1; - goto retry_pin; - } -+ if ((r == SSH_ERR_LIBCRYPTO_ERROR) && strcmp("ssh-rsa", alg)) { -+ char rsa_safe_alg[] = "rsa-sha2-512"; -+ debug3_f("trying to fallback to algorithm %s", rsa_safe_alg); -+ -+ if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, -+ rsa_safe_alg, options.sk_provider, pin, compat)) != 0) -+ debug_fr(r, "sshkey_sign - RSA fallback"); -+ } - goto out; - } - -diff -up openssh-8.7p1/sshd.c.sshrsacheck openssh-8.7p1/sshd.c ---- openssh-8.7p1/sshd.c.sshrsacheck 2023-01-12 13:29:06.355711140 +0100 -+++ openssh-8.7p1/sshd.c 2023-01-12 13:29:06.358711178 +0100 -@@ -1640,6 +1651,7 @@ main(int ac, char **av) - Authctxt *authctxt; - struct connection_info *connection_info = NULL; - sigset_t sigmask; -+ int forbid_ssh_rsa = 0; - - #ifdef HAVE_SECUREWARE - (void)set_auth_parameters(ac, av); -@@ -1938,6 +1950,33 @@ main(int ac, char **av) - key = NULL; - continue; - } -+ if (key && (sshkey_type_plain(key->type) == KEY_RSA || sshkey_type_plain(key->type) == KEY_RSA_CERT)) { -+ size_t sign_size = 0; -+ u_char *tmp = NULL; -+ u_char data[] = "Test SHA1 vector"; -+ int res; -+ -+ res = sshkey_sign(key, &tmp, &sign_size, data, sizeof(data), NULL, NULL, NULL, 0); -+ free(tmp); -+ if (res == SSH_ERR_LIBCRYPTO_ERROR) { -+ verbose_f("sshd: SHA1 in signatures is disabled for RSA keys"); -+ forbid_ssh_rsa = 1; -+ } -+ } -+ if (key && (sshkey_type_plain(key->type) == KEY_DSA || sshkey_type_plain(key->type) == KEY_DSA_CERT)) { -+ size_t sign_size = 0; -+ u_char *tmp = NULL; -+ u_char data[] = "Test SHA1 vector"; -+ int res; -+ -+ res = sshkey_sign(key, &tmp, &sign_size, data, sizeof(data), NULL, NULL, NULL, 0); -+ free(tmp); -+ if (res == SSH_ERR_LIBCRYPTO_ERROR) { -+ logit_f("sshd: ssh-dss is disabled, skipping key file %s", options.host_key_files[i]); -+ key = NULL; -+ continue; -+ } -+ } - if (sshkey_is_sk(key) && - key->sk_flags & SSH_SK_USER_PRESENCE_REQD) { - debug("host key %s requires user presence, ignoring", -@@ -2275,6 +2306,9 @@ main(int ac, char **av) - - check_ip_options(ssh); - -+ if (forbid_ssh_rsa) -+ ssh->compat |= SSH_RH_RSASIGSHA; -+ - /* Prepare the channels layer */ - channel_init_channels(ssh); - channel_set_af(ssh, options.address_family); -diff -up openssh-8.7p1/ssh-rsa.c.sshrsacheck openssh-8.7p1/ssh-rsa.c ---- openssh-8.7p1/ssh-rsa.c.sshrsacheck 2023-01-20 13:07:54.180676144 +0100 -+++ openssh-8.7p1/ssh-rsa.c 2023-01-20 13:07:54.290677074 +0100 -@@ -254,7 +254,8 @@ ssh_rsa_verify(const struct sshkey *key, - ret = SSH_ERR_INVALID_ARGUMENT; - goto out; - } -- if (hash_alg != want_alg) { -+ if (hash_alg != want_alg && want_alg != SSH_DIGEST_SHA1) { -+ debug_f("Unexpected digest algorithm: got %d, wanted %d", hash_alg, want_alg); - ret = SSH_ERR_SIGNATURE_INVALID; - goto out; - } diff --git a/openssh-8.7p1-recursive-scp.patch b/openssh-8.7p1-recursive-scp.patch deleted file mode 100644 index f0d9b0f..0000000 --- a/openssh-8.7p1-recursive-scp.patch +++ /dev/null @@ -1,181 +0,0 @@ -diff -up openssh-8.7p1/scp.c.scp-sftpdirs openssh-8.7p1/scp.c ---- openssh-8.7p1/scp.c.scp-sftpdirs 2022-02-07 12:31:07.407740407 +0100 -+++ openssh-8.7p1/scp.c 2022-02-07 12:31:07.409740424 +0100 -@@ -1324,7 +1324,7 @@ source_sftp(int argc, char *src, char *t - - if (src_is_dir && iamrecursive) { - if (upload_dir(conn, src, abs_dst, pflag, -- SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) { -+ SFTP_PROGRESS_ONLY, 0, 0, 1, 1, 1) != 0) { - error("failed to upload directory %s to %s", src, targ); - errs = 1; - } -diff -up openssh-8.7p1/sftp-client.c.scp-sftpdirs openssh-8.7p1/sftp-client.c ---- openssh-8.7p1/sftp-client.c.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/sftp-client.c 2022-02-07 12:47:59.117516131 +0100 -@@ -971,7 +971,7 @@ do_fsetstat(struct sftp_conn *conn, cons - - /* Implements both the realpath and expand-path operations */ - static char * --do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) -+do_realpath_expand(struct sftp_conn *conn, const char *path, int expand, int create_dir) - { - struct sshbuf *msg; - u_int expected_id, count, id; -@@ -1033,11 +1033,43 @@ do_realpath_expand(struct sftp_conn *con - if ((r = sshbuf_get_u32(msg, &status)) != 0 || - (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0) - fatal_fr(r, "parse status"); -- error("%s %s: %s", expand ? "expand" : "realpath", -- path, *errmsg == '\0' ? fx2txt(status) : errmsg); -- free(errmsg); -- sshbuf_free(msg); -- return NULL; -+ if ((status == SSH2_FX_NO_SUCH_FILE) && create_dir) { -+ memset(&a, '\0', sizeof(a)); -+ if ((r = do_mkdir(conn, path, &a, 0)) != 0) { -+ sshbuf_free(msg); -+ return NULL; -+ } -+ debug2("Sending SSH2_FXP_REALPATH \"%s\" - create dir", path); -+ send_string_request(conn, id, SSH2_FXP_REALPATH, -+ path, strlen(path)); -+ -+ get_msg(conn, msg); -+ if ((r = sshbuf_get_u8(msg, &type)) != 0 || -+ (r = sshbuf_get_u32(msg, &id)) != 0) -+ fatal_fr(r, "parse"); -+ -+ if (id != expected_id) -+ fatal("ID mismatch (%u != %u)", id, expected_id); -+ -+ if (type == SSH2_FXP_STATUS) { -+ free(errmsg); -+ -+ if ((r = sshbuf_get_u32(msg, &status)) != 0 || -+ (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0) -+ fatal_fr(r, "parse status"); -+ error("%s %s: %s", expand ? "expand" : "realpath", -+ path, *errmsg == '\0' ? fx2txt(status) : errmsg); -+ free(errmsg); -+ sshbuf_free(msg); -+ return NULL; -+ } -+ } else { -+ error("%s %s: %s", expand ? "expand" : "realpath", -+ path, *errmsg == '\0' ? fx2txt(status) : errmsg); -+ free(errmsg); -+ sshbuf_free(msg); -+ return NULL; -+ } - } else if (type != SSH2_FXP_NAME) - fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", - SSH2_FXP_NAME, type); -@@ -1039,9 +1067,9 @@ do_realpath_expand(struct sftp_conn *con - } - - char * --do_realpath(struct sftp_conn *conn, const char *path) -+do_realpath(struct sftp_conn *conn, const char *path, int create_dir) - { -- return do_realpath_expand(conn, path, 0); -+ return do_realpath_expand(conn, path, 0, create_dir); - } - - int -@@ -1055,9 +1083,9 @@ do_expand_path(struct sftp_conn *conn, c - { - if (!can_expand_path(conn)) { - debug3_f("no server support, fallback to realpath"); -- return do_realpath_expand(conn, path, 0); -+ return do_realpath_expand(conn, path, 0, 0); - } -- return do_realpath_expand(conn, path, 1); -+ return do_realpath_expand(conn, path, 1, 0); - } - - int -@@ -1807,7 +1835,7 @@ download_dir(struct sftp_conn *conn, con - char *src_canon; - int ret; - -- if ((src_canon = do_realpath(conn, src)) == NULL) { -+ if ((src_canon = do_realpath(conn, src, 0)) == NULL) { - error("download \"%s\": path canonicalization failed", src); - return -1; - } -@@ -2115,12 +2143,12 @@ upload_dir_internal(struct sftp_conn *co - int - upload_dir(struct sftp_conn *conn, const char *src, const char *dst, - int preserve_flag, int print_flag, int resume, int fsync_flag, -- int follow_link_flag, int inplace_flag) -+ int follow_link_flag, int inplace_flag, int create_dir) - { - char *dst_canon; - int ret; - -- if ((dst_canon = do_realpath(conn, dst)) == NULL) { -+ if ((dst_canon = do_realpath(conn, dst, create_dir)) == NULL) { - error("upload \"%s\": path canonicalization failed", dst); - return -1; - } -@@ -2557,7 +2585,7 @@ crossload_dir(struct sftp_conn *from, st - char *from_path_canon; - int ret; - -- if ((from_path_canon = do_realpath(from, from_path)) == NULL) { -+ if ((from_path_canon = do_realpath(from, from_path, 0)) == NULL) { - error("crossload \"%s\": path canonicalization failed", - from_path); - return -1; -diff -up openssh-8.7p1/sftp-client.h.scp-sftpdirs openssh-8.7p1/sftp-client.h ---- openssh-8.7p1/sftp-client.h.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/sftp-client.h 2022-02-07 12:31:07.410740433 +0100 -@@ -111,7 +111,7 @@ int do_fsetstat(struct sftp_conn *, cons - int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a); - - /* Canonicalise 'path' - caller must free result */ --char *do_realpath(struct sftp_conn *, const char *); -+char *do_realpath(struct sftp_conn *, const char *, int); - - /* Canonicalisation with tilde expansion (requires server extension) */ - char *do_expand_path(struct sftp_conn *, const char *); -@@ -159,7 +159,7 @@ int do_upload(struct sftp_conn *, const - * times if 'pflag' is set - */ - int upload_dir(struct sftp_conn *, const char *, const char *, -- int, int, int, int, int, int); -+ int, int, int, int, int, int, int); - - /* - * Download a 'from_path' from the 'from' connection and upload it to -diff -up openssh-8.7p1/sftp.c.scp-sftpdirs openssh-8.7p1/sftp.c ---- openssh-8.7p1/sftp.c.scp-sftpdirs 2021-08-20 06:03:49.000000000 +0200 -+++ openssh-8.7p1/sftp.c 2022-02-07 12:31:07.411740442 +0100 -@@ -760,7 +760,7 @@ process_put(struct sftp_conn *conn, cons - if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { - if (upload_dir(conn, g.gl_pathv[i], abs_dst, - pflag || global_pflag, 1, resume, -- fflag || global_fflag, 0, 0) == -1) -+ fflag || global_fflag, 0, 0, 0) == -1) - err = -1; - } else { - if (do_upload(conn, g.gl_pathv[i], abs_dst, -@@ -1577,7 +1577,7 @@ parse_dispatch_command(struct sftp_conn - if (path1 == NULL || *path1 == '\0') - path1 = xstrdup(startdir); - path1 = make_absolute(path1, *pwd); -- if ((tmp = do_realpath(conn, path1)) == NULL) { -+ if ((tmp = do_realpath(conn, path1, 0)) == NULL) { - err = 1; - break; - } -@@ -2160,7 +2160,7 @@ interactive_loop(struct sftp_conn *conn, - } - #endif /* USE_LIBEDIT */ - -- remote_path = do_realpath(conn, "."); -+ remote_path = do_realpath(conn, ".", 0); - if (remote_path == NULL) - fatal("Need cwd"); - startdir = xstrdup(remote_path); diff --git a/openssh-8.7p1-ssh-manpage.patch b/openssh-8.7p1-ssh-manpage.patch deleted file mode 100644 index c7f6f1e..0000000 --- a/openssh-8.7p1-ssh-manpage.patch +++ /dev/null @@ -1,53 +0,0 @@ -diff --color -ru a/ssh.1 b/ssh.1 ---- a/ssh.1 2022-07-12 11:47:51.307295880 +0200 -+++ b/ssh.1 2022-07-12 11:50:28.793363263 +0200 -@@ -493,6 +493,7 @@ - .It AddressFamily - .It BatchMode - .It BindAddress -+.It BindInterface - .It CanonicalDomains - .It CanonicalizeFallbackLocal - .It CanonicalizeHostname -@@ -510,6 +511,7 @@ - .It ControlPath - .It ControlPersist - .It DynamicForward -+.It EnableSSHKeysign - .It EnableEscapeCommandline - .It EscapeChar - .It ExitOnForwardFailure -@@ -538,6 +540,8 @@ - .It IdentitiesOnly - .It IdentityAgent - .It IdentityFile -+.It IgnoreUnknown -+.It Include - .It IPQoS - .It KbdInteractiveAuthentication - .It KbdInteractiveDevices -@@ -546,6 +550,7 @@ - .It LocalCommand - .It LocalForward - .It LogLevel -+.It LogVerbose - .It MACs - .It Match - .It NoHostAuthenticationForLocalhost -@@ -566,6 +571,8 @@ - .It RemoteCommand - .It RemoteForward - .It RequestTTY -+.It RevokedHostKeys -+.It SecurityKeyProvider - .It RequiredRSASize - .It SendEnv - .It ServerAliveInterval -@@ -575,6 +582,7 @@ - .It StreamLocalBindMask - .It StreamLocalBindUnlink - .It StrictHostKeyChecking -+.It SyslogFacility - .It TCPKeepAlive - .It Tunnel - .It TunnelDevice diff --git a/openssh-9.0p1-audit-log.patch b/openssh-9.0p1-audit-log.patch deleted file mode 100644 index fbf5094..0000000 --- a/openssh-9.0p1-audit-log.patch +++ /dev/null @@ -1,119 +0,0 @@ -diff -up openssh-9.0p1/audit-bsm.c.patch openssh-9.0p1/audit-bsm.c ---- openssh-9.0p1/audit-bsm.c.patch 2022-10-24 15:02:16.544858331 +0200 -+++ openssh-9.0p1/audit-bsm.c 2022-10-24 14:51:43.685766639 +0200 -@@ -405,7 +405,7 @@ audit_session_close(struct logininfo *li - } - - int --audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) -+audit_keyusage(struct ssh *ssh, int host_user, char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) - { - /* not implemented */ - } -diff -up openssh-9.0p1/audit.c.patch openssh-9.0p1/audit.c ---- openssh-9.0p1/audit.c.patch 2022-10-24 15:02:16.544858331 +0200 -+++ openssh-9.0p1/audit.c 2022-10-24 15:20:38.854548226 +0200 -@@ -116,12 +116,22 @@ audit_event_lookup(ssh_audit_event_t ev) - void - audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key) - { -- char *fp; -+ char *key_fp = NULL; -+ char *issuer_fp = NULL; -+ struct sshkey_cert *cert = NULL; - -- fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); -- if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0) -+ key_fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX); -+ if (sshkey_is_cert(key) && key->cert != NULL && key->cert->signature_key != NULL) { -+ cert = key->cert; -+ issuer_fp = sshkey_fingerprint(cert->signature_key, -+ options.fingerprint_hash, SSH_FP_DEFAULT); -+ } -+ if (audit_keyusage(ssh, host_user, key_fp, cert, issuer_fp, (*rv == 0)) == 0) - *rv = -SSH_ERR_INTERNAL_ERROR; -- free(fp); -+ if (key_fp) -+ free(key_fp); -+ if (issuer_fp) -+ free(issuer_fp); - } - - void -diff -up openssh-9.0p1/audit.h.patch openssh-9.0p1/audit.h ---- openssh-9.0p1/audit.h.patch 2022-10-24 15:02:16.544858331 +0200 -+++ openssh-9.0p1/audit.h 2022-10-24 14:58:20.887565518 +0200 -@@ -64,7 +64,7 @@ void audit_session_close(struct logininf - int audit_run_command(struct ssh *, const char *); - void audit_end_command(struct ssh *, int, const char *); - ssh_audit_event_t audit_classify_auth(const char *); --int audit_keyusage(struct ssh *, int, char *, int); -+int audit_keyusage(struct ssh *, int, const char *, const struct sshkey_cert *, const char *, int); - void audit_key(struct ssh *, int, int *, const struct sshkey *); - void audit_unsupported(struct ssh *, int); - void audit_kex(struct ssh *, int, char *, char *, char *, char *); -diff -up openssh-9.0p1/audit-linux.c.patch openssh-9.0p1/audit-linux.c ---- openssh-9.0p1/audit-linux.c.patch 2022-10-24 15:02:16.544858331 +0200 -+++ openssh-9.0p1/audit-linux.c 2022-10-24 15:21:58.165303951 +0200 -@@ -137,10 +137,12 @@ fatal_report: - } - - int --audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv) -+audit_keyusage(struct ssh *ssh, int host_user, const char *key_fp, const struct sshkey_cert *cert, const char *issuer_fp, int rv) - { - char buf[AUDIT_LOG_SIZE]; - int audit_fd, rc, saved_errno; -+ const char *rip; -+ u_int i; - - audit_fd = audit_open(); - if (audit_fd < 0) { -@@ -150,14 +152,44 @@ audit_keyusage(struct ssh *ssh, int host - else - return 0; /* Must prevent login */ - } -+ rip = ssh_remote_ipaddr(ssh); - snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased"); - rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -- buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv); -+ buf, audit_username(), -1, NULL, rip, NULL, rv); - if ((rc < 0) && ((rc != -1) || (getuid() == 0))) - goto out; -- snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp); -+ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", key_fp); - rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL, -- ssh_remote_ipaddr(ssh), NULL, rv); -+ rip, NULL, rv); -+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) -+ goto out; -+ -+ if (cert) { -+ char *pbuf; -+ -+ pbuf = audit_encode_nv_string("key_id", cert->key_id, 0); -+ if (pbuf == NULL) -+ goto out; -+ snprintf(buf, sizeof(buf), "cert %s cert_serial=%llu cert_issuer_alg=\"%s\" cert_issuer_fp=\"%s\"", -+ pbuf, (unsigned long long)cert->serial, sshkey_type(cert->signature_key), issuer_fp); -+ free(pbuf); -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, rip, NULL, rv); -+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) -+ goto out; -+ -+ for (i = 0; cert->principals != NULL && i < cert->nprincipals; i++) { -+ pbuf = audit_encode_nv_string("cert_principal", cert->principals[i], 0); -+ if (pbuf == NULL) -+ goto out; -+ snprintf(buf, sizeof(buf), "principal %s", pbuf); -+ free(pbuf); -+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL, -+ buf, audit_username(), -1, NULL, rip, NULL, rv); -+ if ((rc < 0) && ((rc != -1) || (getuid() == 0))) -+ goto out; -+ } -+ } - out: - saved_errno = errno; - audit_close(audit_fd); diff --git a/openssh-9.0p1-evp-fips-dh.patch b/openssh-9.0p1-evp-fips-dh.patch deleted file mode 100644 index d0470d9..0000000 --- a/openssh-9.0p1-evp-fips-dh.patch +++ /dev/null @@ -1,292 +0,0 @@ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/dh.c openssh-9.0p1-patched/dh.c ---- openssh-9.0p1/dh.c 2023-05-25 09:24:28.730868316 +0200 -+++ openssh-9.0p1-patched/dh.c 2023-05-25 09:23:44.841379532 +0200 -@@ -37,6 +37,9 @@ - #include - #include - #include -+#include -+#include -+#include - - #include "dh.h" - #include "pathnames.h" -@@ -290,10 +293,15 @@ - int - dh_gen_key(DH *dh, int need) - { -- int pbits; -- const BIGNUM *dh_p, *pub_key; -+ const BIGNUM *dh_p, *dh_g; -+ BIGNUM *pub_key = NULL, *priv_key = NULL; -+ EVP_PKEY *pkey = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ OSSL_PARAM_BLD *param_bld = NULL; -+ OSSL_PARAM *params = NULL; -+ int pbits, r = 0; - -- DH_get0_pqg(dh, &dh_p, NULL, NULL); -+ DH_get0_pqg(dh, &dh_p, NULL, &dh_g); - - if (need < 0 || dh_p == NULL || - (pbits = BN_num_bits(dh_p)) <= 0 || -@@ -301,19 +309,85 @@ - return SSH_ERR_INVALID_ARGUMENT; - if (need < 256) - need = 256; -+ -+ if ((param_bld = OSSL_PARAM_BLD_new()) == NULL || -+ (ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL) { -+ OSSL_PARAM_BLD_free(param_bld); -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ -+ if (OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_FFC_P, dh_p) != 1 || -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_FFC_G, dh_g) != 1) { -+ error_f("Could not set p,q,g parameters"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } - /* - * Pollard Rho, Big step/Little Step attacks are O(sqrt(n)), - * so double requested need here. - */ -- if (!DH_set_length(dh, MINIMUM(need * 2, pbits - 1))) -- return SSH_ERR_LIBCRYPTO_ERROR; -- -- if (DH_generate_key(dh) == 0) -- return SSH_ERR_LIBCRYPTO_ERROR; -- DH_get0_key(dh, &pub_key, NULL); -- if (!dh_pub_is_valid(dh, pub_key)) -- return SSH_ERR_INVALID_FORMAT; -- return 0; -+ if (OSSL_PARAM_BLD_push_int(param_bld, -+ OSSL_PKEY_PARAM_DH_PRIV_LEN, -+ MINIMUM(need * 2, pbits - 1)) != 1 || -+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_fromdata_init(ctx) != 1) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_fromdata(ctx, &pkey, -+ EVP_PKEY_KEY_PARAMETERS, params) != 1) { -+ error_f("Failed key generation"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* reuse context for key generation */ -+ EVP_PKEY_CTX_free(ctx); -+ ctx = NULL; -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || -+ EVP_PKEY_keygen_init(ctx) != 1) { -+ error_f("Could not create or init context"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_generate(ctx, &pkey) != 1) { -+ error_f("Could not generate keys"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_public_check(ctx) != 1) { -+ error_f("The public key is incorrect"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, -+ &pub_key) != 1 || -+ EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, -+ &priv_key) != 1 || -+ DH_set0_key(dh, pub_key, priv_key) != 1) { -+ error_f("Could not set pub/priv keys to DH struct"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* transferred */ -+ pub_key = NULL; -+ priv_key = NULL; -+out: -+ OSSL_PARAM_free(params); -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(pkey); -+ BN_clear_free(pub_key); -+ BN_clear_free(priv_key); -+ return r; - } - - DH * -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kex.c openssh-9.0p1-patched/kex.c ---- openssh-9.0p1/kex.c 2023-05-25 09:24:28.731868327 +0200 -+++ openssh-9.0p1-patched/kex.c 2023-05-25 09:23:44.841379532 +0200 -@@ -1623,3 +1623,47 @@ - return r; - } - -+#ifdef WITH_OPENSSL -+/* -+ * Creates an EVP_PKEY from the given parameters and keys. -+ * The private key can be omitted. -+ */ -+int -+kex_create_evp_dh(EVP_PKEY **pkey, const BIGNUM *p, const BIGNUM *q, -+ const BIGNUM *g, const BIGNUM *pub, const BIGNUM *priv) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ int r = 0; -+ -+ /* create EVP_PKEY-DH key */ -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DH", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { -+ error_f("EVP_PKEY_CTX or PARAM_BLD init failed"); -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ if (OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1 || -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1 || -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1 || -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, pub) != 1) { -+ error_f("Failed pushing params to OSSL_PARAM_BLD"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (priv != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { -+ error_f("Failed pushing private key to OSSL_PARAM_BLD"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ return r; -+} -+#endif /* WITH_OPENSSL */ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kexdh.c openssh-9.0p1-patched/kexdh.c ---- openssh-9.0p1/kexdh.c 2023-05-25 09:24:28.674867692 +0200 -+++ openssh-9.0p1-patched/kexdh.c 2023-05-25 09:25:28.494533889 +0200 -@@ -35,6 +35,10 @@ - - #include "openbsd-compat/openssl-compat.h" - #include -+#include -+#include -+#include -+#include - - #include "sshkey.h" - #include "kex.h" -@@ -83,9 +87,12 @@ - kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) - { - BIGNUM *shared_secret = NULL; -+ const BIGNUM *pub, *priv, *p, *q, *g; -+ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; -+ EVP_PKEY_CTX *ctx = NULL; - u_char *kbuf = NULL; - size_t klen = 0; -- int kout, r; -+ int kout, r = 0; - - #ifdef DEBUG_KEXDH - fprintf(stderr, "dh_pub= "); -@@ -100,24 +107,59 @@ - r = SSH_ERR_MESSAGE_INCOMPLETE; - goto out; - } -- klen = DH_size(kex->dh); -+ -+ DH_get0_key(kex->dh, &pub, &priv); -+ DH_get0_pqg(kex->dh, &p, &q, &g); -+ /* import key */ -+ r = kex_create_evp_dh(&pkey, p, q, g, pub, priv); -+ if (r != 0) { -+ error_f("Could not create EVP_PKEY for dh"); -+ ERR_print_errors_fp(stderr); -+ goto out; -+ } -+ /* import peer key -+ * the parameters should be the same as with pkey -+ */ -+ r = kex_create_evp_dh(&dh_pkey, p, q, g, dh_pub, NULL); -+ if (r != 0) { -+ error_f("Could not import peer key for dh"); -+ ERR_print_errors_fp(stderr); -+ goto out; -+ } -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL) { -+ error_f("Could not init EVP_PKEY_CTX for dh"); -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ if (EVP_PKEY_derive_init(ctx) != 1 || -+ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || -+ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { -+ error_f("Could not get key size"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } - if ((kbuf = malloc(klen)) == NULL || - (shared_secret = BN_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || -- BN_bin2bn(kbuf, kout, shared_secret) == NULL) { -+ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1 || -+ BN_bin2bn(kbuf, klen, shared_secret) == NULL) { -+ error_f("Could not derive key"); - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - #ifdef DEBUG_KEXDH -- dump_digest("shared secret", kbuf, kout); -+ dump_digest("shared secret", kbuf, klen); - #endif - r = sshbuf_put_bignum2(out, shared_secret); - out: - freezero(kbuf, klen); - BN_clear_free(shared_secret); -+ EVP_PKEY_free(pkey); -+ EVP_PKEY_free(dh_pkey); -+ EVP_PKEY_CTX_free(ctx); - return r; - } - -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.0p1/kex.h openssh-9.0p1-patched/kex.h ---- openssh-9.0p1/kex.h 2023-05-25 09:24:28.725868260 +0200 -+++ openssh-9.0p1-patched/kex.h 2023-05-25 09:23:44.841379532 +0200 -@@ -33,6 +33,9 @@ - # include - # include - # include -+# include -+# include -+# include - # ifdef OPENSSL_HAS_ECC - # include - # else /* OPENSSL_HAS_ECC */ -@@ -283,6 +286,8 @@ - const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int) - __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) - __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); -+int kex_create_evp_dh(EVP_PKEY **, const BIGNUM *, const BIGNUM *, -+ const BIGNUM *, const BIGNUM *, const BIGNUM *); - - #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) - void dump_digest(const char *, const u_char *, int); diff --git a/openssh-9.0p1-evp-fips-ecdh.patch b/openssh-9.0p1-evp-fips-ecdh.patch deleted file mode 100644 index 0313c6f..0000000 --- a/openssh-9.0p1-evp-fips-ecdh.patch +++ /dev/null @@ -1,207 +0,0 @@ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac ../openssh-8.7p1/kexecdh.c ./kexecdh.c ---- ../openssh-8.7p1/kexecdh.c 2021-08-20 06:03:49.000000000 +0200 -+++ ./kexecdh.c 2023-04-13 14:30:14.882449593 +0200 -@@ -35,17 +35,57 @@ - #include - - #include -+#include -+#include -+#include -+#include - - #include "sshkey.h" - #include "kex.h" - #include "sshbuf.h" - #include "digest.h" - #include "ssherr.h" -+#include "log.h" - - static int - kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, - const EC_GROUP *, struct sshbuf **); - -+static EC_KEY * -+generate_ec_keys(int ec_nid) -+{ -+ EC_KEY *client_key = NULL; -+ EVP_PKEY *pkey = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ OSSL_PARAM_BLD *param_bld = NULL; -+ OSSL_PARAM *params = NULL; -+ const char *group_name; -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) -+ goto out; -+ if ((group_name = OSSL_EC_curve_nid2name(ec_nid)) == NULL || -+ OSSL_PARAM_BLD_push_utf8_string(param_bld, -+ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || -+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ error_f("Could not create OSSL_PARAM"); -+ goto out; -+ } -+ if (EVP_PKEY_keygen_init(ctx) != 1 || -+ EVP_PKEY_CTX_set_params(ctx, params) != 1 || -+ EVP_PKEY_generate(ctx, &pkey) != 1 || -+ (client_key = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) { -+ error_f("Could not generate ec keys"); -+ goto out; -+ } -+out: -+ EVP_PKEY_free(pkey); -+ EVP_PKEY_CTX_free(ctx); -+ OSSL_PARAM_BLD_free(param_bld); -+ OSSL_PARAM_free(params); -+ return client_key; -+} -+ - int - kex_ecdh_keypair(struct kex *kex) - { -@@ -55,11 +95,7 @@ - struct sshbuf *buf = NULL; - int r; - -- if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { -- r = SSH_ERR_ALLOC_FAIL; -- goto out; -- } -- if (EC_KEY_generate_key(client_key) != 1) { -+ if ((client_key = generate_ec_keys(kex->ec_nid)) == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -@@ -101,11 +137,7 @@ - *server_blobp = NULL; - *shared_secretp = NULL; - -- if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { -- r = SSH_ERR_ALLOC_FAIL; -- goto out; -- } -- if (EC_KEY_generate_key(server_key) != 1) { -+ if ((server_key = generate_ec_keys(kex->ec_nid)) == NULL) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -@@ -140,11 +172,21 @@ - { - struct sshbuf *buf = NULL; - BIGNUM *shared_secret = NULL; -- EC_POINT *dh_pub = NULL; -- u_char *kbuf = NULL; -- size_t klen = 0; -+ EVP_PKEY_CTX *ctx = NULL; -+ EVP_PKEY *pkey = NULL, *dh_pkey = NULL; -+ OSSL_PARAM_BLD *param_bld = NULL; -+ OSSL_PARAM *params = NULL; -+ u_char *kbuf = NULL, *pub = NULL; -+ size_t klen = 0, publen; -+ const char *group_name; - int r; - -+ /* import EC_KEY to EVP_PKEY */ -+ if ((r = ssh_create_evp_ec(key, kex->ec_nid, &pkey)) != 0) { -+ error_f("Could not create EVP_PKEY"); -+ goto out; -+ } -+ - *shared_secretp = NULL; - - if ((buf = sshbuf_new()) == NULL) { -@@ -153,45 +195,82 @@ - } - if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) - goto out; -- if ((dh_pub = EC_POINT_new(group)) == NULL) { -+ -+ /* the public key is in the buffer in octet string UNCOMPRESSED -+ * format. See sshbuf_put_ec */ -+ if ((r = sshbuf_get_string(buf, &pub, &publen)) != 0) -+ goto out; -+ sshbuf_reset(buf); -+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { -+ if ((group_name = OSSL_EC_curve_nid2name(kex->ec_nid)) == NULL) { -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (OSSL_PARAM_BLD_push_octet_string(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, pub, publen) != 1 || -+ OSSL_PARAM_BLD_push_utf8_string(param_bld, -+ OSSL_PKEY_PARAM_GROUP_NAME, group_name, 0) != 1 || -+ (params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ error_f("Failed to set params for dh_pkey"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (EVP_PKEY_fromdata_init(ctx) != 1 || -+ EVP_PKEY_fromdata(ctx, &dh_pkey, -+ EVP_PKEY_PUBLIC_KEY, params) != 1 || -+ EVP_PKEY_public_check(ctx) != 1) { -+ error_f("Peer public key import failed"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- sshbuf_reset(buf); - - #ifdef DEBUG_KEXECDH - fputs("public key:\n", stderr); -- sshkey_dump_ec_point(group, dh_pub); -+ EVP_PKEY_print_public_fp(stderr, dh_pkey, 0, NULL); - #endif -- if (sshkey_ec_validate_public(group, dh_pub) != 0) { -- r = SSH_ERR_MESSAGE_INCOMPLETE; -+ EVP_PKEY_CTX_free(ctx); -+ ctx = NULL; -+ if ((ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pkey, NULL)) == NULL || -+ EVP_PKEY_derive_init(ctx) != 1 || -+ EVP_PKEY_derive_set_peer(ctx, dh_pkey) != 1 || -+ EVP_PKEY_derive(ctx, NULL, &klen) != 1) { -+ error_f("Failed to get derive information"); -+ r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- klen = (EC_GROUP_get_degree(group) + 7) / 8; -- if ((kbuf = malloc(klen)) == NULL || -- (shared_secret = BN_new()) == NULL) { -+ if ((kbuf = malloc(klen)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || -- BN_bin2bn(kbuf, klen, shared_secret) == NULL) { -+ if (EVP_PKEY_derive(ctx, kbuf, &klen) != 1) { - r = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - #ifdef DEBUG_KEXECDH - dump_digest("shared secret", kbuf, klen); - #endif -+ if ((shared_secret = BN_new()) == NULL || -+ (BN_bin2bn(kbuf, klen, shared_secret) == NULL)) { -+ r = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } - if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) - goto out; - *shared_secretp = buf; - buf = NULL; - out: -- EC_POINT_clear_free(dh_pub); -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(pkey); -+ EVP_PKEY_free(dh_pkey); -+ OSSL_PARAM_BLD_free(param_bld); -+ OSSL_PARAM_free(params); - BN_clear_free(shared_secret); - freezero(kbuf, klen); -+ freezero(pub, publen); - sshbuf_free(buf); - return r; - } diff --git a/openssh-9.3p1-merged-openssl-evp.patch b/openssh-9.3p1-merged-openssl-evp.patch deleted file mode 100644 index 28d281c..0000000 --- a/openssh-9.3p1-merged-openssl-evp.patch +++ /dev/null @@ -1,1220 +0,0 @@ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/digest.h openssh-9.3p1-patched/digest.h ---- openssh-9.3p1/digest.h 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1-patched/digest.h 2023-06-06 15:52:25.602551466 +0200 -@@ -32,6 +32,12 @@ - struct sshbuf; - struct ssh_digest_ctx; - -+#ifdef WITH_OPENSSL -+#include -+/* Converts internal digest representation to the OpenSSL one */ -+const EVP_MD *ssh_digest_to_md(int digest_type); -+#endif -+ - /* Looks up a digest algorithm by name */ - int ssh_digest_alg_by_name(const char *name); - -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/digest-openssl.c openssh-9.3p1-patched/digest-openssl.c ---- openssh-9.3p1/digest-openssl.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1-patched/digest-openssl.c 2023-06-06 15:52:25.601551454 +0200 -@@ -64,6 +64,22 @@ - { -1, NULL, 0, NULL }, - }; - -+const EVP_MD * -+ssh_digest_to_md(int digest_type) -+{ -+ switch (digest_type) { -+ case SSH_DIGEST_SHA1: -+ return EVP_sha1(); -+ case SSH_DIGEST_SHA256: -+ return EVP_sha256(); -+ case SSH_DIGEST_SHA384: -+ return EVP_sha384(); -+ case SSH_DIGEST_SHA512: -+ return EVP_sha512(); -+ } -+ return NULL; -+} -+ - static const struct ssh_digest * - ssh_digest_by_alg(int alg) - { -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/ssh-dss.c openssh-9.3p1-patched/ssh-dss.c ---- openssh-9.3p1/ssh-dss.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1-patched/ssh-dss.c 2023-06-06 15:52:25.624551743 +0200 -@@ -32,6 +32,8 @@ - #include - #include - #include -+#include -+#include - - #include - #include -@@ -261,11 +263,15 @@ - const u_char *data, size_t datalen, - const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) - { -+ EVP_PKEY *pkey = NULL; - DSA_SIG *sig = NULL; - const BIGNUM *sig_r, *sig_s; -- u_char digest[SSH_DIGEST_MAX_LENGTH], sigblob[SIGBLOB_LEN]; -- size_t rlen, slen, len, dlen = ssh_digest_bytes(SSH_DIGEST_SHA1); -+ u_char sigblob[SIGBLOB_LEN]; -+ size_t rlen, slen; -+ int len; - struct sshbuf *b = NULL; -+ u_char *sigb = NULL; -+ const u_char *psig = NULL; - int ret = SSH_ERR_INVALID_ARGUMENT; - - if (lenp != NULL) -@@ -276,17 +282,23 @@ - if (key == NULL || key->dsa == NULL || - sshkey_type_plain(key->type) != KEY_DSA) - return SSH_ERR_INVALID_ARGUMENT; -- if (dlen == 0) -- return SSH_ERR_INTERNAL_ERROR; - -- if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, datalen, -- digest, sizeof(digest))) != 0) -+ if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) -+ return ret; -+ ret = sshkey_calculate_signature(pkey, SSH_DIGEST_SHA1, &sigb, &len, -+ data, datalen); -+ EVP_PKEY_free(pkey); -+ if (ret < 0) { - goto out; -+ } - -- if ((sig = DSA_do_sign(digest, dlen, key->dsa)) == NULL) { -+ psig = sigb; -+ if ((sig = d2i_DSA_SIG(NULL, &psig, len)) == NULL) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -+ free(sigb); -+ sigb = NULL; - - DSA_SIG_get0(sig, &sig_r, &sig_s); - rlen = BN_num_bytes(sig_r); -@@ -319,7 +331,7 @@ - *lenp = len; - ret = 0; - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - DSA_SIG_free(sig); - sshbuf_free(b); - return ret; -@@ -331,20 +343,20 @@ - const u_char *data, size_t dlen, const char *alg, u_int compat, - struct sshkey_sig_details **detailsp) - { -+ EVP_PKEY *pkey = NULL; - DSA_SIG *dsig = NULL; - BIGNUM *sig_r = NULL, *sig_s = NULL; -- u_char digest[SSH_DIGEST_MAX_LENGTH], *sigblob = NULL; -- size_t len, hlen = ssh_digest_bytes(SSH_DIGEST_SHA1); -+ u_char *sigblob = NULL; -+ size_t len, slen; - int ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; - char *ktype = NULL; -+ u_char *sigb = NULL, *psig = NULL; - - if (key == NULL || key->dsa == NULL || - sshkey_type_plain(key->type) != KEY_DSA || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; -- if (hlen == 0) -- return SSH_ERR_INTERNAL_ERROR; - - /* fetch signature */ - if ((b = sshbuf_from(sig, siglen)) == NULL) -@@ -386,25 +398,28 @@ - } - sig_r = sig_s = NULL; /* transferred */ - -- /* sha1 the data */ -- if ((ret = ssh_digest_memory(SSH_DIGEST_SHA1, data, dlen, -- digest, sizeof(digest))) != 0) -+ if ((slen = i2d_DSA_SIG(dsig, NULL)) == 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; -- -- switch (DSA_do_verify(digest, hlen, dsig, key->dsa)) { -- case 1: -- ret = 0; -- break; -- case 0: -- ret = SSH_ERR_SIGNATURE_INVALID; -+ } -+ if ((sigb = malloc(slen)) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; - goto out; -- default: -+ } -+ psig = sigb; -+ if ((slen = i2d_DSA_SIG(dsig, &psig)) == 0) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - -+ if ((ret = ssh_create_evp_dss(key, &pkey)) != 0) -+ goto out; -+ ret = sshkey_verify_signature(pkey, SSH_DIGEST_SHA1, data, dlen, -+ sigb, slen); -+ EVP_PKEY_free(pkey); -+ - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - DSA_SIG_free(dsig); - BN_clear_free(sig_r); - BN_clear_free(sig_s); -@@ -415,6 +430,65 @@ - return ret; - } - -+int -+ssh_create_evp_dss(const struct sshkey *k, EVP_PKEY **pkey) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ const BIGNUM *p = NULL, *q = NULL, *g = NULL, *pub = NULL, *priv = NULL; -+ int ret = 0; -+ -+ if (k == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "DSA", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ DSA_get0_pqg(k->dsa, &p, &q, &g); -+ DSA_get0_key(k->dsa, &pub, &priv); -+ -+ if (p != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_P, p) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (q != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_Q, q) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (g != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_FFC_G, g) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (pub != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, -+ pub) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (priv != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PRIV_KEY, -+ priv) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ return ret; -+} -+ - static const struct sshkey_impl_funcs sshkey_dss_funcs = { - /* .size = */ ssh_dss_size, - /* .alloc = */ ssh_dss_alloc, -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/ssh-ecdsa.c openssh-9.3p1-patched/ssh-ecdsa.c ---- openssh-9.3p1/ssh-ecdsa.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1-patched/ssh-ecdsa.c 2023-06-06 15:52:25.626551768 +0200 -@@ -34,6 +34,8 @@ - #include - #include - #include -+#include -+#include - - #include - -@@ -126,19 +128,29 @@ - static int - ssh_ecdsa_generate(struct sshkey *k, int bits) - { -- EC_KEY *private; -+ EVP_PKEY_CTX *ctx = NULL; -+ EVP_PKEY *res = NULL; - - if ((k->ecdsa_nid = sshkey_ecdsa_bits_to_nid(bits)) == -1) - return SSH_ERR_KEY_LENGTH; -- if ((private = EC_KEY_new_by_curve_name(k->ecdsa_nid)) == NULL) -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL) - return SSH_ERR_ALLOC_FAIL; -- if (EC_KEY_generate_key(private) != 1) { -- EC_KEY_free(private); -+ -+ if (EVP_PKEY_keygen_init(ctx) <= 0 || EVP_PKEY_CTX_set_group_name(ctx, OBJ_nid2sn(k->ecdsa_nid)) <= 0 -+ || EVP_PKEY_keygen(ctx, &res) <= 0) { -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(res); - return SSH_ERR_LIBCRYPTO_ERROR; - } -- EC_KEY_set_asn1_flag(private, OPENSSL_EC_NAMED_CURVE); -- k->ecdsa = private; -- return 0; -+ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ -+ k->ecdsa = EVP_PKEY_get1_EC_KEY(res); -+ if (k->ecdsa) -+ EC_KEY_set_asn1_flag(k->ecdsa, OPENSSL_EC_NAMED_CURVE); -+ -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(res); -+ return (k->ecdsa) ? 0 : SSH_ERR_LIBCRYPTO_ERROR; - } - - static int -@@ -228,11 +240,13 @@ - const u_char *data, size_t dlen, - const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) - { -+ EVP_PKEY *pkey = NULL; - ECDSA_SIG *esig = NULL; -+ unsigned char *sigb = NULL; -+ const unsigned char *psig; - const BIGNUM *sig_r, *sig_s; - int hash_alg; -- u_char digest[SSH_DIGEST_MAX_LENGTH]; -- size_t len, hlen; -+ int len; - struct sshbuf *b = NULL, *bb = NULL; - int ret = SSH_ERR_INTERNAL_ERROR; - -@@ -245,18 +259,33 @@ - sshkey_type_plain(key->type) != KEY_ECDSA) - return SSH_ERR_INVALID_ARGUMENT; - -- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || -- (hlen = ssh_digest_bytes(hash_alg)) == 0) -+ if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) - return SSH_ERR_INTERNAL_ERROR; -- if ((ret = ssh_digest_memory(hash_alg, data, dlen, -- digest, sizeof(digest))) != 0) -+ -+#ifdef ENABLE_PKCS11 -+ if (is_ecdsa_pkcs11(key->ecdsa)) { -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ } else { -+#endif -+ if ((ret = ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey)) != 0) -+ return ret; -+#ifdef ENABLE_PKCS11 -+ } -+#endif -+ ret = sshkey_calculate_signature(pkey, hash_alg, &sigb, &len, data, -+ dlen); -+ EVP_PKEY_free(pkey); -+ if (ret < 0) { - goto out; -+ } - -- if ((esig = ECDSA_do_sign(digest, hlen, key->ecdsa)) == NULL) { -+ psig = sigb; -+ if (d2i_ECDSA_SIG(&esig, &psig, len) == NULL) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- - if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; -@@ -280,7 +309,7 @@ - *lenp = len; - ret = 0; - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - sshbuf_free(b); - sshbuf_free(bb); - ECDSA_SIG_free(esig); -@@ -293,22 +322,21 @@ - const u_char *data, size_t dlen, const char *alg, u_int compat, - struct sshkey_sig_details **detailsp) - { -+ EVP_PKEY *pkey = NULL; - ECDSA_SIG *esig = NULL; - BIGNUM *sig_r = NULL, *sig_s = NULL; -- int hash_alg; -- u_char digest[SSH_DIGEST_MAX_LENGTH]; -- size_t hlen; -+ int hash_alg, len; - int ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL, *sigbuf = NULL; - char *ktype = NULL; -+ unsigned char *sigb = NULL, *psig = NULL; - - if (key == NULL || key->ecdsa == NULL || - sshkey_type_plain(key->type) != KEY_ECDSA || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; - -- if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || -- (hlen = ssh_digest_bytes(hash_alg)) == 0) -+ if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1) - return SSH_ERR_INTERNAL_ERROR; - - /* fetch signature */ -@@ -344,28 +372,33 @@ - } - sig_r = sig_s = NULL; /* transferred */ - -- if (sshbuf_len(sigbuf) != 0) { -- ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; -+ /* Figure out the length */ -+ if ((len = i2d_ECDSA_SIG(esig, NULL)) == 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- if ((ret = ssh_digest_memory(hash_alg, data, dlen, -- digest, sizeof(digest))) != 0) -- goto out; -- -- switch (ECDSA_do_verify(digest, hlen, esig, key->ecdsa)) { -- case 1: -- ret = 0; -- break; -- case 0: -- ret = SSH_ERR_SIGNATURE_INVALID; -+ if ((sigb = malloc(len)) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; - goto out; -- default: -+ } -+ psig = sigb; -+ if ((len = i2d_ECDSA_SIG(esig, &psig)) == 0) { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } - -+ if (sshbuf_len(sigbuf) != 0) { -+ ret = SSH_ERR_UNEXPECTED_TRAILING_DATA; -+ goto out; -+ } -+ -+ if (ssh_create_evp_ec(key->ecdsa, key->ecdsa_nid, &pkey) != 0) -+ goto out; -+ ret = sshkey_verify_signature(pkey, hash_alg, data, dlen, sigb, len); -+ EVP_PKEY_free(pkey); -+ - out: -- explicit_bzero(digest, sizeof(digest)); -+ free(sigb); - sshbuf_free(sigbuf); - sshbuf_free(b); - ECDSA_SIG_free(esig); -@@ -375,6 +408,79 @@ - return ret; - } - -+int -+ssh_create_evp_ec(EC_KEY *k, int ecdsa_nid, EVP_PKEY **pkey) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ BN_CTX *bn_ctx = NULL; -+ uint8_t *pub_ser = NULL; -+ const char *group_name; -+ const EC_POINT *pub = NULL; -+ const BIGNUM *priv = NULL; -+ int ret = 0; -+ -+ if (k == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL || -+ (bn_ctx = BN_CTX_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ if ((group_name = OSSL_EC_curve_nid2name(ecdsa_nid)) == NULL || -+ OSSL_PARAM_BLD_push_utf8_string(param_bld, -+ OSSL_PKEY_PARAM_GROUP_NAME, -+ group_name, -+ strlen(group_name)) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((pub = EC_KEY_get0_public_key(k)) != NULL) { -+ const EC_GROUP *group; -+ size_t len; -+ -+ group = EC_KEY_get0_group(k); -+ len = EC_POINT_point2oct(group, pub, -+ POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); -+ if ((pub_ser = malloc(len)) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ EC_POINT_point2oct(group, -+ pub, -+ POINT_CONVERSION_UNCOMPRESSED, -+ pub_ser, -+ len, -+ bn_ctx); -+ if (OSSL_PARAM_BLD_push_octet_string(param_bld, -+ OSSL_PKEY_PARAM_PUB_KEY, -+ pub_ser, -+ len) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ } -+ if ((priv = EC_KEY_get0_private_key(k)) != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, -+ OSSL_PKEY_PARAM_PRIV_KEY, priv) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ BN_CTX_free(bn_ctx); -+ free(pub_ser); -+ return ret; -+} -+ - /* NB. not static; used by ECDSA-SK */ - const struct sshkey_impl_funcs sshkey_ecdsa_funcs = { - /* .size = */ ssh_ecdsa_size, -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/sshkey.c openssh-9.3p1-patched/sshkey.c ---- openssh-9.3p1/sshkey.c 2023-06-06 15:53:36.608444190 +0200 -+++ openssh-9.3p1-patched/sshkey.c 2023-06-06 15:52:25.625551756 +0200 -@@ -34,6 +34,8 @@ - #include - #include - #include -+#include -+#include - #endif - - #include "crypto_api.h" -@@ -575,6 +577,86 @@ - } - - #ifdef WITH_OPENSSL -+int -+sshkey_calculate_signature(EVP_PKEY *pkey, int hash_alg, u_char **sigp, -+ int *lenp, const u_char *data, size_t datalen) -+{ -+ EVP_MD_CTX *ctx = NULL; -+ u_char *sig = NULL; -+ int ret, slen; -+ size_t len; -+ -+ if (sigp == NULL || lenp == NULL) { -+ return SSH_ERR_INVALID_ARGUMENT; -+ } -+ -+ slen = EVP_PKEY_get_size(pkey); -+ if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) -+ return SSH_ERR_INVALID_ARGUMENT; -+ -+ len = slen; -+ if ((sig = malloc(slen)) == NULL) { -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ -+ if ((ctx = EVP_MD_CTX_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto error; -+ } -+ if (EVP_DigestSignInit(ctx, NULL, ssh_digest_to_md(hash_alg), -+ NULL, pkey) != 1 || -+ EVP_DigestSignUpdate(ctx, data, datalen) != 1 || -+ EVP_DigestSignFinal(ctx, sig, &len) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto error; -+ } -+ -+ *sigp = sig; -+ *lenp = len; -+ /* Now owned by the caller */ -+ sig = NULL; -+ ret = 0; -+ -+error: -+ EVP_MD_CTX_free(ctx); -+ free(sig); -+ return ret; -+} -+ -+int -+sshkey_verify_signature(EVP_PKEY *pkey, int hash_alg, const u_char *data, -+ size_t datalen, u_char *sigbuf, int siglen) -+{ -+ EVP_MD_CTX *ctx = NULL; -+ int ret; -+ -+ if ((ctx = EVP_MD_CTX_new()) == NULL) { -+ return SSH_ERR_ALLOC_FAIL; -+ } -+ if (EVP_DigestVerifyInit(ctx, NULL, ssh_digest_to_md(hash_alg), -+ NULL, pkey) != 1 || -+ EVP_DigestVerifyUpdate(ctx, data, datalen) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto done; -+ } -+ ret = EVP_DigestVerifyFinal(ctx, sigbuf, siglen); -+ switch (ret) { -+ case 1: -+ ret = 0; -+ break; -+ case 0: -+ ret = SSH_ERR_SIGNATURE_INVALID; -+ break; -+ default: -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ break; -+ } -+ -+done: -+ EVP_MD_CTX_free(ctx); -+ return ret; -+} -+ - /* XXX: these are really begging for a table-driven approach */ - int - sshkey_curve_name_to_nid(const char *name) -@@ -3763,3 +3845,27 @@ - return 0; - } - #endif /* WITH_XMSS */ -+ -+#ifdef WITH_OPENSSL -+EVP_PKEY * -+sshkey_create_evp(OSSL_PARAM_BLD *param_bld, EVP_PKEY_CTX *ctx) -+{ -+ EVP_PKEY *ret = NULL; -+ OSSL_PARAM *params = NULL; -+ if (param_bld == NULL || ctx == NULL) { -+ debug2_f("param_bld or ctx is NULL"); -+ return NULL; -+ } -+ if ((params = OSSL_PARAM_BLD_to_param(param_bld)) == NULL) { -+ debug2_f("Could not build param list"); -+ return NULL; -+ } -+ if (EVP_PKEY_fromdata_init(ctx) != 1 || -+ EVP_PKEY_fromdata(ctx, &ret, EVP_PKEY_KEYPAIR, params) != 1) { -+ debug2_f("EVP_PKEY_fromdata failed"); -+ OSSL_PARAM_free(params); -+ return NULL; -+ } -+ return ret; -+} -+#endif /* WITH_OPENSSL */ -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/sshkey.h openssh-9.3p1-patched/sshkey.h ---- openssh-9.3p1/sshkey.h 2023-06-06 15:53:36.608444190 +0200 -+++ openssh-9.3p1-patched/sshkey.h 2023-06-06 15:52:25.626551768 +0200 -@@ -31,6 +31,9 @@ - #ifdef WITH_OPENSSL - #include - #include -+#include -+#include -+#include - # ifdef OPENSSL_HAS_ECC - # include - # include -@@ -268,6 +271,10 @@ - const char *sshkey_ssh_name_plain(const struct sshkey *); - int sshkey_names_valid2(const char *, int); - char *sshkey_alg_list(int, int, int, char); -+int sshkey_calculate_signature(EVP_PKEY*, int, u_char **, -+ int *, const u_char *, size_t); -+int sshkey_verify_signature(EVP_PKEY *, int, const u_char *, -+ size_t, u_char *, int); - - int sshkey_from_blob(const u_char *, size_t, struct sshkey **); - int sshkey_fromb(struct sshbuf *, struct sshkey **); -@@ -324,6 +331,13 @@ - - void sshkey_sig_details_free(struct sshkey_sig_details *); - -+#ifdef WITH_OPENSSL -+EVP_PKEY *sshkey_create_evp(OSSL_PARAM_BLD *, EVP_PKEY_CTX *); -+int ssh_create_evp_dss(const struct sshkey *, EVP_PKEY **); -+int ssh_create_evp_rsa(const struct sshkey *, EVP_PKEY **); -+int ssh_create_evp_ec(EC_KEY *, int, EVP_PKEY **); -+#endif /* WITH_OPENSSL */ -+ - #ifdef SSHKEY_INTERNAL - int sshkey_sk_fields_equal(const struct sshkey *a, const struct sshkey *b); - void sshkey_sk_cleanup(struct sshkey *k); -@@ -338,6 +352,10 @@ - #endif - #endif - -+#ifdef ENABLE_PKCS11 -+int pkcs11_get_ecdsa_idx(void); -+#endif -+ - #if !defined(WITH_OPENSSL) - # undef RSA - # undef DSA -diff --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-pkcs11.c openssh-9.3p1-patched/ssh-pkcs11.c ---- openssh-9.3p1/ssh-pkcs11.c 2023-06-06 15:53:36.592443989 +0200 -+++ openssh-9.3p1-patched/ssh-pkcs11.c 2023-06-06 15:52:25.626551768 +0200 -@@ -777,8 +777,24 @@ - - return (0); - } -+ -+int -+is_ecdsa_pkcs11(EC_KEY *ecdsa) -+{ -+ if (EC_KEY_get_ex_data(ecdsa, ec_key_idx) != NULL) -+ return 1; -+ return 0; -+} - #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ - -+int -+is_rsa_pkcs11(RSA *rsa) -+{ -+ if (RSA_get_ex_data(rsa, rsa_idx) != NULL) -+ return 1; -+ return 0; -+} -+ - /* remove trailing spaces */ - static void - rmspace(u_char *buf, size_t len) -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/ssh-pkcs11-client.c openssh-9.3p1-patched/ssh-pkcs11-client.c ---- openssh-9.3p1/ssh-pkcs11-client.c 2023-06-06 15:53:36.591443976 +0200 -+++ openssh-9.3p1-patched/ssh-pkcs11-client.c 2023-06-06 15:52:25.626551768 +0200 -@@ -225,8 +225,36 @@ - static RSA_METHOD *helper_rsa; - #if defined(OPENSSL_HAS_ECC) && defined(HAVE_EC_KEY_METHOD_NEW) - static EC_KEY_METHOD *helper_ecdsa; -+ -+int -+is_ecdsa_pkcs11(EC_KEY *ecdsa) -+{ -+ const EC_KEY_METHOD *meth; -+ ECDSA_SIG *(*sign_sig)(const unsigned char *dgst, int dgstlen, -+ const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *eckey) = NULL; -+ -+ meth = EC_KEY_get_method(ecdsa); -+ EC_KEY_METHOD_get_sign(meth, NULL, NULL, &sign_sig); -+ if (sign_sig == ecdsa_do_sign) -+ return 1; -+ return 0; -+} - #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */ - -+int -+is_rsa_pkcs11(RSA *rsa) -+{ -+ const RSA_METHOD *meth; -+ int (*priv_enc)(int flen, const unsigned char *from, -+ unsigned char *to, RSA *rsa, int padding) = NULL; -+ -+ meth = RSA_get_method(rsa); -+ priv_enc = RSA_meth_get_priv_enc(meth); -+ if (priv_enc == rsa_encrypt) -+ return 1; -+ return 0; -+} -+ - /* redirect private key crypto operations to the ssh-pkcs11-helper */ - static void - wrap_key(struct sshkey *k) -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/ssh-pkcs11.h openssh-9.3p1-patched/ssh-pkcs11.h ---- openssh-9.3p1/ssh-pkcs11.h 2023-06-06 15:53:36.592443989 +0200 -+++ openssh-9.3p1-patched/ssh-pkcs11.h 2023-06-06 15:52:25.626551768 +0200 -@@ -39,6 +39,11 @@ - u_int32_t *); - #endif - -+#ifdef HAVE_EC_KEY_METHOD_NEW -+int is_ecdsa_pkcs11(EC_KEY *ecdsa); -+#endif -+int is_rsa_pkcs11(RSA *rsa); -+ - #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11) - #undef ENABLE_PKCS11 - #endif -diff --color -ru -x regress -x autom4te.cache -x '*.o' -x '*.lo' -x Makefile -x config.status -x configure~ -x configure.ac openssh-9.3p1/ssh-rsa.c openssh-9.3p1-patched/ssh-rsa.c ---- openssh-9.3p1/ssh-rsa.c 2023-03-15 22:28:19.000000000 +0100 -+++ openssh-9.3p1-patched/ssh-rsa.c 2023-06-06 15:52:25.627551781 +0200 -@@ -23,6 +23,8 @@ - - #include - #include -+#include -+#include - - #include - #include -@@ -36,7 +38,7 @@ - - #include "openbsd-compat/openssl-compat.h" - --static int openssh_RSA_verify(int, u_char *, size_t, u_char *, size_t, RSA *); -+static int openssh_RSA_verify(int, const u_char *, size_t, u_char *, size_t, EVP_PKEY *); - - static u_int - ssh_rsa_size(const struct sshkey *key) -@@ -131,27 +133,50 @@ - static int - ssh_rsa_generate(struct sshkey *k, int bits) - { -- RSA *private = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ EVP_PKEY *res = NULL; - BIGNUM *f4 = NULL; - int ret = SSH_ERR_INTERNAL_ERROR; - - if (bits < SSH_RSA_MINIMUM_MODULUS_SIZE || - bits > SSHBUF_MAX_BIGNUM * 8) - return SSH_ERR_KEY_LENGTH; -- if ((private = RSA_new()) == NULL || (f4 = BN_new()) == NULL) { -+ -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL -+ || (f4 = BN_new()) == NULL || !BN_set_word(f4, RSA_F4)) { - ret = SSH_ERR_ALLOC_FAIL; - goto out; - } -- if (!BN_set_word(f4, RSA_F4) || -- !RSA_generate_key_ex(private, bits, f4, NULL)) { -+ -+ if (EVP_PKEY_keygen_init(ctx) <= 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0) { -+ ret = SSH_ERR_KEY_LENGTH; -+ goto out; -+ } -+ -+ if (EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, f4) <= 0) -+ goto out; -+ -+ if (EVP_PKEY_keygen(ctx, &res) <= 0) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* This function is deprecated in OpenSSL 3.0 but OpenSSH doesn't worry about it*/ -+ k->rsa = EVP_PKEY_get1_RSA(res); -+ if (k->rsa) { -+ ret = 0; -+ } else { - ret = SSH_ERR_LIBCRYPTO_ERROR; - goto out; - } -- k->rsa = private; -- private = NULL; -- ret = 0; - out: -- RSA_free(private); -+ EVP_PKEY_CTX_free(ctx); -+ EVP_PKEY_free(res); - BN_free(f4); - return ret; - } -@@ -317,21 +342,6 @@ - return -1; - } - --static int --rsa_hash_alg_nid(int type) --{ -- switch (type) { -- case SSH_DIGEST_SHA1: -- return NID_sha1; -- case SSH_DIGEST_SHA256: -- return NID_sha256; -- case SSH_DIGEST_SHA512: -- return NID_sha512; -- default: -- return -1; -- } --} -- - int - ssh_rsa_complete_crt_parameters(struct sshkey *key, const BIGNUM *iqmp) - { -@@ -393,11 +403,10 @@ - const u_char *data, size_t datalen, - const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) - { -- const BIGNUM *rsa_n; -- u_char digest[SSH_DIGEST_MAX_LENGTH], *sig = NULL; -- size_t slen = 0; -- u_int hlen, len; -- int nid, hash_alg, ret = SSH_ERR_INTERNAL_ERROR; -+ EVP_PKEY *pkey = NULL; -+ u_char *sig = NULL; -+ int len, slen = 0; -+ int hash_alg, ret = SSH_ERR_INTERNAL_ERROR; - struct sshbuf *b = NULL; - - if (lenp != NULL) -@@ -409,33 +418,33 @@ - hash_alg = SSH_DIGEST_SHA1; - else - hash_alg = rsa_hash_id_from_keyname(alg); -+ - if (key == NULL || key->rsa == NULL || hash_alg == -1 || - sshkey_type_plain(key->type) != KEY_RSA) - return SSH_ERR_INVALID_ARGUMENT; -- RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); -- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) -- return SSH_ERR_KEY_LENGTH; - slen = RSA_size(key->rsa); -- if (slen <= 0 || slen > SSHBUF_MAX_BIGNUM) -- return SSH_ERR_INVALID_ARGUMENT; -- -- /* hash the data */ -- nid = rsa_hash_alg_nid(hash_alg); -- if ((hlen = ssh_digest_bytes(hash_alg)) == 0) -- return SSH_ERR_INTERNAL_ERROR; -- if ((ret = ssh_digest_memory(hash_alg, data, datalen, -- digest, sizeof(digest))) != 0) -- goto out; -+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) -+ return SSH_ERR_KEY_LENGTH; - -- if ((sig = malloc(slen)) == NULL) { -- ret = SSH_ERR_ALLOC_FAIL; -- goto out; -+#ifdef ENABLE_PKCS11 -+ if (is_rsa_pkcs11(key->rsa)) { -+ if ((pkey = EVP_PKEY_new()) == NULL || -+ EVP_PKEY_set1_RSA(pkey, key->rsa) != 1) -+ return SSH_ERR_ALLOC_FAIL; -+ } else { -+#endif -+ if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) -+ return ret; -+#ifdef ENABLE_PKCS11 - } -- -- if (RSA_sign(nid, digest, hlen, sig, &len, key->rsa) != 1) { -- ret = SSH_ERR_LIBCRYPTO_ERROR; -+#endif -+ ret = sshkey_calculate_signature(pkey, hash_alg, &sig, &len, data, -+ datalen); -+ EVP_PKEY_free(pkey); -+ if (ret < 0) { - goto out; - } -+ - if (len < slen) { - size_t diff = slen - len; - memmove(sig + diff, sig, len); -@@ -444,6 +453,7 @@ - ret = SSH_ERR_INTERNAL_ERROR; - goto out; - } -+ - /* encode signature */ - if ((b = sshbuf_new()) == NULL) { - ret = SSH_ERR_ALLOC_FAIL; -@@ -464,7 +474,6 @@ - *lenp = len; - ret = 0; - out: -- explicit_bzero(digest, sizeof(digest)); - freezero(sig, slen); - sshbuf_free(b); - return ret; -@@ -476,10 +485,10 @@ - const u_char *data, size_t dlen, const char *alg, u_int compat, - struct sshkey_sig_details **detailsp) - { -- const BIGNUM *rsa_n; -+ EVP_PKEY *pkey = NULL; - char *sigtype = NULL; - int hash_alg, want_alg, ret = SSH_ERR_INTERNAL_ERROR; -- size_t len = 0, diff, modlen, hlen; -+ size_t len = 0, diff, modlen; - struct sshbuf *b = NULL; - u_char digest[SSH_DIGEST_MAX_LENGTH], *osigblob, *sigblob = NULL; - -@@ -487,8 +496,7 @@ - sshkey_type_plain(key->type) != KEY_RSA || - sig == NULL || siglen == 0) - return SSH_ERR_INVALID_ARGUMENT; -- RSA_get0_key(key->rsa, &rsa_n, NULL, NULL); -- if (BN_num_bits(rsa_n) < SSH_RSA_MINIMUM_MODULUS_SIZE) -+ if (RSA_bits(key->rsa) < SSH_RSA_MINIMUM_MODULUS_SIZE) - return SSH_ERR_KEY_LENGTH; - - if ((b = sshbuf_from(sig, siglen)) == NULL) -@@ -540,16 +548,13 @@ - explicit_bzero(sigblob, diff); - len = modlen; - } -- if ((hlen = ssh_digest_bytes(hash_alg)) == 0) { -- ret = SSH_ERR_INTERNAL_ERROR; -- goto out; -- } -- if ((ret = ssh_digest_memory(hash_alg, data, dlen, -- digest, sizeof(digest))) != 0) -+ -+ if ((ret = ssh_create_evp_rsa(key, &pkey)) != 0) - goto out; - -- ret = openssh_RSA_verify(hash_alg, digest, hlen, sigblob, len, -- key->rsa); -+ ret = openssh_RSA_verify(hash_alg, data, dlen, sigblob, len, pkey); -+ EVP_PKEY_free(pkey); -+ - out: - freezero(sigblob, len); - free(sigtype); -@@ -558,125 +563,110 @@ - return ret; - } - --/* -- * See: -- * http://www.rsasecurity.com/rsalabs/pkcs/pkcs-1/ -- * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.asn -- */ -- --/* -- * id-sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) -- * oiw(14) secsig(3) algorithms(2) 26 } -- */ --static const u_char id_sha1[] = { -- 0x30, 0x21, /* type Sequence, length 0x21 (33) */ -- 0x30, 0x09, /* type Sequence, length 0x09 */ -- 0x06, 0x05, /* type OID, length 0x05 */ -- 0x2b, 0x0e, 0x03, 0x02, 0x1a, /* id-sha1 OID */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x14 /* Octet string, length 0x14 (20), followed by sha1 hash */ --}; -- --/* -- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html -- * id-sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) -- * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) -- * id-sha256(1) } -- */ --static const u_char id_sha256[] = { -- 0x30, 0x31, /* type Sequence, length 0x31 (49) */ -- 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ -- 0x06, 0x09, /* type OID, length 0x09 */ -- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, /* id-sha256 */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x20 /* Octet string, length 0x20 (32), followed by sha256 hash */ --}; -- --/* -- * See http://csrc.nist.gov/groups/ST/crypto_apps_infra/csor/algorithms.html -- * id-sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) -- * organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) -- * id-sha256(3) } -- */ --static const u_char id_sha512[] = { -- 0x30, 0x51, /* type Sequence, length 0x51 (81) */ -- 0x30, 0x0d, /* type Sequence, length 0x0d (13) */ -- 0x06, 0x09, /* type OID, length 0x09 */ -- 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, /* id-sha512 */ -- 0x05, 0x00, /* NULL */ -- 0x04, 0x40 /* Octet string, length 0x40 (64), followed by sha512 hash */ --}; -- - static int --rsa_hash_alg_oid(int hash_alg, const u_char **oidp, size_t *oidlenp) -+openssh_RSA_verify(int hash_alg, const u_char *data, size_t datalen, -+ u_char *sigbuf, size_t siglen, EVP_PKEY *pkey) - { -- switch (hash_alg) { -- case SSH_DIGEST_SHA1: -- *oidp = id_sha1; -- *oidlenp = sizeof(id_sha1); -- break; -- case SSH_DIGEST_SHA256: -- *oidp = id_sha256; -- *oidlenp = sizeof(id_sha256); -- break; -- case SSH_DIGEST_SHA512: -- *oidp = id_sha512; -- *oidlenp = sizeof(id_sha512); -- break; -- default: -- return SSH_ERR_INVALID_ARGUMENT; -- } -- return 0; --} -+ size_t rsasize = 0; -+ int ret; - --static int --openssh_RSA_verify(int hash_alg, u_char *hash, size_t hashlen, -- u_char *sigbuf, size_t siglen, RSA *rsa) --{ -- size_t rsasize = 0, oidlen = 0, hlen = 0; -- int ret, len, oidmatch, hashmatch; -- const u_char *oid = NULL; -- u_char *decrypted = NULL; -- -- if ((ret = rsa_hash_alg_oid(hash_alg, &oid, &oidlen)) != 0) -- return ret; -- ret = SSH_ERR_INTERNAL_ERROR; -- hlen = ssh_digest_bytes(hash_alg); -- if (hashlen != hlen) { -- ret = SSH_ERR_INVALID_ARGUMENT; -- goto done; -- } -- rsasize = RSA_size(rsa); -+ rsasize = EVP_PKEY_get_size(pkey); - if (rsasize <= 0 || rsasize > SSHBUF_MAX_BIGNUM || - siglen == 0 || siglen > rsasize) { - ret = SSH_ERR_INVALID_ARGUMENT; - goto done; - } -- if ((decrypted = malloc(rsasize)) == NULL) { -- ret = SSH_ERR_ALLOC_FAIL; -- goto done; -- } -- if ((len = RSA_public_decrypt(siglen, sigbuf, decrypted, rsa, -- RSA_PKCS1_PADDING)) < 0) { -- ret = SSH_ERR_LIBCRYPTO_ERROR; -- goto done; -- } -- if (len < 0 || (size_t)len != hlen + oidlen) { -- ret = SSH_ERR_INVALID_FORMAT; -- goto done; -- } -- oidmatch = timingsafe_bcmp(decrypted, oid, oidlen) == 0; -- hashmatch = timingsafe_bcmp(decrypted + oidlen, hash, hlen) == 0; -- if (!oidmatch || !hashmatch) { -- ret = SSH_ERR_SIGNATURE_INVALID; -- goto done; -- } -- ret = 0; -+ -+ ret = sshkey_verify_signature(pkey, hash_alg, data, datalen, -+ sigbuf, siglen); -+ - done: -- freezero(decrypted, rsasize); - return ret; - } - -+int -+ssh_create_evp_rsa(const struct sshkey *k, EVP_PKEY **pkey) -+{ -+ OSSL_PARAM_BLD *param_bld = NULL; -+ EVP_PKEY_CTX *ctx = NULL; -+ int ret = 0; -+ const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL; -+ const BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL; -+ -+ if (k == NULL) -+ return SSH_ERR_INVALID_ARGUMENT; -+ if ((ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) == NULL || -+ (param_bld = OSSL_PARAM_BLD_new()) == NULL) { -+ ret = SSH_ERR_ALLOC_FAIL; -+ goto out; -+ } -+ -+ RSA_get0_key(k->rsa, &n, &e, &d); -+ RSA_get0_factors(k->rsa, &p, &q); -+ RSA_get0_crt_params(k->rsa, &dmp1, &dmq1, &iqmp); -+ -+ if (n != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_N, n) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (e != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_E, e) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (d != NULL && -+ OSSL_PARAM_BLD_push_BN(param_bld, OSSL_PKEY_PARAM_RSA_D, d) != 1) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ if ((*pkey = sshkey_create_evp(param_bld, ctx)) == NULL) { -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+ /* setting this to param_build makes the creation process fail */ -+ if (p != NULL && -+ EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, p) != 1) { -+ debug2_f("failed to add 'p' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (q != NULL && -+ EVP_PKEY_set_bn_param(*pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, q) != 1) { -+ debug2_f("failed to add 'q' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (dmp1 != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_EXPONENT1, dmp1) != 1) { -+ debug2_f("failed to add 'dmp1' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (dmq1 != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_EXPONENT2, dmq1) != 1) { -+ debug2_f("failed to add 'dmq1' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ if (iqmp != NULL && -+ EVP_PKEY_set_bn_param(*pkey, -+ OSSL_PKEY_PARAM_RSA_COEFFICIENT1, iqmp) != 1) { -+ debug2_f("failed to add 'iqmp' param"); -+ ret = SSH_ERR_LIBCRYPTO_ERROR; -+ goto out; -+ } -+ -+out: -+ OSSL_PARAM_BLD_free(param_bld); -+ EVP_PKEY_CTX_free(ctx); -+ return ret; -+} -+ - static const struct sshkey_impl_funcs sshkey_rsa_funcs = { - /* .size = */ ssh_rsa_size, - /* .alloc = */ ssh_rsa_alloc, diff --git a/openssh-9.3p1-openssl-compat.patch b/openssh-9.3p1-openssl-compat.patch deleted file mode 100644 index cf512ef..0000000 --- a/openssh-9.3p1-openssl-compat.patch +++ /dev/null @@ -1,40 +0,0 @@ ---- openssh-9.3p1/openbsd-compat/openssl-compat.c 2023-03-15 22:28:19.000000000 +0100 -+++ /home/dbelyavs/work/upstream/openssh-portable/openbsd-compat/openssl-compat.c 2023-05-25 14:19:42.870841944 +0200 -@@ -33,10 +33,10 @@ - - /* - * OpenSSL version numbers: MNNFFPPS: major minor fix patch status -- * We match major, minor, fix and status (not patch) for <1.0.0. -- * After that, we acceptable compatible fix versions (so we -- * allow 1.0.1 to work with 1.0.0). Going backwards is only allowed -- * within a patch series. -+ * Versions >=3 require only major versions to match. -+ * For versions <3, we accept compatible fix versions (so we allow 1.0.1 -+ * to work with 1.0.0). Going backwards is only allowed within a patch series. -+ * See https://www.openssl.org/policies/releasestrat.html - */ - - int -@@ -48,15 +48,17 @@ - if (headerver == libver) - return 1; - -- /* for versions < 1.0.0, major,minor,fix,status must match */ -- if (headerver < 0x1000000f) { -- mask = 0xfffff00fL; /* major,minor,fix,status */ -+ /* -+ * For versions >= 3.0, only the major and status must match. -+ */ -+ if (headerver >= 0x3000000f) { -+ mask = 0xf000000fL; /* major,status */ - return (headerver & mask) == (libver & mask); - } - - /* -- * For versions >= 1.0.0, major,minor,status must match and library -- * fix version must be equal to or newer than the header. -+ * For versions >= 1.0.0, but <3, major,minor,status must match and -+ * library fix version must be equal to or newer than the header. - */ - mask = 0xfff0000fL; /* major,minor,status */ - hfix = (headerver & 0x000ff000) >> 12; diff --git a/openssh-9.3p1-upstream-cve-2023-38408.patch b/openssh-9.3p1-upstream-cve-2023-38408.patch deleted file mode 100644 index e9ac2ae..0000000 --- a/openssh-9.3p1-upstream-cve-2023-38408.patch +++ /dev/null @@ -1,130 +0,0 @@ -diff --git a/ssh-agent.c b/ssh-agent.c -index 618bb198..8ea831f4 100644 -diff -up openssh-9.3p1/ssh-agent.c.cve openssh-9.3p1/ssh-agent.c ---- openssh-9.3p1/ssh-agent.c.cve 2023-07-21 15:38:13.237276580 +0200 -+++ openssh-9.3p1/ssh-agent.c 2023-07-21 15:41:30.269943569 +0200 -@@ -169,6 +169,12 @@ char socket_dir[PATH_MAX]; - /* Pattern-list of allowed PKCS#11/Security key paths */ - static char *allowed_providers; - -+/* -+ * Allows PKCS11 providers or SK keys that use non-internal providers to -+ * be added over a remote connection (identified by session-bind@openssh.com). -+ */ -+static int remote_add_provider; -+ - /* locking */ - #define LOCK_SIZE 32 - #define LOCK_SALT_SIZE 16 -@@ -1228,6 +1234,12 @@ process_add_identity(SocketEntry *e) - if (strcasecmp(sk_provider, "internal") == 0) { - debug_f("internal provider"); - } else { -+ if (e->nsession_ids != 0 && !remote_add_provider) { -+ verbose("failed add of SK provider \"%.100s\": " -+ "remote addition of providers is disabled", -+ sk_provider); -+ goto out; -+ } - if (realpath(sk_provider, canonical_provider) == NULL) { - verbose("failed provider \"%.100s\": " - "realpath: %s", sk_provider, -@@ -1368,7 +1380,7 @@ no_identities(SocketEntry *e) - - #ifdef ENABLE_PKCS11 - static char * --sanitize_pkcs11_provider(const char *provider) -+sanitize_pkcs11_provider(SocketEntry *e, const char *provider) - { - struct pkcs11_uri *uri = NULL; - char *sane_uri, *module_path = NULL; /* default path */ -@@ -1399,6 +1411,11 @@ sanitize_pkcs11_provider(const char *pro - module_path = strdup(provider); /* simple path */ - - if (module_path != NULL) { /* do not validate default NULL path in URI */ -+ if (e->nsession_ids != 0 && !remote_add_provider) { -+ verbose("failed PKCS#11 add of \"%.100s\": remote addition of " -+ "providers is disabled", provider); -+ return NULL; -+ } - if (realpath(module_path, canonical_provider) == NULL) { - verbose("failed PKCS#11 provider \"%.100s\": realpath: %s", - module_path, strerror(errno)); -@@ -1455,7 +1472,7 @@ process_add_smartcard_key(SocketEntry *e - goto send; - } - -- sane_uri = sanitize_pkcs11_provider(provider); -+ sane_uri = sanitize_pkcs11_provider(e, provider); - if (sane_uri == NULL) - goto send; - -@@ -1516,7 +1533,7 @@ process_remove_smartcard_key(SocketEntry - } - free(pin); - -- sane_uri = sanitize_pkcs11_provider(provider); -+ sane_uri = sanitize_pkcs11_provider(e, provider); - if (sane_uri == NULL) - goto send; - -@@ -2108,7 +2125,9 @@ main(int ac, char **av) - break; - case 'O': - if (strcmp(optarg, "no-restrict-websafe") == 0) -- restrict_websafe = 0; -+ restrict_websafe = 0; -+ else if (strcmp(optarg, "allow-remote-pkcs11") == 0) -+ remote_add_provider = 1; - else - fatal("Unknown -O option"); - break; -diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c -index 6be647ec..ebddf6c3 100644 ---- a/ssh-pkcs11.c -+++ b/ssh-pkcs11.c -@@ -1537,10 +1537,8 @@ pkcs11_register_provider(char *provider_id, char *pin, - error("dlopen %s failed: %s", provider_module, dlerror()); - goto fail; - } -- if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) { -- error("dlsym(C_GetFunctionList) failed: %s", dlerror()); -- goto fail; -- } -+ if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) -+ fatal("dlsym(C_GetFunctionList) failed: %s", dlerror()); - - p->module->handle = handle; - /* setup the pkcs11 callbacks */ ---- a/ssh-agent.1 2023-03-15 22:28:19.000000000 +0100 -+++ b/ssh-agent.1 2023-07-19 21:39:17.981406432 +0200 -@@ -107,9 +107,27 @@ - .It Fl O Ar option - Specify an option when starting - .Nm . --Currently only one option is supported: -+Currently two options are supported: -+.Cm allow-remote-pkcs11 -+and - .Cm no-restrict-websafe . --This instructs -+.Pp -+The -+.Cm allow-remote-pkcs11 -+option allows clients of a forwarded -+.Nm -+to load PKCS#11 or FIDO provider libraries. -+By default only local clients may perform this operation. -+Note that signalling that a -+.Nm -+client remote is performed by -+.Xr ssh 1 , -+and use of other tools to forward access to the agent socket may circumvent -+this restriction. -+.Pp -+The -+.Cm no-restrict-websafe , -+instructs - .Nm - to permit signatures using FIDO keys that might be web authentication - requests. diff --git a/openssh-9.6p1-CVE-2023-48795.patch b/openssh-9.6p1-CVE-2023-48795.patch deleted file mode 100644 index 7ada8b0..0000000 --- a/openssh-9.6p1-CVE-2023-48795.patch +++ /dev/null @@ -1,443 +0,0 @@ -diff --git a/PROTOCOL b/PROTOCOL -index d453c779..ded935eb 100644 ---- a/PROTOCOL -+++ b/PROTOCOL -@@ -137,6 +137,32 @@ than as a named global or channel request to allow pings with very - - This is identical to curve25519-sha256 as later published in RFC8731. - -+1.9 transport: strict key exchange extension -+ -+OpenSSH supports a number of transport-layer hardening measures under -+a "strict KEX" feature. This feature is signalled similarly to the -+RFC8308 ext-info feature: by including a additional algorithm in the -+initiial SSH2_MSG_KEXINIT kex_algorithms field. The client may append -+"kex-strict-c-v00@openssh.com" to its kex_algorithms and the server -+may append "kex-strict-s-v00@openssh.com". These pseudo-algorithms -+are only valid in the initial SSH2_MSG_KEXINIT and MUST be ignored -+if they are present in subsequent SSH2_MSG_KEXINIT packets. -+ -+When an endpoint that supports this extension observes this algorithm -+name in a peer's KEXINIT packet, it MUST make the following changes to -+the the protocol: -+ -+a) During initial KEX, terminate the connection if any unexpected or -+ out-of-sequence packet is received. This includes terminating the -+ connection if the first packet received is not SSH2_MSG_KEXINIT. -+ Unexpected packets for the purpose of strict KEX include messages -+ that are otherwise valid at any time during the connection such as -+ SSH2_MSG_DEBUG and SSH2_MSG_IGNORE. -+b) After sending or receiving a SSH2_MSG_NEWKEYS message, reset the -+ packet sequence number to zero. This behaviour persists for the -+ duration of the connection (i.e. not just the first -+ SSH2_MSG_NEWKEYS). -+ - 2. Connection protocol changes - - 2.1. connection: Channel write close extension "eow@openssh.com" -diff --git a/kex.c b/kex.c -index aa5e792d..d478ff6e 100644 ---- a/kex.c -+++ b/kex.c -@@ -65,7 +65,7 @@ - #endif - - /* prototype */ --static int kex_choose_conf(struct ssh *); -+static int kex_choose_conf(struct ssh *, uint32_t seq); - static int kex_input_newkeys(int, u_int32_t, struct ssh *); - - static const char * const proposal_names[PROPOSAL_MAX] = { -@@ -177,6 +177,18 @@ kex_names_valid(const char *names) - return 1; - } - -+/* returns non-zero if proposal contains any algorithm from algs */ -+static int -+has_any_alg(const char *proposal, const char *algs) -+{ -+ char *cp; -+ -+ if ((cp = match_list(proposal, algs, NULL)) == NULL) -+ return 0; -+ free(cp); -+ return 1; -+} -+ - /* - * Concatenate algorithm names, avoiding duplicates in the process. - * Caller must free returned string. -@@ -184,7 +196,7 @@ kex_names_valid(const char *names) - char * - kex_names_cat(const char *a, const char *b) - { -- char *ret = NULL, *tmp = NULL, *cp, *p, *m; -+ char *ret = NULL, *tmp = NULL, *cp, *p; - size_t len; - - if (a == NULL || *a == '\0') -@@ -201,10 +213,8 @@ kex_names_cat(const char *a, const char *b) - } - strlcpy(ret, a, len); - for ((p = strsep(&cp, ",")); p && *p != '\0'; (p = strsep(&cp, ","))) { -- if ((m = match_list(ret, p, NULL)) != NULL) { -- free(m); -+ if (has_any_alg(ret, p)) - continue; /* Algorithm already present */ -- } - if (strlcat(ret, ",", len) >= len || - strlcat(ret, p, len) >= len) { - free(tmp); -@@ -334,15 +344,23 @@ kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX], - const char *defpropclient[PROPOSAL_MAX] = { KEX_CLIENT }; - const char **defprop = ssh->kex->server ? defpropserver : defpropclient; - u_int i; -+ char *cp; - - if (prop == NULL) - fatal_f("proposal missing"); - -+ /* Append EXT_INFO signalling to KexAlgorithms */ -+ if (kexalgos == NULL) -+ kexalgos = defprop[PROPOSAL_KEX_ALGS]; -+ if ((cp = kex_names_cat(kexalgos, ssh->kex->server ? -+ "kex-strict-s-v00@openssh.com" : -+ "ext-info-c,kex-strict-c-v00@openssh.com")) == NULL) -+ fatal_f("kex_names_cat"); -+ - for (i = 0; i < PROPOSAL_MAX; i++) { - switch(i) { - case PROPOSAL_KEX_ALGS: -- prop[i] = compat_kex_proposal(ssh, -- kexalgos ? kexalgos : defprop[i]); -+ prop[i] = compat_kex_proposal(ssh, cp); - break; - case PROPOSAL_ENC_ALGS_CTOS: - case PROPOSAL_ENC_ALGS_STOC: -@@ -363,6 +381,7 @@ kex_proposal_populate_entries(struct ssh *ssh, char *prop[PROPOSAL_MAX], - prop[i] = xstrdup(defprop[i]); - } - } -+ free(cp); - } - - void -@@ -466,7 +485,12 @@ kex_protocol_error(int type, u_int32_t seq, struct ssh *ssh) - { - int r; - -- error("kex protocol error: type %d seq %u", type, seq); -+ /* If in strict mode, any unexpected message is an error */ -+ if ((ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) { -+ ssh_packet_disconnect(ssh, "strict KEX violation: " -+ "unexpected packet type %u (seqnr %u)", type, seq); -+ } -+ error_f("type %u seq %u", type, seq); - if ((r = sshpkt_start(ssh, SSH2_MSG_UNIMPLEMENTED)) != 0 || - (r = sshpkt_put_u32(ssh, seq)) != 0 || - (r = sshpkt_send(ssh)) != 0) -@@ -563,7 +587,7 @@ kex_input_ext_info(int type, u_int32_t seq, struct ssh *ssh) - if (ninfo >= 1024) { - error("SSH2_MSG_EXT_INFO with too many entries, expected " - "<=1024, received %u", ninfo); -- return SSH_ERR_INVALID_FORMAT; -+ return dispatch_protocol_error(type, seq, ssh); - } - for (i = 0; i < ninfo; i++) { - if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0) -@@ -681,7 +705,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) - error_f("no kex"); - return SSH_ERR_INTERNAL_ERROR; - } -- ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); -+ ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_protocol_error); - ptr = sshpkt_ptr(ssh, &dlen); - if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) - return r; -@@ -717,7 +741,7 @@ kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) - if (!(kex->flags & KEX_INIT_SENT)) - if ((r = kex_send_kexinit(ssh)) != 0) - return r; -- if ((r = kex_choose_conf(ssh)) != 0) -+ if ((r = kex_choose_conf(ssh, seq)) != 0) - return r; - - if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) -@@ -981,20 +1005,14 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) - return (1); - } - --/* returns non-zero if proposal contains any algorithm from algs */ - static int --has_any_alg(const char *proposal, const char *algs) -+kexalgs_contains(char **peer, const char *ext) - { -- char *cp; -- -- if ((cp = match_list(proposal, algs, NULL)) == NULL) -- return 0; -- free(cp); -- return 1; -+ return has_any_alg(peer[PROPOSAL_KEX_ALGS], ext); - } - - static int --kex_choose_conf(struct ssh *ssh) -+kex_choose_conf(struct ssh *ssh, uint32_t seq) - { - struct kex *kex = ssh->kex; - struct newkeys *newkeys; -@@ -1019,13 +1037,23 @@ kex_choose_conf(struct ssh *ssh) - sprop=peer; - } - -- /* Check whether client supports ext_info_c */ -- if (kex->server && (kex->flags & KEX_INITIAL)) { -- char *ext; -- -- ext = match_list("ext-info-c", peer[PROPOSAL_KEX_ALGS], NULL); -- kex->ext_info_c = (ext != NULL); -- free(ext); -+ /* Check whether peer supports ext_info/kex_strict */ -+ if ((kex->flags & KEX_INITIAL) != 0) { -+ if (kex->server) { -+ kex->ext_info_c = kexalgs_contains(peer, "ext-info-c"); -+ kex->kex_strict = kexalgs_contains(peer, -+ "kex-strict-c-v00@openssh.com"); -+ } else { -+ kex->kex_strict = kexalgs_contains(peer, -+ "kex-strict-s-v00@openssh.com"); -+ } -+ if (kex->kex_strict) { -+ debug3_f("will use strict KEX ordering"); -+ if (seq != 0) -+ ssh_packet_disconnect(ssh, -+ "strict KEX violation: " -+ "KEXINIT was not the first packet"); -+ } - } - - /* Check whether client supports rsa-sha2 algorithms */ -diff --git a/kex.h b/kex.h -index 5f7ef784..272ebb43 100644 ---- a/kex.h -+++ b/kex.h -@@ -149,6 +149,7 @@ struct kex { - u_int kex_type; - char *server_sig_algs; - int ext_info_c; -+ int kex_strict; - struct sshbuf *my; - struct sshbuf *peer; - struct sshbuf *client_version; -diff --git a/packet.c b/packet.c -index 52017def..beb214f9 100644 ---- a/packet.c -+++ b/packet.c -@@ -1207,8 +1207,13 @@ ssh_packet_send2_wrapped(struct ssh *ssh) - sshbuf_dump(state->output, stderr); - #endif - /* increment sequence number for outgoing packets */ -- if (++state->p_send.seqnr == 0) -+ if (++state->p_send.seqnr == 0) { -+ if ((ssh->kex->flags & KEX_INITIAL) != 0) { -+ ssh_packet_disconnect(ssh, "outgoing sequence number " -+ "wrapped during initial key exchange"); -+ } - logit("outgoing seqnr wraps around"); -+ } - if (++state->p_send.packets == 0) - if (!(ssh->compat & SSH_BUG_NOREKEY)) - return SSH_ERR_NEED_REKEY; -@@ -1216,6 +1221,11 @@ ssh_packet_send2_wrapped(struct ssh *ssh) - state->p_send.bytes += len; - sshbuf_reset(state->outgoing_packet); - -+ if (type == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) { -+ debug_f("resetting send seqnr %u", state->p_send.seqnr); -+ state->p_send.seqnr = 0; -+ } -+ - if (type == SSH2_MSG_NEWKEYS) - r = ssh_set_newkeys(ssh, MODE_OUT); - else if (type == SSH2_MSG_USERAUTH_SUCCESS && state->server_side) -@@ -1344,8 +1354,7 @@ ssh_packet_read_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - /* Stay in the loop until we have received a complete packet. */ - for (;;) { - /* Try to read a packet from the buffer. */ -- r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p); -- if (r != 0) -+ if ((r = ssh_packet_read_poll_seqnr(ssh, typep, seqnr_p)) != 0) - break; - /* If we got a packet, return it. */ - if (*typep != SSH_MSG_NONE) -@@ -1629,10 +1615,16 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - if ((r = sshbuf_consume(state->input, mac->mac_len)) != 0) - goto out; - } -+ - if (seqnr_p != NULL) - *seqnr_p = state->p_read.seqnr; -- if (++state->p_read.seqnr == 0) -+ if (++state->p_read.seqnr == 0) { -+ if ((ssh->kex->flags & KEX_INITIAL) != 0) { -+ ssh_packet_disconnect(ssh, "incoming sequence number " -+ "wrapped during initial key exchange"); -+ } - logit("incoming seqnr wraps around"); -+ } - if (++state->p_read.packets == 0) - if (!(ssh->compat & SSH_BUG_NOREKEY)) - return SSH_ERR_NEED_REKEY; -@@ -1698,6 +1690,10 @@ ssh_packet_read_poll2(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - #endif - /* reset for next packet */ - state->packlen = 0; -+ if (*typep == SSH2_MSG_NEWKEYS && ssh->kex->kex_strict) { -+ debug_f("resetting read seqnr %u", state->p_read.seqnr); -+ state->p_read.seqnr = 0; -+ } - - if ((r = ssh_packet_check_rekey(ssh)) != 0) - return r; -@@ -1720,10 +1716,39 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - r = ssh_packet_read_poll2(ssh, typep, seqnr_p); - if (r != 0) - return r; -- if (*typep) { -- state->keep_alive_timeouts = 0; -- DBG(debug("received packet type %d", *typep)); -+ if (*typep == 0) { -+ /* no message ready */ -+ return 0; - } -+ state->keep_alive_timeouts = 0; -+ DBG(debug("received packet type %d", *typep)); -+ -+ /* Always process disconnect messages */ -+ if (*typep == SSH2_MSG_DISCONNECT) { -+ if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || -+ (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) -+ return r; -+ /* Ignore normal client exit notifications */ -+ do_log2(ssh->state->server_side && -+ reason == SSH2_DISCONNECT_BY_APPLICATION ? -+ SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, -+ "Received disconnect from %s port %d:" -+ "%u: %.400s", ssh_remote_ipaddr(ssh), -+ ssh_remote_port(ssh), reason, msg); -+ free(msg); -+ return SSH_ERR_DISCONNECTED; -+ } -+ -+ /* -+ * Do not implicitly handle any messages here during initial -+ * KEX when in strict mode. They will be need to be allowed -+ * explicitly by the KEX dispatch table or they will generate -+ * protocol errors. -+ */ -+ if (ssh->kex != NULL && -+ (ssh->kex->flags & KEX_INITIAL) && ssh->kex->kex_strict) -+ return 0; -+ /* Implicitly handle transport-level messages */ - switch (*typep) { - case SSH2_MSG_IGNORE: - debug3("Received SSH2_MSG_IGNORE"); -@@ -1738,19 +1763,6 @@ ssh_packet_read_poll_seqnr(struct ssh *ssh, u_char *typep, u_int32_t *seqnr_p) - debug("Remote: %.900s", msg); - free(msg); - break; -- case SSH2_MSG_DISCONNECT: -- if ((r = sshpkt_get_u32(ssh, &reason)) != 0 || -- (r = sshpkt_get_string(ssh, &msg, NULL)) != 0) -- return r; -- /* Ignore normal client exit notifications */ -- do_log2(ssh->state->server_side && -- reason == SSH2_DISCONNECT_BY_APPLICATION ? -- SYSLOG_LEVEL_INFO : SYSLOG_LEVEL_ERROR, -- "Received disconnect from %s port %d:" -- "%u: %.400s", ssh_remote_ipaddr(ssh), -- ssh_remote_port(ssh), reason, msg); -- free(msg); -- return SSH_ERR_DISCONNECTED; - case SSH2_MSG_UNIMPLEMENTED: - if ((r = sshpkt_get_u32(ssh, &seqnr)) != 0) - return r; -@@ -2242,6 +2254,7 @@ kex_to_blob(struct sshbuf *m, struct kex *kex) - (r = sshbuf_put_u32(m, kex->hostkey_type)) != 0 || - (r = sshbuf_put_u32(m, kex->hostkey_nid)) != 0 || - (r = sshbuf_put_u32(m, kex->kex_type)) != 0 || -+ (r = sshbuf_put_u32(m, kex->kex_strict)) != 0 || - (r = sshbuf_put_stringb(m, kex->my)) != 0 || - (r = sshbuf_put_stringb(m, kex->peer)) != 0 || - (r = sshbuf_put_stringb(m, kex->client_version)) != 0 || -@@ -2404,6 +2417,7 @@ kex_from_blob(struct sshbuf *m, struct kex **kexp) - (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_type)) != 0 || - (r = sshbuf_get_u32(m, (u_int *)&kex->hostkey_nid)) != 0 || - (r = sshbuf_get_u32(m, &kex->kex_type)) != 0 || -+ (r = sshbuf_get_u32(m, &kex->kex_strict)) != 0 || - (r = sshbuf_get_stringb(m, kex->my)) != 0 || - (r = sshbuf_get_stringb(m, kex->peer)) != 0 || - (r = sshbuf_get_stringb(m, kex->client_version)) != 0 || -@@ -2732,6 +2746,7 @@ sshpkt_disconnect(struct ssh *ssh, const char *fmt,...) - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - -+ debug2_f("sending SSH2_MSG_DISCONNECT: %s", buf); - if ((r = sshpkt_start(ssh, SSH2_MSG_DISCONNECT)) != 0 || - (r = sshpkt_put_u32(ssh, SSH2_DISCONNECT_PROTOCOL_ERROR)) != 0 || - (r = sshpkt_put_cstring(ssh, buf)) != 0 || -diff --git a/sshconnect2.c b/sshconnect2.c -index df6caf81..0cccbcc4 100644 ---- a/sshconnect2.c -+++ b/sshconnect2.c -@@ -358,7 +358,6 @@ struct cauthmethod { - }; - - static int input_userauth_service_accept(int, u_int32_t, struct ssh *); --static int input_userauth_ext_info(int, u_int32_t, struct ssh *); - static int input_userauth_success(int, u_int32_t, struct ssh *); - static int input_userauth_failure(int, u_int32_t, struct ssh *); - static int input_userauth_banner(int, u_int32_t, struct ssh *); -@@ -472,7 +471,7 @@ ssh_userauth2(struct ssh *ssh, const char *local_user, - - ssh->authctxt = &authctxt; - ssh_dispatch_init(ssh, &input_userauth_error); -- ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, &input_userauth_ext_info); -+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, kex_input_ext_info); - ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_ACCEPT, &input_userauth_service_accept); - ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt.success); /* loop until success */ - pubkey_cleanup(ssh); -@@ -531,12 +530,6 @@ input_userauth_service_accept(int type, u_int32_t seq, struct ssh *ssh) - return r; - } - --static int --input_userauth_ext_info(int type, u_int32_t seqnr, struct ssh *ssh) --{ -- return kex_input_ext_info(type, seqnr, ssh); --} -- - void - userauth(struct ssh *ssh, char *authlist) - { -@@ -615,6 +608,7 @@ input_userauth_success(int type, u_int32_t seq, struct ssh *ssh) - free(authctxt->methoddata); - authctxt->methoddata = NULL; - authctxt->success = 1; /* break out */ -+ ssh_dispatch_set(ssh, SSH2_MSG_EXT_INFO, dispatch_protocol_error); - return 0; - } - -diff -up openssh-8.7p1/sshd.c.kexstrict openssh-8.7p1/sshd.c ---- openssh-8.7p1/sshd.c.kexstrict 2023-11-27 13:19:18.855433602 +0100 -+++ openssh-8.7p1/sshd.c 2023-11-27 13:28:10.441325314 +0100 -@@ -2586,7 +2586,7 @@ do_ssh2_kex(struct ssh *ssh) - if (gss && orig) - xasprintf(&newstr, "%s,%s", gss, orig); - else if (gss) -- newstr = gss; -+ xasprintf(&newstr, "%s,%s", gss, "kex-strict-s-v00@openssh.com"); - else if (orig) - newstr = orig; - diff --git a/openssh-9.6p1-CVE-2023-51384.patch b/openssh-9.6p1-CVE-2023-51384.patch deleted file mode 100644 index 673ff1d..0000000 --- a/openssh-9.6p1-CVE-2023-51384.patch +++ /dev/null @@ -1,149 +0,0 @@ -diff --git a/ssh-agent.c b/ssh-agent.c -index f528611635e..1d4c321eb0b 100644 ---- a/ssh-agent.c -+++ b/ssh-agent.c -@@ -247,6 +247,91 @@ free_dest_constraints(struct dest_constraint *dcs, size_t ndcs) - free(dcs); - } - -+static void -+dup_dest_constraint_hop(const struct dest_constraint_hop *dch, -+ struct dest_constraint_hop *out) -+{ -+ u_int i; -+ int r; -+ -+ out->user = dch->user == NULL ? NULL : xstrdup(dch->user); -+ out->hostname = dch->hostname == NULL ? NULL : xstrdup(dch->hostname); -+ out->is_ca = dch->is_ca; -+ out->nkeys = dch->nkeys; -+ out->keys = out->nkeys == 0 ? NULL : -+ xcalloc(out->nkeys, sizeof(*out->keys)); -+ out->key_is_ca = out->nkeys == 0 ? NULL : -+ xcalloc(out->nkeys, sizeof(*out->key_is_ca)); -+ for (i = 0; i < dch->nkeys; i++) { -+ if (dch->keys[i] != NULL && -+ (r = sshkey_from_private(dch->keys[i], -+ &(out->keys[i]))) != 0) -+ fatal_fr(r, "copy key"); -+ out->key_is_ca[i] = dch->key_is_ca[i]; -+ } -+} -+ -+static struct dest_constraint * -+dup_dest_constraints(const struct dest_constraint *dcs, size_t ndcs) -+{ -+ size_t i; -+ struct dest_constraint *ret; -+ -+ if (ndcs == 0) -+ return NULL; -+ ret = xcalloc(ndcs, sizeof(*ret)); -+ for (i = 0; i < ndcs; i++) { -+ dup_dest_constraint_hop(&dcs[i].from, &ret[i].from); -+ dup_dest_constraint_hop(&dcs[i].to, &ret[i].to); -+ } -+ return ret; -+} -+ -+#ifdef DEBUG_CONSTRAINTS -+static void -+dump_dest_constraint_hop(const struct dest_constraint_hop *dch) -+{ -+ u_int i; -+ char *fp; -+ -+ debug_f("user %s hostname %s is_ca %d nkeys %u", -+ dch->user == NULL ? "(null)" : dch->user, -+ dch->hostname == NULL ? "(null)" : dch->hostname, -+ dch->is_ca, dch->nkeys); -+ for (i = 0; i < dch->nkeys; i++) { -+ fp = NULL; -+ if (dch->keys[i] != NULL && -+ (fp = sshkey_fingerprint(dch->keys[i], -+ SSH_FP_HASH_DEFAULT, SSH_FP_DEFAULT)) == NULL) -+ fatal_f("fingerprint failed"); -+ debug_f("key %u/%u: %s%s%s key_is_ca %d", i, dch->nkeys, -+ dch->keys[i] == NULL ? "" : sshkey_ssh_name(dch->keys[i]), -+ dch->keys[i] == NULL ? "" : " ", -+ dch->keys[i] == NULL ? "none" : fp, -+ dch->key_is_ca[i]); -+ free(fp); -+ } -+} -+#endif /* DEBUG_CONSTRAINTS */ -+ -+static void -+dump_dest_constraints(const char *context, -+ const struct dest_constraint *dcs, size_t ndcs) -+{ -+#ifdef DEBUG_CONSTRAINTS -+ size_t i; -+ -+ debug_f("%s: %zu constraints", context, ndcs); -+ for (i = 0; i < ndcs; i++) { -+ debug_f("constraint %zu / %zu: from: ", i, ndcs); -+ dump_dest_constraint_hop(&dcs[i].from); -+ debug_f("constraint %zu / %zu: to: ", i, ndcs); -+ dump_dest_constraint_hop(&dcs[i].to); -+ } -+ debug_f("done for %s", context); -+#endif /* DEBUG_CONSTRAINTS */ -+} -+ - static void - free_identity(Identity *id) - { -@@ -518,13 +603,22 @@ process_request_identities(SocketEntry *e) - Identity *id; - struct sshbuf *msg, *keys; - int r; -- u_int nentries = 0; -+ u_int i = 0, nentries = 0; -+ char *fp; - - debug2_f("entering"); - - if ((msg = sshbuf_new()) == NULL || (keys = sshbuf_new()) == NULL) - fatal_f("sshbuf_new failed"); - TAILQ_FOREACH(id, &idtab->idlist, next) { -+ if ((fp = sshkey_fingerprint(id->key, SSH_FP_HASH_DEFAULT, -+ SSH_FP_DEFAULT)) == NULL) -+ fatal_f("fingerprint failed"); -+ debug_f("key %u / %u: %s %s", i++, idtab->nentries, -+ sshkey_ssh_name(id->key), fp); -+ dump_dest_constraints(__func__, -+ id->dest_constraints, id->ndest_constraints); -+ free(fp); - /* identity not visible, don't include in response */ - if (identity_permitted(id, e, NULL, NULL, NULL) != 0) - continue; -@@ -1224,6 +1318,7 @@ process_add_identity(SocketEntry *e) - sshbuf_reset(e->request); - goto out; - } -+ dump_dest_constraints(__func__, dest_constraints, ndest_constraints); - - if (sk_provider != NULL) { - if (!sshkey_is_sk(k)) { -@@ -1403,6 +1498,7 @@ process_add_smartcard_key(SocketEntry *e) - error_f("failed to parse constraints"); - goto send; - } -+ dump_dest_constraints(__func__, dest_constraints, ndest_constraints); - - sane_uri = sanitize_pkcs11_provider(e, provider); - if (sane_uri == NULL) -@@ -1438,10 +1534,9 @@ process_add_smartcard_key(SocketEntry *e) - } - id->death = death; - id->confirm = confirm; -- id->dest_constraints = dest_constraints; -+ id->dest_constraints = dup_dest_constraints( -+ dest_constraints, ndest_constraints); - id->ndest_constraints = ndest_constraints; -- dest_constraints = NULL; /* transferred */ -- ndest_constraints = 0; - TAILQ_INSERT_TAIL(&idtab->idlist, id, next); - idtab->nentries++; - success = 1; diff --git a/openssh-9.6p1-CVE-2023-51385.patch b/openssh-9.6p1-CVE-2023-51385.patch deleted file mode 100644 index 7596d20..0000000 --- a/openssh-9.6p1-CVE-2023-51385.patch +++ /dev/null @@ -1,57 +0,0 @@ -diff --git a/ssh.c b/ssh.c -index 35c48e62..48d93ddf 100644 ---- a/ssh.c -+++ b/ssh.c -@@ -626,6 +626,41 @@ ssh_conn_info_free(struct ssh_conn_info *cinfo) - free(cinfo); - } - -+static int -+valid_hostname(const char *s) -+{ -+ size_t i; -+ -+ if (*s == '-') -+ return 0; -+ for (i = 0; s[i] != 0; i++) { -+ if (strchr("'`\"$\\;&<>|(){}", s[i]) != NULL || -+ isspace((u_char)s[i]) || iscntrl((u_char)s[i])) -+ return 0; -+ } -+ return 1; -+} -+ -+static int -+valid_ruser(const char *s) -+{ -+ size_t i; -+ -+ if (*s == '-') -+ return 0; -+ for (i = 0; s[i] != 0; i++) { -+ if (strchr("'`\";&<>|(){}", s[i]) != NULL) -+ return 0; -+ /* Disallow '-' after whitespace */ -+ if (isspace((u_char)s[i]) && s[i + 1] == '-') -+ return 0; -+ /* Disallow \ in last position */ -+ if (s[i] == '\\' && s[i + 1] == '\0') -+ return 0; -+ } -+ return 1; -+} -+ - /* - * Main program for the ssh client. - */ -@@ -1118,6 +1153,10 @@ main(int ac, char **av) - if (!host) - usage(); - -+ if (!valid_hostname(host)) -+ fatal("hostname contains invalid characters"); -+ if (options.user != NULL && !valid_ruser(options.user)) -+ fatal("remote username contains invalid characters"); - options.host_arg = xstrdup(host); - - /* Initialize the command to execute on remote host. */ diff --git a/openssh-9.6p1-cve-2024-6387.patch b/openssh-9.6p1-cve-2024-6387.patch deleted file mode 100644 index 0b976c0..0000000 --- a/openssh-9.6p1-cve-2024-6387.patch +++ /dev/null @@ -1,18 +0,0 @@ -diff --git a/log.c b/log.c -index 9fc1a2e2e..191ff4a5a 100644 ---- a/log.c -+++ b/log.c -@@ -451,12 +451,14 @@ void - sshsigdie(const char *file, const char *func, int line, int showfunc, - LogLevel level, const char *suffix, const char *fmt, ...) - { -+#ifdef SYSLOG_R_SAFE_IN_SIGHAND - va_list args; - - va_start(args, fmt); - sshlogv(file, func, line, showfunc, SYSLOG_LEVEL_FATAL, - suffix, fmt, args); - va_end(args); -+#endif - _exit(1); - } diff --git a/sources b/sources index c322d35..10b461b 100644 --- a/sources +++ b/sources @@ -1,3 +1,3 @@ -SHA512 (openssh-9.3p1.tar.gz) = 087ff6fe5f6caab4c6c3001d906399e02beffad7277280f11187420c2939fd4befdcb14643862a657ce4cad2f115b82a0a1a2c99df6ee54dcd76b53647637c19 -SHA512 (openssh-9.3p1.tar.gz.asc) = 6222378eb24a445c6c1db255392b405f5369b1af0e92f558d4ba05b0d83ab0d084cb8f4b91d7ae8636f333d970638a6635e2bc7af885135dd34992d87f2ef1f4 +SHA512 (openssh-10.0p1.tar.gz) = 2daa1fcf95793b23810142077e68ddfabdf3732b207ef4f033a027f72d733d0e9bcdb6f757e7f3a5934b972de05bfaae3baae381cfc7a400cd8ab4d4e277a0ed +SHA512 (openssh-10.0p1.tar.gz.asc) = 6ab9deb4233ff159e55a18c9fc07d5ff8a41723dad74aa3d803e1476b585f5662aba34f8a7a1f5fe1d248f3ff3cd663f2c2fb8e399c6a4723b6215b0eb423d13 SHA512 (gpgkey-736060BA.gpg) = df44f3fdbcd1d596705348c7f5aed3f738c5f626a55955e0642f7c6c082995cf36a1b1891bb41b8715cb2aff34fef1c877e0eff0d3507dd00a055ba695757a21